枚举 Windows Media 设备管理器 设备

对应用程序进行身份验证后,你可以开始枚举 Windows Media 设备管理器检测到的设备。 枚举通过使用 IWMDeviceManager2::EnumDevices2 或 IWMDeviceManager::EnumDevices 获取的枚举接口 IWMDMEnumDevice 来完成。 如果受支持,请使用 EnumDevices2 方法,因为早期版本仅在设备上返回旧版接口,而新版本返回旧接口和新接口。

在获取枚举器之前,应确定要使用的枚举视图。 某些设备将每个存储公开为不同的设备。 例如,设备上的两个闪存卡将枚举,就好像它们是单独的设备一样。 可以指定将设备上的所有存储一起枚举为单个设备。 只能在应用程序中设置此首选项一次;如果要更改它,则必须关闭应用程序并重新启动它。 但请注意,旧设备有时会忽略将单独的设备存储枚举为单个设备的请求,并继续单独枚举它们。

以下步骤演示如何枚举连接的设备:

  1. 使用 IWMDeviceManager3::SetDeviceEnumPreference 设置设备枚举首选项。 如果未调用此方法,则默认方法是将存储显示为单独的设备。 若要确定单个“设备”是否实际上是同一设备上的存储,请调用 IWMDMDevice2::GetCanonicalName;同一设备的存储将返回相同的值,但最后一个“$”符号后的最后一个数字除外。
  2. 查询 IWMDeviceManagerIWMDeviceManager2,然后调用 IWMDeviceManager2::EnumDevices2 以获取设备枚举器接口 IWMDMEnumDevice。 (如果受支持,请使用 EnumDevices2,这会更高效,因为早期版本可能不会) 返回 MTP 设备。
  3. 调用 IWMDMEnumDevices::Next 方法,一次检索一个或多个设备。 继续调用此方法,直到该方法返回S_FALSE或错误消息。 如果一次只检索一个设备,则无需分配数组来保存设备。

由于用户可以在应用程序运行时在计算机中附加或删除设备,因此最好实现设备连接或删除通知。 这是通过实现 IWMDMNotification 接口并注册它来实现的。 有关此内容的详细信息,请参阅 启用通知

以下 C++ 代码枚举设备并请求有关每个设备的信息。

HRESULT CWMDMController::EnumDevices()
{
    HRESULT hr = S_OK;

    // Change behavior to show devices as one object, not each storage as a device.
    // This can be called only once for each instance of this application.
    CComQIPtr<IWMDeviceManager3>pDevMgr3(m_IWMDMDeviceMgr);
    hr = pDevMgr3->SetDeviceEnumPreference(DO_NOT_VIRTUALIZE_STORAGES_AS_DEVICES);
    
    // Get number of attached devices.
    DWORD iDevices = 0;
    hr = m_IWMDMDeviceMgr->GetDeviceCount(&iDevices);
    if (hr == S_OK)
    {
        // TODO: Display count of devices.
    }

    //
    // Get a device enumerator to enumerate devices.
    //
    CComPtr<IWMDeviceManager2> pDevMgr2;
    hr = m_IWMDMDeviceMgr->QueryInterface (__uuidof(IWMDeviceManager2), (void**) &pDevMgr2);
    if (hr == S_OK)
    {
        // TODO: Display message indicating that application obtained IWMDeviceManager2.
    }
    else
    {
        // TODO: Display message indicating that we couldn't 
        // get IWMDeviceManager2 in EnumDevices.
        return hr;
    }
   CComPtr<IWMDMEnumDevice> pEnumDevice;
   hr = pDevMgr2->EnumDevices2(&pEnumDevice);
    if (hr != S_OK)
    {
        // TODO: Display messaging indicating that an error occurred 
        // in calling EnumDevices2.
        return hr;
    }

    // Length of all the strings we'll send in. 
    const UINT MAX_CHARS = 100;

    // Iterate through devices.
    while(TRUE)
    {
        // Get a device handle.
        IWMDMDevice *pIWMDMDevice;
        ULONG ulFetched = 0;
        hr = pEnumDevice->Next(1, &pIWMDMDevice, &ulFetched);
        if ((hr != S_OK) || (ulFetched != 1))
        {
            break;
        }
        
        // Get a display icon for the device.
        ULONG deviceIcon = 0;
        hr = pIWMDMDevice->GetDeviceIcon(&deviceIcon);

        // Print the device manufacturer.
        WCHAR manufacturer[MAX_CHARS];
        hr = pIWMDMDevice->GetManufacturer((LPWSTR)&manufacturer, MAX_CHARS);
        if (hr == S_OK)
        {
            // TODO: Display manufacturer name.
        }

        // Get the device name.
        WCHAR name[MAX_CHARS];
        hr = pIWMDMDevice->GetName((LPWSTR)&name, MAX_CHARS);
        if (hr == S_OK)
        {
            // TODO: Display name.
        }

        // TODO: Get other device information if wanted.

        // Obtain an IWMDMDevice2 interface and call some methods.
        CComQIPtr<IWMDMDevice2> pIWMDMDevice2(pIWMDMDevice);
        if (pIWMDMDevice2 != NULL)
        {
            // Get the canonical name.
            WCHAR canonicalName[MAX_CHARS];
            hr = pIWMDMDevice2->GetCanonicalName(canonicalName, MAX_CHARS);
            if (hr == S_OK)
            {
                // TODO: Display canonical name.
            }
        }

        // Obtain an IWMDMDevice3 interface and call some methods.
        CComQIPtr<IWMDMDevice3>pIWMDMDevice3(pIWMDMDevice);
        if (pIWMDMDevice3 != NULL)
        {
            // Find out what protocol is being used.
            PROPVARIANT val;
            PropVariantInit(&val);
            hr = pIWMDMDevice3->GetProperty(g_wszWMDMDeviceProtocol, &val);

            if (hr == S_OK)
            {
                if (*val.puuid == WMDM_DEVICE_PROTOCOL_RAPI)
                {
                    // TODO: Display message indicating device is a RAPI device.
                }
                else if (*val.puuid == WMDM_DEVICE_PROTOCOL_MTP)
                {
                    / /TODO: Display message indicating device is an MTP device.
                }
                else if (*val.puuid == WMDM_DEVICE_PROTOCOL_MSC)
                {
                    // TODO: Display message indicating device is an MSC device.
                }
                else
                {
                    // TODO: Display message indicating that the 
                    // application encountered an unknown protocol.
                }
                PropVariantClear(&val);
            }
        }

        // Examine the device capabilities. You could use some of these
        // to enable or disable the application's UI elements.
        CComQIPtr<IWMDMDeviceControl> pDeviceControl(pIWMDMDevice);
        if (pDeviceControl != NULL)
        {
            DWORD caps = 0;
            hr = pDeviceControl->GetCapabilities(&caps);
            if (caps & WMDM_DEVICECAP_CANPLAY)
            {
                // TODO: Display message indicating that the media 
                // device can play MP3 audio.
            }
            // TODO: Test for other capabilities here.
        }
    } // Get the next device.
    return hr;
}

创建 Windows Media 设备管理器 应用程序