Как открыть дескриптор устройства, используя его идентификатор экземпляра устройства? - PullRequest
0 голосов
/ 15 января 2020

Я обновляю свой вопрос, чтобы лучше отражать то, что я на самом деле собирался. Чтобы быстро констатировать факт моей первоначальной путаницы, неверно утверждать, что существует отношение «1 к 1» между « GUID класса интерфейса устройства » и идентификатором экземпляра устройства . Устройство может иметь много интерфейсов устройства. Как отметил Бен Фойгт в комментариях, см. для получения дополнительной информации.


Как можно открыть дескриптор дочернего устройства после вызова CM_Get_Child (...) функция?

В качестве примера возьмем следующий фрагмент кода:

#pragma comment (lib, "Setupapi.lib")
#pragma comment (lib, "Cfgmgr32.lib")

#include <iostream>
#include <Windows.h>
#include <Setupapi.h>
#include <Cfgmgr32.h> 

#define GUID_STRING_SIZE 40

int main ()
{
    CONFIGRET CMResult = CR_SUCCESS;
    WCHAR DeviceInstanceID[] = L"USB\\VID_2109&PID_0813\\8&216C1825&0&4\0"; // Parent Device Instance ID.

    DEVNODE ParentDeviceNode = (DWORD) 0; // A device instance handle. This handle is bounded to the local machine.
    CMResult = CM_Locate_DevNode ((PDEVINST) &ParentDeviceNode, DeviceInstanceID, CM_LOCATE_DEVNODE_NORMAL);

    if (CMResult != CR_SUCCESS)
    {
        std::cout << "No parent device node found." << std::endl;
        return -1;
    }
    else
    {
        DEVINST NextChildDeviceNode = (DWORD) 0;
        CMResult = CM_Get_Child ((PDEVINST) &NextChildDeviceNode, ParentDeviceNode, 0x0);    // Gets the first child of the parent node. If this returns "CR_NO_SUCH_DEVNODE," then there is no child attached.

        if (CMResult != CR_SUCCESS)
        {
            std::cout << "No child device node found." << std::endl;
            return -2;
        }
        else
        {
            ULONG ChildInstanceIDBuffLength = 0;
            CMResult = CM_Get_Device_ID_Size (&ChildInstanceIDBuffLength, NextChildDeviceNode, 0x0);

            if (CMResult != CR_SUCCESS)
            {
                std::cout << "Could not get the size of the device instance ID of child device." << std::endl;
                return -3;
            }
            else
            {
                WCHAR * ChildInstanceIDBuff = (WCHAR *) malloc (ChildInstanceIDBuffLength);
                CMResult = CM_Get_Device_IDW (NextChildDeviceNode, ChildInstanceIDBuff, ChildInstanceIDBuffLength, 0x0);

                if (CMResult != CR_SUCCESS)
                {
                    std::cout << "Could not actual device instance ID string of child device" << std::endl;
                    return -4;
                }
                else
                {
                    std::cout << "Found child device instance ID: ";
                    std::wcout << ChildInstanceIDBuff << std::endl;

                    /*
                     *  Open handle to the child device node now!
                     */
                }

                free (ChildInstanceIDBuff);
            }
        }
    }

    return 0;
}

Как я могу использовать только что полученного ребенка Идентификатор экземпляра устройства , чтобы открыть дескриптор устройства? CreateFile (...) требуется полный путь к устройству, включая отсутствующий «GUID класса интерфейса устройства».

В частности, путь к устройству имеет следующий формат:
\\?\usb#vid_2109&pid_0813#7&3981C8D6&0&2#{[DEVICE_INTERFACE_GUID]}, где:

  1. [DEVICE_INTERFACE_GUID] - Это " Класс интерфейса устройства" GUID «. Это НЕ то же самое, что " GUID класса настройки устройства ."

Похоже, что это не простой способ получить это " GUID класса интерфейса устройства"без некоторого уровня грубой силы (например, CM_Enumerate_Classes (...) с использованием флага CM_ENUMERATE_CLASSES_INTERFACE). Есть ли функция, которую я могу вызвать, чтобы получить дескриптор устройства, используя только его « Идентификатор устройства », чтобы я мог затем вызвать DeviceIoControl (...) и запросить информацию об устройстве?

Ответы [ 2 ]

0 голосов
/ 15 января 2020

если нам нужен открытый дескриптор для устройства с помощью ID экземпляра устройства -

  • первый вызов CM_Locate_DevNodeW функция для получения дескриптора экземпляра устройства для узел устройства, связанный с указанным идентификатором экземпляра устройства на локальном компьютере.
  • , тогда нам нужно вызвать CM_Get_DevNode_PropertyW функцию с DEVPKEY_Device_PDOName - это возвращаемое имя объекта физического имени ( PDO ), представляющего устройство, и мы можем использовать его в вызове NtOpenFile. конечно, если очень хочется - можно использовать и в вызове CreateFileW, если добавить L"\\\\?\\Global\\GLOBALROOT" к имени, но не иметь никакого смысла делать это.

volatile UCHAR guz = 0;

ULONG OpenDeviceByDeviceID(_Out_ PHANDLE FileHandle, _In_ PWSTR DeviceID)
{
    DEVINST dnDevInst;

    CONFIGRET CmReturnCode = CM_Locate_DevNodeW(&dnDevInst, DeviceID, CM_LOCATE_DEVNODE_NORMAL);

    if (CmReturnCode == CR_SUCCESS)
    {
        ULONG cb = 0, rcb = 128;

        PVOID stack = alloca(guz);

        DEVPROPTYPE PropertyType;

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

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

            CmReturnCode = CM_Get_DevNode_PropertyW(dnDevInst, 
                &DEVPKEY_Device_PDOName, &PropertyType, pb, &rcb, 0);

            if (CmReturnCode == CR_SUCCESS)
            {
                if (PropertyType == DEVPROP_TYPE_STRING)
                {
                    DbgPrint("PDOName = %S\n", sz);

#if 1
                    IO_STATUS_BLOCK iosb;
                    UNICODE_STRING ObjectName;
                    OBJECT_ATTRIBUTES oa = { sizeof(oa), 0, &ObjectName };
                    RtlInitUnicodeString(&ObjectName, sz);
                    NTSTATUS status = NtOpenFile(FileHandle, 
                        FILE_GENERIC_READ, &oa, &iosb, 0, 0);

                    return 0 > status ? RtlNtStatusToDosError(status) : NOERROR;
#else
                    static WCHAR prefix[] = L"\\\\?\\Global\\GLOBALROOT";
                    alloca(sizeof(prefix) - sizeof(WCHAR));

                    PWSTR fileName = sz - _countof(prefix) + 1;
                    memcpy(fileName, prefix, sizeof(prefix) - sizeof(WCHAR));

                    HANDLE hFile = CreateFileW(fileName, FILE_GENERIC_READ, 
                        0, 0, OPEN_EXISTING, 0, 0);
                    if (hFile == INVALID_HANDLE_VALUE)
                    {
                        return GetLastError();
                    }

                    *FileHandle = hFile;
                    return NOERROR;
#endif
                }
                else
                {
                    CmReturnCode = CR_WRONG_TYPE;
                }
            }

        } while (CmReturnCode == CR_BUFFER_SMALL);
    }

    return CM_MapCrToWin32Err(CmReturnCode, 0);
}
0 голосов
/ 15 января 2020

Вы можете использовать функцию CM_Enumerate_Classes с флагом CM_ENUMERATE_CLASSES_INTERFACE (Требуется Windows 8), чтобы получить возможные значения для передачи в качестве третьего параметра SetupDiEnumDeviceInterfaces.

* 1007. *

Начиная с Windows 8 и более поздних операционных систем, вызывающие абоненты могут использовать элемент ulFlags, чтобы указать, какие классы устройств CM_Enumerate_Classes должны возвращаться. До Windows 8 CM_Enumerate_Classes возвращал только классы настройки устройства.

Обратите внимание, что поиск всех интерфейсов на устройстве очень полезен для диагностики проблем с драйверами и / или обратного проектирования случайных периферийных устройств, спасенных из утиля , Но вы должны знать, с каким классом интерфейса вы имеете дело задолго до того, как приступите к вызову CreateFile.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...