chendral
chendral

Reputation: 684

Get device instance DWORD from device instance path string

I get an device instance path like

L"\\\\?\\USB#VID_0403&PID_6001#6&2cc2d230&0&2#{219d0508-57a8-4ff5-97a1-bd86587c6c7e}"

from IWDFRemoteInterfaceInitialize::RetrieveSymbolicLink.
But for CM_Get_Parent I need the DEVINST/DWORD of the device which drives me crazy.
I've tried for example

instancePath = L"\\\\?\\USB#VID_0403&PID_6001#6&2cc2d230&0&2#{219d0508-57a8-4ff5-97a1-bd86587c6c7e}";
HDEVINFO hinfo = SetupDiGetClassDevs(NULL, instancePath, NULL, DIGCF_DEVICEINTERFACE | DIGCF_ALLCLASSES);

and some other SetupDi... voodoo with no success. Any help is highly appreciated because -as mentioned- I haven't been able to get around this madness for hours now and though there are dozens of examples for the other way round (devid->instance path) I haven't found any for instance path->DEVINST.

Upvotes: 5

Views: 3856

Answers (2)

alexmerry
alexmerry

Reputation: 31

While modifying the path will probably work, the Windows docs explicitly say that you should not parse device paths.

You can do it with the CfgMgr32 API, though, using CM_Get_Device_Interface_PropertyW () and DEVPKEY_Device_InstanceId:

#include <cfgmgr32.h>
#include <initguid.h> // needed for devpkey.h to parse properly
#include <devpkey.h>

#include <cassert>
#include <string>
#include <vector>

/*
 *   @brief The following retrieves the Device Instance ID from the main device path.
 *   @param device_path A device path that has the form of the following:
 *                      \\?\usb#vid_[VENDOR_ID]&pid_[PRODUCT_ID]#INSTANCE_ID#{[DEVICE_INTERFACE_GUID]}
 *
 *                      Where the following components are described as:
 *                          1. VENDOR_ID             - The vendor ID of the device.
 *                          2. PRODUCT_ID            - The product ID of the device.
 *                          3. INSTANCE_ID           - The unique ID generated when the device connects to the host.
 *                          4. DEVICE_INTERFACE_GUID - The GUID that describes the interface of the device.
 *                                                     This is NOT the same as the "Device Class GUID."
 *   @return The Device Instance ID (linked below). A Device Instance ID has the form of:
 *           <device-id>\<instance-id>
 *
 *           Example: USB\VID_2109&PID_0813\7&3981c8d6&0&2
 *   @see https://learn.microsoft.com/en-us/windows-hardware/drivers/install/device-instance-ids
 *   @see https://learn.microsoft.com/en-us/windows/win32/api/cfgmgr32/nf-cfgmgr32-cm_get_device_interface_propertyw
 */
std::wstring map_path (LPCWSTR device_path) {
    ULONG buf_size = 0;
    DEVPROPTYPE type;
    CM_Get_Device_Interface_PropertyW(
        device_path, &DEVPKEY_Device_InstanceId, &type,
        nullptr, &buf_size, 0);

    std::vector<BYTE> buffer(buf_size);
    auto result = CM_Get_Device_Interface_PropertyW(
        device_path, &DEVPKEY_Device_InstanceId, &type,
        buffer.data(), &buf_size, 0);

    assert(result == CR_SUCCESS);
    assert(type == DEVPROP_TYPE_STRING);

    // buffer will be null-terminated
    return reinterpret_cast<wchar_t*>(buffer.data());
}

Upvotes: 2

gog
gog

Reputation: 1367

As you said, there's not a direct way.

However, you should be able to get a Device Instance ID from your Device Path / Device Interface ID by means of some string editing, following the below steps:

  1. Remove entirely the starting \\\\?\\ part, until the USB.
  2. Remove entirely the last {...} part
  3. Replace # with \

Starting from

"\\\\?\\USB#VID_0403&PID_6001#6&2cc2d230&0&2#{219d0508-57a8-4ff5-97a1-bd86587c6c7e}"

you should now have

"USB\VID_0403&PID_6001\6&2cc2d230&0&2\"

which should be a valid Device Instance ID. If it's not, try removing the last "\" too.

Then, you can feed this to CM_Locate_DevNode() and get the wanted DEVINST.

Upvotes: 1

Related Questions