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() };
// ...