Leaked source code of windows server 2003
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.

903 lines
37 KiB

  1. /****************************************************************************
  2. *
  3. * File: inptinfo.cpp
  4. * Project: DxDiag (DirectX Diagnostic Tool)
  5. * Author: Mike Anderson (manders@microsoft.com)
  6. * Purpose: Gather information about input devices on this machine
  7. *
  8. * (C) Copyright 1998 Microsoft Corp. All rights reserved.
  9. *
  10. ****************************************************************************/
  11. #define DIRECTINPUT_VERSION 0x0800
  12. #include <tchar.h>
  13. #include <Windows.h>
  14. #include <regstr.h>
  15. #include <mmsystem.h>
  16. #include <stdio.h>
  17. #include <hidclass.h>
  18. #include <setupapi.h>
  19. #include <cfgmgr32.h>
  20. #include <dinput.h>
  21. #include "mmddk.h"
  22. #include "reginfo.h"
  23. #include "sysinfo.h" // for BIsPlatformNT
  24. #include "inptinfo.h"
  25. #include "fileinfo.h"
  26. #include "resource.h"
  27. static HRESULT Get9xInputDeviceInfo(InputInfo* pInputInfo);
  28. static HRESULT GetNTInputDeviceInfo(InputInfo* pInputInfo);
  29. static VOID GetJoystickTypeDesc(DWORD dwType, TCHAR* pszDesc);
  30. static HRESULT CheckRegistry(InputInfo* pInputInfo, RegError** ppRegErrorFirst);
  31. /****************************************************************************
  32. *
  33. * GetInputInfo
  34. *
  35. ****************************************************************************/
  36. HRESULT GetInputInfo(InputInfo** ppInputInfo)
  37. {
  38. HRESULT hr;
  39. *ppInputInfo = new InputInfo;
  40. if (*ppInputInfo == NULL)
  41. return E_OUTOFMEMORY;
  42. ZeroMemory(*ppInputInfo, sizeof(InputInfo));
  43. (*ppInputInfo)->m_bNT = BIsPlatformNT();
  44. if ((*ppInputInfo)->m_bNT)
  45. {
  46. if (FAILED(hr = GetNTInputDeviceInfo(*ppInputInfo)))
  47. return hr;
  48. }
  49. else
  50. {
  51. if (FAILED(hr = Get9xInputDeviceInfo(*ppInputInfo)))
  52. return hr;
  53. }
  54. if (FAILED(hr = CheckRegistry(*ppInputInfo, &(*ppInputInfo)->m_pRegErrorFirst)))
  55. return hr;
  56. return S_OK;
  57. }
  58. // Have to do the LoadLibrary/GetProcAddress thing for dinput.dll and setupapi.dll:
  59. typedef HRESULT (WINAPI* PfnDirectInputCreateA)(HINSTANCE hinst, DWORD dwVersion, LPDIRECTINPUTA *ppDI, LPUNKNOWN punkOuter);
  60. typedef HRESULT (WINAPI* PfnDirectInputCreateW)(HINSTANCE hinst, DWORD dwVersion, LPDIRECTINPUTW *ppDI, LPUNKNOWN punkOuter);
  61. typedef WINSETUPAPI HDEVINFO (WINAPI* PfnSetupDiGetClassDevsA)(IN CONST GUID *ClassGuid, IN PCSTR Enumerator, IN HWND hwndParent, IN DWORD Flags);
  62. typedef WINSETUPAPI HDEVINFO (WINAPI* PfnSetupDiGetClassDevsW)(IN CONST GUID *ClassGuid, IN PCWSTR Enumerator, IN HWND hwndParent, IN DWORD Flags);
  63. typedef WINSETUPAPI BOOL (WINAPI* PfnSetupDiEnumDeviceInterfaces)(IN HDEVINFO DeviceInfoSet, IN PSP_DEVINFO_DATA DeviceInfoData, IN CONST GUID *InterfaceClassGuid, IN DWORD MemberIndex, OUT PSP_DEVICE_INTERFACE_DATA DeviceInterfaceData);
  64. typedef WINSETUPAPI BOOL (WINAPI* PfnSetupDiGetDeviceInterfaceDetailA)(IN HDEVINFO DeviceInfoSet, IN PSP_DEVICE_INTERFACE_DATA DeviceInterfaceData, OUT PSP_DEVICE_INTERFACE_DETAIL_DATA_A DeviceInterfaceDetailData, IN DWORD DeviceInterfaceDetailDataSize, OUT PDWORD RequiredSize, OUT PSP_DEVINFO_DATA DeviceInfoData);
  65. typedef WINSETUPAPI BOOL (WINAPI* PfnSetupDiGetDeviceInterfaceDetailW)(IN HDEVINFO DeviceInfoSet, IN PSP_DEVICE_INTERFACE_DATA DeviceInterfaceData, OUT PSP_DEVICE_INTERFACE_DETAIL_DATA_W DeviceInterfaceDetailData, IN DWORD DeviceInterfaceDetailDataSize, OUT PDWORD RequiredSize, OUT PSP_DEVINFO_DATA DeviceInfoData);
  66. typedef WINSETUPAPI BOOL (WINAPI* PfnSetupDiDestroyDeviceInfoList)(IN HDEVINFO DeviceInfoSet);
  67. typedef CMAPI CONFIGRET (WINAPI* PfnCM_Get_Parent)(OUT PDEVINST pdnDevInst, IN DEVINST dnDevInst, IN ULONG ulFlags);
  68. typedef CMAPI CONFIGRET (WINAPI* PfnCM_Get_DevNode_Status)(OUT PULONG pulStatus, OUT PULONG pulProblemNumber, IN DEVINST dnDevInst, IN ULONG ulFlags);
  69. typedef CMAPI CONFIGRET (WINAPI* PfnCM_Get_DevNode_Registry_PropertyW)(IN DEVINST dnDevInst, IN ULONG ulProperty, OUT PULONG pulRegDataType, OPTIONAL OUT PVOID Buffer, OPTIONAL IN OUT PULONG pulLength, IN ULONG ulFlags);
  70. typedef CMAPI CONFIGRET (WINAPI* PfnCM_Get_DevNode_Registry_PropertyA)(IN DEVINST dnDevInst, IN ULONG ulProperty, OUT PULONG pulRegDataType, OPTIONAL OUT PVOID Buffer, OPTIONAL IN OUT PULONG pulLength, IN ULONG ulFlags);
  71. /****************************************************************************
  72. *
  73. * GetNTInputDeviceInfo
  74. *
  75. ****************************************************************************/
  76. HRESULT GetNTInputDeviceInfo(InputInfo* pInputInfo)
  77. {
  78. HINSTANCE hInstDInput = NULL;
  79. HINSTANCE hInstSetupApi = NULL;
  80. LPDIRECTINPUT pDI = NULL;
  81. GUID guidHid;
  82. HDEVINFO hdev = NULL;
  83. SP_DEVICE_INTERFACE_DETAIL_DATA* pdidd;
  84. InputDeviceInfoNT* pInputDeviceInfoNTNew;
  85. PfnCM_Get_Parent FnCM_Get_Parent = NULL;
  86. PfnCM_Get_DevNode_Status FnCM_Get_DevNode_Status = NULL;
  87. PfnSetupDiEnumDeviceInterfaces FnSetupDiEnumDeviceInterfaces = NULL;
  88. PfnSetupDiDestroyDeviceInfoList FnSetupDiDestroyDeviceInfoList = NULL;
  89. #ifdef UNICODE
  90. PfnDirectInputCreateW FnDirectInputCreate = NULL;
  91. PfnCM_Get_DevNode_Registry_PropertyW FnCM_Get_DevNode_Registry_Property = NULL;
  92. PfnSetupDiGetClassDevsW FnSetupDiGetClassDevs = NULL;
  93. PfnSetupDiGetDeviceInterfaceDetailW FnSetupDiGetDeviceInterfaceDetail = NULL;
  94. #else
  95. PfnDirectInputCreateA FnDirectInputCreate = NULL;
  96. PfnCM_Get_DevNode_Registry_PropertyA FnCM_Get_DevNode_Registry_Property = NULL;
  97. PfnSetupDiGetClassDevsA FnSetupDiGetClassDevs = NULL;
  98. PfnSetupDiGetDeviceInterfaceDetailA FnSetupDiGetDeviceInterfaceDetail = NULL;
  99. #endif
  100. // Apparently one must initialize DInput before enumerating HID devices
  101. hInstDInput = LoadLibrary(TEXT("dinput.dll"));
  102. if (hInstDInput == NULL)
  103. goto LEnd;
  104. #ifdef UNICODE
  105. FnDirectInputCreate = (PfnDirectInputCreateW)GetProcAddress(hInstDInput, "DirectInputCreateW");
  106. if (FnDirectInputCreate == NULL)
  107. goto LEnd;
  108. #else
  109. FnDirectInputCreate = (PfnDirectInputCreateA)GetProcAddress(hInstDInput, "DirectInputCreateA");
  110. if (FnDirectInputCreate == NULL)
  111. goto LEnd;
  112. #endif
  113. if (SUCCEEDED(FnDirectInputCreate(NULL, 0x0300, &pDI, NULL)))
  114. pDI->Release(); // immediately drop DI interface; we don't actually use it
  115. hInstSetupApi = LoadLibrary(TEXT("setupapi.dll"));
  116. if (hInstSetupApi == NULL)
  117. goto LEnd;
  118. FnCM_Get_Parent = (PfnCM_Get_Parent)GetProcAddress(hInstSetupApi, "CM_Get_Parent");
  119. if (FnCM_Get_Parent == NULL)
  120. goto LEnd;
  121. FnCM_Get_DevNode_Status = (PfnCM_Get_DevNode_Status)GetProcAddress(hInstSetupApi, "CM_Get_DevNode_Status");
  122. if (FnCM_Get_DevNode_Status == NULL)
  123. goto LEnd;
  124. FnSetupDiEnumDeviceInterfaces = (PfnSetupDiEnumDeviceInterfaces)GetProcAddress(hInstSetupApi, "SetupDiEnumDeviceInterfaces");
  125. if (FnSetupDiEnumDeviceInterfaces == NULL)
  126. goto LEnd;
  127. FnSetupDiDestroyDeviceInfoList = (PfnSetupDiDestroyDeviceInfoList)GetProcAddress(hInstSetupApi, "SetupDiDestroyDeviceInfoList");
  128. if (FnSetupDiDestroyDeviceInfoList == NULL)
  129. goto LEnd;
  130. #ifdef UNICODE
  131. FnCM_Get_DevNode_Registry_Property = (PfnCM_Get_DevNode_Registry_PropertyW)GetProcAddress(hInstSetupApi, "CM_Get_DevNode_Registry_PropertyW");
  132. if (FnCM_Get_DevNode_Registry_Property == NULL)
  133. goto LEnd;
  134. FnSetupDiGetClassDevs = (PfnSetupDiGetClassDevsW)GetProcAddress(hInstSetupApi, "SetupDiGetClassDevsW");
  135. if (FnSetupDiGetClassDevs == NULL)
  136. goto LEnd;
  137. FnSetupDiGetDeviceInterfaceDetail = (PfnSetupDiGetDeviceInterfaceDetailW)GetProcAddress(hInstSetupApi, "SetupDiGetDeviceInterfaceDetailW");
  138. if (FnSetupDiGetDeviceInterfaceDetail == NULL)
  139. goto LEnd;
  140. #else
  141. FnCM_Get_DevNode_Registry_Property = (PfnCM_Get_DevNode_Registry_PropertyA)GetProcAddress(hInstSetupApi, "CM_Get_DevNode_Registry_PropertyA");
  142. if (FnCM_Get_DevNode_Registry_Property == NULL)
  143. goto LEnd;
  144. FnSetupDiGetClassDevs = (PfnSetupDiGetClassDevsA)GetProcAddress(hInstSetupApi, "SetupDiGetClassDevsA");
  145. if (FnSetupDiGetClassDevs == NULL)
  146. goto LEnd;
  147. FnSetupDiGetDeviceInterfaceDetail = (PfnSetupDiGetDeviceInterfaceDetailA)GetProcAddress(hInstSetupApi, "SetupDiGetDeviceInterfaceDetailA");
  148. if (FnSetupDiGetDeviceInterfaceDetail == NULL)
  149. goto LEnd;
  150. #endif
  151. guidHid = GUID_CLASS_INPUT;
  152. hdev = FnSetupDiGetClassDevs(&guidHid, 0, 0, DIGCF_PRESENT | DIGCF_DEVICEINTERFACE);
  153. if (hdev == INVALID_HANDLE_VALUE || hdev == NULL)
  154. return E_FAIL;
  155. int idev;
  156. // There is no way to query the number of devices.
  157. // You just have to keep incrementing until you run out.
  158. // To avoid infinite looping on internal errors, break on any
  159. // error once we have tried more than chdiMax devices, since that's the most
  160. // HID will ever give us. 64 is a resonable value for chidMax. It is the
  161. // max allowed USB/HID devices.
  162. for (idev = 0; idev < 64/*chdiMax*/; idev++)
  163. {
  164. SP_DEVICE_INTERFACE_DATA did;
  165. did.cbSize = sizeof(did);
  166. if (!FnSetupDiEnumDeviceInterfaces(hdev, 0, &guidHid, idev, &did))
  167. {
  168. if(GetLastError() == ERROR_NO_MORE_ITEMS)
  169. break;
  170. else
  171. continue;
  172. }
  173. /*
  174. * Ask for the required size then allocate it then fill it.
  175. *
  176. * Note that we don't need to free the memory on the failure
  177. * path; our caller will do the necessary memory freeing.
  178. *
  179. * Sigh. Windows NT and Windows 98 implement
  180. * SetupDiGetDeviceInterfaceDetail differently if you are
  181. * querying for the buffer size.
  182. *
  183. * Windows 98 returns FALSE, and GetLastError() returns
  184. * ERROR_INSUFFICIENT_BUFFER.
  185. *
  186. * Windows NT returns TRUE.
  187. *
  188. * So we allow the cases either where the call succeeds or
  189. * the call fails with ERROR_INSUFFICIENT_BUFFER.
  190. */
  191. SP_DEVINFO_DATA dinf;
  192. DWORD cbRequired;
  193. if (FnSetupDiGetDeviceInterfaceDetail(hdev, &did, 0, 0, &cbRequired, 0) ||
  194. GetLastError() == ERROR_INSUFFICIENT_BUFFER)
  195. {
  196. pdidd = (SP_DEVICE_INTERFACE_DETAIL_DATA*)(new BYTE[cbRequired]);
  197. if (pdidd == NULL)
  198. continue;
  199. ZeroMemory(pdidd, cbRequired);
  200. pdidd->cbSize = sizeof(SP_DEVICE_INTERFACE_DETAIL_DATA);
  201. dinf.cbSize = sizeof(dinf);
  202. if (!FnSetupDiGetDeviceInterfaceDetail(hdev, &did, pdidd, cbRequired, &cbRequired, &dinf))
  203. {
  204. delete[] pdidd;
  205. continue;
  206. }
  207. delete[] pdidd;
  208. DEVINST dinst;
  209. if (CR_SUCCESS != FnCM_Get_Parent(&dinst, dinf.DevInst, 0))
  210. continue;
  211. pInputDeviceInfoNTNew = new InputDeviceInfoNT;
  212. if (pInputDeviceInfoNTNew == NULL)
  213. return E_OUTOFMEMORY;
  214. ZeroMemory(pInputDeviceInfoNTNew, sizeof(InputDeviceInfoNT));
  215. if (pInputInfo->m_pInputDeviceInfoNTFirst == NULL)
  216. {
  217. pInputInfo->m_pInputDeviceInfoNTFirst = pInputDeviceInfoNTNew;
  218. }
  219. else
  220. {
  221. InputDeviceInfoNT* pInputDeviceInfoNT;
  222. for (pInputDeviceInfoNT = pInputInfo->m_pInputDeviceInfoNTFirst;
  223. pInputDeviceInfoNT->m_pInputDeviceInfoNTNext != NULL;
  224. pInputDeviceInfoNT = pInputDeviceInfoNT->m_pInputDeviceInfoNTNext)
  225. {
  226. }
  227. pInputDeviceInfoNT->m_pInputDeviceInfoNTNext = pInputDeviceInfoNTNew;
  228. }
  229. CONFIGRET cr;
  230. TCHAR sz[200];
  231. ULONG ulLength;
  232. ulLength = 200;
  233. cr = FnCM_Get_DevNode_Registry_Property(dinst, CM_DRP_DEVICEDESC,
  234. NULL, (BYTE*)pInputDeviceInfoNTNew->m_szName, &ulLength, NULL);
  235. // Friendly name is preferably to device desc, but is often (always?) missing
  236. ulLength = 200;
  237. cr = FnCM_Get_DevNode_Registry_Property(dinst, CM_DRP_FRIENDLYNAME,
  238. NULL, (BYTE*)sz, &ulLength, NULL);
  239. if (cr == CR_SUCCESS)
  240. lstrcpy(pInputDeviceInfoNTNew->m_szName, sz);
  241. ulLength = 200;
  242. cr = FnCM_Get_DevNode_Registry_Property(dinst, CM_DRP_MFG,
  243. NULL, (BYTE*)pInputDeviceInfoNTNew->m_szProvider, &ulLength, NULL);
  244. ulLength = 200;
  245. cr = FnCM_Get_DevNode_Registry_Property(dinst, CM_DRP_HARDWAREID,
  246. NULL, (BYTE*)pInputDeviceInfoNTNew->m_szId, &ulLength, NULL);
  247. cr = FnCM_Get_DevNode_Status(&pInputDeviceInfoNTNew->m_dwStatus, &pInputDeviceInfoNTNew->m_dwProblem, dinst, 0);
  248. DEVINST dinstPort;
  249. if (CR_SUCCESS != FnCM_Get_Parent(&dinstPort, dinst, 0))
  250. continue;
  251. ulLength = 200;
  252. cr = FnCM_Get_DevNode_Registry_Property(dinstPort, CM_DRP_DEVICEDESC,
  253. NULL, (BYTE*)pInputDeviceInfoNTNew->m_szPortName, &ulLength, NULL);
  254. // Friendly name is preferably to device desc, but is often (always?) missing
  255. ulLength = 200;
  256. cr = FnCM_Get_DevNode_Registry_Property(dinstPort, CM_DRP_FRIENDLYNAME,
  257. NULL, (BYTE*)sz, &ulLength, NULL);
  258. if (cr == CR_SUCCESS)
  259. lstrcpy(pInputDeviceInfoNTNew->m_szPortName, sz);
  260. ulLength = 200;
  261. cr = FnCM_Get_DevNode_Registry_Property(dinstPort, CM_DRP_MFG,
  262. NULL, (BYTE*)pInputDeviceInfoNTNew->m_szPortProvider, &ulLength, NULL);
  263. ulLength = 200;
  264. cr = FnCM_Get_DevNode_Registry_Property(dinstPort, CM_DRP_HARDWAREID,
  265. NULL, (BYTE*)pInputDeviceInfoNTNew->m_szPortId, &ulLength, NULL);
  266. cr = FnCM_Get_DevNode_Status(&pInputDeviceInfoNTNew->m_dwPortStatus, &pInputDeviceInfoNTNew->m_dwPortProblem, dinstPort, 0);
  267. }
  268. }
  269. LEnd:
  270. if (hdev != NULL)
  271. FnSetupDiDestroyDeviceInfoList(hdev);
  272. if (hInstSetupApi != NULL)
  273. FreeLibrary(hInstSetupApi);
  274. if (hInstDInput != NULL)
  275. FreeLibrary(hInstDInput);
  276. return S_OK;
  277. }
  278. /****************************************************************************
  279. *
  280. * Get9xInputDeviceInfo
  281. *
  282. ****************************************************************************/
  283. HRESULT Get9xInputDeviceInfo(InputInfo* pInputInfo)
  284. {
  285. DWORD dwDevNum;
  286. JOYCAPS jc;
  287. HKEY hkBase;
  288. HKEY hkDrv;
  289. HKEY hkData;
  290. JOYREGHWCONFIG jhwc;
  291. DWORD dwBufferLen;
  292. INT i;
  293. TCHAR szKey[256];
  294. TCHAR szOEMKey[256];
  295. HKEY hkOEMBase;
  296. HKEY hkOEMData;
  297. TCHAR szOEMName[256];
  298. TCHAR szOEMCallout[256];
  299. InputDeviceInfo* pInputDeviceInfoNew;
  300. InputDeviceInfo* pInputDeviceInfo;
  301. TCHAR szPath[MAX_PATH];
  302. TCHAR sz[200];
  303. dwDevNum = (DWORD)-1;
  304. if (JOYERR_NOERROR == joyGetDevCaps(dwDevNum, &jc, sizeof jc))
  305. {
  306. if ((ERROR_SUCCESS == RegOpenKeyEx(HKEY_LOCAL_MACHINE, REGSTR_PATH_JOYCONFIG, 0, KEY_READ, &hkBase))
  307. && (ERROR_SUCCESS == RegOpenKeyEx(hkBase, jc.szRegKey, 0, KEY_READ, &hkDrv))
  308. && (ERROR_SUCCESS == RegOpenKeyEx(hkDrv, REGSTR_KEY_JOYCURR, 0, KEY_READ, &hkData)))
  309. {
  310. for (i = 0; i < 20; i++)
  311. {
  312. wsprintf(szKey, REGSTR_VAL_JOYNCONFIG, i + 1);
  313. dwBufferLen = sizeof JOYREGHWCONFIG;
  314. if (ERROR_SUCCESS == RegQueryValueEx(hkData, szKey, 0, NULL, (LPBYTE)&jhwc, &dwBufferLen))
  315. {
  316. // Skip devices whose type is JOY_HW_NONE.
  317. if (jhwc.dwType == JOY_HW_NONE)
  318. continue;
  319. pInputDeviceInfoNew = new InputDeviceInfo;
  320. if (pInputDeviceInfoNew == NULL)
  321. return E_OUTOFMEMORY;
  322. ZeroMemory(pInputDeviceInfoNew, sizeof(InputDeviceInfo));
  323. if (pInputInfo->m_pInputDeviceInfoFirst == NULL)
  324. {
  325. pInputInfo->m_pInputDeviceInfoFirst = pInputDeviceInfoNew;
  326. }
  327. else
  328. {
  329. for (pInputDeviceInfo = pInputInfo->m_pInputDeviceInfoFirst;
  330. pInputDeviceInfo->m_pInputDeviceInfoNext != NULL;
  331. pInputDeviceInfo = pInputDeviceInfo->m_pInputDeviceInfoNext)
  332. {
  333. }
  334. pInputDeviceInfo->m_pInputDeviceInfoNext = pInputDeviceInfoNew;
  335. }
  336. pInputDeviceInfoNew->m_dwUsageSettings = jhwc.dwUsageSettings;
  337. wsprintf(pInputDeviceInfoNew->m_szSettings, TEXT("0x%08x"), jhwc.dwUsageSettings);
  338. if (JOY_US_PRESENT & jhwc.dwUsageSettings)
  339. {
  340. LoadString(NULL, IDS_JOYSTICKPRESENT, sz, 200);
  341. lstrcat(pInputDeviceInfoNew->m_szSettings, sz);
  342. }
  343. // Try reading an OEM name
  344. wsprintf(szKey, REGSTR_VAL_JOYNOEMNAME, i + 1);
  345. dwBufferLen = sizeof szOEMKey;
  346. szOEMKey[0] = 0;
  347. szOEMName[0] = 0;
  348. if (ERROR_SUCCESS == RegQueryValueEx(hkData, szKey, 0, NULL, (LPBYTE)szOEMKey, &dwBufferLen))
  349. {
  350. hkOEMBase = 0;
  351. hkOEMData = 0;
  352. // If there is an OEM name, look in the PrivateProperties to find out
  353. // the name of the device as shown in the control panel applet.
  354. if((szOEMKey[0] != 0)
  355. && (ERROR_SUCCESS == RegOpenKeyEx(HKEY_LOCAL_MACHINE, REGSTR_PATH_JOYOEM, 0, KEY_READ, &hkOEMBase))
  356. && (ERROR_SUCCESS == RegOpenKeyEx(hkOEMBase, szOEMKey, 0, KEY_READ, &hkOEMData))
  357. && (ERROR_SUCCESS == RegQueryValueEx(hkOEMData, REGSTR_VAL_JOYOEMNAME, 0, NULL, NULL, &dwBufferLen))
  358. && dwBufferLen)
  359. {
  360. dwBufferLen = sizeof szOEMName;
  361. RegQueryValueEx(hkOEMData, REGSTR_VAL_JOYOEMNAME, 0, NULL, (LPBYTE)szOEMName, &dwBufferLen);
  362. }
  363. if (hkOEMData)
  364. RegCloseKey(hkOEMData);
  365. }
  366. if (hkOEMBase)
  367. RegCloseKey(hkOEMBase);
  368. if (szOEMName[0] != 0)
  369. {
  370. _tcsncpy(pInputDeviceInfoNew->m_szDeviceName, szOEMName, 100);
  371. pInputDeviceInfoNew->m_szDeviceName[99] = 0;
  372. }
  373. else
  374. GetJoystickTypeDesc(jhwc.dwType, pInputDeviceInfoNew->m_szDeviceName);
  375. wsprintf(szKey, REGSTR_VAL_JOYNOEMCALLOUT, i + 1);
  376. dwBufferLen = sizeof szOEMCallout;
  377. if (ERROR_SUCCESS == RegQueryValueEx(hkData, szKey, 0, NULL, (LPBYTE)szOEMCallout, &dwBufferLen))
  378. {
  379. _tcsncpy(pInputDeviceInfoNew->m_szDriverName, szOEMCallout, 100);
  380. pInputDeviceInfoNew->m_szDriverName[99] = 0;
  381. GetSystemDirectory(szPath, MAX_PATH);
  382. lstrcat(szPath, TEXT("\\"));
  383. lstrcat(szPath, szOEMCallout);
  384. GetFileVersion(szPath, pInputDeviceInfoNew->m_szDriverVersion,
  385. pInputDeviceInfoNew->m_szDriverAttributes, pInputDeviceInfoNew->m_szDriverLanguageLocal, pInputDeviceInfoNew->m_szDriverLanguage,
  386. &pInputDeviceInfoNew->m_bBeta, &pInputDeviceInfoNew->m_bDebug);
  387. GetFileDateAndSize(szPath, pInputDeviceInfoNew->m_szDriverDateLocal, pInputDeviceInfoNew->m_szDriverDate, &pInputDeviceInfoNew->m_numBytes);
  388. FileIsSigned(szPath, &pInputDeviceInfoNew->m_bDriverSigned, &pInputDeviceInfoNew->m_bDriverSignedValid);
  389. }
  390. else
  391. {
  392. LoadString(NULL, IDS_DEFAULT, pInputDeviceInfoNew->m_szDriverName, 100);
  393. }
  394. }
  395. }
  396. }
  397. }
  398. return S_OK;
  399. }
  400. /****************************************************************************
  401. *
  402. * GetJoystickTypeDesc
  403. *
  404. ****************************************************************************/
  405. VOID GetJoystickTypeDesc(DWORD dwType, TCHAR* pszDesc)
  406. {
  407. LONG ids;
  408. switch(dwType)
  409. {
  410. case JOY_HW_NONE:
  411. ids = IDS_JOY_HW_NONE;
  412. break;
  413. case JOY_HW_CUSTOM:
  414. ids = IDS_JOY_HW_CUSTOM;
  415. break;
  416. case JOY_HW_2A_2B_GENERIC:
  417. ids = IDS_JOY_HW_2A_2B_GENERIC;
  418. break;
  419. case JOY_HW_2A_4B_GENERIC:
  420. ids = IDS_JOY_HW_2A_4B_GENERIC;
  421. break;
  422. case JOY_HW_2B_GAMEPAD:
  423. ids = IDS_JOY_HW_2B_GAMEPAD;
  424. break;
  425. case JOY_HW_2B_FLIGHTYOKE:
  426. ids = IDS_JOY_HW_2B_FLIGHTYOKE;
  427. break;
  428. case JOY_HW_2B_FLIGHTYOKETHROTTLE:
  429. ids = IDS_JOY_HW_2B_FLIGHTYOKETHROTTLE;
  430. break;
  431. case JOY_HW_3A_2B_GENERIC:
  432. ids = IDS_JOY_HW_3A_2B_GENERIC;
  433. break;
  434. case JOY_HW_3A_4B_GENERIC:
  435. ids = IDS_JOY_HW_3A_4B_GENERIC;
  436. break;
  437. case JOY_HW_4B_GAMEPAD:
  438. ids = IDS_JOY_HW_4B_GAMEPAD;
  439. break;
  440. case JOY_HW_4B_FLIGHTYOKE:
  441. ids = IDS_JOY_HW_4B_FLIGHTYOKE;
  442. break;
  443. case JOY_HW_4B_FLIGHTYOKETHROTTLE:
  444. ids = IDS_JOY_HW_4B_FLIGHTYOKETHROTTLE;
  445. break;
  446. default:
  447. ids = IDS_JOY_UNKNOWN;
  448. break;
  449. }
  450. LoadString(NULL, ids, pszDesc, 60);
  451. }
  452. /****************************************************************************
  453. *
  454. * GetInputDriverInfo
  455. *
  456. ****************************************************************************/
  457. HRESULT GetInputDriverInfo(InputInfo* pInputInfo)
  458. {
  459. HKEY hkBase;
  460. HKEY hkDrv;
  461. HKEY hkMedia;
  462. HKEY hkMediaDriver;
  463. DWORD dwIndex = 0;
  464. TCHAR szName[100];
  465. DWORD dwNameSize;
  466. TCHAR szClass[100];
  467. DWORD dwClassSize;
  468. InputDriverInfo* pInputDriverInfoNew;
  469. InputDriverInfo* pInputDriverInfo;
  470. DWORD dwBufferLen;
  471. TCHAR szActive[10];
  472. TCHAR szSubMediaKey[100];
  473. if (ERROR_SUCCESS != RegOpenKeyEx(HKEY_LOCAL_MACHINE, REGSTR_PATH_JOYCONFIG, 0, KEY_READ, &hkBase))
  474. return S_OK; // This key doesn't exist on NT, so exit silently for now.
  475. dwNameSize = 100;
  476. dwClassSize = 100;
  477. while (ERROR_SUCCESS == RegEnumKeyEx(hkBase, dwIndex, szName,
  478. &dwNameSize, NULL, szClass, &dwClassSize, NULL))
  479. {
  480. if (szName[dwNameSize - 1] == '>' &&
  481. szName[dwNameSize - 6] == '<')
  482. {
  483. // It's a driver
  484. pInputDriverInfoNew = new InputDriverInfo;
  485. if (pInputDriverInfoNew == NULL)
  486. return E_OUTOFMEMORY;
  487. ZeroMemory(pInputDriverInfoNew, sizeof(InputDriverInfo));
  488. if (pInputInfo->m_pInputDriverInfoFirst == NULL)
  489. {
  490. pInputInfo->m_pInputDriverInfoFirst = pInputDriverInfoNew;
  491. }
  492. else
  493. {
  494. for (pInputDriverInfo = pInputInfo->m_pInputDriverInfoFirst;
  495. pInputDriverInfo->m_pInputDriverInfoNext != NULL;
  496. pInputDriverInfo = pInputDriverInfo->m_pInputDriverInfoNext)
  497. {
  498. }
  499. pInputDriverInfo->m_pInputDriverInfoNext = pInputDriverInfoNew;
  500. }
  501. lstrcpy(pInputDriverInfoNew->m_szRegKey, szName);
  502. // Read info from reg key
  503. if (ERROR_SUCCESS != RegOpenKeyEx(hkBase, szName, 0, KEY_READ, &hkDrv))
  504. return E_FAIL;
  505. dwBufferLen = 100;
  506. RegQueryValueEx(hkDrv, TEXT("DeviceID"), 0, NULL, (LPBYTE)pInputDriverInfoNew->m_szDeviceID, &dwBufferLen);
  507. dwBufferLen = 10;
  508. RegQueryValueEx(hkDrv, TEXT("Active"), 0, NULL, (LPBYTE)szActive, &dwBufferLen);
  509. if (lstrcmp(szActive, TEXT("1")) == 0)
  510. pInputDriverInfoNew->m_bActive = TRUE;
  511. dwBufferLen = 100;
  512. RegQueryValueEx(hkDrv, TEXT("Driver"), 0, NULL, (LPBYTE)pInputDriverInfoNew->m_szDriver16, &dwBufferLen);
  513. RegCloseKey(hkDrv);
  514. // Open corresponding key under Services\Class\Media and read more info
  515. szSubMediaKey[0] = 0;
  516. if( lstrlen(szName) > (int) (dwNameSize - 5) )
  517. lstrcpy(szSubMediaKey, &szName[dwNameSize - 5]);
  518. szSubMediaKey[4] = '\0';
  519. if (ERROR_SUCCESS == RegOpenKeyEx(HKEY_LOCAL_MACHINE, REGSTR_PATH_CLASS TEXT("\\") REGSTR_KEY_MEDIA_CLASS, 0, KEY_READ, &hkMedia))
  520. {
  521. if (ERROR_SUCCESS == RegOpenKeyEx(hkMedia, szSubMediaKey, 0, KEY_READ, &hkMediaDriver))
  522. {
  523. dwBufferLen = 100;
  524. RegQueryValueEx(hkMediaDriver, TEXT("MatchingDeviceId"), 0, NULL, (LPBYTE)pInputDriverInfoNew->m_szMatchingDeviceID, &dwBufferLen);
  525. dwBufferLen = 100;
  526. RegQueryValueEx(hkMediaDriver, TEXT("Driver"), 0, NULL, (LPBYTE)pInputDriverInfoNew->m_szDriver32, &dwBufferLen);
  527. RegCloseKey(hkMediaDriver);
  528. }
  529. RegCloseKey(hkMedia);
  530. }
  531. }
  532. dwNameSize = 100;
  533. dwClassSize = 100;
  534. dwIndex++;
  535. }
  536. RegCloseKey(hkBase);
  537. return S_OK;
  538. }
  539. /****************************************************************************
  540. *
  541. * CheckRegistry
  542. *
  543. ****************************************************************************/
  544. HRESULT CheckRegistry(InputInfo* pInputInfo, RegError** ppRegErrorFirst)
  545. {
  546. HRESULT hr;
  547. HKEY HKCR = HKEY_CLASSES_ROOT;
  548. TCHAR szVersion[100];
  549. HKEY hkey;
  550. DWORD cbData;
  551. ULONG ulType;
  552. DWORD dwMajor = 0;
  553. DWORD dwMinor = 0;
  554. DWORD dwRevision = 0;
  555. DWORD dwBuild = 0;
  556. if (ERROR_SUCCESS == RegOpenKeyEx(HKEY_LOCAL_MACHINE, TEXT("Software\\Microsoft\\DirectX"),
  557. 0, KEY_READ, &hkey))
  558. {
  559. cbData = 100;
  560. RegQueryValueEx(hkey, TEXT("Version"), 0, &ulType, (LPBYTE)szVersion, &cbData);
  561. RegCloseKey(hkey);
  562. if (lstrlen(szVersion) > 6 &&
  563. lstrlen(szVersion) < 20)
  564. {
  565. if( _stscanf(szVersion, TEXT("%d.%d.%d.%d"), &dwMajor, &dwMinor, &dwRevision, &dwBuild) != 4 )
  566. {
  567. dwMajor = 0;
  568. dwMinor = 0;
  569. dwRevision = 0;
  570. dwBuild = 0;
  571. }
  572. }
  573. }
  574. // No registry checking on DX versions before DX7
  575. if (dwMinor < 7)
  576. return S_OK;
  577. // 34644: check for poll flags
  578. DWORD dwData = 0;
  579. DWORD dwSize = sizeof(dwData);
  580. DWORD dwType;
  581. if (ERROR_SUCCESS == RegOpenKeyEx(HKEY_LOCAL_MACHINE, TEXT("System\\CurrentControlSet\\control\\MediaProperties\\PrivateProperties\\Joystick\\OEM\\Standard Gameport"),
  582. 0, KEY_READ, &hkey))
  583. {
  584. RegQueryValueEx(hkey, TEXT("PollFlags"), NULL, &dwType, (BYTE *)&dwData, &dwSize);
  585. RegCloseKey(hkey);
  586. }
  587. pInputInfo->m_bPollFlags = ( dwData == 0x00000001 );
  588. // From dinput.inf:
  589. if (FAILED(hr = CheckRegString(ppRegErrorFirst, HKCR, TEXT("CLSID\\{25E609E0-B259-11CF-BFC7-444553540000}"), TEXT(""), TEXT("*"))))
  590. return hr;
  591. if (FAILED(hr = CheckRegString(ppRegErrorFirst, HKCR, TEXT("CLSID\\{25E609E0-B259-11CF-BFC7-444553540000}\\InProcServer32"), TEXT(""), TEXT("dinput.dll"), CRF_LEAF)))
  592. return hr;
  593. if (FAILED(hr = CheckRegString(ppRegErrorFirst, HKCR, TEXT("CLSID\\{25E609E0-B259-11CF-BFC7-444553540000}\\InprocServer32"), TEXT("ThreadingModel"), TEXT("Both"))))
  594. return hr;
  595. if (FAILED(hr = CheckRegString(ppRegErrorFirst, HKCR, TEXT("CLSID\\{25E609E1-B259-11CF-BFC7-444553540000}"), TEXT(""), TEXT("*"))))
  596. return hr;
  597. if (FAILED(hr = CheckRegString(ppRegErrorFirst, HKCR, TEXT("CLSID\\{25E609E1-B259-11CF-BFC7-444553540000}\\InProcServer32"), TEXT(""), TEXT("dinput.dll"), CRF_LEAF)))
  598. return hr;
  599. if (FAILED(hr = CheckRegString(ppRegErrorFirst, HKCR, TEXT("CLSID\\{25E609E1-B259-11CF-BFC7-444553540000}\\InprocServer32"), TEXT("ThreadingModel"), TEXT("Both"))))
  600. return hr;
  601. if (!BIsPlatformNT())
  602. {
  603. if (FAILED(hr = CheckRegString(ppRegErrorFirst, HKCR, TEXT("CLSID\\{92187326-72B4-11d0-A1AC-0000F8026977}"), TEXT(""), TEXT("*"))))
  604. return hr;
  605. if (FAILED(hr = CheckRegString(ppRegErrorFirst, HKCR, TEXT("CLSID\\{92187326-72B4-11d0-A1AC-0000F8026977}\\ProgID"), TEXT(""), TEXT("*"))))
  606. return hr;
  607. // Bug 119850: gchand.dll doesn't need to be on any DX7 OS.
  608. // if (FAILED(hr = CheckRegString(ppRegErrorFirst, HKCR, TEXT("CLSID\\{92187326-72B4-11d0-A1AC-0000F8026977}\\InProcHandler32"), TEXT(""), TEXT("gchand.dll"), CRF_LEAF)))
  609. // return hr;
  610. if (FAILED(hr = CheckRegString(ppRegErrorFirst, HKCR, TEXT("CLSID\\{92187326-72B4-11d0-A1AC-0000F8026977}\\InProcServer32"), TEXT(""), TEXT("gcdef.dll"), CRF_LEAF)))
  611. return hr;
  612. if (FAILED(hr = CheckRegString(ppRegErrorFirst, HKCR, TEXT("CLSID\\{92187326-72B4-11d0-A1AC-0000F8026977}\\InprocServer32"), TEXT("ThreadingModel"), TEXT("Apartment"))))
  613. return hr;
  614. }
  615. return S_OK;
  616. }
  617. /****************************************************************************
  618. *
  619. * DestroyInputInfo
  620. *
  621. ****************************************************************************/
  622. VOID DestroyInputInfo(InputInfo* pInputInfo)
  623. {
  624. if( pInputInfo )
  625. {
  626. DestroyReg( &pInputInfo->m_pRegErrorFirst );
  627. InputDeviceInfo* pInputDeviceInfo;
  628. InputDeviceInfo* pInputDeviceInfoNext;
  629. for (pInputDeviceInfo = pInputInfo->m_pInputDeviceInfoFirst; pInputDeviceInfo != NULL;
  630. pInputDeviceInfo = pInputDeviceInfoNext)
  631. {
  632. pInputDeviceInfoNext = pInputDeviceInfo->m_pInputDeviceInfoNext;
  633. delete pInputDeviceInfo;
  634. }
  635. InputDeviceInfoNT* pInputDeviceNTInfo;
  636. InputDeviceInfoNT* pInputDeviceNTInfoNext;
  637. for (pInputDeviceNTInfo = pInputInfo->m_pInputDeviceInfoNTFirst; pInputDeviceNTInfo != NULL;
  638. pInputDeviceNTInfo = pInputDeviceNTInfoNext)
  639. {
  640. pInputDeviceNTInfoNext = pInputDeviceNTInfo->m_pInputDeviceInfoNTNext;
  641. delete pInputDeviceNTInfo;
  642. }
  643. InputDriverInfo* pInputDriverInfo;
  644. InputDriverInfo* pInputDriverInfoNext;
  645. for (pInputDriverInfo = pInputInfo->m_pInputDriverInfoFirst; pInputDriverInfo != NULL;
  646. pInputDriverInfo = pInputDriverInfoNext)
  647. {
  648. pInputDriverInfoNext = pInputDriverInfo->m_pInputDriverInfoNext;
  649. delete pInputDriverInfo;
  650. }
  651. delete pInputInfo;
  652. }
  653. }
  654. /****************************************************************************
  655. *
  656. * DiagnoseInput
  657. *
  658. ****************************************************************************/
  659. VOID DiagnoseInput(SysInfo* pSysInfo, InputInfo* pInputInfo)
  660. {
  661. InputDeviceInfo* pInputDeviceInfo;
  662. InputDeviceInfoNT* pInputDeviceInfoNT;
  663. TCHAR szDebug[200];
  664. TCHAR szBeta[200];
  665. LONG lwNumDebug;
  666. LONG lwNumBeta;
  667. TCHAR szListContinuer[30];
  668. TCHAR szListEtc[30];
  669. TCHAR szFmt[300];
  670. TCHAR szMessage[300];
  671. BOOL bProblem = FALSE;
  672. if( pInputInfo == NULL )
  673. return;
  674. lwNumDebug = 0;
  675. lwNumBeta = 0;
  676. LoadString(NULL, IDS_LISTCONTINUER, szListContinuer, 30);
  677. LoadString(NULL, IDS_LISTETC, szListEtc, 30);
  678. for (pInputDeviceInfo = pInputInfo->m_pInputDeviceInfoFirst; pInputDeviceInfo != NULL;
  679. pInputDeviceInfo = pInputDeviceInfo->m_pInputDeviceInfoNext)
  680. {
  681. if (pInputDeviceInfo->m_bBeta)
  682. {
  683. pInputDeviceInfo->m_bProblem = TRUE;
  684. bProblem = TRUE;
  685. lwNumBeta++;
  686. if (lwNumBeta == 1)
  687. {
  688. lstrcpy(szBeta, pInputDeviceInfo->m_szDriverName);
  689. }
  690. else if (lwNumBeta < 4)
  691. {
  692. lstrcat(szBeta, szListContinuer);
  693. lstrcat(szBeta, pInputDeviceInfo->m_szDriverName);
  694. }
  695. else if (lwNumBeta < 5)
  696. {
  697. lstrcat(szBeta, szListEtc);
  698. }
  699. }
  700. if (pInputDeviceInfo->m_bDebug)
  701. {
  702. pInputDeviceInfo->m_bProblem = TRUE;
  703. bProblem = TRUE;
  704. lwNumDebug++;
  705. if (lwNumDebug == 1)
  706. {
  707. lstrcpy(szDebug, pInputDeviceInfo->m_szDriverName);
  708. }
  709. else if (lwNumDebug < 4)
  710. {
  711. lstrcat(szDebug, szListContinuer);
  712. lstrcat(szDebug, pInputDeviceInfo->m_szDriverName);
  713. }
  714. else if (lwNumDebug < 5)
  715. {
  716. lstrcat(szDebug, szListEtc);
  717. }
  718. }
  719. }
  720. _tcscpy( pSysInfo->m_szInputNotes, TEXT("") );
  721. _tcscpy( pSysInfo->m_szInputNotesEnglish, TEXT("") );
  722. for (pInputDeviceInfoNT = pInputInfo->m_pInputDeviceInfoNTFirst; pInputDeviceInfoNT != NULL;
  723. pInputDeviceInfoNT = pInputDeviceInfoNT->m_pInputDeviceInfoNTNext)
  724. {
  725. if (pInputDeviceInfoNT->m_dwProblem != 0)
  726. {
  727. bProblem = TRUE;
  728. pInputDeviceInfoNT->m_bProblem = TRUE;
  729. LoadString(NULL, IDS_INPUTDEVPROBLEMFMT, szFmt, 300);
  730. wsprintf(szMessage, szFmt, pInputDeviceInfoNT->m_szName, pInputDeviceInfoNT->m_dwProblem);
  731. _tcscat( pSysInfo->m_szInputNotes, szMessage );
  732. LoadString(NULL, IDS_INPUTDEVPROBLEMFMT_ENGLISH, szFmt, 300);
  733. wsprintf(szMessage, szFmt, pInputDeviceInfoNT->m_szName, pInputDeviceInfoNT->m_dwProblem);
  734. _tcscat( pSysInfo->m_szInputNotesEnglish, szMessage );
  735. }
  736. if (pInputDeviceInfoNT->m_dwPortProblem != 0)
  737. {
  738. bProblem = TRUE;
  739. pInputDeviceInfoNT->m_bProblem = TRUE;
  740. LoadString(NULL, IDS_INPUTPORTPROBLEMFMT, szFmt, 300);
  741. wsprintf(szMessage, szFmt, pInputDeviceInfoNT->m_szPortName, pInputDeviceInfoNT->m_dwPortProblem);
  742. _tcscat( pSysInfo->m_szInputNotes, szMessage );
  743. LoadString(NULL, IDS_INPUTPORTPROBLEMFMT_ENGLISH, szFmt, 300);
  744. wsprintf(szMessage, szFmt, pInputDeviceInfoNT->m_szPortName, pInputDeviceInfoNT->m_dwPortProblem);
  745. _tcscat( pSysInfo->m_szInputNotesEnglish, szMessage );
  746. }
  747. }
  748. if (lwNumBeta > 0)
  749. {
  750. if (lwNumBeta == 1)
  751. LoadString(NULL, IDS_BETADRIVERFMT1, szFmt, 300);
  752. else
  753. LoadString(NULL, IDS_BETADRIVERFMT2, szFmt, 300);
  754. wsprintf(szMessage, szFmt, szBeta);
  755. _tcscat( pSysInfo->m_szInputNotes, szMessage );
  756. if (lwNumBeta == 1)
  757. LoadString(NULL, IDS_BETADRIVERFMT1_ENGLISH, szFmt, 300);
  758. else
  759. LoadString(NULL, IDS_BETADRIVERFMT2_ENGLISH, szFmt, 300);
  760. wsprintf(szMessage, szFmt, szBeta);
  761. _tcscat( pSysInfo->m_szInputNotesEnglish, szMessage );
  762. }
  763. if (lwNumDebug > 0)
  764. {
  765. if (lwNumDebug == 1)
  766. LoadString(NULL, IDS_DEBUGDRIVERFMT1, szFmt, 300);
  767. else
  768. LoadString(NULL, IDS_DEBUGDRIVERFMT2, szFmt, 300);
  769. wsprintf(szMessage, szFmt, szDebug);
  770. _tcscat( pSysInfo->m_szInputNotes, szMessage );
  771. if (lwNumDebug == 1)
  772. LoadString(NULL, IDS_DEBUGDRIVERFMT1_ENGLISH, szFmt, 300);
  773. else
  774. LoadString(NULL, IDS_DEBUGDRIVERFMT2_ENGLISH, szFmt, 300);
  775. wsprintf(szMessage, szFmt, szDebug);
  776. _tcscat( pSysInfo->m_szInputNotesEnglish, szMessage );
  777. }
  778. if (pInputInfo->m_pInputDeviceInfoFirst == NULL &&
  779. pInputInfo->m_pInputDeviceInfoNTFirst == NULL)
  780. {
  781. LoadString(NULL, IDS_NOINPUT, szMessage, 300);
  782. _tcscat( pSysInfo->m_szInputNotes, szMessage );
  783. LoadString(NULL, IDS_NOINPUT_ENGLISH, szMessage, 300);
  784. _tcscat( pSysInfo->m_szInputNotesEnglish, szMessage );
  785. }
  786. if (pInputInfo->m_pRegErrorFirst != NULL)
  787. {
  788. bProblem = TRUE;
  789. LoadString(NULL, IDS_REGISTRYPROBLEM, szMessage, 300);
  790. _tcscat( pSysInfo->m_szInputNotes, szMessage );
  791. LoadString(NULL, IDS_REGISTRYPROBLEM_ENGLISH, szMessage, 300);
  792. _tcscat( pSysInfo->m_szInputNotesEnglish, szMessage );
  793. }
  794. if (!bProblem)
  795. {
  796. LoadString(NULL, IDS_NOPROBLEM, szMessage, 300);
  797. _tcscat( pSysInfo->m_szInputNotes, szMessage );
  798. LoadString(NULL, IDS_NOPROBLEM_ENGLISH, szMessage, 300);
  799. _tcscat( pSysInfo->m_szInputNotesEnglish, szMessage );
  800. }
  801. }