Last active
August 1, 2024 19:24
-
-
Save ahawker/9715872 to your computer and use it in GitHub Desktop.
Battery info from win32 api
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
using System; | |
using System.IO; | |
using Microsoft.Win32.SafeHandles; | |
using System.Collections.Generic; | |
using System.ComponentModel; | |
using System.Runtime.InteropServices; | |
using System.Text; | |
namespace Test | |
{ | |
class Program | |
{ | |
static void Main(string[] args) | |
{ | |
BatteryInformation cap = BatteryInfo.GetBatteryInformation(); | |
} | |
} | |
public class BatteryInformation | |
{ | |
public uint CurrentCapacity { get; set; } | |
public int DesignedMaxCapacity { get; set; } | |
public int FullChargeCapacity { get; set; } | |
public uint Voltage { get; set; } | |
public int DischargeRate { get; set; } | |
} | |
public static class BatteryInfo | |
{ | |
public static BatteryInformation GetBatteryInformation() | |
{ | |
IntPtr deviceDataPointer = IntPtr.Zero; | |
IntPtr queryInfoPointer = IntPtr.Zero; | |
IntPtr batteryInfoPointer = IntPtr.Zero; | |
IntPtr batteryWaitStatusPointer = IntPtr.Zero; | |
IntPtr batteryStatusPointer = IntPtr.Zero; | |
try | |
{ | |
IntPtr deviceHandle = SetupDiGetClassDevs( | |
Win32.GUID_DEVCLASS_BATTERY, Win32.DEVICE_GET_CLASS_FLAGS.DIGCF_PRESENT | Win32.DEVICE_GET_CLASS_FLAGS.DIGCF_DEVICEINTERFACE); | |
Win32.SP_DEVICE_INTERFACE_DATA deviceInterfaceData = new Win32.SP_DEVICE_INTERFACE_DATA(); | |
deviceInterfaceData.CbSize = Marshal.SizeOf(deviceInterfaceData); | |
SetupDiEnumDeviceInterfaces(deviceHandle, Win32.GUID_DEVCLASS_BATTERY, 0, ref deviceInterfaceData); | |
deviceDataPointer = Marshal.AllocHGlobal(Win32.DEVICE_INTERFACE_BUFFER_SIZE); | |
//Win32.SP_DEVICE_INTERFACE_DETAIL_DATA deviceDetailData = | |
// (Win32.SP_DEVICE_INTERFACE_DETAIL_DATA)Marshal.PtrToStructure(deviceDataPointer, typeof(Win32.SP_DEVICE_INTERFACE_DETAIL_DATA)); | |
//toggle these two and see if naything changes... ^^^^^^^^^^^^ | |
Win32.SP_DEVICE_INTERFACE_DETAIL_DATA deviceDetailData = new Win32.SP_DEVICE_INTERFACE_DETAIL_DATA(); | |
deviceDetailData.CbSize = (IntPtr.Size == 8) ? 8 : 4 + Marshal.SystemDefaultCharSize; | |
SetupDiGetDeviceInterfaceDetail(deviceHandle, ref deviceInterfaceData, ref deviceDetailData, Win32.DEVICE_INTERFACE_BUFFER_SIZE); | |
IntPtr batteryHandle = CreateFile(deviceDetailData.DevicePath, FileAccess.ReadWrite, FileShare.ReadWrite, FileMode.Open, Win32.FILE_ATTRIBUTES.Normal); | |
Win32.BATTERY_QUERY_INFORMATION queryInformation = new Win32.BATTERY_QUERY_INFORMATION(); | |
DeviceIoControl(batteryHandle, Win32.IOCTL_BATTERY_QUERY_TAG, ref queryInformation.BatteryTag); | |
Win32.BATTERY_INFORMATION batteryInformation = new Win32.BATTERY_INFORMATION(); | |
queryInformation.InformationLevel = Win32.BATTERY_QUERY_INFORMATION_LEVEL.BatteryInformation; | |
int queryInfoSize = Marshal.SizeOf(queryInformation); | |
int batteryInfoSize = Marshal.SizeOf(batteryInformation); | |
queryInfoPointer = Marshal.AllocHGlobal(queryInfoSize); | |
Marshal.StructureToPtr(queryInformation, queryInfoPointer, false); | |
batteryInfoPointer = Marshal.AllocHGlobal(batteryInfoSize); | |
Marshal.StructureToPtr(batteryInformation, batteryInfoPointer, false); | |
DeviceIoControl(batteryHandle, Win32.IOCTL_BATTERY_QUERY_INFORMATION, queryInfoPointer, queryInfoSize, batteryInfoPointer, batteryInfoSize); | |
Win32.BATTERY_INFORMATION updatedBatteryInformation = | |
(Win32.BATTERY_INFORMATION)Marshal.PtrToStructure(batteryInfoPointer, typeof(Win32.BATTERY_INFORMATION)); | |
Win32.BATTERY_WAIT_STATUS batteryWaitStatus = new Win32.BATTERY_WAIT_STATUS(); | |
batteryWaitStatus.BatteryTag = queryInformation.BatteryTag; | |
Win32.BATTERY_STATUS batteryStatus = new Win32.BATTERY_STATUS(); | |
int waitStatusSize = Marshal.SizeOf(batteryWaitStatus); | |
int batteryStatusSize = Marshal.SizeOf(batteryStatus); | |
batteryWaitStatusPointer = Marshal.AllocHGlobal(waitStatusSize); | |
Marshal.StructureToPtr(batteryWaitStatus, batteryWaitStatusPointer, false); | |
batteryStatusPointer = Marshal.AllocHGlobal(batteryStatusSize); | |
Marshal.StructureToPtr(batteryStatus, batteryStatusPointer, false); | |
DeviceIoControl(batteryHandle, Win32.IOCTL_BATTERY_QUERY_STATUS, batteryWaitStatusPointer, waitStatusSize, batteryStatusPointer, batteryStatusSize); | |
Win32.BATTERY_STATUS updatedStatus = | |
(Win32.BATTERY_STATUS)Marshal.PtrToStructure(batteryStatusPointer, typeof(Win32.BATTERY_STATUS)); | |
Win32.SetupDiDestroyDeviceInfoList(deviceHandle); | |
return new BatteryInformation() | |
{ | |
DesignedMaxCapacity = updatedBatteryInformation.DesignedCapacity, | |
FullChargeCapacity = updatedBatteryInformation.FullChargedCapacity, | |
CurrentCapacity = updatedStatus.Capacity, | |
Voltage = updatedStatus.Voltage, | |
DischargeRate = updatedStatus.Rate | |
}; | |
} | |
finally | |
{ | |
Marshal.FreeHGlobal(deviceDataPointer); | |
Marshal.FreeHGlobal(queryInfoPointer); | |
Marshal.FreeHGlobal(batteryInfoPointer); | |
Marshal.FreeHGlobal(batteryStatusPointer); | |
Marshal.FreeHGlobal(batteryWaitStatusPointer); | |
} | |
} | |
private static bool DeviceIoControl(IntPtr deviceHandle, uint controlCode, ref uint output) | |
{ | |
uint bytesReturned; | |
uint junkInput = 0; | |
bool retval = Win32.DeviceIoControl( | |
deviceHandle, controlCode, ref junkInput, 0, ref output, (uint)Marshal.SizeOf(output), out bytesReturned, IntPtr.Zero); | |
if (!retval) | |
{ | |
int errorCode = Marshal.GetLastWin32Error(); | |
if (errorCode != 0) | |
throw Marshal.GetExceptionForHR(errorCode); | |
else | |
throw new Exception( | |
"DeviceIoControl call failed but Win32 didn't catch an error."); | |
} | |
return retval; | |
} | |
private static bool DeviceIoControl( | |
IntPtr deviceHandle, uint controlCode, IntPtr input, int inputSize, IntPtr output, int outputSize) | |
{ | |
uint bytesReturned; | |
bool retval = Win32.DeviceIoControl( | |
deviceHandle, controlCode, input, (uint)inputSize, output, (uint)outputSize, out bytesReturned, IntPtr.Zero); | |
if (!retval) | |
{ | |
int errorCode = Marshal.GetLastWin32Error(); | |
if (errorCode != 0) | |
throw Marshal.GetExceptionForHR(errorCode); | |
else | |
throw new Exception( | |
"DeviceIoControl call failed but Win32 didn't catch an error."); | |
} | |
return retval; | |
} | |
private static IntPtr SetupDiGetClassDevs(Guid guid, Win32.DEVICE_GET_CLASS_FLAGS flags) | |
{ | |
IntPtr handle = Win32.SetupDiGetClassDevs(ref guid, null, IntPtr.Zero, flags); | |
if (handle == IntPtr.Zero || handle.ToInt32() == -1) | |
{ | |
int errorCode = Marshal.GetLastWin32Error(); | |
if (errorCode != 0) | |
throw Marshal.GetExceptionForHR(errorCode); | |
else | |
throw new Exception("SetupDiGetClassDev call returned a bad handle."); | |
} | |
return handle; | |
} | |
private static bool SetupDiEnumDeviceInterfaces( | |
IntPtr deviceInfoSet, Guid guid, int memberIndex, ref Win32.SP_DEVICE_INTERFACE_DATA deviceInterfaceData) | |
{ | |
bool retval = Win32.SetupDiEnumDeviceInterfaces( | |
deviceInfoSet, IntPtr.Zero, ref guid, (uint)memberIndex, ref deviceInterfaceData); | |
if (!retval) | |
{ | |
int errorCode = Marshal.GetLastWin32Error(); | |
if (errorCode != 0) | |
{ | |
if (errorCode == 259) | |
throw new Exception("SetupDeviceInfoEnumerateDeviceInterfaces ran out of batteries to enumerate."); | |
throw Marshal.GetExceptionForHR(errorCode); | |
} | |
else | |
throw new Exception( | |
"SetupDeviceInfoEnumerateDeviceInterfaces call failed but Win32 didn't catch an error."); | |
} | |
return retval; | |
} | |
private static bool SetupDiDestroyDeviceInfoList(IntPtr deviceInfoSet) | |
{ | |
bool retval = Win32.SetupDiDestroyDeviceInfoList(deviceInfoSet); | |
if (!retval) | |
{ | |
int errorCode = Marshal.GetLastWin32Error(); | |
if (errorCode != 0) | |
throw Marshal.GetExceptionForHR(errorCode); | |
else | |
throw new Exception( | |
"SetupDiDestroyDeviceInfoList call failed but Win32 didn't catch an error."); | |
} | |
return retval; | |
} | |
private static bool SetupDiGetDeviceInterfaceDetail( | |
IntPtr deviceInfoSet, ref Win32.SP_DEVICE_INTERFACE_DATA deviceInterfaceData, ref Win32.SP_DEVICE_INTERFACE_DETAIL_DATA deviceInterfaceDetailData, int deviceInterfaceDetailSize) | |
{ | |
//int tmpSize = Marshal.SizeOf(deviceInterfaceDetailData); | |
uint reqSize; | |
bool retval = Win32.SetupDiGetDeviceInterfaceDetail( | |
deviceInfoSet, ref deviceInterfaceData, ref deviceInterfaceDetailData, (uint)deviceInterfaceDetailSize, out reqSize, IntPtr.Zero); | |
if (!retval) | |
{ | |
int errorCode = Marshal.GetLastWin32Error(); | |
if (errorCode != 0) | |
throw Marshal.GetExceptionForHR(errorCode); | |
else | |
throw new Exception( | |
"SetupDiGetDeviceInterfaceDetail call failed but Win32 didn't catch an error."); | |
} | |
return retval; | |
} | |
private static IntPtr CreateFile( | |
string filename, FileAccess access, FileShare shareMode, FileMode creation, Win32.FILE_ATTRIBUTES flags) | |
{ | |
IntPtr handle = Win32.CreateFile( | |
filename, access, shareMode, IntPtr.Zero, creation, flags, IntPtr.Zero); | |
if (handle == IntPtr.Zero || handle.ToInt32() == -1) | |
{ | |
int errorCode = Marshal.GetLastWin32Error(); | |
if (errorCode != 0) | |
Marshal.ThrowExceptionForHR(errorCode); | |
else | |
throw new Exception( | |
"SetupDiGetDeviceInterfaceDetail call failed but Win32 didn't catch an error."); | |
} | |
return handle; | |
} | |
} | |
internal static class Win32 | |
{ | |
internal static readonly Guid GUID_DEVCLASS_BATTERY = new Guid(0x72631E54, 0x78A4, 0x11D0, 0xBC, 0xF7, 0x00, 0xAA, 0x00, 0xB7, 0xB3, 0x2A); | |
internal const uint IOCTL_BATTERY_QUERY_TAG = (0x00000029 << 16) | ((int)FileAccess.Read << 14) | (0x10 << 2) | (0); | |
internal const uint IOCTL_BATTERY_QUERY_INFORMATION = (0x00000029 << 16) | ((int)FileAccess.Read << 14) | (0x11 << 2) | (0); | |
internal const uint IOCTL_BATTERY_QUERY_STATUS = (0x00000029 << 16) | ((int)FileAccess.Read << 14) | (0x13 << 2) | (0); | |
internal const int DEVICE_INTERFACE_BUFFER_SIZE = 120; | |
[DllImport("setupapi.dll", CharSet = CharSet.Auto, SetLastError = true)] | |
internal static extern IntPtr SetupDiGetClassDevs( | |
ref Guid guid, | |
[MarshalAs(UnmanagedType.LPTStr)] string enumerator, | |
IntPtr hwnd, | |
DEVICE_GET_CLASS_FLAGS flags); | |
[DllImport("setupapi.dll", CharSet = CharSet.Auto, SetLastError = true)] | |
internal static extern bool SetupDiDestroyDeviceInfoList(IntPtr deviceInfoSet); | |
[DllImport("setupapi.dll", CharSet = CharSet.Auto, SetLastError = true)] | |
internal static extern bool SetupDiEnumDeviceInterfaces( | |
IntPtr hdevInfo, | |
IntPtr devInfo, | |
ref Guid guid, | |
uint memberIndex, | |
ref SP_DEVICE_INTERFACE_DATA devInterfaceData); | |
[DllImport("setupapi.dll", CharSet = CharSet.Auto, SetLastError = true)] | |
internal static extern bool SetupDiGetDeviceInterfaceDetail( | |
IntPtr hdevInfo, | |
ref SP_DEVICE_INTERFACE_DATA deviceInterfaceData, | |
ref SP_DEVICE_INTERFACE_DETAIL_DATA deviceInterfaceDetailData, | |
uint deviceInterfaceDetailDataSize, | |
out uint requiredSize, | |
IntPtr deviceInfoData); | |
[DllImport("setupapi.dll", CharSet = CharSet.Auto, SetLastError = true)] | |
internal static extern bool SetupDiGetDeviceInterfaceDetail( | |
IntPtr hdevInfo, | |
ref SP_DEVICE_INTERFACE_DATA deviceInterfaceData, | |
IntPtr deviceInterfaceDetailData, | |
uint deviceInterfaceDetailDataSize, | |
out uint requiredSize, | |
IntPtr deviceInfoData); | |
[DllImport("kernel32.dll", SetLastError = true, CharSet = CharSet.Auto)] | |
internal static extern IntPtr CreateFile( | |
string filename, | |
[MarshalAs(UnmanagedType.U4)] FileAccess desiredAccess, | |
[MarshalAs(UnmanagedType.U4)] FileShare shareMode, | |
IntPtr securityAttributes, | |
[MarshalAs(UnmanagedType.U4)] FileMode creationDisposition, | |
[MarshalAs(UnmanagedType.U4)] FILE_ATTRIBUTES flags, | |
IntPtr template); | |
[DllImport("kernel32.dll", SetLastError = true, CharSet = CharSet.Auto)] | |
internal static extern bool DeviceIoControl( | |
IntPtr handle, | |
uint controlCode, | |
[In] IntPtr inBuffer, | |
uint inBufferSize, | |
[Out] IntPtr outBuffer, | |
uint outBufferSize, | |
out uint bytesReturned, | |
IntPtr overlapped); | |
[DllImport("kernel32.dll", SetLastError = true, CharSet = CharSet.Auto)] | |
internal static extern bool DeviceIoControl( | |
IntPtr handle, | |
uint controlCode, | |
ref uint inBuffer, | |
uint inBufferSize, | |
ref uint outBuffer, | |
uint outBufferSize, | |
out uint bytesReturned, | |
IntPtr overlapped); | |
[Flags] | |
internal enum DEVICE_GET_CLASS_FLAGS : uint | |
{ | |
DIGCF_DEFAULT = 0x00000001, | |
DIGCF_PRESENT = 0x00000002, | |
DIGCF_ALLCLASSES = 0x00000004, | |
DIGCF_PROFILE = 0x00000008, | |
DIGCF_DEVICEINTERFACE = 0x00000010 | |
} | |
[Flags] | |
internal enum LOCAL_MEMORY_FLAGS | |
{ | |
LMEM_FIXED = 0x0000, | |
LMEM_MOVEABLE = 0x0002, | |
LMEM_NOCOMPACT = 0x0010, | |
LMEM_NODISCARD = 0x0020, | |
LMEM_ZEROINIT = 0x0040, | |
LMEM_MODIFY = 0x0080, | |
LMEM_DISCARDABLE = 0x0F00, | |
LMEM_VALID_FLAGS = 0x0F72, | |
LMEM_INVALID_HANDLE = 0x8000, | |
LHND = (LMEM_MOVEABLE | LMEM_ZEROINIT), | |
LPTR = (LMEM_FIXED | LMEM_ZEROINIT), | |
NONZEROLHND = (LMEM_MOVEABLE), | |
NONZEROLPTR = (LMEM_FIXED) | |
} | |
[Flags] | |
internal enum FILE_ATTRIBUTES : uint | |
{ | |
Readonly = 0x00000001, | |
Hidden = 0x00000002, | |
System = 0x00000004, | |
Directory = 0x00000010, | |
Archive = 0x00000020, | |
Device = 0x00000040, | |
Normal = 0x00000080, | |
Temporary = 0x00000100, | |
SparseFile = 0x00000200, | |
ReparsePoint = 0x00000400, | |
Compressed = 0x00000800, | |
Offline = 0x00001000, | |
NotContentIndexed = 0x00002000, | |
Encrypted = 0x00004000, | |
Write_Through = 0x80000000, | |
Overlapped = 0x40000000, | |
NoBuffering = 0x20000000, | |
RandomAccess = 0x10000000, | |
SequentialScan = 0x08000000, | |
DeleteOnClose = 0x04000000, | |
BackupSemantics = 0x02000000, | |
PosixSemantics = 0x01000000, | |
OpenReparsePoint = 0x00200000, | |
OpenNoRecall = 0x00100000, | |
FirstPipeInstance = 0x00080000 | |
} | |
internal enum BATTERY_QUERY_INFORMATION_LEVEL | |
{ | |
BatteryInformation = 0, | |
BatteryGranularityInformation = 1, | |
BatteryTemperature = 2, | |
BatteryEstimatedTime = 3, | |
BatteryDeviceName = 4, | |
BatteryManufactureDate = 5, | |
BatteryManufactureName = 6, | |
BatteryUniqueID = 7 | |
} | |
[Flags] | |
internal enum POWER_STATE : uint | |
{ | |
BATTERY_POWER_ONLINE = 0x00000001, | |
BATTERY_DISCHARGING = 0x00000002, | |
BATTERY_CHARGING = 0x00000004, | |
BATTERY_CRITICAL = 0x00000008 | |
} | |
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)] | |
internal struct BATTERY_INFORMATION | |
{ | |
public int Capabilities; | |
public byte Technology; | |
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 3)] | |
public byte[] Reserved; | |
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 4)] | |
public byte[] Chemistry; | |
public int DesignedCapacity; | |
public int FullChargedCapacity; | |
public int DefaultAlert1; | |
public int DefaultAlert2; | |
public int CriticalBias; | |
public int CycleCount; | |
} | |
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)] | |
internal struct SP_DEVICE_INTERFACE_DETAIL_DATA | |
{ | |
public int CbSize; | |
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 256)] | |
public string DevicePath; | |
} | |
[StructLayout(LayoutKind.Sequential)] | |
internal struct SP_DEVICE_INTERFACE_DATA | |
{ | |
public int CbSize; | |
public Guid InterfaceClassGuid; | |
public int Flags; | |
public UIntPtr Reserved; | |
} | |
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)] | |
internal struct BATTERY_QUERY_INFORMATION | |
{ | |
public uint BatteryTag; | |
public BATTERY_QUERY_INFORMATION_LEVEL InformationLevel; | |
public int AtRate; | |
} | |
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)] | |
internal struct BATTERY_STATUS | |
{ | |
public POWER_STATE PowerState; | |
public uint Capacity; | |
public uint Voltage; | |
public int Rate; | |
} | |
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)] | |
internal struct BATTERY_WAIT_STATUS | |
{ | |
public uint BatteryTag; | |
public uint Timeout; | |
public POWER_STATE PowerState; | |
public uint LowCapacity; | |
public uint HighCapacity; | |
} | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// Example from somewhere in MSDN | |
// | |
//DWORD GetBatteryState() | |
// { | |
//#define GBS_HASBATTERY 0x1 | |
//#define GBS_ONBATTERY 0x2 | |
// // Returned value includes GBS_HASBATTERY if the system has a | |
// // non-UPS battery, and GBS_ONBATTERY if the system is running on | |
// // a battery. | |
// // | |
// // dwResult & GBS_ONBATTERY means we have not yet found AC power. | |
// // dwResult & GBS_HASBATTERY means we have found a non-UPS battery. | |
// DWORD dwResult = GBS_ONBATTERY; | |
// // IOCTL_BATTERY_QUERY_INFORMATION, | |
// // enumerate the batteries and ask each one for information. | |
// HDEVINFO hdev = | |
// SetupDiGetClassDevs(&GUID_DEVCLASS_BATTERY, | |
// 0, | |
// 0, | |
// DIGCF_PRESENT | DIGCF_DEVICEINTERFACE); | |
// if (INVALID_HANDLE_VALUE != hdev) | |
// { | |
// // Limit search to 100 batteries max | |
// for (int idev = 0; idev < 100; idev++) | |
// { | |
// SP_DEVICE_INTERFACE_DATA did = {0}; | |
// did.cbSize = sizeof(did); | |
// if (SetupDiEnumDeviceInterfaces(hdev, | |
// 0, | |
// &GUID_DEVCLASS_BATTERY, | |
// idev, | |
// &did)) | |
// { | |
// DWORD cbRequired = 0; | |
// SetupDiGetDeviceInterfaceDetail(hdev, | |
// &did, | |
// 0, | |
// 0, | |
// &cbRequired, | |
// 0); | |
// if (ERROR_INSUFFICIENT_BUFFER == GetLastError()) | |
// { | |
// PSP_DEVICE_INTERFACE_DETAIL_DATA pdidd = | |
// (PSP_DEVICE_INTERFACE_DETAIL_DATA)LocalAlloc(LPTR, | |
// cbRequired); | |
// if (pdidd) | |
// { | |
// pdidd->cbSize = sizeof(*pdidd); | |
// if (SetupDiGetDeviceInterfaceDetail(hdev, | |
// &did, | |
// pdidd, | |
// cbRequired, | |
// &cbRequired, | |
// 0)) | |
// { | |
// // Enumerated a battery. Ask it for information. | |
// HANDLE hBattery = | |
// CreateFile(pdidd->DevicePath, | |
// GENERIC_READ | GENERIC_WRITE, | |
// FILE_SHARE_READ | FILE_SHARE_WRITE, | |
// NULL, | |
// OPEN_EXISTING, | |
// FILE_ATTRIBUTE_NORMAL, | |
// NULL); | |
// if (INVALID_HANDLE_VALUE != hBattery) | |
// { | |
// // Ask the battery for its tag. | |
// BATTERY_QUERY_INFORMATION bqi = {0}; | |
// DWORD dwWait = 0; | |
// DWORD dwOut; | |
// if (DeviceIoControl(hBattery, | |
// IOCTL_BATTERY_QUERY_TAG, | |
// &dwWait, | |
// sizeof(dwWait), | |
// &bqi.BatteryTag, | |
// sizeof(bqi.BatteryTag), | |
// &dwOut, | |
// NULL) | |
// && bqi.BatteryTag) | |
// { | |
// // With the tag, you can query the battery info. | |
// BATTERY_INFORMATION bi = {0}; | |
// bqi.InformationLevel = BatteryInformation; | |
// if (DeviceIoControl(hBattery, | |
// IOCTL_BATTERY_QUERY_INFORMATION, | |
// &bqi, | |
// sizeof(bqi), | |
// &bi, | |
// sizeof(bi), | |
// &dwOut, | |
// NULL)) | |
// { | |
// // Only non-UPS system batteries count | |
// if (bi.Capabilities & BATTERY_SYSTEM_BATTERY) | |
// { | |
// if (!(bi.Capabilities & BATTERY_IS_SHORT_TERM)) | |
// { | |
// dwResult |= GBS_HASBATTERY; | |
// } | |
// // Query the battery status. | |
// BATTERY_WAIT_STATUS bws = {0}; | |
// bws.BatteryTag = bqi.BatteryTag; | |
// BATTERY_STATUS bs; | |
// if (DeviceIoControl(hBattery, | |
// IOCTL_BATTERY_QUERY_STATUS, | |
// &bws, | |
// sizeof(bws), | |
// &bs, | |
// sizeof(bs), | |
// &dwOut, | |
// NULL)) | |
// { | |
// if (bs.PowerState & BATTERY_POWER_ON_LINE) | |
// { | |
// dwResult &= ~GBS_ONBATTERY; | |
// } | |
// } | |
// } | |
// } | |
// } | |
// CloseHandle(hBattery); | |
// } | |
// } | |
// LocalFree(pdidd); | |
// } | |
// } | |
// } | |
// else if (ERROR_NO_MORE_ITEMS == GetLastError()) | |
// { | |
// break; // Enumeration failed - perhaps we're out of items | |
// } | |
// } | |
// SetupDiDestroyDeviceInfoList(hdev); | |
// } | |
// // Final cleanup: If we didn't find a battery, then presume that we | |
// // are on AC power. | |
// if (!(dwResult & GBS_HASBATTERY)) | |
// dwResult &= ~GBS_ONBATTERY; | |
// return dwResult; | |
// } |
@StevenJDH, would be nice if you post a link to your forked gist.
@daluu sure, here it is: https://gist.github.com/StevenJDH/c66655967e21072b1d8644456129efc0
OMG I SEARCHED SOO SO LONG FOR A LIVE CHARGE RATE SOLUTION AND HERE WE ARE THANK YOU SO SO MUCH IT JUST WORKS <3 <3 <3 <3
When I put this to arm64 device. I got errorCode 122 and 1784 (ERROR_INSUFFICIENT_BUFFER) and Object reference not set to an instance of an object
from Line223 Win32.SetupDiGetDeviceInterfaceDetail(...
change line 221 -225 to follow works for me. I think this is also the proper way to get the reqSize
of deviceInterfaceDetailData
Win32.SetupDiGetDeviceInterfaceDetail(
deviceInfoSet, ref deviceInterfaceData, IntPtr.Zero, 0,
out var reqSize, IntPtr.Zero);
bool retval = Win32.SetupDiGetDeviceInterfaceDetail(
deviceInfoSet, ref deviceInterfaceData, ref deviceInterfaceDetailData, reqSize,
out _, IntPtr.Zero);
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Nearby,
in cases of failing memberIndices (like I wrote before) in
DeviceIoControl(...)
int errorCode = Marshal.GetLastWin32Error();
if ( errorCode != 0 )
{
throw Marshal.GetExceptionForHR( errorCode );
...
errorCode results to 2,
but then Marshal.GetExceptionForHR( 2 ) returns null.
so throw throws a NullReferenceExeption
Maybe not all Marshal.GetLastWin32Error() -Results map to a corresponding .NET exception.