CodeGuru Home VC++ / MFC / C++ .NET / C# Visual Basic VB Forums Developer.com
Results 1 to 9 of 9
  1. #1
    Join Date
    Apr 2008
    Posts
    6

    Post Need help retrieving the drive letter upon mass storage arrival

    Hi,

    I'm writing a simple software that has to detect a new USB device insertion and basically retrieve a couple of informations from it before it really start working.

    By using some MSDN references I could get the message for device arrival without major problems, however, I'm not being able to get the drive letter.

    basically this is what I did:

    1- Registered my software to receive device arrival/removal message for the desired type:

    static const GUID GUID_DEVINTERFACE_USBSTOR =
    { 0xA5DCBF10L, 0x6530, 0x11D2, { 0x90, 0x1F, 0x00, 0xC0, 0x4F, 0xB9, 0x51, 0xED } };
    ....
    hDevNotify = RegisterDeviceNotification(this->GetSafeHwnd(), &NotificationFilter, DEVICE_NOTIFY_WINDOW_HANDLE);
    ....

    then I created a ::OnMyDeviceChange(WPARAM wParam, LPARAM lParam) function to handle these notifications.

    until here, everything is working fine.
    I can get the enumeration information from a DEV_BROADCAST_DEVICEINTERFACE structure. However, according to the documentation, I would also need a DEV_BROADCAST_VOLUME structure to get the drive letter from, but seems that it's not available at the moment I get notified of a device arrival.

    So I was wondering, what can I do to get the drive letter associated to that device arrival event?

    Namaste
    Last edited by Namaste; April 23rd, 2008 at 08:31 AM.

  2. #2
    Join Date
    Jun 2006
    Location
    M31
    Posts
    885

    Re: Need help retrieving the drive letter upon mass storage arrival

    MSDN sample. =\

  3. #3
    Join Date
    Apr 2008
    Posts
    6

    Re: Need help retrieving the drive letter uppon mass storage arrival

    This is the MSDN sample that I used and mentioned before.
    however, I need two informations for a given enumeration and I'm not being able to get.

    I need to get the dbcc_name from the DEV_BROADCAST_DEVICEINTERFACE and the dbcv_unitmask from the DEV_BROADCAST_VOLUME.

    seens that I don't have both informations at the same time. first I get the DEVICEINTERFACE AND LATER THE BROADCAST_VOLUME.
    I wanted to get both at the same time to make sure they both belongs to the same enumeration.

    this is what I tried to do:
    LRESULT CTFCPROGRAMMERDlg::OnMyDeviceChange(WPARAM wParam, LPARAM lParam)
    {
    if ( DBT_DEVICEARRIVAL == wParam || DBT_DEVICEREMOVECOMPLETE == wParam )
    {
    PDEV_BROADCAST_HDR pHdr = (PDEV_BROADCAST_HDR)lParam;
    switch( pHdr->dbch_devicetype )
    {
    case DBT_DEVTYP_DEVICEINTERFACE:
    {
    PDEV_BROADCAST_DEVICEINTERFACE pDevInf = (PDEV_BROADCAST_DEVICEINTERFACE)pHdr;
    PDEV_BROADCAST_VOLUME pDevVolume = (PDEV_BROADCAST_VOLUME)pHdr;

    break;
    }
    ....

    But it won't work, so I'm looking in a better way of doing this without having to receive two messages.
    Since I will be connecting several devices to a computer, I want to make sure that I've all the information from the enumeration in one shot
    Last edited by Namaste; April 23rd, 2008 at 09:27 AM.

  4. #4
    Join Date
    Jun 2006
    Location
    M31
    Posts
    885

    Re: Need help retrieving the drive letter uppon mass storage arrival

    Code:
            if(msg == WM_DEVICECHANGE && wParam == DBT_DEVICEARRIVAL)
            {
                PDEV_BROADCAST_DEVICEINTERFACE pData = reinterpret_cast<PDEV_BROADCAST_DEVICEINTERFACE>(lParam);
    
                if(pData->dbcc_devicetype == DBT_DEVTYP_VOLUME)
                {
                    PDEV_BROADCAST_VOLUME pVolume = reinterpret_cast<PDEV_BROADCAST_VOLUME>(lParam);
    
                    //Extract letter from pVolume->dbcv_unitmask...
                }
            }
    Just wrote a small test; seemed to work with my USB key...

  5. #5
    Join Date
    Apr 2008
    Posts
    6

    Re: Need help retrieving the drive letter uppon mass storage arrival

    I've just tried your code here and the same thing happened.
    It can successfully retrieve the drive letter, but the dbcc_name is not holding the correct value.

    did you check your pData.dbcc_name?

    Mine have "HÈA".

    It was supposed to have:
    "\\?\USB#Vid_05e3&Pid_0712#000000009225#{a5dcbf10-6530-11d2-901f-00c04fb951ed}"

    these are the info that I'm looking for
    this string + the drive letter.

  6. #6
    Join Date
    Mar 2013
    Posts
    2

    Re: Need help retrieving the drive letter uppon mass storage arrival

    #include "stdafx.h"
    #include "windows.h"
    #include <C:\WinDDK\7600.16385.1\inc\ddk\mountmgr.h>

    bool GetDriveLetterForDeviceInterface( TCHAR *InterfaceName, UCHAR *Letter ) {

    HANDLE MountMgr = INVALID_HANDLE_VALUE;
    HANDLE Interface = INVALID_HANDLE_VALUE;
    MOUNTMGR_DRIVE_LETTER_INFORMATION DriveLetter;
    ULONG DeviceNameLength = sizeof( MOUNTMGR_DRIVE_LETTER_TARGET ) + 128;
    void* DeviceName = NULL;
    DWORD BytesReturned;
    bool Result = false;

    MountMgr = CreateFile(
    MOUNTMGR_DOS_DEVICE_NAME,
    FILE_READ_ACCESS | FILE_WRITE_ACCESS,
    FILE_SHARE_READ | FILE_SHARE_WRITE,
    NULL,
    OPEN_EXISTING,
    0,
    NULL
    );
    if ( MountMgr == INVALID_HANDLE_VALUE )
    goto Exit;

    Interface = CreateFile(
    InterfaceName,
    0,
    FILE_SHARE_READ | FILE_SHARE_WRITE,
    NULL,
    OPEN_EXISTING,
    0,
    NULL
    );
    if ( Interface == INVALID_HANDLE_VALUE )
    goto Exit;

    while ( true ) {

    if ( DeviceName )
    free( DeviceName );

    DeviceName = malloc( DeviceNameLength );
    if ( !DeviceName )
    goto Exit;

    Result = DeviceIoControl(
    Interface,
    IOCTL_MOUNTDEV_QUERY_DEVICE_NAME,
    NULL,
    0,
    DeviceName,
    DeviceNameLength,
    &BytesReturned,
    NULL
    ) ? true : false;
    if ( Result )
    break;

    if ( GetLastError() == ERROR_MORE_DATA ||
    GetLastError() == ERROR_INSUFFICIENT_BUFFER ||
    GetLastError() == ERROR_BUFFER_OVERFLOW ) {
    DeviceNameLength *= 2;
    continue;
    }

    goto Exit;

    }

    Result = DeviceIoControl(
    MountMgr,
    IOCTL_MOUNTMGR_NEXT_DRIVE_LETTER,
    DeviceName,
    DeviceNameLength,
    &DriveLetter,
    sizeof(DriveLetter),
    &BytesReturned,
    NULL
    ) ? true : false;
    if ( !Result )
    goto Exit;

    *Letter = DriveLetter.CurrentDriveLetter;
    *Letter &= ~0x20;

    Result = true;

    Exit:

    if ( DeviceName )
    free( DeviceName );

    if ( Interface != INVALID_HANDLE_VALUE )
    CloseHandle( Interface );

    if ( MountMgr != INVALID_HANDLE_VALUE )
    CloseHandle( MountMgr );

    return Result;

    }

    int _tmain(int argc, _TCHAR* argv[]) {

    UCHAR Letter;
    bool Result = false;

    Result = GetDriveLetterForDeviceInterface(
    TEXT("\\\\.\\STORAGE#Volume#{8871b640-813c-11e1-a7c5-806e6f6e6963}#0000000006500000#{53f5630d-b6bf-11d0-94f2-00a0c91efb8b}"),
    &Letter
    );

    return 0;

    }

  7. #7
    2kaud's Avatar
    2kaud is offline Super Moderator Power Poster
    Join Date
    Dec 2012
    Location
    England
    Posts
    7,822

    Re: Need help retrieving the drive letter uppon mass storage arrival

    If you are going to post code to a 5 year old thread, at least follow the etiquette of this forum and correctly format the code and enclose within [code] tags.

    Your code does what exactly? And why have you posted it without any comment or explanation?
    All advice is offered in good faith only. All my code is tested (unless stated explicitly otherwise) with the latest version of Microsoft Visual Studio (using the supported features of the latest standard) and is offered as examples only - not as production quality. I cannot offer advice regarding any other c/c++ compiler/IDE or incompatibilities with VS. You are ultimately responsible for the effects of your programs and the integrity of the machines they run on. Anything I post, code snippets, advice, etc is licensed as Public Domain https://creativecommons.org/publicdomain/zero/1.0/ and can be used without reference or acknowledgement. Also note that I only provide advice and guidance via the forums - and not via private messages!

    C++23 Compiler: Microsoft VS2022 (17.6.5)

  8. #8
    Join Date
    Mar 2013
    Posts
    2

    Re: Need help retrieving the drive letter uppon mass storage arrival

    I beg your pardon.

    Code:
    #include "stdafx.h"
    #include "windows.h"
    #include <C:\WinDDK\7600.16385.1\inc\ddk\mountmgr.h>
    
    bool GetDriveLetterForDeviceInterface( TCHAR *InterfaceName, UCHAR *Letter ) {
    
    HANDLE MountMgr = INVALID_HANDLE_VALUE;
    HANDLE Interface = INVALID_HANDLE_VALUE;
    MOUNTMGR_DRIVE_LETTER_INFORMATION DriveLetter;
    ULONG DeviceNameLength = sizeof( MOUNTMGR_DRIVE_LETTER_TARGET ) + 128;
    void* DeviceName = NULL;
    DWORD BytesReturned;
    bool Result = false;
    
    MountMgr = CreateFile(
    MOUNTMGR_DOS_DEVICE_NAME,
    FILE_READ_ACCESS | FILE_WRITE_ACCESS,
    FILE_SHARE_READ | FILE_SHARE_WRITE,
    NULL,
    OPEN_EXISTING,
    0,
    NULL
    );
    if ( MountMgr == INVALID_HANDLE_VALUE )
    goto Exit;
    
    Interface = CreateFile(
    InterfaceName,
    0,
    FILE_SHARE_READ | FILE_SHARE_WRITE,
    NULL,
    OPEN_EXISTING,
    0,
    NULL
    );
    if ( Interface == INVALID_HANDLE_VALUE )
    goto Exit;
    
    while ( true ) {
    
    if ( DeviceName )
    free( DeviceName );
    
    DeviceName = malloc( DeviceNameLength );
    if ( !DeviceName )
    goto Exit;
    
    Result = DeviceIoControl(
    Interface,
    IOCTL_MOUNTDEV_QUERY_DEVICE_NAME,
    NULL,
    0,
    DeviceName,
    DeviceNameLength,
    &BytesReturned,
    NULL
    ) ? true : false;
    if ( Result )
    break;
    
    if ( GetLastError() == ERROR_MORE_DATA ||
    GetLastError() == ERROR_INSUFFICIENT_BUFFER ||
    GetLastError() == ERROR_BUFFER_OVERFLOW ) {
    DeviceNameLength *= 2;
    continue;
    }
    
    goto Exit;
    
    }
    
    Result = DeviceIoControl(
    MountMgr,
    IOCTL_MOUNTMGR_NEXT_DRIVE_LETTER,
    DeviceName,
    DeviceNameLength,
    &DriveLetter,
    sizeof(DriveLetter),
    &BytesReturned,
    NULL
    ) ? true : false;
    if ( !Result )
    goto Exit;
    
    *Letter = DriveLetter.CurrentDriveLetter;
    *Letter &= ~0x20;
    
    Result = true;
    
    Exit:
    
    if ( DeviceName )
    free( DeviceName );
    
    if ( Interface != INVALID_HANDLE_VALUE )
    CloseHandle( Interface );
    
    if ( MountMgr != INVALID_HANDLE_VALUE )
    CloseHandle( MountMgr );
    
    return Result;
    
    }
    
    int _tmain(int argc, _TCHAR* argv[]) {
    
    UCHAR Letter;
    bool Result = false;
    
    Result = GetDriveLetterForDeviceInterface(
    TEXT("\\\\.\\STORAGE#Volume#{8871b640-813c-11e1-a7c5-806e6f6e6963}#0000000006500000#{53f5630d-b6bf-11d0-94f2-00a0c91efb8b}"),
    &Letter
    );
    
    return 0;
    
    }
    This is an example how to obtain drive letter by interface name cantained in structures like DEV_BROADCAST_DEVICEINTERFACE. It's especially useful in services due to services don't retreive DEV_BROADCAST_VOLUME notification. The GetDriveLetterForDeviceInterface function takes two parameters, interface name and a pointer to UCHAR variable which contains the result. The function returns true if it could determine the letter successfully or false otherwise. UCHAR variable contains 0(if the drive has no a letter) or corresponding drive letter.

    About 5 years, i think it doesn't matter because you can still meet enough posts like this.

  9. #9
    VictorN's Avatar
    VictorN is online now Super Moderator Power Poster
    Join Date
    Jan 2003
    Location
    Hanover Germany
    Posts
    20,396

    Re: Need help retrieving the drive letter uppon mass storage arrival

    Quote Originally Posted by anatolymik View Post
    I beg your pardon.

    Code:
    #include "stdafx.h"
    #include "windows.h"
    #include <C:\WinDDK\7600.16385.1\inc\ddk\mountmgr.h>
    
    bool GetDriveLetterForDeviceInterface( TCHAR *InterfaceName, UCHAR *Letter ) {
    ...
    }
    Your code is still unformatted! Note that any code enclosed within Code tages must be initially formatted with the proper indentations!

    Quote Originally Posted by anatolymik View Post
    This is an example how to obtain drive letter by interface name cantained in structures like DEV_BROADCAST_DEVICEINTERFACE. It's especially useful in services due to services don't retreive DEV_BROADCAST_VOLUME notification. The GetDriveLetterForDeviceInterface function takes two parameters, interface name and a pointer to UCHAR variable which contains the result. The function returns true if it could determine the letter successfully or false otherwise. UCHAR variable contains 0(if the drive has no a letter) or corresponding drive letter.

    About 5 years, i think it doesn't matter because you can still meet enough posts like this.
    Then you should have better submit it as an article or a tip (with some comments and explanations, of course!)
    Victor Nijegorodov

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