DevicePath Information

In Windows based environment, each device belongs to a device class, and the operating system assigns a unique device path and instance ID to identify each device.

In this article, you'll see how to retrieve the device path and the device instance ID for storage devices attached to a system. I strongly suggest that you also read the MSDN artcles as well.

I have used following APIs to achieve the same results:

HDEVINFO  SetupDiGetClassDevs( 
         IN LPGUID  ClassGuid..OPTIONAL, 
         IN PCTSTR  Enumerator..OPTIONAL,
         IN HWND  hwndParent..OPTIONAL,
         IN DWORD  Flags);

The SetupDiGetClassDevs function returns a handle to the device information set. For a full description of this class, please see the MSDN article.

         IN HDEVINFO  DeviceInfoSet,    
         IN DWORD  MemberIndex,    
         OUT PSP_DEVINFO_DATA  DeviceInfoData);

The SetupDiEnumDeviceInf function returns SP_DEVINFO_DATA structure from the the device information set. For detailed information please see this MSDN article.

WINSETUPAPI BOOL WINAPI SetupDiEnumDeviceInterfaces(
         IN HDEVINFO  DeviceInfoSet,    
         IN PSP_DEVINFO_DATA  DeviceInfoData  OPTIONAL,
         IN LPGUID  InterfaceClassGuid,    
         IN DWORD  MemberIndex,    
         OUT PSP_DEVICE_INTERFACE_DATA DeviceInterfaceData);

The SetupDiEnumDeviceInterfaces function enumerates the device interfaces presented within the device information set.

WINSETUPAPI BOOL WINAPI  SetupDiGetDeviceInterfaceDetail(
          IN HDEVINFO  DeviceInfoSet,    
          IN PSP_DEVICE_INTERFACE_DATA DeviceInterfaceData,    
          OUT PSP_DEVICE_INTERFACE_DETAIL_DATA  DeviceInterfaceDetailData..OPTIONAL,    
          IN DWORD  DeviceInterfaceDetailDataSize,    
          OUT PDWORD  RequiredSize..OPTIONAL,    
          OUT PSP_DEVINFO_DATA  DeviceInfoData OPTIONAL);

The SetupDiGetDeviceInterfaceDetail function helps to retrieve details about a device. To get details about the interfaces you need to call this function twice. First, Call SetupDiGetDeviceInterfaceDetail with a NULL DeviceInterfaceDetailData pointer, a DeviceInterfaceDetailDataSize of zero, and a valid RequiredSize variable. In response to this function call, the function returns the required buffer size to RequiredSize variable. You can then allocate a buffer[TCHAR] and call the function again, which in turn returns the interface details.

WINSETUPAPI BOOL WINAPI  SetupDiGetClassDescription(
         IN LPGUID  ClassGuid,    
         OUT PTSTR  ClassDescription,    
         IN DWORD  ClassDescriptionSize,    
         OUT PDWORD  RequiredSize  OPTIONAL);

The SetupDiGetClassDescription function returns the class description associated with the setup GUID.

WINSETUPAPI BOOL WINAPI  SetupDiGetDeviceInstanceId(    
         IN HDEVINFO  DeviceInfoSet,    
         IN PSP_DEVINFO_DATA  DeviceInfoData,    
         OUT PTSTR  DeviceInstanceId,    
         IN DWORD  DeviceInstanceIdSize,     
         OUT PDWORD  RequiredSize  OPTIONAL);

The SetupDiGetDeviceInstanceId function returns device instance Id associated with device information element.

The following demo code snippet is the implemenation details to get attached storage devices device path and device instance ID:

// USB_Drive_Property.cpp : Defines the entry point for the console application.

#include "stdafx.h"
#include "USB_Drive_Property.h"
#include <windows.h>
#include <SetupApi.h> // Included from Windows SDKs

#ifdef _DEBUG
#define new DEBUG_NEW

// Defined in winioctl.h
DEFINE_GUID(GUID_DEVINTERFACE_VOLUME, 0x53f5630dL, 0xb6bf, 0x11d0, 0x94, 0xf2, 0x00, 0xa0, 0xc9, 0x1e, 0xfb, 0x8b);

// The one and only application object

CWinApp theApp;

using namespace std;

int _tmain(int argc, TCHAR* argv[], TCHAR* envp[])
   int nRetCode = 0;
   // initialize MFC and print and error on failure
   if (!AfxWinInit(::GetModuleHandle(NULL), NULL, ::GetCommandLine(), 0))
      // TODO: change error code to suit your needs
      _tprintf(_T("Fatal Error: MFC initialization failed\n"));
      nRetCode = 1;
      // TODO: code your application's behavior here.

      HDEVINFO hDevHandle;
      SP_DEVICE_INTERFACE_DATA deviceInterfaceData;
      DWORD required = 0;
      deviceInterfaceData.cbSize = sizeof(SP_DEVICE_INTERFACE_DATA);

      int nBufferSize = 0;
      SP_DEVINFO_DATA devInfoData;
      devInfoData.cbSize = sizeof(SP_DEVINFO_DATA);

      DWORD MemberIndex = 0;
      BOOL  Result;

      hDevHandle = SetupDiGetClassDevs(&GUID_DEVINTERFACE_VOLUME, NULL, NULL, 

      if(hDevHandle == INVALID_HANDLE_VALUE)
         return 1;
         BOOL bStart = false;
         TCHAR *buffer = NULL;
         PSP_DEVICE_INTERFACE_DETAIL_DATA devicedetailData;
				Result = SetupDiEnumDeviceInfo(hDevHandle, MemberIndex, &devInfoData);

				   Result = SetupDiEnumDeviceInterfaces(hDevHandle, 0, &GUID_DEVINTERFACE_VOLUME, 
                  MemberIndex, &deviceInterfaceData);
               delete []buffer;
               buffer = NULL;
               return 1;

            BOOL detailResult = FALSE;
               // As per MSDN, Get the required buffer size. Call SetupDiGetDeviceInterfaceDetail with a 
               // NULL DeviceInterfaceDetailData pointer, a DeviceInterfaceDetailDataSize of zero, 
               // and a valid RequiredSize variable. In response to such a call, this function returns 
               // the required buffer size at RequiredSize and fails with GetLastError returning 
               // Allocate an appropriately sized buffer and call the function again to get the interface details. 

               SetupDiGetDeviceInterfaceDetail(hDevHandle, &deviceInterfaceData, NULL, 0, &required, NULL);

               buffer = new TCHAR[required];
               devicedetailData = (PSP_DEVICE_INTERFACE_DETAIL_DATA) buffer;
               devicedetailData->cbSize = sizeof(SP_INTERFACE_DEVICE_DETAIL_DATA);
               nBufferSize = required;
               bStart = true;

            detailResult = SetupDiGetDeviceInterfaceDetail(hDevHandle, &deviceInterfaceData, 
               devicedetailData, nBufferSize , &required, NULL);

            _tprintf(L"Device Path = %s\n\n", devicedetailData->DevicePath);

               TCHAR szDescription[MAX_PATH];
               memset(szDescription, 0, MAX_PATH);

               SetupDiGetClassDescription(&devInfoData.ClassGuid, szDescription, MAX_PATH, &required);
               _tprintf(L"Class Description = %s\n\n", szDescription);

               memset(szDescription, 0, MAX_PATH);
               SetupDiGetDeviceInstanceId(hDevHandle, &devInfoData, szDescription, MAX_PATH, 0);
               _tprintf(L"Device Instance Id = %s\n\n\n", szDescription);


   return nRetCode;

The snap shot of the output looks like the picture below:

This article was originally published on March 25th, 2009

About the Author

Mufti Mohammed

Small-Talk and Small-Programming working together. My Blog

Most Popular Programming Stories

More for Developers

RSS Feeds

Thanks for your registration, follow us on our social networks to keep up-to-date