Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

331 lines
11 KiB

  1. //*********************************************************************
  2. //* Microsoft Windows **
  3. //* Copyright(c) Microsoft Corp., 1999 **
  4. //*********************************************************************
  5. //
  6. // usbHwChk.CPP - Implementation of USB Keyboard and Mouse checking
  7. //
  8. // HISTORY:
  9. //
  10. // 8/20/99 vyung Created.
  11. //
  12. #include "msobcomm.h"
  13. #include <setupapi.h>
  14. #include <cfgmgr32.h>
  15. #include <devguid.h>
  16. #include <util.h>
  17. #define ENUM_SUCCESS 0
  18. #define ENUM_GENFAILURE 4
  19. #define ENUM_CHILDFAILURE 2
  20. #define ENUM_SIBLINGFAILURE 1
  21. #define DEVICETYPE_MOUSE L"Mouse"
  22. #define DEVICETYPE_KEYBOARD L"keyboard"
  23. // BUGBUG: should be defined by sdk\inc\devguid.h
  24. #ifndef GUID_DEVCLASS_USB
  25. DEFINE_GUID( GUID_DEVCLASS_USB, 0x36fc9e60L, 0xc465, 0x11cf, 0x80, 0x56, 0x44, 0x45, 0x53, 0x54, 0x00, 0x00 );
  26. #endif
  27. // Function prototypes for cfgmgr32.dll
  28. typedef CMAPI
  29. CONFIGRET
  30. (WINAPI*
  31. PFNCMGETCHILD)(
  32. OUT PDEVINST pdnDevInst,
  33. IN DEVINST dnDevInst,
  34. IN ULONG ulFlags
  35. );
  36. typedef CMAPI
  37. CONFIGRET
  38. (WINAPI*
  39. PFCMGETSIBLING)(
  40. OUT PDEVINST pdnDevInst,
  41. IN DEVINST DevInst,
  42. IN ULONG ulFlags
  43. );
  44. typedef CMAPI
  45. #if defined(_REMOVE_) // looks like a typo
  46. CMAPI
  47. #endif // _REMOVE_
  48. CONFIGRET
  49. (WINAPI*
  50. PFCMGETDEVNODEREGISTRYPROPERTYA)(
  51. IN DEVINST dnDevInst,
  52. IN ULONG ulProperty,
  53. OUT PULONG pulRegDataType, OPTIONAL
  54. OUT PVOID Buffer, OPTIONAL
  55. IN OUT PULONG pulLength,
  56. IN ULONG ulFlags
  57. );
  58. BOOL g_bKeyboard = FALSE;
  59. BOOL g_bMouse = FALSE;
  60. /***************************************************************************
  61. Function: ProcessDevNode
  62. Retrieve each DevNode in the system and checks for keyboard and mouse
  63. ***************************************************************************/
  64. void ProcessDevNode(DEVNODE dnDevNode, FARPROC pfGetDevNodeProp)
  65. {
  66. //
  67. // We have gotten a child or a sibling. Get the class of device.
  68. //
  69. WCHAR buf[512];
  70. DWORD len = 0;
  71. len = MAX_CHARS_IN_BUFFER(buf);// BUGBUG: look up params to GetDevNodeProp
  72. DWORD cr = ((PFCMGETDEVNODEREGISTRYPROPERTYA)pfGetDevNodeProp)(dnDevNode,
  73. CM_DRP_CLASS, // Or CM_DRP_CLASSGUID
  74. NULL,
  75. buf,
  76. &len,
  77. 0);
  78. //
  79. // Does it match the keyboard class or the mouse class?
  80. // If so, set that variable and continue.
  81. //
  82. if(0 == lstrcmpi((LPCWSTR)buf, DEVICETYPE_KEYBOARD))
  83. {
  84. g_bKeyboard = TRUE;
  85. }
  86. if(0 == lstrcmp((LPCWSTR)buf, DEVICETYPE_MOUSE))
  87. {
  88. g_bMouse = TRUE;
  89. }
  90. }
  91. /***************************************************************************
  92. Function: EnumerateDevices
  93. Used to walk through every DevNode in the system and retrieve it's resources
  94. in the registry
  95. ***************************************************************************/
  96. long EnumerateDevices(DEVNODE dnDevNodeTraverse,
  97. int j,
  98. DEVNODE dnParentNode,
  99. FARPROC pfGetChild,
  100. FARPROC pfGetSibling,
  101. FARPROC pfGetDevNodeProp)
  102. {
  103. DEVNODE dnDevNodeMe;
  104. DEVNODE dnDevNodeSibling;
  105. DEVNODE dnDevNodeChild;
  106. CONFIGRET cr;
  107. static long lError;
  108. dnDevNodeMe = dnDevNodeTraverse;
  109. while( TRUE )
  110. {
  111. cr = ((PFNCMGETCHILD)pfGetChild)(&dnDevNodeChild, dnDevNodeMe, 0);
  112. switch(cr)
  113. {
  114. case CR_SUCCESS:
  115. //Write new node, as a branch or root
  116. ProcessDevNode(dnDevNodeMe, pfGetDevNodeProp);
  117. //Pass up failure
  118. lError = EnumerateDevices(dnDevNodeChild, 0, dnDevNodeMe, pfGetChild, pfGetSibling, pfGetDevNodeProp);
  119. if ( lError != ENUM_SUCCESS )
  120. return lError;
  121. break;
  122. //No children, I am a bottom branch!
  123. case CR_NO_SUCH_DEVNODE:
  124. // This is ok too. If just means the the call couldn't find
  125. // either a sibling or a child.
  126. // Write new node, as a leaf
  127. ProcessDevNode(dnDevNodeMe, pfGetDevNodeProp);
  128. break;
  129. //We puked on something, return code of 3 will end entire traversal
  130. default:
  131. return ENUM_CHILDFAILURE;
  132. }
  133. //Get next sibling, repeat
  134. cr = ((PFCMGETSIBLING)pfGetSibling)(&dnDevNodeSibling, dnDevNodeMe, 0);
  135. switch(cr)
  136. {
  137. case CR_SUCCESS:
  138. dnDevNodeMe = dnDevNodeSibling; // I'm now the sibling
  139. break;
  140. case CR_NO_SUCH_DEVNODE:
  141. return ENUM_SUCCESS; //Out of siblings...
  142. default:
  143. return ENUM_SIBLINGFAILURE ; //We puked on something, return code of 2 will end entire traversal
  144. }
  145. }
  146. }
  147. /***************************************************************************
  148. Function: IsMouseOrKeyboardPresent
  149. Used to walk through every USB DevNode in the system and check it's resources
  150. in the registry for keyboard and mouse
  151. ***************************************************************************/
  152. DWORD
  153. IsMouseOrKeyboardPresent(HWND HWnd,
  154. PBOOL pbKeyboardPresent,
  155. PBOOL pbMousePresent)
  156. {
  157. SP_DEVINFO_DATA DevData;
  158. HDEVINFO hDevInfo;
  159. DEVNODE dnDevInst;
  160. DWORD dwPropertyType;
  161. BYTE* lpPropertyBuffer = NULL; //buf[MAX_PATH];
  162. DWORD requiredSize = MAX_PATH;
  163. DWORD dwRet = ERROR_SUCCESS;
  164. GUID tempGuid;
  165. int i;
  166. memcpy(&tempGuid, &GUID_DEVCLASS_USB, sizeof(GUID));
  167. HINSTANCE hInst = NULL;
  168. g_bKeyboard = FALSE;
  169. g_bMouse = FALSE;
  170. FARPROC pfGetChild = NULL, pfGetSibling = NULL, pfGetDevNodeProp = NULL;
  171. hInst = LoadLibrary(L"CFGMGR32.DLL");
  172. if (hInst)
  173. {
  174. // Load the CM_Get_* API
  175. pfGetChild = GetProcAddress(hInst, "CM_Get_Child");
  176. pfGetSibling = GetProcAddress(hInst, "CM_Get_Sibling");
  177. pfGetDevNodeProp = GetProcAddress(hInst, "CM_Get_DevNode_Registry_PropertyW");
  178. if (pfGetChild && pfGetSibling && pfGetDevNodeProp)
  179. {
  180. lpPropertyBuffer = new BYTE[requiredSize];
  181. if ( ! lpPropertyBuffer ) {
  182. dwRet = ERROR_NOT_ENOUGH_MEMORY;
  183. goto IsMouseOrKeyboardPresentError;
  184. }
  185. hDevInfo = SetupDiGetClassDevs(&tempGuid,
  186. NULL,
  187. HWnd,
  188. DIGCF_PRESENT);
  189. //Set the size of DevData
  190. DevData.cbSize = sizeof(DevData);
  191. for (i = 0;
  192. SetupDiEnumDeviceInfo(hDevInfo, i, &DevData);
  193. i++)
  194. {
  195. if (!SetupDiGetDeviceRegistryProperty(hDevInfo,
  196. &DevData,
  197. SPDRP_HARDWAREID,
  198. (PDWORD)&dwPropertyType,
  199. lpPropertyBuffer,
  200. requiredSize,
  201. &requiredSize))
  202. {
  203. dwRet = GetLastError();
  204. if (dwRet == ERROR_INSUFFICIENT_BUFFER) {
  205. //
  206. // Allocate an appropriate size buffer and call
  207. // SetupDiGetDeviceRegistryProperty again to get
  208. // the hardware ids.
  209. //
  210. dwRet = ERROR_SUCCESS;
  211. delete [] lpPropertyBuffer;
  212. lpPropertyBuffer = new BYTE[requiredSize];
  213. if ( ! lpPropertyBuffer ) {
  214. dwRet = ERROR_NOT_ENOUGH_MEMORY;
  215. goto IsMouseOrKeyboardPresentError;
  216. }
  217. if (!SetupDiGetDeviceRegistryProperty(hDevInfo,
  218. &DevData,
  219. SPDRP_HARDWAREID,
  220. (PDWORD)&dwPropertyType,
  221. lpPropertyBuffer,
  222. requiredSize,
  223. &requiredSize))
  224. {
  225. dwRet = GetLastError();
  226. goto IsMouseOrKeyboardPresentError;
  227. }
  228. } else {
  229. goto IsMouseOrKeyboardPresentError;
  230. }
  231. }
  232. //
  233. // We've now got the hardware ids.
  234. // Using your best string compare code for MULTI_SZ strings,
  235. // Find out if one of the ids is "USB\ROOT_HUB"
  236. //
  237. // if (one of the ids is not "USB\ROOT_HUB") {
  238. // continue;
  239. // }
  240. //
  241. if(0 != wmemcmp( (LPCWSTR)lpPropertyBuffer, L"USB", MAX_CHARS_IN_BUFFER(L"USB") ))
  242. {
  243. continue;
  244. }
  245. dnDevInst = DevData.DevInst;
  246. //
  247. // One of the ids is USB\ROOT_HUB.
  248. // Time to search for a keyboard or a mouse!
  249. // Use the following two apis to search through the tree underneath
  250. // the root hub to find devnodes. I haven't included this search code,
  251. // but I'm sure you can be creative and use a depth or breadth algorithm
  252. // of some sort. When you're done, break out of the loop.
  253. //
  254. if (ENUM_SUCCESS != EnumerateDevices(dnDevInst, 2, 0, pfGetChild, pfGetSibling, pfGetDevNodeProp))
  255. {
  256. dwRet = GetLastError();
  257. TRACE1( L"EnumerateDevices failed. Error = %d", dwRet);
  258. }
  259. }
  260. }
  261. else
  262. {
  263. dwRet = GetLastError();
  264. }
  265. }
  266. else
  267. {
  268. dwRet = GetLastError();
  269. }
  270. MYASSERT( dwRet == ERROR_SUCCESS );
  271. IsMouseOrKeyboardPresentError:
  272. if (hInst) {
  273. FreeLibrary(hInst);
  274. hInst = NULL;
  275. }
  276. if (lpPropertyBuffer) {
  277. delete [] lpPropertyBuffer;
  278. lpPropertyBuffer = NULL;
  279. }
  280. *pbKeyboardPresent = g_bKeyboard;
  281. *pbMousePresent = g_bMouse;
  282. return dwRet;
  283. }