diff --git a/base/applications/network/netsh/CMakeLists.txt b/base/applications/network/netsh/CMakeLists.txt index 5e8946e9bb8..230a76b17f0 100644 --- a/base/applications/network/netsh/CMakeLists.txt +++ b/base/applications/network/netsh/CMakeLists.txt @@ -8,6 +8,7 @@ list(APPEND SOURCE helper.c interpreter.c netsh.c + wmi.c precomp.h ${CMAKE_CURRENT_BINARY_DIR}/netsh_stubs.c) @@ -21,5 +22,5 @@ set_target_properties(netsh set_module_type(netsh win32cui UNICODE) target_link_libraries(netsh conutils) -add_importlibs(netsh iphlpapi advapi32 msvcrt kernel32 ntdll) +add_importlibs(netsh ole32 oleaut32 iphlpapi advapi32 msvcrt kernel32 ntdll) add_cd_file(TARGET netsh DESTINATION reactos/system32 FOR all) diff --git a/base/applications/network/netsh/context.c b/base/applications/network/netsh/context.c index 1f193f1fe02..21ce9ae0599 100644 --- a/base/applications/network/netsh/context.c +++ b/base/applications/network/netsh/context.c @@ -104,7 +104,8 @@ AddContextCommand( PFN_HANDLE_CMD pfnCmdHandler, DWORD dwShortCmdHelpToken, DWORD dwCmdHlpToken, - DWORD dwFlags) + DWORD dwFlags, + PNS_OSVERSIONCHECK pfnOsVersionCheck) { PCOMMAND_ENTRY pEntry; @@ -131,6 +132,7 @@ AddContextCommand( pEntry->dwShortCmdHelpToken = dwShortCmdHelpToken; pEntry->dwCmdHlpToken = dwCmdHlpToken; pEntry->dwFlags = dwFlags; + pEntry->pfnOsVersionCheck = pfnOsVersionCheck; if (pContext->pCommandListHead == NULL && pContext->pCommandListTail == NULL) { @@ -153,7 +155,8 @@ AddCommandGroup( PCONTEXT_ENTRY pContext, LPCWSTR pwszCmdGroupToken, DWORD dwShortCmdHelpToken, - DWORD dwFlags) + DWORD dwFlags, + PNS_OSVERSIONCHECK pfnOsVersionCheck) { PCOMMAND_GROUP pEntry; @@ -176,6 +179,7 @@ AddCommandGroup( wcscpy((LPWSTR)pEntry->pwszCmdGroupToken, pwszCmdGroupToken); pEntry->dwShortCmdHelpToken = dwShortCmdHelpToken; pEntry->dwFlags = dwFlags; + pEntry->pfnOsVersionCheck = pfnOsVersionCheck; if (pContext->pGroupListHead == NULL && pContext->pGroupListTail == NULL) { @@ -200,7 +204,8 @@ AddGroupCommand( PFN_HANDLE_CMD pfnCmdHandler, DWORD dwShortCmdHelpToken, DWORD dwCmdHlpToken, - DWORD dwFlags) + DWORD dwFlags, + PNS_OSVERSIONCHECK pfnOsVersionCheck) { PCOMMAND_ENTRY pEntry; @@ -227,6 +232,7 @@ AddGroupCommand( pEntry->dwShortCmdHelpToken = dwShortCmdHelpToken; pEntry->dwCmdHlpToken = dwCmdHlpToken; pEntry->dwFlags = dwFlags; + pEntry->pfnOsVersionCheck = pfnOsVersionCheck; if (pGroup->pCommandListHead == NULL && pGroup->pCommandListTail == NULL) { @@ -813,48 +819,48 @@ CreateRootContext(VOID) pRootContext->hModule = g_hModule; - AddContextCommand(pRootContext, L"..", UpCommand, IDS_HLP_UP, IDS_HLP_UP_EX, 0); - AddContextCommand(pRootContext, L"?", NULL, IDS_HLP_HELP, IDS_HLP_HELP_EX, 0); - AddContextCommand(pRootContext, L"abort", AbortCommand, IDS_HLP_ABORT, IDS_HLP_ABORT_EX, 0); - AddContextCommand(pRootContext, L"alias", AliasCommand, IDS_HLP_ALIAS, IDS_HLP_ALIAS_EX, 0); - AddContextCommand(pRootContext, L"bye", ExitCommand, IDS_HLP_EXIT, IDS_HLP_EXIT_EX, 0); - AddContextCommand(pRootContext, L"commit", CommitCommand, IDS_HLP_COMMIT, IDS_HLP_COMMIT_EX, 0); - AddContextCommand(pRootContext, L"dump", DumpCommand, IDS_HLP_DUMP, IDS_HLP_DUMP_EX, 0); - AddContextCommand(pRootContext, L"exec", ExecCommand, IDS_HLP_EXEC, IDS_HLP_EXEC_EX, 0); - AddContextCommand(pRootContext, L"exit", ExitCommand, IDS_HLP_EXIT, IDS_HLP_EXIT_EX, 0); - AddContextCommand(pRootContext, L"help", NULL, IDS_HLP_HELP, IDS_HLP_HELP_EX, 0); - AddContextCommand(pRootContext, L"offline", OfflineCommand, IDS_HLP_OFFLINE, IDS_HLP_OFFLINE_EX, 0); - AddContextCommand(pRootContext, L"online", OnlineCommand, IDS_HLP_ONLINE, IDS_HLP_ONLINE_EX, 0); - AddContextCommand(pRootContext, L"popd", PopdCommand, IDS_HLP_POPD, IDS_HLP_POPD_EX, 0); - AddContextCommand(pRootContext, L"pushd", PushdCommand, IDS_HLP_PUSHD, IDS_HLP_PUSHD_EX, 0); - AddContextCommand(pRootContext, L"quit", ExitCommand, IDS_HLP_EXIT, IDS_HLP_EXIT_EX, 0); - AddContextCommand(pRootContext, L"unalias", UnaliasCommand, IDS_HLP_UNALIAS, IDS_HLP_UNALIAS_EX, 0); + AddContextCommand(pRootContext, L"..", UpCommand, IDS_HLP_UP, IDS_HLP_UP_EX, 0, NULL); + AddContextCommand(pRootContext, L"?", NULL, IDS_HLP_HELP, IDS_HLP_HELP_EX, 0, NULL); + AddContextCommand(pRootContext, L"abort", AbortCommand, IDS_HLP_ABORT, IDS_HLP_ABORT_EX, 0, NULL); + AddContextCommand(pRootContext, L"alias", AliasCommand, IDS_HLP_ALIAS, IDS_HLP_ALIAS_EX, 0, NULL); + AddContextCommand(pRootContext, L"bye", ExitCommand, IDS_HLP_EXIT, IDS_HLP_EXIT_EX, 0, NULL); + AddContextCommand(pRootContext, L"commit", CommitCommand, IDS_HLP_COMMIT, IDS_HLP_COMMIT_EX, 0, NULL); + AddContextCommand(pRootContext, L"dump", DumpCommand, IDS_HLP_DUMP, IDS_HLP_DUMP_EX, 0, NULL); + AddContextCommand(pRootContext, L"exec", ExecCommand, IDS_HLP_EXEC, IDS_HLP_EXEC_EX, 0, NULL); + AddContextCommand(pRootContext, L"exit", ExitCommand, IDS_HLP_EXIT, IDS_HLP_EXIT_EX, 0, NULL); + AddContextCommand(pRootContext, L"help", NULL, IDS_HLP_HELP, IDS_HLP_HELP_EX, 0, NULL); + AddContextCommand(pRootContext, L"offline", OfflineCommand, IDS_HLP_OFFLINE, IDS_HLP_OFFLINE_EX, 0, NULL); + AddContextCommand(pRootContext, L"online", OnlineCommand, IDS_HLP_ONLINE, IDS_HLP_ONLINE_EX, 0, NULL); + AddContextCommand(pRootContext, L"popd", PopdCommand, IDS_HLP_POPD, IDS_HLP_POPD_EX, 0, NULL); + AddContextCommand(pRootContext, L"pushd", PushdCommand, IDS_HLP_PUSHD, IDS_HLP_PUSHD_EX, 0, NULL); + AddContextCommand(pRootContext, L"quit", ExitCommand, IDS_HLP_EXIT, IDS_HLP_EXIT_EX, 0, NULL); + AddContextCommand(pRootContext, L"unalias", UnaliasCommand, IDS_HLP_UNALIAS, IDS_HLP_UNALIAS_EX, 0, NULL); - pGroup = AddCommandGroup(pRootContext, L"add", IDS_HLP_GROUP_ADD, 0); + pGroup = AddCommandGroup(pRootContext, L"add", IDS_HLP_GROUP_ADD, 0, NULL); if (pGroup) { - AddGroupCommand(pGroup, L"helper", AddHelperCommand, IDS_HLP_ADD_HELPER, IDS_HLP_ADD_HELPER_EX, 0); + AddGroupCommand(pGroup, L"helper", AddHelperCommand, IDS_HLP_ADD_HELPER, IDS_HLP_ADD_HELPER_EX, 0, NULL); } - pGroup = AddCommandGroup(pRootContext, L"delete", IDS_HLP_GROUP_DELETE, 0); + pGroup = AddCommandGroup(pRootContext, L"delete", IDS_HLP_GROUP_DELETE, 0, NULL); if (pGroup) { - AddGroupCommand(pGroup, L"helper", DeleteHelperCommand, IDS_HLP_DEL_HELPER, IDS_HLP_DEL_HELPER_EX, 0); + AddGroupCommand(pGroup, L"helper", DeleteHelperCommand, IDS_HLP_DEL_HELPER, IDS_HLP_DEL_HELPER_EX, 0, NULL); } - pGroup = AddCommandGroup(pRootContext, L"set", IDS_HLP_GROUP_SET, 0); + pGroup = AddCommandGroup(pRootContext, L"set", IDS_HLP_GROUP_SET, 0, NULL); if (pGroup) { - AddGroupCommand(pGroup, L"machine", SetMachineCommand, IDS_HLP_SET_MACHINE, IDS_HLP_SET_MACHINE_EX, 0); - AddGroupCommand(pGroup, L"mode", SetModeCommand, IDS_HLP_SET_MODE, IDS_HLP_SET_MODE_EX, 0); + AddGroupCommand(pGroup, L"machine", SetMachineCommand, IDS_HLP_SET_MACHINE, IDS_HLP_SET_MACHINE_EX, 0, NULL); + AddGroupCommand(pGroup, L"mode", SetModeCommand, IDS_HLP_SET_MODE, IDS_HLP_SET_MODE_EX, 0, NULL); } - pGroup = AddCommandGroup(pRootContext, L"show", IDS_HLP_GROUP_SHOW, 0); + pGroup = AddCommandGroup(pRootContext, L"show", IDS_HLP_GROUP_SHOW, 0, NULL); if (pGroup) { - AddGroupCommand(pGroup, L"alias", ShowAliasCommand, IDS_HLP_SHOW_ALIAS, IDS_HLP_SHOW_ALIAS_EX, 0); - AddGroupCommand(pGroup, L"helper", ShowHelperCommand, IDS_HLP_SHOW_HELPER, IDS_HLP_SHOW_HELPER_EX, 0); - AddGroupCommand(pGroup, L"mode", ShowModeCommand, IDS_HLP_SHOW_MODE, IDS_HLP_SHOW_MODE_EX, 0); + AddGroupCommand(pGroup, L"alias", ShowAliasCommand, IDS_HLP_SHOW_ALIAS, IDS_HLP_SHOW_ALIAS_EX, 0, NULL); + AddGroupCommand(pGroup, L"helper", ShowHelperCommand, IDS_HLP_SHOW_HELPER, IDS_HLP_SHOW_HELPER_EX, 0, NULL); + AddGroupCommand(pGroup, L"mode", ShowModeCommand, IDS_HLP_SHOW_MODE, IDS_HLP_SHOW_MODE_EX, 0, NULL); } pCurrentContext = pRootContext; @@ -952,6 +958,7 @@ RegisterContext( pContext->pfnCommitFn = pChildContext->pfnCommitFn; pContext->pfnDumpFn = pChildContext->pfnDumpFn; pContext->pfnConnectFn = pChildContext->pfnConnectFn; + pContext->pfnOsVersionCheck = pChildContext->pfnOsVersionCheck; pContext->ulPriority = (pChildContext->dwFlags & CMD_FLAG_PRIORITY) ? pChildContext->ulPriority : DEFAULT_CONTEXT_PRIORITY; @@ -967,7 +974,8 @@ RegisterContext( pChildContext->pTopCmds[i].pfnCmdHandler, pChildContext->pTopCmds[i].dwShortCmdHelpToken, pChildContext->pTopCmds[i].dwCmdHlpToken, - pChildContext->pTopCmds[i].dwFlags); + pChildContext->pTopCmds[i].dwFlags, + pChildContext->pTopCmds[i].pOsVersionCheck); } /* Add command groups */ @@ -976,7 +984,8 @@ RegisterContext( pGroup = AddCommandGroup(pContext, pChildContext->pCmdGroups[i].pwszCmdGroupToken, pChildContext->pCmdGroups[i].dwShortCmdHelpToken, - pChildContext->pCmdGroups[i].dwFlags); + pChildContext->pCmdGroups[i].dwFlags, + pChildContext->pCmdGroups[i].pOsVersionCheck); if (pGroup != NULL) { for (j = 0; j < pChildContext->pCmdGroups[i].ulCmdGroupSize; j++) @@ -986,7 +995,8 @@ RegisterContext( pChildContext->pCmdGroups[i].pCmdGroup[j].pfnCmdHandler, pChildContext->pCmdGroups[i].pCmdGroup[j].dwShortCmdHelpToken, pChildContext->pCmdGroups[i].pCmdGroup[j].dwCmdHlpToken, - pChildContext->pCmdGroups[i].pCmdGroup[j].dwFlags); + pChildContext->pCmdGroups[i].pCmdGroup[j].dwFlags, + pChildContext->pCmdGroups[i].pCmdGroup[j].pOsVersionCheck); } } } diff --git a/base/applications/network/netsh/netsh.c b/base/applications/network/netsh/netsh.c index ad9cb5adad4..7b238f44441 100644 --- a/base/applications/network/netsh/netsh.c +++ b/base/applications/network/netsh/netsh.c @@ -101,6 +101,8 @@ wmain( DPRINT("wmain(%S)\n", GetCommandLineW()); + GetWmiVersionInfo(); + g_hModule = GetModuleHandle(NULL); /* Initialize the Console Standard Streams */ diff --git a/base/applications/network/netsh/precomp.h b/base/applications/network/netsh/precomp.h index 11bbb351566..cde167579e1 100644 --- a/base/applications/network/netsh/precomp.h +++ b/base/applications/network/netsh/precomp.h @@ -80,6 +80,7 @@ typedef struct _COMMAND_ENTRY DWORD dwShortCmdHelpToken; DWORD dwCmdHlpToken; DWORD dwFlags; + PNS_OSVERSIONCHECK pfnOsVersionCheck; } COMMAND_ENTRY, *PCOMMAND_ENTRY; typedef struct _COMMAND_GROUP @@ -90,6 +91,7 @@ typedef struct _COMMAND_GROUP PWSTR pwszCmdGroupToken; DWORD dwShortCmdHelpToken; DWORD dwFlags; + PNS_OSVERSIONCHECK pfnOsVersionCheck; PCOMMAND_ENTRY pCommandListHead; PCOMMAND_ENTRY pCommandListTail; @@ -110,6 +112,7 @@ typedef struct _CONTEXT_ENTRY PNS_CONTEXT_COMMIT_FN pfnCommitFn; PNS_CONTEXT_DUMP_FN pfnDumpFn; PNS_CONTEXT_CONNECT_FN pfnConnectFn; + PNS_OSVERSIONCHECK pfnOsVersionCheck; PCOMMAND_ENTRY pCommandListHead; PCOMMAND_ENTRY pCommandListTail; @@ -132,6 +135,15 @@ extern PHELPER_ENTRY pHelperListHead; extern HMODULE g_hModule; extern PWSTR pszMachine; +extern UINT VersionInfoArchitecture; +extern UINT VersionInfoOsProductSuite; +extern UINT VersionInfoOsType; +extern UINT VersionInfoVersion; +extern WCHAR VersionInfoBuildNumber[MAX_PATH]; +extern WCHAR VersionInfoServicePackMajorVersion[MAX_PATH]; +extern WCHAR VersionInfoServicePackMinorVersion[MAX_PATH]; + + /* PROTOTYPES *****************************************************************/ /* alias.c */ @@ -273,3 +285,8 @@ LPWSTR MergeStrings( _In_ LPWSTR pszStringArray[], _In_ UINT nCount); + +/* wmi.c */ + +HRESULT +GetWmiVersionInfo(VOID); diff --git a/base/applications/network/netsh/wmi.c b/base/applications/network/netsh/wmi.c new file mode 100644 index 00000000000..960d89bc2c8 --- /dev/null +++ b/base/applications/network/netsh/wmi.c @@ -0,0 +1,283 @@ +/* + * PROJECT: ReactOS NetSh + * LICENSE: GPL-2.0-or-later (https://spdx.org/licenses/GPL-2.0-or-later) + * PURPOSE: Network Shell WMI info functions + * COPYRIGHT: Copyright 2026 Eric Kohl + */ + +/* INCLUDES *******************************************************************/ + +#define COBJMACROS + +#include "precomp.h" + +#include +#include +#include +#include + +#define NDEBUG +#include + +/* GLOBALS ********************************************************************/ + +UINT VersionInfoArchitecture; +UINT VersionInfoOsProductSuite; +UINT VersionInfoOsType; +UINT VersionInfoVersion; +WCHAR VersionInfoBuildNumber[MAX_PATH]; +WCHAR VersionInfoServicePackMajorVersion[MAX_PATH]; +WCHAR VersionInfoServicePackMinorVersion[MAX_PATH]; + +/* FUNCTIONS ******************************************************************/ + +static +HRESULT +QueryOperatingSystemInfo( + _In_ IWbemServices *Services) +{ + IEnumWbemClassObject *Result = NULL; + IWbemClassObject *Object = NULL; + BSTR Wql = NULL; + BSTR Query = NULL; + BSTR Name; + CIMTYPE Type; + ULONG Count; + VARIANT Value; + HRESULT hr; + + Wql = SysAllocString(L"WQL"); + if (Wql == NULL) + return E_OUTOFMEMORY; + + Query = SysAllocString(L"SELECT * FROM Win32_OperatingSystem"); + if (Query == NULL) + { + hr = E_OUTOFMEMORY; + goto done; + } + + hr = IWbemServices_ExecQuery(Services, Wql, Query, 0, NULL, &Result); + if (hr != S_OK) + { + DPRINT1("IWbemServices_ExecQuery failed %08x\n", hr); + goto done; + } + + hr = IEnumWbemClassObject_Next(Result, 10000, 1, &Object, &Count); + if (hr != S_OK) + { + DPRINT1("IEnumWbemClassObject_Next failed %08x\n", hr); + goto done; + } + + hr = IWbemClassObject_BeginEnumeration(Object, 0); + if (hr != S_OK) + { + DPRINT1("IWbemClassObject_BeginEnumeration returned %08x\n", hr); + goto done; + } + + while (IWbemClassObject_Next(Object, 0, &Name, &Value, &Type, NULL) == S_OK) + { + DPRINT1("Name: %S\n", Name); + if (_wcsicmp(Name, L"BuildNumber") == 0) + { + DPRINT1("BuildNumber %S\n", V_BSTR(&Value)); + StringCbCopyW(VersionInfoBuildNumber, sizeof(VersionInfoBuildNumber), V_BSTR(&Value)); + } + else if (_wcsicmp(Name, L"OSProductSuite") == 0) + { + DPRINT1("OSProductSuite 0x%x\n", V_UINT(&Value)); + VersionInfoOsProductSuite = V_UINT(&Value); + } + else if (_wcsicmp(Name, L"OSType") == 0) + { + DPRINT1("OSType %u\n", V_UINT(&Value)); + VersionInfoOsType = V_UINT(&Value); + } + else if (_wcsicmp(Name, L"ServicePackMajorVersion") == 0) + { + DPRINT1("ServicePackMajorVersion %S\n", V_BSTR(&Value)); + StringCbCopyW(VersionInfoServicePackMajorVersion, sizeof(VersionInfoServicePackMajorVersion), V_BSTR(&Value)); + } + else if (_wcsicmp(Name, L"ServicePackMinorVersion") == 0) + { + DPRINT1("ServicePackMinorVersion %S\n", V_BSTR(&Value)); + StringCbCopyW(VersionInfoServicePackMinorVersion, sizeof(VersionInfoServicePackMinorVersion), V_BSTR(&Value)); + } + else if (_wcsicmp(Name, L"Version") == 0) + { + DPRINT1("Version %S\n", V_BSTR(&Value)); + VersionInfoVersion = V_UINT(&Value); + } + + SysFreeString(Name); + VariantClear(&Value); + } + + hr = IWbemClassObject_EndEnumeration(Object); + if (hr != S_OK) + { + DPRINT1("got %08x\n", hr); + goto done; + } + +done: + if (Object) + IWbemClassObject_Release(Object); + + if (Result) + IEnumWbemClassObject_Release(Result); + + if (Query) + SysFreeString(Query); + + if (Wql) + SysFreeString(Wql); + + return hr; +} + + +static +HRESULT +QueryProcessorInfo( + _In_ IWbemServices *Services) +{ + IEnumWbemClassObject *Result = NULL; + IWbemClassObject *Object = NULL; + BSTR Wql = NULL; + BSTR Query = NULL; + BSTR Name; + CIMTYPE Type; + ULONG Count; + VARIANT Value; + HRESULT hr; + + Wql = SysAllocString(L"WQL"); + if (Wql == NULL) + return E_OUTOFMEMORY; + + Query = SysAllocString(L"SELECT * FROM Win32_Processor"); + if (Query == NULL) + { + hr = E_OUTOFMEMORY; + goto done; + } + + hr = IWbemServices_ExecQuery(Services, Wql, Query, 0, NULL, &Result); + if (hr != S_OK) + { + DPRINT1("IWbemServices_ExecQuery failed %08x\n", hr); + goto done; + } + + hr = IEnumWbemClassObject_Next(Result, 10000, 1, &Object, &Count); + if (hr != S_OK) + { + DPRINT1("IEnumWbemClassObject_Next failed %08x\n", hr); + goto done; + } + + hr = IWbemClassObject_BeginEnumeration(Object, 0); + if (hr != S_OK) + { + DPRINT1("IWbemClassObject_BeginEnumeration returned %08x\n", hr); + goto done; + } + + while (IWbemClassObject_Next(Object, 0, &Name, &Value, &Type, NULL) == S_OK) + { + DPRINT1("Name: %S\n", Name); + if (_wcsicmp(Name, L"Architecture") == 0) + { + DPRINT1("Architecture %u\n", V_UINT(&Value)); + } + + SysFreeString(Name); + VariantClear(&Value); + } + + hr = IWbemClassObject_EndEnumeration(Object); + if (hr != S_OK) + { + DPRINT1("got %08x\n", hr); + goto done; + } + +done: + if (Object) + IWbemClassObject_Release(Object); + + if (Result) + IEnumWbemClassObject_Release(Result); + + if (Query) + SysFreeString(Query); + + if (Wql) + SysFreeString(Wql); + + return hr; +} + +HRESULT +GetWmiVersionInfo(VOID) +{ + BSTR Path = NULL; + IWbemLocator *Locator = NULL; + IWbemServices *Services = NULL; + HRESULT hr; + + CoInitialize(NULL); + + CoInitializeSecurity(NULL, -1, NULL, NULL, RPC_C_AUTHN_LEVEL_DEFAULT, + RPC_C_IMP_LEVEL_IMPERSONATE, NULL, EOAC_NONE, NULL); + hr = CoCreateInstance(&CLSID_WbemLocator, NULL, CLSCTX_INPROC_SERVER, + &IID_IWbemLocator, (void **)&Locator); + if (hr != S_OK) + { + DPRINT1("Can't create instance of WbemLocator\n"); + return hr; + } + + Path = SysAllocString(L"ROOT\\CIMV2"); + if (Path == NULL) + { + hr = E_OUTOFMEMORY; + goto done; + } + + hr = IWbemLocator_ConnectServer(Locator, Path, NULL, NULL, NULL, 0, NULL, NULL, &Services); + if (hr != S_OK) + { + DPRINT1("Failed to get IWbemServices interface %08x\n", hr); + goto done; + } + + hr = CoSetProxyBlanket((IUnknown *)Services, RPC_C_AUTHN_WINNT, RPC_C_AUTHZ_NONE, NULL, + RPC_C_AUTHN_LEVEL_CALL, RPC_C_IMP_LEVEL_IMPERSONATE, NULL, EOAC_NONE); + if (hr != S_OK) + { + DPRINT1("Failed to set proxy blanket %08x\n", hr); + goto done; + } + + hr = QueryOperatingSystemInfo(Services); + hr = QueryProcessorInfo(Services); + +done: + if (Path) + SysFreeString(Path); + + if (Services) + IWbemServices_Release(Services); + + if (Locator) + IWbemLocator_Release(Locator); + + CoUninitialize(); + + return hr; +}