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.

890 lines
36 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. lstrcpy(pInputDeviceInfoNew->m_szDeviceName, szOEMName);
  370. else
  371. GetJoystickTypeDesc(jhwc.dwType, pInputDeviceInfoNew->m_szDeviceName);
  372. wsprintf(szKey, REGSTR_VAL_JOYNOEMCALLOUT, i + 1);
  373. dwBufferLen = sizeof szOEMCallout;
  374. if (ERROR_SUCCESS == RegQueryValueEx(hkData, szKey, 0, NULL, (LPBYTE)&szOEMCallout, &dwBufferLen))
  375. {
  376. lstrcpy(pInputDeviceInfoNew->m_szDriverName, szOEMCallout);
  377. GetSystemDirectory(szPath, MAX_PATH);
  378. lstrcat(szPath, TEXT("\\"));
  379. lstrcat(szPath, szOEMCallout);
  380. GetFileVersion(szPath, pInputDeviceInfoNew->m_szDriverVersion,
  381. pInputDeviceInfoNew->m_szDriverAttributes, pInputDeviceInfoNew->m_szDriverLanguageLocal, pInputDeviceInfoNew->m_szDriverLanguage,
  382. &pInputDeviceInfoNew->m_bBeta, &pInputDeviceInfoNew->m_bDebug);
  383. GetFileDateAndSize(szPath, pInputDeviceInfoNew->m_szDriverDateLocal, pInputDeviceInfoNew->m_szDriverDate, &pInputDeviceInfoNew->m_numBytes);
  384. FileIsSigned(szPath, &pInputDeviceInfoNew->m_bDriverSigned, &pInputDeviceInfoNew->m_bDriverSignedValid);
  385. }
  386. else
  387. {
  388. LoadString(NULL, IDS_DEFAULT, pInputDeviceInfoNew->m_szDriverName, 100);
  389. }
  390. }
  391. }
  392. }
  393. }
  394. return S_OK;
  395. }
  396. /****************************************************************************
  397. *
  398. * GetJoystickTypeDesc
  399. *
  400. ****************************************************************************/
  401. VOID GetJoystickTypeDesc(DWORD dwType, TCHAR* pszDesc)
  402. {
  403. LONG ids;
  404. switch(dwType)
  405. {
  406. case JOY_HW_NONE:
  407. ids = IDS_JOY_HW_NONE;
  408. break;
  409. case JOY_HW_CUSTOM:
  410. ids = IDS_JOY_HW_CUSTOM;
  411. break;
  412. case JOY_HW_2A_2B_GENERIC:
  413. ids = IDS_JOY_HW_2A_2B_GENERIC;
  414. break;
  415. case JOY_HW_2A_4B_GENERIC:
  416. ids = IDS_JOY_HW_2A_4B_GENERIC;
  417. break;
  418. case JOY_HW_2B_GAMEPAD:
  419. ids = IDS_JOY_HW_2B_GAMEPAD;
  420. break;
  421. case JOY_HW_2B_FLIGHTYOKE:
  422. ids = IDS_JOY_HW_2B_FLIGHTYOKE;
  423. break;
  424. case JOY_HW_2B_FLIGHTYOKETHROTTLE:
  425. ids = IDS_JOY_HW_2B_FLIGHTYOKETHROTTLE;
  426. break;
  427. case JOY_HW_3A_2B_GENERIC:
  428. ids = IDS_JOY_HW_3A_2B_GENERIC;
  429. break;
  430. case JOY_HW_3A_4B_GENERIC:
  431. ids = IDS_JOY_HW_3A_4B_GENERIC;
  432. break;
  433. case JOY_HW_4B_GAMEPAD:
  434. ids = IDS_JOY_HW_4B_GAMEPAD;
  435. break;
  436. case JOY_HW_4B_FLIGHTYOKE:
  437. ids = IDS_JOY_HW_4B_FLIGHTYOKE;
  438. break;
  439. case JOY_HW_4B_FLIGHTYOKETHROTTLE:
  440. ids = IDS_JOY_HW_4B_FLIGHTYOKETHROTTLE;
  441. break;
  442. default:
  443. ids = IDS_JOY_UNKNOWN;
  444. break;
  445. }
  446. LoadString(NULL, ids, pszDesc, 60);
  447. }
  448. /****************************************************************************
  449. *
  450. * GetInputDriverInfo
  451. *
  452. ****************************************************************************/
  453. HRESULT GetInputDriverInfo(InputInfo* pInputInfo)
  454. {
  455. HKEY hkBase;
  456. HKEY hkDrv;
  457. HKEY hkMedia;
  458. HKEY hkMediaDriver;
  459. DWORD dwIndex = 0;
  460. TCHAR szName[100];
  461. DWORD dwNameSize;
  462. TCHAR szClass[100];
  463. DWORD dwClassSize;
  464. InputDriverInfo* pInputDriverInfoNew;
  465. InputDriverInfo* pInputDriverInfo;
  466. DWORD dwBufferLen;
  467. TCHAR szActive[10];
  468. TCHAR szSubMediaKey[10];
  469. if (ERROR_SUCCESS != RegOpenKeyEx(HKEY_LOCAL_MACHINE, REGSTR_PATH_JOYCONFIG, 0, KEY_READ, &hkBase))
  470. return S_OK; // This key doesn't exist on NT, so exit silently for now.
  471. dwNameSize = 100;
  472. dwClassSize = 100;
  473. while (ERROR_SUCCESS == RegEnumKeyEx(hkBase, dwIndex, szName,
  474. &dwNameSize, NULL, szClass, &dwClassSize, NULL))
  475. {
  476. if (szName[dwNameSize - 1] == '>' &&
  477. szName[dwNameSize - 6] == '<')
  478. {
  479. // It's a driver
  480. pInputDriverInfoNew = new InputDriverInfo;
  481. if (pInputDriverInfoNew == NULL)
  482. return E_OUTOFMEMORY;
  483. ZeroMemory(pInputDriverInfoNew, sizeof(InputDriverInfo));
  484. if (pInputInfo->m_pInputDriverInfoFirst == NULL)
  485. {
  486. pInputInfo->m_pInputDriverInfoFirst = pInputDriverInfoNew;
  487. }
  488. else
  489. {
  490. for (pInputDriverInfo = pInputInfo->m_pInputDriverInfoFirst;
  491. pInputDriverInfo->m_pInputDriverInfoNext != NULL;
  492. pInputDriverInfo = pInputDriverInfo->m_pInputDriverInfoNext)
  493. {
  494. }
  495. pInputDriverInfo->m_pInputDriverInfoNext = pInputDriverInfoNew;
  496. }
  497. lstrcpy(pInputDriverInfoNew->m_szRegKey, szName);
  498. // Read info from reg key
  499. if (ERROR_SUCCESS != RegOpenKeyEx(hkBase, szName, 0, KEY_READ, &hkDrv))
  500. return E_FAIL;
  501. dwBufferLen = 100;
  502. RegQueryValueEx(hkDrv, TEXT("DeviceID"), 0, NULL, (LPBYTE)pInputDriverInfoNew->m_szDeviceID, &dwBufferLen);
  503. dwBufferLen = 10;
  504. RegQueryValueEx(hkDrv, TEXT("Active"), 0, NULL, (LPBYTE)szActive, &dwBufferLen);
  505. if (lstrcmp(szActive, TEXT("1")) == 0)
  506. pInputDriverInfoNew->m_bActive = TRUE;
  507. dwBufferLen = 100;
  508. RegQueryValueEx(hkDrv, TEXT("Driver"), 0, NULL, (LPBYTE)pInputDriverInfoNew->m_szDriver16, &dwBufferLen);
  509. RegCloseKey(hkDrv);
  510. // Open corresponding key under Services\Class\Media and read more info
  511. lstrcpy(szSubMediaKey, &szName[dwNameSize - 5]);
  512. szSubMediaKey[4] = '\0';
  513. if (ERROR_SUCCESS == RegOpenKeyEx(HKEY_LOCAL_MACHINE, REGSTR_PATH_CLASS TEXT("\\") REGSTR_KEY_MEDIA_CLASS, 0, KEY_READ, &hkMedia))
  514. {
  515. if (ERROR_SUCCESS == RegOpenKeyEx(hkMedia, szSubMediaKey, 0, KEY_READ, &hkMediaDriver))
  516. {
  517. dwBufferLen = 100;
  518. RegQueryValueEx(hkMediaDriver, TEXT("MatchingDeviceId"), 0, NULL, (LPBYTE)pInputDriverInfoNew->m_szMatchingDeviceID, &dwBufferLen);
  519. dwBufferLen = 100;
  520. RegQueryValueEx(hkMediaDriver, TEXT("Driver"), 0, NULL, (LPBYTE)pInputDriverInfoNew->m_szDriver32, &dwBufferLen);
  521. RegCloseKey(hkMediaDriver);
  522. }
  523. RegCloseKey(hkMedia);
  524. }
  525. }
  526. dwNameSize = 100;
  527. dwClassSize = 100;
  528. dwIndex++;
  529. }
  530. RegCloseKey(hkBase);
  531. return S_OK;
  532. }
  533. /****************************************************************************
  534. *
  535. * CheckRegistry
  536. *
  537. ****************************************************************************/
  538. HRESULT CheckRegistry(InputInfo* pInputInfo, RegError** ppRegErrorFirst)
  539. {
  540. HRESULT hr;
  541. HKEY HKCR = HKEY_CLASSES_ROOT;
  542. TCHAR szVersion[100];
  543. HKEY hkey;
  544. DWORD cbData;
  545. ULONG ulType;
  546. DWORD dwMajor = 0;
  547. DWORD dwMinor = 0;
  548. DWORD dwRevision = 0;
  549. DWORD dwBuild = 0;
  550. if (ERROR_SUCCESS == RegOpenKeyEx(HKEY_LOCAL_MACHINE, TEXT("Software\\Microsoft\\DirectX"),
  551. 0, KEY_READ, &hkey))
  552. {
  553. cbData = 100;
  554. RegQueryValueEx(hkey, TEXT("Version"), 0, &ulType, (LPBYTE)szVersion, &cbData);
  555. RegCloseKey(hkey);
  556. if (lstrlen(szVersion) > 6 &&
  557. lstrlen(szVersion) < 20)
  558. {
  559. _stscanf(szVersion, TEXT("%d.%d.%d.%d"), &dwMajor, &dwMinor, &dwRevision, &dwBuild);
  560. }
  561. }
  562. // No registry checking on DX versions before DX7
  563. if (dwMinor < 7)
  564. return S_OK;
  565. // 34644: check for poll flags
  566. DWORD dwData = 0;
  567. DWORD dwSize = sizeof(dwData);
  568. DWORD dwType;
  569. if (ERROR_SUCCESS == RegOpenKeyEx(HKEY_LOCAL_MACHINE, TEXT("System\\CurrentControlSet\\control\\MediaProperties\\PrivateProperties\\Joystick\\OEM\\Standard Gameport"),
  570. 0, KEY_READ, &hkey))
  571. {
  572. RegQueryValueEx(hkey, TEXT("PollFlags"), NULL, &dwType, (BYTE *)&dwData, &dwSize);
  573. RegCloseKey(hkey);
  574. }
  575. pInputInfo->m_bPollFlags = ( dwData == 0x00000001 );
  576. // From dinput.inf:
  577. if (FAILED(hr = CheckRegString(ppRegErrorFirst, HKCR, TEXT("CLSID\\{25E609E0-B259-11CF-BFC7-444553540000}"), TEXT(""), TEXT("*"))))
  578. return hr;
  579. if (FAILED(hr = CheckRegString(ppRegErrorFirst, HKCR, TEXT("CLSID\\{25E609E0-B259-11CF-BFC7-444553540000}\\InProcServer32"), TEXT(""), TEXT("dinput.dll"), CRF_LEAF)))
  580. return hr;
  581. if (FAILED(hr = CheckRegString(ppRegErrorFirst, HKCR, TEXT("CLSID\\{25E609E0-B259-11CF-BFC7-444553540000}\\InprocServer32"), TEXT("ThreadingModel"), TEXT("Both"))))
  582. return hr;
  583. if (FAILED(hr = CheckRegString(ppRegErrorFirst, HKCR, TEXT("CLSID\\{25E609E1-B259-11CF-BFC7-444553540000}"), TEXT(""), TEXT("*"))))
  584. return hr;
  585. if (FAILED(hr = CheckRegString(ppRegErrorFirst, HKCR, TEXT("CLSID\\{25E609E1-B259-11CF-BFC7-444553540000}\\InProcServer32"), TEXT(""), TEXT("dinput.dll"), CRF_LEAF)))
  586. return hr;
  587. if (FAILED(hr = CheckRegString(ppRegErrorFirst, HKCR, TEXT("CLSID\\{25E609E1-B259-11CF-BFC7-444553540000}\\InprocServer32"), TEXT("ThreadingModel"), TEXT("Both"))))
  588. return hr;
  589. if (!BIsPlatformNT())
  590. {
  591. if (FAILED(hr = CheckRegString(ppRegErrorFirst, HKCR, TEXT("CLSID\\{92187326-72B4-11d0-A1AC-0000F8026977}"), TEXT(""), TEXT("*"))))
  592. return hr;
  593. if (FAILED(hr = CheckRegString(ppRegErrorFirst, HKCR, TEXT("CLSID\\{92187326-72B4-11d0-A1AC-0000F8026977}\\ProgID"), TEXT(""), TEXT("*"))))
  594. return hr;
  595. // Bug 119850: gchand.dll doesn't need to be on any DX7 OS.
  596. // if (FAILED(hr = CheckRegString(ppRegErrorFirst, HKCR, TEXT("CLSID\\{92187326-72B4-11d0-A1AC-0000F8026977}\\InProcHandler32"), TEXT(""), TEXT("gchand.dll"), CRF_LEAF)))
  597. // return hr;
  598. if (FAILED(hr = CheckRegString(ppRegErrorFirst, HKCR, TEXT("CLSID\\{92187326-72B4-11d0-A1AC-0000F8026977}\\InProcServer32"), TEXT(""), TEXT("gcdef.dll"), CRF_LEAF)))
  599. return hr;
  600. if (FAILED(hr = CheckRegString(ppRegErrorFirst, HKCR, TEXT("CLSID\\{92187326-72B4-11d0-A1AC-0000F8026977}\\InprocServer32"), TEXT("ThreadingModel"), TEXT("Apartment"))))
  601. return hr;
  602. }
  603. return S_OK;
  604. }
  605. /****************************************************************************
  606. *
  607. * DestroyInputInfo
  608. *
  609. ****************************************************************************/
  610. VOID DestroyInputInfo(InputInfo* pInputInfo)
  611. {
  612. if( pInputInfo )
  613. {
  614. DestroyReg( &pInputInfo->m_pRegErrorFirst );
  615. InputDeviceInfo* pInputDeviceInfo;
  616. InputDeviceInfo* pInputDeviceInfoNext;
  617. for (pInputDeviceInfo = pInputInfo->m_pInputDeviceInfoFirst; pInputDeviceInfo != NULL;
  618. pInputDeviceInfo = pInputDeviceInfoNext)
  619. {
  620. pInputDeviceInfoNext = pInputDeviceInfo->m_pInputDeviceInfoNext;
  621. delete pInputDeviceInfo;
  622. }
  623. InputDeviceInfoNT* pInputDeviceNTInfo;
  624. InputDeviceInfoNT* pInputDeviceNTInfoNext;
  625. for (pInputDeviceNTInfo = pInputInfo->m_pInputDeviceInfoNTFirst; pInputDeviceNTInfo != NULL;
  626. pInputDeviceNTInfo = pInputDeviceNTInfoNext)
  627. {
  628. pInputDeviceNTInfoNext = pInputDeviceNTInfo->m_pInputDeviceInfoNTNext;
  629. delete pInputDeviceNTInfo;
  630. }
  631. InputDriverInfo* pInputDriverInfo;
  632. InputDriverInfo* pInputDriverInfoNext;
  633. for (pInputDriverInfo = pInputInfo->m_pInputDriverInfoFirst; pInputDriverInfo != NULL;
  634. pInputDriverInfo = pInputDriverInfoNext)
  635. {
  636. pInputDriverInfoNext = pInputDriverInfo->m_pInputDriverInfoNext;
  637. delete pInputDriverInfo;
  638. }
  639. delete pInputInfo;
  640. }
  641. }
  642. /****************************************************************************
  643. *
  644. * DiagnoseInput
  645. *
  646. ****************************************************************************/
  647. VOID DiagnoseInput(SysInfo* pSysInfo, InputInfo* pInputInfo)
  648. {
  649. InputDeviceInfo* pInputDeviceInfo;
  650. InputDeviceInfoNT* pInputDeviceInfoNT;
  651. TCHAR szDebug[200];
  652. TCHAR szBeta[200];
  653. LONG lwNumDebug;
  654. LONG lwNumBeta;
  655. TCHAR szListContinuer[30];
  656. TCHAR szListEtc[30];
  657. TCHAR szFmt[300];
  658. TCHAR szMessage[300];
  659. BOOL bProblem = FALSE;
  660. if( pInputInfo == NULL )
  661. return;
  662. lwNumDebug = 0;
  663. lwNumBeta = 0;
  664. LoadString(NULL, IDS_LISTCONTINUER, szListContinuer, 30);
  665. LoadString(NULL, IDS_LISTETC, szListEtc, 30);
  666. for (pInputDeviceInfo = pInputInfo->m_pInputDeviceInfoFirst; pInputDeviceInfo != NULL;
  667. pInputDeviceInfo = pInputDeviceInfo->m_pInputDeviceInfoNext)
  668. {
  669. if (pInputDeviceInfo->m_bBeta)
  670. {
  671. pInputDeviceInfo->m_bProblem = TRUE;
  672. bProblem = TRUE;
  673. lwNumBeta++;
  674. if (lwNumBeta == 1)
  675. {
  676. lstrcpy(szBeta, pInputDeviceInfo->m_szDriverName);
  677. }
  678. else if (lwNumBeta < 4)
  679. {
  680. lstrcat(szBeta, szListContinuer);
  681. lstrcat(szBeta, pInputDeviceInfo->m_szDriverName);
  682. }
  683. else if (lwNumBeta < 5)
  684. {
  685. lstrcat(szBeta, szListEtc);
  686. }
  687. }
  688. if (pInputDeviceInfo->m_bDebug)
  689. {
  690. pInputDeviceInfo->m_bProblem = TRUE;
  691. bProblem = TRUE;
  692. lwNumDebug++;
  693. if (lwNumDebug == 1)
  694. {
  695. lstrcpy(szDebug, pInputDeviceInfo->m_szDriverName);
  696. }
  697. else if (lwNumDebug < 4)
  698. {
  699. lstrcat(szDebug, szListContinuer);
  700. lstrcat(szDebug, pInputDeviceInfo->m_szDriverName);
  701. }
  702. else if (lwNumDebug < 5)
  703. {
  704. lstrcat(szDebug, szListEtc);
  705. }
  706. }
  707. }
  708. _tcscpy( pSysInfo->m_szInputNotes, TEXT("") );
  709. _tcscpy( pSysInfo->m_szInputNotesEnglish, TEXT("") );
  710. for (pInputDeviceInfoNT = pInputInfo->m_pInputDeviceInfoNTFirst; pInputDeviceInfoNT != NULL;
  711. pInputDeviceInfoNT = pInputDeviceInfoNT->m_pInputDeviceInfoNTNext)
  712. {
  713. if (pInputDeviceInfoNT->m_dwProblem != 0)
  714. {
  715. bProblem = TRUE;
  716. pInputDeviceInfoNT->m_bProblem = TRUE;
  717. LoadString(NULL, IDS_INPUTDEVPROBLEMFMT, szFmt, 300);
  718. wsprintf(szMessage, szFmt, pInputDeviceInfoNT->m_szName, pInputDeviceInfoNT->m_dwProblem);
  719. _tcscat( pSysInfo->m_szInputNotes, szMessage );
  720. LoadString(NULL, IDS_INPUTDEVPROBLEMFMT_ENGLISH, szFmt, 300);
  721. wsprintf(szMessage, szFmt, pInputDeviceInfoNT->m_szName, pInputDeviceInfoNT->m_dwProblem);
  722. _tcscat( pSysInfo->m_szInputNotesEnglish, szMessage );
  723. }
  724. if (pInputDeviceInfoNT->m_dwPortProblem != 0)
  725. {
  726. bProblem = TRUE;
  727. pInputDeviceInfoNT->m_bProblem = TRUE;
  728. LoadString(NULL, IDS_INPUTPORTPROBLEMFMT, szFmt, 300);
  729. wsprintf(szMessage, szFmt, pInputDeviceInfoNT->m_szPortName, pInputDeviceInfoNT->m_dwPortProblem);
  730. _tcscat( pSysInfo->m_szInputNotes, szMessage );
  731. LoadString(NULL, IDS_INPUTPORTPROBLEMFMT_ENGLISH, szFmt, 300);
  732. wsprintf(szMessage, szFmt, pInputDeviceInfoNT->m_szPortName, pInputDeviceInfoNT->m_dwPortProblem);
  733. _tcscat( pSysInfo->m_szInputNotesEnglish, szMessage );
  734. }
  735. }
  736. if (lwNumBeta > 0)
  737. {
  738. if (lwNumBeta == 1)
  739. LoadString(NULL, IDS_BETADRIVERFMT1, szFmt, 300);
  740. else
  741. LoadString(NULL, IDS_BETADRIVERFMT2, szFmt, 300);
  742. wsprintf(szMessage, szFmt, szBeta);
  743. _tcscat( pSysInfo->m_szInputNotes, szMessage );
  744. if (lwNumBeta == 1)
  745. LoadString(NULL, IDS_BETADRIVERFMT1_ENGLISH, szFmt, 300);
  746. else
  747. LoadString(NULL, IDS_BETADRIVERFMT2_ENGLISH, szFmt, 300);
  748. wsprintf(szMessage, szFmt, szBeta);
  749. _tcscat( pSysInfo->m_szInputNotesEnglish, szMessage );
  750. }
  751. if (lwNumDebug > 0)
  752. {
  753. if (lwNumDebug == 1)
  754. LoadString(NULL, IDS_DEBUGDRIVERFMT1, szFmt, 300);
  755. else
  756. LoadString(NULL, IDS_DEBUGDRIVERFMT2, szFmt, 300);
  757. wsprintf(szMessage, szFmt, szDebug);
  758. _tcscat( pSysInfo->m_szInputNotes, szMessage );
  759. if (lwNumDebug == 1)
  760. LoadString(NULL, IDS_DEBUGDRIVERFMT1_ENGLISH, szFmt, 300);
  761. else
  762. LoadString(NULL, IDS_DEBUGDRIVERFMT2_ENGLISH, szFmt, 300);
  763. wsprintf(szMessage, szFmt, szDebug);
  764. _tcscat( pSysInfo->m_szInputNotesEnglish, szMessage );
  765. }
  766. if (pInputInfo->m_pInputDeviceInfoFirst == NULL &&
  767. pInputInfo->m_pInputDeviceInfoNTFirst == NULL)
  768. {
  769. LoadString(NULL, IDS_NOINPUT, szMessage, 300);
  770. _tcscat( pSysInfo->m_szInputNotes, szMessage );
  771. LoadString(NULL, IDS_NOINPUT_ENGLISH, szMessage, 300);
  772. _tcscat( pSysInfo->m_szInputNotesEnglish, szMessage );
  773. }
  774. if (pInputInfo->m_pRegErrorFirst != NULL)
  775. {
  776. bProblem = TRUE;
  777. LoadString(NULL, IDS_REGISTRYPROBLEM, szMessage, 300);
  778. _tcscat( pSysInfo->m_szInputNotes, szMessage );
  779. LoadString(NULL, IDS_REGISTRYPROBLEM_ENGLISH, szMessage, 300);
  780. _tcscat( pSysInfo->m_szInputNotesEnglish, szMessage );
  781. }
  782. if (!bProblem)
  783. {
  784. LoadString(NULL, IDS_NOPROBLEM, szMessage, 300);
  785. _tcscat( pSysInfo->m_szInputNotes, szMessage );
  786. LoadString(NULL, IDS_NOPROBLEM_ENGLISH, szMessage, 300);
  787. _tcscat( pSysInfo->m_szInputNotesEnglish, szMessage );
  788. }
  789. }