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.

949 lines
32 KiB

  1. /*****************************************************************************
  2. *
  3. * PidReg.c
  4. *
  5. * Copyright (c) 1999 Microsoft Corporation. All Rights Reserved.
  6. *
  7. * Abstract:
  8. *
  9. * Update registry information for PID device.
  10. *
  11. *****************************************************************************/
  12. #include "pidpr.h"
  13. #define sqfl ( sqflReg )
  14. #pragma BEGIN_CONST_DATA
  15. /*
  16. ;---------------------------------------
  17. ;
  18. ; Force feedback registry settings for GUID_Sine.
  19. ;
  20. ; GUID_Sine is a predefined GUID; applications which want
  21. ; to use a sine effect independent of hardware will
  22. ; request a GUID_Sine.
  23. ;
  24. ; The default value is the friendly name for the effect.
  25. ;
  26. HKLM,%KEY_OEM%\XYZZY.FFDrv1\OEMForceFeedback\Effects\%GUID_Sine%,,,"%Sine.Desc%"
  27. ;
  28. ; The Attributes value contains a DIEFFECTATTRIBUTES structure.
  29. ;
  30. ; The effect ID is the number that is passed by DirectInput to the
  31. ; effect driver to identify the effect (thereby saving the effect
  32. ; driver the trouble of parsing GUIDs all the time).
  33. ;
  34. ; Our effect is a periodic effect whose optional envelope
  35. ; supports attack and fade.
  36. ;
  37. ; Our hardware supports changing the following parameters when
  38. ; the effect is not playing (static): Duration, gain, trigger button,
  39. ; axes, direction, envelope, type-specific parameters. We do not
  40. ; support sample period or trigger repeat interval.
  41. ;
  42. ; Our hardware does not support changing any parameters while an
  43. ; effect is playing (dynamic).
  44. ;
  45. ; Our hardware prefers receiving multiple-axis direction information
  46. ; in polar coordinates.
  47. ;
  48. ; dwEffectId = EFFECT_SINE
  49. ; = 723 = D3,02,00,00
  50. ; dwEffType = DIEFT_PERIODIC | DIEFT_FFATTACK | DIEFT_FFFADE | DIEFT_STARTDELAY
  51. ; = 0x00000603 = 03,06,00,00
  52. ; dwStaticParams = DIEP_DURATION | DIEP_GAIN | DIEP_TRIGGERBUTTON |
  53. ; DIEP_AXES | DIEP_DIRECTION | DIEP_ENVELOPE |
  54. ; DIEP_TYPESPECIFICPARAMS | DIEP_STARTDELAY
  55. ; = 0x000001ED = ED,01,00,00
  56. ; dwDynamicParams = 0x00000000 = 00,00,00,00
  57. ; dwCoords = DIEFF_POLAR
  58. ; = 0x00000020 = 20,00,00,00
  59. */
  60. static EFFECTMAPINFO g_EffectMapInfo[] =
  61. {
  62. {
  63. PIDMAKEUSAGEDWORD(ET_CONSTANT),
  64. DIEFT_CONSTANTFORCE | DIEFT_FFATTACK | DIEFT_FFFADE | DIEFT_STARTDELAY,
  65. DIEP_DURATION | DIEP_GAIN | DIEP_TRIGGERBUTTON | DIEP_TRIGGERREPEATINTERVAL | DIEP_AXES | DIEP_DIRECTION | DIEP_ENVELOPE | DIEP_TYPESPECIFICPARAMS | DIEP_STARTDELAY,
  66. DIEP_DURATION | DIEP_GAIN | DIEP_TRIGGERBUTTON | DIEP_TRIGGERREPEATINTERVAL | DIEP_AXES | DIEP_DIRECTION | DIEP_ENVELOPE | DIEP_TYPESPECIFICPARAMS | DIEP_STARTDELAY,
  67. DIEFF_POLAR,
  68. &GUID_ConstantForce,
  69. TEXT("GUID_ConstantForce"),
  70. },
  71. {
  72. PIDMAKEUSAGEDWORD(ET_RAMP),
  73. DIEFT_RAMPFORCE | DIEFT_FFATTACK | DIEFT_FFFADE | DIEFT_STARTDELAY,
  74. DIEP_DURATION | DIEP_GAIN | DIEP_TRIGGERBUTTON | DIEP_TRIGGERREPEATINTERVAL | DIEP_AXES | DIEP_DIRECTION | DIEP_ENVELOPE | DIEP_TYPESPECIFICPARAMS | DIEP_STARTDELAY,
  75. DIEP_DURATION | DIEP_GAIN | DIEP_TRIGGERBUTTON | DIEP_TRIGGERREPEATINTERVAL | DIEP_AXES | DIEP_DIRECTION | DIEP_ENVELOPE | DIEP_TYPESPECIFICPARAMS | DIEP_STARTDELAY,
  76. DIEFF_POLAR,
  77. &GUID_RampForce,
  78. TEXT("GUID_RampForce"),
  79. },
  80. {
  81. PIDMAKEUSAGEDWORD(ET_SQUARE),
  82. DIEFT_PERIODIC | DIEFT_FFATTACK | DIEFT_FFFADE | DIEFT_STARTDELAY,
  83. DIEP_DURATION | DIEP_GAIN | DIEP_TRIGGERBUTTON | DIEP_TRIGGERREPEATINTERVAL | DIEP_AXES | DIEP_DIRECTION | DIEP_ENVELOPE | DIEP_TYPESPECIFICPARAMS | DIEP_STARTDELAY,
  84. DIEP_DURATION | DIEP_GAIN | DIEP_TRIGGERBUTTON | DIEP_TRIGGERREPEATINTERVAL | DIEP_AXES | DIEP_DIRECTION | DIEP_ENVELOPE | DIEP_TYPESPECIFICPARAMS | DIEP_STARTDELAY,
  85. DIEFF_POLAR,
  86. &GUID_Square,
  87. TEXT("GUID_Square"),
  88. },
  89. {
  90. PIDMAKEUSAGEDWORD(ET_SINE),
  91. DIEFT_PERIODIC | DIEFT_FFATTACK | DIEFT_FFFADE | DIEFT_STARTDELAY,
  92. DIEP_DURATION | DIEP_GAIN | DIEP_TRIGGERBUTTON | DIEP_TRIGGERREPEATINTERVAL | DIEP_AXES | DIEP_DIRECTION | DIEP_ENVELOPE | DIEP_TYPESPECIFICPARAMS | DIEP_STARTDELAY,
  93. DIEP_DURATION | DIEP_GAIN | DIEP_TRIGGERBUTTON | DIEP_TRIGGERREPEATINTERVAL | DIEP_AXES | DIEP_DIRECTION | DIEP_ENVELOPE | DIEP_TYPESPECIFICPARAMS | DIEP_STARTDELAY,
  94. DIEFF_POLAR,
  95. &GUID_Sine,
  96. TEXT("GUID_Sine"),
  97. },
  98. {
  99. PIDMAKEUSAGEDWORD(ET_TRIANGLE),
  100. DIEFT_PERIODIC | DIEFT_FFATTACK | DIEFT_FFFADE | DIEFT_STARTDELAY,
  101. DIEP_DURATION | DIEP_GAIN | DIEP_TRIGGERBUTTON | DIEP_TRIGGERREPEATINTERVAL | DIEP_AXES | DIEP_DIRECTION | DIEP_ENVELOPE | DIEP_TYPESPECIFICPARAMS | DIEP_STARTDELAY,
  102. DIEP_DURATION | DIEP_GAIN | DIEP_TRIGGERBUTTON | DIEP_TRIGGERREPEATINTERVAL | DIEP_AXES | DIEP_DIRECTION | DIEP_ENVELOPE | DIEP_TYPESPECIFICPARAMS | DIEP_STARTDELAY,
  103. DIEFF_POLAR,
  104. &GUID_Triangle,
  105. TEXT("GUID_Triangle"),
  106. },
  107. {
  108. PIDMAKEUSAGEDWORD(ET_SAWTOOTH_UP),
  109. DIEFT_PERIODIC | DIEFT_FFATTACK | DIEFT_FFFADE | DIEFT_STARTDELAY,
  110. DIEP_DURATION | DIEP_GAIN | DIEP_TRIGGERBUTTON | DIEP_TRIGGERREPEATINTERVAL | DIEP_AXES | DIEP_DIRECTION | DIEP_ENVELOPE | DIEP_TYPESPECIFICPARAMS | DIEP_STARTDELAY,
  111. DIEP_DURATION | DIEP_GAIN | DIEP_TRIGGERBUTTON | DIEP_TRIGGERREPEATINTERVAL | DIEP_AXES | DIEP_DIRECTION | DIEP_ENVELOPE | DIEP_TYPESPECIFICPARAMS | DIEP_STARTDELAY,
  112. DIEFF_POLAR,
  113. &GUID_SawtoothUp,
  114. TEXT("GUID_SawtoothUp"),
  115. },
  116. {
  117. PIDMAKEUSAGEDWORD(ET_SAWTOOTH_DOWN),
  118. DIEFT_PERIODIC | DIEFT_FFATTACK | DIEFT_FFFADE | DIEFT_STARTDELAY,
  119. DIEP_DURATION | DIEP_GAIN | DIEP_TRIGGERBUTTON | DIEP_TRIGGERREPEATINTERVAL | DIEP_AXES | DIEP_DIRECTION | DIEP_ENVELOPE | DIEP_TYPESPECIFICPARAMS | DIEP_STARTDELAY,
  120. DIEP_DURATION | DIEP_GAIN | DIEP_TRIGGERBUTTON | DIEP_TRIGGERREPEATINTERVAL | DIEP_AXES | DIEP_DIRECTION | DIEP_ENVELOPE | DIEP_TYPESPECIFICPARAMS | DIEP_STARTDELAY,
  121. DIEFF_POLAR,
  122. &GUID_SawtoothDown,
  123. TEXT("GUID_SawtoothDown"),
  124. },
  125. {
  126. PIDMAKEUSAGEDWORD(ET_SPRING),
  127. DIEFT_CONDITION | DIEFT_SATURATION | DIEFT_DEADBAND | DIEFT_STARTDELAY,
  128. DIEP_DURATION | DIEP_GAIN | DIEP_AXES | DIEP_DIRECTION | DIEP_TYPESPECIFICPARAMS | DIEP_STARTDELAY,
  129. DIEP_DURATION | DIEP_GAIN | DIEP_AXES | DIEP_DIRECTION | DIEP_TYPESPECIFICPARAMS | DIEP_STARTDELAY,
  130. DIEFF_POLAR,
  131. &GUID_Spring,
  132. TEXT("GUID_Spring"),
  133. },
  134. {
  135. PIDMAKEUSAGEDWORD(ET_DAMPER),
  136. DIEFT_CONDITION | DIEFT_SATURATION | DIEFT_DEADBAND | DIEFT_STARTDELAY,
  137. DIEP_DURATION | DIEP_GAIN | DIEP_AXES | DIEP_DIRECTION | DIEP_TYPESPECIFICPARAMS | DIEP_STARTDELAY,
  138. DIEP_DURATION | DIEP_GAIN | DIEP_AXES | DIEP_DIRECTION | DIEP_TYPESPECIFICPARAMS | DIEP_STARTDELAY,
  139. DIEFF_POLAR,
  140. &GUID_Damper,
  141. TEXT("GUID_Damper"),
  142. },
  143. {
  144. PIDMAKEUSAGEDWORD(ET_INERTIA),
  145. DIEFT_CONDITION | DIEFT_SATURATION | DIEFT_DEADBAND | DIEFT_STARTDELAY,
  146. DIEP_DURATION | DIEP_GAIN | DIEP_AXES | DIEP_DIRECTION | DIEP_TYPESPECIFICPARAMS | DIEP_STARTDELAY,
  147. DIEP_DURATION | DIEP_GAIN | DIEP_AXES | DIEP_DIRECTION | DIEP_TYPESPECIFICPARAMS | DIEP_STARTDELAY,
  148. DIEFF_POLAR,
  149. &GUID_Inertia,
  150. TEXT("GUID_Inertia"),
  151. },
  152. {
  153. PIDMAKEUSAGEDWORD(ET_FRICTION),
  154. DIEFT_CONDITION | DIEFT_SATURATION | DIEFT_DEADBAND | DIEFT_STARTDELAY,
  155. DIEP_DURATION | DIEP_GAIN | DIEP_AXES | DIEP_DIRECTION | DIEP_TYPESPECIFICPARAMS | DIEP_STARTDELAY,
  156. DIEP_DURATION | DIEP_GAIN | DIEP_AXES | DIEP_DIRECTION | DIEP_TYPESPECIFICPARAMS | DIEP_STARTDELAY,
  157. DIEFF_POLAR,
  158. &GUID_Friction,
  159. TEXT("GUID_Friction"),
  160. },
  161. {
  162. PIDMAKEUSAGEDWORD(ET_CUSTOM),
  163. DIEFT_CUSTOMFORCE | DIEFT_SATURATION | DIEFT_DEADBAND | DIEFT_STARTDELAY,
  164. DIEP_DURATION | DIEP_GAIN | DIEP_TRIGGERBUTTON | DIEP_TRIGGERREPEATINTERVAL | DIEP_AXES | DIEP_DIRECTION | DIEP_ENVELOPE | DIEP_TYPESPECIFICPARAMS | DIEP_STARTDELAY,
  165. DIEP_DURATION | DIEP_GAIN | DIEP_TRIGGERBUTTON | DIEP_TRIGGERREPEATINTERVAL | DIEP_AXES | DIEP_DIRECTION | DIEP_ENVELOPE | DIEP_TYPESPECIFICPARAMS | DIEP_STARTDELAY,
  166. DIEFF_POLAR,
  167. &GUID_CustomForce,
  168. TEXT("GUID_CustomForce"),
  169. },
  170. };
  171. static PIDSUPPORT g_DIeft[] =
  172. {
  173. {DIEFT_CONSTANTFORCE, PIDMAKEUSAGEDWORD(SET_CONSTANT_FORCE_REPORT), HID_COLLECTION, 0x0},
  174. {DIEFT_RAMPFORCE, PIDMAKEUSAGEDWORD(SET_RAMP_FORCE_REPORT), HID_COLLECTION, 0x0},
  175. {DIEFT_PERIODIC, PIDMAKEUSAGEDWORD(SET_PERIODIC_REPORT), HID_COLLECTION, 0x0},
  176. {DIEFT_CONDITION, PIDMAKEUSAGEDWORD(SET_CONDITION_REPORT), HID_COLLECTION, 0x0},
  177. {DIEFT_CUSTOMFORCE, PIDMAKEUSAGEDWORD(SET_CUSTOM_FORCE_REPORT), HID_COLLECTION, 0x0},
  178. //{DIEFT_HARDWARE, ???? },
  179. {DIEFT_FFATTACK, PIDMAKEUSAGEDWORD(ATTACK_LEVEL), HID_VALUE, HidP_Output},
  180. {DIEFT_FFFADE, PIDMAKEUSAGEDWORD(FADE_LEVEL), HID_VALUE, HidP_Output},
  181. {DIEFT_SATURATION, PIDMAKEUSAGEDWORD(POSITIVE_SATURATION), HID_VALUE, HidP_Output},
  182. {DIEFT_POSNEGCOEFFICIENTS, PIDMAKEUSAGEDWORD(NEGATIVE_COEFFICIENT), HID_VALUE, HidP_Output},
  183. {DIEFT_POSNEGSATURATION, PIDMAKEUSAGEDWORD(NEGATIVE_SATURATION), HID_VALUE, HidP_Output},
  184. {DIEFT_DEADBAND, PIDMAKEUSAGEDWORD(DEAD_BAND), HID_VALUE, HidP_Output},
  185. #if DIRECTINPUT_VERSION >= 0x600
  186. {DIEFT_STARTDELAY, PIDMAKEUSAGEDWORD(START_DELAY), HID_VALUE, HidP_Output},
  187. #endif
  188. };
  189. static PIDSUPPORT g_DIep[] =
  190. {
  191. {DIEP_DURATION, PIDMAKEUSAGEDWORD(DURATION), HID_VALUE, HidP_Output},
  192. {DIEP_SAMPLEPERIOD, PIDMAKEUSAGEDWORD(SAMPLE_PERIOD), HID_VALUE, HidP_Output},
  193. {DIEP_GAIN, PIDMAKEUSAGEDWORD(GAIN), HID_VALUE, HidP_Output},
  194. {DIEP_TRIGGERBUTTON, PIDMAKEUSAGEDWORD(TRIGGER_BUTTON), HID_VALUE, HidP_Output},
  195. {DIEP_TRIGGERREPEATINTERVAL, PIDMAKEUSAGEDWORD(TRIGGER_REPEAT_INTERVAL), HID_VALUE, HidP_Output},
  196. {DIEP_AXES, PIDMAKEUSAGEDWORD(AXES_ENABLE), HID_COLLECTION, 0x0},
  197. {DIEP_DIRECTION, PIDMAKEUSAGEDWORD(DIRECTION), HID_COLLECTION, 0x0},
  198. {DIEP_ENVELOPE, PIDMAKEUSAGEDWORD(SET_ENVELOPE_REPORT), HID_COLLECTION, 0x0},
  199. #if DIRECTINPUT_VERSION >= 0x600
  200. {DIEP_STARTDELAY, PIDMAKEUSAGEDWORD(START_DELAY), HID_VALUE, HidP_Output},
  201. #endif
  202. };
  203. static PIDSUPPORT g_DIeff[] =
  204. {
  205. {DIEFF_POLAR, PIDMAKEUSAGEDWORD(DIRECTION_ENABLE), HID_BUTTON, HidP_Output},
  206. // PID devices do not support Cartesian
  207. // {DIEFF_ CARTESIAN, PIDMAKEUSAGEDWORD(AXES_ENABLE), HID_COLLECTION,0x0},
  208. };
  209. #pragma END_CONST_DATA
  210. //our own version of KEY_ALL_ACCESS, that does not use WRITE_DAC and WRITE_OWNER (see Whistler bug 318865, 370734)
  211. #define DI_DAC_OWNER (WRITE_DAC | WRITE_OWNER)
  212. #define DI_KEY_ALL_ACCESS (KEY_ALL_ACCESS & ~DI_DAC_OWNER)
  213. // we need to know on which OS we're running, to to have appropriate reg key permissions (see Whistler bug 318865, 370734)
  214. #define WIN_UNKNOWN_OS 0
  215. #define WIN95_OS 1
  216. #define WIN98_OS 2
  217. #define WINME_OS 3
  218. #define WINNT_OS 4
  219. #define WINWH_OS 5
  220. STDMETHODIMP
  221. PID_Support
  222. (
  223. IDirectInputEffectDriver *ped,
  224. UINT cAPidSupport,
  225. PPIDSUPPORT rgPidSupport,
  226. PDWORD pdwFlags
  227. )
  228. {
  229. CPidDrv *this = (CPidDrv *)ped;
  230. HRESULT hres;
  231. UINT indx;
  232. PPIDSUPPORT pPidSupport;
  233. EnterProcI(PID_Support, (_"xxxx", ped, cAPidSupport, rgPidSupport, pdwFlags));
  234. hres = S_OK;
  235. for( indx = 0x0, pPidSupport = rgPidSupport;
  236. indx < cAPidSupport;
  237. indx++, pPidSupport++
  238. )
  239. {
  240. USAGE Usage = DIGETUSAGE(pPidSupport->dwPidUsage);
  241. USAGE UsagePage = DIGETUSAGEPAGE(pPidSupport->dwPidUsage);
  242. if( pPidSupport->Type == HID_COLLECTION )
  243. {
  244. HRESULT hres0;
  245. USHORT LinkCollection;
  246. hres0 = PID_GetLinkCollectionIndex(ped, UsagePage, Usage , 0x0, &LinkCollection);
  247. if( SUCCEEDED(hres0) )
  248. {
  249. *pdwFlags |= pPidSupport->dwDIFlags;
  250. } else
  251. {
  252. hres |= E_NOTIMPL;
  253. SquirtSqflPtszV(sqfl | sqflBenign,
  254. TEXT("%s: FAIL PID_GetCollectionIndex:0x%x for(%x,%x,%x:%s)"),
  255. s_tszProc, hres0,
  256. LinkCollection,UsagePage, Usage,
  257. PIDUSAGETXT(UsagePage,Usage)
  258. );
  259. }
  260. } else if( pPidSupport->Type == HID_VALUE )
  261. {
  262. NTSTATUS ntStat;
  263. HIDP_VALUE_CAPS ValCaps;
  264. USHORT cAValCaps = 0x1;
  265. ntStat = HidP_GetSpecificValueCaps
  266. (
  267. pPidSupport->HidP_Type, //ReportType
  268. UsagePage, //UsagePage
  269. 0x0, //LinkCollection,
  270. Usage, //Usage
  271. &ValCaps, //ValueCaps,
  272. &cAValCaps, //ValueCapsLength,
  273. this->ppd //Preparsed Data
  274. );
  275. if( SUCCEEDED(ntStat )
  276. || ntStat == HIDP_STATUS_BUFFER_TOO_SMALL)
  277. {
  278. *pdwFlags |= pPidSupport->dwDIFlags;
  279. } else
  280. {
  281. hres |= E_NOTIMPL;
  282. SquirtSqflPtszV(sqfl | sqflBenign,
  283. TEXT("%s: FAIL HidP_GetSpValCaps:0x%x for(%x,%x,%x:%s)"),
  284. s_tszProc, ntStat,
  285. 0x0,UsagePage, Usage,
  286. PIDUSAGETXT(UsagePage,Usage)
  287. );
  288. }
  289. } else if( pPidSupport->Type == HID_BUTTON )
  290. {
  291. NTSTATUS ntStat;
  292. HIDP_BUTTON_CAPS ButtonCaps;
  293. USHORT cAButtonCaps = 0x1;
  294. ntStat = HidP_GetSpecificButtonCaps
  295. (
  296. pPidSupport->HidP_Type, //ReportType
  297. UsagePage, //UsagePage
  298. 0x0, //LinkCollection,
  299. Usage, //Usage
  300. &ButtonCaps, //ValueCaps,
  301. &cAButtonCaps, //ValueCapsLength,
  302. this->ppd //Preparsed Data
  303. );
  304. if( SUCCEEDED(ntStat )
  305. || ntStat == HIDP_STATUS_BUFFER_TOO_SMALL)
  306. {
  307. *pdwFlags |= pPidSupport->dwDIFlags;
  308. } else
  309. {
  310. hres |= E_NOTIMPL;
  311. SquirtSqflPtszV(sqfl | sqflBenign,
  312. TEXT("%s: FAIL HidP_GetSpButtonCaps:0x%x for(%x,%x,%x:%s)"),
  313. s_tszProc, ntStat,
  314. 0x0,UsagePage, Usage,
  315. PIDUSAGETXT(UsagePage,Usage)
  316. );
  317. }
  318. } else
  319. {
  320. hres |= DIERR_PID_USAGENOTFOUND;
  321. }
  322. }
  323. ExitOleProc();
  324. return hres;
  325. }
  326. /*****************************************************************************
  327. *
  328. * @doc INTERNAL
  329. *
  330. * @func void | NameFromGUID |
  331. *
  332. * Convert a GUID into an ASCII string that will be used
  333. * to name it in the global namespace.
  334. *
  335. *
  336. * @parm LPTSTR | ptszBuf |
  337. *
  338. * Output buffer to receive the converted name. It must
  339. * be <c ctchNameGuid> characters in size.
  340. *
  341. * @parm PCGUID | pguid |
  342. *
  343. * The GUID to convert.
  344. *
  345. *
  346. *****************************************************************************/
  347. #pragma BEGIN_CONST_DATA
  348. /* Note: If you change this string, you need to change ctchNameGuid to match */
  349. TCHAR c_tszNameFormat[] =
  350. TEXT("{%08X-%04X-%04X-%02X%02X-%02X%02X%02X%02X%02X%02X}");
  351. #pragma END_CONST_DATA
  352. #define ctchGuid (1 + 8 + 1 + 4 + 1 + 4 + 1 + 4 + 1 + 12 + 1 + 1)
  353. void EXTERNAL
  354. NameFromGUID(LPTSTR ptszBuf, PCGUID pguid)
  355. {
  356. int ctch;
  357. ctch = wsprintf(ptszBuf, c_tszNameFormat,
  358. pguid->Data1, pguid->Data2, pguid->Data3,
  359. pguid->Data4[0], pguid->Data4[1],
  360. pguid->Data4[2], pguid->Data4[3],
  361. pguid->Data4[4], pguid->Data4[5],
  362. pguid->Data4[6], pguid->Data4[7]);
  363. AssertF(ctch == ctchGuid - 1);
  364. }
  365. #define hresLe(le) MAKE_HRESULT(SEVERITY_ERROR, FACILITY_WIN32, (USHORT)(le))
  366. BOOL INLINE
  367. IsWriteSam(REGSAM sam)
  368. {
  369. return sam & (KEY_SET_VALUE | KEY_CREATE_SUB_KEY | MAXIMUM_ALLOWED);
  370. }
  371. /*****************************************************************************
  372. *
  373. * @doc INTERNAL
  374. *
  375. * @func DWORD | PID_GetOSVersion |
  376. *
  377. * Return the OS version on which pid.dll is running.
  378. *
  379. * @returns
  380. *
  381. * WIN95_OS, WIN98_OS, WINME_OS, WINNT_OS, WINWH_OS, or WIN_UNKNOWN_OS.
  382. *
  383. *****************************************************************************/
  384. DWORD PID_GetOSVersion()
  385. {
  386. OSVERSIONINFO osVerInfo;
  387. DWORD dwVer;
  388. if( GetVersion() < 0x80000000 ) {
  389. dwVer = WINNT_OS;
  390. } else {
  391. dwVer = WIN95_OS; //assume Windows 95 for safe
  392. }
  393. osVerInfo.dwOSVersionInfoSize = sizeof( OSVERSIONINFO );
  394. // If GetVersionEx is supported, then get more details.
  395. if( GetVersionEx( &osVerInfo ) )
  396. {
  397. // Win2K
  398. if( osVerInfo.dwPlatformId == VER_PLATFORM_WIN32_NT )
  399. {
  400. // Whistler: Major = 5 & Build # > 2195
  401. if( osVerInfo.dwMajorVersion == 5 && osVerInfo.dwBuildNumber > 2195 )
  402. {
  403. dwVer = WINWH_OS;
  404. } else {
  405. dwVer = WINNT_OS;
  406. }
  407. }
  408. // Win9X
  409. else
  410. {
  411. if( (HIBYTE(HIWORD(osVerInfo.dwBuildNumber)) == 4) )
  412. {
  413. // WinMe: Major = 4, Minor = 90
  414. if( (LOBYTE(HIWORD(osVerInfo.dwBuildNumber)) == 90) )
  415. {
  416. dwVer = WINME_OS;
  417. } else if ( (LOBYTE(HIWORD(osVerInfo.dwBuildNumber)) > 0) ) {
  418. dwVer = WIN98_OS;
  419. } else {
  420. dwVer = WIN95_OS;
  421. }
  422. }
  423. }
  424. }
  425. return dwVer;
  426. }
  427. /*****************************************************************************
  428. *
  429. * @doc INTERNAL
  430. *
  431. * @func HRESULT | hresMumbleKeyEx |
  432. *
  433. * Either open or create the key, depending on the degree
  434. * of access requested.
  435. *
  436. * @parm HKEY | hk |
  437. *
  438. * Base key.
  439. *
  440. * @parm LPCTSTR | ptszKey |
  441. *
  442. * Name of subkey, possibly NULL.
  443. *
  444. * @parm REGSAM | sam |
  445. *
  446. * Security access mask.
  447. *
  448. * @parm DWORD | dwOptions |
  449. * Options for RegCreateEx
  450. *
  451. * @parm PHKEY | phk |
  452. *
  453. * Receives output key.
  454. *
  455. * @returns
  456. *
  457. * Return value from <f RegOpenKeyEx> or <f RegCreateKeyEx>,
  458. * converted to an <t HRESULT>.
  459. *
  460. *****************************************************************************/
  461. STDMETHODIMP
  462. hresMumbleKeyEx(HKEY hk, LPCTSTR ptszKey, REGSAM sam, DWORD dwOptions, PHKEY phk)
  463. {
  464. HRESULT hres;
  465. LONG lRc;
  466. BOOL bWinXP = FALSE;
  467. EnterProc(hresMumbleKeyEx, (_"xsxxx", hk, ptszKey, sam, dwOptions, phk));
  468. /*
  469. * If caller is requesting write access, then create the key.
  470. * Else just open it.
  471. */
  472. if(IsWriteSam(sam))
  473. {
  474. // on WinXP, we strip out WRITE_DAC and WRITE_OWNER bits
  475. if (PID_GetOSVersion() == WINWH_OS)
  476. {
  477. sam &= ~DI_DAC_OWNER;
  478. bWinXP = TRUE;
  479. }
  480. lRc = RegOpenKeyEx(hk, ptszKey, 0, sam, phk);
  481. if( lRc == ERROR_SUCCESS )
  482. {
  483. // Don't need to create it already exists
  484. } else
  485. {
  486. #ifdef WINNT
  487. EXPLICIT_ACCESS ExplicitAccess;
  488. PACL pACL;
  489. DWORD dwErr;
  490. SECURITY_DESCRIPTOR SecurityDesc;
  491. DWORD dwDisposition;
  492. SECURITY_ATTRIBUTES sa;
  493. PSID pSid = NULL;
  494. SID_IDENTIFIER_AUTHORITY authority = SECURITY_WORLD_SID_AUTHORITY;
  495. // Describe the access we want to create the key with
  496. ZeroMemory (&ExplicitAccess, sizeof(ExplicitAccess) );
  497. //set the access depending on the OS (see Whistler bug 318865)
  498. if (bWinXP == TRUE)
  499. {
  500. ExplicitAccess.grfAccessPermissions = DI_KEY_ALL_ACCESS;
  501. }
  502. else
  503. {
  504. ExplicitAccess.grfAccessPermissions = KEY_ALL_ACCESS;
  505. }
  506. ExplicitAccess.grfAccessMode = GRANT_ACCESS;
  507. ExplicitAccess.grfInheritance = SUB_CONTAINERS_AND_OBJECTS_INHERIT;
  508. if (AllocateAndInitializeSid(
  509. &authority,
  510. 1,
  511. SECURITY_WORLD_RID, 0, 0, 0, 0, 0, 0, 0,
  512. &pSid
  513. ))
  514. {
  515. BuildTrusteeWithSid(&(ExplicitAccess.Trustee), pSid );
  516. dwErr = SetEntriesInAcl( 1, &ExplicitAccess, NULL, &pACL );
  517. if( dwErr == ERROR_SUCCESS )
  518. {
  519. AssertF( pACL );
  520. if( InitializeSecurityDescriptor( &SecurityDesc, SECURITY_DESCRIPTOR_REVISION ) )
  521. {
  522. if( SetSecurityDescriptorDacl( &SecurityDesc, TRUE, pACL, FALSE ) )
  523. {
  524. // Initialize a security attributes structure.
  525. sa.nLength = sizeof (SECURITY_ATTRIBUTES);
  526. sa.lpSecurityDescriptor = &SecurityDesc;
  527. sa.bInheritHandle = TRUE;// Use the security attributes to create a key.
  528. lRc = RegCreateKeyEx
  529. (
  530. hk, // handle of an open key
  531. ptszKey, // address of subkey name
  532. 0, // reserved
  533. NULL, // address of class string
  534. dwOptions, // special options flag
  535. ExplicitAccess.grfAccessPermissions, // desired security access
  536. &sa, // address of key security structure
  537. phk, // address of buffer for opened handle
  538. &dwDisposition // address of disposition value buffer);
  539. );
  540. }
  541. else
  542. {
  543. SquirtSqflPtszV( sqflError | sqflReg,
  544. TEXT("SetSecurityDescriptorDacl failed lastError=0x%x "),
  545. GetLastError());
  546. }
  547. }
  548. else
  549. {
  550. SquirtSqflPtszV( sqflError | sqflReg,
  551. TEXT("InitializeSecurityDescriptor failed lastError=0x%x "),
  552. GetLastError());
  553. }
  554. LocalFree( pACL );
  555. }
  556. else
  557. {
  558. SquirtSqflPtszV( sqflError | sqflReg,
  559. TEXT("SetEntriesInACL failed, dwErr=0x%x"), dwErr );
  560. }
  561. }
  562. else
  563. {
  564. SquirtSqflPtszV( sqflError | sqflReg,
  565. TEXT("AllocateAndInitializeSid failed"));
  566. }
  567. //Cleanup pSid
  568. if (pSid != NULL)
  569. {
  570. FreeSid(pSid);
  571. }
  572. if( lRc != ERROR_SUCCESS )
  573. {
  574. SquirtSqflPtszV( sqflError,
  575. TEXT("Failed to create regkey %s with security descriptor, lRc=0x%x "),
  576. ptszKey, lRc);
  577. }
  578. #else
  579. lRc = RegCreateKeyEx(hk, ptszKey, 0, 0,
  580. dwOptions,
  581. sam, 0, phk, 0);
  582. #endif
  583. }
  584. } else
  585. {
  586. lRc = RegOpenKeyEx(hk, ptszKey, 0, sam, phk);
  587. }
  588. if(lRc == ERROR_SUCCESS)
  589. {
  590. hres = S_OK;
  591. } else
  592. {
  593. if(lRc == ERROR_KEY_DELETED || lRc == ERROR_BADKEY)
  594. {
  595. lRc = ERROR_FILE_NOT_FOUND;
  596. }
  597. hres = hresLe(lRc);
  598. }
  599. ExitOleProc();
  600. return hres;
  601. }
  602. /*****************************************************************************
  603. *
  604. * @doc INTERNAL
  605. *
  606. * @func HRESULT | PID_CreateFFKeys |
  607. *
  608. * Given a handle to a PID device, create the registry entries to enable
  609. * force feedback.
  610. *
  611. * @parm HANDLE | hdev |
  612. *
  613. * Handle to the PID device.
  614. *
  615. * @parm HKEY | hkFF |
  616. *
  617. * Force Feedback registry key.
  618. *
  619. * @returns
  620. *
  621. * Returns a COM error code. The following error codes are
  622. * intended to be illustrative and not necessarily comprehensive.
  623. *
  624. * <c DI_OK> = <c S_OK>: The operation completed successfully.
  625. *
  626. * <c DIERR_NOTFOUND>: Couldn't open the key.
  627. *
  628. *****************************************************************************/
  629. STDMETHODIMP
  630. PID_CreateFFKeys
  631. (
  632. IDirectInputEffectDriver *ped,
  633. HKEY hkFF
  634. )
  635. {
  636. CPidDrv *this = (CPidDrv *)ped;
  637. HRESULT hres;
  638. UINT uEffect;
  639. HKEY hkEffect;
  640. EnterProc(PID_CreateFFKey, (_"xx", ped, hkFF));
  641. hres = hresMumbleKeyEx(hkFF, REGSTR_EFFECTS, KEY_ALL_ACCESS, REG_OPTION_NON_VOLATILE, &hkEffect);
  642. if( SUCCEEDED(hres) )
  643. {
  644. DWORD dwDIef, dwDIep, dwDIeff;
  645. dwDIef = dwDIep = dwDIeff = 0x0;
  646. /*
  647. * Determine supported flags for effectType and Effect Params
  648. * based on the PID descriptors
  649. */
  650. PID_Support(ped, cA(g_DIeft), g_DIeft, &dwDIef);
  651. PID_Support(ped, cA(g_DIep), g_DIep, &dwDIep);
  652. PID_Support(ped, cA(g_DIeff), g_DIeff, &dwDIeff);
  653. // All effects support DIEP_TYPESPECIFICPARAMS
  654. dwDIep |= DIEP_TYPESPECIFICPARAMS;
  655. for( uEffect = 0x0; uEffect < cA(g_EffectMapInfo); uEffect++ )
  656. {
  657. EFFECTMAPINFO emi = g_EffectMapInfo[uEffect];
  658. PIDSUPPORT PidSupport;
  659. DWORD dwJunk;
  660. HRESULT hres0;
  661. PidSupport.dwPidUsage = emi.attr.dwEffectId;
  662. PidSupport.Type = HID_BUTTON;
  663. PidSupport.HidP_Type = HidP_Output;
  664. hres0 = PID_Support(ped, 0x1, &PidSupport, &dwJunk);
  665. if( SUCCEEDED(hres0) )
  666. {
  667. TCHAR tszName[ctchGuid];
  668. HKEY hk;
  669. NameFromGUID(tszName, emi.pcguid);
  670. hres = hresMumbleKeyEx(hkEffect, tszName, KEY_ALL_ACCESS, REG_OPTION_NON_VOLATILE, &hk);
  671. if( SUCCEEDED(hres) )
  672. {
  673. LONG lRc;
  674. lRc = RegSetValueEx(hk, 0x0, 0x0, REG_SZ, (char*)emi.tszName, lstrlen(emi.tszName) * cbX(emi.tszName[0]));
  675. if( lRc == ERROR_SUCCESS )
  676. {
  677. /*
  678. * Modify generic attribute flags depending
  679. * on PID firmware descriptors
  680. */
  681. emi.attr.dwEffType &= dwDIef;
  682. emi.attr.dwStaticParams &= dwDIep;
  683. emi.attr.dwDynamicParams &= dwDIep;
  684. emi.attr.dwCoords &= dwDIeff;
  685. lRc = RegSetValueEx(hk, REGSTR_ATTRIBUTES, 0x0, REG_BINARY, (char*)&emi.attr, cbX(emi.attr) ) ;
  686. if( lRc == ERROR_SUCCESS )
  687. {
  688. } else
  689. {
  690. hres = REGDB_E_WRITEREGDB;
  691. }
  692. } else
  693. {
  694. hres = REGDB_E_WRITEREGDB;
  695. }
  696. RegCloseKey(hk);
  697. }
  698. }
  699. }
  700. RegCloseKey(hkEffect);
  701. }
  702. ExitOleProc();
  703. return hres;
  704. }
  705. /*****************************************************************************
  706. *
  707. * PID_InitRegistry
  708. *
  709. * This function updates the registry for a specified device.
  710. *
  711. * LPTSTR ptszDeviceInterface
  712. *
  713. *
  714. * Returns:
  715. *
  716. * S_OK if the operation completed successfully.
  717. *
  718. * Any DIERR_* error code may be returned.
  719. *
  720. * Private driver-specific error codes in the range
  721. * DIERR_DRIVERFIRST through DIERR_DRIVERLAST
  722. * may be returned.
  723. *
  724. *****************************************************************************/
  725. STDMETHODIMP
  726. PID_InitRegistry
  727. (
  728. IDirectInputEffectDriver *ped
  729. )
  730. {
  731. CPidDrv *this = (CPidDrv *)ped;
  732. HRESULT hres;
  733. TCHAR tszType[MAX_JOYSTRING];
  734. HKEY hkFF;
  735. EnterProc(PID_InitRegistry, (_"x", ped));
  736. wsprintf(tszType, REGSTR_OEM_FF_TEMPLATE, this->attr.VendorID, this->attr.ProductID);
  737. //If there is no pid version written, -- or it is less then the "last known good version" (today it is 0x0720),
  738. //overwrite the previous key.
  739. hres = hresMumbleKeyEx(HKEY_LOCAL_MACHINE, tszType, KEY_READ, REG_OPTION_NON_VOLATILE, &hkFF );
  740. if( SUCCEEDED(hres) )
  741. {
  742. DWORD dwCreatedBy = 0x0;
  743. DWORD dwSize = cbX(dwCreatedBy);
  744. hres = E_FAIL;
  745. if ((RegQueryValueEx(hkFF, REGSTR_CREATEDBY, 0x0, 0x0, (BYTE*)&dwCreatedBy, &dwSize) == ERROR_SUCCESS) &&
  746. (dwCreatedBy >= 0x0720))
  747. {
  748. hres = S_OK;
  749. }
  750. RegCloseKey(hkFF);
  751. }
  752. if (FAILED(hres))
  753. {
  754. hres = hresMumbleKeyEx(HKEY_LOCAL_MACHINE, tszType, KEY_ALL_ACCESS, REG_OPTION_NON_VOLATILE, &hkFF);
  755. if( SUCCEEDED(hres) )
  756. {
  757. hres = PID_CreateFFKeys(ped, hkFF );
  758. if( SUCCEEDED(hres) )
  759. {
  760. DWORD dwCreatedBy = DIRECTINPUT_HEADER_VERSION;
  761. LONG lRc;
  762. DWORD dwSize;
  763. DWORD dwType;
  764. //DX8a Do not overwrite an existing CLSID as we may have
  765. //been loaded by an IHV with their own CLSID. In DX8, this
  766. //was always written causing some IHV drivers to be ignored.
  767. //Allow long values as a lot of people write strings with
  768. //garbage after a null terminated string
  769. //For now, DInput won't load such a CLSID but just in case
  770. lRc = RegQueryValueEx( hkFF, REGSTR_CLSID, NULL, &dwType, NULL, &dwSize );
  771. if( ( lRc == ERROR_SUCCESS )
  772. && ( dwType == REG_SZ )
  773. && ( dwSize >= ctchGuid - 1 ) )
  774. {
  775. #ifdef DEBUG
  776. TCHAR tszDbg[MAX_PATH];
  777. dwSize = cbX(tszDbg);
  778. if( RegQueryValueEx( hkFF, REGSTR_CLSID, NULL, NULL, (BYTE*)tszDbg, &dwSize )
  779. || !dwSize )
  780. {
  781. tszDbg[0] = TEXT('?');
  782. tszDbg[1] = TEXT('\0');
  783. }
  784. SquirtSqflPtszV(sqfl | sqflBenign,
  785. TEXT("RegistryInit: Not overwiting existing CLSID %s"), tszDbg );
  786. #endif
  787. }
  788. else
  789. {
  790. TCHAR tszGuid[ctchGuid];
  791. NameFromGUID(tszGuid, &IID_IDirectInputPIDDriver);
  792. AssertF( lstrlen(tszGuid) * cbX(tszGuid[0]) == cbX(tszGuid) - cbX(tszGuid[0]) );
  793. lRc = RegSetValueEx(hkFF, REGSTR_CLSID, 0x0, REG_SZ, (char*)tszGuid, cbX(tszGuid) - cbX(tszGuid[0]));
  794. if( lRc == ERROR_SUCCESS )
  795. {
  796. } else
  797. {
  798. hres = REGDB_E_WRITEREGDB;
  799. }
  800. }
  801. //set "CreatedBy" value
  802. lRc = RegSetValueEx(hkFF, REGSTR_CREATEDBY, 0x0, REG_BINARY, (BYTE*) &dwCreatedBy, cbX(dwCreatedBy));
  803. if( lRc == ERROR_SUCCESS )
  804. {
  805. } else
  806. {
  807. hres = REGDB_E_WRITEREGDB;
  808. }
  809. }
  810. if(SUCCEEDED(hres) )
  811. {
  812. DIFFDEVICEATTRIBUTES diff;
  813. LONG lRc;
  814. diff.dwFlags = 0x0;
  815. diff.dwFFSamplePeriod =
  816. diff.dwFFMinTimeResolution = DI_SECONDS;
  817. lRc = RegSetValueEx(hkFF, REGSTR_ATTRIBUTES, 0x0, REG_BINARY, (char*)&diff, cbX(diff) ) ;
  818. if(lRc == ERROR_SUCCESS)
  819. {
  820. } else
  821. {
  822. hres = REGDB_E_WRITEREGDB;
  823. }
  824. }
  825. RegCloseKey(hkFF);
  826. }
  827. }
  828. ExitOleProc();
  829. return hres;
  830. }