How do I determine a mapped drive's details - c++

How do I determine a mapped drive's details like its actual path, FreeSize, and so on? So if I have a mapped drive on a machine called "MP" how can I using C++/Win32 or Qt determine the machine and path for the mapped folder and also other practical details?
I wanted to get extract information from the remote machine filesystem. I can make an SMB connection with the remote machine and get access to shared drive but I wanted to enumerate all information as possible from its file system. How can I do that?
There is a command in Powershell which we can use it to enumerate such information like the following command:
get-WmiObject win32_logicaldisk -Computername remotecomputer
However, I wanted to get such information with written some code in my application and show those information in user friendly format to the user.

You could use WMI class win32_logicaldisk in C++, here is the sample:
#include <stdio.h>
#define _WIN32_DCOM
#include <wbemidl.h>
#pragma comment(lib, "wbemuuid.lib")
#include <iostream>
using namespace std;
#include <comdef.h>
void PrintDriveDetails(wstring drive)
{
HRESULT hr;
IWbemLocator* pWbemLocator = NULL;
IWbemServices* pServices = NULL;
IWbemClassObject* pDrive = NULL;
hr = CoInitializeSecurity(NULL, -1, NULL, NULL,
RPC_C_AUTHN_LEVEL_DEFAULT,
RPC_C_IMP_LEVEL_IMPERSONATE,
NULL, EOAC_NONE, 0);
if (FAILED(hr))
{
CoUninitialize();
cout << "Failed to initialize security. Error code = 0x" << hex << hr << endl;
return;
}
hr = CoCreateInstance(CLSID_WbemLocator, NULL, CLSCTX_INPROC_SERVER, IID_IWbemLocator, (void**)&pWbemLocator);
if (FAILED(hr))
{
CoUninitialize();
cout << "Failed to CoCreateInstance. Error code = 0x" << hex << hr << endl;
return;
}
_bstr_t bstrNamespace = L"root\\cimv2";
hr = pWbemLocator->ConnectServer(bstrNamespace, NULL, NULL, NULL, 0, NULL, NULL, &pServices);
if (FAILED(hr))
{
pWbemLocator->Release();
CoUninitialize();
cout << "Failed to Connect to the Server. Error code = 0x" << hex << hr << endl;
return;
}
pWbemLocator->Release();
printf("Successfully connected to namespace.\n");
hr = CoSetProxyBlanket(
pServices,
RPC_C_AUTHN_WINNT,
RPC_C_AUTHZ_NONE,
NULL,
RPC_C_AUTHN_LEVEL_CALL,
RPC_C_IMP_LEVEL_IMPERSONATE,
NULL,
EOAC_NONE
);
if (FAILED(hr))
{
pServices->Release();
cout << "Could not set proxy blanket. Error code = 0x" << hex << hr << endl;
CoUninitialize();
return; // Program has failed.
}
wstring bstrPath = L"Win32_LogicalDisk.DeviceID=\"" + drive + L"\"";
// *******************************************************//
// Perform a full-instance retrieval.
// *******************************************************//
hr = pServices->GetObject(BSTR(bstrPath.c_str()),
0, 0, &pDrive, 0);
if (FAILED(hr))
{
pServices->Release();
CoUninitialize();
cout << "failed GetObject. Error code = 0x" << hex << hr << endl;
return;
}
// Display the object
BSTR bstrDriveObj;
hr = pDrive->GetObjectText(0, &bstrDriveObj);
if (FAILED(hr))
{
pServices->Release();
CoUninitialize();
cout << "failed GetObjectText. Error code = 0x" << hex << hr << endl;
return;
}
printf("%S\n\n", bstrDriveObj);
VARIANT freesize, totlesize;
hr = pDrive->Get(L"FreeSpace", 0, &freesize, 0, NULL);
if (FAILED(hr))
{
pServices->Release();
CoUninitialize();
cout << "failed Get FreeSpace. Error code = 0x" << hex << hr << endl;
return;
}
printf("freesize %S\n", freesize.bstrVal);
hr = pDrive->Get(L"Size", 0, &totlesize, 0, NULL);
if (FAILED(hr))
{
pServices->Release();
CoUninitialize();
cout << "failed Get Size. Error code = 0x" << hex << hr << endl;
return;
}
printf("totlesize : %S\n", totlesize.bstrVal);
VariantClear(&freesize);
VariantClear(&totlesize);
pDrive->Release();
pServices->Release();
pServices = NULL;
}
void main(void)
{
HRESULT hr = S_OK;
hr = CoInitializeEx(NULL, COINIT_MULTITHREADED);
PrintDriveDetails(L"Z:");
CoUninitialize();
return;
};

Related

MDM bridge WMI: How to allow camera MDM_Policy_Config01_Camera02

I would like to enable and disable windows devices as camera using WMI in C++. For example I'm able to access to table MDM_Policy_Result01_Camera02 and get the property AllowCamera quite easily where on the documentation is specify "Access type: Read/write".
So in my opinion I should be able to modify it.
But seems like WQL doesn't work with UPDATE.
This is my code to access to table MDM_Policy_Result01_Camera02 :
#include <iostream>
#define _WIN32_DCOM
#include <windows.h>
#include <Wbemidl.h>
#include <comdef.h>
# pragma comment(lib, "wbemuuid.lib")
bool initializeCom(){
// Step 1: --------------------------------------------------
// Initialize COM. ------------------------------------------
HRESULT hres = CoInitializeEx(0, COINIT_MULTITHREADED);
if (FAILED(hres))
{
std::cout << "Failed to initialize COM library. Error code = 0x"
<< std::hex << hres << std::endl;
return false; // Program has failed.
}
// Step 2: --------------------------------------------------
// Set general COM security levels --------------------------
hres = CoInitializeSecurity(
nullptr,
-1, // COM authentication
nullptr, // Authentication services
nullptr, // Reserved
RPC_C_AUTHN_LEVEL_DEFAULT, // Default authentication
RPC_C_IMP_LEVEL_IMPERSONATE, // Default Impersonation
nullptr, // Authentication info
EOAC_NONE, // Additional capabilities
nullptr // Reserved
);
if (FAILED(hres))
{
std::cout << "Failed to initialize security. Error code = 0x"
<< std::hex << hres << std::endl;
CoUninitialize();
return false; // Program has failed.
}
return true;
}
bool setUpWBEM(IWbemLocator*& wbemLocator, IWbemServices*& wbemServices){
// Step 3: ---------------------------------------------------
// Obtain the initial locator to WMI -------------------------
HRESULT hres = CoCreateInstance(
CLSID_WbemLocator,
0,
CLSCTX_INPROC_SERVER,
IID_IWbemLocator, (LPVOID *) &wbemLocator);
if (FAILED(hres))
{
std::cout << "Failed to create IWbemLocator object."
<< " Err code = 0x"
<< std::hex << hres << std::endl;
CoUninitialize();
return false; // Program has failed.
}
// Step 4: -----------------------------------------------------
// Connect to WMI through the IWbemLocator::ConnectServer method
// Connect to the root\cimv2 namespace with
// the current user and obtain pointer wbemServices
// to make IWbemServices calls.
hres = wbemLocator->ConnectServer(
_bstr_t(L"Root\\CIMv2\\MDM\\DMMap"), // Object path of WMI namespace
nullptr, // User name. NULL = current user
nullptr, // User password. NULL = current
0, // Locale. NULL indicates current
0, // Security flags.
0, // Authority (for example, Kerberos)
0, // Context object
&wbemServices // pointer to IWbemServices proxy
);
if (FAILED(hres))
{
std::cout << "Could not connect. Error code = 0x" << std::hex << hres << std::endl;
wbemLocator->Release();
CoUninitialize();
return false; // Program has failed.
}
std::cout << "Connected to ROOT\\CIMV2 WMI namespace" << std::endl;
// Step 5: --------------------------------------------------
// Set security levels on the proxy -------------------------
hres = CoSetProxyBlanket(
wbemServices, // Indicates the proxy to set
RPC_C_AUTHN_WINNT, // RPC_C_AUTHN_xxx
RPC_C_AUTHZ_NONE, // RPC_C_AUTHZ_xxx
nullptr, // Server principal name
RPC_C_AUTHN_LEVEL_CALL, // RPC_C_AUTHN_LEVEL_xxx
RPC_C_IMP_LEVEL_IMPERSONATE, // RPC_C_IMP_LEVEL_xxx
nullptr, // client identity
EOAC_NONE // proxy capabilities
);
if (FAILED(hres))
{
std::cout << "Could not set proxy blanket. Error code = 0x"
<< std::hex << hres << std::endl;
wbemServices->Release();
wbemLocator->Release();
CoUninitialize();
return false; // Program has failed.
}
return true;
}
int main() {
std::cout << "HelloWorld" << std::endl;
IWbemLocator* wbemLocator{nullptr};
IWbemServices* wbemServices{nullptr};
try{
if(!initializeCom())
throw "initializeCom failed";
if(!setUpWBEM(wbemLocator,wbemServices))
throw "setUpWBEM failed";
// Step 6: --------------------------------------------------
// Use the IWbemServices pointer to make requests of WMI ----
BSTR bstr_wql = SysAllocString(L"WQL" );
BSTR bstr_sql = SysAllocString(L"SELECT AllowCamera FROM MDM_Policy_Result01_Camera02" );
// For example, get the name of the operating system
IEnumWbemClassObject* pEnumerator{nullptr};
HRESULT hres = wbemServices->ExecQuery(
bstr_wql,
bstr_sql,
WBEM_FLAG_FORWARD_ONLY | WBEM_FLAG_RETURN_IMMEDIATELY,
nullptr,
&pEnumerator);
if (FAILED(hres))
{
std::cout << "Query for operating system name failed."
<< " Error code = 0x"
<< std::hex << hres << std::endl;
wbemServices->Release();
wbemLocator->Release();
CoUninitialize();
throw "ExecQuery failed";; // Program has failed.
}
// Step 7: -------------------------------------------------
// Get the data from the query in step 6 -------------------
IWbemClassObject *pclsObj{nullptr};
ULONG uReturn = 0;
while (pEnumerator)
{
HRESULT hr = pEnumerator->Next(WBEM_INFINITE, 1,
&pclsObj, &uReturn);
if(0 == uReturn)
{
break;
}
VARIANT vtProp;
// Get the value of the Name property
hr = pclsObj->Get(L"AllowCamera", 0, &vtProp, 0, 0);
if(FAILED(hr))
std::cout << "Failed to get name " << std::endl;
std::cout << "Camera allow : " << vtProp.intVal << std::endl;
VariantClear(&vtProp);
pclsObj->Release();
}
// Cleanup
// ========
wbemServices->Release();
wbemLocator->Release();
pEnumerator->Release();
CoUninitialize();
} catch(const std::string& error){
std::cout << error << std::endl;
}
return 0;
}
Changing SELECT AllowCamera FROM MDM_Policy_Result01_Camera02 with UPDATE MDM_Policy_Result01_Camera02 SET AllowCamera=0 doesn't work ...
If you have any idea, let me know !
Finally came out the MDM brigde WSI C++ example :
https://learn.microsoft.com/fr-fr/windows/win32/wmisdk/example--calling-a-provider-method

Read the windows log files using C++ and WMI(Windows Management Instrumentation)

I have been going through the windows docs to access the windows log files using C++ and WMI. I saw a sample code for creating a WMI application. But it shows an error when I compile it using the g++ compiler.
code:
#define _WIN32_DCOM
#include <iostream>
using namespace std;
#include <comdef.h>
#include <Wbemidl.h>
#pragma comment(lib, "wbemuuid.lib")
int main(int argc, char **argv)
{
HRESULT hres;
// Initialize COM.
hres = CoInitializeEx(0, COINIT_MULTITHREADED);
if (FAILED(hres))
{
cout << "Failed to initialize COM library. "
<< "Error code = 0x"
<< hex << hres << endl;
return 1; // Program has failed.
}
// Initialize
hres = CoInitializeSecurity(
NULL,
-1, // COM negotiates service
NULL, // Authentication services
NULL, // Reserved
RPC_C_AUTHN_LEVEL_DEFAULT, // authentication
RPC_C_IMP_LEVEL_IMPERSONATE, // Impersonation
NULL, // Authentication info
EOAC_NONE, // Additional capabilities
NULL // Reserved
);
if (FAILED(hres))
{
cout << "Failed to initialize security. "
<< "Error code = 0x"
<< hex << hres << endl;
CoUninitialize();
return 1; // Program has failed.
}
// Obtain the initial locator to Windows Management
// on a particular host computer.
IWbemLocator *pLoc = 0;
hres = CoCreateInstance(
CLSID_WbemLocator,
0,
CLSCTX_INPROC_SERVER,
IID_IWbemLocator, (LPVOID *) &pLoc);
if (FAILED(hres))
{
cout << "Failed to create IWbemLocator object. "
<< "Error code = 0x"
<< hex << hres << endl;
CoUninitialize();
return 1; // Program has failed.
}
IWbemServices *pSvc = 0;
// Connect to the root\cimv2 namespace with the
// current user and obtain pointer pSvc
// to make IWbemServices calls.
hres = pLoc->ConnectServer(
_bstr_t(L"ROOT\\CIMV2"), // WMI namespace
NULL, // User name
NULL, // User password
0, // Locale
NULL, // Security flags
0, // Authority
0, // Context object
&pSvc // IWbemServices proxy
);
if (FAILED(hres))
{
cout << "Could not connect. Error code = 0x"
<< hex << hres << endl;
pLoc->Release();
CoUninitialize();
return 1; // Program has failed.
}
cout << "Connected to ROOT\\CIMV2 WMI namespace" << endl;
// Set the IWbemServices proxy so that impersonation
// of the user (client) occurs.
hres = CoSetProxyBlanket(
pSvc, // the proxy to set
RPC_C_AUTHN_WINNT, // authentication service
RPC_C_AUTHZ_NONE, // authorization service
NULL, // Server principal name
RPC_C_AUTHN_LEVEL_CALL, // authentication level
RPC_C_IMP_LEVEL_IMPERSONATE, // impersonation level
NULL, // client identity
EOAC_NONE // proxy capabilities
);
if (FAILED(hres))
{
cout << "Could not set proxy blanket. Error code = 0x"
<< hex << hres << endl;
pSvc->Release();
pLoc->Release();
CoUninitialize();
return 1; // Program has failed.
}
// Use the IWbemServices pointer to make requests of WMI.
// Make requests here:
// For example, query for all the running processes
IEnumWbemClassObject* pEnumerator = NULL;
hres = pSvc->ExecQuery(
bstr_t("WQL"),
bstr_t("SELECT * FROM Win32_Process"),
WBEM_FLAG_FORWARD_ONLY | WBEM_FLAG_RETURN_IMMEDIATELY,
NULL,
&pEnumerator);
if (FAILED(hres))
{
cout << "Query for processes failed. "
<< "Error code = 0x"
<< hex << hres << endl;
pSvc->Release();
pLoc->Release();
CoUninitialize();
return 1; // Program has failed.
}
else
{
IWbemClassObject *pclsObj;
ULONG uReturn = 0;
while (pEnumerator)
{
hres = pEnumerator->Next(WBEM_INFINITE, 1,
&pclsObj, &uReturn);
if(0 == uReturn)
{
break;
}
VARIANT vtProp;
// Get the value of the Name property
hres = pclsObj->Get(L"Name", 0, &vtProp, 0, 0);
wcout << "Process Name : " << vtProp.bstrVal << endl;
VariantClear(&vtProp);
pclsObj->Release();
pclsObj = NULL;
}
}
// Cleanup
// ========
pSvc->Release();
pLoc->Release();
pEnumerator->Release();
CoUninitialize();
return 0; // Program successfully completed.
}
If I saved it in a file named sample.cpp I compiled it suing the command
g++ -o sample sample.cpp
Is that a mistake? Should I be compiling it in a different way?
I'm new to this. Can somebody please guide me on how to learn the WMI using C++ in order to read the windows log files?
Kindly respond
Thank you.
It seems like you have just copy pasted the code from a website, due to which & has become & (because of HTML) as mentioned in the comments by #Vlad274.
If you're compiling in the command prompt, you have to link your libraries before compilation, probably ole32 and oleaut.
If you're using Visual Studio, make sure they are included in the linker settings.(Which they are by default in VS2017)
EXTRA: Before using the Get method, you could check for property names using the GetNames method to ensure that the property 'Name' exists.

WMI Queries is not working in service mode for Network drive(UNC path) in C++ but working in console mode

Trying to convert the network drive or mapped drive(Z:) to its UNC path( 192.168.x.x\Shared). Tried different ways like WNetGetUniversalName and WNetGetConnection, but getting error like ERROR_NOT_CONNECTED or ERROR_CONNECTION_UNAVAIL. then elevated its privileges and also tried with api LogonUser. but still getting same errors.
Then tried using WMI query, it works fine when running in console mode. But it is not working in service mode. Even Function to convert UNC path from the network drive is not directly called under service running process. Suppose Service process name is "parentService.exe", it creates a child called "childService.exe". this "childService.exe" is running function of converting network drive to UNC path, this means "childService.exe" is actually a console application running without standard I/O's.
this same "childService.exe" works fine if its run as individually in console mode. variable "vRet.bstrVal"(provider name) contains unc path. it doesn't give any error for service mode running, it just returns successfully .but while loop condition is not met. Both console and service runs on same user.
How to make it work also when it runs as part of service?
Here is code the for it:
#include <windows.h>
#include <Winnetwk.h>
#include <iostream>
#pragma comment(lib, "wbemuuid.lib")
int wmi_call()
{
HRESULT hRes;
hRes = CoInitializeEx(0, COINIT_MULTITHREADED);
if (FAILED(hRes))
{
cout << "Unable to launch COM: 0x" << std::hex << hRes << endl;
return 1;
}
if ((FAILED(hRes = CoInitializeSecurity(NULL, -1, NULL, NULL, RPC_C_AUTHN_LEVEL_CONNECT, RPC_C_IMP_LEVEL_IMPERSONATE, NULL, EOAC_NONE, 0))))
{
cout << "Unable to initialize security: 0x" << std::hex << hRes << endl;
return 1;
}
IWbemLocator* pLocator = NULL;
if (FAILED(hRes = CoCreateInstance(CLSID_WbemLocator, NULL, CLSCTX_ALL, IID_PPV_ARGS(&pLocator))))
{
cout << "Unable to create a WbemLocator: " << std::hex << hRes << endl;
return 1;
}
IWbemServices* pService = NULL;
if (FAILED(hRes = pLocator->ConnectServer(L"root\\CIMV2", NULL, NULL, NULL, WBEM_FLAG_CONNECT_USE_MAX_WAIT, NULL, NULL, &pService)))
{
pLocator->Release();
cout << "Unable to connect to \"CIMV2\": " << std::hex << hRes << endl;
return 1;
}
IEnumWbemClassObject* pEnumerator = NULL;
if (FAILED(hRes = pService->ExecQuery(L"WQL", L"SELECT ProviderName FROM Win32_LogicalDisk where DeviceId = \"Z:\"", WBEM_FLAG_FORWARD_ONLY, NULL, &pEnumerator)))
{
pLocator->Release();
pService->Release();
cout << "Unable to retrive desktop monitors: " << std::hex << hRes << endl;
return 1;
}
IWbemClassObject* clsObj = NULL;
int numElems;
while ((hRes = pEnumerator->Next(WBEM_INFINITE, 1, &clsObj, (ULONG*)&numElems)) != WBEM_S_FALSE)
{
if (FAILED(hRes))
break;
VARIANT vRet;
VariantInit(&vRet);
hRes = clsObj->Get(L"ProviderName", 0, &vRet, NULL, NULL);
if (SUCCEEDED(hRes) && vRet.vt == VT_BSTR)
{
std::wcout << L"Succesfull conversion to UNC path, ProviderName: " << vRet.bstrVal << endl;
VariantClear(&vRet);
}
else
{
cout << "Unable clsObj " << std::hex << hRes << endl;
}
clsObj->Release();
}
pEnumerator->Release();
pService->Release();
pLocator->Release();
return 0;
}
it worked fine, when used "SELECT ProviderName FROM Win32_MappedLogicalDisk where DeviceId = \"Z:\"" instead of
"SELECT ProviderName FROM Win32_LogicalDisk where DeviceId = \"Z:\""

Get process handle of created processes Windows

I need to the the Handle or the PID for all the process that are just being created while I run my program.
So far I have used this code that tell me each time that a process is created. The problem is that I just get the information about a process created but I don't have any information about the process itself. https://msdn.microsoft.com/en-us/library/aa390425(VS.85).aspx
This is the fuction where I get the event but I don't know from where I can get the info for the new process:
HRESULT EventSink::Indicate(long lObjectCount,
IWbemClassObject **apObjArray)
{
HRESULT hres = S_OK;
for (int i = 0; i < lObjectCount; i++)
{
printf("Event occurred\n");
}
return WBEM_S_NO_ERROR;
}
Thank you
Since you are using this WQL sentence SELECT * FROM __InstanceCreationEvent WITHIN 1 WHERE TargetInstance ISA 'Win32_Process', In order to get additional info about the created processes you must access the TargetInstance property which in this case will return a Win32_Process instance.
Try this sample
#include "stdafx.h"
#include <conio.h>
#ifndef EVENTSINK_H
#define EVENTSINK_H
#define _WIN32_DCOM
#include <iostream>
using namespace std;
#include <comdef.h>
#include <Wbemidl.h>
# pragma comment(lib, "wbemuuid.lib")
class EventSink : public IWbemObjectSink
{
LONG m_lRef;
bool bDone;
public:
EventSink() { m_lRef = 0; }
~EventSink() { bDone = true; }
virtual ULONG STDMETHODCALLTYPE AddRef();
virtual ULONG STDMETHODCALLTYPE Release();
virtual HRESULT
STDMETHODCALLTYPE QueryInterface(REFIID riid, void** ppv);
virtual HRESULT STDMETHODCALLTYPE Indicate(
LONG lObjectCount,
IWbemClassObject __RPC_FAR *__RPC_FAR *apObjArray
);
virtual HRESULT STDMETHODCALLTYPE SetStatus(
/* [in] */ LONG lFlags,
/* [in] */ HRESULT hResult,
/* [in] */ BSTR strParam,
/* [in] */ IWbemClassObject __RPC_FAR *pObjParam
);
};
#endif // end of EventSink.h
ULONG EventSink::AddRef()
{
return InterlockedIncrement(&m_lRef);
}
ULONG EventSink::Release()
{
LONG lRef = InterlockedDecrement(&m_lRef);
if (lRef == 0)
delete this;
return lRef;
}
HRESULT EventSink::QueryInterface(REFIID riid, void** ppv)
{
if (riid == IID_IUnknown || riid == IID_IWbemObjectSink)
{
*ppv = (IWbemObjectSink *) this;
AddRef();
return WBEM_S_NO_ERROR;
}
else return E_NOINTERFACE;
}
HRESULT EventSink::Indicate(long lObjectCount,
IWbemClassObject **apObjArray)
{
HRESULT hr = S_OK;
_variant_t vtProp;
for (int i = 0; i < lObjectCount; i++)
{
hr = apObjArray[i]->Get(_bstr_t(L"TargetInstance"), 0, &vtProp, 0, 0);
if (!FAILED(hr))
{
IUnknown* str = vtProp;
hr = str->QueryInterface(IID_IWbemClassObject, reinterpret_cast< void** >(&apObjArray[i]));
if (SUCCEEDED(hr))
{
_variant_t cn;
hr = apObjArray[i]->Get(L"Caption", 0, &cn, NULL, NULL);
if (SUCCEEDED(hr))
{
if ((cn.vt == VT_NULL) || (cn.vt == VT_EMPTY))
wcout << "Caption : " << ((cn.vt == VT_NULL) ? "NULL" : "EMPTY") << endl;
else
if ((cn.vt & VT_ARRAY))
wcout << "Caption : " << "Array types not supported (yet)" << endl;
else
wcout << "Caption : " << cn.bstrVal << endl;
}
VariantClear(&cn);
hr = apObjArray[i]->Get(L"CommandLine", 0, &cn, NULL, NULL);
if (SUCCEEDED(hr))
{
if ((cn.vt == VT_NULL) || (cn.vt == VT_EMPTY))
wcout << "CommandLine : " << ((cn.vt == VT_NULL) ? "NULL" : "EMPTY") << endl;
else
if ((cn.vt & VT_ARRAY))
wcout << "CommandLine : " << "Array types not supported (yet)" << endl;
else
wcout << "CommandLine : " << cn.bstrVal << endl;
}
VariantClear(&cn);
hr = apObjArray[i]->Get(L"Handle", 0, &cn, NULL, NULL);
if (SUCCEEDED(hr))
{
if ((cn.vt == VT_NULL) || (cn.vt == VT_EMPTY))
wcout << "Handle : " << ((cn.vt == VT_NULL) ? "NULL" : "EMPTY") << endl;
else
if ((cn.vt & VT_ARRAY))
wcout << "Handle : " << "Array types not supported (yet)" << endl;
else
wcout << "Handle : " << cn.bstrVal << endl;
}
VariantClear(&cn);
}
}
VariantClear(&vtProp);
}
return WBEM_S_NO_ERROR;
}
HRESULT EventSink::SetStatus(
/* [in] */ LONG lFlags,
/* [in] */ HRESULT hResult,
/* [in] */ BSTR strParam,
/* [in] */ IWbemClassObject __RPC_FAR *pObjParam
)
{
if (lFlags == WBEM_STATUS_COMPLETE)
{
printf("Call complete. hResult = 0x%X\n", hResult);
}
else if (lFlags == WBEM_STATUS_PROGRESS)
{
printf("Call in progress.\n");
}
return WBEM_S_NO_ERROR;
} // end of EventSink.cpp
int main(int iArgCnt, char ** argv)
{
HRESULT hres;
// Step 1: --------------------------------------------------
// Initialize COM. ------------------------------------------
hres = CoInitializeEx(0, COINIT_MULTITHREADED);
if (FAILED(hres))
{
cout << "Failed to initialize COM library. Error code = 0x"
<< hex << hres << endl;
return 1; // Program has failed.
}
// Step 2: --------------------------------------------------
// Set general COM security levels --------------------------
// Note: If you are using Windows 2000, you need to specify -
// the default authentication credentials for a user by using
// a SOLE_AUTHENTICATION_LIST structure in the pAuthList ----
// parameter of CoInitializeSecurity ------------------------
hres = CoInitializeSecurity(
NULL,
-1, // COM negotiates service
NULL, // Authentication services
NULL, // Reserved
RPC_C_AUTHN_LEVEL_DEFAULT, // Default authentication
RPC_C_IMP_LEVEL_IMPERSONATE, // Default Impersonation
NULL, // Authentication info
EOAC_NONE, // Additional capabilities
NULL // Reserved
);
if (FAILED(hres))
{
cout << "Failed to initialize security. Error code = 0x"
<< hex << hres << endl;
CoUninitialize();
return 1; // Program has failed.
}
// Step 3: ---------------------------------------------------
// Obtain the initial locator to WMI -------------------------
IWbemLocator *pLoc = NULL;
hres = CoCreateInstance(CLSID_WbemLocator, 0, CLSCTX_INPROC_SERVER, IID_IWbemLocator, (LPVOID *)&pLoc);
if (FAILED(hres))
{
cout << "Failed to create IWbemLocator object. "
<< "Err code = 0x"
<< hex << hres << endl;
CoUninitialize();
return 1; // Program has failed.
}
// Step 4: ---------------------------------------------------
// Connect to WMI through the IWbemLocator::ConnectServer method
IWbemServices *pSvc = NULL;
// Connect to the local root\cimv2 namespace
// and obtain pointer pSvc to make IWbemServices calls.
hres = pLoc->ConnectServer(
_bstr_t(L"root\\CIMV2"),
NULL,
NULL,
0,
NULL,
0,
0,
&pSvc
);
if (FAILED(hres))
{
cout << "Could not connect. Error code = 0x"
<< hex << hres << endl;
pLoc->Release();
CoUninitialize();
return 1; // Program has failed.
}
cout << "Connected to root\\CIMV2 WMI namespace" << endl;
// Step 5: --------------------------------------------------
// Set security levels on the proxy -------------------------
hres = CoSetProxyBlanket(
pSvc, // Indicates the proxy to set
RPC_C_AUTHN_WINNT, // RPC_C_AUTHN_xxx
RPC_C_AUTHZ_NONE, // RPC_C_AUTHZ_xxx
NULL, // Server principal name
RPC_C_AUTHN_LEVEL_CALL, // RPC_C_AUTHN_LEVEL_xxx
RPC_C_IMP_LEVEL_IMPERSONATE, // RPC_C_IMP_LEVEL_xxx
NULL, // client identity
EOAC_NONE // proxy capabilities
);
if (FAILED(hres))
{
cout << "Could not set proxy blanket. Error code = 0x" << hex << hres << endl;
pSvc->Release();
pLoc->Release();
CoUninitialize();
return 1; // Program has failed.
}
// Step 6: -------------------------------------------------
// Receive event notifications -----------------------------
// Use an unsecured apartment for security
IUnsecuredApartment* pUnsecApp = NULL;
hres = CoCreateInstance(CLSID_UnsecuredApartment, NULL, CLSCTX_LOCAL_SERVER, IID_IUnsecuredApartment, (void**)&pUnsecApp);
EventSink* pSink = new EventSink;
pSink->AddRef();
IUnknown* pStubUnk = NULL;
pUnsecApp->CreateObjectStub(pSink, &pStubUnk);
IWbemObjectSink* pStubSink = NULL;
pStubUnk->QueryInterface(IID_IWbemObjectSink, (void **)&pStubSink);
BSTR WQL;
WQL = L"Select * From __InstanceCreationEvent Within 1 "
L"Where TargetInstance ISA 'Win32_Process' "
;
// The ExecNotificationQueryAsync method will call
// The EventQuery::Indicate method when an event occurs
hres = pSvc->ExecNotificationQueryAsync(
_bstr_t("WQL"), _bstr_t(WQL), WBEM_FLAG_SEND_STATUS, NULL, pStubSink);
// Check for errors.
if (FAILED(hres))
{
printf("ExecNotificationQueryAsync failed with = 0x%X\n", hres);
pSvc->Release();
pLoc->Release();
pUnsecApp->Release();
pStubUnk->Release();
pSink->Release();
pStubSink->Release();
CoUninitialize();
return 1;
}
// Wait for the event
cout << "Press any key to terminate" << endl;
while (!_kbhit()) {}
hres = pSvc->CancelAsyncCall(pStubSink);
// Cleanup
// ========
pSvc->Release();
pLoc->Release();
pUnsecApp->Release();
pStubUnk->Release();
pSink->Release();
pStubSink->Release();
CoUninitialize();
return 0; // Program successfully completed.
}
The example above seems to have a memory leak inside EventSink::Indicate.
IUnknown* str = vtProp;
This assignment uses operator IUnknown* of the _variant_t class, which implicitly calls an AddRef() on the object. So str->Release() needs to be called after usage, since
VariantClear(&vtProp);
is not enough to decrement the ref count of the object.

Conversion of physical drive paths using C++

I'm using WMI to retrieve information about physical drives on the system:
SELECT * FROM Win32_PhysicalMedia
And the "Tag" property returns physical device paths such as "\.\PHYSICALDRIVE0", or "\.\CDROM0", etc.
Is there a way to associate it with the actual drive paths, stuff like "C:" or "D:" or at least a device path "\Device\HarddiskVolume1"?
PS. In despite of my use of WMI, I'm writing the code using WinAPIs and C++.
EDIT:
Below is how it's done in C++. Note that this code should not be called right-when-you-need-this because it is extremely slow. What I would do is run it in a worker thread when the app starts and cache it somewhere for later user. I'd also watch for the WM_DEVICECHANGE notification and rerun it if drive layout changes.
Whew. I know it's complicated ... but, hey, it's Windows.
The code below comes from comments to this page.
#define _WIN32_DCOM
#include <iostream>
using namespace std;
#include <comdef.h>
#include <Wbemidl.h>
#pragma comment(lib, "wbemuuid.lib")
BOOL wmi_run();
BOOL wmi_getDriveLetters();
BOOL wmi_close();
IWbemLocator *pLoc = NULL;
IWbemServices *pSvc = NULL;
int main(int argc, char **argv)
{
wmi_run();
wmi_getDriveLetters();
system("pause");
wmi_close();
}
//
// Step 1-5 at:
// http://msdn.microsoft.com/en-us/library/aa390423(VS.85).aspx
BOOL wmi_run()
{
HRESULT hres;
// Step 1: --------------------------------------------------
// Initialize COM. ------------------------------------------
hres = CoInitializeEx(0, COINIT_MULTITHREADED);
if (FAILED(hres))
{
cout << "Failed to initialize COM library. Error code = 0x"
<< hex << hres << endl;
return 1; // Program has failed.
}
// Step 2: --------------------------------------------------
// Set general COM security levels --------------------------
// Note: If you are using Windows 2000, you need to specify -
// the default authentication credentials for a user by using
// a SOLE_AUTHENTICATION_LIST structure in the pAuthList ----
// parameter of CoInitializeSecurity ------------------------
hres = CoInitializeSecurity(
NULL,
-1, // COM authentication
NULL, // Authentication services
NULL, // Reserved
RPC_C_AUTHN_LEVEL_DEFAULT, // Default authentication
RPC_C_IMP_LEVEL_IMPERSONATE, // Default Impersonation
NULL, // Authentication info
EOAC_NONE, // Additional capabilities
NULL // Reserved
);
if (FAILED(hres))
{
cout << "Failed to initialize security. Error code = 0x"
<< hex << hres << endl;
CoUninitialize();
return 1; // Program has failed.
}
// Step 3: ---------------------------------------------------
// Obtain the initial locator to WMI -------------------------
//IWbemLocator *pLoc = NULL;
hres = CoCreateInstance(
CLSID_WbemLocator,
0,
CLSCTX_INPROC_SERVER,
IID_IWbemLocator, (LPVOID *) &pLoc);
if (FAILED(hres))
{
cout << "Failed to create IWbemLocator object."
<< " Err code = 0x"
<< hex << hres << endl;
CoUninitialize();
return 1; // Program has failed.
}
// Step 4: -----------------------------------------------------
// Connect to WMI through the IWbemLocator::ConnectServer method
//IWbemServices *pSvc = NULL;
// Connect to the root\cimv2 namespace with
// the current user and obtain pointer pSvc
// to make IWbemServices calls.
hres = pLoc->ConnectServer(
_bstr_t(L"ROOT\\CIMV2"), // Object path of WMI namespace
NULL, // User name. NULL = current user
NULL, // User password. NULL = current
0, // Locale. NULL indicates current
NULL, // Security flags.
0, // Authority (e.g. Kerberos)
0, // Context object
&pSvc // pointer to IWbemServices proxy
);
if (FAILED(hres))
{
cout << "Could not connect. Error code = 0x"
<< hex << hres << endl;
pLoc->Release();
CoUninitialize();
return 1; // Program has failed.
}
cout << "Connected to ROOT\\CIMV2 WMI namespace" << endl;
// Step 5: --------------------------------------------------
// Set security levels on the proxy -------------------------
hres = CoSetProxyBlanket(
pSvc, // Indicates the proxy to set
RPC_C_AUTHN_WINNT, // RPC_C_AUTHN_xxx
RPC_C_AUTHZ_NONE, // RPC_C_AUTHZ_xxx
NULL, // Server principal name
RPC_C_AUTHN_LEVEL_CALL, // RPC_C_AUTHN_LEVEL_xxx
RPC_C_IMP_LEVEL_IMPERSONATE, // RPC_C_IMP_LEVEL_xxx
NULL, // client identity
EOAC_NONE // proxy capabilities
);
if (FAILED(hres))
{
cout << "Could not set proxy blanket. Error code = 0x"
<< hex << hres << endl;
pSvc->Release();
pLoc->Release();
CoUninitialize();
return 1; // Program has failed.
}
return 0;
}
//
// get Drives, logical Drives and Driveletters
BOOL wmi_getDriveLetters()
{
// Use the IWbemServices pointer to make requests of WMI.
// Make requests here:
HRESULT hres;
IEnumWbemClassObject* pEnumerator = NULL;
// get localdrives
hres = pSvc->ExecQuery(
bstr_t("WQL"),
bstr_t("SELECT * FROM Win32_DiskDrive"),
WBEM_FLAG_FORWARD_ONLY | WBEM_FLAG_RETURN_IMMEDIATELY,
NULL,
&pEnumerator);
if (FAILED(hres)) {
cout << "Query for processes failed. "
<< "Error code = 0x"
<< hex << hres << endl;
pSvc->Release();
pLoc->Release();
CoUninitialize();
return FALSE; // Program has failed.
}
else {
IWbemClassObject *pclsObj;
ULONG uReturn = 0;
while (pEnumerator) {
hres = pEnumerator->Next(WBEM_INFINITE, 1,
&pclsObj, &uReturn);
if(0 == uReturn) break;
VARIANT vtProp;
hres = pclsObj->Get(_bstr_t(L"DeviceID"), 0, &vtProp, 0, 0);
// adjust string
wstring tmp = vtProp.bstrVal;
tmp = tmp.substr(4);
wstring wstrQuery = L"Associators of {Win32_DiskDrive.DeviceID='\\\\.\\";
wstrQuery += tmp;
wstrQuery += L"'} where AssocClass=Win32_DiskDriveToDiskPartition";
// reference drive to partition
IEnumWbemClassObject* pEnumerator1 = NULL;
hres = pSvc->ExecQuery(
bstr_t("WQL"),
bstr_t( wstrQuery.c_str()),
WBEM_FLAG_FORWARD_ONLY | WBEM_FLAG_RETURN_IMMEDIATELY,
NULL,
&pEnumerator1 );
if ( FAILED(hres) ) {
cout << "Query for processes failed. "
<< "Error code = 0x"
<< hex << hres << endl;
pSvc->Release();
pLoc->Release();
CoUninitialize();
return FALSE; // Program has failed.
} else {
IWbemClassObject *pclsObj1;
ULONG uReturn1 = 0;
while( pEnumerator1 ) {
hres = pEnumerator1->Next( WBEM_INFINITE, 1,
&pclsObj1, &uReturn1 );
if(0 == uReturn1) break;
// reference logical drive to partition
VARIANT vtProp1;
hres = pclsObj1->Get( _bstr_t(L"DeviceID"), 0, &vtProp1, 0, 0 );
wstring wstrQuery = L"Associators of {Win32_DiskPartition.DeviceID='";
wstrQuery += vtProp1.bstrVal;
wstrQuery += L"'} where AssocClass=Win32_LogicalDiskToPartition";
IEnumWbemClassObject* pEnumerator2 = NULL;
hres = pSvc->ExecQuery(
bstr_t("WQL"),
bstr_t(wstrQuery.c_str()),
WBEM_FLAG_FORWARD_ONLY | WBEM_FLAG_RETURN_IMMEDIATELY,
NULL,
&pEnumerator2 );
if ( FAILED(hres) ) {
cout << "Query for processes failed. "
<< "Error code = 0x"
<< hex << hres << endl;
pSvc->Release();
pLoc->Release();
CoUninitialize();
return FALSE; // Program has failed.
} else {
// get driveletter
IWbemClassObject *pclsObj2;
ULONG uReturn2 = 0;
while( pEnumerator2 ) {
hres = pEnumerator2->Next( WBEM_INFINITE, 1,
&pclsObj2, &uReturn2 );
if(0 == uReturn2) break;
VARIANT vtProp2;
hres = pclsObj2->Get( _bstr_t(L"DeviceID"), 0, &vtProp2, 0, 0 );
// print result
printf("%ls : %ls\n", vtProp.bstrVal, vtProp2.bstrVal);
VariantClear( &vtProp2 );
}
pclsObj1->Release();
}
VariantClear( &vtProp1 );
pEnumerator2->Release();
}
pclsObj->Release();
}
VariantClear( &vtProp );
pEnumerator1->Release();
}
}
pEnumerator->Release();
return TRUE;
}
BOOL wmi_close()
{
// Cleanup
// ========
pSvc->Release();
pLoc->Release();
CoUninitialize();
return 0; // Program successfully completed.
}
This MSDN article explains how to use WMI to get from a disk drive to a list of the drive letters on it (it's the final section of the page).
You can use Win32_DiskDrivePhysicalMedia to get from the physical media to the disk drive.
But if you actually want a list of partitions, why not start at Win32_LogicalDisk?