-
-
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.