首页 > 解决方案 > 从 WM_DEVICECHANGE LParam 获取设备的友好名称

问题描述

所以我正在为学校电脑构建一个应用程序来跟踪所有插入的设备。每当我插入或移除设备时,我设法使用RegisterDeviceNotification()在主线程中获取通知。我所能得到的只是LParam,一个设备唯一的指针。

我找不到任何关于如何使用该 LParam 获取设备的友好名称的信息。我能找到的唯一资源是这个2006 年的 CodeProject(在 C++ 中)。

我在 pinvoke.net 上找不到任何东西,我唯一找到的东西(我不记得确切的位置)是使用 aManagementObjectSearcher来获取这些数据,但它找到了空数据。(这里是代码)

ManagementObjectSearcher searcher = new ManagementObjectSearcher("Select Name from Win32_PnpEntity");

            foreach (ManagementObject devices in searcher.Get())
            {
                foreach (var v in devices.Properties)
                {
                    Console.WriteLine(v.Value);
                }
            }

            searcher.Dispose();

谁能帮我弄清楚如何获得设备的友好名称?

标签: c#winapipinvoke

解决方案


演示代码:

struct DeviceName : public LIST_ENTRY 
{
    ULONG InterfaceHash;
    WCHAR Name[];

    void* operator new(size_t cb, size_t len)
    {
        return LocalAlloc(0, cb + len);
    }

    void operator delete(void* pv)
    {
        LocalFree(pv);
    }
};

volatile const UCHAR guz = 0;
CONFIGRET GetFriendlyNameByDevNode(DeviceName** pp, DEVINST dnDevInst)
{
    CONFIGRET status;

    ULONG cb = 32;

    DEVPROPTYPE PropertyType;

    do 
    {
        if (DeviceName* p = new(cb) DeviceName)
        {
            status = CM_Get_DevNode_PropertyW(
                dnDevInst, &DEVPKEY_DeviceInterface_FriendlyName, &PropertyType, (PBYTE)p->Name, &cb, 0);

            if (status == CR_SUCCESS)
            {
                if (PropertyType == DEVPROP_TYPE_STRING)
                {
                    *pp = p;
                    return CR_SUCCESS;
                }
                else
                {
                    status = CR_WRONG_TYPE;
                }
            }

            delete p;
        }
        else
        {
            status = CR_OUT_OF_MEMORY;
        }

    } while (CR_BUFFER_SMALL == status);

    return status;
}

CONFIGRET GetFriendlyNameByInterface(DeviceName** pp, PCWSTR pszDeviceInterface)
{
    // RTCu must be disabled !
    ULONG cb = 0, rcb = 64;

    PVOID stack = alloca(guz);
    DEVPROPTYPE PropertyType;

    CONFIGRET status;

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

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

    } while (CR_BUFFER_SMALL == (status = CM_Get_Device_Interface_PropertyW(
        pszDeviceInterface, &DEVPKEY_Device_InstanceId, &PropertyType, pb, &rcb, 0)));

    if (status == CR_SUCCESS)
    {
        if (PropertyType == DEVPROP_TYPE_STRING)
        {
            DEVINST dnDevInst;

            status = CM_Locate_DevNodeW(&dnDevInst, DeviceID, CM_LOCATE_DEVNODE_NORMAL);

            return status == CR_SUCCESS ? GetFriendlyNameByDevNode(pp, dnDevInst) : status;
        }
        else
        {
            status = CR_WRONG_TYPE;
        }
    }

    return status;
}

        case WM_DESTROY:
            if (_hDevNot)
            {
                UnregisterDeviceNotification(_hDevNot);

                PLIST_ENTRY head = &_DevListHead, entry = head->Flink;

                while (entry != head)
                {
                    DeviceName* p = static_cast<DeviceName*>(entry);

                    entry = entry->Flink;

                    delete p;
                }
            }
            break;

        case WM_DEVICECHANGE:
            switch (wParam)
            {
            case DBT_DEVICEREMOVECOMPLETE:
            case DBT_DEVICEARRIVAL:
                if (reinterpret_cast<PDEV_BROADCAST_DEVICEINTERFACE>(lParam)->dbcc_devicetype == DBT_DEVTYP_DEVICEINTERFACE)
                {
                    DeviceName* p;
                    ULONG InterfaceHash;
                    UNICODE_STRING dbcc_name;
                    RtlInitUnicodeString(&dbcc_name, reinterpret_cast<PDEV_BROADCAST_DEVICEINTERFACE>(lParam)->dbcc_name);
                    RtlHashUnicodeString(&dbcc_name, FALSE, HASH_STRING_ALGORITHM_DEFAULT, &InterfaceHash);

                    if (wParam == DBT_DEVICEARRIVAL)
                    {
                        if (CR_SUCCESS == GetFriendlyNameByInterface(&p, dbcc_name.Buffer))
                        {
                            p->InterfaceHash = InterfaceHash;
                            InsertHeadList(&_DevListHead, p);
                            DbgPrint("inserted %S ( %wZ )\n", p->Name, &dbcc_name);
                        }
                    }
                    else
                    {

                        PLIST_ENTRY head = &_DevListHead, entry = head;

                        while ((entry = entry->Flink) != head)
                        {
                            if (static_cast<DeviceName*>(entry)->InterfaceHash == InterfaceHash)
                            {
                                DbgPrint("removed %S ( %wZ )\n", 
                                    static_cast<DeviceName*>(entry)->Name, &dbcc_name);

                                RemoveEntryList(entry);
                                delete static_cast<DeviceName*>(entry);
                                break;
                            }
                        }
                    }
                }
                break;
            }
            return 0;

        case WM_CREATE:
            InitializeListHead(&_DevListHead);
            static DEV_BROADCAST_DEVICEINTERFACE dbd = { sizeof(dbd), DBT_DEVTYP_DEVICEINTERFACE };
            _hDevNot = RegisterDeviceNotificationW(hwnd, &dbd, DEVICE_NOTIFY_WINDOW_HANDLE|DEVICE_NOTIFY_ALL_INTERFACE_CLASSES);
            break;

推荐阅读