0

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;
}
  • 2
    the length of the buffer is `length` and it contains multiple null terminated strings. `std::cout << buffer` only prints characters until it encounters the first null terminator – 463035818_is_not_an_ai Mar 30 '22 at 12:07
  • Oh yes, I have missed it, good point, thank you. could you also provide a solution please? I really don't know how to tackle with this problem quickly...only if I inspect each char, which is silly. – linuspauling Mar 30 '22 at 12:10
  • why is it silly? I am not proficient with windows, the comment was just what I found in documentation – 463035818_is_not_an_ai Mar 30 '22 at 12:11
  • Because I have to write a bit more code than I have expected...but I will try to do some operations pointer operations. – linuspauling Mar 30 '22 at 12:13
  • `while (*Buffer) { ... Buffer += strlen(Buffer) + 1;}` and use not A but W version of api – RbMm Mar 30 '22 at 12:15

1 Answers1

1

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() };
    // ...
IInspectable
  • 46,945
  • 8
  • 85
  • 181
  • Thank you for your good answer. Could you also explain me what does char const* current{ buffer }; mean? I haven't encountered this notation (curly brackets) till now. – linuspauling Mar 30 '22 at 13:07
  • C++11 introduced [uniform initialization syntax](https://isocpp.org/wiki/faq/cpp11-language#uniform-init). `char const* current{ buffer };` does the same as `char const* current = buffer;`. – IInspectable Mar 30 '22 at 13:13