master
h 575 lines 18.3 KB
Raw
1 // Copyright (C) Microsoft Corporation. All rights reserved.
2
3 #pragma once
4
5 // cpp headers
6 #include <vector>
7 #include <string>
8
9 // os headers
10 #include <Windows.h>
11 #include <objbase.h>
12 #include <wil/stl.h>
13 #include <wil/com.h>
14 #include <wil/resource.h>
15
16 // WmiMakeVariant(const ) functions are specializations designed to help callers
17 // who want a way to construct a VARIANT that is safe for passing into WMI
18 // since WMI has limitations on what VARIANT types it accepts
19 namespace wsl::core {
20 inline bool IsVariantEmptyOrNull(_In_ const VARIANT* variant) noexcept
21 {
22 return V_VT(variant) == VT_EMPTY || V_VT(variant) == VT_NULL;
23 }
24
25 inline wil::unique_variant WmiMakeVariant(const bool value)
26 {
27 wil::unique_variant localVariant;
28 V_VT(localVariant.addressof()) = VT_BOOL;
29 V_BOOL(localVariant.addressof()) = value ? TRUE : FALSE;
30 return localVariant;
31 }
32
33 inline bool WmiReadFromVariant(_In_ const VARIANT* variant, _Out_ bool* value)
34 {
35 if (IsVariantEmptyOrNull(variant))
36 {
37 return false;
38 }
39 THROW_HR_IF(E_INVALIDARG, V_VT(variant) != VT_BOOL);
40 *value = V_BOOL(variant);
41 return true;
42 }
43
44 inline wil::unique_variant WmiMakeVariant(const char value)
45 {
46 wil::unique_variant localVariant;
47 V_VT(localVariant.addressof()) = VT_UI1;
48 V_UI1(localVariant.addressof()) = value;
49 return localVariant;
50 }
51
52 inline bool WmiReadFromVariant(_In_ const VARIANT* variant, _Out_ char* value)
53 {
54 if (IsVariantEmptyOrNull(variant))
55 {
56 return false;
57 }
58 THROW_HR_IF(E_INVALIDARG, V_VT(variant) != VT_UI1);
59 *value = V_UI1(variant);
60 return true;
61 }
62
63 inline wil::unique_variant WmiMakeVariant(const unsigned char value)
64 {
65 wil::unique_variant localVariant;
66 V_VT(localVariant.addressof()) = VT_UI1;
67 V_UI1(localVariant.addressof()) = value;
68 return localVariant;
69 }
70
71 inline bool WmiReadFromVariant(_In_ const VARIANT* variant, _Out_ unsigned char* value)
72 {
73 if (IsVariantEmptyOrNull(variant))
74 {
75 return false;
76 }
77 THROW_HR_IF(E_INVALIDARG, V_VT(variant) != VT_UI1);
78 *value = V_UI1(variant);
79 return true;
80 }
81
82 inline wil::unique_variant WmiMakeVariant(const short value)
83 {
84 wil::unique_variant localVariant;
85 V_VT(localVariant.addressof()) = VT_I2;
86 V_I2(localVariant.addressof()) = value;
87 return localVariant;
88 }
89
90 inline bool WmiReadFromVariant(_In_ const VARIANT* variant, _Out_ short* value)
91 {
92 if (IsVariantEmptyOrNull(variant))
93 {
94 return false;
95 }
96 THROW_HR_IF(E_INVALIDARG, V_VT(variant) != VT_I2);
97 *value = V_I2(variant);
98 return true;
99 }
100
101 inline wil::unique_variant WmiMakeVariant(const unsigned short value)
102 {
103 wil::unique_variant localVariant;
104 V_VT(localVariant.addressof()) = VT_I2;
105 V_I2(localVariant.addressof()) = static_cast<short>(value);
106 return localVariant;
107 }
108
109 inline bool WmiReadFromVariant(_In_ const VARIANT* variant, _Out_ unsigned short* value)
110 {
111 if (IsVariantEmptyOrNull(variant))
112 {
113 return false;
114 }
115 THROW_HR_IF(E_INVALIDARG, V_VT(variant) != VT_I2);
116 *value = V_I2(variant);
117 return true;
118 }
119
120 inline wil::unique_variant WmiMakeVariant(const long value)
121 {
122 wil::unique_variant localVariant;
123 V_VT(localVariant.addressof()) = VT_I4;
124 V_I4(localVariant.addressof()) = value;
125 return localVariant;
126 }
127
128 inline bool WmiReadFromVariant(_In_ const VARIANT* variant, _Out_ long* value)
129 {
130 if (IsVariantEmptyOrNull(variant))
131 {
132 return false;
133 }
134 THROW_HR_IF(E_INVALIDARG, V_VT(variant) != VT_I4);
135 *value = V_I4(variant);
136 return true;
137 }
138
139 inline wil::unique_variant WmiMakeVariant(const unsigned long value)
140 {
141 wil::unique_variant localVariant;
142 V_VT(localVariant.addressof()) = VT_I4;
143 V_I4(localVariant.addressof()) = static_cast<long>(value);
144 return localVariant;
145 }
146
147 inline bool WmiReadFromVariant(_In_ const VARIANT* variant, _Out_ unsigned long* value)
148 {
149 if (IsVariantEmptyOrNull(variant))
150 {
151 return false;
152 }
153 THROW_HR_IF(E_INVALIDARG, V_VT(variant) != VT_I4);
154 *value = V_I4(variant);
155 return true;
156 }
157
158 inline wil::unique_variant WmiMakeVariant(const int value)
159 {
160 wil::unique_variant localVariant;
161 V_VT(localVariant.addressof()) = VT_I4;
162 V_I4(localVariant.addressof()) = value;
163 return localVariant;
164 }
165
166 inline bool WmiReadFromVariant(_In_ const VARIANT* variant, _Out_ int* value)
167 {
168 if (IsVariantEmptyOrNull(variant))
169 {
170 return false;
171 }
172 THROW_HR_IF(E_INVALIDARG, V_VT(variant) != VT_I4);
173 *value = V_I4(variant);
174 return true;
175 }
176
177 inline wil::unique_variant WmiMakeVariant(const unsigned int value)
178 {
179 wil::unique_variant localVariant;
180 V_VT(localVariant.addressof()) = VT_I4;
181 V_I4(localVariant.addressof()) = static_cast<long>(value);
182 return localVariant;
183 }
184
185 inline bool WmiReadFromVariant(_In_ const VARIANT* variant, _Out_ unsigned int* value)
186 {
187 if (IsVariantEmptyOrNull(variant))
188 {
189 return false;
190 }
191 THROW_HR_IF(E_INVALIDARG, V_VT(variant) != VT_I4);
192 *value = V_I4(variant);
193 return true;
194 }
195
196 inline wil::unique_variant WmiMakeVariant(const float value)
197 {
198 wil::unique_variant localVariant;
199 V_VT(localVariant.addressof()) = VT_R4;
200 V_R4(localVariant.addressof()) = value;
201 return localVariant;
202 }
203
204 inline bool WmiReadFromVariant(_In_ const VARIANT* variant, _Out_ float* value)
205 {
206 if (IsVariantEmptyOrNull(variant))
207 {
208 return false;
209 }
210 THROW_HR_IF(E_INVALIDARG, V_VT(variant) != VT_R4);
211 *value = V_R4(variant);
212 return true;
213 }
214
215 inline wil::unique_variant WmiMakeVariant(const double value)
216 {
217 wil::unique_variant localVariant;
218 V_VT(localVariant.addressof()) = VT_R8;
219 V_R8(localVariant.addressof()) = value;
220 return localVariant;
221 }
222
223 inline bool WmiReadFromVariant(_In_ const VARIANT* variant, _Out_ double* value)
224 {
225 if (IsVariantEmptyOrNull(variant))
226 {
227 return false;
228 }
229 THROW_HR_IF(E_INVALIDARG, V_VT(variant) != VT_R8);
230 *value = V_R8(variant);
231 return true;
232 }
233
234 inline wil::unique_variant WmiMakeVariant(SYSTEMTIME value)
235 {
236 wil::unique_variant localVariant;
237 DOUBLE time{};
238 THROW_HR_IF(E_INVALIDARG, !::SystemTimeToVariantTime(&value, &time));
239 V_VT(localVariant.addressof()) = VT_DATE;
240 V_DATE(localVariant.addressof()) = time;
241 return localVariant;
242 }
243
244 inline bool WmiReadFromVariant(_In_ const VARIANT* variant, _Out_ SYSTEMTIME* value)
245 {
246 if (IsVariantEmptyOrNull(variant))
247 {
248 return false;
249 }
250 THROW_HR_IF(E_INVALIDARG, V_VT(variant) != VT_DATE);
251 THROW_HR_IF(E_INVALIDARG, !::VariantTimeToSystemTime(V_DATE(variant), value));
252 return true;
253 }
254
255 inline wil::unique_variant WmiMakeVariant(_In_ const BSTR value) // NOLINT(misc-misplaced-const)
256 {
257 wil::unique_variant localVariant;
258 V_VT(localVariant.addressof()) = VT_BSTR;
259 V_BSTR(localVariant.addressof()) = SysAllocString(value);
260 THROW_IF_NULL_ALLOC(V_BSTR(localVariant.addressof()));
261 return localVariant;
262 }
263
264 inline bool WmiReadFromVariant(_In_ const VARIANT* variant, _Out_ BSTR* value)
265 {
266 if (IsVariantEmptyOrNull(variant))
267 {
268 return false;
269 }
270 THROW_HR_IF(E_INVALIDARG, V_VT(variant) != VT_BSTR);
271 *value = SysAllocString(V_BSTR(variant));
272 THROW_IF_NULL_ALLOC(*value);
273 return true;
274 }
275
276 inline wil::unique_variant WmiMakeVariant(_In_ PCWSTR value)
277 {
278 wil::unique_variant localVariant;
279 V_VT(localVariant.addressof()) = VT_BSTR;
280 V_BSTR(localVariant.addressof()) = SysAllocString(value);
281 THROW_IF_NULL_ALLOC(V_BSTR(localVariant.addressof()));
282 return localVariant;
283 }
284
285 inline bool WmiReadFromVariant(_In_ const VARIANT* variant, _Inout_ std::wstring* value)
286 {
287 if (IsVariantEmptyOrNull(variant))
288 {
289 return false;
290 }
291 THROW_HR_IF(E_INVALIDARG, V_VT(variant) != VT_BSTR);
292 value->assign(V_BSTR(variant));
293 return true;
294 }
295
296 // Even though VARIANTs support 64-bit integers, WMI passes them around as BSTRs
297 inline wil::unique_variant WmiMakeVariant(const unsigned long long value)
298 {
299 wil::unique_variant localVariant;
300 V_VT(localVariant.addressof()) = VT_BSTR;
301 V_BSTR(localVariant.addressof()) = SysAllocString(std::to_wstring(value).c_str());
302 THROW_IF_NULL_ALLOC(V_BSTR(localVariant.addressof()));
303 return localVariant;
304 }
305
306 inline bool WmiReadFromVariant(_In_ const VARIANT* variant, _Out_ unsigned long long* value)
307 {
308 *value = 0;
309 if (IsVariantEmptyOrNull(variant))
310 {
311 return false;
312 }
313 THROW_HR_IF(E_INVALIDARG, V_VT(variant) != VT_BSTR);
314 *value = _wcstoui64(V_BSTR(variant), nullptr, 10);
315 return true;
316 }
317
318 // Even though VARIANTs support 64-bit integers, WMI passes them around as BSTRs
319 inline wil::unique_variant WmiMakeVariant(_In_ const long long value)
320 {
321 wil::unique_variant localVariant;
322 V_VT(localVariant.addressof()) = VT_BSTR;
323 V_BSTR(localVariant.addressof()) = SysAllocString(std::to_wstring(value).c_str());
324 THROW_IF_NULL_ALLOC(V_BSTR(localVariant.addressof()));
325 return localVariant;
326 }
327
328 inline bool WmiReadFromVariant(_In_ const VARIANT* variant, _Out_ long long* value)
329 {
330 *value = 0;
331 if (IsVariantEmptyOrNull(variant))
332 {
333 return false;
334 }
335 THROW_HR_IF(E_INVALIDARG, V_VT(variant) != VT_BSTR);
336 *value = _wcstoi64(V_BSTR(variant), nullptr, 10);
337 return true;
338 }
339
340 template <typename T>
341 wil::unique_variant WmiMakeVariant(const wil::com_ptr<T>& value) noexcept
342 {
343 wil::unique_variant variant;
344 V_VT(&variant) = VT_UNKNOWN;
345 V_UNKNOWN(variant.addressof()) = value.get();
346 // Must deliberately AddRef the raw pointer assigned to punkVal in the variant
347 V_UNKNOWN(variant.addressof())->AddRef();
348 return variant;
349 }
350
351 template <typename T>
352 bool WmiReadFromVariant(_In_ const VARIANT* variant, _Inout_ wil::com_ptr<T>* value)
353 {
354 if (IsVariantEmptyOrNull(variant))
355 {
356 return false;
357 }
358 THROW_HR_IF(E_INVALIDARG, V_VT(variant) != VT_UNKNOWN);
359 THROW_IF_FAILED(V_UNKNOWN(variant)->QueryInterface(__uuidof(T), reinterpret_cast<void**>(value->put())));
360 return true;
361 }
362
363 template <typename T>
364 bool WmiReadFromVariant(_In_ const VARIANT* variant, _Inout_ std::vector<wil::com_ptr<T>>* value)
365 {
366 if (IsVariantEmptyOrNull(variant))
367 {
368 return false;
369 }
370 THROW_HR_IF(E_INVALIDARG, V_VT(variant) != (VT_UNKNOWN | VT_ARRAY));
371
372 IUnknown** iUnknownArray;
373 THROW_IF_FAILED(::SafeArrayAccessData(variant->parray, reinterpret_cast<void**>(&iUnknownArray)));
374 const auto unaccessArray = wil::scope_exit([&]() noexcept { SafeArrayUnaccessData(variant->parray); });
375
376 std::vector<wil::com_ptr<T>> tempData;
377 for (auto loop = 0ul; loop < variant->parray->rgsabound[0].cElements; ++loop)
378 {
379 wil::com_ptr<T> tempPtr;
380 THROW_IF_FAILED(iUnknownArray[loop]->QueryInterface(__uuidof(T), reinterpret_cast<void**>(tempPtr.put())));
381 tempData.push_back(tempPtr);
382 }
383 value->swap(tempData);
384 return true;
385 }
386
387 inline wil::unique_variant WmiMakeVariant(const std::vector<std::wstring>& data)
388 {
389 auto* const tempSafeArray = SafeArrayCreateVector(VT_BSTR, 0, static_cast<ULONG>(data.size()));
390 THROW_IF_NULL_ALLOC(tempSafeArray);
391 auto guardArray = wil::scope_exit([&]() noexcept { SafeArrayDestroy(tempSafeArray); });
392
393 for (size_t loop = 0; loop < data.size(); ++loop)
394 {
395 // SafeArrayPutElement requires an array of indexes for each dimension of the array
396 // - in this case, we have a 1-dimensional array, thus an array of 1 LONG - assigned to the loop variable
397 long index[1]{static_cast<long>(loop)};
398
399 auto* const bstr = SysAllocString(data[loop].c_str());
400 THROW_IF_NULL_ALLOC(bstr);
401 THROW_IF_FAILED(::SafeArrayPutElement(tempSafeArray, index, bstr));
402 }
403
404 wil::unique_variant variant;
405 variant.parray = tempSafeArray;
406 variant.vt = VT_BSTR | VT_ARRAY;
407
408 // don't free the SAFEARRAY on success - its lifetime is transferred to variant
409 guardArray.release();
410 return variant;
411 }
412
413 inline bool WmiReadFromVariant(_In_ const VARIANT* variant, _Inout_ std::vector<std::wstring>* value)
414 {
415 if (IsVariantEmptyOrNull(variant))
416 {
417 return false;
418 }
419 THROW_HR_IF(E_INVALIDARG, V_VT(variant) != (VT_BSTR | VT_ARRAY));
420
421 BSTR* stringArray{};
422 THROW_IF_FAILED(::SafeArrayAccessData(variant->parray, reinterpret_cast<void**>(&stringArray)));
423 const auto unaccessArray = wil::scope_exit([&]() noexcept { SafeArrayUnaccessData(variant->parray); });
424
425 std::vector<std::wstring> tempData;
426 for (auto loop = 0ul; loop < variant->parray->rgsabound[0].cElements; ++loop)
427 {
428 tempData.emplace_back(stringArray[loop]);
429 }
430 value->swap(tempData);
431 return true;
432 }
433
434 inline wil::unique_variant WmiMakeVariant(const std::vector<uint32_t>& data)
435 {
436 auto* const tempSafeArray = SafeArrayCreateVector(VT_UI4, 0, static_cast<ULONG>(data.size()));
437 THROW_IF_NULL_ALLOC(tempSafeArray);
438 auto guardArray = wil::scope_exit([&]() noexcept { SafeArrayDestroy(tempSafeArray); });
439
440 for (size_t loop = 0; loop < data.size(); ++loop)
441 {
442 // SafeArrayPutElement requires an array of indexes for each dimension of the array
443 // - in this case, we have a 1-dimensional array, thus an array of 1 LONG - assigned to the loop variable
444 long index[1]{static_cast<long>(loop)};
445
446 uint32_t value = data[loop];
447 THROW_IF_FAILED(::SafeArrayPutElement(tempSafeArray, index, &value));
448 }
449
450 wil::unique_variant variant;
451 variant.parray = tempSafeArray;
452 variant.vt = VT_UI4 | VT_ARRAY;
453
454 // don't free the SAFEARRAY on success - its lifetime is transferred to variant
455 guardArray.release();
456 return variant;
457 }
458
459 inline bool WmiReadFromVariant(_In_ const VARIANT* variant, _Inout_ std::vector<uint32_t>* value)
460 {
461 if (IsVariantEmptyOrNull(variant))
462 {
463 return false;
464 }
465 THROW_HR_IF(E_INVALIDARG, V_VT(variant) != (VT_UI4 | VT_ARRAY));
466
467 uint32_t* intArray{};
468 THROW_IF_FAILED(::SafeArrayAccessData(variant->parray, reinterpret_cast<void**>(&intArray)));
469 const auto unaccessArray = wil::scope_exit([&]() noexcept { SafeArrayUnaccessData(variant->parray); });
470
471 std::vector<uint32_t> tempData;
472 for (auto loop = 0ul; loop < variant->parray->rgsabound[0].cElements; ++loop)
473 {
474 tempData.push_back(intArray[loop]);
475 }
476 value->swap(tempData);
477 return true;
478 }
479
480 inline wil::unique_variant WmiMakeVariant(const std::vector<unsigned short>& data)
481 {
482 // WMI marshaler complains type mismatch using VT_UI2 | VT_ARRAY, and VT_I4 | VT_ARRAY works fine.
483 auto* const tempSafeArray = SafeArrayCreateVector(VT_I4, 0, static_cast<ULONG>(data.size()));
484 THROW_IF_NULL_ALLOC(tempSafeArray);
485 auto guardArray = wil::scope_exit([&]() noexcept { SafeArrayDestroy(tempSafeArray); });
486
487 for (size_t loop = 0; loop < data.size(); ++loop)
488 {
489 // SafeArrayPutElement requires an array of indexes for each dimension of the array
490 // - in this case, we have a 1-dimensional array, thus an array of 1 LONG - assigned to the loop variable
491 long index[1]{static_cast<long>(loop)};
492
493 // Expand unsigned short to long because the SAFEARRAY created assumes VT_I4 elements
494 long value = data[loop];
495 THROW_IF_FAILED(::SafeArrayPutElement(tempSafeArray, index, &value));
496 }
497
498 wil::unique_variant variant;
499 variant.parray = tempSafeArray;
500 variant.vt = VT_I4 | VT_ARRAY;
501
502 // don't free the SAFEARRAY on success - its lifetime is transferred to variant
503 guardArray.release();
504 return variant;
505 }
506
507 inline bool WmiReadFromVariant(_In_ const VARIANT* variant, _Inout_ std::vector<unsigned short>* value)
508 {
509 // WMI marshaler complains type mismatch using VT_UI2 | VT_ARRAY, and VT_I4 | VT_ARRAY works fine.
510 if (IsVariantEmptyOrNull(variant))
511 {
512 return false;
513 }
514 THROW_HR_IF(E_INVALIDARG, V_VT(variant) != (VT_I4 | VT_ARRAY));
515
516 long* intArray{};
517 THROW_IF_FAILED(::SafeArrayAccessData(variant->parray, reinterpret_cast<void**>(&intArray)));
518 const auto unaccessArray = wil::scope_exit([&]() noexcept { SafeArrayUnaccessData(variant->parray); });
519
520 std::vector<unsigned short> tempData;
521 for (auto loop = 0ul; loop < variant->parray->rgsabound[0].cElements; ++loop)
522 {
523 THROW_HR_IF(E_INVALIDARG, intArray[loop] > MAXUINT16);
524 tempData.push_back(static_cast<unsigned short>(intArray[loop]));
525 }
526 value->swap(tempData);
527 return true;
528 }
529
530 inline wil::unique_variant WmiMakeVariant(const std::vector<unsigned char>& data)
531 {
532 auto* const tempSafeArray = SafeArrayCreateVector(VT_UI1, 0, static_cast<ULONG>(data.size()));
533 THROW_IF_NULL_ALLOC(tempSafeArray);
534 auto guardArray = wil::scope_exit([&]() noexcept { SafeArrayDestroy(tempSafeArray); });
535
536 for (size_t loop = 0; loop < data.size(); ++loop)
537 {
538 // SafeArrayPutElement requires an array of indexes for each dimension of the array
539 // - in this case, we have a 1-dimensional array, thus an array of 1 LONG - assigned to the loop variable
540 long index[1]{static_cast<long>(loop)};
541
542 unsigned char value = data[loop];
543 THROW_IF_FAILED(::SafeArrayPutElement(tempSafeArray, index, &value));
544 }
545
546 wil::unique_variant variant;
547 variant.parray = tempSafeArray;
548 variant.vt = VT_UI1 | VT_ARRAY;
549
550 // don't free the SAFEARRAY on success - its lifetime is transferred to variant
551 guardArray.release();
552 return variant;
553 }
554
555 inline bool WmiReadFromVariant(_In_ const VARIANT* variant, _Inout_ std::vector<unsigned char>* value)
556 {
557 if (IsVariantEmptyOrNull(variant))
558 {
559 return false;
560 }
561 THROW_HR_IF(E_INVALIDARG, V_VT(variant) != (VT_UI1 | VT_ARRAY));
562
563 unsigned char* charArray{};
564 THROW_IF_FAILED(::SafeArrayAccessData(variant->parray, reinterpret_cast<void**>(&charArray)));
565 const auto unaccessArray = wil::scope_exit([&]() noexcept { SafeArrayUnaccessData(variant->parray); });
566
567 std::vector<unsigned char> tempData;
568 for (auto loop = 0ul; loop < variant->parray->rgsabound[0].cElements; ++loop)
569 {
570 tempData.push_back(charArray[loop]);
571 }
572 value->swap(tempData);
573 return true;
574 }
575 } // namespace wsl::core