@@ -5,27 +5,118 @@ extern "C"
55#include " util/windows/wmi.hpp"
66#include " util/windows/unicode.hpp"
77
8- #include < propvarutil.h>
9-
108STDAPI InitVariantFromStringArray (_In_reads_(cElems) PCWSTR *prgsz, _In_ ULONG cElems, _Out_ VARIANT *pvar);
119
12- static const char * detectWithWmi (FFlist* result)
10+ template <typename Fn>
11+ struct on_scope_exit {
12+ on_scope_exit (Fn &&fn): _fn(std::move(fn)) {}
13+ ~on_scope_exit () { this ->_fn (); }
14+
15+ private:
16+ Fn _fn;
17+ };
18+
19+ extern " C"
20+ const char * ffBluetoothDetectBattery (FFlist* devices)
1321{
1422 FFWmiQuery query (L" SELECT __PATH FROM Win32_PnPEntity WHERE Service = 'BthHFEnum'" , nullptr , FFWmiNamespace::CIMV2);
1523 if (!query)
1624 return " Query WMI service failed" ;
1725
18- while (FFWmiRecord record = query.next ())
26+ IWbemClassObject* pInParams = nullptr ;
27+ on_scope_exit releaseInParams ([&] { pInParams && pInParams->Release (); });
1928 {
20- IWbemClassObject* pInParams = nullptr ;
21- PCWSTR props[] = { L" {104EA319-6EE2-4701-BD47-8DDBF425BBE5} 2" };
29+ IWbemClassObject* pnpEntityClass = nullptr ;
30+
31+ if (FAILED (query.pService ->GetObjectW (bstr_t (L" Win32_PnPEntity" ), 0 , nullptr , &pnpEntityClass, nullptr )))
32+ return " Failed to get PnP entity class" ;
33+ on_scope_exit releasePnpEntityClass ([&] { pnpEntityClass && pnpEntityClass->Release (); });
34+
35+ if (FAILED (pnpEntityClass->GetMethod (bstr_t (L" GetDeviceProperties" ), 0 , &pInParams, NULL )))
36+ return " Failed to get GetDeviceProperties method" ;
37+
2238 VARIANT devicePropertyKeys;
23- InitVariantFromStringArray (props, ARRAY_SIZE (props), &devicePropertyKeys);
24- record.obj ->GetMethod (bstr_t (L" GetDeviceProperties" ), 0 , &pInParams, NULL );
25- pInParams->Put (L" devicePropertyKeys" , 0 , &devicePropertyKeys, CIM_FLAG_ARRAY | CIM_STRING);
26- IWbemCallResult* pResult = nullptr ;
27- query.pService ->ExecMethod (bstr_t (record.get (L" __PATH" ).bstrVal ), bstr_t (L" GetDeviceProperties" ), 0 , nullptr , pInParams, nullptr , &pResult);
28- // TODO: parse result
39+ PCWSTR props[] = { L" {104EA319-6EE2-4701-BD47-8DDBF425BBE5} 2" , L" DEVPKEY_Bluetooth_DeviceAddress" };
40+
41+ if (FAILED (InitVariantFromStringArray (props, ARRAY_SIZE (props), &devicePropertyKeys)))
42+ return " Failed to init variant from string array" ;
43+ on_scope_exit releaseDevicePropertyKeys ([&] { VariantClear (&devicePropertyKeys); });
44+
45+ if (FAILED (pInParams->Put (L" devicePropertyKeys" , 0 , &devicePropertyKeys, CIM_FLAG_ARRAY | CIM_STRING)))
46+ return " Failed to put devicePropertyKeys" ;
47+ }
48+
49+ while (FFWmiRecord record = query.next ())
50+ {
51+ IWbemCallResult* pCallResult = nullptr ;
52+
53+ if (FAILED (query.pService ->ExecMethod (record.get (L" __PATH" ).bstrVal , bstr_t (L" GetDeviceProperties" ), 0 , nullptr , pInParams, nullptr , &pCallResult)))
54+ continue ;
55+ on_scope_exit releaseCallResult ([&] { pCallResult && pCallResult->Release (); });
56+
57+ IWbemClassObject* pResultObject = nullptr ;
58+ if (FAILED (pCallResult->GetResultObject (WBEM_INFINITE, &pResultObject)))
59+ continue ;
60+ on_scope_exit releaseResultObject ([&] { pResultObject && pResultObject->Release (); });
61+
62+ VARIANT propArray;
63+ if (FAILED (pResultObject->Get (L" deviceProperties" , 0 , &propArray, nullptr , nullptr )))
64+ continue ;
65+ on_scope_exit releasePropArray ([&] { VariantClear (&propArray); });
66+
67+ if (propArray.vt != (VT_ARRAY | VT_UNKNOWN) ||
68+ (propArray.parray ->fFeatures & FADF_UNKNOWN) == 0 ||
69+ propArray.parray ->cDims != 1 ||
70+ propArray.parray ->rgsabound [0 ].cElements != 2
71+ )
72+ continue ;
73+
74+ uint8_t batt = 0 ;
75+ for (LONG i = 0 ; i < 2 ; i++)
76+ {
77+ IWbemClassObject* object = nullptr ;
78+ if (FAILED (SafeArrayGetElement (propArray.parray , &i, &object)))
79+ continue ;
80+
81+ FFWmiRecord rec (object);
82+ auto data = rec.get (L" Data" );
83+ if (data.vt == VT_EMPTY)
84+ break ;
85+
86+ if (i == 0 )
87+ batt = data.get <uint8_t >();
88+ else
89+ {
90+ FF_STRBUF_AUTO_DESTROY addr; // MAC address without colon
91+ ffStrbufInitWSV (&addr, data.get <std::wstring_view>());
92+ if (__builtin_expect (addr.length != 12 , 0 ))
93+ continue ;
94+
95+ FF_LIST_FOR_EACH (FFBluetoothResult, bt, *devices)
96+ {
97+ if (bt->address .length != 12 + 5 )
98+ continue ;
99+
100+ if (addr.chars [0 ] == bt->address .chars [0 ] &&
101+ addr.chars [1 ] == bt->address .chars [1 ] &&
102+ addr.chars [2 ] == bt->address .chars [3 ] &&
103+ addr.chars [3 ] == bt->address .chars [4 ] &&
104+ addr.chars [4 ] == bt->address .chars [6 ] &&
105+ addr.chars [5 ] == bt->address .chars [7 ] &&
106+ addr.chars [6 ] == bt->address .chars [9 ] &&
107+ addr.chars [7 ] == bt->address .chars [10 ] &&
108+ addr.chars [8 ] == bt->address .chars [12 ] &&
109+ addr.chars [9 ] == bt->address .chars [13 ] &&
110+ addr.chars [10 ] == bt->address .chars [15 ] &&
111+ addr.chars [11 ] == bt->address .chars [16 ])
112+ {
113+ bt->battery = batt;
114+ break ;
115+ }
116+ }
117+ }
118+ }
29119 }
120+
30121 return NULL ;
31122}
0 commit comments