I've found some code on here that lists all the USB devices on a computer. Here's the code:
#include <windows.h>
#include <devguid.h> // for GUID_DEVCLASS_CDROM etc
#include <setupapi.h>
#include <cfgmgr32.h> // for MAX_DEVICE_ID_LEN, CM_Get_Parent and CM_Get_Device_ID
#define INITGUID
#include "c:\WinDDK\7600.16385.1\inc\api\devpkey.h"
#include <tchar.h>
#include <stdio.h>
#include <iostream>
#define ARRAY_SIZE(arr) (sizeof(arr)/sizeof(arr[0]))
#pragma comment (lib, "setupapi.lib")
typedef BOOL (WINAPI *FN_SetupDiGetDeviceProperty)(
__in HDEVINFO DeviceInfoSet,
__in PSP_DEVINFO_DATA DeviceInfoData,
__in const DEVPROPKEY *PropertyKey,
__out DEVPROPTYPE *PropertyType,
__out_opt PBYTE PropertyBuffer,
__in DWORD PropertyBufferSize,
__out_opt PDWORD RequiredSize,
__in DWORD Flags
);
// List all USB devices with some additional information
void ListUsbDevices(void)
{
unsigned i, j;
DWORD dwSize, dwPropertyRegDataType;
DEVPROPTYPE ulPropertyType;
OSVERSIONINFO osvi;
CONFIGRET r;
HDEVINFO hDevInfo;
SP_DEVINFO_DATA DeviceInfoData;
const static LPCTSTR arPrefix[3] = {TEXT("VID_"), TEXT("PID_"), TEXT("MI_")};
TCHAR szDeviceInstanceID [MAX_DEVICE_ID_LEN];
TCHAR szDesc[1024];
LPTSTR pszToken, pszNextToken;
TCHAR szVid[MAX_DEVICE_ID_LEN], szPid[MAX_DEVICE_ID_LEN], szMi[MAX_DEVICE_ID_LEN];
#ifdef UNICODE
FN_SetupDiGetDeviceProperty fn_SetupDiGetDeviceProperty = (FN_SetupDiGetDeviceProperty)
GetProcAddress (GetModuleHandle (TEXT("Setupapi.dll")), "SetupDiGetDevicePropertyW");
#else
FN_SetupDiGetDeviceProperty fn_SetupDiGetDeviceProperty = (FN_SetupDiGetDeviceProperty)
GetProcAddress(GetModuleHandle(TEXT("Setupapi.dll")), "SetupDiGetDevicePropertyA");
#endif
// List all connected USB devices
hDevInfo = SetupDiGetClassDevs (NULL, TEXT("USB"), NULL, DIGCF_PRESENT|DIGCF_ALLCLASSES);
if (hDevInfo == INVALID_HANDLE_VALUE)
return;
// Find the ones that are driverless
for (i = 0; ; i++) {
DeviceInfoData.cbSize = sizeof (DeviceInfoData);
if (!SetupDiEnumDeviceInfo(hDevInfo, i, &DeviceInfoData))
break;
r = CM_Get_Device_ID(DeviceInfoData.DevInst, szDeviceInstanceID , MAX_PATH, 0);
if (r != CR_SUCCESS)
continue;
_tprintf (TEXT("%s\n"), szDeviceInstanceID );
if (SetupDiGetDeviceRegistryProperty (hDevInfo, &DeviceInfoData, SPDRP_DEVICEDESC,
&dwPropertyRegDataType, (BYTE*)szDesc,
sizeof(szDesc), // The size, in bytes
&dwSize))
_tprintf (TEXT(" Device Description: \"%s\"\n"), szDesc);
// Retreive the device description as reported by the device itself
memset(&osvi, 0, sizeof(OSVERSIONINFO));
osvi.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);
if ( (GetVersionEx(&osvi) != 0)
&& (osvi.dwBuildNumber >= 7000) ) {
// On Vista and earlier, we can use only SPDRP_DEVICEDESC
// On Windows 7, the information we want ("Bus reported device description") is
// accessed through DEVPKEY_Device_BusReportedDeviceDesc
if (fn_SetupDiGetDeviceProperty && fn_SetupDiGetDeviceProperty (hDevInfo, &DeviceInfoData, &DEVPKEY_Device_BusReportedDeviceDesc,
&ulPropertyType, (BYTE*)szDesc, sizeof(szDesc), &dwSize, 0))
_tprintf (TEXT(" Bus Reported Device Description: \"%s\"\n"), szDesc);
}
pszToken = _tcstok_s (szDeviceInstanceID , TEXT("\\#&"), &pszNextToken);
while(pszToken != NULL)
{
szVid[0] = TEXT('\0');
szPid[0] = TEXT('\0');
szMi[0] = TEXT('\0');
for (j = 0; j < 3; j++) {
if (_tcsncmp(pszToken, arPrefix[j], lstrlen(arPrefix[j])) == 0) {
switch(j) {
case 0:
_tcscpy_s(szVid, ARRAY_SIZE(szVid), pszToken);
break;
case 1:
_tcscpy_s(szPid, ARRAY_SIZE(szPid), pszToken);
break;
case 2:
_tcscpy_s(szMi, ARRAY_SIZE(szMi), pszToken);
break;
default:
break;
}
}
}
if (szVid[0] != TEXT('\0'))
_tprintf (TEXT(" vid: \"%s\"\n"), szVid);
if (szPid[0] != TEXT('\0'))
_tprintf (TEXT(" pid: \"%s\"\n"), szPid);
if (szMi[0] != TEXT('\0'))
_tprintf (TEXT(" mi: \"%s\"\n"), szMi);
pszToken = _tcstok_s (NULL, TEXT("\\#&"), &pszNextToken);
//VID and PID for the playstation Move.
if( szVid[4] == TEXT('8') &&
szVid[5] == TEXT('8') &&
szVid[6] == TEXT('8') &&
szVid[7] == TEXT('8') &&
szPid[4] == TEXT('0') &&
szPid[5] == TEXT('3') &&
szPid[6] == TEXT('0') &&
szPid[7] == TEXT('8'))
{
std::cout << "PlayStation Move Detected!" << std::endl;
break;
}
}
}
return;
}
int main()
{
int iQuit;
ListUsbDevices();
std::cin >> iQuit;
return 0;
}
How come we need to define the FN_SetupDiGetDeviceProperty block of code first? And what does it acturly do? I thought that the SetupDiGetDeviceProperty function is part of the WDK so we can use it straight away??
typedef BOOL (WINAPI *FN_SetupDiGetDeviceProperty)(
__in HDEVINFO DeviceInfoSet,
__in PSP_DEVINFO_DATA DeviceInfoData,
__in const DEVPROPKEY *PropertyKey,
__out DEVPROPTYPE *PropertyType,
__out_opt PBYTE PropertyBuffer,
__in DWORD PropertyBufferSize,
__out_opt PDWORD RequiredSize,
__in DWORD Flags
);
The above code is defining FN_SetupDiGetDeviceProperty
as a pointer to a function taking that (long) list of parameters and returning a BOOL
. WINAPI
is a macro specifying the calling convention (__stdcall
, __cdecl
etc.) of the function.
Later on in your code, the function pointer fn_SetupDiGetDeviceProperty
is being conditionally set to either SetupDiGetDevicePropertyW
or SetupDiGetDevicePropertyA
depending on whether you're compiling with the UNICODE
macro defined or not.
There is actually no function named SetupDiGetDeviceProperty
exported by the DLL. If you dig through the headers of the library you're using you'll find something like this:
#ifdef UNICODE
#define SetupDiGetDeviceProperty SetupDiGetDevicePropertyW
#else
#define SetupDiGetDeviceProperty SetupDiGetDevicePropertyA
#endif
So, when you call SetupDiGetDeviceProperty
you're actually calling one of the 2 variants (A/W) of the function.