SetupApi函数
+ -

Devcon ListClass命令代码实现

2022-01-28 32 0

ListClass命令用于列出当前系统中该设备类下的的有设备实例并显示设备的友名。
ListClass命令由两部分组成:

  • 第一部分是根据设备的类名获取其类GUID,然后再通过SetupDiGetClassDevsEx打开该GUID分类的设备集,获取其 HDEVINFO devs句柄。当然这里也为了显法该设备类更详尽的信息,通过SetupDiGetClassDescriptionEx获取设备类的描述符信息。
    由于这个命令支持多类名传递,故代码中搞了一个循环。
int cmdListClass(_In_ LPCTSTR BaseName, _In_opt_ LPCTSTR Machine, _In_ DWORD Flags, _In_ int argc, _In_reads_(argc) PTSTR argv[])
/*++

Routine Description:

    LISTCLASS <name>....
    lists all devices for each specified class
    there can be more than one physical class for a class name (shouldn't be
    though) in such cases, list each class
    if machine given, list devices for that machine

Arguments:

    BaseName  - name of executable
    Machine   - if non-NULL, remote machine
    argc/argv - remaining parameters - list of class names

Return Value:

    EXIT_xxxx

--*/
{
    DWORD reqGuids = 16;
    int argIndex;
    int failcode = EXIT_FAIL;
    LPGUID guids = NULL;
    HDEVINFO devs = INVALID_HANDLE_VALUE;

    UNREFERENCED_PARAMETER(BaseName);
    UNREFERENCED_PARAMETER(Flags);

    if(!argc) {
        return EXIT_USAGE;
    }

    guids = new GUID[reqGuids];
    if(!guids) {
        goto final;
    }

    for(argIndex = 0;argIndex<argc;argIndex++) {
        DWORD numGuids;
        DWORD index;

        if(!(argv[argIndex] && argv[argIndex][0])) {
            continue;
        }

        //
        // there could be one to many name to GUID mapping
        //
        while(!SetupDiClassGuidsFromNameEx(argv[argIndex],guids,reqGuids,&numGuids,Machine,NULL)) {
            if(GetLastError() != ERROR_INSUFFICIENT_BUFFER) {
                goto final;
            }
            delete [] guids;
            reqGuids = numGuids;
            guids = new GUID[reqGuids];
            if(!guids) {
                goto final;
            }
        }
        if(numGuids == 0) {
            FormatToStream(stdout,Machine?MSG_LISTCLASS_NOCLASS:MSG_LISTCLASS_NOCLASS_LOCAL,argv[argIndex],Machine);
            continue;
        }
        for(index = 0;index<numGuids;index++) {
            TCHAR className[MAX_CLASS_NAME_LEN];
            TCHAR classDesc[LINE_LEN];
            DWORD devCount = 0;
            SP_DEVINFO_DATA devInfo;
            DWORD devIndex;

            devs = SetupDiGetClassDevsEx(&guids[index],NULL,NULL,/*DIGCF_PRESENT*/0,NULL,Machine,NULL);
            if(devs != INVALID_HANDLE_VALUE) {
                //
                // count number of devices
                //
                devInfo.cbSize = sizeof(devInfo);
                while(SetupDiEnumDeviceInfo(devs,devCount,&devInfo)) {
                    devCount++;
                }
            }

            if(!SetupDiClassNameFromGuidEx(&guids[index],className,MAX_CLASS_NAME_LEN,NULL,Machine,NULL)) {
                if (FAILED(StringCchCopy(className,MAX_CLASS_NAME_LEN,TEXT("?")))) {
                    goto final;
                }
            }
            if(!SetupDiGetClassDescriptionEx(&guids[index],classDesc,LINE_LEN,NULL,Machine,NULL)) {
                if (FAILED(StringCchCopy(classDesc,LINE_LEN,className))) {
                    goto final;
                }
            }

            //
            // how many devices?
            //
            if (!devCount) {
                FormatToStream(stdout,Machine?MSG_LISTCLASS_HEADER_NONE:MSG_LISTCLASS_HEADER_NONE_LOCAL,className,classDesc,Machine);
            } else {
                FormatToStream(stdout,Machine?MSG_LISTCLASS_HEADER:MSG_LISTCLASS_HEADER_LOCAL,devCount,className,classDesc,Machine);
                for(devIndex=0;SetupDiEnumDeviceInfo(devs,devIndex,&devInfo);devIndex++) {
                    DumpDevice(devs,&devInfo);
                }
            }
            if(devs != INVALID_HANDLE_VALUE) {
                SetupDiDestroyDeviceInfoList(devs);
                devs = INVALID_HANDLE_VALUE;
            }
        }
    }

    failcode = 0;

final:

    if(guids) {
        delete [] guids;
    }

    if(devs != INVALID_HANDLE_VALUE) {
        SetupDiDestroyDeviceInfoList(devs);
    }

    return failcode;
}

第二部根据打开的设备集HDEVINFO devs句柄,枚举该设备类下的所有设备

           for(devIndex=0;SetupDiEnumDeviceInfo(devs,devIndex,&devInfo);devIndex++) {
                    DumpDevice(devs,&devInfo);
                }

然后通过DumpDevice函数打开设备的实例名和描述符信息。


BOOL DumpDevice(_In_ HDEVINFO Devs, _In_ PSP_DEVINFO_DATA DevInfo)
/*++

Routine Description:

    Write device instance & description to stdout

Arguments:

    Devs    )_ uniquely identify device
    DevInfo )

Return Value:

    TRUE if success

--*/
{
    LPTSTR desc;
    BOOL b;

    desc = GetDeviceDescription(Devs,DevInfo);
    b = DumpDeviceWithInfo(Devs,DevInfo,desc);
    if(desc) {
        delete [] desc;
    }
    return b;
}

可以看到,设备的描述信息是通过自定义GetDeviceDescription获取的,其就是通过GetDeviceStringProperty获取设备的SPDRP_FRIENDLYNAME或SPDRP_DEVICEDESC信息。


LPTSTR GetDeviceDescription(_In_ HDEVINFO Devs, _In_ PSP_DEVINFO_DATA DevInfo)
/*++

Routine Description:

    Return a string containing a description of the device, otherwise NULL
    Always try friendly name first

Arguments:

    Devs    )_ uniquely identify device
    DevInfo )

Return Value:

    string containing description

--*/
{
    LPTSTR desc;
    desc = GetDeviceStringProperty(Devs,DevInfo,SPDRP_FRIENDLYNAME);
    if(!desc) {
        desc = GetDeviceStringProperty(Devs,DevInfo,SPDRP_DEVICEDESC);
    }
    return desc;
}

而设备的实例名信息是通过自定义函数DumpDeviceWithInfo实现的。


BOOL DumpDeviceWithInfo(_In_ HDEVINFO Devs, _In_ PSP_DEVINFO_DATA DevInfo, _In_opt_ LPCTSTR Info)
/*++

Routine Description:

    Write device instance & info to stdout

Arguments:

    Devs    )_ uniquely identify device
    DevInfo )

Return Value:

    none

--*/
{
    TCHAR devID[MAX_DEVICE_ID_LEN];
    BOOL b = TRUE;
    SP_DEVINFO_LIST_DETAIL_DATA devInfoListDetail;

    devInfoListDetail.cbSize = sizeof(devInfoListDetail);
    if((!SetupDiGetDeviceInfoListDetail(Devs,&devInfoListDetail)) ||
            (CM_Get_Device_ID_Ex(DevInfo->DevInst,devID,MAX_DEVICE_ID_LEN,0,devInfoListDetail.RemoteMachineHandle)!=CR_SUCCESS)) {
        StringCchCopy(devID, ARRAYSIZE(devID), TEXT("?"));
        b = FALSE;
    }

    if(Info) {
        _tprintf(TEXT("%-60s: %s\n"),devID,Info);
    } else {
        _tprintf(TEXT("%s\n"),devID);
    }
    return b;
}

可以看到,设备的实例名是首先通过SetupDiGetDeviceInfoListDetail获取设备的HMACHINE句柄,再通过CM_Get_Device_ID_Ex获取其实例名路径。

CM_Get_Device_ID_ExW(
    _In_  DEVINST       dnDevInst,
    _Out_writes_(BufferLen) PWSTR Buffer,
    _In_  ULONG         BufferLen,
    _In_  ULONG         ulFlags,
    _In_opt_ HMACHINE   hMachine
    );

0 篇笔记 写笔记

DevCon ListClass命令
DevCon ListClass用于列出指定设备设置类中的所有设备。 在本地和远程计算机上有效。命令格式devcon [/m:\computer] listclass class [class...]参数如果要在指定的远程机器上运行,使用/m参数,并且目标计算机的路径使用反斜杠””来标识。......
Devcon ListClass命令代码实现
ListClass命令用于列出当前系统中该设备类下的的有设备实例并显示设备的友名。ListClass命令由两部分组成:第一部分是根据设备的类名获取其类GUID,然后再通过SetupDiGetClassDevsEx打开该GUID分类的设备集,获取其 HDEVINFO devs句柄。当然这里也为了显......
Windows设备实例路径生成规则
PNP管理器通过PipMakeGloballyUniqueId来生成设备的实例路径。默认情况下,设备的实例路径由系统按一定的规则生成,但是也有例外,即可以通过总线驱动来指定设备的实例路径。设备实例路径生成规则是选择由按系统规则还是由驱动指定,取决于总线驱动返回的PDO设备的DeviceCapabil......
作者信息
我爱内核
Windows驱动开发,网站开发
好好学习,天天向上。
取消
感谢您的支持,我会继续努力的!
扫码支持
扫码打赏,你说多少就多少

打开支付宝扫一扫,即可进行扫码打赏哦

您的支持,是我们前进的动力!