| 
									
										
										
										
											2022-09-07 21:09:20 +01:00
										 |  |  | //
 | 
					
						
							|  |  |  | // Helper library for querying WMI using its COM-based query API.
 | 
					
						
							|  |  |  | //
 | 
					
						
							|  |  |  | // Copyright (c) Microsoft Corporation
 | 
					
						
							|  |  |  | // Licensed to PSF under a contributor agreement
 | 
					
						
							|  |  |  | //
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // Version history
 | 
					
						
							|  |  |  | //  2022-08: Initial contribution (Steve Dower)
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-10-17 14:30:31 +02:00
										 |  |  | // clinic/_wmimodule.cpp.h uses internal pycore_modsupport.h API
 | 
					
						
							|  |  |  | #ifndef Py_BUILD_CORE_BUILTIN
 | 
					
						
							|  |  |  | #  define Py_BUILD_CORE_MODULE 1
 | 
					
						
							|  |  |  | #endif
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-09-07 21:09:20 +01:00
										 |  |  | #define _WIN32_DCOM
 | 
					
						
							|  |  |  | #include <Windows.h>
 | 
					
						
							|  |  |  | #include <comdef.h>
 | 
					
						
							|  |  |  | #include <Wbemidl.h>
 | 
					
						
							|  |  |  | #include <propvarutil.h>
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | #include <Python.h>
 | 
					
						
							| 
									
										
										
										
											2022-09-07 22:53:33 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-01-09 11:48:24 -06:00
										 |  |  | #if _MSVC_LANG >= 202002L
 | 
					
						
							| 
									
										
										
										
											2022-09-07 22:53:33 +01:00
										 |  |  | // We can use clinic directly when the C++ compiler supports C++20
 | 
					
						
							| 
									
										
										
										
											2022-09-07 21:09:20 +01:00
										 |  |  | #include "clinic/_wmimodule.cpp.h"
 | 
					
						
							| 
									
										
										
										
											2022-09-07 22:53:33 +01:00
										 |  |  | #else
 | 
					
						
							|  |  |  | // Cannot use clinic because of missing C++20 support, so create a simpler
 | 
					
						
							|  |  |  | // API instead. This won't impact releases, so fine to omit the docstring.
 | 
					
						
							|  |  |  | static PyObject *_wmi_exec_query_impl(PyObject *module, PyObject *query); | 
					
						
							|  |  |  | #define _WMI_EXEC_QUERY_METHODDEF {"exec_query", _wmi_exec_query_impl, METH_O, NULL},
 | 
					
						
							|  |  |  | #endif
 | 
					
						
							| 
									
										
										
										
											2022-09-07 21:09:20 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /*[clinic input]
 | 
					
						
							|  |  |  | module _wmi | 
					
						
							|  |  |  | [clinic start generated code]*/ | 
					
						
							|  |  |  | /*[clinic end generated code: output=da39a3ee5e6b4b0d input=7ca95dad1453d10d]*/ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | struct _query_data { | 
					
						
							|  |  |  |     LPCWSTR query; | 
					
						
							|  |  |  |     HANDLE writePipe; | 
					
						
							|  |  |  |     HANDLE readPipe; | 
					
						
							| 
									
										
										
										
											2023-12-09 00:52:22 +08:00
										 |  |  |     HANDLE initEvent; | 
					
						
							| 
									
										
										
										
											2023-12-08 01:26:29 +08:00
										 |  |  |     HANDLE connectEvent; | 
					
						
							| 
									
										
										
										
											2022-09-07 21:09:20 +01:00
										 |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static DWORD WINAPI | 
					
						
							|  |  |  | _query_thread(LPVOID param) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     IWbemLocator *locator = NULL; | 
					
						
							|  |  |  |     IWbemServices *services = NULL; | 
					
						
							|  |  |  |     IEnumWbemClassObject* enumerator = NULL; | 
					
						
							|  |  |  |     BSTR bstrQuery = NULL; | 
					
						
							|  |  |  |     struct _query_data *data = (struct _query_data*)param; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     HRESULT hr = CoInitializeEx(nullptr, COINIT_APARTMENTTHREADED); | 
					
						
							|  |  |  |     if (FAILED(hr)) { | 
					
						
							|  |  |  |         CloseHandle(data->writePipe); | 
					
						
							|  |  |  |         return (DWORD)hr; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     hr = CoInitializeSecurity( | 
					
						
							|  |  |  |         NULL, -1, NULL, NULL, | 
					
						
							|  |  |  |         RPC_C_AUTHN_LEVEL_DEFAULT, | 
					
						
							|  |  |  |         RPC_C_IMP_LEVEL_IMPERSONATE, | 
					
						
							|  |  |  |         NULL, EOAC_NONE, NULL | 
					
						
							|  |  |  |     ); | 
					
						
							| 
									
										
										
										
											2022-09-08 22:02:04 +01:00
										 |  |  |     // gh-96684: CoInitializeSecurity will fail if another part of the app has
 | 
					
						
							|  |  |  |     // already called it. Hopefully they passed lenient enough settings that we
 | 
					
						
							|  |  |  |     // can complete the WMI query, so keep going.
 | 
					
						
							|  |  |  |     if (hr == RPC_E_TOO_LATE) { | 
					
						
							|  |  |  |         hr = 0; | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2022-09-07 21:09:20 +01:00
										 |  |  |     if (SUCCEEDED(hr)) { | 
					
						
							|  |  |  |         hr = CoCreateInstance( | 
					
						
							|  |  |  |             CLSID_WbemLocator, 0, CLSCTX_INPROC_SERVER, | 
					
						
							|  |  |  |             IID_IWbemLocator, (LPVOID *)&locator | 
					
						
							|  |  |  |         ); | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2023-12-09 00:52:22 +08:00
										 |  |  |     if (SUCCEEDED(hr) && !SetEvent(data->initEvent)) { | 
					
						
							|  |  |  |         hr = HRESULT_FROM_WIN32(GetLastError()); | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2022-09-07 21:09:20 +01:00
										 |  |  |     if (SUCCEEDED(hr)) { | 
					
						
							|  |  |  |         hr = locator->ConnectServer( | 
					
						
							|  |  |  |             bstr_t(L"ROOT\\CIMV2"), | 
					
						
							|  |  |  |             NULL, NULL, 0, NULL, 0, 0, &services | 
					
						
							|  |  |  |         ); | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2023-12-09 00:52:22 +08:00
										 |  |  |     if (SUCCEEDED(hr) && !SetEvent(data->connectEvent)) { | 
					
						
							| 
									
										
										
										
											2023-12-08 01:26:29 +08:00
										 |  |  |         hr = HRESULT_FROM_WIN32(GetLastError()); | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2022-09-07 21:09:20 +01:00
										 |  |  |     if (SUCCEEDED(hr)) { | 
					
						
							|  |  |  |         hr = CoSetProxyBlanket( | 
					
						
							|  |  |  |             services, RPC_C_AUTHN_WINNT, RPC_C_AUTHZ_NONE, NULL, | 
					
						
							|  |  |  |             RPC_C_AUTHN_LEVEL_CALL, RPC_C_IMP_LEVEL_IMPERSONATE, | 
					
						
							|  |  |  |             NULL, EOAC_NONE | 
					
						
							|  |  |  |         ); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     if (SUCCEEDED(hr)) { | 
					
						
							|  |  |  |         bstrQuery = SysAllocString(data->query); | 
					
						
							|  |  |  |         if (!bstrQuery) { | 
					
						
							|  |  |  |             hr = HRESULT_FROM_WIN32(ERROR_NOT_ENOUGH_MEMORY); | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     if (SUCCEEDED(hr)) { | 
					
						
							|  |  |  |         hr = services->ExecQuery( | 
					
						
							| 
									
										
										
										
											2023-01-09 11:48:24 -06:00
										 |  |  |             bstr_t("WQL"), | 
					
						
							| 
									
										
										
										
											2022-09-07 21:09:20 +01:00
										 |  |  |             bstrQuery, | 
					
						
							| 
									
										
										
										
											2023-01-09 11:48:24 -06:00
										 |  |  |             WBEM_FLAG_FORWARD_ONLY | WBEM_FLAG_RETURN_IMMEDIATELY, | 
					
						
							| 
									
										
										
										
											2022-09-07 21:09:20 +01:00
										 |  |  |             NULL, | 
					
						
							|  |  |  |             &enumerator | 
					
						
							|  |  |  |         ); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     // Okay, after all that, at this stage we should have an enumerator
 | 
					
						
							|  |  |  |     // to the query results and can start writing them to the pipe!
 | 
					
						
							|  |  |  |     IWbemClassObject *value = NULL; | 
					
						
							|  |  |  |     int startOfEnum = TRUE; | 
					
						
							|  |  |  |     int endOfEnum = FALSE; | 
					
						
							|  |  |  |     while (SUCCEEDED(hr) && !endOfEnum) { | 
					
						
							|  |  |  |         ULONG got = 0; | 
					
						
							|  |  |  |         DWORD written; | 
					
						
							|  |  |  |         hr = enumerator->Next(WBEM_INFINITE, 1, &value, &got); | 
					
						
							|  |  |  |         if (hr == WBEM_S_FALSE) { | 
					
						
							|  |  |  |             // Could be at the end, but still got a result this time
 | 
					
						
							|  |  |  |             endOfEnum = TRUE; | 
					
						
							|  |  |  |             hr = 0; | 
					
						
							|  |  |  |             break; | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |         if (FAILED(hr) || got != 1 || !value) { | 
					
						
							|  |  |  |             continue; | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |         if (!startOfEnum && !WriteFile(data->writePipe, (LPVOID)L"\0", 2, &written, NULL)) { | 
					
						
							|  |  |  |             hr = HRESULT_FROM_WIN32(GetLastError()); | 
					
						
							|  |  |  |             break; | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |         startOfEnum = FALSE; | 
					
						
							|  |  |  |         // Okay, now we have each resulting object it's time to
 | 
					
						
							|  |  |  |         // enumerate its members
 | 
					
						
							|  |  |  |         hr = value->BeginEnumeration(0); | 
					
						
							|  |  |  |         if (FAILED(hr)) { | 
					
						
							|  |  |  |             value->Release(); | 
					
						
							|  |  |  |             break; | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |         while (SUCCEEDED(hr)) { | 
					
						
							|  |  |  |             BSTR propName; | 
					
						
							|  |  |  |             VARIANT propValue; | 
					
						
							|  |  |  |             long flavor; | 
					
						
							|  |  |  |             hr = value->Next(0, &propName, &propValue, NULL, &flavor); | 
					
						
							|  |  |  |             if (hr == WBEM_S_NO_MORE_DATA) { | 
					
						
							|  |  |  |                 hr = 0; | 
					
						
							|  |  |  |                 break; | 
					
						
							|  |  |  |             } | 
					
						
							|  |  |  |             if (SUCCEEDED(hr) && (flavor & WBEM_FLAVOR_MASK_ORIGIN) != WBEM_FLAVOR_ORIGIN_SYSTEM) { | 
					
						
							|  |  |  |                 WCHAR propStr[8192]; | 
					
						
							|  |  |  |                 hr = VariantToString(propValue, propStr, sizeof(propStr) / sizeof(propStr[0])); | 
					
						
							|  |  |  |                 if (SUCCEEDED(hr)) { | 
					
						
							|  |  |  |                     DWORD cbStr1, cbStr2; | 
					
						
							|  |  |  |                     cbStr1 = (DWORD)(wcslen(propName) * sizeof(propName[0])); | 
					
						
							|  |  |  |                     cbStr2 = (DWORD)(wcslen(propStr) * sizeof(propStr[0])); | 
					
						
							|  |  |  |                     if (!WriteFile(data->writePipe, propName, cbStr1, &written, NULL) || | 
					
						
							|  |  |  |                         !WriteFile(data->writePipe, (LPVOID)L"=", 2, &written, NULL) || | 
					
						
							|  |  |  |                         !WriteFile(data->writePipe, propStr, cbStr2, &written, NULL) || | 
					
						
							|  |  |  |                         !WriteFile(data->writePipe, (LPVOID)L"\0", 2, &written, NULL) | 
					
						
							|  |  |  |                     ) { | 
					
						
							|  |  |  |                         hr = HRESULT_FROM_WIN32(GetLastError()); | 
					
						
							|  |  |  |                     } | 
					
						
							|  |  |  |                 } | 
					
						
							|  |  |  |                 VariantClear(&propValue); | 
					
						
							|  |  |  |                 SysFreeString(propName); | 
					
						
							|  |  |  |             } | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |         value->EndEnumeration(); | 
					
						
							|  |  |  |         value->Release(); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     if (bstrQuery) { | 
					
						
							|  |  |  |         SysFreeString(bstrQuery); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     if (enumerator) { | 
					
						
							|  |  |  |         enumerator->Release(); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     if (services) { | 
					
						
							|  |  |  |         services->Release(); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     if (locator) { | 
					
						
							|  |  |  |         locator->Release(); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     CoUninitialize(); | 
					
						
							|  |  |  |     CloseHandle(data->writePipe); | 
					
						
							|  |  |  |     return (DWORD)hr; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-12-09 00:52:22 +08:00
										 |  |  | static DWORD | 
					
						
							|  |  |  | wait_event(HANDLE event, DWORD timeout) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     DWORD err = 0; | 
					
						
							|  |  |  |     switch (WaitForSingleObject(event, timeout)) { | 
					
						
							|  |  |  |     case WAIT_OBJECT_0: | 
					
						
							|  |  |  |         break; | 
					
						
							|  |  |  |     case WAIT_TIMEOUT: | 
					
						
							|  |  |  |         err = WAIT_TIMEOUT; | 
					
						
							|  |  |  |         break; | 
					
						
							|  |  |  |     default: | 
					
						
							|  |  |  |         err = GetLastError(); | 
					
						
							|  |  |  |         break; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     return err; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-09-07 21:09:20 +01:00
										 |  |  | /*[clinic input]
 | 
					
						
							|  |  |  | _wmi.exec_query | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     query: unicode | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | Runs a WMI query against the local machine. | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | This returns a single string with 'name=value' pairs in a flat array separated | 
					
						
							|  |  |  | by null characters. | 
					
						
							|  |  |  | [clinic start generated code]*/ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static PyObject * | 
					
						
							|  |  |  | _wmi_exec_query_impl(PyObject *module, PyObject *query) | 
					
						
							|  |  |  | /*[clinic end generated code: output=a62303d5bb5e003f input=48d2d0a1e1a7e3c2]*/ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /*[clinic end generated code]*/ | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     PyObject *result = NULL; | 
					
						
							|  |  |  |     HANDLE hThread = NULL; | 
					
						
							|  |  |  |     int err = 0; | 
					
						
							|  |  |  |     WCHAR buffer[8192]; | 
					
						
							|  |  |  |     DWORD offset = 0; | 
					
						
							|  |  |  |     DWORD bytesRead; | 
					
						
							|  |  |  |     struct _query_data data = {0}; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     if (PySys_Audit("_wmi.exec_query", "O", query) < 0) { | 
					
						
							|  |  |  |         return NULL; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     data.query = PyUnicode_AsWideCharString(query, NULL); | 
					
						
							|  |  |  |     if (!data.query) { | 
					
						
							|  |  |  |         return NULL; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     if (0 != _wcsnicmp(data.query, L"select ", 7)) { | 
					
						
							|  |  |  |         PyMem_Free((void *)data.query); | 
					
						
							|  |  |  |         PyErr_SetString(PyExc_ValueError, "only SELECT queries are supported"); | 
					
						
							|  |  |  |         return NULL; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     Py_BEGIN_ALLOW_THREADS | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-12-09 00:52:22 +08:00
										 |  |  |     data.initEvent = CreateEvent(NULL, TRUE, FALSE, NULL); | 
					
						
							| 
									
										
										
										
											2023-12-08 01:26:29 +08:00
										 |  |  |     data.connectEvent = CreateEvent(NULL, TRUE, FALSE, NULL); | 
					
						
							| 
									
										
										
										
											2023-12-09 00:52:22 +08:00
										 |  |  |     if (!data.initEvent || !data.connectEvent || | 
					
						
							|  |  |  |         !CreatePipe(&data.readPipe, &data.writePipe, NULL, 0)) | 
					
						
							|  |  |  |     { | 
					
						
							| 
									
										
										
										
											2022-09-07 21:09:20 +01:00
										 |  |  |         err = GetLastError(); | 
					
						
							|  |  |  |     } else { | 
					
						
							|  |  |  |         hThread = CreateThread(NULL, 0, _query_thread, (LPVOID*)&data, 0, NULL); | 
					
						
							|  |  |  |         if (!hThread) { | 
					
						
							|  |  |  |             err = GetLastError(); | 
					
						
							|  |  |  |             // Normally the thread proc closes this handle, but since we never started
 | 
					
						
							|  |  |  |             // we need to close it here.
 | 
					
						
							|  |  |  |             CloseHandle(data.writePipe); | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-12-08 01:26:29 +08:00
										 |  |  |     // gh-112278: If current user doesn't have permission to query the WMI, the
 | 
					
						
							|  |  |  |     // function IWbemLocator::ConnectServer will hang for 5 seconds, and there
 | 
					
						
							|  |  |  |     // is no way to specify the timeout. So we use an Event object to simulate
 | 
					
						
							| 
									
										
										
										
											2023-12-09 00:52:22 +08:00
										 |  |  |     // a timeout.  The initEvent will be set after COM initialization, it will
 | 
					
						
							|  |  |  |     // take a longer time when first initialized.  The connectEvent will be set
 | 
					
						
							|  |  |  |     // after connected to WMI.
 | 
					
						
							|  |  |  |     if (!err) { | 
					
						
							| 
									
										
										
										
											2024-04-15 15:43:11 +01:00
										 |  |  |         err = wait_event(data.initEvent, 1000); | 
					
						
							|  |  |  |         if (!err) { | 
					
						
							|  |  |  |             err = wait_event(data.connectEvent, 100); | 
					
						
							|  |  |  |         } | 
					
						
							| 
									
										
										
										
											2023-12-08 01:26:29 +08:00
										 |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-09-07 21:09:20 +01:00
										 |  |  |     while (!err) { | 
					
						
							|  |  |  |         if (ReadFile( | 
					
						
							|  |  |  |             data.readPipe, | 
					
						
							|  |  |  |             (LPVOID)&buffer[offset / sizeof(buffer[0])], | 
					
						
							|  |  |  |             sizeof(buffer) - offset, | 
					
						
							|  |  |  |             &bytesRead, | 
					
						
							|  |  |  |             NULL | 
					
						
							|  |  |  |         )) { | 
					
						
							|  |  |  |             offset += bytesRead; | 
					
						
							|  |  |  |             if (offset >= sizeof(buffer)) { | 
					
						
							|  |  |  |                 err = ERROR_MORE_DATA; | 
					
						
							|  |  |  |             } | 
					
						
							|  |  |  |         } else { | 
					
						
							|  |  |  |             err = GetLastError(); | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     if (data.readPipe) { | 
					
						
							|  |  |  |         CloseHandle(data.readPipe); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-04-15 15:43:11 +01:00
										 |  |  |     if (hThread) { | 
					
						
							|  |  |  |         // Allow the thread some time to clean up
 | 
					
						
							|  |  |  |         int thread_err; | 
					
						
							|  |  |  |         switch (WaitForSingleObject(hThread, 100)) { | 
					
						
							|  |  |  |         case WAIT_OBJECT_0: | 
					
						
							|  |  |  |             // Thread ended cleanly
 | 
					
						
							|  |  |  |             if (!GetExitCodeThread(hThread, (LPDWORD)&thread_err)) { | 
					
						
							|  |  |  |                 thread_err = GetLastError(); | 
					
						
							|  |  |  |             } | 
					
						
							|  |  |  |             break; | 
					
						
							|  |  |  |         case WAIT_TIMEOUT: | 
					
						
							|  |  |  |             // Probably stuck - there's not much we can do, unfortunately
 | 
					
						
							|  |  |  |             thread_err = WAIT_TIMEOUT; | 
					
						
							|  |  |  |             break; | 
					
						
							|  |  |  |         default: | 
					
						
							|  |  |  |             thread_err = GetLastError(); | 
					
						
							|  |  |  |             break; | 
					
						
							| 
									
										
										
										
											2022-09-07 21:09:20 +01:00
										 |  |  |         } | 
					
						
							| 
									
										
										
										
											2024-04-15 15:43:11 +01:00
										 |  |  |         // An error on our side is more likely to be relevant than one from
 | 
					
						
							|  |  |  |         // the thread, but if we don't have one on our side we'll take theirs.
 | 
					
						
							| 
									
										
										
										
											2022-09-07 21:09:20 +01:00
										 |  |  |         if (err == 0 || err == ERROR_BROKEN_PIPE) { | 
					
						
							| 
									
										
										
										
											2024-04-15 15:43:11 +01:00
										 |  |  |             err = thread_err; | 
					
						
							| 
									
										
										
										
											2022-09-07 21:09:20 +01:00
										 |  |  |         } | 
					
						
							| 
									
										
										
										
											2024-04-15 15:43:11 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  |         CloseHandle(hThread); | 
					
						
							| 
									
										
										
										
											2022-09-07 21:09:20 +01:00
										 |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-12-09 00:52:22 +08:00
										 |  |  |     CloseHandle(data.initEvent); | 
					
						
							| 
									
										
										
										
											2023-12-08 01:26:29 +08:00
										 |  |  |     CloseHandle(data.connectEvent); | 
					
						
							| 
									
										
										
										
											2022-09-07 21:09:20 +01:00
										 |  |  |     hThread = NULL; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     Py_END_ALLOW_THREADS | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     PyMem_Free((void *)data.query); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     if (err == ERROR_MORE_DATA) { | 
					
						
							|  |  |  |         PyErr_Format(PyExc_OSError, "Query returns more than %zd characters", Py_ARRAY_LENGTH(buffer)); | 
					
						
							|  |  |  |         return NULL; | 
					
						
							|  |  |  |     } else if (err) { | 
					
						
							|  |  |  |         PyErr_SetFromWindowsErr(err); | 
					
						
							|  |  |  |         return NULL; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     if (!offset) { | 
					
						
							|  |  |  |         return PyUnicode_FromStringAndSize(NULL, 0); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     return PyUnicode_FromWideChar(buffer, offset  / sizeof(buffer[0]) - 1); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static PyMethodDef wmi_functions[] = { | 
					
						
							|  |  |  |     _WMI_EXEC_QUERY_METHODDEF | 
					
						
							|  |  |  |     { NULL, NULL, 0, NULL } | 
					
						
							|  |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-05-06 20:07:23 -07:00
										 |  |  | static PyModuleDef_Slot wmi_slots[] = { | 
					
						
							|  |  |  |     {Py_mod_gil, Py_MOD_GIL_NOT_USED}, | 
					
						
							|  |  |  |     {0, NULL}, | 
					
						
							|  |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-09-07 21:09:20 +01:00
										 |  |  | static PyModuleDef wmi_def = { | 
					
						
							|  |  |  |     PyModuleDef_HEAD_INIT, | 
					
						
							|  |  |  |     "_wmi", | 
					
						
							| 
									
										
										
										
											2024-05-06 20:07:23 -07:00
										 |  |  |     NULL,          // doc
 | 
					
						
							|  |  |  |     0,             // m_size
 | 
					
						
							|  |  |  |     wmi_functions, // m_methods
 | 
					
						
							|  |  |  |     wmi_slots,     // m_slots
 | 
					
						
							| 
									
										
										
										
											2022-09-07 21:09:20 +01:00
										 |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | extern "C" { | 
					
						
							|  |  |  |     PyMODINIT_FUNC PyInit__wmi(void) | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |         return PyModuleDef_Init(&wmi_def); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | } |