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.

538 lines
15 KiB

  1. /*****************************************************************************
  2. *
  3. * DIApHack.c
  4. *
  5. * Copyright (c) 1999 Microsoft Corporation. All Rights Reserved.
  6. *
  7. * Abstract:
  8. *
  9. * Support routines for app hacks
  10. *
  11. * Contents:
  12. *
  13. *****************************************************************************/
  14. #include "dinputpr.h"
  15. /*****************************************************************************
  16. *
  17. * The sqiffle for this file.
  18. *
  19. *****************************************************************************/
  20. //ISSUE-2001/03/29-timgill Need to sort out a prefixed version of of SquirtSqflPtszV
  21. TCHAR c_tszPrefix[]=TEXT("DINPUT: ");
  22. #define sqfl sqflCompat
  23. typedef enum
  24. {
  25. DICOMPATID_REACQUIRE, // Perform auto reaquire if device lost
  26. DICOMPATID_NOSUBCLASS, // Do not use subclassing
  27. DICOMPATID_MAXDEVICENAMELENGTH, // Truncate device names
  28. DICOMPATID_NATIVEAXISONLY, // Always report axis data in native mode
  29. DICOMPATID_NOPOLLUNACQUIRE, // Don't unaquire the device if a poll fails
  30. DICOMPATID_SUCCEEDACQUIRE // Always return a success code for calls to Acquire()
  31. } DIAPPHACKID, *LPDIAPPHACKID;
  32. typedef struct tagAPPHACKENTRY
  33. {
  34. LPCTSTR pszName;
  35. DWORD cbData;
  36. DWORD dwOSMask;
  37. } APPHACKENTRY, *LPAPPHACKENTRY;
  38. typedef struct tagAPPHACKTABLE
  39. {
  40. LPAPPHACKENTRY aEntries;
  41. ULONG cEntries;
  42. } APPHACKTABLE, *LPAPPHACKTABLE;
  43. #define BEGIN_DECLARE_APPHACK_ENTRIES(name) \
  44. APPHACKENTRY name[] = {
  45. #define DECLARE_APPHACK_ENTRY(name, type, osmask) \
  46. { TEXT(#name), sizeof(type), osmask },
  47. #define END_DECLARE_APPHACK_ENTRIES() \
  48. };
  49. #define BEGIN_DECLARE_APPHACK_TABLE(name) \
  50. APPHACKTABLE name =
  51. #define DECLARE_APPHACK_TABLE(entries) \
  52. { entries, cA(entries) }
  53. #define END_DECLARE_APPHACK_TABLE() \
  54. ;
  55. #define DIHACKOS_WIN2K (0x00000001L)
  56. #define DIHACKOS_WIN9X (0x00000002L)
  57. BEGIN_DECLARE_APPHACK_ENTRIES(g_aheAppHackEntries)
  58. DECLARE_APPHACK_ENTRY(ReAcquire, BOOL, DIHACKOS_WIN2K )
  59. DECLARE_APPHACK_ENTRY(NoSubClass, BOOL, DIHACKOS_WIN2K )
  60. DECLARE_APPHACK_ENTRY(MaxDeviceNameLength, DWORD, DIHACKOS_WIN2K | DIHACKOS_WIN9X )
  61. DECLARE_APPHACK_ENTRY(NativeAxisOnly, BOOL, DIHACKOS_WIN2K | DIHACKOS_WIN9X )
  62. DECLARE_APPHACK_ENTRY(NoPollUnacquire, BOOL, DIHACKOS_WIN2K | DIHACKOS_WIN9X )
  63. DECLARE_APPHACK_ENTRY(SucceedAcquire, BOOL, DIHACKOS_WIN2K )
  64. END_DECLARE_APPHACK_ENTRIES()
  65. BEGIN_DECLARE_APPHACK_TABLE(g_ahtAppHackTable)
  66. DECLARE_APPHACK_TABLE(g_aheAppHackEntries)
  67. END_DECLARE_APPHACK_TABLE()
  68. /***************************************************************************
  69. *
  70. * AhGetOSMask
  71. *
  72. * Description:
  73. * Gets the mask for the current OS
  74. * This mask should be used when we get app hacks for more than just
  75. * Win2k such that hacks can be applied selectively per OS.
  76. * For now just #define a value as constant.
  77. *
  78. * Arguments:
  79. * none
  80. *
  81. * Returns:
  82. * DWORD: Mask of flags applicable for the current OS.
  83. *
  84. ***************************************************************************/
  85. #ifdef WINNT
  86. #define AhGetOSMask() DIHACKOS_WIN2K
  87. #else
  88. #define AhGetOSMask() DIHACKOS_WIN9X
  89. #endif
  90. /***************************************************************************
  91. *
  92. * AhGetCurrentApplicationPath
  93. *
  94. * Description:
  95. * Gets the full path to the current application's executable.
  96. *
  97. * Arguments:
  98. * LPTSTR [out]: receives application id. This buffer is assumed to be
  99. * at least MAX_PATH characters in size.
  100. * LPTSTR * [out]: receives pointer to executable part of the path.
  101. *
  102. * Returns:
  103. * BOOL: TRUE on success.
  104. *
  105. ***************************************************************************/
  106. BOOL AhGetCurrentApplicationPath
  107. (
  108. LPTSTR pszPath,
  109. LPTSTR * ppszModule
  110. )
  111. {
  112. BOOL fSuccess = TRUE;
  113. TCHAR szOriginal[MAX_PATH];
  114. EnterProcI(AhGetCurrentApplicationPath, (_ ""));
  115. fSuccess = GetModuleFileName(GetModuleHandle(NULL), szOriginal, cA(szOriginal));
  116. if(fSuccess)
  117. {
  118. fSuccess = ( GetFullPathName(szOriginal, MAX_PATH, pszPath, ppszModule) != 0 );
  119. }
  120. ExitProcF(fSuccess);
  121. return fSuccess;
  122. }
  123. /***************************************************************************
  124. *
  125. * AhGetApplicationId
  126. *
  127. * Description:
  128. * Gets the id used to identify the current application.
  129. *
  130. * Arguments:
  131. * LPTSTR [out]: receives application id.
  132. *
  133. * Arguments:
  134. * LPTSTR [out optional]: receives application name.
  135. *
  136. * Returns:
  137. * BOOL: TRUE on success.
  138. *
  139. ***************************************************************************/
  140. BOOL AhGetApplicationId
  141. (
  142. LPTSTR pszAppId,
  143. LPTSTR pszAppName
  144. )
  145. {
  146. HANDLE hFile = NULL;
  147. TCHAR szExecutable[MAX_PATH];
  148. LPTSTR pszModule;
  149. IMAGE_NT_HEADERS nth;
  150. IMAGE_DOS_HEADER dh;
  151. DWORD cbRead;
  152. DWORD dwFileSize;
  153. BOOL fSuccess;
  154. EnterProcI(AhGetApplicationId, (_ ""));
  155. AssertF( pszAppId );
  156. // Get the application path
  157. fSuccess = AhGetCurrentApplicationPath(szExecutable, &pszModule);
  158. if(fSuccess)
  159. {
  160. SquirtSqflPtszV(sqfl | sqflVerbose, TEXT("%sApplication executable path: %s"), c_tszPrefix, szExecutable);
  161. SquirtSqflPtszV(sqfl | sqflVerbose, TEXT("%sApplication module: %s"), c_tszPrefix, pszModule);
  162. }
  163. // Open the executable
  164. if(fSuccess)
  165. {
  166. hFile = CreateFile(szExecutable, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, NULL);
  167. if(!(( hFile ) && ( hFile != INVALID_HANDLE_VALUE )))
  168. {
  169. SquirtSqflPtszV(sqfl | sqflError, TEXT("%sCreateFile failed to open %s with error %lu"), c_tszPrefix,
  170. szExecutable, GetLastError());
  171. fSuccess = FALSE;
  172. }
  173. }
  174. // Read the executable's DOS header
  175. if(fSuccess)
  176. {
  177. fSuccess = ReadFile(hFile, &dh, sizeof(dh), &cbRead, NULL);
  178. if(!fSuccess || sizeof(dh) != cbRead)
  179. {
  180. SquirtSqflPtszV(sqfl | sqflError, TEXT("%sUnable to read DOS header"), c_tszPrefix);
  181. fSuccess = FALSE;
  182. }
  183. }
  184. if(fSuccess && IMAGE_DOS_SIGNATURE != dh.e_magic)
  185. {
  186. SquirtSqflPtszV(sqfl | sqflError, TEXT("%sInvalid DOS signature"), c_tszPrefix);
  187. fSuccess = FALSE;
  188. }
  189. // Read the executable's PE header
  190. if(fSuccess)
  191. {
  192. cbRead = SetFilePointer(hFile, dh.e_lfanew, NULL, FILE_BEGIN);
  193. if((LONG)cbRead != dh.e_lfanew)
  194. {
  195. SquirtSqflPtszV(sqfl | sqflError, TEXT("%sUnable to seek to PE header"), c_tszPrefix);
  196. fSuccess = FALSE;
  197. }
  198. }
  199. if(fSuccess)
  200. {
  201. fSuccess = ReadFile(hFile, &nth, sizeof(nth), &cbRead, NULL);
  202. if(!fSuccess || sizeof(nth) != cbRead)
  203. {
  204. SquirtSqflPtszV(sqfl | sqflError, TEXT("%sUnable to read PE header"), c_tszPrefix);
  205. fSuccess = FALSE;
  206. }
  207. }
  208. if(fSuccess && IMAGE_NT_SIGNATURE != nth.Signature)
  209. {
  210. SquirtSqflPtszV(sqfl | sqflError, TEXT("%sInvalid PE signature"), c_tszPrefix);
  211. fSuccess = FALSE;
  212. }
  213. // Get the executable's size
  214. if(fSuccess)
  215. {
  216. // Assuming < 4 GB
  217. dwFileSize = GetFileSize(hFile, NULL);
  218. if((DWORD)(-1) == dwFileSize)
  219. {
  220. SquirtSqflPtszV(sqfl | sqflError, TEXT("%sUnable to get file size"), c_tszPrefix);
  221. fSuccess = FALSE;
  222. }
  223. }
  224. // Create the application id
  225. if(fSuccess)
  226. {
  227. CharUpper(pszModule);
  228. wsprintf(pszAppId, TEXT("%s%8.8lX%8.8lX"), pszModule, nth.FileHeader.TimeDateStamp, dwFileSize);
  229. if( pszAppName )
  230. {
  231. lstrcpy(pszAppName, pszModule);
  232. }
  233. SquirtSqflPtszV(sqfl | sqflTrace, TEXT("%sApplication id: %s"), c_tszPrefix, pszAppId);
  234. }
  235. // Clean up
  236. if( hFile != NULL )
  237. {
  238. CloseHandle( hFile );
  239. }
  240. ExitProcF(fSuccess);
  241. return fSuccess;
  242. }
  243. /***************************************************************************
  244. *
  245. * AhOpenApplicationKey
  246. *
  247. * Description:
  248. * Opens or creates the application's root key.
  249. *
  250. * Arguments:
  251. * LPCTSTR [in]: application id.
  252. *
  253. * Returns:
  254. * HKEY: registry key handle.
  255. *
  256. ***************************************************************************/
  257. HKEY AhOpenApplicationKey
  258. (
  259. LPCTSTR pszAppId
  260. )
  261. {
  262. #ifdef DEBUG
  263. TCHAR szName[0x100] = { 0 };
  264. LONG cbName = sizeof(szName);
  265. #endif // DEBUG
  266. HKEY hkeyAll = NULL;
  267. HKEY hkeyApp = NULL;
  268. HRESULT hr;
  269. EnterProcI(AhOpenApplicationKey, (_ ""));
  270. // Open the parent key
  271. hr = hresMumbleKeyEx( HKEY_LOCAL_MACHINE,
  272. REGSTR_PATH_DINPUT TEXT("\\") REGSTR_KEY_APPHACK, KEY_READ, 0, &hkeyAll );
  273. if(SUCCEEDED(hr))
  274. {
  275. hr = hresMumbleKeyEx( hkeyAll, pszAppId, KEY_READ, 0, &hkeyApp );
  276. RegCloseKey( hkeyAll );
  277. #ifdef DEBUG
  278. // Query for the application description
  279. if(SUCCEEDED(hr))
  280. {
  281. JoyReg_GetValue( hkeyApp, NULL, REG_SZ, szName, cbName );
  282. SquirtSqflPtszV(sqfl | sqflTrace,
  283. TEXT( "%sApplication description: %ls"), c_tszPrefix, szName );
  284. }
  285. #endif // DEBUG
  286. }
  287. ExitProc();
  288. return hkeyApp;
  289. }
  290. /***************************************************************************
  291. *
  292. * AhGetHackValue
  293. *
  294. * Description:
  295. * Queries an apphack value.
  296. *
  297. * Arguments:
  298. * HKEY [in]: application registry key.
  299. * DSAPPHACKID [in]: apphack id.
  300. * LPVOID [out]: receives apphack data.
  301. * DWORD [in]: size of above data buffer.
  302. *
  303. * Returns:
  304. * BOOL: TRUE on success.
  305. *
  306. ***************************************************************************/
  307. BOOL AhGetHackValue
  308. (
  309. HKEY hkey,
  310. DWORD dwOSMask,
  311. DIAPPHACKID ahid,
  312. LPVOID pvData,
  313. DWORD cbData
  314. )
  315. {
  316. HRESULT hr;
  317. EnterProcI(AhGetHackValue, (_ ""));
  318. AssertF(ahid < (DIAPPHACKID)g_ahtAppHackTable.cEntries);
  319. AssertF(cbData == g_ahtAppHackTable.aEntries[ahid].cbData);
  320. if( !( dwOSMask & g_ahtAppHackTable.aEntries[ahid].dwOSMask ) )
  321. {
  322. hr = DI_OK;
  323. }
  324. else
  325. {
  326. hr = JoyReg_GetValue( hkey, g_ahtAppHackTable.aEntries[ahid].pszName,
  327. REG_BINARY, pvData, cbData );
  328. if( !SUCCEEDED( hr ) )
  329. {
  330. SquirtSqflPtszV(sqfl | sqflBenign,
  331. TEXT("%sfailed to read value \"%s\", code 0x%08x"),
  332. c_tszPrefix, g_ahtAppHackTable.aEntries[ahid].pszName, hr);
  333. }
  334. }
  335. ExitProcF(DI_OK == hr);
  336. return DI_OK == hr;
  337. }
  338. /***************************************************************************
  339. *
  340. * AhGetAppHacks
  341. *
  342. * Description:
  343. * Gets all app-hacks for the current application.
  344. *
  345. * Arguments:
  346. * LPDSAPPHACKS [out]: receives app-hack data.
  347. *
  348. * Returns:
  349. * BOOL: TRUE if any apphacks exist for the current application.
  350. *
  351. ***************************************************************************/
  352. BOOL AhGetAppHacks
  353. (
  354. LPDIAPPHACKS pahAppHacks
  355. )
  356. {
  357. static const DIAPPHACKS ahDefaults = { FALSE, FALSE, FALSE, FALSE, FALSE, MAX_PATH };
  358. TCHAR szAppId[MAX_PATH + 8 + 8] = { 0 };
  359. HKEY hkey = NULL;
  360. BOOL fSuccess;
  361. DWORD dwOSMask;
  362. EnterProcI(AhGetAppHacks, (_ ""));
  363. // Assume defaults
  364. CopyMemory(pahAppHacks, &ahDefaults, sizeof(ahDefaults));
  365. // Get the OS version mask
  366. dwOSMask = AhGetOSMask();
  367. // Get the application id
  368. fSuccess = AhGetApplicationId(szAppId, NULL);
  369. if(fSuccess)
  370. {
  371. SquirtSqflPtszV(sqfl | sqflTrace, TEXT("%sFinding apphacks for %s..."), c_tszPrefix, szAppId);
  372. }
  373. // Open the application key
  374. if(fSuccess)
  375. {
  376. hkey = AhOpenApplicationKey(szAppId);
  377. fSuccess = ( hkey && (hkey != INVALID_HANDLE_VALUE ) );
  378. }
  379. #define GET_APP_HACK( hackid, field ) \
  380. if( !AhGetHackValue( hkey, dwOSMask, hackid, &pahAppHacks->##field, sizeof(pahAppHacks->##field) ) ) \
  381. { \
  382. pahAppHacks->##field = ahDefaults.##field; \
  383. }
  384. // Query all apphack values
  385. if(fSuccess)
  386. {
  387. GET_APP_HACK( DICOMPATID_REACQUIRE, fReacquire );
  388. GET_APP_HACK( DICOMPATID_NOSUBCLASS, fNoSubClass );
  389. GET_APP_HACK( DICOMPATID_MAXDEVICENAMELENGTH, nMaxDeviceNameLength );
  390. GET_APP_HACK( DICOMPATID_NATIVEAXISONLY, fNativeAxisOnly );
  391. GET_APP_HACK( DICOMPATID_NOPOLLUNACQUIRE, fNoPollUnacquire );
  392. GET_APP_HACK( DICOMPATID_SUCCEEDACQUIRE, fSucceedAcquire );
  393. }
  394. #undef GET_APP_HACK
  395. if(fSuccess)
  396. {
  397. SquirtSqflPtszV(sqfl | sqflTrace, TEXT("%sfReacquire: %d"), c_tszPrefix, pahAppHacks->fReacquire );
  398. SquirtSqflPtszV(sqfl | sqflTrace, TEXT("%sfNoSubClass: %d"), c_tszPrefix, pahAppHacks->fNoSubClass );
  399. SquirtSqflPtszV(sqfl | sqflTrace, TEXT("%snMaxDeviceNameLength: %d"), c_tszPrefix, pahAppHacks->nMaxDeviceNameLength );
  400. SquirtSqflPtszV(sqfl | sqflTrace, TEXT("%sfNativeAxisOnly: %d"), c_tszPrefix, pahAppHacks->fNativeAxisOnly );
  401. SquirtSqflPtszV(sqfl | sqflTrace, TEXT("%sfNoPollUnacquire: %d"), c_tszPrefix, pahAppHacks->fNoPollUnacquire );
  402. SquirtSqflPtszV(sqfl | sqflTrace, TEXT("%sfSucceedAcquire: %d"), c_tszPrefix, pahAppHacks->fSucceedAcquire );
  403. }
  404. else
  405. {
  406. SquirtSqflPtszV(sqfl | sqflTrace, TEXT("%sNo apphacks exist"), c_tszPrefix);
  407. }
  408. // Clean up
  409. if( hkey )
  410. {
  411. RegCloseKey(hkey);
  412. }
  413. ExitProc();
  414. return fSuccess;
  415. }
  416. HRESULT EXTERNAL AhAppRegister(DWORD dwVer)
  417. {
  418. TCHAR szAppName[MAX_PATH];
  419. TCHAR szAppId[MAX_PATH + 8 + 8] = { 0 };
  420. BOOL fSuccess;
  421. HRESULT hr = E_FAIL;
  422. fSuccess = AhGetApplicationId(szAppId, szAppName);
  423. if (fSuccess)
  424. {
  425. HKEY hKey;
  426. hr = hresMumbleKeyEx( HKEY_CURRENT_USER,
  427. REGSTR_PATH_LASTAPP, KEY_WRITE, 0, &hKey );
  428. if( SUCCEEDED(hr) )
  429. {
  430. FILETIME ftSysTime;
  431. GetSystemTimeAsFileTime( &ftSysTime );
  432. RegSetValueEx(hKey, DIRECTINPUT_REGSTR_VAL_VERSION, 0x0, REG_BINARY, (PUCHAR) &dwVer, cbX(dwVer) );
  433. RegSetValueEx(hKey, DIRECTINPUT_REGSTR_VAL_NAME, 0x0, REG_SZ, (PUCHAR) szAppName, cbCtch(lstrlen(szAppName)+1) );
  434. RegSetValueEx(hKey, DIRECTINPUT_REGSTR_VAL_ID, 0x0, REG_SZ, (PUCHAR) szAppId, cbCtch(lstrlen(szAppId)+1) );
  435. RegSetValueEx(hKey, DIRECTINPUT_REGSTR_VAL_LASTSTART, 0x0, REG_BINARY, (PUCHAR)&ftSysTime, cbX(ftSysTime));
  436. RegCloseKey(hKey);
  437. }
  438. }
  439. return hr;
  440. }