2Copyright 2021 Intel Corporation
4Licensed under the Apache License, Version 2.0 (the "License");
5you may not use this file except in compliance with the License.
6You may obtain a copy of the License at
8 http://www.apache.org/licenses/LICENSE-2.0
10Unless required by applicable law or agreed to in writing, software
11distributed under the License is distributed on an "AS IS" BASIS,
12WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13See the License for the specific language governing permissions and
14limitations under the License.
17var promise = require('promise');
18var GM = require('_GenericMarshal');
19const CLSID_WbemAdministrativeLocator = '{CB8555CC-9128-11D1-AD9B-00C04FD8FDFF}';
20const IID_WbemLocator = '{dc12a687-737f-11cf-884d-00aa004b2e24}';
21const WBEM_FLAG_BIDIRECTIONAL = 0;
22const WBEM_INFINITE = -1;
23const WBEM_FLAG_ALWAYS = 0;
24const E_NOINTERFACE = 0x80004002;
25var OleAut32 = GM.CreateNativeProxy('OleAut32.dll');
26OleAut32.CreateMethod('SafeArrayAccessData');
30const LocatorFunctions = ['QueryInterface', 'AddRef', 'Release', 'ConnectToServer'];
33// Reference for IWbemServices can be found at:
34// https://learn.microsoft.com/en-us/windows/win32/api/wbemcli/nn-wbemcli-iwbemservices
36const ServiceFunctions = [
50 'CreateClassEnumAsync',
54 'DeleteInstanceAsync',
56 'CreateInstanceEnumAsync',
59 'ExecNotificationQuery',
60 'ExecNotificationQueryAsync',
66// Reference to IEnumWbemClassObject can be found at:
67// https://learn.microsoft.com/en-us/windows/win32/api/wbemcli/nn-wbemcli-ienumwbemclassobject
69const ResultsFunctions = [
81// Reference to IWbemClassObject can be found at:
82// https://learn.microsoft.com/en-us/windows/win32/api/wbemcli/nn-wbemcli-iwbemclassobject
84const ResultFunctions = [
96 'GetPropertyQualifierSet',
107 'BeginMethodEnumeration',
109 'EndMethodEnumeration',
110 'GetMethodQualifierSet',
115// Reference to IWbemObjectSink can be found at:
116// https://learn.microsoft.com/en-us/windows/win32/wmisdk/iwbemobjectsink
118const QueryAsyncHandler =
121 cx: 10, parms: 3, name: 'QueryInterface', func: function (j, riid, ppv)
123 var ret = GM.CreateVariable(4);
124 console.info1('QueryInterface', riid.Deref(0, 16).toBuffer().toString('hex'));
125 switch (riid.Deref(0, 16).toBuffer().toString('hex'))
127 case '0000000000000000C000000000000046': // IID_IUnknown
128 j.pointerBuffer().copy(ppv.Deref(0, GM.PointerSize).toBuffer());
129 ret.increment(0, true);
131 console.info1('QueryInterface (IID_IUnknown)', this.refcount);
133 case '0178857C8173CF11884D00AA004B2E24': // IID_IWmiObjectSink
134 j.pointerBuffer().copy(ppv.Deref(0, GM.PointerSize).toBuffer());
135 ret.increment(0, true);
137 console.info1('QueryInterface (IID_IWmiObjectSink)', this.refcount);
140 ret.increment(E_NOINTERFACE, true);
141 console.info1(riid.Deref(0, 16).toBuffer().toString('hex'), 'returning E_NOINTERFACE');
149 cx: 11, parms: 1, name: 'AddRef', func: function ()
152 console.info1('AddRef', this.refcount);
153 return (GM.CreateVariable(4));
157 cx: 12, parms: 1, name: 'Release', func: function ()
160 console.info1('Release', this.refcount);
161 if (this.refcount == 0)
163 console.info1('No More References');
166 this.services.funcs.Release(this.services.Deref());
168 this.services = null;
170 if (this.callbackDispatched)
172 setImmediate(function (j) { j.locator = null; }, this);
179 console.info1('No More References [END]');
181 return (GM.CreateVariable(4));
185 cx: 13, parms: 3, name: 'Indicate', func: function (j, count, arr)
187 console.info1('Indicate', count.Val);
190 for (var i = 0; i < count.Val; ++i)
192 j = arr.Deref((i * GM.PointerSize) + 0, GM.PointerSize);
193 this.results.push(enumerateProperties(j, this.fields));
196 var ret = GM.CreateVariable(4);
197 ret.increment(0, true);
202 cx: 14, parms: 5, name: 'SetStatus', func: function (j, lFlags, hResult, strParam, pObjParam)
204 console.info1('SetStatus', hResult.Val);
206 var ret = GM.CreateVariable(4);
207 ret.increment(0, true);
209 if (hResult.Val == 0)
211 this.p.resolve(this.results);
215 this.p.reject(hResult.Val);
223function enumerateProperties(j, fields)
226 // Reference to SafeArrayAccessData() can be found at:
227 // https://learn.microsoft.com/en-us/windows/win32/api/oleauto/nf-oleauto-safearrayaccessdata
234 j.funcs = require('win-com').marshalFunctions(j.Deref(), ResultFunctions);
236 // First we need to enumerate the COM Array
237 if (fields != null && Array.isArray(fields))
243 nme = GM.CreatePointer();
244 j.funcs.GetNames(j.Deref(), 0, WBEM_FLAG_ALWAYS, 0, nme);
245 len = nme.Deref().Deref(GM.PointerSize == 8 ? 24 : 16, 4).toBuffer().readUInt32LE();
246 nn = GM.CreatePointer();
247 OleAut32.SafeArrayAccessData(nme.Deref(), nn);
250 for (var i = 0; i < len; ++i)
252 var propName = nn.Deref().increment(i * GM.PointerSize).Deref().Wide2UTF8;
253 if (propName.length === 0) { continue; }
254 properties.push(propName);
258 // Now we need to introspect the Array Fields
259 for (var i = 0; i < properties.length; ++i)
261 var tmp1 = GM.CreateVariable(24);
262 if (j.funcs.Get(j.Deref(), GM.CreateVariable(properties[i], { wide: true }), 0, tmp1, 0, 0).Val == 0)
265 // Reference for IWbemClassObject::Get() can be found at:
266 // https://learn.microsoft.com/en-us/windows/win32/api/wbemcli/nf-wbemcli-iwbemclassobject-get
269 var vartype = tmp1.toBuffer().readUInt16LE();
270 var isArray = (vartype & 0x2000) != 0; // VT_ARRAY flag
271 var baseType = vartype & 0x0FFF;
275 // Handle array types (VT_ARRAY | base type)
276 var safeArray = tmp1.Deref(8, GM.PointerSize).Deref();
277 var arrayLength = safeArray.Deref(GM.PointerSize == 8 ? 24 : 16, 4).toBuffer().readUInt32LE();
278 var arrayData = GM.CreatePointer();
279 OleAut32.SafeArrayAccessData(safeArray, arrayData);
281 var arrayValues = [];
282 for (var k = 0; k < arrayLength; ++k)
286 case 0x0002: // VT_I2
287 arrayValues.push(arrayData.Deref().Deref(k * 2, 2).toBuffer().readInt16LE());
289 case 0x0003: // VT_I4
290 case 0x0016: // VT_INT
291 arrayValues.push(arrayData.Deref().Deref(k * 4, 4).toBuffer().readInt32LE());
293 case 0x000B: // VT_BOOL
294 arrayValues.push(arrayData.Deref().Deref(k * 2, 2).toBuffer().readInt16LE() != 0);
296 case 0x0010: // VT_I1
297 arrayValues.push(arrayData.Deref().Deref(k, 1).toBuffer().readInt8());
299 case 0x0011: // VT_UI1
300 arrayValues.push(arrayData.Deref().Deref(k, 1).toBuffer().readUInt8());
302 case 0x0012: // VT_UI2
303 arrayValues.push(arrayData.Deref().Deref(k * 2, 2).toBuffer().readUInt16LE());
305 case 0x0013: // VT_UI4
306 case 0x0017: // VT_UINT
307 arrayValues.push(arrayData.Deref().Deref(k * 4, 4).toBuffer().readUInt32LE());
309 case 0x0008: // VT_BSTR
310 arrayValues.push(arrayData.Deref().Deref(k * GM.PointerSize, GM.PointerSize).Deref().Wide2UTF8);
314 values[properties[i]] = arrayValues;
318 // Handle scalar types
321 case 0x0000: // VT_EMPTY
322 case 0x0001: // VT_NULL
323 values[properties[i]] = null;
325 case 0x0002: // VT_I2
326 values[properties[i]] = tmp1.Deref(8, GM.PointerSize).toBuffer().readInt16LE();
328 case 0x0003: // VT_I4
329 case 0x0016: // VT_INT
330 values[properties[i]] = tmp1.Deref(8, GM.PointerSize).toBuffer().readInt32LE();
332 case 0x000B: // VT_BOOL
333 values[properties[i]] = tmp1.Deref(8, GM.PointerSize).toBuffer().readInt32LE() != 0;
335 case 0x000E: // VT_DECIMAL
337 case 0x0010: // VT_I1
338 values[properties[i]] = tmp1.Deref(8, GM.PointerSize).toBuffer().readInt8();
340 case 0x0011: // VT_UI1
341 values[properties[i]] = tmp1.Deref(8, GM.PointerSize).toBuffer().readUInt8();
343 case 0x0012: // VT_UI2
344 values[properties[i]] = tmp1.Deref(8, GM.PointerSize).toBuffer().readUInt16LE();
346 case 0x0013: // VT_UI4
347 case 0x0017: // VT_UINT
348 values[properties[i]] = tmp1.Deref(8, GM.PointerSize).toBuffer().readUInt32LE();
350 //case 0x0014: // VT_I8
352 //case 0x0015: // VT_UI8
354 case 0x0008: // VT_BSTR
355 values[properties[i]] = tmp1.Deref(8, GM.PointerSize).Deref().Wide2UTF8;
358 console.info1('VARTYPE: ' + vartype);
368function queryAsync(resourceString, queryString, fields)
370 var p = new promise(require('promise').defaultInit);
371 var resource = GM.CreateVariable(resourceString, { wide: true });
372 var language = GM.CreateVariable("WQL", { wide: true });
373 var query = GM.CreateVariable(queryString, { wide: true });
374 var results = GM.CreatePointer();
376 // Setup the Async COM handler for QueryAsync()
377 var handlers = require('win-com').marshalInterface(QueryAsyncHandler);
378 handlers.refcount = 1;
379 handlers.results = [];
380 handlers.fields = fields;
381 handlers.locator = require('win-com').createInstance(require('win-com').CLSIDFromString(CLSID_WbemAdministrativeLocator), require('win-com').IID_IUnknown);
382 handlers.locator.funcs = require('win-com').marshalFunctions(handlers.locator, LocatorFunctions);
384 handlers.services = require('_GenericMarshal').CreatePointer();
385 if (handlers.locator.funcs.ConnectToServer(handlers.locator, resource, 0, 0, 0, 0, 0, 0, handlers.services).Val != 0) { throw ('Error calling ConnectToService'); }
387 handlers.services.funcs = require('win-com').marshalFunctions(handlers.services.Deref(), ServiceFunctions);
391 if (handlers.services.funcs.ExecQueryAsync(handlers.services.Deref(), language, query, WBEM_FLAG_BIDIRECTIONAL, 0, handlers).Val != 0)
393 throw ('Error in Query');
396 // Hold a reference to the callback object
397 wmi_handlers[handlers._hashCode()] = handlers;
400function query(resourceString, queryString, fields)
402 var resource = GM.CreateVariable(resourceString, { wide: true });
403 var language = GM.CreateVariable("WQL", { wide: true });
404 var query = GM.CreateVariable(queryString, { wide: true });
405 var results = GM.CreatePointer();
407 // Connect the locator connection for WMI
408 var locator = require('win-com').createInstance(require('win-com').CLSIDFromString(CLSID_WbemAdministrativeLocator), require('win-com').IID_IUnknown);
409 locator.funcs = require('win-com').marshalFunctions(locator, LocatorFunctions);
410 var services = require('_GenericMarshal').CreatePointer();
411 if (locator.funcs.ConnectToServer(locator, resource, 0, 0, 0, 0, 0, 0, services).Val != 0) { throw ('Error calling ConnectToService'); }
414 services.funcs = require('win-com').marshalFunctions(services.Deref(), ServiceFunctions);
415 if (services.funcs.ExecQuery(services.Deref(), language, query, WBEM_FLAG_BIDIRECTIONAL, 0, results).Val != 0) { throw ('Error in Query'); }
417 results.funcs = require('win-com').marshalFunctions(results.Deref(), ResultsFunctions);
418 var returnedCount = GM.CreateVariable(8);
419 var result = GM.CreatePointer();
422 // Enumerate the results
423 while (results.funcs.Next(results.Deref(), WBEM_INFINITE, 1, result, returnedCount).Val == 0)
425 ret.push(enumerateProperties(result, fields));
428 results.funcs.Release(results.Deref());
429 services.funcs.Release(services.Deref());
430 locator.funcs.Release(locator);
435module.exports = { query: query, queryAsync: queryAsync };