EverydayTech Platform - Developer Reference
Complete Source Code Documentation - All Applications
Loading...
Searching...
No Matches
win-wmi-fixed.js
Go to the documentation of this file.
1/*
2Copyright 2021 Intel Corporation
3
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
7
8 http://www.apache.org/licenses/LICENSE-2.0
9
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.
15*/
16
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');
27
28var wmi_handlers = {};
29
30const LocatorFunctions = ['QueryInterface', 'AddRef', 'Release', 'ConnectToServer'];
31
32//
33// Reference for IWbemServices can be found at:
34// https://learn.microsoft.com/en-us/windows/win32/api/wbemcli/nn-wbemcli-iwbemservices
35//
36const ServiceFunctions = [
37 'QueryInterface',
38 'AddRef',
39 'Release',
40 'OpenNamespace',
41 'CancelAsyncCall',
42 'QueryObjectSink',
43 'GetObject',
44 'GetObjectAsync',
45 'PutClass',
46 'PutClassAsync',
47 'DeleteClass',
48 'DeleteClassAsync',
49 'CreateClassEnum',
50 'CreateClassEnumAsync',
51 'PutInstance',
52 'PutInstanceAsync',
53 'DeleteInstance',
54 'DeleteInstanceAsync',
55 'CreateInstanceEnum',
56 'CreateInstanceEnumAsync',
57 'ExecQuery',
58 'ExecQueryAsync',
59 'ExecNotificationQuery',
60 'ExecNotificationQueryAsync',
61 'ExecMethod',
62 'ExecMethodAsync'
63];
64
65//
66// Reference to IEnumWbemClassObject can be found at:
67// https://learn.microsoft.com/en-us/windows/win32/api/wbemcli/nn-wbemcli-ienumwbemclassobject
68//
69const ResultsFunctions = [
70 'QueryInterface',
71 'AddRef',
72 'Release',
73 'Reset',
74 'Next',
75 'NextAsync',
76 'Clone',
77 'Skip'
78];
79
80//
81// Reference to IWbemClassObject can be found at:
82// https://learn.microsoft.com/en-us/windows/win32/api/wbemcli/nn-wbemcli-iwbemclassobject
83//
84const ResultFunctions = [
85 'QueryInterface',
86 'AddRef',
87 'Release',
88 'GetQualifierSet',
89 'Get',
90 'Put',
91 'Delete',
92 'GetNames',
93 'BeginEnumeration',
94 'Next',
95 'EndEnumeration',
96 'GetPropertyQualifierSet',
97 'Clone',
98 'GetObjectText',
99 'SpawnDerivedClass',
100 'SpawnInstance',
101 'CompareTo',
102 'GetPropertyOrigin',
103 'InheritsFrom',
104 'GetMethod',
105 'PutMethod',
106 'DeleteMethod',
107 'BeginMethodEnumeration',
108 'NextMethod',
109 'EndMethodEnumeration',
110 'GetMethodQualifierSet',
111 'GetMethodOrigin'
112];
113
114//
115// Reference to IWbemObjectSink can be found at:
116// https://learn.microsoft.com/en-us/windows/win32/wmisdk/iwbemobjectsink
117//
118const QueryAsyncHandler =
119 [
120 {
121 cx: 10, parms: 3, name: 'QueryInterface', func: function (j, riid, ppv)
122 {
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'))
126 {
127 case '0000000000000000C000000000000046': // IID_IUnknown
128 j.pointerBuffer().copy(ppv.Deref(0, GM.PointerSize).toBuffer());
129 ret.increment(0, true);
130 //++this.p.refcount;
131 console.info1('QueryInterface (IID_IUnknown)', this.refcount);
132 break;
133 case '0178857C8173CF11884D00AA004B2E24': // IID_IWmiObjectSink
134 j.pointerBuffer().copy(ppv.Deref(0, GM.PointerSize).toBuffer());
135 ret.increment(0, true);
136 //++this.p.refcount;
137 console.info1('QueryInterface (IID_IWmiObjectSink)', this.refcount);
138 break;
139 default:
140 ret.increment(E_NOINTERFACE, true);
141 console.info1(riid.Deref(0, 16).toBuffer().toString('hex'), 'returning E_NOINTERFACE');
142 break;
143 }
144
145 return (ret);
146 }
147 },
148 {
149 cx: 11, parms: 1, name: 'AddRef', func: function ()
150 {
151 ++this.refcount;
152 console.info1('AddRef', this.refcount);
153 return (GM.CreateVariable(4));
154 }
155 },
156 {
157 cx: 12, parms: 1, name: 'Release', func: function ()
158 {
159 --this.refcount;
160 console.info1('Release', this.refcount);
161 if (this.refcount == 0)
162 {
163 console.info1('No More References');
164
165 this.cleanup();
166 this.services.funcs.Release(this.services.Deref());
167
168 this.services = null;
169 this.p = null;
170 if (this.callbackDispatched)
171 {
172 setImmediate(function (j) { j.locator = null; }, this);
173 }
174 else
175 {
176 this.locator = null;
177 }
178
179 console.info1('No More References [END]');
180 }
181 return (GM.CreateVariable(4));
182 }
183 },
184 {
185 cx: 13, parms: 3, name: 'Indicate', func: function (j, count, arr)
186 {
187 console.info1('Indicate', count.Val);
188 var j, nme, len, nn;
189
190 for (var i = 0; i < count.Val; ++i)
191 {
192 j = arr.Deref((i * GM.PointerSize) + 0, GM.PointerSize);
193 this.results.push(enumerateProperties(j, this.fields));
194 }
195
196 var ret = GM.CreateVariable(4);
197 ret.increment(0, true);
198 return (ret);
199 }
200 },
201 {
202 cx: 14, parms: 5, name: 'SetStatus', func: function (j, lFlags, hResult, strParam, pObjParam)
203 {
204 console.info1('SetStatus', hResult.Val);
205
206 var ret = GM.CreateVariable(4);
207 ret.increment(0, true);
208
209 if (hResult.Val == 0)
210 {
211 this.p.resolve(this.results);
212 }
213 else
214 {
215 this.p.reject(hResult.Val);
216 }
217 return (ret);
218 }
219 }
220 ];
221
222
223function enumerateProperties(j, fields)
224{
225 //
226 // Reference to SafeArrayAccessData() can be found at:
227 // https://learn.microsoft.com/en-us/windows/win32/api/oleauto/nf-oleauto-safearrayaccessdata
228 //
229
230 var nme, len, nn;
231 var properties = [];
232 var values = {};
233
234 j.funcs = require('win-com').marshalFunctions(j.Deref(), ResultFunctions);
235
236 // First we need to enumerate the COM Array
237 if (fields != null && Array.isArray(fields))
238 {
239 properties = fields;
240 }
241 else
242 {
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);
248
249
250 for (var i = 0; i < len; ++i)
251 {
252 var propName = nn.Deref().increment(i * GM.PointerSize).Deref().Wide2UTF8;
253 if (propName.length === 0) { continue; }
254 properties.push(propName);
255 }
256 }
257
258 // Now we need to introspect the Array Fields
259 for (var i = 0; i < properties.length; ++i)
260 {
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)
263 {
264 //
265 // Reference for IWbemClassObject::Get() can be found at:
266 // https://learn.microsoft.com/en-us/windows/win32/api/wbemcli/nf-wbemcli-iwbemclassobject-get
267 //
268
269 var vartype = tmp1.toBuffer().readUInt16LE();
270 var isArray = (vartype & 0x2000) != 0; // VT_ARRAY flag
271 var baseType = vartype & 0x0FFF;
272
273 if (isArray)
274 {
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);
280
281 var arrayValues = [];
282 for (var k = 0; k < arrayLength; ++k)
283 {
284 switch (baseType)
285 {
286 case 0x0002: // VT_I2
287 arrayValues.push(arrayData.Deref().Deref(k * 2, 2).toBuffer().readInt16LE());
288 break;
289 case 0x0003: // VT_I4
290 case 0x0016: // VT_INT
291 arrayValues.push(arrayData.Deref().Deref(k * 4, 4).toBuffer().readInt32LE());
292 break;
293 case 0x000B: // VT_BOOL
294 arrayValues.push(arrayData.Deref().Deref(k * 2, 2).toBuffer().readInt16LE() != 0);
295 break;
296 case 0x0010: // VT_I1
297 arrayValues.push(arrayData.Deref().Deref(k, 1).toBuffer().readInt8());
298 break;
299 case 0x0011: // VT_UI1
300 arrayValues.push(arrayData.Deref().Deref(k, 1).toBuffer().readUInt8());
301 break;
302 case 0x0012: // VT_UI2
303 arrayValues.push(arrayData.Deref().Deref(k * 2, 2).toBuffer().readUInt16LE());
304 break;
305 case 0x0013: // VT_UI4
306 case 0x0017: // VT_UINT
307 arrayValues.push(arrayData.Deref().Deref(k * 4, 4).toBuffer().readUInt32LE());
308 break;
309 case 0x0008: // VT_BSTR
310 arrayValues.push(arrayData.Deref().Deref(k * GM.PointerSize, GM.PointerSize).Deref().Wide2UTF8);
311 break;
312 }
313 }
314 values[properties[i]] = arrayValues;
315 }
316 else
317 {
318 // Handle scalar types
319 switch (vartype)
320 {
321 case 0x0000: // VT_EMPTY
322 case 0x0001: // VT_NULL
323 values[properties[i]] = null;
324 break;
325 case 0x0002: // VT_I2
326 values[properties[i]] = tmp1.Deref(8, GM.PointerSize).toBuffer().readInt16LE();
327 break;
328 case 0x0003: // VT_I4
329 case 0x0016: // VT_INT
330 values[properties[i]] = tmp1.Deref(8, GM.PointerSize).toBuffer().readInt32LE();
331 break;
332 case 0x000B: // VT_BOOL
333 values[properties[i]] = tmp1.Deref(8, GM.PointerSize).toBuffer().readInt32LE() != 0;
334 break;
335 case 0x000E: // VT_DECIMAL
336 break;
337 case 0x0010: // VT_I1
338 values[properties[i]] = tmp1.Deref(8, GM.PointerSize).toBuffer().readInt8();
339 break;
340 case 0x0011: // VT_UI1
341 values[properties[i]] = tmp1.Deref(8, GM.PointerSize).toBuffer().readUInt8();
342 break;
343 case 0x0012: // VT_UI2
344 values[properties[i]] = tmp1.Deref(8, GM.PointerSize).toBuffer().readUInt16LE();
345 break;
346 case 0x0013: // VT_UI4
347 case 0x0017: // VT_UINT
348 values[properties[i]] = tmp1.Deref(8, GM.PointerSize).toBuffer().readUInt32LE();
349 break;
350 //case 0x0014: // VT_I8
351 // break;
352 //case 0x0015: // VT_UI8
353 // break;
354 case 0x0008: // VT_BSTR
355 values[properties[i]] = tmp1.Deref(8, GM.PointerSize).Deref().Wide2UTF8;
356 break;
357 default:
358 console.info1('VARTYPE: ' + vartype);
359 break;
360 }
361 }
362 }
363 }
364
365 return (values);
366}
367
368function queryAsync(resourceString, queryString, fields)
369{
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();
375
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);
383
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'); }
386
387 handlers.services.funcs = require('win-com').marshalFunctions(handlers.services.Deref(), ServiceFunctions);
388 handlers.p = p;
389
390 // Make the COM call
391 if (handlers.services.funcs.ExecQueryAsync(handlers.services.Deref(), language, query, WBEM_FLAG_BIDIRECTIONAL, 0, handlers).Val != 0)
392 {
393 throw ('Error in Query');
394 }
395
396 // Hold a reference to the callback object
397 wmi_handlers[handlers._hashCode()] = handlers;
398 return (p);
399}
400function query(resourceString, queryString, fields)
401{
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();
406
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'); }
412
413 // Execute the Query
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'); }
416
417 results.funcs = require('win-com').marshalFunctions(results.Deref(), ResultsFunctions);
418 var returnedCount = GM.CreateVariable(8);
419 var result = GM.CreatePointer();
420 var ret = [];
421
422 // Enumerate the results
423 while (results.funcs.Next(results.Deref(), WBEM_INFINITE, 1, result, returnedCount).Val == 0)
424 {
425 ret.push(enumerateProperties(result, fields));
426 }
427
428 results.funcs.Release(results.Deref());
429 services.funcs.Release(services.Deref());
430 locator.funcs.Release(locator);
431
432 return (ret);
433}
434
435module.exports = { query: query, queryAsync: queryAsync };