From c65fb1a8689c974f966af728ae12a15daf43e868 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=9D=8E=E9=80=9A=E6=B4=B2?= Date: Sun, 6 Jul 2025 17:04:51 +0800 Subject: [PATCH] Battery (Windows): use `CMAPI` instead of `SetupAPI` --- src/detection/battery/battery_windows.c | 47 ++++++++++--------------- 1 file changed, 19 insertions(+), 28 deletions(-) diff --git a/src/detection/battery/battery_windows.c b/src/detection/battery/battery_windows.c index 101bd6dea..dde78d217 100644 --- a/src/detection/battery/battery_windows.c +++ b/src/detection/battery/battery_windows.c @@ -8,40 +8,31 @@ #undef WIN32_LEAN_AND_MEAN #include -#include #include #include +#include #include -static inline void wrapSetupDiDestroyDeviceInfoList(HDEVINFO* hdev) +static const char* detectWithCmApi(FFBatteryOptions* options, FFlist* results) { - if(*hdev) - SetupDiDestroyDeviceInfoList(*hdev); -} + //https://learn.microsoft.com/en-us/windows-hardware/drivers/install/using-device-interfaces + ULONG cchDeviceInterfaces = 0; + CONFIGRET cr = CM_Get_Device_Interface_List_SizeW(&cchDeviceInterfaces, (LPGUID)&GUID_DEVCLASS_BATTERY, NULL, CM_GET_DEVICE_INTERFACE_LIST_PRESENT); + if (cr != CR_SUCCESS) + return "CM_Get_Device_Interface_List_SizeW() failed"; -static const char* detectWithSetupApi(FFBatteryOptions* options, FFlist* results) -{ - //https://learn.microsoft.com/en-us/windows/win32/power/enumerating-battery-devices - HDEVINFO hdev __attribute__((__cleanup__(wrapSetupDiDestroyDeviceInfoList))) = - SetupDiGetClassDevsW(&GUID_DEVCLASS_BATTERY, 0, 0, DIGCF_PRESENT | DIGCF_DEVICEINTERFACE); - if(hdev == INVALID_HANDLE_VALUE) - return "SetupDiGetClassDevsW(&GUID_DEVCLASS_BATTERY) failed"; + if (cchDeviceInterfaces <= 1) + return NULL; // Not found - SP_DEVICE_INTERFACE_DATA did = { .cbSize = sizeof(did) }; - for(DWORD idev = 0; SetupDiEnumDeviceInterfaces(hdev, NULL, &GUID_DEVCLASS_BATTERY, idev, &did); idev++) + wchar_t* FF_AUTO_FREE mszDeviceInterfaces = (wchar_t*)malloc(cchDeviceInterfaces * sizeof(wchar_t)); + cr = CM_Get_Device_Interface_ListW((LPGUID)&GUID_DEVCLASS_BATTERY, NULL, mszDeviceInterfaces, cchDeviceInterfaces, CM_GET_DEVICE_INTERFACE_LIST_PRESENT); + if (cr != CR_SUCCESS) + return "CM_Get_Device_Interface_ListW() failed"; + + for (const wchar_t* pDeviceInterface = mszDeviceInterfaces; *pDeviceInterface; pDeviceInterface += wcslen(pDeviceInterface) + 1) { - DWORD cbRequired = 0; - SetupDiGetDeviceInterfaceDetailW(hdev, &did, NULL, 0, &cbRequired, NULL); //Fail with not enough buffer - SP_DEVICE_INTERFACE_DETAIL_DATA_W* FF_AUTO_FREE pdidd = (SP_DEVICE_INTERFACE_DETAIL_DATA_W*)malloc(cbRequired); - if(!pdidd) - break; //Out of memory - - pdidd->cbSize = sizeof(*pdidd); - if(!SetupDiGetDeviceInterfaceDetailW(hdev, &did, pdidd, cbRequired, &cbRequired, NULL)) - continue; - HANDLE FF_AUTO_CLOSE_FD hBattery = - CreateFileW(pdidd->DevicePath, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); + CreateFileW(pDeviceInterface, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); if(hBattery == INVALID_HANDLE_VALUE) continue; @@ -99,7 +90,7 @@ static const char* detectWithSetupApi(FFBatteryOptions* options, FFlist* results bqi.InformationLevel = BatteryManufactureDate; BATTERY_MANUFACTURE_DATE date; if(DeviceIoControl(hBattery, IOCTL_BATTERY_QUERY_INFORMATION, &bqi, sizeof(bqi), &date, sizeof(date), &dwOut, NULL)) - ffStrbufSetF(&battery->manufactureDate, "%.4d-%.2d-%.2d", date.Year + 1900, date.Month, date.Day); + ffStrbufSetF(&battery->manufactureDate, "%.4d-%.2d-%.2d", date.Year < 1000 ? date.Year + 1900 : date.Year, date.Month, date.Day); } { @@ -131,7 +122,7 @@ static const char* detectWithSetupApi(FFBatteryOptions* options, FFlist* results { BATTERY_STATUS bs; BATTERY_WAIT_STATUS bws = { .BatteryTag = bqi.BatteryTag }; - if(DeviceIoControl(hBattery, IOCTL_BATTERY_QUERY_STATUS, &bws, sizeof(bws), &bs, sizeof(bs), &dwOut, NULL) && bs.Capacity != BATTERY_UNKNOWN_CAPACITY) + if(DeviceIoControl(hBattery, IOCTL_BATTERY_QUERY_STATUS, &bws, sizeof(bws), &bs, sizeof(bs), &dwOut, NULL) && bs.Capacity != BATTERY_UNKNOWN_CAPACITY && bi.FullChargedCapacity != 0) battery->capacity = bs.Capacity * 100.0 / bi.FullChargedCapacity; else battery->capacity = 0; @@ -271,6 +262,6 @@ static const char* detectWithNtApi(FF_MAYBE_UNUSED FFBatteryOptions* options, FF const char* ffDetectBattery(FFBatteryOptions* options, FFlist* results) { return options->useSetupApi - ? detectWithSetupApi(options, results) + ? detectWithCmApi(options, results) : detectWithNtApi(options, results); }