-
-
Save ahawker/9715872 to your computer and use it in GitHub Desktop.
| 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; | |
| } | |
| } | |
| } |
| // 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; | |
| // } |
Hi, first of all thank you for the great code!
I just wanted to warn you that I got overflow errors with this: handle.ToInt32() == -1
I replaced it with handle.ToInt64() == -1 and seems to work fine.
Thank you for this sample code.
I've found out, that not erverytime the memberIndex of der battery is 0. (In my special case I had to use memberIndex 2), so
SetupDiEnumDeviceInterfaces(deviceHandle, Win32.GUID_DEVCLASS_BATTERY, 2, ref deviceInterfaceData); works, all other memberIndex fail on DeviceIoControl(...) later.
I've found an MSDN c++ example here, where they try numbers between 0 and 100 (why 100?).
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.
@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);
Great implementation of the BATTERY_INFORMATION and BATTERY_STATUS structures. It was the only method I have seen that actually returns the battery’s cycle count and designed capacity reliably. I have forked your code and made a few changes as follows:
“Fixed arithmetic overflow in 64-bit mode. Exposed cycle count and power state. Changed DiscargeRate to Rate since it also shows charge rate as per MSDN. Other minor corrections made.”
I wish GitHub would implement pull requests for gists. Anyways, thanks a lot.