I will do this once. Here is some code I wrote a few years ago for my own
use. It will be somewhat mangled by the email software, but it works and
has worked for several years. It is a mapping of drive letters to physical
drives from a user mode application. You may study it and use it to create
your own implementation as you see fit for any purpose. You are not going
to like it with all the funny C++ features and use of interesting stuff. I
removed the full file names from this post.
// Wmi.h - Header file for Wmi.cpp
//
// Copyright (c) 2003 by David J. Craig
//
class ID1
{
public:
CString Physical;
CString Partition;
CString FullPart;
ID1() : Physical(“”), Partition(“”), FullPart(“”) {}
ID1(CString newPhysical, CString newPartition, CString newFull) : \
Physical(newPhysical), Partition(newPartition), FullPart(newFull) {}
};
class ID2
{
public:
CString Partition;
CString Logical;
CString FullPart;
ID2() : Partition(“”), Logical(“”), FullPart(“”) {}
ID2(CString newPartition, CString newLogical, CString newFull) : \
Partition(newPartition), Logical(newLogical), FullPart(newFull) {}
};
typedef vector < ID1 > VECPHY;
typedef vector < ID2 > VECLOG;
void WINAPI WaitThread(HANDLE hWait);
// Wmi.cpp - source file for WMI interface
//
// Copyright (c) 2003 by David J. Craig
//
// The functions in this file are defined in CDlg.h except for
// WaitThread() which is not a member of the CDlg class.
//
//#pragma warning(disable: 4201)
#include “stdafx.h”
using namespace std;
#include <devioctl.h>
#include <wbemidl.h>
#include
#include
#include <mountmgr.h>
#include <mountdev.h>
#include <strsafe.h>
#include <ntdddisk.h>
#include <ntddscsi.h>
#include <ntddstor.h>
#include “Format32.h”
#include “Format32Wmi.h”
#include “Fat.h”
#include “Lfn.h”
#include “Fatnn.h”
#include “Fat32.h”
#include “Fat16.h”
#include “Fat12.h”
#include “PhysicalDrive.h”
#include “Format32Dlg.h”
#pragma comment(user, “Copyright (c) 2003 by David J. Craig\n”)
#pragma comment(user, “Compiled on " DATE” at " TIME )
#pragma comment(user, “Compiling " FILE )
#pragma comment(user, “Last modified on " TIMESTAMP )
#pragma comment(lib, “wbemuuid.lib”) // WMI library
#pragma message(“Copyright (c) 2003 by David J. Craig\n”)
#pragma message(“Compiled on " DATE” at " TIME )
#pragma message(“Compiling " FILE )
#pragma message(“Last modified on " TIMESTAMP )
int
CFormat32Dlg::GetPhysicalMap(IWbemServices * pIWbemServices)
{
HRESULT hr;
BSTR PropName = NULL;
VARIANT vVal;
ULONG uReturned;
BSTR PerfClass;
CString str;
CString physical;
CString partition;
CString FullPart;
IEnumWbemClassObject * pEnum = NULL;
IWbemClassObject * pPerfInst = NULL;
// Initialization
//
VariantInit(&vVal);
PerfClass = NULL;
// Alloc class name string for DiskPerf
//
PerfClass = SysAllocString(L"Win32_DiskDriveToDiskPartition”);
// Now that the data class info is displayed,
// go get the values for all the disk instances
//
if (!PerfClass)
{
str.Format(_T(“SysAllocString() failed: %u\n”), GetLastError());
AfxMessageBox(str);
return(1);
}
// Create enumerator
//
hr = pIWbemServices->CreateInstanceEnum(
PerfClass,
WBEM_FLAG_SHALLOW,
NULL,
&pEnum
);
SysFreeString(PerfClass);
PerfClass = NULL;
if (hr == WBEM_NO_ERROR)
{
while (pEnum->Next(
INFINITE,
1,
&pPerfInst,
&uReturned) == WBEM_NO_ERROR)
{
// Explicitly get the properties of InstanceName and Active state
// Get the Instance Name string
//
PropName = L"Antecedent”;
if ((pPerfInst->Get(
PropName,
0L,
&vVal,
NULL,
NULL)) == WBEM_NO_ERROR)
{
int i;
ASSERT(V_VT(&vVal) == VT_BSTR);
physical = V_BSTR(&vVal);
i = physical.Find(_T(“PHYSICALDRIVE”));
physical = physical.Right(physical.GetLength() - i);
i = physical.Find(_T(”"”));
physical = physical.Left(i);
VariantClear(&vVal);
}
PropName = L"Dependent";
if ((pPerfInst->Get(
PropName,
0L,
&vVal,
NULL,
NULL)) == WBEM_NO_ERROR)
{
int i;
ASSERT(V_VT(&vVal) == VT_BSTR);
partition = V_BSTR(&vVal);
FullPart = V_BSTR(&vVal);
i = partition.Find(_T(“Disk #”));
partition = partition.Right(partition.GetLength() - i);
i = FullPart.Find(_T(“Disk #”));
FullPart = FullPart.Right(FullPart.GetLength() - i);
i = partition.Find(_T(“, Partition”));
partition = partition.Left(i);
i = FullPart.Find(_T(“"”));
FullPart = FullPart.Left(i);
VariantClear(&vVal);
}
m_Phy.push_back(ID1(physical, partition, FullPart));
pPerfInst->Release();
}
pEnum->Release();
}
else
{
str.Format(_T(“CreateInstanceEnum() failed: %u\n”), GetLastError());
AfxMessageBox(str);
return(2);
}
return(0);
}
int
CFormat32Dlg::GetLogicalMap(IWbemServices * pIWbemServices)
{
HRESULT hr;
BSTR PropName = NULL;
VARIANT vVal;
ULONG uReturned;
BSTR PerfClass;
CString str;
CString logical;
CString partition;
CString FullPart;
IEnumWbemClassObject * pEnum = NULL;
IWbemClassObject * pPerfInst = NULL;
// Initialization
//
VariantInit(&vVal);
PerfClass = NULL;
// Alloc class name string for DiskPerf
//
PerfClass = SysAllocString(L"Win32_LogicalDiskToPartition");
// Now that the data class info is displayed,
// go get the values for all the disk instances
//
if (!PerfClass)
{
str.Format(_T(“SysAllocString() failed: %u\n”), GetLastError());
AfxMessageBox(str);
return(11);
}
// Create enumerator
//
hr = pIWbemServices->CreateInstanceEnum(
PerfClass,
WBEM_FLAG_SHALLOW,
NULL,
&pEnum
);
SysFreeString(PerfClass);
PerfClass = NULL;
if (hr == WBEM_NO_ERROR)
{
while (pEnum->Next(
INFINITE,
1,
&pPerfInst,
&uReturned) == WBEM_NO_ERROR)
{
// Explicitly get the properties of InstanceName and Active state
// Get the Instance Name string
//
PropName = L"Antecedent";
if ((pPerfInst->Get(
PropName,
0L,
&vVal,
NULL,
NULL)) == WBEM_NO_ERROR)
{
int i;
ASSERT(V_VT(&vVal) == VT_BSTR);
partition = V_BSTR(&vVal);
FullPart = V_BSTR(&vVal);
i = partition.Find(_T(“Disk #”));
partition = partition.Right(partition.GetLength() - i);
i = FullPart.Find(_T(“Disk #”));
FullPart = FullPart.Right(FullPart.GetLength() - i);
i = partition.Find(_T(“, Partition”));
partition = partition.Left(i);
i = FullPart.Find(_T(“"”));
FullPart = FullPart.Left(i);
VariantClear(&vVal);
}
PropName = L"Dependent";
if ((pPerfInst->Get(
PropName,
0L,
&vVal,
NULL,
NULL)) == WBEM_NO_ERROR)
{
int i;
ASSERT(V_VT(&vVal) == VT_BSTR);
logical = V_BSTR(&vVal);
i = logical.Find(_T(“"”));
logical = logical.Right(logical.GetLength() - i - 1);
i = logical.Find(_T(“"”));
logical = logical.Left(i);
VariantClear(&vVal);
}
m_Log.push_back(ID2(partition, logical, FullPart));
pPerfInst->Release();
}
pEnum->Release();
}
else
{
str.Format(_T(“CreateInstanceEnum() failed: %u\n”), GetLastError());
AfxMessageBox(str);
return(12);
}
return(0);
}
void WINAPI
WaitThread(HANDLE hWait)
{
while (::WaitForSingleObject(hWait, 300) == WAIT_TIMEOUT)
{
// We don’t want to do anything here.
}
return;
}
BOOL
CFormat32Dlg::InitSecurity(void)
{
// Adjust the security to allow client impersonation.
//
HRESULT hres = CoInitializeSecurity(
NULL,
-1,
NULL,
NULL,
RPC_C_AUTHN_LEVEL_PKT_PRIVACY,
RPC_C_IMP_LEVEL_IMPERSONATE,
NULL,
EOAC_SECURE_REFS,
NULL
);
return(SUCCEEDED(hres));
}
int
CFormat32Dlg::GetMapping()
{
HRESULT hr;
DWORD ThreadId;
DWORD dwLen = MAX_COMPUTERNAME_LENGTH + 1;
HANDLE hWait;
HANDLE hThread;
BSTR pNamespace;
TCHAR szSysName[MAX_COMPUTERNAME_LENGTH + 3];
CString str;
IWbemLocator * pIWbemLocator;
IWbemServices * pIWbemServices;
// Initialization
//
pIWbemLocator = NULL;
pIWbemServices = NULL;
if (!SUCCEEDED(CoInitialize(NULL)) || !InitSecurity())
{
str.Format(_T(“COM stuff hosed\n”));
AfxMessageBox(str);
return(21);
}
// Create an instance of the WbemLocator interface.
//
if (CoCreateInstance(
CLSID_WbemLocator,
NULL,
CLSCTX_INPROC_SERVER,
IID_IWbemLocator,
( LPVOID * ) &pIWbemLocator) == S_OK)
{
StringCbCopy(szSysName, sizeof(szSysName), _T(“\\”));
BOOL bRes = GetComputerName(szSysName + 2, &dwLen);
if (!bRes)
{
str.Format(_T(“GetComputerName() failed: %u\n”), GetLastError());
AfxMessageBox(str);
CoUninitialize();
return(22);
}
pNamespace = SysAllocString(L"root\cimv2");
if (!pNamespace)
{
str.Format(_T(“SysAllocString() failed: %u\n”), GetLastError());
AfxMessageBox(str);
CoUninitialize();
return(23);
}
// make a wait event and kick off wait thread
//
hWait = CreateEvent(NULL, TRUE, FALSE, NULL);
hThread = CreateThread(
NULL,
0,
( LPTHREAD_START_ROUTINE ) WaitThread,
hWait,
0,
&ThreadId
);
// connect and get the IWbemServices pointer
//
hr = pIWbemLocator->ConnectServer(
pNamespace,
NULL,
NULL,
0L,
0L,
NULL,
NULL,
&pIWbemServices
);
// kill wait feedback thread
//
SetEvent(hWait);
// make sure thread is gone
//
WaitForSingleObject(hThread, INFINITE);
CloseHandle(hWait);
SysFreeString(pNamespace);
// See what WBEM/WMI says about
//
if (hr == WBEM_NO_ERROR)
{
// done with locator object
//
pIWbemLocator->Release();
// go enumerate diskperf instances…
//
GetPhysicalMap(pIWbemServices);
GetLogicalMap(pIWbemServices);
pIWbemServices->Release();
}
else
{
str.Format(_T(“Failed to connect with %s: 0x%X\n”),
szSysName,
hr
);
AfxMessageBox(str);
return(24);
}
}
else
{
str.Format(_T(“WMI services not present or unavailable!\n”));
AfxMessageBox(str);
return(25);
}
CoUninitialize();
return(0);
}
__________________________________________________
–
David J. Craig
Engineer, Sr. Staff Software Systems
Broadcom Corporation
wrote in message news:xxxxx@ntdev…
>> One common way is to open each device by its device interface and issue
>> an
>> IOCTL_STORAGE_GET_DEVICE_NUMBER. Then open each drive letter and issue
>> the same
>> IOCTL. When you have drive numbers that match you’ve found your device.
>
> You make an assumption that the target disk is removable, i.e. that it may
> have only one physical partition and that drive letter corresponds to the
> physical partition itself ( Ftdisk.sys does not get involved with
> removable media, so that logical volumes don’t apply). If this is the
> case, then, indeed, the above approach will work just fine.
>
> However, please don’t forget that USB device may present itself as a
> basic, rather than removable, disk. In such case we have 2 problems with
> the above approach:
>
> 1. Logical volumes may be mounted on the target device, so that drive
> letter will correspond not to the physical partition itself but to the
> logical volume that is mounted on it. IOCTL_STORAGE_GET_DEVICE_NUMBER is a
> disk-related IOCTL that has to be sent to the storage stack where Disk.sys
> participates, so that sending it to Ftdisk.sys is going to be, apparently,
> of no help here
>
> 2. To make things even more complex, the target device may have more than
> one physical partition, and, hence, multiple logical volumes may be
> mounted on it. Therefore, there is no one-to-one correspondence between a
> disk number and a drive letter, because multiple drive letters may
> correspond to the same device.
>
> Anton Bassov
>
></ntddstor.h></ntddscsi.h></ntdddisk.h></strsafe.h></mountdev.h></mountmgr.h></wbemidl.h></devioctl.h>