I'm trying to call the Win32Shutdown method of Win32_OperatingSystem to cause a logout or reboot.
I'm using WMI to get Win32_OperatingSystem then I want to call its Win32Shutdown method. In this program,Win32_OperatingSystem class object uses IWbemServices::GetObject.
The problem,is that having obtained the IWbemClassObject, a call to IWbemClassObject::GetMethod for the Win32Shutdown method always returns 0x8004101e("Illegal Operation").
Did I set the SeShutdownPrivilege (SE_SHUTDOWN_NAME) correctly ?
Privileges Code:
BOOL SetPrivilege(
HANDLE hToken, // access token handle
LPCTSTR lpszPrivilege, // name of privilege to enable/disable
BOOL bEnablePrivilege // to enable or disable privilege
){
TOKEN_PRIVILEGES tp;
LUID luid;
if (!LookupPrivilegeValue(NULL, // lookup privilege on local system
lpszPrivilege, // privilege to lookup
&luid )) { // receives LUID of privilege
printf("LookupPrivilegeValue error: %u for string '%s'\n",
GetLastError(), lpszPrivilege);
return FALSE;
}
tp.PrivilegeCount = 1;
tp.Privileges[0].Luid = luid;
if (bEnablePrivilege) {
tp.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;
} else {
tp.Privileges[0].Attributes = 0;
}
// Enable the privilege or disable all privileges.
if (!AdjustTokenPrivileges(hToken, FALSE, &tp, sizeof(TOKEN_PRIVILEGES),
(PTOKEN_PRIVILEGES)NULL, (PDWORD)NULL)) {
DWORD err = GetLastError();
printf("AdjustTokenPrivileges error: %u\n", err);
return FALSE;
}
if (GetLastError() == ERROR_NOT_ALL_ASSIGNED) {
printf("The token does not have the specified privilege. \n");
return FALSE;
}
return TRUE;
}
WMI Code:
Connection has been established.
cout << "Attempting to call Win32Shutdown using IWbemServices::GetObject..." << endl;
BSTR MethodName = SysAllocString(L"Win32Shutdown");
BSTR ClassName = SysAllocString(L"Win32_OperatingSystem=@"); // =@: Singleton
IWbemClassObject* pClass = NULL;
hres = pSvc->GetObject(ClassName, 0, NULL, &pClass, NULL);
if (FAILED (hres)) {
printf("GetObject Error: %u\n", GetLastError());
return 1;
}
IWbemClassObject* pInParamsDefinition = NULL;
hres = pClass->GetMethod(MethodName, 0,
&pInParamsDefinition, NULL);
switch (hres) {
case WBEM_S_NO_ERROR:
cout << "_S_NO_ERROR: " << hex << hres << endl;
break;
case WBEM_E_NOT_FOUND:
cout << "_E_NOT_FOUND: " << hex << hres << endl;
break;
case WBEM_E_OUT_OF_MEMORY:
cout << "_E_OUT_OF_MEMORY: " << hex << hres << endl;
break;
case 0x8004101e:
wcout << "pClass->GetMethod returned 0x8004101e "
<< "(Illegal operation, apparently) for '"
<< MethodName << "'" << endl;
break;
default:
cout << "unknown: " << hex << hres << endl;
break;
}
if (FAILED (hres)) {
return 1;
}
IWbemClassObject* pClassInstance = NULL;
hres = pInParamsDefinition->SpawnInstance(0, &pClassInstance);
if (FAILED (hres)) {
printf("SpawnInstance Error: %u\n", GetLastError());
return 1;
}
// Create the values for the in parameters
VARIANT varFlags;
VariantInit (&varFlags);
varFlags.vt = VT_I4; // Seems to work...
varFlags.lVal = 0x5;
varFlags.intVal = 0x5;
varFlags.iVal = 0x5;
// Store the value for the in parameters
hres = pClassInstance->Put(L"Flags", 0, &varFlags, 0);
if (FAILED (hres)) {
ShowPutError (hres);
return 1;
}
wprintf(L"The flags: %d\n", V_INT(&varFlags));
//reserved arg - Is this neccessary ?
VARIANT varFlags2;
varFlags2.vt = VT_I4;
varFlags2.lVal = 0x0;
hres = pClassInstance->Put(L"Reserved", 0, &varFlags2, 0);
if (FAILED (hres)) {
ShowPutError (hres);
return 1;
}
IWbemClassObject* pOutParams = NULL;
hres = pSvc->ExecMethod(ClassName, MethodName, 0,
NULL, pClassInstance, &pOutParams, NULL);
if (FAILED(hres)) {
// See http://msdn.microsoft.com/en-us/library/cc250949%28v=prot.10%29.aspx
// for returned codes. This Windows error handling is ghastly.
cout << "ExecMethod error: " << hex << hres << endl;
return 1;
}
// Cleanup
// ========
pSvc->Release();
pLoc->Release();
pClass->Release();
CoUninitialize();


