CodeGuru Home VC++ / MFC / C++ .NET / C# Visual Basic VB Forums Developer.com
Page 1 of 2 12 LastLast
Results 1 to 15 of 16
  1. #1
    Join Date
    Feb 2009
    Location
    Portland, OR
    Posts
    1,488

    [RESOLVED] Need to get name of a USB flash drive device

    Hi:


    I've asked this question before but did not receive an answer. Please take a look at this screenshot:
    http://www.codeguru.com/forum/attach...1&d=1273174719

    How to get the name of a USB flash drive device like shown there?

    PS. GetVolumeInformation() returns only the volume name given to the device during formatting (and may be an empty string).

  2. #2
    Arjay's Avatar
    Arjay is offline Moderator / EX MS MVP Power Poster
    Join Date
    Aug 2004
    Posts
    13,490

    Re: Need to get name of a USB flash drive device

    What are you trying to do? Read the name of a USB device? Stop a USB device?

  3. #3
    Join Date
    Feb 2009
    Location
    Portland, OR
    Posts
    1,488

    Re: Need to get name of a USB flash drive device

    Quote Originally Posted by Arjay View Post
    What are you trying to do? Read the name of a USB device? Stop a USB device?
    Get the list of all USB devices inserted in the system and yes, stop (or eject) any at a user's request. (I know how to eject them, so all I need is to get names.) The code currently uses GetVolumeInformation() to retrieve a USB device name but that method has a flaw when it returns an empty string for some of them.

  4. #4
    Arjay's Avatar
    Arjay is offline Moderator / EX MS MVP Power Poster
    Join Date
    Aug 2004
    Posts
    13,490

    Re: Need to get name of a USB flash drive device

    Post the code that ejects the drive and I'll see if my approach using WMI works.

  5. #5
    Join Date
    Feb 2009
    Location
    Portland, OR
    Posts
    1,488

    Re: Need to get name of a USB flash drive device

    Here you go (all error checks are removed):

    Code:
    1. The drive being ejected is represented by 
       szVolumePath, format: '\\.\X:'
       szDevicePath, format: 'X:'
    
    2. Get the volume's device number in DeviceNumber:
    
       HANDLE hVolume = CreateFile(szVolumePath, 0, 
    	FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, 
    	OPEN_EXISTING, NULL, NULL);
    
       STORAGE_DEVICE_NUMBER sdn;
       DeviceIoControl(hVolume, IOCTL_STORAGE_GET_DEVICE_NUMBER, NULL, 0, 
    	&sdn, sizeof(sdn), &dwBytesReturned, NULL);
    
       CloseHandle(hVolume);
    
       DeviceNumber = sdn.DeviceNumber;
    
    4. Get device instance handle in DevInst:
    
       DEVINST DevInst = 0;
    
       switch(GetDriveType(szDevicePath))
       {
          //Need only these devices
          case DRIVE_REMOVABLE:
          case DRIVE_FIXED:
            break;
          default:
    	return;
       }
    
       HDEVINFO hDevInfo = SetupDiGetClassDevs(GUID_DEVINTERFACE_DISK,
    	NULL, NULL, DIGCF_PRESENT | DIGCF_DEVICEINTERFACE);
    
       DWORD dwSize;
       BYTE pLargeBuffer[1024];
       SP_DEVINFO_DATA spdd;
       SP_DEVICE_INTERFACE_DATA spdid;
       PSP_DEVICE_INTERFACE_DETAIL_DATA pspdidd = (PSP_DEVICE_INTERFACE_DETAIL_DATA)pLargeBuffer;
    
       for(int dwIndex = 0;; dwIndex++)
       {
          if(!SetupDiEnumDeviceInterfaces(hDevInfo, NULL, GUID_DEVINTERFACE_DISK, dwIndex, &spdid))
             break;
    
          SetupDiGetDeviceInterfaceDetail(hDevInfo, &spdid, pspdidd, dwSize, &dwSize, &spdd);
    
          HANDLE hDrive = CreateFile(pspdidd->DevicePath, 0, 
             FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, 0, NULL);
    
          STORAGE_DEVICE_NUMBER sdn;
          DWORD dwBytesReturned = 0;
          DeviceIoControl(hDrive, IOCTL_STORAGE_GET_DEVICE_NUMBER, 
             NULL, 0, &sdn, sizeof(sdn), &dwBytesReturned, NULL);
    
          CloseHandle(hDrive);
    
          if(DeviceNumber == sdn.DeviceNumber)
          {
             DevInst =  spdd.DevInst;
             break;
          }
       }
    
       SetupDiDestroyDeviceInfoList(hDevInfo);
    
    5. Now do the ejection:
    
       PNP_VETO_TYPE VetoType = PNP_VetoTypeUnknown; 
       WCHAR VetoNameW[MAX_PATH] = {0};
    
       DEVINST DevInstParent = 0;
       CM_Get_Parent(&DevInstParent, DevInst, 0); 
    
       long r = CM_Request_Device_EjectW(DevInstParent, &VetoType, VetoNameW, MAX_PATH, 0);
    
    6. See if succeeded:
    
       if(r == CR_SUCCESS && VetoType == PNP_VetoTypeUnknown)
           bEjectedOK = true;

  6. #6
    Arjay's Avatar
    Arjay is offline Moderator / EX MS MVP Power Poster
    Join Date
    Aug 2004
    Posts
    13,490

    Re: Need to get name of a USB flash drive device

    Do you have anything that compiles? I want to help, but I don't want to take the time to fix up the code.

  7. #7
    Join Date
    Feb 2009
    Location
    Portland, OR
    Posts
    1,488

    Re: Need to get name of a USB flash drive device

    Quote Originally Posted by Arjay View Post
    Do you have anything that compiles? I want to help, but I don't want to take the time to fix up the code.
    ...
    Attached Files Attached Files

  8. #8
    Arjay's Avatar
    Arjay is offline Moderator / EX MS MVP Power Poster
    Join Date
    Aug 2004
    Posts
    13,490

    Re: Need to get name of a USB flash drive device

    See the attached project that uses WMI to grab the info. It's a VC2008 project, so you'll have to move the stdafx.h, wmi.h, and wmitest.cpp into an earlier project.

    The sample uses a WMI class that I develop here. I extended that class to handle WMI associations.

    At any rate, here's the output on my machine with 3 USB drives attached:

    Code:
    USB Flash Memory
    Removable Disk (H:)
    
    Generic Flash Disk
    USB DISK (F:)
    
    Lexar USB Flash Drive
    Lexar (I:)
    Here's the relevant code:

    Code:
    #include "stdafx.h"
    #include "wmi.h"
    
    const LPCTSTR QueryDiskDrives	= _T("SELECT * FROM Win32_DiskDrive WHERE InterfaceType = \"USB\"");
    const LPCTSTR QueryPartitions   = _T("ASSOCIATORS OF {Win32_DiskDrive.DeviceID=\"%s\"} WHERE AssocClass = Win32_DiskDriveToDiskPartition");
    const LPCTSTR QueryLogicalDisks = _T("ASSOCIATORS OF {Win32_DiskPartition.DeviceID=\"%s\"} WHERE AssocClass = Win32_LogicalDiskToPartition");
    
    void DisplayUSBDrive( CString sDrive, CString sDescription, CString sVolumeName )
    {
      CString sDisplay;
      sDisplay.Format( _T("%s (%s)"), sVolumeName.GetLength( ) ? sVolumeName : sDescription, sDrive  );
    
      std::wcout << sDisplay.GetString( ) << std::endl << std::endl;
    }
    
    int _tmain(int argc, _TCHAR* argv[])
    {
      if( FAILED( CoInitialize( NULL ) ) )
      {
        return 0;
      }
    
      try
      {
        CWmi wmi;
    
        IEnumWbemClassObjectPtr spDiskDriveEnum, spPartitionEnum, spLogicalDiskEnum;
    
        wmi.ExecuteQueryWMIClassObjectEnum( QueryDiskDrives, spDiskDriveEnum, WBEM_FLAG_FORWARD_ONLY );
    
        IWbemClassObjectPtr spDiskDrive;
        ULONG uReturned1 = 0;
    
        while( S_OK == spDiskDriveEnum->Next( WBEM_INFINITE, 1, &spDiskDrive, &uReturned1 ) )
       {
          CString sCaption, sDeviceID, sPNPDeviceID;
    
          wmi.GetPropertyString( spDiskDrive, sCaption, L"Caption" );
          wmi.GetPropertyString( spDiskDrive, sDeviceID, L"DeviceID" );
          wmi.GetPropertyString( spDiskDrive, sPNPDeviceID, L"PNPDeviceID" );
    
          sCaption.Replace( _T(" USB Device"), _T("") );
    
          std::wcout << sCaption.GetString( ) << std::endl;
          // std::wcout << L"DeviceID:    " << sDeviceID.GetString( ) << std::endl;
          // std::wcout << L"PNPDeviceID: " << sPNPDeviceID.GetString( ) << std::endl;
    
          sDeviceID.Replace( _T("\\"), _T("\\\\") );
    
          CString sPartitions;
          sPartitions.Format( QueryPartitions, sDeviceID ); 
    
          wmi.ExecuteQueryWMIClassObjectEnum( sPartitions.GetString( ), spPartitionEnum, WBEM_FLAG_FORWARD_ONLY );
    
          IWbemClassObjectPtr spPartition;
    
          ULONG uReturned2 = 0;
    		
          while( S_OK == spPartitionEnum->Next( WBEM_INFINITE, 1, &spPartition, &uReturned2 ) )
          {
            CString sDevID;
    
            wmi.GetPropertyString( spPartition, sDevID, L"DeviceID" );
    
            CString sLogicalDisks;
            sLogicalDisks.Format( QueryLogicalDisks, sDevID ); 
    
            wmi.ExecuteQueryWMIClassObjectEnum( sLogicalDisks.GetString( ), spLogicalDiskEnum, WBEM_FLAG_FORWARD_ONLY );
    
            IWbemClassObjectPtr spLogicalDisk;
    
            ULONG uReturned3 = 0;
    
            while( S_OK == spLogicalDiskEnum->Next( WBEM_INFINITE, 1, &spLogicalDisk, &uReturned3 ) )
            {
               CString sDrive, sDescription, sVolumeName;
    
                wmi.GetPropertyString( spLogicalDisk, sDrive, L"DeviceID" );
                wmi.GetPropertyString( spLogicalDisk, sDescription, L"Description" );
                wmi.GetPropertyString( spLogicalDisk, sVolumeName, L"VolumeName" );
    
                // std::wcout << L"Drive:      " << sDrive.GetString( ) << std::endl;
                // std::wcout << L"Drive:      " << sDescription.GetString( ) << std::endl;
                // std::wcout << L"VolumeName: " << sVolumeName.GetString( ) << std::endl<< std::endl;
    
                DisplayUSBDrive( sDrive, sDescription, sVolumeName );
              }
            }
          }
      }
      catch( _com_error& e )
      {
        std::wcout << L"" << e.ErrorMessage( ) << std::endl;
      }
    
      CoUninitialize( );
    
      return 0;
    }

    __________________________________________________________
    Arjay

    See my latest series on using WCF to communicate between a Windows Service and WPF task bar application.
    Tray Notify - Part I Tray Notify - Part II

    Need a little help with Win32 thread synchronization? Check out the following CG articles and posts:
    Sharing a thread safe std::queue between threads w/progress bar updating
    Simple Thread: Part I Simple Thread: Part II
    Win32 Thread Synchronization, Part I: Overview Win32 Thread Synchronization, Part 2: Helper Classes

    www.iridyn.com



    ...
    Attached Files Attached Files

  9. #9
    Join Date
    Nov 2000
    Location
    Voronezh, Russia
    Posts
    6,620

    Re: Need to get name of a USB flash drive device

    Non-WMI version.
    Attached Files Attached Files
    Last edited by Igor Vartanov; July 6th, 2010 at 10:33 AM.
    Best regards,
    Igor

  10. #10
    Join Date
    Feb 2009
    Location
    Portland, OR
    Posts
    1,488

    Re: Need to get name of a USB flash drive device

    Nice! Thank you, Arjay and Igor. Both approaches work. Now I have a new dilemma -- which method to use No, seriously, I like WMI method, it's more elegant, but on the other hand it carries a heavier overhead than Igor's Windows Driver Kit one.

  11. #11
    Join Date
    Feb 2005
    Posts
    2,160

    Re: [RESOLVED] Need to get name of a USB flash drive device

    WMI is atrociously slow compared to IOCTL. I once tried to use WMI to get various hardware signatures for a machine ID for software protection. This ran before the app would come up and it was so slow what with initializing all the WMI prerequisites and all that we had to abandon it.

  12. #12
    Arjay's Avatar
    Arjay is offline Moderator / EX MS MVP Power Poster
    Join Date
    Aug 2004
    Posts
    13,490

    Re: [RESOLVED] Need to get name of a USB flash drive device

    Speed only matters if the solution works. The IOCTL approach didn't retrieve the drive letter on my 2008 R2 machine.

    Not that this is a contest or anything.

  13. #13
    Join Date
    Feb 2009
    Location
    Portland, OR
    Posts
    1,488

    Re: [RESOLVED] Need to get name of a USB flash drive device

    Yes, as I said, WMI is way too slow but in most cases it is the only way to retrieve some hardware information. My way to use it is to call it once at the app start-up, preferably in a separate thread and cache the results.

    In my original question here WMI works perfectly since a small overhead doesn't matter that much.

    On the side note, guys, are there lower-level APIs to WMI? Because the stuff you can get with it is amazing.

  14. #14
    Arjay's Avatar
    Arjay is offline Moderator / EX MS MVP Power Poster
    Join Date
    Aug 2004
    Posts
    13,490

    Re: [RESOLVED] Need to get name of a USB flash drive device

    To help speed things up (as you know), you can initialize WMI at app startup and keep the WMI object around.

    Also, it seems that some of the WMI info (or infrastructure) is cached. I believe you will find that the first call to getting WMI info (other than initialization) takes longer than subsequent calls.

    I believe the performance would be acceptable if you initialized WMI at start up and grabbed the info on demand - say to fill out a context menu. I was actually going to code up a taskbar sample with a context menu, but I got lazy.

    Btw, many of what is available with WMI isn't easily obtained by other methods.

  15. #15
    Join Date
    Nov 2000
    Location
    Voronezh, Russia
    Posts
    6,620

    Re: [RESOLVED] Need to get name of a USB flash drive device

    The IOCTL approach didn't retrieve the drive letter on my 2008 R2 machine.
    Neither on my Win7. It needs elevated level to CreateFile on device path, then works fine. No surprise.
    Best regards,
    Igor

Page 1 of 2 12 LastLast

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •  





Click Here to Expand Forum to Full Width

Featured