//********************************************************************* //* Microsoft Windows ** //* Copyright(c) Microsoft Corp., 1999 ** //********************************************************************* // // usbHwChk.CPP - Implementation of USB Keyboard and Mouse checking // // HISTORY: // // 8/20/99 vyung Created. // #include "msobcomm.h" #include #include #include #include #define ENUM_SUCCESS 0 #define ENUM_GENFAILURE 4 #define ENUM_CHILDFAILURE 2 #define ENUM_SIBLINGFAILURE 1 #define DEVICETYPE_MOUSE L"Mouse" #define DEVICETYPE_KEYBOARD L"keyboard" // BUGBUG: should be defined by sdk\inc\devguid.h #ifndef GUID_DEVCLASS_USB DEFINE_GUID( GUID_DEVCLASS_USB, 0x36fc9e60L, 0xc465, 0x11cf, 0x80, 0x56, 0x44, 0x45, 0x53, 0x54, 0x00, 0x00 ); #endif // Function prototypes for cfgmgr32.dll typedef CMAPI CONFIGRET (WINAPI* PFNCMGETCHILD)( OUT PDEVINST pdnDevInst, IN DEVINST dnDevInst, IN ULONG ulFlags ); typedef CMAPI CONFIGRET (WINAPI* PFCMGETSIBLING)( OUT PDEVINST pdnDevInst, IN DEVINST DevInst, IN ULONG ulFlags ); typedef CMAPI #if defined(_REMOVE_) // looks like a typo CMAPI #endif // _REMOVE_ CONFIGRET (WINAPI* PFCMGETDEVNODEREGISTRYPROPERTYA)( IN DEVINST dnDevInst, IN ULONG ulProperty, OUT PULONG pulRegDataType, OPTIONAL OUT PVOID Buffer, OPTIONAL IN OUT PULONG pulLength, IN ULONG ulFlags ); BOOL g_bKeyboard = FALSE; BOOL g_bMouse = FALSE; /*************************************************************************** Function: ProcessDevNode Retrieve each DevNode in the system and checks for keyboard and mouse ***************************************************************************/ void ProcessDevNode(DEVNODE dnDevNode, FARPROC pfGetDevNodeProp) { // // We have gotten a child or a sibling. Get the class of device. // WCHAR buf[512]; DWORD len = 0; len = MAX_CHARS_IN_BUFFER(buf);// BUGBUG: look up params to GetDevNodeProp DWORD cr = ((PFCMGETDEVNODEREGISTRYPROPERTYA)pfGetDevNodeProp)(dnDevNode, CM_DRP_CLASS, // Or CM_DRP_CLASSGUID NULL, buf, &len, 0); // // Does it match the keyboard class or the mouse class? // If so, set that variable and continue. // if(0 == lstrcmpi((LPCWSTR)buf, DEVICETYPE_KEYBOARD)) { g_bKeyboard = TRUE; } if(0 == lstrcmp((LPCWSTR)buf, DEVICETYPE_MOUSE)) { g_bMouse = TRUE; } } /*************************************************************************** Function: EnumerateDevices Used to walk through every DevNode in the system and retrieve it's resources in the registry ***************************************************************************/ long EnumerateDevices(DEVNODE dnDevNodeTraverse, int j, DEVNODE dnParentNode, FARPROC pfGetChild, FARPROC pfGetSibling, FARPROC pfGetDevNodeProp) { DEVNODE dnDevNodeMe; DEVNODE dnDevNodeSibling; DEVNODE dnDevNodeChild; CONFIGRET cr; static long lError; dnDevNodeMe = dnDevNodeTraverse; while( TRUE ) { cr = ((PFNCMGETCHILD)pfGetChild)(&dnDevNodeChild, dnDevNodeMe, 0); switch(cr) { case CR_SUCCESS: //Write new node, as a branch or root ProcessDevNode(dnDevNodeMe, pfGetDevNodeProp); //Pass up failure lError = EnumerateDevices(dnDevNodeChild, 0, dnDevNodeMe, pfGetChild, pfGetSibling, pfGetDevNodeProp); if ( lError != ENUM_SUCCESS ) return lError; break; //No children, I am a bottom branch! case CR_NO_SUCH_DEVNODE: // This is ok too. If just means the the call couldn't find // either a sibling or a child. // Write new node, as a leaf ProcessDevNode(dnDevNodeMe, pfGetDevNodeProp); break; //We puked on something, return code of 3 will end entire traversal default: return ENUM_CHILDFAILURE; } //Get next sibling, repeat cr = ((PFCMGETSIBLING)pfGetSibling)(&dnDevNodeSibling, dnDevNodeMe, 0); switch(cr) { case CR_SUCCESS: dnDevNodeMe = dnDevNodeSibling; // I'm now the sibling break; case CR_NO_SUCH_DEVNODE: return ENUM_SUCCESS; //Out of siblings... default: return ENUM_SIBLINGFAILURE ; //We puked on something, return code of 2 will end entire traversal } } } /*************************************************************************** Function: IsMouseOrKeyboardPresent Used to walk through every USB DevNode in the system and check it's resources in the registry for keyboard and mouse ***************************************************************************/ DWORD IsMouseOrKeyboardPresent(HWND HWnd, PBOOL pbKeyboardPresent, PBOOL pbMousePresent) { SP_DEVINFO_DATA DevData; HDEVINFO hDevInfo; DEVNODE dnDevInst; DWORD dwPropertyType; BYTE* lpPropertyBuffer = NULL; //buf[MAX_PATH]; DWORD requiredSize = MAX_PATH; DWORD dwRet = ERROR_SUCCESS; GUID tempGuid; int i; memcpy(&tempGuid, &GUID_DEVCLASS_USB, sizeof(GUID)); HINSTANCE hInst = NULL; g_bKeyboard = FALSE; g_bMouse = FALSE; FARPROC pfGetChild = NULL, pfGetSibling = NULL, pfGetDevNodeProp = NULL; hInst = LoadLibrary(L"CFGMGR32.DLL"); if (hInst) { // Load the CM_Get_* API pfGetChild = GetProcAddress(hInst, "CM_Get_Child"); pfGetSibling = GetProcAddress(hInst, "CM_Get_Sibling"); pfGetDevNodeProp = GetProcAddress(hInst, "CM_Get_DevNode_Registry_PropertyW"); if (pfGetChild && pfGetSibling && pfGetDevNodeProp) { lpPropertyBuffer = new BYTE[requiredSize]; if ( ! lpPropertyBuffer ) { dwRet = ERROR_NOT_ENOUGH_MEMORY; goto IsMouseOrKeyboardPresentError; } hDevInfo = SetupDiGetClassDevs(&tempGuid, NULL, HWnd, DIGCF_PRESENT); //Set the size of DevData DevData.cbSize = sizeof(DevData); for (i = 0; SetupDiEnumDeviceInfo(hDevInfo, i, &DevData); i++) { if (!SetupDiGetDeviceRegistryProperty(hDevInfo, &DevData, SPDRP_HARDWAREID, (PDWORD)&dwPropertyType, lpPropertyBuffer, requiredSize, &requiredSize)) { dwRet = GetLastError(); if (dwRet == ERROR_INSUFFICIENT_BUFFER) { // // Allocate an appropriate size buffer and call // SetupDiGetDeviceRegistryProperty again to get // the hardware ids. // dwRet = ERROR_SUCCESS; delete [] lpPropertyBuffer; lpPropertyBuffer = new BYTE[requiredSize]; if ( ! lpPropertyBuffer ) { dwRet = ERROR_NOT_ENOUGH_MEMORY; goto IsMouseOrKeyboardPresentError; } if (!SetupDiGetDeviceRegistryProperty(hDevInfo, &DevData, SPDRP_HARDWAREID, (PDWORD)&dwPropertyType, lpPropertyBuffer, requiredSize, &requiredSize)) { dwRet = GetLastError(); goto IsMouseOrKeyboardPresentError; } } else { goto IsMouseOrKeyboardPresentError; } } // // We've now got the hardware ids. // Using your best string compare code for MULTI_SZ strings, // Find out if one of the ids is "USB\ROOT_HUB" // // if (one of the ids is not "USB\ROOT_HUB") { // continue; // } // if(0 != wmemcmp( (LPCWSTR)lpPropertyBuffer, L"USB", MAX_CHARS_IN_BUFFER(L"USB") )) { continue; } dnDevInst = DevData.DevInst; // // One of the ids is USB\ROOT_HUB. // Time to search for a keyboard or a mouse! // Use the following two apis to search through the tree underneath // the root hub to find devnodes. I haven't included this search code, // but I'm sure you can be creative and use a depth or breadth algorithm // of some sort. When you're done, break out of the loop. // if (ENUM_SUCCESS != EnumerateDevices(dnDevInst, 2, 0, pfGetChild, pfGetSibling, pfGetDevNodeProp)) { dwRet = GetLastError(); TRACE1( L"EnumerateDevices failed. Error = %d", dwRet); } } } else { dwRet = GetLastError(); } } else { dwRet = GetLastError(); } MYASSERT( dwRet == ERROR_SUCCESS ); IsMouseOrKeyboardPresentError: if (hInst) { FreeLibrary(hInst); hInst = NULL; } if (lpPropertyBuffer) { delete [] lpPropertyBuffer; lpPropertyBuffer = NULL; } *pbKeyboardPresent = g_bKeyboard; *pbMousePresent = g_bMouse; return dwRet; }