2

当转到 Windows 的“设备管理器”并单击(几乎)列表中的任何设备时,“常规”选项卡中的一条信息称为“位置”。那是一个字符串,可以是:

  • 人类可读,例如“在 NVIDIA GeForce GTX 1080 上”
  • 半有用的,例如“位置 0(内部高清音频总线)”或“PCI 总线 9,设备 0,功能 0”
  • USB 位置,例如“Port_#0004.Hub_#0015”甚至是“0009.0000.0000.004.000.000.000.000.000”

该信息可通过 Windows 的统一设备属性模型API 获得。

我正在寻找的是从给定IMFActivate对象中获取该信息。

有没有办法这样做?我找不到如何从该激活对象获取“设备”信息。我拥有的唯一数据是“符号链接”(在我的例子中,这个字符串:),\\?\usb#vid_04b4&pid_8888&mi_00#9&4fe28be&0&0000#{e5323777-f976-4f5b-9b55-b94699c46e44}\global但该链接的格式与我在“位置”中看到的字符串完全不同。

因此我的问题是:如何获取设备的“位置”字符串,给定它的IMFActivate对象?

更新

这是我用来“转换”符号链接的代码,由提供IMFActivate的设备 id 字符串提供,可由 setup-api 函数识别,然后提取“位置字符串”:

CString symLink2Location(const CString & _symLink)
{
    DEVINST di;
    CString devId = _symLink;
    devId = devId.Left( devId.Find(L"#{") );
    devId.Replace(L"\\\\?\\", L"");
    devId.Replace(L"#", L"\\");
    const auto rc = CM_Locate_DevNodeW(&di, devId.GetBuffer(), CM_LOCATE_DEVNODE_NORMAL);
    if(rc == CR_SUCCESS){
        DEVPROPTYPE dpt;
        ULONG sz = MAX_PATH;
        WCHAR prop[MAX_PATH];
        if(CM_Get_DevNode_PropertyW(di, &DEVPKEY_Device_LocationInfo, &dpt, (PBYTE)&prop, &sz, 0) == CR_SUCCESS){
            if(dpt == DEVPROP_TYPE_STRING){
                return prop;
            }
        }
    }
    return L"";
}

更新 2

devmgmt.msc以下是“声音、视频和游戏控制器”下的 3 个音频输入设备:

  • MS LifeCam Cinema (TM),位置:0000.0014.0000.013.003.000.000.000.000(符号链接\\?\SWD#MMDEVAPI#{0.0.1.00000000}.{751fe058-cef2-4d28-bbeb-e438981938d7}#{2eef81be-33fa-4800-9670-1cd474972c3f}:)
  • MS LifeCam Studio (TM),位置:0000.0014.0000.013.004.004.000.000.000(符号链接\\?\SWD#MMDEVAPI#{0.0.1.00000000}.{59267d2e-940b-45f5-8655-45372787bd85}#{2eef81be-33fa-4800-9670-1cd474972c3f}:)
  • SUB2r USB 3.0 高清网络摄像头,位置:0009.0000.0000.004.000.000.000.000.000(符号链接\\?\SWD#MMDEVAPI#{0.0.1.00000000}.{26a4f608-cbd8-4206-b958-d57ee6847153}#{2eef81be-33fa-4800-9670-1cd474972c3f}:)

所有 3 个都是 USB 设备,调用时会列出所有 3 个,MFEnumDeviceSources但它们的“符号链接”不会解析为硬件设备。

4

1 回答 1

2

IMFAttributes::Get[Allocated]Stringwith返回的字符串MF_DEVSOURCE_ATTRIBUTE_SOURCE_TYPE_VIDCAP_SYMBOLIC_LINKMF_DEVSOURCE_ATTRIBUTE_SOURCE_TYPE_AUDCAP_SYMBOLIC_LINK这是设备接口字符串,我们可以将其用作CM_Get_Device_Interface_PropertyW. 获取位置信息(如果存在)需要执行 3 个步骤:

  1. 调用- 结果我们得到CM_Get_Device_Interface_PropertyWDEVPKEY_Device_InstanceId设备的设备实例标识符
  2. 在调用中使用返回的字符串CM_Locate_DevNodeW
  3. 最后打电话CM_Get_DevNode_PropertyWDEVPKEY_Device_LocationInfo

代码示例:

CONFIGRET PrintLocation(PCWSTR pszDeviceInterface)
{
    ULONG cb = 0, rcb = 64;

    static volatile UCHAR guz;

    PVOID stack = alloca(guz);
    DEVPROPTYPE PropertyType;

    CONFIGRET err;

    union {
        PVOID pv;
        PWSTR sz;
        PBYTE pb;
    };

    do 
    {
        if (cb < rcb)
        {
            rcb = cb = RtlPointerToOffset(pv = alloca(rcb - cb), stack);
        }

        if (!(err = CM_Get_Device_Interface_PropertyW(pszDeviceInterface, &DEVPKEY_Device_InstanceId, &PropertyType, pb, &rcb, 0)))
        {
            if (PropertyType == DEVPROP_TYPE_STRING)
            {
                DbgPrint("InstanceId=%S\n", sz);

                DEVINST dnDevInst;

                if (!(err = CM_Locate_DevNodeW(&dnDevInst, sz, CM_LOCATE_DEVNODE_NORMAL)))
                {
                    do 
                    {
                        if (cb < rcb)
                        {
                            rcb = cb = RtlPointerToOffset(pv = alloca(rcb - cb), stack);
                        }

                        if (!(err = CM_Get_DevNode_PropertyW(dnDevInst, &DEVPKEY_Device_LocationInfo, &PropertyType, pb, &rcb, 0)))
                        {
                            if (PropertyType == DEVPROP_TYPE_STRING)
                            {
                                DbgPrint("Location=%S\n", sz);
                            }
                            else
                            {
                                err = CR_WRONG_TYPE;
                            }
                        }

                    } while (err == CR_BUFFER_SMALL);
                }
            }
            else
            {
                err = CR_WRONG_TYPE;
            }

            break;
        }

    } while (err == CR_BUFFER_SMALL);

    return err;
}

当然如果硬编码缓冲区大小,功能可以更简单

CONFIGRET PrintLocationSimp(PCWSTR pszDeviceInterface)
{
    WCHAR buf[1024];

    DEVPROPTYPE PropertyType;

    ULONG BufferSize = sizeof(buf);

    CONFIGRET err;

    if (!(err = CM_Get_Device_Interface_PropertyW(pszDeviceInterface, &DEVPKEY_Device_InstanceId, &PropertyType, (PBYTE)buf, &BufferSize, 0)))
    {
        if (PropertyType == DEVPROP_TYPE_STRING)
        {
            DbgPrint("InstanceId=%S\n", buf);

            DEVINST dnDevInst;

            if (!(err = CM_Locate_DevNodeW(&dnDevInst, buf, CM_LOCATE_DEVNODE_NORMAL)))
            {
                BufferSize = sizeof(buf);

                if (!(err = CM_Get_DevNode_PropertyW(dnDevInst, &DEVPKEY_Device_LocationInfo, &PropertyType, (PBYTE)buf, &BufferSize, 0)))
                {
                    if (PropertyType == DEVPROP_TYPE_STRING)
                    {
                        DbgPrint("Location=%S\n", buf);
                    }
                    else
                    {
                        err = CR_WRONG_TYPE;
                    }
                }
            }
        }
        else
        {
            err = CR_WRONG_TYPE;
        }
    }

    return err;
}

因为IMFActivate我们可以使用下一个代码:

void mftest()
{
    IMFAttributes *pAttributes;

    if (SUCCEEDED(MFCreateAttributes(&pAttributes, 1)))
    {
        UINT32 count, cchLength;
        IMFActivate **ppDevices, *pDevice;

        if (SUCCEEDED(pAttributes->SetGUID(
            MF_DEVSOURCE_ATTRIBUTE_SOURCE_TYPE, MF_DEVSOURCE_ATTRIBUTE_SOURCE_TYPE_VIDCAP_GUID)) && 
            SUCCEEDED(MFEnumDeviceSources(pAttributes, &ppDevices, &count)) &&
            count)
        {
            PVOID pv = ppDevices;

            do 
            {
                pDevice = *ppDevices++;

                PWSTR pszDeviceInterface;

                if (SUCCEEDED(pDevice->GetAllocatedString(
                    MF_DEVSOURCE_ATTRIBUTE_SOURCE_TYPE_VIDCAP_SYMBOLIC_LINK, &pszDeviceInterface, &cchLength)))
                {
                    DbgPrint("%S\n", pszDeviceInterface);

                    PrintLocation(pszDeviceInterface);

                    CoTaskMemFree(pszDeviceInterface);
                }

            } while (--count);

            CoTaskMemFree(pv);
        }

        pAttributes->Release();
    }
}
于 2017-07-15T11:37:42.600 回答