Home > Mobile >  I can see only one USB string when I try to print all the USB devices (WinAPI)
I can see only one USB string when I try to print all the USB devices (WinAPI)

Time:03-30

I try to print a message whenever a new USB device is connected to my PC, but I don't want to create an application which just catches and treats the events triggered by the windows' kernel. So I used some specific functions in order to print the active USB devices and then, whenever a new device is plugged in, a signal produces something (a pop-up or something like that). Thus, firstly, I tried to enumerate all the USB devices, but I had no success as long as I receive only one line of text which represents a specific USB device, not all the USB devices connected. Here is the code

#pragma comment(lib, "Cfgmgr32")
#include <iostream>
#include <Windows.h>
#include <cfgmgr32.h>
#include <initguid.h>
#include <Usbiodef.h>

#define MAX 1024

int main()
{
    ULONG length;
    auto eroare1 = CM_Get_Device_Interface_List_SizeA(
        &length,
        (LPGUID)&GUID_DEVINTERFACE_USB_DEVICE,
        NULL,
        CM_GET_DEVICE_INTERFACE_LIST_PRESENT
    );
    if (eroare1 != CR_SUCCESS)
    {
        std::cout << "eroare 1";
    }
    PSZ buffer;
    buffer = new char[MAX];
    auto eroare2 =  CM_Get_Device_Interface_ListA(
        (LPGUID)&GUID_DEVINTERFACE_USB_DEVICE,
        NULL,
        buffer
        length,
        CM_GET_DEVICE_INTERFACE_LIST_PRESENT
    );
    if (eroare2 != CR_SUCCESS)
    {
        std::cout << "eroare";
    }
    std::cout << buffer << std::endl;
}

CodePudding user response:

The format used by CM_Get_Device_Interface_ListA to return a list of items is a double-null-terminated list (see also Why double-null-terminated strings instead of an array of pointers to strings? for rationale). This isn't explicitly spelled out in the documentation, but can be inferred from the argument type of Buffer: PZZSTR.

It is declared in winnt.h like this:

typedef _NullNull_terminated_ CHAR *PZZSTR;

This is really just a char* but with the _NullNull_terminated_ SAL annotation. It allows static code analyzers to know about the additional semantics of PZZSTR, and serves as a hint to developers.

The code in question only prints characters up to the first NUL character, i.e. it displays at most one item from the list. To display all items, you'll have to iterate over the strings until you find an empty string:

    char const* current{ buffer };
    while (*current != '\0') {
        std::cout << current << std::endl;
        current  = strlen(current)   1;
    }

That fixes the immediate issue. To make the code actually work, you'll have to fix the potential memory corruption bug. In the call to CM_Get_Device_Interface_ListA you're telling the API that buffer is pointing to length bytes of memory, but you allocated MAX bytes.

The arguments of Buffer and BufferLen must match the actual allocation. Speaking of which, you never actually clean up that memory. Using a std::vector solves both issues:

    std::vector<char> buffer(length);
    auto eroare2 = CM_Get_Device_Interface_ListA(
        (LPGUID)&GUID_DEVINTERFACE_USB_DEVICE,
        NULL,
        buffer.data(),
        buffer.size(),
        CM_GET_DEVICE_INTERFACE_LIST_PRESENT
    );

    // ...

    char const* current{ buffer.data() };
    // ...
  • Related