2

I'm wanting to get a list of all physical disks under Windows and was linked to this question yesterday which does work, but it doesn't seem to find my unformatted hard drive (and although I don't think it makes a difference, the disk is connected via USB).

Is there another solution to getting the "\\.\PhysicalDrive" name for ALL connected hard disks?

Community
  • 1
  • 1
Lander
  • 3,369
  • 2
  • 37
  • 53

3 Answers3

2

You can use the SetupDi API to list all devices in the "DISK" class. (It will be the same list shown in Device Manager)

Ben Voigt
  • 277,958
  • 43
  • 419
  • 720
  • This seems like it would work perfectly, but do you know of any samples that would work in this situation? I was looking at [this](http://stackoverflow.com/questions/3438366/setupdigetdeviceproperty) and changed "USB" to NULL to list all devices, and it lists everything I'd like it to but it seems like there has to be an easier way, and I'm not sure how to convert the ID to a GUID to use in order to get the physical drive path. I'll try do some more hunting to see if I can find more information on how to properly utilize this API... – Lander Dec 17 '11 at 00:54
  • Figured out how to list only disk drives (GUID class {4D36E967-E325-11CE-BFC1-08002BE10318}), now the question of getting the volume's GUID or physical drive path. – Lander Dec 17 '11 at 01:56
  • Okay, after some research I've found that the example linked in the first comment wasn't too far off, but I should have been enumerating device interfaces to get the proper path to use in the CreateFile function. The code is closer to what's [here](http://stackoverflow.com/questions/8263380/send-ioctl-to-windows-device-driver-createfile-fails), except with 'GUID_DEVINTERFACE_DISK' as the interface GUID. Thank you for leading me in the correct direction! – Lander Dec 17 '11 at 06:18
1

For anyone who may come across this in future searches, here's what I eventually came up with. Note that there are a few undefined types that are a part of external libraries or defined by me, and not a part of Windows. e.g. nowide and qDebug

The commenting is poor to say the least, but cross-referencing MSDN documentation for the function calls should get you on your way. The goal was to list every list every disk, and obtain the required information to both allow me to get a HANDLE for the device, AND populate the Plug and Play information (the device description/name).

typedef struct _DISK_DRIVE_INFORMATION
{
    std::string Path;
    std::string FriendlyName;
} DISK_DRIVE_INFORMATION;

unsigned i;
DWORD dwSize, dwPropertyRegDataType = SPDRP_PHYSICAL_DEVICE_OBJECT_NAME;
CONFIGRET r;
HDEVINFO hDevInfo;
SP_DEVINFO_DATA DeviceInfoData;
SP_DEVICE_INTERFACE_DATA interfaceData;

TCHAR szDeviceInstanceID [MAX_DEVICE_ID_LEN];
TCHAR szDesc[1024];

GUID HddClass;
HddClass = GUID_DEVINTERFACE_DISK;//GUID_DEVCLASS_DISKDRIVE;

// List all connected disk drives
hDevInfo = SetupDiGetClassDevs (&HddClass, NULL, NULL, DIGCF_PRESENT | DIGCF_DEVICEINTERFACE);
if (hDevInfo == INVALID_HANDLE_VALUE)
    return;

// Find the ones that are driverless
for (i = 0; ; i++)
{
    DeviceInfoData.cbSize = sizeof (DeviceInfoData);
    // Get the next device info
    if (!SetupDiEnumDeviceInfo(hDevInfo, i, &DeviceInfoData))
        break;
    interfaceData.cbSize = sizeof(SP_INTERFACE_DEVICE_DATA);
    // Get the next device interface
    if (!SetupDiEnumInterfaceDevice(hDevInfo, NULL, &HddClass, i, &interfaceData))
    {
        break;
    }

    // Get the device ID
    r = CM_Get_Device_ID(DeviceInfoData.DevInst, szDeviceInstanceID , MAX_PATH, 0);
    if (r != CR_SUCCESS)
        continue;

    // To add to the vector
    DISK_DRIVE_INFORMATION AddToVector;

    DWORD requiredSize = 0;

    // Get the path
    SetupDiGetDeviceInterfaceDetail(hDevInfo, &interfaceData, NULL, NULL, &requiredSize, NULL);
    SP_INTERFACE_DEVICE_DETAIL_DATA* data = (SP_INTERFACE_DEVICE_DETAIL_DATA*) malloc(requiredSize);

    data->cbSize = sizeof(SP_INTERFACE_DEVICE_DETAIL_DATA);


    if (!SetupDiGetDeviceInterfaceDetail(hDevInfo, &interfaceData, data, requiredSize, NULL, NULL))
    {
        continue;
    }

    AddToVector.Path = nowide::convert(std::wstring(data->DevicePath));
    qDebug("Disk path: %s", AddToVector.Path.c_str());

    // Friendly name (e.g. SanDisk Cruzer USB...)
    SetupDiGetDeviceRegistryProperty (hDevInfo, &DeviceInfoData, SPDRP_FRIENDLYNAME,
                                      &dwPropertyRegDataType, (BYTE*)szDesc,
                                      sizeof(szDesc),   // The size, in bytes
                                      &dwSize);
    AddToVector.FriendlyName = nowide::convert(std::wstring((TCHAR*)szDesc));
    qDebug("Friendly name: %s", AddToVector.FriendlyName.c_str());

    OutVector.push_back(AddToVector);
    delete data;
}
Lander
  • 3,369
  • 2
  • 37
  • 53
1

Or you can use WMI...

#include <comutil.h>
#pragma comment(lib, "comsuppd.lib")
#pragma comment(lib, "comsuppwd.lib")
#define _WIN32_DCOM
#include <wbemcli.h>
#pragma comment(lib, "wbemuuid.lib")

#include <string>
#include <vector>

using namespace std;

IWbemLocator* pWbemLoc;
IWbemServices* pWbemSvc;

bool ReleaseWMI()
{
    if (pWbemSvc != NULL)
        pWbemSvc->Release();
    pWbemSvc = NULL;
    if (pWbemLoc != NULL)
        pWbemLoc->Release();
    pWbemLoc = NULL;

    CoUninitialize();

    return true;
}

bool InitWMI()
{
    HRESULT hr;
    hr = CoInitializeEx(0, COINIT_MULTITHREADED);
    if (FAILED(hr))
        return false;

    hr = CoInitializeSecurity(
        NULL,
        -1,
        NULL,
        NULL,
        RPC_C_AUTHN_LEVEL_DEFAULT,
        RPC_C_IMP_LEVEL_IMPERSONATE,
        NULL,
        EOAC_NONE,
        NULL);
    if (FAILED(hr))
        return false;

    HRESULT hres = CoCreateInstance(CLSID_WbemLocator, 0, CLSCTX_INPROC_SERVER, IID_IWbemLocator, (LPVOID*) &pWbemLoc);
    if(FAILED(hres))
    {
        ReleaseWMI();
        return false;
    }

    hres = pWbemLoc->ConnectServer(_bstr_t(L"ROOT\\CIMV2"), NULL, NULL, NULL, WBEM_FLAG_CONNECT_USE_MAX_WAIT, NULL, NULL, &pWbemSvc);
    if(FAILED(hres))
    {
        ReleaseWMI();
        return false;
    }

    hres = CoSetProxyBlanket(pWbemSvc, RPC_C_AUTHN_WINNT, RPC_C_AUTHZ_NONE, NULL, RPC_C_AUTHN_LEVEL_CALL, RPC_C_IMP_LEVEL_IMPERSONATE, NULL, EOAC_NONE);
    if(FAILED(hres))
    {
        ReleaseWMI();
        return false;
    }

    return true;
}

struct diskInfo
{
    wstring deviceId;
    wstring freeSpace;
};

wstring GetProperty(IWbemClassObject* pclsObj, const wstring &property)
{
    wstring retVal( L"" );
    VARIANT vtProp;
    VariantInit(&vtProp);
    HRESULT hr;
    hr = pclsObj->Get(property.c_str(),0,&vtProp,0,0);
    if (!FAILED(hr))
    {
        VARIANT vtBstrProp;
        VariantInit(&vtBstrProp);
        hr = VariantChangeType(&vtBstrProp, &vtProp, 0, VT_BSTR);
        if (!FAILED(hr))
        {
            retVal = vtBstrProp.bstrVal;
        }
        VariantClear(&vtBstrProp);
    }
    VariantClear(&vtProp);

    return retVal;
}

bool QueryWMI(_bstr_t query, vector<diskInfo> &disks)
{
    bool bRet = false;

    HRESULT hres;
    IEnumWbemClassObject* pEnumerator = NULL;
    IWbemClassObject* pclsObj = NULL;

    if(pWbemSvc)
    {
        hres = pWbemSvc->ExecQuery(bstr_t("WQL"), query, WBEM_FLAG_FORWARD_ONLY | WBEM_FLAG_RETURN_IMMEDIATELY, NULL, &pEnumerator);
        if(!FAILED(hres))
        {
            ULONG uReturn = 0;
            while(pEnumerator)
            {
                HRESULT hr = pEnumerator->Next(WBEM_INFINITE, 1, &pclsObj, &uReturn);
                if(uReturn == 0)
                    break;
                diskInfo d;
                d.deviceId  = GetProperty(pclsObj, L"DeviceID");
                d.freeSpace = GetProperty(pclsObj, L"FreeSpace");
                disks.push_back(d);
                bRet = true;
            }
            if(pclsObj != NULL)
                pclsObj->Release();
            if(pEnumerator != NULL)
                pEnumerator->Release();
        }
    }

    return bRet;
}

void main()
{
    InitWMI();
    vector<diskInfo> d;
    bool ret = QueryWMI(bstr_t("SELECT * FROM Win32_LogicalDisk WHERE DriveType=3"), d);
    ReleaseWMI();
}
Mike Caron
  • 5,674
  • 4
  • 48
  • 71