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.

3452 lines
106 KiB

  1. /*****************************************************************************
  2. *
  3. * DIJoyCfg.c
  4. *
  5. * Copyright (c) 1996 Microsoft Corporation. All Rights Reserved.
  6. *
  7. * Abstract:
  8. *
  9. * IDirectInputJoyConfig8
  10. *
  11. * Contents:
  12. *
  13. * CJoyCfg_New
  14. *
  15. *****************************************************************************/
  16. #include "dinputpr.h"
  17. /*****************************************************************************
  18. *
  19. * The sqiffle for this file.
  20. *
  21. *****************************************************************************/
  22. #define sqfl sqflJoyCfg
  23. BOOL fVjoydDeviceNotExist = TRUE;
  24. #ifdef WINNT
  25. WCHAR wszDITypeName[128];
  26. #endif
  27. #pragma BEGIN_CONST_DATA
  28. /*****************************************************************************
  29. *
  30. * Declare the interfaces we will be providing.
  31. *
  32. * WARNING! If you add a secondary interface, you must also change
  33. * CJoyCfg_New!
  34. *
  35. *****************************************************************************/
  36. Primary_Interface(CJoyCfg, IDirectInputJoyConfig8);
  37. Interface_Template_Begin(CJoyCfg)
  38. Primary_Interface_Template(CJoyCfg, IDirectInputJoyConfig8)
  39. Interface_Template_End(CJoyCfg)
  40. /*****************************************************************************
  41. *
  42. * @doc INTERNAL
  43. *
  44. * @struct CJoyCfg |
  45. *
  46. * The <i IDirectInputJoyConfig8> object. Note that this is
  47. * aggregated onto the main <i IDirectInput> object.
  48. *
  49. * @field IDirectInputJoyConfig8 | djc |
  50. *
  51. * The object (containing vtbl).
  52. *
  53. * @field BOOL | fAcquired:1 |
  54. *
  55. * Set if joystick configuration has been acquired.
  56. *
  57. * @field BOOL | fCritInited:1 |
  58. *
  59. * Set if the critical section has been initialized.
  60. *
  61. * @field HKEY | hkTypesW |
  62. *
  63. * Read/write key to access the joystick types.
  64. * This key is created only while acquired.
  65. *
  66. * @field DWORD | idJoyCache |
  67. *
  68. * The identifier of the joystick in the effect shepherd cache,
  69. * if there is anything in the cache at all.
  70. *
  71. * @field IDirectInputEffectShepherd * | pes |
  72. *
  73. * The cached effect shepherd itself.
  74. *
  75. * @field LONG | cCrit |
  76. *
  77. * Number of times the critical section has been taken.
  78. * Used only in XDEBUG to check whether the caller is
  79. * releasing the object while another method is using it.
  80. *
  81. * @field DWORD | thidCrit |
  82. *
  83. * The thread that is currently in the critical section.
  84. * Used only in DEBUG for internal consistency checking.
  85. *
  86. * @field CRITICAL_SECTION | crst |
  87. *
  88. * Object critical section. Must be taken when accessing
  89. * volatile member variables.
  90. *
  91. *****************************************************************************/
  92. typedef struct CJoyCfg
  93. {
  94. /* Supported interfaces */
  95. IDirectInputJoyConfig8 djc;
  96. BOOL fAcquired:1;
  97. BOOL fCritInited:1;
  98. HKEY hkTypesW;
  99. HWND hwnd;
  100. DWORD discl;
  101. DWORD idJoyCache;
  102. LPDIRECTINPUTEFFECTSHEPHERD pes;
  103. RD(LONG cCrit;)
  104. D(DWORD thidCrit;)
  105. CRITICAL_SECTION crst;
  106. } CJoyCfg, JC, *PJC;
  107. typedef LPDIRECTINPUTJOYCONFIG8 PDJC;
  108. #define ThisClass CJoyCfg
  109. #define ThisInterface IDirectInputJoyConfig8
  110. #define ThisInterfaceT IDirectInputJoyConfig8
  111. /*****************************************************************************
  112. *
  113. * Forward references
  114. *
  115. * Not really needed; just a convenience, because Finalize
  116. * calls Unacquire to clean up in the case where the caller forgot.
  117. *
  118. *****************************************************************************/
  119. STDMETHODIMP CJoyCfg_InternalUnacquire(PV pdd);
  120. /*****************************************************************************
  121. *
  122. * @doc INTERNAL
  123. *
  124. * @func TCHAR | CJoyCfg_CharFromType |
  125. *
  126. * Convert a predefined type number to a character.
  127. *
  128. * @func UINT | CJoyCfg_TypeFromChar |
  129. *
  130. * Convert a character back to a predefined type number.
  131. *
  132. *****************************************************************************/
  133. #define CJoyCfg_CharFromType(t) ((TCHAR)(L'0' + t))
  134. #define CJoyCfg_TypeFromChar(tch) ((tch) - L'0')
  135. /*****************************************************************************
  136. *
  137. * @doc INTERNAL
  138. *
  139. * @method void | IDirectInputJoyConfig8 | EnterCrit |
  140. *
  141. * Enter the object critical section.
  142. *
  143. * @cwrap LPDIRECTINPUTJOYCONFIG8 | LPDIRECTINPUTJOYCONFIG8
  144. *
  145. *****************************************************************************/
  146. void INLINE
  147. CJoyCfg_EnterCrit(PJC this)
  148. {
  149. EnterCriticalSection(&this->crst);
  150. D(this->thidCrit = GetCurrentThreadId());
  151. RD(InterlockedIncrement(&this->cCrit));
  152. }
  153. /*****************************************************************************
  154. *
  155. * @doc INTERNAL
  156. *
  157. * @method void | IDirectInputJoyConfig8 | LeaveCrit |
  158. *
  159. * Leave the object critical section.
  160. *
  161. * @cwrap LPDIRECTINPUTJOYCONFIG8 | LPDIRECTINPUTJOYCONFIG8
  162. *
  163. *****************************************************************************/
  164. void INLINE
  165. CJoyCfg_LeaveCrit(PJC this)
  166. {
  167. #ifdef XDEBUG
  168. AssertF(this->cCrit);
  169. AssertF(this->thidCrit == GetCurrentThreadId());
  170. if(InterlockedDecrement(&this->cCrit) == 0)
  171. {
  172. D(this->thidCrit = 0);
  173. }
  174. #endif
  175. LeaveCriticalSection(&this->crst);
  176. }
  177. /*****************************************************************************
  178. *
  179. * @doc INTERNAL
  180. *
  181. * @mfunc BOOL | CJoyCfg | InCrit |
  182. *
  183. * Nonzero if we are in the critical section.
  184. *
  185. * @cwrap LPDIRECTINPUTJOYCONFIG8 | LPDIRECTINPUTJOYCONFIG8
  186. *
  187. *****************************************************************************/
  188. #ifdef DEBUG
  189. BOOL INTERNAL
  190. CJoyCfg_InCrit(PJC this)
  191. {
  192. return this->cCrit && this->thidCrit == GetCurrentThreadId();
  193. }
  194. #endif
  195. /*****************************************************************************
  196. *
  197. * @doc INTERNAL
  198. *
  199. * @method HRESULT | CJoyCfg | IsAcquired |
  200. *
  201. * Check that the device is acquired.
  202. *
  203. * @cwrap LPDIRECTINPUTJOYCONFIG8 | LPDIRECTINPUTJOYCONFIG8
  204. *
  205. * @returns
  206. *
  207. * Returns
  208. * <c S_OK> if all is well, or <c DIERR_NOTACQUIRED> if
  209. * the device is not acquired.
  210. *
  211. *
  212. *****************************************************************************/
  213. #ifndef XDEBUG
  214. \
  215. #define CJoyCfg_IsAcquired_(pdd, z) \
  216. _CJoyCfg_IsAcquired_(pdd) \
  217. #endif
  218. HRESULT INLINE
  219. CJoyCfg_IsAcquired_(PJC this, LPCSTR s_szProc)
  220. {
  221. HRESULT hres;
  222. if(this->fAcquired)
  223. {
  224. hres = S_OK;
  225. } else
  226. {
  227. RPF("ERROR %s: Not acquired", s_szProc);
  228. hres = DIERR_NOTACQUIRED;
  229. }
  230. return hres;
  231. }
  232. #define CJoyCfg_IsAcquired(pdd) \
  233. CJoyCfg_IsAcquired_(pdd, s_szProc) \
  234. /*****************************************************************************
  235. *
  236. * CJoyCfg::QueryInterface (from IUnknown)
  237. * CJoyCfg::AddRef (from IUnknown)
  238. * CJoyCfg::Release (from IUnknown)
  239. *
  240. *****************************************************************************/
  241. /*****************************************************************************
  242. *
  243. * @doc INTERNAL
  244. *
  245. * @method HRESULT | CJoyCfg | QueryInterface |
  246. *
  247. * Gives a client access to other interfaces on an object.
  248. *
  249. * @parm IN REFIID | riid |
  250. *
  251. * The requested interface's IID.
  252. *
  253. * @parm OUT LPVOID * | ppvObj |
  254. *
  255. * Receives a pointer to the obtained interface.
  256. *
  257. * @returns
  258. *
  259. * Returns a COM error code.
  260. *
  261. * @xref OLE documentation for <mf IUnknown::QueryInterface>.
  262. *
  263. *****************************************************************************
  264. *
  265. * @doc INTERNAL
  266. *
  267. * @method HRESULT | CJoyCfg | AddRef |
  268. *
  269. * Increments the reference count for the interface.
  270. *
  271. * @returns
  272. *
  273. * Returns the object reference count.
  274. *
  275. * @xref OLE documentation for <mf IUnknown::AddRef>.
  276. *
  277. *****************************************************************************
  278. *
  279. * @doc INTERNAL
  280. *
  281. * @method HRESULT | CJoyCfg | Release |
  282. *
  283. * Decrements the reference count for the interface.
  284. * If the reference count on the object falls to zero,
  285. * the object is freed from memory.
  286. *
  287. * @returns
  288. *
  289. * Returns the object reference count.
  290. *
  291. * @xref OLE documentation for <mf IUnknown::Release>.
  292. *
  293. *****************************************************************************
  294. *
  295. * @doc INTERNAL
  296. *
  297. * @method HRESULT | CJoyCfg | QIHelper |
  298. *
  299. * We don't have any dynamic interfaces and simply forward
  300. * to <f Common_QIHelper>.
  301. *
  302. * @parm IN REFIID | riid |
  303. *
  304. * The requested interface's IID.
  305. *
  306. * @parm OUT LPVOID * | ppvObj |
  307. *
  308. * Receives a pointer to the obtained interface.
  309. *
  310. *****************************************************************************
  311. *
  312. * @doc INTERNAL
  313. *
  314. * @method HRESULT | CJoyCfg | AppFinalize |
  315. *
  316. * We don't have any weak pointers, so we can just
  317. * forward to <f Common_Finalize>.
  318. *
  319. * @parm PV | pvObj |
  320. *
  321. * Object being released from the application's perspective.
  322. *
  323. *****************************************************************************/
  324. #ifdef DEBUG
  325. Default_QueryInterface(CJoyCfg)
  326. Default_AddRef(CJoyCfg)
  327. Default_Release(CJoyCfg)
  328. #else
  329. #define CJoyCfg_QueryInterface Common_QueryInterface
  330. #define CJoyCfg_AddRef Common_AddRef
  331. #define CJoyCfg_Release Common_Release
  332. #endif
  333. #define CJoyCfg_QIHelper Common_QIHelper
  334. #define CJoyCfg_AppFinalize Common_AppFinalize
  335. /*****************************************************************************
  336. *
  337. * @doc INTERNAL
  338. *
  339. * @method HRESULT | CJoyCfg | InternalUnacquire |
  340. *
  341. * Do the real work of an unacquire.
  342. *
  343. * See <mf IDirectInputJoyConfig8::Unacquire> for more
  344. * information.
  345. *
  346. * @cwrap LPDIRECTINPUTJOYCONFIG8 | LPDIRECTINPUTJOYCONFIG88
  347. *
  348. * @returns
  349. *
  350. * Returns a COM error code.
  351. * See <mf IDirectInputJoyConfig8::Unacquire> for more
  352. * information.
  353. *
  354. *****************************************************************************/
  355. STDMETHODIMP
  356. CJoyCfg_InternalUnacquire(PJC this)
  357. {
  358. HRESULT hres;
  359. EnterProc(CJoyCfg_InternalUnacquire, (_ "p", this));
  360. /*
  361. * Must protect with the critical section to prevent somebody from
  362. * interfering with us while we're unacquiring.
  363. */
  364. CJoyCfg_EnterCrit(this);
  365. if(this->fAcquired)
  366. {
  367. AssertF(this->hkTypesW);
  368. RegCloseKey(this->hkTypesW);
  369. this->hkTypesW = 0;
  370. Invoke_Release(&this->pes);
  371. Excl_Unacquire(&IID_IDirectInputJoyConfig, this->hwnd, this->discl);
  372. this->fAcquired = 0;
  373. hres = S_OK;
  374. } else
  375. {
  376. hres = S_FALSE;
  377. }
  378. CJoyCfg_LeaveCrit(this);
  379. ExitOleProc();
  380. return hres;
  381. }
  382. /*****************************************************************************
  383. *
  384. * @doc INTERNAL
  385. *
  386. * @func void | CJoyCfg_Finalize |
  387. *
  388. * Releases the resources of the device.
  389. *
  390. * @parm PV | pvObj |
  391. *
  392. * Object being released. Note that it may not have been
  393. * completely initialized, so everything should be done
  394. * carefully.
  395. *
  396. *****************************************************************************/
  397. void INTERNAL
  398. CJoyCfg_Finalize(PV pvObj)
  399. {
  400. PJC this = pvObj;
  401. #ifdef XDEBUG
  402. if(this->cCrit)
  403. {
  404. RPF("IDirectInputJoyConfig8::Release: Another thread is using the object; crash soon!");
  405. }
  406. #endif
  407. if(this->fAcquired)
  408. {
  409. CJoyCfg_InternalUnacquire(this);
  410. }
  411. AssertF(this->pes == 0);
  412. if(this->hkTypesW)
  413. {
  414. RegCloseKey(this->hkTypesW);
  415. }
  416. if(this->fCritInited)
  417. {
  418. DeleteCriticalSection(&this->crst);
  419. }
  420. }
  421. /*****************************************************************************
  422. *
  423. * @doc EXTERNAL
  424. *
  425. * @method HRESULT | IDirectInputJoyConfig8 | SetCooperativeLevel |
  426. *
  427. * Establish the cooperativity level for the instance of
  428. * the device.
  429. *
  430. * The only cooperative levels supported for the
  431. * <i IDirectInputJoyConfig8> interface are
  432. * <c DISCL_EXCLUSIVE> and <c DISCL_BACKGROUND>.
  433. *
  434. * @cwrap LPDIRECTINPUTJOYCONFIG8 | LPDIRECTINPUTJOYCONFIG8
  435. *
  436. * @parm HWND | hwnd |
  437. *
  438. * The window associated with the interface. This parameter
  439. * must be non-NULL and must be a top-level window.
  440. *
  441. * It is an error to destroy the window while it is still
  442. * associated with an <i IDirectInputJoyConfig8> interface.
  443. *
  444. * @parm DWORD | dwFlags |
  445. *
  446. * Flags which describe the cooperativity level associated
  447. * with the device.
  448. *
  449. * The value must be
  450. * <c DISCL_EXCLUSIVE> <vbar> <c DISCL_BACKGROUND>.
  451. *
  452. * @returns
  453. *
  454. * Returns a COM error code. The following error codes are
  455. * intended to be illustrative and not necessarily comprehensive.
  456. *
  457. * <c DI_OK> = <c S_OK>: The operation completed successfully.
  458. *
  459. * <c DIERR_INVALIDPARAM> = <c E_INVALIDARG>: The
  460. * <p hwnd> parameter is not a valid pointer.
  461. *
  462. *****************************************************************************/
  463. STDMETHODIMP
  464. CJoyCfg_SetCooperativeLevel(PDJC pdjc, HWND hwnd, DWORD dwFlags)
  465. {
  466. HRESULT hres;
  467. EnterProcR(IDirectInputJoyConfig8::SetCooperativityLevel,
  468. (_ "pxx", pdjc, hwnd, dwFlags));
  469. if(SUCCEEDED(hres = hresPv(pdjc)))
  470. {
  471. PJC this = _thisPvNm(pdjc, djc);
  472. if(dwFlags != (DISCL_EXCLUSIVE | DISCL_BACKGROUND))
  473. {
  474. RPF("%s: Cooperative level must be "
  475. "DISCL_EXCLUSIVE | DISCL_BACKGROUND", s_szProc);
  476. hres = E_NOTIMPL;
  477. } else if(GetWindowPid(hwnd) == GetCurrentProcessId())
  478. {
  479. this->hwnd = hwnd;
  480. this->discl = dwFlags;
  481. hres = S_OK;
  482. } else
  483. {
  484. RPF("ERROR %s: window must belong to current process", s_szProc);
  485. hres = E_HANDLE;
  486. }
  487. }
  488. ExitOleProcR();
  489. return hres;
  490. }
  491. /*****************************************************************************
  492. *
  493. * @doc EXTERNAL
  494. *
  495. * @method HRESULT | IDirectInputJoyConfig8 | Acquire |
  496. *
  497. * Acquire "joystick configuration mode". Only one application can
  498. * be in joystick configuration mode at a time; subsequent
  499. * applications will receive the error <c DIERR_OTHERAPPHASPRIO>.
  500. *
  501. * After entering configuration mode, the application may
  502. * make alterations to the global joystick configuration
  503. * settings. It is encouraged that the application
  504. * re-check the existing settings before installing the new
  505. * ones in case another application had changed the settings
  506. * in the interim.
  507. *
  508. * @cwrap LPDIRECTINPUTJOYCONFIG8 | LPDIRECTINPUTJOYCONFIG8
  509. *
  510. * @returns
  511. *
  512. * Returns a COM error code. The following error codes are
  513. * intended to be illustrative and not necessarily comprehensive.
  514. *
  515. * <c DI_OK> = <c S_OK>: The operation completed successfully.
  516. *
  517. * <c DIERR_OTHERAPPHASPRIO>: Another application is already
  518. * in joystick configuration mode.
  519. *
  520. * <c DIERR_INSUFFICIENTPRIVS>: The current user does not have
  521. * the necessary permissions to alter the joystick configuration.
  522. *
  523. * <c DIERR_DEVICECHANGE>: Another application has changed
  524. * the global joystick configuration. The interface needs
  525. * to be re-initialized.
  526. *
  527. *****************************************************************************/
  528. STDMETHODIMP
  529. CJoyCfg_Acquire(PDJC pdjc)
  530. {
  531. HRESULT hres;
  532. EnterProcR(IDirectInputJoyConfig8::Acquire, (_ "p", pdjc));
  533. if(SUCCEEDED(hres = hresPv(pdjc)))
  534. {
  535. PJC this = _thisPvNm(pdjc, djc);
  536. /*
  537. * Must protect with the critical section to prevent somebody from
  538. * acquiring or changing the data format while we're acquiring.
  539. */
  540. CJoyCfg_EnterCrit(this);
  541. if(this->discl == 0)
  542. {
  543. RPF("%s: Cooperative level not yet set", s_szProc);
  544. hres = E_FAIL;
  545. goto done;
  546. }
  547. if(this->fAcquired)
  548. {
  549. AssertF(this->hkTypesW);
  550. hres = S_FALSE;
  551. } else if(SUCCEEDED(hres = Excl_Acquire(&IID_IDirectInputJoyConfig,
  552. this->hwnd, this->discl)))
  553. {
  554. AssertF(this->hkTypesW == 0);
  555. hres = hresMumbleKeyEx(HKEY_LOCAL_MACHINE,
  556. REGSTR_PATH_JOYOEM,
  557. DI_KEY_ALL_ACCESS,
  558. REG_OPTION_NON_VOLATILE,
  559. &this->hkTypesW);
  560. if(SUCCEEDED(hres) )
  561. {
  562. this->fAcquired = 1;
  563. } else
  564. {
  565. RegCloseKey(this->hkTypesW);
  566. this->hkTypesW = 0;
  567. hres = DIERR_INSUFFICIENTPRIVS;
  568. }
  569. }
  570. done:;
  571. CJoyCfg_LeaveCrit(this);
  572. }
  573. ExitOleProcR();
  574. return hres;
  575. }
  576. /*****************************************************************************
  577. *
  578. * @doc EXTERNAL
  579. *
  580. * @method HRESULT | IDirectInputJoyConfig8 | Unacquire |
  581. *
  582. * Unacquire "joystick configuration mode". Before unacquiring
  583. * configuration mode, the application must perform an
  584. * <mf IDirectInputJoyConfig8::SendNotify> to propagate
  585. * the changes in the joystick configuration
  586. * to all device drivers and applications.
  587. *
  588. * Applications which hold interfaces to a joystick which is
  589. * materially affected by a change in configuration will
  590. * receive the <c DIERR_DEVICECHANGE> error code until the
  591. * device is re-initialized.
  592. *
  593. * Examples of material changes to configuration include
  594. * altering the number of axes or the number of buttons.
  595. * In comparison, changes to device calibration
  596. * are handled internally by
  597. * DirectInput and are transparent to the application.
  598. *
  599. * @cwrap LPDIRECTINPUTJOYCONFIG8 | LPDIRECTINPUTJOYCONFIG8
  600. *
  601. * @returns
  602. *
  603. * Returns a COM error code. The following error codes are
  604. * intended to be illustrative and not necessarily comprehensive.
  605. *
  606. * <c DI_OK> = <c S_OK>: The operation completed successfully.
  607. *
  608. * <c DIERR_NOTACQUIRED>: Joystick configuration mode was
  609. * not acquired.
  610. *
  611. *****************************************************************************/
  612. STDMETHODIMP
  613. CJoyCfg_Unacquire(PDJC pdjc)
  614. {
  615. HRESULT hres;
  616. EnterProcR(IDirectInputJoyConfig8::Unacquire, (_ "p", pdjc));
  617. if(SUCCEEDED(hres = hresPv(pdjc)))
  618. {
  619. PJC this = _thisPvNm(pdjc, djc);
  620. hres = CJoyCfg_InternalUnacquire(this);
  621. }
  622. ExitOleProcR();
  623. return hres;
  624. }
  625. /*****************************************************************************
  626. *
  627. * @doc EXTERNAL
  628. *
  629. * @method HRESULT | IDirectInputJoyConfig8 | SendNotify |
  630. *
  631. * Notifies device drivers and applications that changes to
  632. * the device configuration have been made. An application
  633. * which changes device configurations must invoke this
  634. * method after the changes have been made (and before
  635. * unacquiring).
  636. *
  637. * @cwrap LPDIRECTINPUTJOYCONFIG8 | LPDIRECTINPUTJOYCONFIG8
  638. *
  639. * @returns
  640. *
  641. * Returns a COM error code. The following error codes are
  642. * intended to be illustrative and not necessarily comprehensive.
  643. *
  644. * <c DI_OK> = <c S_OK>: The operation completed successfully.
  645. *
  646. * <c DIERR_NOTACQUIRED>: Joystick configuration mode was
  647. * not acquired.
  648. *
  649. *****************************************************************************/
  650. STDMETHODIMP
  651. CJoyCfg_SendNotify(PDJC pdjc)
  652. {
  653. HRESULT hres;
  654. EnterProcR(IDirectInputJoyConfig8::SendNotify, (_ "p", pdjc));
  655. if(SUCCEEDED(hres = hresPv(pdjc)))
  656. {
  657. PJC this = _thisPvNm(pdjc, djc);
  658. CJoyCfg_EnterCrit(this);
  659. if(this->fAcquired)
  660. {
  661. #ifdef WINNT
  662. Excl_SetConfigChangedTime( GetTickCount() );
  663. PostMessage(HWND_BROADCAST, g_wmJoyChanged, 0, 0L);
  664. #else
  665. joyConfigChanged(0);
  666. #endif
  667. /*
  668. * If we don't have a joyConfigChanged, it's probably just
  669. * because we're running on NT and don't need it.
  670. */
  671. hres = S_OK;
  672. } else
  673. {
  674. hres = DIERR_NOTACQUIRED;
  675. }
  676. CJoyCfg_LeaveCrit(this);
  677. }
  678. ExitOleProcR();
  679. return hres;
  680. }
  681. /*****************************************************************************
  682. *
  683. * @doc INTERNAL
  684. *
  685. * @func HRESULT | JoyCfg_ConvertCurrentConfigs |
  686. *
  687. * Converts any OEMType name matching the first input string and
  688. * replaces it with the other input string.
  689. *
  690. * @parm IN LPTSTR | szFindType |
  691. *
  692. * String to match.
  693. *
  694. * @parm IN LPTSTR | szReplaceType |
  695. *
  696. * String to replace any matches instances.
  697. *
  698. * @returns
  699. *
  700. * A COM success code unless the current configuration key could not
  701. * be opened, or a type that needed to be replaced could not be
  702. * overwritten.
  703. *
  704. *****************************************************************************/
  705. HRESULT JoyCfg_ConvertCurrentConfigs( LPTSTR szFindType, LPTSTR szReplaceType )
  706. {
  707. HRESULT hres;
  708. LONG lRc;
  709. HKEY hkCurrCfg;
  710. UINT JoyId;
  711. TCHAR szTestType[MAX_JOYSTRING];
  712. TCHAR szTypeName[MAX_JOYSTRING];
  713. DWORD cb;
  714. EnterProcI(JoyCfg_ConvertCurrentConfigs, (_ "ss", szFindType, szReplaceType ));
  715. hres = JoyReg_OpenConfigKey( (UINT)(-1), KEY_WRITE, REG_OPTION_NON_VOLATILE, &hkCurrCfg );
  716. if( SUCCEEDED( hres ) )
  717. {
  718. for( JoyId = 0; (JoyId < 16) || ( lRc == ERROR_SUCCESS ); JoyId++ )
  719. {
  720. wsprintf( szTypeName, REGSTR_VAL_JOYNOEMNAME, JoyId+1 );
  721. cb = sizeof( szTestType );
  722. lRc = RegQueryValueEx( hkCurrCfg, szTypeName, 0, NULL, (PBYTE)szTestType, &cb );
  723. if( lRc == ERROR_SUCCESS )
  724. {
  725. if( !lstrcmpi( szTestType, szFindType ) )
  726. {
  727. cb = sizeof( szReplaceType) * (1 + lstrlen( szReplaceType ));
  728. lRc = RegSetValueEx( hkCurrCfg, szTypeName, 0, REG_SZ, (PBYTE)szReplaceType, cb );
  729. if( lRc != ERROR_SUCCESS )
  730. {
  731. SquirtSqflPtszV(sqfl | sqflError,
  732. TEXT("RegSetValueEx failed to replace type of %s 0x%08x"),
  733. szTypeName, lRc );
  734. /* This is the only error that counts as an error in this loop */
  735. hres = hresReg( lRc );
  736. }
  737. }
  738. }
  739. }
  740. }
  741. else
  742. {
  743. SquirtSqflPtszV(sqfl | sqflError,
  744. TEXT("JoyReg_OpenConfigKey failed code 0x%08x"), hres );
  745. }
  746. ExitOleProc();
  747. return hres;
  748. } /* JoyCfg_ConvertCurrentConfigs */
  749. #ifdef WINNT
  750. /*****************************************************************************
  751. *
  752. * @doc INTERNAL
  753. *
  754. * @func HRESULT | JoyCfg_FixHardwareId |
  755. *
  756. * Fixes the hardwareId for an analog type by assinging a VID/PID to
  757. * it and recreating the type using that hardwareId.
  758. *
  759. * @parm IN HKEY | hkTypesR |
  760. *
  761. * Handle of key opened to the root of types.
  762. *
  763. * @parm IN HKEY | hkSrc |
  764. *
  765. * Handle of key opened to the original type.
  766. *
  767. * @parm IN PTCHAR | ptszPrefName |
  768. *
  769. * VID&PID name from the HardwareID if present, NULL otherwise
  770. *
  771. * @returns
  772. *
  773. * Returns a COM error code. The following error codes are
  774. * intended to be illustrative and not necessarily comprehensive.
  775. *
  776. * <c DI_OK> = <c S_OK>: The key is valid
  777. * <c DI_NOEFFECT> = <c S_FALSE> The key should be ignored
  778. *
  779. * <c OLE_E_ENUM_NOMORE> = The key has been fixed but enumeration
  780. * must be restarted.
  781. * <c DIERR_OUTOFMEMORY> = <c E_OUTOFMEMORY>: Out of memory.
  782. *
  783. *****************************************************************************/
  784. HRESULT INTERNAL
  785. JoyCfg_FixHardwareId( HKEY hkTypesR, HKEY hkSrc, PTCHAR szSrcType , PTCHAR ptszPrefName)
  786. {
  787. HRESULT hres;
  788. HKEY hkNew;
  789. BYTE PIDlow;
  790. DWORD ClassLen;
  791. PTCHAR szClassName;
  792. TCHAR szDestType[sizeof( ANALOG_ID_ROOT ) + 2]; //Two digits will be appended
  793. TCHAR szHardwareId[MAX_JOYSTRING];
  794. EnterProcI(JoyCfg_FixHardwareId, (_ "xxs", hkTypesR, hkSrc, szSrcType));
  795. hres = hresReg( RegQueryInfoKey( hkSrc, // handle to key to query
  796. NULL, // Class
  797. &ClassLen, // ClassLen
  798. NULL, // Reserved
  799. NULL, NULL, NULL, // NumSubKeys, MaxSubKeyLen, MaxClassLen
  800. NULL, NULL, NULL, // NumValues, MaxValueNameLen, MaxValueLen
  801. NULL, NULL ) ); // Security descriptor, last write
  802. if( SUCCEEDED( hres ) )
  803. {
  804. ClassLen++;
  805. /*
  806. * Part of mb:34633 (see below, 2 comments) was that prefix considers
  807. * the case of zero bytes being requested in the following call so
  808. * assert that we always ask for some memory otherwise checking the
  809. * result does not guarantee that the pointer is valid.
  810. */
  811. AssertF( ClassLen * sizeof(szClassName[0]) );
  812. hres = AllocCbPpv( ClassLen * sizeof(szClassName[0]), &szClassName );
  813. if( SUCCEEDED( hres ) )
  814. {
  815. hres = hresReg( RegQueryInfoKey( hkSrc, // handle to key to query
  816. szClassName, // Class
  817. &ClassLen, // ClassLen
  818. NULL, // Reserved
  819. NULL, NULL, NULL, // NumSubKeys, MaxSubKeyLen, MaxClassLen
  820. NULL, NULL, NULL, // NumValues, MaxValueNameLen, MaxValueLen
  821. NULL, NULL ) ); // Security descriptor, last write
  822. if( FAILED( hres ) )
  823. {
  824. SquirtSqflPtszV(sqfl | sqflError,
  825. TEXT("RegQueryInfoKey on type %s for class name failed 0x%04x"),
  826. szSrcType, LOWORD(hres) );
  827. }
  828. }
  829. else
  830. {
  831. SquirtSqflPtszV(sqfl | sqflError,
  832. TEXT("Failed to allocate %d bytes for class name of type %s, error 0x%04x"),
  833. ClassLen, szSrcType, LOWORD(hres) );
  834. }
  835. }
  836. else
  837. {
  838. SquirtSqflPtszV(sqfl | sqflError,
  839. TEXT("RegQueryInfoKey on type %s for class name length failed 0x%04x"),
  840. szSrcType, LOWORD(hres) );
  841. /* Make sure not to free an uninitialized pointer */
  842. szClassName = NULL;
  843. }
  844. if( SUCCEEDED( hres ) )
  845. {
  846. for( PIDlow = JOY_HW_PREDEFMAX+1; PIDlow; PIDlow++ )
  847. {
  848. if (ptszPrefName)
  849. {
  850. lstrcpy( szDestType, ptszPrefName);
  851. #ifdef UNICODE
  852. CharUpperW(szDestType);
  853. #else
  854. CharUpper(szDestType);
  855. #endif
  856. }
  857. else
  858. {
  859. wsprintf( szDestType, TEXT("%s%02X"), ANALOG_ID_ROOT, PIDlow );
  860. }
  861. hres = hresRegCopyKey( hkTypesR, szSrcType, szClassName, hkTypesR, szDestType, &hkNew );
  862. if( hres == S_OK )
  863. {
  864. /*
  865. * Prefix warns that hkNew may be uninitialized (mb:34633)
  866. * however hresRegCopyKey only returns a SUCCESS if hkNew
  867. * is initialized to an opened key handle.
  868. */
  869. hres = hresRegCopyBranch( hkSrc, hkNew );
  870. if( SUCCEEDED( hres ) )
  871. {
  872. if (!ptszPrefName)
  873. {
  874. #ifdef MULTI_SZ_HARDWARE_IDS
  875. /*
  876. * Make up the hardwareId using the assigned PID with a generic hardwareId appended
  877. */
  878. int CharIdx = 0;
  879. while( TRUE )
  880. {
  881. CharIdx += wsprintf( &szHardwareId[CharIdx], TEXT("%s%s%02X"), TEXT("GamePort\\"), ANALOG_ID_ROOT, PIDlow );
  882. CharIdx++; /* Leave NULL terminator in place */
  883. if( PIDlow )
  884. {
  885. PIDlow = 0; /* Trash this value to make the generic PID on second iteration */
  886. }
  887. else
  888. {
  889. break;
  890. }
  891. }
  892. szHardwareId[CharIdx++] = TEXT('\0'); /* MULTI_SZ */
  893. hres = hresReg( RegSetValueEx( hkNew, REGSTR_VAL_JOYOEMHARDWAREID, 0,
  894. REG_MULTI_SZ, (PBYTE)szHardwareId, (DWORD)( sizeof(szHardwareId[0]) * CharIdx ) ) );
  895. if( FAILED( hres ) )
  896. {
  897. SquirtSqflPtszV(sqfl | sqflBenign,
  898. TEXT("JoyCfg_FixHardwareId: failed to write hardware ID %s"), szHardwareId );
  899. }
  900. #else
  901. /*
  902. * Make up the hardwareId using the assigned PID
  903. */
  904. int CharIdx = 0;
  905. CharIdx = wsprintf( szHardwareId, TEXT("%s%s%02X"), TEXT("GamePort\\"), ANALOG_ID_ROOT, PIDlow );
  906. CharIdx++; /* Leave NULL terminator in place */
  907. hres = hresReg( RegSetValueEx( hkNew, REGSTR_VAL_JOYOEMHARDWAREID, 0,
  908. REG_SZ, (PBYTE)szHardwareId, (DWORD)( sizeof(szHardwareId[0]) * CharIdx ) ) );
  909. if( FAILED( hres ) )
  910. {
  911. SquirtSqflPtszV(sqfl | sqflBenign,
  912. TEXT("JoyCfg_FixHardwareId: failed to write hardware ID %s"), szHardwareId );
  913. }
  914. #endif
  915. }
  916. }
  917. /*
  918. * Prefix warns that hkNew may be uninitialized (mb:34633)
  919. * however hresRegCopyKey only returns a SUCCESS if hkNew
  920. * is initialized to an opened key handle.
  921. */
  922. RegCloseKey( hkNew );
  923. if( SUCCEEDED( hres ) )
  924. {
  925. hres = JoyCfg_ConvertCurrentConfigs( szSrcType, szDestType );
  926. }
  927. DIWinnt_RegDeleteKey( hkTypesR, ( SUCCEEDED( hres ) ) ? szSrcType
  928. : szDestType );
  929. break;
  930. }
  931. else if( SUCCEEDED( hres ) )
  932. {
  933. /*
  934. * Prefix warns that hkNew may be uninitialized (mb:37926)
  935. * however hresRegCopyKey only returns a SUCCESS if hkNew
  936. * is initialized to an opened key handle.
  937. */
  938. /*
  939. * The key already existed so keep looking
  940. */
  941. RegCloseKey( hkNew );
  942. }
  943. else
  944. {
  945. /*
  946. * RegCopyKey should have already posted errors
  947. */
  948. break;
  949. }
  950. }
  951. if( !PIDlow )
  952. {
  953. SquirtSqflPtszV(sqfl | sqflBenign,
  954. TEXT("JoyCfg_FixHardwareId: no free analog keys for type %s"),
  955. szSrcType );
  956. hres = DIERR_NOTFOUND;
  957. }
  958. }
  959. if( szClassName )
  960. {
  961. FreePpv( &szClassName );
  962. }
  963. ExitOleProc();
  964. return( hres );
  965. } /* JoyCfg_FixHardwareId */
  966. #endif
  967. /*****************************************************************************
  968. *
  969. * @doc INTERNAL
  970. *
  971. * @func HRESULT | JoyCfg_CheckTypeKey |
  972. *
  973. * Checks the contents of a type key for validity on the current OS
  974. * and if not valid, try to make it so.
  975. *
  976. * Only custom analog types can be fixed and this only needs to be
  977. * done on a WDM enabled OS as non-WDM requirements are a sub-set of
  978. * the WDM ones.
  979. *
  980. * @parm IN HKEY | hkTypesR |
  981. *
  982. * Handle of key opened to the root of types.
  983. *
  984. * @parm IN LPTSTR | szType |
  985. *
  986. * Receives a pointer either an ansi or UNICODE key name to test.
  987. *
  988. * @returns
  989. *
  990. * Returns a COM error code. The following error codes are
  991. * intended to be illustrative and not necessarily comprehensive.
  992. *
  993. * <c DI_OK> = <c S_OK>: The key is valid
  994. * <c DI_NOEFFECT> = <c S_FALSE> The key should be ignored
  995. *
  996. * <c OLE_E_ENUM_NOMORE> = The key has been fixed but enumeration
  997. * must be restarted.
  998. * <c DIERR_OUTOFMEMORY> = <c E_OUTOFMEMORY>: Out of memory.
  999. *
  1000. *****************************************************************************/
  1001. HRESULT INTERNAL
  1002. JoyCfg_CheckTypeKey( HKEY hkTypesR, LPTSTR szType )
  1003. {
  1004. HRESULT hres;
  1005. HKEY hk;
  1006. LONG lRc;
  1007. DWORD cb;
  1008. TCHAR tszCallout[MAX_JOYSTRING];
  1009. TCHAR tszHardwareId[MAX_JOYSTRING];
  1010. #ifdef WINNT
  1011. JOYREGHWSETTINGS hws;
  1012. TCHAR* ptszLastSlash=NULL;
  1013. #endif
  1014. EnterProcI(JoyCfg_CheckTypeKey, (_ "xs",hkTypesR, szType));
  1015. /*
  1016. * Open read only just in case we don't have better permission to any
  1017. * of the type sub-keys.
  1018. */
  1019. lRc = RegOpenKeyEx( hkTypesR, szType, 0, KEY_QUERY_VALUE | KEY_ENUMERATE_SUB_KEYS, &hk );
  1020. if(lRc == ERROR_SUCCESS )
  1021. {
  1022. /*
  1023. * Gather the needed results using standard registry functions so
  1024. * that the exact return code is known.
  1025. */
  1026. lRc = RegQueryValueEx(hk, REGSTR_VAL_JOYOEMNAME, NULL, NULL, NULL, NULL );
  1027. #ifdef WINNT
  1028. if(lRc == ERROR_SUCCESS )
  1029. {
  1030. cb = cbX(hws);
  1031. lRc = RegQueryValueEx(hk, REGSTR_VAL_JOYOEMDATA, NULL, NULL, (PBYTE)&hws, &cb );
  1032. if( ( lRc == ERROR_SUCCESS ) && ( hws.dwFlags & JOY_HWS_AUTOLOAD ) )
  1033. {
  1034. /*
  1035. * WARNING goto
  1036. * If we have a name and JOY_HWS_AUTOLOAD is set, that's all we need
  1037. */
  1038. RegCloseKey( hk );
  1039. hres = S_OK;
  1040. goto fast_out;
  1041. }
  1042. if( lRc == ERROR_FILE_NOT_FOUND )
  1043. {
  1044. hws.dwFlags = 0;
  1045. lRc = ERROR_SUCCESS;
  1046. }
  1047. }
  1048. #endif
  1049. if(lRc == ERROR_SUCCESS )
  1050. {
  1051. cb = cbX(tszCallout);
  1052. lRc = RegQueryValueEx(hk, REGSTR_VAL_JOYOEMCALLOUT, NULL, NULL, (PBYTE)tszCallout, &cb );
  1053. if( lRc == ERROR_FILE_NOT_FOUND )
  1054. {
  1055. tszCallout[0] = TEXT('\0');
  1056. lRc = ERROR_SUCCESS;
  1057. }
  1058. }
  1059. if(lRc == ERROR_SUCCESS )
  1060. {
  1061. cb = cbX(tszHardwareId);
  1062. lRc = RegQueryValueEx(hk, REGSTR_VAL_JOYOEMHARDWAREID, NULL, NULL, (PBYTE)tszHardwareId, &cb );
  1063. if( lRc == ERROR_FILE_NOT_FOUND )
  1064. {
  1065. tszHardwareId[0] = TEXT('\0');
  1066. lRc = ERROR_SUCCESS;
  1067. }
  1068. #ifdef WINNT
  1069. else
  1070. {
  1071. TCHAR* ptsz;
  1072. for (ptsz = tszHardwareId;*ptsz!='\0';++ptsz)
  1073. {
  1074. if (*ptsz == '\\')
  1075. {
  1076. ptszLastSlash = ptsz;
  1077. }
  1078. }
  1079. if (ptszLastSlash)
  1080. {
  1081. ptszLastSlash++; //next char is the one we want
  1082. }
  1083. }
  1084. #endif
  1085. }
  1086. if(lRc != ERROR_SUCCESS )
  1087. {
  1088. RegCloseKey( hk );
  1089. }
  1090. }
  1091. if(lRc == ERROR_SUCCESS )
  1092. {
  1093. #ifdef WINNT
  1094. SHORT DontCare;
  1095. #endif
  1096. WCHAR wszType[18];
  1097. TToU( wszType, cA(wszType),szType );
  1098. /*
  1099. * Work out the status of this type based on the OS and the registry data
  1100. *
  1101. * Note on 98 we allow WDM types to be enumerated but do not convert
  1102. * analog types to WDM. We may want to convert analog types if we get
  1103. * WDM gameport drivers appear for gameports that are incompatible with
  1104. * msanalog.
  1105. */
  1106. #define HAS_VIDPID ( ParseVIDPID( &DontCare, &DontCare, wszType ) )
  1107. #define HAS_HARDWARE_ID ( tszHardwareId[0] != TEXT('\0') )
  1108. #define HAS_OEMCALLOUT ( tszCallout[0] != TEXT('\0') )
  1109. #define IS_ANALOG \
  1110. ( tszHardwareId[ sizeof( ANALOG_ID_ROOT ) - 1 ] = TEXT('\0'), \
  1111. ( !lstrcmpi( tszHardwareId, ANALOG_ID_ROOT ) ) )
  1112. #define IS_WIN98 (HidD_GetHidGuid)
  1113. #ifdef WINNT
  1114. if (HAS_HARDWARE_ID)
  1115. {
  1116. //Need to check if there is a VID and PID in the HW ID
  1117. if (ParseVIDPID(&DontCare, &DontCare, ptszLastSlash))
  1118. {
  1119. //If the type VIDPID doesn't match the HardwareId VIDPID
  1120. //we need to fix it
  1121. if (!lstrcmpi(ptszLastSlash,wszType))
  1122. {
  1123. SquirtSqflPtszV(sqfl | sqflVerbose,
  1124. TEXT("OEMHW %s(%s) and/or Type %s have matching VID/PID"),
  1125. tszHardwareId,ptszLastSlash,wszType);
  1126. hres = S_OK;
  1127. }
  1128. else
  1129. {
  1130. hres = OLE_E_ENUM_NOMORE;
  1131. SquirtSqflPtszV(sqfl | sqflVerbose,
  1132. TEXT("OEMHW %s(%s) and/or Type %s have non-matching VID/PID. Fix Needed."),
  1133. tszHardwareId,ptszLastSlash,wszType);
  1134. }
  1135. }
  1136. else
  1137. {
  1138. hres = S_OK; //no VIDPID in the type
  1139. SquirtSqflPtszV(sqfl | sqflVerbose,
  1140. TEXT("OEMHW %s(%s) and/or Type %s have no VID/PID"),
  1141. tszHardwareId,ptszLastSlash,wszType);
  1142. }
  1143. }
  1144. else
  1145. {
  1146. if (HAS_VIDPID)
  1147. {
  1148. hres = DIERR_MOREDATA;
  1149. }
  1150. else
  1151. {
  1152. if (HAS_OEMCALLOUT)
  1153. {
  1154. hres = S_FALSE;
  1155. }
  1156. else
  1157. {
  1158. hres = OLE_E_ENUM_NOMORE;
  1159. }
  1160. }
  1161. }
  1162. #else
  1163. hres = (IS_WIN98) ? S_OK /* Anything goes on 98 */
  1164. : (HAS_OEMCALLOUT) ? S_OK /* Win9x device, OK */
  1165. : (HAS_HARDWARE_ID) ? (IS_ANALOG) ? S_OK /* Analog type, OK */
  1166. : S_FALSE /* WDM device, ignore */
  1167. : S_OK; /* Analog type, OK */
  1168. #endif
  1169. switch( hres )
  1170. {
  1171. #ifdef WINNT
  1172. case DIERR_MOREDATA:
  1173. /*
  1174. * The device is not marked as autoload but has a VID/PID type
  1175. * name. If the OEMCallout is blank or "joyhid.vxd" we'll assume
  1176. * the type should be autoload and correct it.
  1177. * If there's any other value, we could assume either that we
  1178. * have a bogus Win9x driver type key and hide it or that the
  1179. * device is autoload.
  1180. * Safest route, now that our expose code is smart enough to not
  1181. * expose a device without a hardware ID, is to enumerate it as
  1182. * non-autoload as Win2k did. It won't work if you try to add
  1183. * it but at least the type will be enumerated if the device
  1184. * does show up from PnP (so nobody will get confused by a
  1185. * device without a type).
  1186. *
  1187. * ISSUE-2001/01/04-MarcAnd should use common joyhid string
  1188. * Not sure if the compiler/linker will resolve the various
  1189. * instances of L"joyhid.vxd" to a single string. Should
  1190. * reference the same one to be certain.
  1191. */
  1192. if( !HAS_OEMCALLOUT
  1193. || ( !lstrcmpi( tszCallout, L"joyhid.vxd" ) ) )
  1194. {
  1195. HKEY hkSet;
  1196. /*
  1197. * Need to open a new handle for the key as the one we have
  1198. * is read-only.
  1199. */
  1200. lRc = RegOpenKeyEx( hkTypesR, szType, 0, KEY_SET_VALUE, &hkSet );
  1201. if( lRc == ERROR_SUCCESS )
  1202. {
  1203. hws.dwFlags |= JOY_HWS_AUTOLOAD;
  1204. cb = cbX(hws);
  1205. lRc = RegSetValueEx( hkSet, REGSTR_VAL_JOYOEMDATA, 0,
  1206. REG_BINARY, (PBYTE)&hws, (DWORD)( cbX(hws) ) );
  1207. if( lRc == ERROR_SUCCESS )
  1208. {
  1209. SquirtSqflPtszV(sqfl | sqflTrace,
  1210. TEXT("FIXED Type %s to have JOY_HWS_AUTOLOAD"), szType );
  1211. }
  1212. else
  1213. {
  1214. SquirtSqflPtszV(sqfl | sqflBenign,
  1215. TEXT("Failed to set JOY_HWS_AUTOLOAD on Type %s (rc=%d,le=%d)"),
  1216. szType, lRc, GetLastError() );
  1217. }
  1218. RegCloseKey( hkSet );
  1219. }
  1220. else
  1221. {
  1222. SquirtSqflPtszV(sqfl | sqflBenign,
  1223. TEXT("Failed to open Type %s to fix JOY_HWS_AUTOLOAD(rc=%d,le=%d)"),
  1224. szType, lRc, GetLastError() );
  1225. }
  1226. }
  1227. else
  1228. {
  1229. SquirtSqflPtszV(sqfl | sqflBenign,
  1230. TEXT("Type %s with OEMCallout<%s> has no HardwareId so cannot be added"),
  1231. szType, tszCallout );
  1232. }
  1233. /*
  1234. * Whether or not we fixed this, we want to enumerate the key.
  1235. */
  1236. hres = S_OK;
  1237. break;
  1238. case OLE_E_ENUM_NOMORE:
  1239. {
  1240. HRESULT hres0;
  1241. hres0 = JoyCfg_FixHardwareId( hkTypesR, hk, szType , ptszLastSlash);
  1242. if( FAILED( hres0 ) )
  1243. {
  1244. /*
  1245. * Failed to fix type it must be ignored to avoid an infinite loop
  1246. */
  1247. SquirtSqflPtszV(sqfl | sqflBenign,
  1248. TEXT("Ignoring type %s as fix failed"), szType );
  1249. hres = S_FALSE;
  1250. }
  1251. else
  1252. {
  1253. SquirtSqflPtszV(sqfl | sqflTrace,
  1254. TEXT("FIXED Type %s with HardwareId<%s> and OEMCallout<%s>"),
  1255. szType, tszHardwareId, tszCallout );
  1256. }
  1257. }
  1258. break;
  1259. #endif
  1260. case S_FALSE:
  1261. SquirtSqflPtszV(sqfl | sqflBenign,
  1262. TEXT("Ignoring type %s with HardwareId<%s> and OEMCallout<%s>"),
  1263. szType, tszHardwareId, tszCallout );
  1264. break;
  1265. case S_OK:
  1266. SquirtSqflPtszV(sqfl | sqflTrace,
  1267. TEXT("Enumerating type %s with HardwareId<%s> and OEMCallout<%s>"),
  1268. szType, tszHardwareId, tszCallout );
  1269. break;
  1270. }
  1271. RegCloseKey( hk );
  1272. #undef HAS_VIDPID
  1273. #undef HAS_HARDWARE_ID
  1274. #undef HAS_OEMCALLOUT
  1275. #undef IS_ANALOG
  1276. #undef IS_WIN98
  1277. }
  1278. else
  1279. {
  1280. SquirtSqflPtszV(sqfl | sqflBenign,
  1281. TEXT("Ignoring type %s due to registry error 0x%08x"), szType, lRc );
  1282. /*
  1283. * It seems a bit bogus, to return success for an error but this
  1284. * makes sure the key is ignored and enumeration will proceed.
  1285. */
  1286. hres = S_FALSE;
  1287. }
  1288. #ifdef WINNT
  1289. fast_out:;
  1290. #endif
  1291. ExitOleProc();
  1292. return( hres );
  1293. } /* JoyCfg_CheckTypeKey */
  1294. /*****************************************************************************
  1295. *
  1296. * @doc INTERNAL
  1297. *
  1298. * @method HRESULT | CDIJoyCfg | SnapTypes |
  1299. *
  1300. * Snapshot the list of subkeys for OEM types.
  1301. *
  1302. * @cwrap LPDIRECTINPUTJOYCONFIG8 | LPDIRECTINPUTJOYCONFIG8
  1303. *
  1304. * @parm OUT LPWSTR * | ppwszz |
  1305. *
  1306. * Receives a pointer to a UNICODEZZ
  1307. * list of type names. Note that the returned list
  1308. * is pre-populated with the predefined types, too.
  1309. *
  1310. * We need to snapshot the names up front because
  1311. * the caller might create or delete OEM types during the
  1312. * enumeration.
  1313. *
  1314. * As we enumerate we check each key for validity and repair any
  1315. * analog custom configurations that we can.
  1316. *
  1317. * @returns
  1318. *
  1319. * Returns a COM error code. The following error codes are
  1320. * intended to be illustrative and not necessarily comprehensive.
  1321. *
  1322. * <c DI_OK> = <c S_OK>: The operation completed successfully.
  1323. *
  1324. * <c DIERR_OUTOFMEMORY> = <c E_OUTOFMEMORY>: Out of memory.
  1325. *
  1326. *****************************************************************************/
  1327. HRESULT INTERNAL
  1328. CJoyCfg_SnapTypes(PJC this, LPWSTR *ppwszz)
  1329. {
  1330. HRESULT hres;
  1331. LONG lRc;
  1332. HKEY hkTypesR;
  1333. DWORD chkSub;
  1334. BOOL fRetry;
  1335. EnterProcI(CJoyCfg_SnapTypes, (_ "p", this));
  1336. RD(*ppwszz = 0);
  1337. /*
  1338. * If an analog configuration needs to be fixed, the enumeration is
  1339. * restarted because adding/removing keys may mess with the key indicies.
  1340. * Since registry keys can go stale, start from scratch.
  1341. */
  1342. do
  1343. {
  1344. fRetry=FALSE;
  1345. /*
  1346. * Note that it is not safe to cache the registry key in
  1347. * the object. If somebody deletes the registry key, our
  1348. * cached handle goes stale and becomes useless.
  1349. */
  1350. lRc = RegOpenKeyEx(HKEY_LOCAL_MACHINE,
  1351. REGSTR_PATH_JOYOEM, 0,
  1352. KEY_QUERY_VALUE | KEY_ENUMERATE_SUB_KEYS, &hkTypesR);
  1353. /*
  1354. * Note also that if the registry key is not available,
  1355. * we still want to return the predefined types.
  1356. */
  1357. if(lRc == ERROR_SUCCESS)
  1358. {
  1359. lRc = RegQueryInfoKey(hkTypesR, 0, 0, 0, &chkSub,
  1360. 0, 0, 0, 0, 0, 0, 0);
  1361. if(lRc == ERROR_SUCCESS )
  1362. {
  1363. } else
  1364. {
  1365. chkSub = 0;
  1366. }
  1367. } else
  1368. {
  1369. hkTypesR = 0;
  1370. chkSub = 0;
  1371. }
  1372. /*
  1373. * Each predefined name is of the form #n\0,
  1374. * which is 3 characters.
  1375. */
  1376. hres = AllocCbPpv(cbCwch( chkSub * MAX_JOYSTRING +
  1377. (JOY_HW_PREDEFMAX - JOY_HW_PREDEFMIN)
  1378. * 3 + 1), ppwszz);
  1379. // Not really a bug,we never get to this point with a NULL ptr,
  1380. // but lets keep prefix happy Manbugs: 29340
  1381. if(SUCCEEDED(hres) && *ppwszz != NULL ){
  1382. DWORD dw;
  1383. LPWSTR pwsz;
  1384. /*
  1385. * First add the predef keys.
  1386. */
  1387. for(dw = JOY_HW_PREDEFMIN, pwsz = *ppwszz;
  1388. dw < JOY_HW_PREDEFMAX; dw++)
  1389. {
  1390. *pwsz++ = L'#';
  1391. *pwsz++ = CJoyCfg_CharFromType(dw);
  1392. *pwsz++ = L'\0';
  1393. }
  1394. /*
  1395. * Now add the named keys.
  1396. */
  1397. for(dw = 0; dw < chkSub; dw++)
  1398. {
  1399. #ifdef UNICODE
  1400. lRc = RegEnumKey(hkTypesR, dw, pwsz, MAX_JOYSTRING);
  1401. #else
  1402. CHAR sz[MAX_JOYSTRING];
  1403. lRc = RegEnumKey(hkTypesR, dw, sz, MAX_JOYSTRING);
  1404. #endif
  1405. if(lRc == ERROR_SUCCESS )
  1406. {
  1407. #ifdef UNICODE
  1408. hres = JoyCfg_CheckTypeKey( hkTypesR, pwsz );
  1409. #else
  1410. hres = JoyCfg_CheckTypeKey( hkTypesR, sz );
  1411. #endif
  1412. if( FAILED( hres ) )
  1413. {
  1414. /*
  1415. * Had to fix type so restart
  1416. */
  1417. FreePpv( ppwszz );
  1418. break;
  1419. }
  1420. if( hres != S_OK )
  1421. {
  1422. /*
  1423. * Ignore this type
  1424. */
  1425. continue;
  1426. }
  1427. #ifdef UNICODE
  1428. pwsz += lstrlenW(pwsz) + 1;
  1429. #else
  1430. pwsz += AToU(pwsz, MAX_JOYSTRING, sz);
  1431. #endif
  1432. }
  1433. else
  1434. {
  1435. }
  1436. }
  1437. if( SUCCEEDED( hres ) )
  1438. {
  1439. *pwsz = L'\0'; /* Make it ZZ */
  1440. hres = S_OK;
  1441. }
  1442. else
  1443. {
  1444. fRetry = TRUE;
  1445. }
  1446. }
  1447. if(hkTypesR)
  1448. {
  1449. RegCloseKey(hkTypesR);
  1450. }
  1451. } while( fRetry );
  1452. ExitOleProcPpv(ppwszz);
  1453. return hres;
  1454. }
  1455. /*****************************************************************************
  1456. *
  1457. * @doc EXTERNAL
  1458. *
  1459. * @method HRESULT | IDirectInputJoyConfig8 | EnumTypes |
  1460. *
  1461. * Enumerate the joystick types currently supported by
  1462. * DirectInput. A "joystick type" describes how DirectInput
  1463. * should communicate with a joystick device. It includes
  1464. * information such as the presence and
  1465. * locations of each of the axes and the number of buttons
  1466. * supported by the device.
  1467. *
  1468. * @cwrap LPDIRECTINPUTJOYCONFIG8 | LPDIRECTINPUTJOYCONFIG8
  1469. *
  1470. * @parm LPDIJOYTYPECALLBACK | lpCallback |
  1471. *
  1472. * Points to an application-defined callback function.
  1473. * For more information, see the description of the
  1474. * <f DIEnumJoyTypeProc> callback function.
  1475. *
  1476. * @parm IN LPVOID | pvRef |
  1477. *
  1478. * Specifies a 32-bit application-defined
  1479. * value to be passed to the callback function. This value
  1480. * may be any 32-bit value; it is prototyped as an <t LPVOID>
  1481. * for convenience.
  1482. *
  1483. * @returns
  1484. *
  1485. * Returns a COM error code. The following error codes are
  1486. * intended to be illustrative and not necessarily comprehensive.
  1487. *
  1488. * <c DI_OK> = <c S_OK>: The operation completed successfully.
  1489. * Note that if the callback stops the enumeration prematurely,
  1490. * the enumeration is considered to have succeeded.
  1491. *
  1492. * <c DIERR_INVALIDPARAM> = <c E_INVALIDARG>: The
  1493. * callback procedure returned an invalid status code.
  1494. *
  1495. * @cb BOOL CALLBACK | DIEnumJoyTypeProc |
  1496. *
  1497. * An application-defined callback function that receives
  1498. * DirectInput joystick types as a result of a call to the
  1499. * <om IDirectInputJoyConfig8::EnumTypes> method.
  1500. *
  1501. * @parm IN LPCWSTR | pwszTypeName |
  1502. *
  1503. * The name of the joystick type. A buffer of <c MAX_JOYSTRING>
  1504. * characters will be sufficient to hold the type name.
  1505. * The type name should never be shown to the end user; instead,
  1506. * the "display name" should be shown. Use
  1507. * <mf IDirectInputJoyConfig8::GetTypeInfo> to obtain the
  1508. * display name of a joystick type.
  1509. *
  1510. * Type names that begin with a sharp character ("#")
  1511. * represent predefined types which cannot be modified
  1512. * or deleted.
  1513. *
  1514. * @parm IN OUT LPVOID | pvRef |
  1515. * Specifies the application-defined value given in the
  1516. * <mf IDirectInputJoyConfig8::EnumTypes> function.
  1517. *
  1518. * @returns
  1519. *
  1520. * Returns <c DIENUM_CONTINUE> to continue the enumeration
  1521. * or <c DIENUM_STOP> to stop the enumeration.
  1522. *
  1523. * @devnote
  1524. *
  1525. * EnumTypes must snapshot because people will try to get/set/delete
  1526. * during the enumeration.
  1527. *
  1528. * EnumTypes enumerates the predefined types as "#digit".
  1529. *
  1530. *****************************************************************************/
  1531. STDMETHODIMP
  1532. CJoyCfg_EnumTypes(PDJC pdjc, LPDIJOYTYPECALLBACK ptc, LPVOID pvRef)
  1533. {
  1534. HRESULT hres;
  1535. EnterProcR(IDirectInputJoyConfig8::EnumTypes, (_ "ppx", pdjc, ptc, pvRef));
  1536. if(SUCCEEDED(hres = hresPv(pdjc)) &&
  1537. SUCCEEDED(hres = hresFullValidPfn(ptc, 1)))
  1538. {
  1539. PJC this = _thisPvNm(pdjc, djc);
  1540. LPWSTR pwszKeys;
  1541. hres = CJoyCfg_SnapTypes(this, &pwszKeys);
  1542. if(SUCCEEDED(hres))
  1543. {
  1544. LPWSTR pwsz;
  1545. /*
  1546. * Prefix warns that pwszKeys could be null (mb:34685)
  1547. * Little does it know that CJoyCfg_SnapTypes can only return a
  1548. * success if the pointer is not NULL.
  1549. */
  1550. AssertF( pwszKeys );
  1551. /*
  1552. * Surprise! Win95 implements lstrlenW.
  1553. */
  1554. for(pwsz = pwszKeys; *pwsz; pwsz += lstrlenW(pwsz) + 1)
  1555. {
  1556. BOOL fRc;
  1557. /*
  1558. * WARNING! "goto" here! Make sure that nothing
  1559. * is held while we call the callback.
  1560. */
  1561. fRc = Callback(ptc, pwsz, pvRef);
  1562. switch(fRc)
  1563. {
  1564. case DIENUM_STOP: goto enumdoneok;
  1565. case DIENUM_CONTINUE: break;
  1566. default:
  1567. RPF("%s: Invalid return value from callback", s_szProc);
  1568. ValidationException();
  1569. break;
  1570. }
  1571. }
  1572. FreePpv(&pwszKeys);
  1573. hres = DIPort_SnapTypes(&pwszKeys);
  1574. if(SUCCEEDED(hres))
  1575. {
  1576. LPWSTR pwsz;
  1577. /*
  1578. * Surprise! Win95 implements lstrlenW.
  1579. */
  1580. for(pwsz = pwszKeys; *pwsz; pwsz += lstrlenW(pwsz) + 1)
  1581. {
  1582. BOOL fRc;
  1583. /*
  1584. * WARNING! "goto" here! Make sure that nothing
  1585. * is held while we call the callback.
  1586. */
  1587. fRc = Callback(ptc, pwsz, pvRef);
  1588. switch(fRc)
  1589. {
  1590. case DIENUM_STOP: goto enumdoneok;
  1591. case DIENUM_CONTINUE: break;
  1592. default:
  1593. RPF("%s: Invalid return value from callback", s_szProc);
  1594. ValidationException();
  1595. break;
  1596. }
  1597. }
  1598. }
  1599. enumdoneok:;
  1600. FreePpv(&pwszKeys);
  1601. hres = S_OK;
  1602. }
  1603. hres = S_OK;
  1604. }
  1605. ExitOleProcR();
  1606. return hres;
  1607. }
  1608. /*****************************************************************************
  1609. *
  1610. * @doc EXTERNAL
  1611. *
  1612. * @method HRESULT | IDirectInputJoyConfig8 | GetTypeInfo |
  1613. *
  1614. * Obtain information about a joystick type.
  1615. *
  1616. * @cwrap LPDIRECTINPUTJOYCONFIG8 | LPDIRECTINPUTJOYCONFIG8
  1617. *
  1618. * @parm LPCWSTR | pwszTypeName |
  1619. *
  1620. * Points to the name of the type, previously obtained
  1621. * from a call to <mf IDirectInputJoyConfig8::EnumTypes>.
  1622. *
  1623. * @parm IN OUT LPDIJOYTYPEINFO | pjti |
  1624. *
  1625. * Receives information about the joystick type.
  1626. * The caller "must" initialize the <e DIJOYTYPEINFO.dwSize>
  1627. * field before calling this method.
  1628. *
  1629. * @parm DWORD | dwFlags |
  1630. *
  1631. * Zero or more <c DITC_*> flags
  1632. * which specify which parts of the structure pointed
  1633. * to by <p pjti> are to be filled in.
  1634. *
  1635. * @returns
  1636. *
  1637. * Returns a COM error code. The following error codes are
  1638. * intended to be illustrative and not necessarily comprehensive.
  1639. *
  1640. * <c DI_OK> = <c S_OK>: The operation completed successfully.
  1641. *
  1642. * <c DIERR_INVALIDPARAM> = <c E_INVALIDARG>: One or more
  1643. * parameters was invalid.
  1644. *
  1645. * <c DIERR_NOTFOUND>: The joystick type was not found.
  1646. *
  1647. *****************************************************************************/
  1648. STDMETHODIMP
  1649. CJoyCfg_GetTypeInfo(PDJC pdjc, LPCWSTR pwszType,
  1650. LPDIJOYTYPEINFO pjti, DWORD fl)
  1651. {
  1652. HRESULT hres;
  1653. EnterProcR(IDirectInputJoyConfig8::GetTypeInfo,
  1654. (_ "pWpx", pdjc, pwszType, pjti, fl));
  1655. if(SUCCEEDED(hres = hresPv(pdjc)) &&
  1656. SUCCEEDED(hres = hresFullValidReadStrW(pwszType, MAX_JOYSTRING, 1)) &&
  1657. SUCCEEDED(hres = hresFullValidWritePxCb3(pjti,
  1658. DIJOYTYPEINFO_DX8,
  1659. DIJOYTYPEINFO_DX6,
  1660. DIJOYTYPEINFO_DX5, 2)) &&
  1661. SUCCEEDED( (pjti->dwSize == cbX(DIJOYTYPEINFO_DX8) )
  1662. ? ( hres = hresFullValidFl(fl, DITC_GETVALID, 3) )
  1663. : (pjti->dwSize == cbX(DIJOYTYPEINFO_DX6 ) )
  1664. ? ( hres = hresFullValidFl(fl, DITC_GETVALID_DX6, 3) )
  1665. : ( hres = hresFullValidFl(fl, DITC_GETVALID_DX5, 3) ) ) )
  1666. {
  1667. PJC this = _thisPvNm(pdjc, djc);
  1668. GUID guid;
  1669. BOOL fParseGuid;
  1670. #ifndef UNICODE
  1671. TCHAR tszType[MAX_PATH/4];
  1672. UToT( tszType, cA(tszType), pwszType );
  1673. fParseGuid = ParseGUID(&guid, tszType);
  1674. #else
  1675. fParseGuid = ParseGUID(&guid, pwszType);
  1676. #endif
  1677. if(pwszType[0] == TEXT('#'))
  1678. {
  1679. hres = JoyReg_GetPredefTypeInfo(pwszType, pjti, fl);
  1680. } else if( fParseGuid )
  1681. {
  1682. hres = DIBusDevice_GetTypeInfo(&guid, pjti, fl);
  1683. }else
  1684. {
  1685. hres = JoyReg_GetTypeInfo(pwszType, pjti, fl);
  1686. }
  1687. }
  1688. ExitOleProcR();
  1689. return hres;
  1690. }
  1691. /*****************************************************************************
  1692. *
  1693. * @doc INTERNAL
  1694. *
  1695. * @func HRESULT | hresFullValidStructStr |
  1696. *
  1697. * Validate a string field in a struct.
  1698. *
  1699. * @parm IN LPCWSTR | pwsz |
  1700. *
  1701. * String to be validated.
  1702. *
  1703. * @parm UINT | cwch |
  1704. *
  1705. * Maximum string length.
  1706. *
  1707. * @parm LPCSTR | pszName |
  1708. *
  1709. * Field name.
  1710. *
  1711. * @returns
  1712. *
  1713. * Returns a COM error code. The following error codes are
  1714. * intended to be illustrative and not necessarily comprehensive.
  1715. *
  1716. * <c DI_OK> = <c S_OK>: The operation completed successfully.
  1717. *
  1718. * <c DIERR_INVALIDPARAM> = <c E_INVALIDARG>: One or more
  1719. * parameters was invalid.
  1720. *
  1721. *****************************************************************************/
  1722. #ifndef XDEBUG
  1723. \
  1724. #define hresFullValidStructStr_(pwsz, cwch, pszName, z, i) \
  1725. _hresFullValidStructStr_(pwsz, cwch) \
  1726. #endif
  1727. #define hresFullValidStructStr(Struct, f, iarg) \
  1728. hresFullValidStructStr_(Struct->f, cA(Struct->f), #f, s_szProc,iarg)\
  1729. HRESULT INLINE
  1730. hresFullValidStructStr_(LPCWSTR pwsz, UINT cwch, LPCSTR pszName,
  1731. LPCSTR s_szProc, int iarg)
  1732. {
  1733. HRESULT hres;
  1734. if(SUCCEEDED(hres = hresFullValidReadStrW(pwsz, cwch, iarg)))
  1735. {
  1736. } else
  1737. {
  1738. #ifdef XDEBUG
  1739. RPF("%s: Invalid value for %s", s_szProc, pszName);
  1740. #endif
  1741. }
  1742. return hres;
  1743. }
  1744. /*****************************************************************************
  1745. *
  1746. * @doc INTERNAL
  1747. *
  1748. * @func HRESULT | hresValidFlags2 |
  1749. *
  1750. * Validate the dwFlags2 value for SetTypeInfo.
  1751. *
  1752. * @parm IN DWORD | dwFlags2 |
  1753. *
  1754. * Flags to be validated.
  1755. *
  1756. * @returns
  1757. *
  1758. * <c DI_OK> = <c S_OK>: The flags appear to be valid.
  1759. *
  1760. * <c DIERR_INVALIDPARAM> = <c E_INVALIDARG>: The flags are invalid.
  1761. *
  1762. *****************************************************************************/
  1763. #ifdef XDEBUG
  1764. #define hresValidFlags2( flags, iarg ) hresValidFlags2_( flags, s_szProc, iarg )
  1765. HRESULT INLINE hresValidFlags2_
  1766. (
  1767. DWORD dwFlags2,
  1768. LPCSTR s_szProc,
  1769. int iarg
  1770. )
  1771. #else
  1772. #define hresValidFlags2( flags, iarg ) hresValidFlags2_( flags )
  1773. HRESULT hresValidFlags2_
  1774. (
  1775. DWORD dwFlags2
  1776. )
  1777. #endif
  1778. {
  1779. if( !( dwFlags2 & ~JOYTYPE_FLAGS2_SETVALID )
  1780. && ( ( GET_DIDEVICE_TYPEANDSUBTYPE( dwFlags2 ) == 0 )
  1781. || GetValidDI8DevType( dwFlags2, 0, 0 ) ) )
  1782. {
  1783. return S_OK;
  1784. }
  1785. else
  1786. {
  1787. #ifdef XDEBUG
  1788. if( dwFlags2 & ~JOYTYPE_FLAGS2_SETVALID )
  1789. {
  1790. RPF("%s: Invalid flags 0x%04x in HIWORD(dwFlags2) of arg %d",
  1791. s_szProc, HIWORD(dwFlags2), iarg);
  1792. }
  1793. if( GET_DIDEVICE_TYPEANDSUBTYPE( dwFlags2 )
  1794. &&!GetValidDI8DevType( dwFlags2, 127, JOY_HWS_HASPOV | JOY_HWS_HASZ ) )
  1795. {
  1796. RPF("%s: Invalid type:subtype 0x%02x:%02x in dwFlags2 of arg %d",
  1797. s_szProc, GET_DIDEVICE_TYPE( dwFlags2 ),
  1798. GET_DIDEVICE_SUBTYPE( dwFlags2 ), iarg );
  1799. }
  1800. #endif
  1801. return E_INVALIDARG;
  1802. }
  1803. }
  1804. /*****************************************************************************
  1805. *
  1806. * @doc EXTERNAL
  1807. *
  1808. * @method HRESULT | IDirectInputJoyConfig8 | SetTypeInfo |
  1809. *
  1810. * Creates a new joystick type
  1811. * or redefine information about an existing joystick type.
  1812. *
  1813. * @cwrap LPDIRECTINPUTJOYCONFIG8 | LPDIRECTINPUTJOYCONFIG8
  1814. *
  1815. * @parm LPCWSTR | pwszTypeName |
  1816. *
  1817. * Points to the name of the type. The name of the type may
  1818. * not exceed MAX_JOYSTRING characters, including the terminating
  1819. * null character.
  1820. *
  1821. * If the type name does not already exist, then it is created.
  1822. *
  1823. * You cannot change the type information for a predefined type.
  1824. *
  1825. * The name may not begin with
  1826. * a "#" character. Types beginning with "#" are reserved
  1827. * by DirectInput.
  1828. *
  1829. * @parm IN LPDIJOYTYPEINFO | pjti |
  1830. *
  1831. * Contains information about the joystick type.
  1832. *
  1833. * @parm DWORD | dwFlags |
  1834. *
  1835. * Zero or more <c DITC_*> flags
  1836. * which specify which parts of the structure pointed
  1837. * to by <p pjti> contain values which are to be set.
  1838. *
  1839. * @parm OUT LPWSTR | pwszVIDPIDTypeName |
  1840. * If the type name is an OEM type not in VID_xxxx&PID_yyyy format,
  1841. * pwszVIDPIDTypeName will return the name in VID_xxxx&PID_yyyy
  1842. * format that is assigned by Dinput.
  1843. * This VID_xxxx&PID_yyyy name should be used in DIJOYCONFIG.wszType
  1844. * field when calling SetConfig.
  1845. *
  1846. * @returns
  1847. *
  1848. * Returns a COM error code. The following error codes are
  1849. * intended to be illustrative and not necessarily comprehensive.
  1850. *
  1851. * <c DI_OK> = <c S_OK>: The operation completed successfully.
  1852. *
  1853. * <c DIERR_NOTACQUIRED>: Joystick configuration has not been
  1854. * acquired. You must call <mf IDirectInputJoyConfig8::Acquire>
  1855. * before you can alter joystick configuration settings.
  1856. *
  1857. * <c DIERR_INVALIDPARAM> = <c E_INVALIDARG>: One or more
  1858. * parameters was invalid.
  1859. *
  1860. * <c DIERR_READONLY>: Attempted to change a predefined type.
  1861. *
  1862. *****************************************************************************/
  1863. typedef struct _TYPENAME {
  1864. WCHAR wszRealTypeName[MAX_JOYSTRING];
  1865. WCHAR wszDITypeName[MAX_JOYSTRING/4];
  1866. } TYPENAME, *LPTYPENAME;
  1867. #ifdef WINNT
  1868. BOOL CALLBACK CJoyCfg_FindTypeProc( LPCWSTR pwszTypeName, LPVOID pv )
  1869. {
  1870. DIJOYTYPEINFO dijti;
  1871. LPTYPENAME lptype = (LPTYPENAME)pv;
  1872. ZeroMemory( &dijti, sizeof(dijti));
  1873. dijti.dwSize = sizeof(dijti);
  1874. if( pwszTypeName[0] == L'\0' || pwszTypeName[0] == L'#' )
  1875. {
  1876. return TRUE;
  1877. } else {
  1878. if( SUCCEEDED(JoyReg_GetTypeInfo(pwszTypeName, &dijti, DITC_REGHWSETTINGS | DITC_DISPLAYNAME)) )
  1879. {
  1880. if( !lstrcmpW(dijti.wszDisplayName, lptype->wszRealTypeName) ) {
  1881. lstrcpynW(lptype->wszDITypeName, pwszTypeName, sizeof(lptype->wszDITypeName)-1 );
  1882. return FALSE;
  1883. }
  1884. }
  1885. }
  1886. return(TRUE);
  1887. }
  1888. #endif // #ifdef WINNT
  1889. STDMETHODIMP
  1890. CJoyCfg_SetTypeInfo(PDJC pdjc, LPCWSTR pwszType,
  1891. LPCDIJOYTYPEINFO pjti, DWORD fl, LPWSTR pwszDITypeName)
  1892. {
  1893. HRESULT hres;
  1894. EnterProcR(IDirectInputJoyConfig8::SetTypeInfo,
  1895. (_ "pWpx", pdjc, pwszType, pjti, fl));
  1896. if(SUCCEEDED(hres = hresPv(pdjc)) &&
  1897. SUCCEEDED(hres = hresFullValidReadStrW(pwszType, MAX_JOYSTRING, 1)) &&
  1898. SUCCEEDED(hres = hresFullValidReadPxCb3((PV)pjti,
  1899. DIJOYTYPEINFO_DX8,
  1900. DIJOYTYPEINFO_DX6,
  1901. DIJOYTYPEINFO_DX5, 2)) &&
  1902. #ifdef WINNT
  1903. SUCCEEDED(hres = hresFullValidFl(pjti->dwFlags1, JOYTYPE_FLAGS1_SETVALID, 3) ) &&
  1904. #endif
  1905. SUCCEEDED( (pjti->dwSize == cbX(DIJOYTYPEINFO_DX8) )
  1906. ? ( hres = hresFullValidFl(fl, DITC_SETVALID, 3) )
  1907. : (pjti->dwSize == cbX(DIJOYTYPEINFO_DX6 ) )
  1908. ? ( hres = hresFullValidFl(fl, DITC_SETVALID_DX6, 3) )
  1909. : ( hres = hresFullValidFl(fl, DITC_SETVALID_DX5, 3) ) ) &&
  1910. fLimpFF(fl & DITC_HARDWAREID,
  1911. SUCCEEDED(hres = hresFullValidStructStr(pjti, wszHardwareId, 2))) &&
  1912. fLimpFF(fl & DITC_DISPLAYNAME,
  1913. SUCCEEDED(hres = hresFullValidStructStr(pjti, wszDisplayName, 2))) &&
  1914. #ifndef WINNT
  1915. fLimpFF(fl & DITC_CALLOUT,
  1916. SUCCEEDED(hres = hresFullValidStructStr(pjti, wszCallout, 2))) &&
  1917. #endif
  1918. fLimpFF(fl & DITC_FLAGS2,
  1919. SUCCEEDED(hres = hresValidFlags2( pjti->dwFlags2, 2)) ) &&
  1920. fLimpFF(fl & DITC_MAPFILE,
  1921. SUCCEEDED(hres = hresFullValidStructStr(pjti, wszMapFile, 2)))
  1922. )
  1923. {
  1924. PJC this = _thisPvNm(pdjc, djc);
  1925. CJoyCfg_EnterCrit(this);
  1926. if(SUCCEEDED(hres = CJoyCfg_IsAcquired(this)))
  1927. {
  1928. switch(pwszType[0])
  1929. {
  1930. case L'\0':
  1931. RPF("%s: Invalid pwszType (null)", s_szProc);
  1932. hres = E_INVALIDARG;
  1933. break;
  1934. case L'#':
  1935. RPF("%s: Invalid pwszType (predefined)", s_szProc);
  1936. hres = DIERR_READONLY;
  1937. break;
  1938. default:
  1939. hres = JoyReg_SetTypeInfo(this->hkTypesW, pwszType, pjti, fl);
  1940. if( SUCCEEDED(hres) ) {
  1941. #ifdef WINNT
  1942. TYPENAME type;
  1943. short DontCare;
  1944. if( (pjti->wszHardwareId[0] == TEXT('\0')) &&
  1945. !(ParseVIDPID(&DontCare, &DontCare, pwszType)) )
  1946. {
  1947. lstrcpyW(type.wszRealTypeName, pwszType);
  1948. hres = CJoyCfg_EnumTypes(pdjc, CJoyCfg_FindTypeProc, &type);
  1949. if( SUCCEEDED(hres) ) {
  1950. if( !IsBadWritePtr((LPVOID)pwszDITypeName, lstrlenW(type.wszDITypeName)) )
  1951. {
  1952. CharUpperW(type.wszDITypeName);
  1953. lstrcpyW(pwszDITypeName, type.wszDITypeName);
  1954. } else {
  1955. hres = ERROR_NOT_ENOUGH_MEMORY;
  1956. }
  1957. }
  1958. } else
  1959. #endif
  1960. {
  1961. if( !IsBadWritePtr((LPVOID)pwszDITypeName, lstrlenW(pwszType)) )
  1962. {
  1963. lstrcpyW(pwszDITypeName, pwszType);
  1964. } else {
  1965. hres = ERROR_NOT_ENOUGH_MEMORY;
  1966. }
  1967. }
  1968. }
  1969. break;
  1970. }
  1971. }
  1972. CJoyCfg_LeaveCrit(this);
  1973. }
  1974. ExitOleProcR();
  1975. return hres;
  1976. }
  1977. /*****************************************************************************
  1978. *
  1979. * @doc EXTERNAL
  1980. *
  1981. * @method HRESULT | IDirectInputJoyConfig8 | DeleteType |
  1982. *
  1983. * Removes information about a joystick type.
  1984. *
  1985. * Use this method with caution; it is the caller's responsibility
  1986. * to ensure that no joystick refers to the deleted type.
  1987. *
  1988. * @cwrap LPDIRECTINPUTJOYCONFIG8 | LPDIRECTINPUTJOYCONFIG8
  1989. *
  1990. * @parm LPCWSTR | pwszTypeName |
  1991. *
  1992. * Points to the name of the type. The name of the type may
  1993. * not exceed <c MAX_PATH> characters, including the terminating
  1994. * null character.
  1995. *
  1996. * The name may not begin with
  1997. * a "#" character. Types beginning with "#" are reserved
  1998. * by DirectInput.
  1999. *
  2000. * @returns
  2001. *
  2002. * Returns a COM error code. The following error codes are
  2003. * intended to be illustrative and not necessarily comprehensive.
  2004. *
  2005. * <c DI_OK> = <c S_OK>: The operation completed successfully.
  2006. *
  2007. * <c DIERR_NOTACQUIRED>: Joystick configuration has not been
  2008. * acquired. You must call <mf IDirectInputJoyConfig8::Acquire>
  2009. * before you can alter joystick configuration settings.
  2010. *
  2011. * <c DIERR_INVALIDPARAM> = <c E_INVALIDARG>: One or more
  2012. * parameters was invalid.
  2013. *
  2014. *****************************************************************************/
  2015. STDMETHODIMP
  2016. CJoyCfg_DeleteType(PDJC pdjc, LPCWSTR pwszType)
  2017. {
  2018. HRESULT hres;
  2019. EnterProcR(IDirectInputJoyConfig8::DeleteType, (_ "pW", pdjc, pwszType));
  2020. if(SUCCEEDED(hres = hresPv(pdjc)) &&
  2021. SUCCEEDED(hres = hresFullValidReadStrW( pwszType, MAX_JOYSTRING, 1)))
  2022. {
  2023. PJC this = _thisPvNm(pdjc, djc);
  2024. CJoyCfg_EnterCrit(this);
  2025. if(SUCCEEDED(hres = CJoyCfg_IsAcquired(this)))
  2026. {
  2027. LONG lRc;
  2028. switch(pwszType[0])
  2029. {
  2030. case L'\0':
  2031. RPF("%s: Invalid pwszType (null)", s_szProc);
  2032. hres = E_INVALIDARG;
  2033. break;
  2034. case L'#':
  2035. RPF("%s: Invalid pwszType (predefined)", s_szProc);
  2036. hres = DIERR_READONLY;
  2037. break;
  2038. default:
  2039. #ifdef WINNT
  2040. #ifdef UNICODE
  2041. lRc = DIWinnt_RegDeleteKey(this->hkTypesW, (LPTSTR)pwszType);
  2042. #else
  2043. {
  2044. CHAR sz[MAX_PATH];
  2045. UToA( sz, cA(sz), pwszType );
  2046. lRc = DIWinnt_RegDeleteKey(this->hkTypesW, (LPTSTR)sz);
  2047. }
  2048. #endif
  2049. #else
  2050. #ifdef UNICODE
  2051. lRc = RegDeleteKey(this->hkTypesW, (LPTSTR)pwszType);
  2052. #else
  2053. {
  2054. CHAR sz[MAX_PATH];
  2055. UToA( sz, cA(sz), pwszType );
  2056. lRc = RegDeleteKey(this->hkTypesW, (LPTSTR)sz);
  2057. }
  2058. #endif
  2059. #endif
  2060. /*
  2061. #ifdef WINNT
  2062. lRc = DIWinnt_RegDeleteKey(this->hkTypesW, pwszType);
  2063. #else
  2064. lRc = RegDeleteKeyW(this->hkTypesW, pwszType);
  2065. #endif
  2066. */
  2067. if(lRc == ERROR_SUCCESS)
  2068. {
  2069. hres = S_OK;
  2070. } else
  2071. {
  2072. if(lRc == ERROR_KEY_DELETED || lRc == ERROR_BADKEY)
  2073. {
  2074. lRc = ERROR_FILE_NOT_FOUND;
  2075. }
  2076. hres = hresLe(lRc);
  2077. }
  2078. break;
  2079. }
  2080. }
  2081. CJoyCfg_LeaveCrit(this);
  2082. }
  2083. ExitOleProcR();
  2084. return hres;
  2085. }
  2086. /*****************************************************************************
  2087. *
  2088. * @doc EXTERNAL
  2089. *
  2090. * @method HRESULT | IDirectInputJoyConfig8 | GetConfig |
  2091. *
  2092. * Obtain information about a joystick's configuration.
  2093. *
  2094. * @cwrap LPDIRECTINPUTJOYCONFIG8 | LPDIRECTINPUTJOYCONFIG8
  2095. *
  2096. * @parm UINT | uiJoy |
  2097. *
  2098. * Joystick identification number. This is a nonnegative
  2099. * integer. To enumerate joysticks, begin with joystick
  2100. * zero and increment the joystick number by one until the
  2101. * function returns <c DIERR_NOMOREITEMS>.
  2102. *
  2103. * Yes, it's different from all other DirectX enumerations.
  2104. *
  2105. *
  2106. * @parm IN OUT LPDIJOYCONFIG | pjc |
  2107. *
  2108. * Receives information about the joystick configuration.
  2109. * The caller "must" initialize the <e DIJOYCONFIG.dwSize>
  2110. * field before calling this method.
  2111. *
  2112. * @parm DWORD | dwFlags |
  2113. *
  2114. * Zero or more <c DIJC_*> flags
  2115. * which specify which parts of the structure pointed
  2116. * to by <p pjc> are to be filled in.
  2117. *
  2118. * @returns
  2119. *
  2120. * Returns a COM error code. The following error codes are
  2121. * intended to be illustrative and not necessarily comprehensive.
  2122. *
  2123. * <c DI_OK> = <c S_OK>: The operation completed successfully.
  2124. *
  2125. * <c S_FALSE>: The specified joystick has not yet been
  2126. * configured.
  2127. *
  2128. * <c DIERR_INVALIDPARAM> = <c E_INVALIDARG>: One or more
  2129. * parameters was invalid.
  2130. *
  2131. * <c DIERR_NOMOREITEMS>: No more joysticks.
  2132. *
  2133. *****************************************************************************/
  2134. STDMETHODIMP
  2135. CJoyCfg_GetConfig(PDJC pdjc, UINT uiJoy, LPDIJOYCONFIG pjc, DWORD fl)
  2136. {
  2137. HRESULT hres;
  2138. EnterProcR(IDirectInputJoyConfig8::GetConfig,
  2139. (_ "pupx", pdjc, uiJoy, pjc, fl));
  2140. if(SUCCEEDED(hres = hresPv(pdjc)) &&
  2141. SUCCEEDED(hres = hresFullValidWritePxCb2(pjc,
  2142. DIJOYCONFIG_DX6,
  2143. DIJOYCONFIG_DX5, 2)) &&
  2144. SUCCEEDED( (pjc->dwSize == cbX(DIJOYCONFIG)
  2145. ? (hres = hresFullValidFl(fl, DIJC_GETVALID, 3) )
  2146. : (hres = hresFullValidFl(fl, DIJC_GETVALID_DX5, 3)))) )
  2147. {
  2148. PJC this = _thisPvNm(pdjc, djc);
  2149. CJoyCfg_EnterCrit(this);
  2150. /*
  2151. * Note that we always get the DIJC_REGHWCONFIGTYPE because
  2152. * we need to check if the joystick type is "none".
  2153. */
  2154. hres = JoyReg_GetConfig(uiJoy, pjc, fl | DIJC_REGHWCONFIGTYPE);
  2155. if(SUCCEEDED(hres))
  2156. {
  2157. #ifndef WINNT
  2158. static WCHAR s_wszMSGAME[] = L"MSGAME.VXD";
  2159. if(memcmp(pjc->wszCallout, s_wszMSGAME, cbX(s_wszMSGAME)) == 0)
  2160. {
  2161. ; // do nothing
  2162. } else
  2163. #endif
  2164. if(fInOrder(JOY_HW_PREDEFMIN, pjc->hwc.dwType,
  2165. JOY_HW_PREDEFMAX))
  2166. {
  2167. pjc->wszType[0] = TEXT('#');
  2168. pjc->wszType[1] = CJoyCfg_CharFromType(pjc->hwc.dwType);
  2169. pjc->wszType[2] = TEXT('\0');
  2170. }
  2171. if(pjc->hwc.dwType == JOY_HW_NONE)
  2172. {
  2173. hres = S_FALSE;
  2174. } else
  2175. {
  2176. hres = S_OK;
  2177. }
  2178. /*
  2179. * In DEBUG, re-scramble the hwc and type if the caller
  2180. * didn't ask for it.
  2181. */
  2182. if(!(fl & DIJC_REGHWCONFIGTYPE))
  2183. {
  2184. ScrambleBuf(&pjc->hwc, cbX(pjc->hwc));
  2185. ScrambleBuf(&pjc->wszType, cbX(pjc->wszType));
  2186. }
  2187. }
  2188. CJoyCfg_LeaveCrit(this);
  2189. }
  2190. ExitBenignOleProcR();
  2191. return hres;
  2192. }
  2193. #if 0
  2194. /*****************************************************************************
  2195. *
  2196. * @doc INTERNAL
  2197. *
  2198. * @method HRESULT | CJoyCfg | UpdateGlobalGain |
  2199. *
  2200. * Create the device callback so we can talk to its driver and
  2201. * tell it to change the gain value.
  2202. *
  2203. * This function must be called under the object critical section.
  2204. *
  2205. * @cwrap PJC | this
  2206. *
  2207. * @parm DWORD | idJoy |
  2208. *
  2209. * The joystick identifier.
  2210. *
  2211. * @parm DWORD | dwCplGain |
  2212. *
  2213. * New global gain.
  2214. *
  2215. * @returns
  2216. *
  2217. * Returns a COM error code.
  2218. *
  2219. *****************************************************************************/
  2220. STDMETHODIMP
  2221. CJoyCfg_UpdateGlobalGain(PJC this, DWORD idJoy, DWORD dwCplGain)
  2222. {
  2223. HRESULT hres;
  2224. EnterProcI(CJoyCfg_UpdateGlobalGain, (_ "puu", this, idJoy, dwCplGain));
  2225. AssertF(CJoyCfg_InCrit(this));
  2226. /*
  2227. * Create the deviceeffect shepherd if we don't already have it.
  2228. */
  2229. if(this->pes && idJoy == this->idJoyCache)
  2230. {
  2231. hres = S_OK;
  2232. } else if(idJoy < cA(rgGUID_Joystick))
  2233. {
  2234. PCGUID rguid;
  2235. #ifdef DEBUG
  2236. CREATEDCB CreateDcb;
  2237. #endif
  2238. IDirectInputDeviceCallback *pdcb;
  2239. /*
  2240. * Assume the creation will work.
  2241. */
  2242. this->idJoyCache = idJoy;
  2243. /*
  2244. * Out with the old...
  2245. */
  2246. Invoke_Release(&this->pes);
  2247. /*
  2248. * And in with the new...
  2249. */
  2250. rguid = &rgGUID_Joystick[idJoy];
  2251. #ifdef DEBUG
  2252. hres = hresFindInstanceGUID(rguid, &CreateDcb, 1);
  2253. AssertF(SUCCEEDED(hres));
  2254. AssertF(CreateDcb == CJoy_New);
  2255. #endif
  2256. if(SUCCEEDED(hres = CJoy_New(0, rguid,
  2257. &IID_IDirectInputDeviceCallback,
  2258. (PPV)&pdcb)))
  2259. {
  2260. hres = pdcb->lpVtbl->CreateEffect(pdcb, &this->pes);
  2261. Invoke_Release(&pdcb);
  2262. }
  2263. } else
  2264. {
  2265. hres = DIERR_DEVICENOTREG;
  2266. }
  2267. /*
  2268. * If we have an effect shepherd, then tell it what the new
  2269. * global gain is.
  2270. */
  2271. if(SUCCEEDED(hres))
  2272. {
  2273. AssertF(this->pes && idJoy == this->idJoyCache);
  2274. hres = this->pes->lpVtbl->SetGlobalGain(this->pes, dwCplGain);
  2275. }
  2276. ExitOleProc();
  2277. return hres;
  2278. }
  2279. #endif
  2280. /*****************************************************************************
  2281. *
  2282. * @doc EXTERNAL
  2283. *
  2284. * @method HRESULT | IDirectInputJoyConfig8 | SetConfig |
  2285. *
  2286. * Create or redefine configuration information about a joystick.
  2287. *
  2288. * @cwrap LPDIRECTINPUTJOYCONFIG8 | LPDIRECTINPUTJOYCONFIG8
  2289. *
  2290. * @parm UINT | idJoy |
  2291. *
  2292. * Zero-based joystick identification number.
  2293. *
  2294. * @parm IN LPDIJOYCONFIG | pcfg |
  2295. *
  2296. * Contains information about the joystick.
  2297. *
  2298. * @parm DWORD | dwFlags |
  2299. *
  2300. * Zero or more <c DIJC_*> flags
  2301. * which specify which parts of the structure pointed
  2302. * to by <p pjc> contain information to be set.
  2303. *
  2304. * @returns
  2305. *
  2306. * Returns a COM error code. The following error codes are
  2307. * intended to be illustrative and not necessarily comprehensive.
  2308. *
  2309. * <c DI_OK> = <c S_OK>: The operation completed successfully.
  2310. *
  2311. * <c DIERR_NOTACQUIRED>: Joystick configuration has not been
  2312. * acquired. You must call <mf IDirectInputJoyConfig8::Acquire>
  2313. * before you can alter joystick configuration settings.
  2314. *
  2315. * <c DIERR_INVALIDPARAM> = <c E_INVALIDARG>: One or more
  2316. * parameters was invalid.
  2317. *
  2318. * @devnote
  2319. *
  2320. * This one is tricky. If the type begins with a sharp, then
  2321. * it's an internal type. And if it is null, then it's a
  2322. * custom type.
  2323. *
  2324. *
  2325. *****************************************************************************/
  2326. STDMETHODIMP
  2327. CJoyCfg_SetConfig(PDJC pdjc, UINT idJoy, LPCDIJOYCONFIG pcfg, DWORD fl)
  2328. {
  2329. HRESULT hres;
  2330. EnterProcR(IDirectInputJoyConfig8::SetConfig,
  2331. (_ "pupx", pdjc, idJoy, pcfg, fl));
  2332. if(SUCCEEDED(hres = hresPv(pdjc)) &&
  2333. SUCCEEDED(hres = hresFullValidReadPxCb2(pcfg,
  2334. DIJOYCONFIG_DX6,
  2335. DIJOYCONFIG_DX5, 2)) &&
  2336. SUCCEEDED( (pcfg->dwSize == cbX(DIJOYCONFIG)
  2337. ? ( hres = hresFullValidFl(fl, DIJC_SETVALID, 3) )
  2338. : ( hres = hresFullValidFl(fl, DIJC_SETVALID_DX5,3)) )) &&
  2339. fLimpFF(fl & DIJC_REGHWCONFIGTYPE,
  2340. SUCCEEDED(hres = hresFullValidStructStr(pcfg, wszType, 2))) &&
  2341. #ifndef WINNT
  2342. fLimpFF(fl & DIJC_CALLOUT,
  2343. SUCCEEDED(hres = hresFullValidStructStr(pcfg, wszCallout, 2))) &&
  2344. #endif
  2345. fLimpFF(fl & DIJC_WDMGAMEPORT,
  2346. SUCCEEDED(hres = hresFullValidGuid(&pcfg->guidGameport, 2)))
  2347. )
  2348. {
  2349. PJC this = _thisPvNm(pdjc, djc);
  2350. CJoyCfg_EnterCrit(this);
  2351. if(SUCCEEDED(hres = CJoyCfg_IsAcquired(this)))
  2352. {
  2353. JOYREGHWCONFIG jwc;
  2354. // We just ignore the DIJC_WDMGAMEPORT flag for Win9x passed by user.
  2355. // We will detect it ourself.
  2356. #ifndef WINNT
  2357. fl &= ~DIJC_WDMGAMEPORT;
  2358. #endif
  2359. if(fl & DIJC_REGHWCONFIGTYPE)
  2360. {
  2361. LPDWORD lpStart, lp;
  2362. jwc = pcfg->hwc;
  2363. /*
  2364. * Need to check whether the whole jwc is zero.
  2365. * If all are zero, we won't set it to JOY_HW_CUSTOM type.
  2366. * See manbug: 39542.
  2367. */
  2368. for( lpStart=(LPDWORD)&jwc, lp=(LPDWORD)&jwc.dwReserved; lp >= lpStart; lp-- ) {
  2369. if( *lp ) {
  2370. break;
  2371. }
  2372. }
  2373. if( lp < lpStart ) {
  2374. goto _CONTINUE_SET;
  2375. }
  2376. jwc.dwUsageSettings &= ~JOY_US_ISOEM;
  2377. if(pcfg->wszType[0] == TEXT('\0'))
  2378. {
  2379. jwc.dwType = JOY_HW_CUSTOM;
  2380. } else if(pcfg->wszType[0] == TEXT('#'))
  2381. {
  2382. jwc.dwType = CJoyCfg_TypeFromChar(pcfg->wszType[1]);
  2383. if(fInOrder(JOY_HW_PREDEFMIN, jwc.dwType,
  2384. JOY_HW_PREDEFMAX) &&
  2385. pcfg->wszType[2] == TEXT('\0'))
  2386. {
  2387. /*
  2388. * If we want to use WDM for predefined devices,
  2389. * then take away the comments.
  2390. *
  2391. * fl |= DIJC_WDMGAMEPORT;
  2392. */
  2393. } else
  2394. {
  2395. RPF("%s: Invalid predefined type \"%ls\"",
  2396. s_szProc, pcfg->wszType);
  2397. hres = E_INVALIDARG;
  2398. goto done;
  2399. }
  2400. } else
  2401. {
  2402. /*
  2403. * The precise value of jwc.dwType is not relevant.
  2404. * The Windows 95 joystick control panel sets the
  2405. * value to JOY_HW_PREDEFMAX + id, so we will too.
  2406. */
  2407. jwc.dwUsageSettings |= JOY_US_ISOEM;
  2408. jwc.dwType = JOY_HW_PREDEFMAX + idJoy;
  2409. #ifndef WINNT
  2410. if( !(fl & DIJC_WDMGAMEPORT) ) {
  2411. HKEY hk;
  2412. hres = JoyReg_OpenTypeKey(pcfg->wszType, MAXIMUM_ALLOWED, REG_OPTION_NON_VOLATILE, &hk);
  2413. if( SUCCEEDED( hres ) ) {
  2414. hres = JoyReg_IsWdmGameport( hk );
  2415. if( SUCCEEDED(hres) ) {
  2416. fl |= DIJC_WDMGAMEPORT;
  2417. }
  2418. RegCloseKey( hk );
  2419. }
  2420. }
  2421. #endif
  2422. }
  2423. }
  2424. _CONTINUE_SET:
  2425. #ifdef WINNT
  2426. fl |= DIJC_WDMGAMEPORT;
  2427. if(
  2428. #else
  2429. if( (fl & DIJC_WDMGAMEPORT) &&
  2430. #endif
  2431. (cbX(*pcfg) >= cbX(DIJOYCONFIG_DX6)) )
  2432. {
  2433. #ifndef WINNT
  2434. if( (pcfg->hwc.hws.dwFlags & JOY_HWS_ISANALOGPORTDRIVER) // USB joystick
  2435. && !fVjoydDeviceNotExist ) // WDM gameport joystick and no VJOYD is used.
  2436. {
  2437. /*
  2438. * This is in Win9X, and VJOYD devices are being used.
  2439. * We don't want to add WDM device at the same time.
  2440. */
  2441. hres = E_FAIL;
  2442. }
  2443. else
  2444. #endif
  2445. {
  2446. DIJOYCONFIG cfg;
  2447. GUID guidGameport = {0xcae56030, 0x684a, 0x11d0, 0xd6, 0xf6, 0x00, 0xa0, 0xc9, 0x0f, 0x57, 0xda};
  2448. if( fHasAllBitsFlFl( fl, DIJC_GUIDINSTANCE | DIJC_REGHWCONFIGTYPE | DIJC_GAIN | DIJC_WDMGAMEPORT ) )
  2449. {
  2450. memcpy( &cfg, pcfg, sizeof(DIJOYCONFIG) );
  2451. } else {
  2452. hres = JoyReg_GetConfig( idJoy, &cfg, DIJC_GUIDINSTANCE | DIJC_REGHWCONFIGTYPE | DIJC_GAIN | DIJC_WDMGAMEPORT);
  2453. if( SUCCEEDED(hres) ) {
  2454. if( fl & DIJC_GUIDINSTANCE ) {
  2455. cfg.guidInstance = pcfg->guidInstance;
  2456. }
  2457. if( fl & DIJC_GAIN ) {
  2458. cfg.dwGain = pcfg->dwGain;
  2459. }
  2460. if( fl & DIJC_REGHWCONFIGTYPE ) {
  2461. memcpy( &cfg.hwc, &pcfg->hwc, sizeof(JOYREGHWCONFIG) );
  2462. memcpy( &cfg.wszType, &pcfg->wszType, sizeof(pcfg->wszType) );
  2463. }
  2464. if( fl & DIJC_WDMGAMEPORT ) {
  2465. cfg.guidGameport = pcfg->guidGameport;
  2466. }
  2467. } else {
  2468. memcpy( &cfg, pcfg, sizeof(DIJOYCONFIG) );
  2469. }
  2470. }
  2471. /*
  2472. * use standard guidGameport if it is NULL.
  2473. */
  2474. if( IsEqualGUID(&cfg.guidGameport, &GUID_NULL) )
  2475. {
  2476. memcpy( &cfg.guidGameport, &guidGameport, sizeof(GUID) );
  2477. }
  2478. if( IsEqualGUID(&cfg.guidInstance, &GUID_NULL) )
  2479. {
  2480. DWORD i;
  2481. DIJOYCONFIG cfg2;
  2482. hres = DIWdm_SetConfig(idJoy, &jwc, &cfg, fl );
  2483. if( SUCCEEDED(hres) )
  2484. {
  2485. // We can't set the correct id from above call, so we have to find
  2486. // which id we set and try again.
  2487. for( i=0; i<16; i++ ) {
  2488. hres = JoyReg_GetConfig( i, &cfg2, DIJC_GUIDINSTANCE | DIJC_REGHWCONFIGTYPE | DIJC_GAIN | DIJC_WDMGAMEPORT);
  2489. if( SUCCEEDED(hres) && (i != idJoy) ) {
  2490. if( lstrcmpW(cfg.wszType, cfg2.wszType) == 0 ) {
  2491. hres = DIWdm_SetJoyId(&cfg2.guidInstance, idJoy);
  2492. break;
  2493. }
  2494. }
  2495. }
  2496. hres = JoyReg_SetConfig(idJoy, &jwc, &cfg, fl);
  2497. }
  2498. goto done;
  2499. } else
  2500. {
  2501. /*
  2502. * Since pcfg is not null, we set it here to avoid calling
  2503. * DIWdm_JoyHidMapping. Even if it fails, it doesn't hurt anything.
  2504. */
  2505. hres = JoyReg_SetConfig(idJoy, &jwc, &cfg, fl);
  2506. hres = DIWdm_SetJoyId(&cfg.guidInstance, idJoy);
  2507. hres = JoyReg_SetConfig(idJoy, &jwc, &cfg, fl);
  2508. }
  2509. }
  2510. } else {
  2511. hres = JoyReg_SetConfig(idJoy, &jwc, pcfg, DIJC_UPDATEALIAS | fl);
  2512. if (SUCCEEDED(hres)) {
  2513. #ifdef WINNT
  2514. PostMessage(HWND_BROADCAST, g_wmJoyChanged, idJoy+1, 0L);
  2515. #else
  2516. joyConfigChanged(0);
  2517. fVjoydDeviceNotExist = FALSE;
  2518. #endif
  2519. }
  2520. }
  2521. }
  2522. done:;
  2523. CJoyCfg_LeaveCrit(this);
  2524. }
  2525. ExitOleProcR();
  2526. return hres;
  2527. }
  2528. /*****************************************************************************
  2529. *
  2530. * @doc EXTERNAL
  2531. *
  2532. * @method HRESULT | IDirectInputJoyConfig8 | DeleteConfig |
  2533. *
  2534. * Delete configuration information about a joystick.
  2535. *
  2536. * @cwrap LPDIRECTINPUTJOYCONFIG8 | LPDIRECTINPUTJOYCONFIG8
  2537. *
  2538. * @parm UINT | idJoy |
  2539. *
  2540. * Zero-based joystick identification number.
  2541. *
  2542. * @returns
  2543. *
  2544. * Returns a COM error code. The following error codes are
  2545. * intended to be illustrative and not necessarily comprehensive.
  2546. *
  2547. * <c DI_OK> = <c S_OK>: The operation completed successfully.
  2548. *
  2549. * <c DIERR_NOTACQUIRED>: Joystick configuration has not been
  2550. * acquired. You must call <mf IDirectInputJoyConfig8::Acquire>
  2551. * before you can alter joystick configuration settings.
  2552. *
  2553. * <c DIERR_INVALIDPARAM> = <c E_INVALIDARG>: One or more
  2554. * parameters was invalid.
  2555. *
  2556. *****************************************************************************/
  2557. DIJOYCONFIG c_djcReset = {
  2558. cbX(c_djcReset), /* dwSize */
  2559. { 0}, /* guidInstance */
  2560. { 0}, /* hwc */
  2561. DI_FFNOMINALMAX, /* dwGain */
  2562. { 0}, /* wszType */
  2563. { 0}, /* wszCallout */
  2564. };
  2565. STDMETHODIMP
  2566. CJoyCfg_DeleteConfig(PDJC pdjc, UINT idJoy)
  2567. {
  2568. HRESULT hres;
  2569. EnterProcR(IDirectInputJoyConfig8::DeleteConfig, (_ "pu", pdjc, idJoy));
  2570. if(SUCCEEDED(hres = hresPv(pdjc)))
  2571. {
  2572. PJC this = _thisPvNm(pdjc, djc);
  2573. CJoyCfg_EnterCrit(this);
  2574. if(SUCCEEDED(hres = CJoyCfg_IsAcquired(this)))
  2575. {
  2576. HKEY hk;
  2577. TCHAR tsz[MAX_JOYSTRING];
  2578. DIJOYCONFIG dijcfg;
  2579. hres = DIWdm_DeleteConfig(idJoy);
  2580. #ifndef WINNT
  2581. if( hres == DIERR_DEVICENOTREG ) {
  2582. fVjoydDeviceNotExist = TRUE;
  2583. }
  2584. #endif
  2585. /*
  2586. * To delete it, set everything to the Reset values and
  2587. * delete the configuration subkey.
  2588. */
  2589. if( ( SUCCEEDED(hres) || hres == DIERR_DEVICENOTREG ) &&
  2590. SUCCEEDED(hres = JoyReg_SetConfig(idJoy, &c_djcReset.hwc,
  2591. &c_djcReset, DIJC_SETVALID)) &&
  2592. SUCCEEDED(hres = JoyReg_OpenConfigKey(idJoy, MAXIMUM_ALLOWED,
  2593. REG_OPTION_VOLATILE, &hk)))
  2594. {
  2595. wsprintf(tsz, TEXT("%u"), idJoy + 1);
  2596. // DIWinnt_RegDeleteKey:: name is a mismomer, the function
  2597. // recursively deletes the key and all subkeys.
  2598. DIWinnt_RegDeleteKey(hk, tsz);
  2599. RegCloseKey(hk);
  2600. #ifndef WINNT
  2601. joyConfigChanged(0);
  2602. #endif
  2603. hres = S_OK;
  2604. }
  2605. if( FAILED(hres) )
  2606. {
  2607. if( FAILED( JoyReg_GetConfig(idJoy, &dijcfg, DIJC_REGHWCONFIGTYPE | DIJC_GUIDINSTANCE) ) )
  2608. {
  2609. /* No config exists, so vacuous success on delete */
  2610. hres = S_FALSE;
  2611. }
  2612. }
  2613. }
  2614. CJoyCfg_LeaveCrit(this);
  2615. }
  2616. ExitOleProcR();
  2617. return hres;
  2618. }
  2619. /*****************************************************************************
  2620. *
  2621. * @doc EXTERNAL
  2622. *
  2623. * @method HRESULT | IDirectInputJoyConfig8 | GetUserValues |
  2624. *
  2625. * Obtain information about user settings for the joystick.
  2626. *
  2627. *
  2628. * @cwrap LPDIRECTINPUTJOYCONFIG8 | LPDIRECTINPUTJOYCONFIG8
  2629. *
  2630. * @parm IN OUT LPDIJOYUSERVALUES | pjuv |
  2631. *
  2632. * Receives information about the user joystick configuration.
  2633. * The caller "must" initialize the <e DIJOYUSERVALUES.dwSize>
  2634. * field before calling this method.
  2635. *
  2636. * @parm DWORD | dwFlags |
  2637. *
  2638. * Zero or more <c DIJU_*> flags specifying which parts
  2639. * of the <t DIJOYUSERVALUES> structure contain values
  2640. * which are to be retrieved.
  2641. *
  2642. * @returns
  2643. *
  2644. * Returns a COM error code. The following error codes are
  2645. * intended to be illustrative and not necessarily comprehensive.
  2646. *
  2647. * <c DI_OK> = <c S_OK>: The operation completed successfully.
  2648. *
  2649. * <c DIERR_INVALIDPARAM> = <c E_INVALIDARG>: One or more
  2650. * parameters was invalid.
  2651. *
  2652. *****************************************************************************/
  2653. STDMETHODIMP
  2654. CJoyCfg_GetUserValues(PDJC pdjc, LPDIJOYUSERVALUES pjuv, DWORD fl)
  2655. {
  2656. HRESULT hres;
  2657. EnterProcR(IDirectInputJoyConfig8::GetUserValues,
  2658. (_ "ppx", pdjc, pjuv, fl));
  2659. if(SUCCEEDED(hres = hresPv(pdjc)) &&
  2660. SUCCEEDED(hres = hresFullValidWritePxCb(pjuv, DIJOYUSERVALUES, 2)) &&
  2661. SUCCEEDED(hres = hresFullValidFl(fl, DIJU_GETVALID, 3)))
  2662. {
  2663. PJC this = _thisPvNm(pdjc, djc);
  2664. hres = JoyReg_GetUserValues(pjuv, fl);
  2665. }
  2666. ExitOleProcR();
  2667. return hres;
  2668. }
  2669. /*****************************************************************************
  2670. *
  2671. * @doc INTERNAL
  2672. *
  2673. * @func HRESULT | hresFullValidUVStr |
  2674. *
  2675. * Validate a string field in a <t DIJOYUSERVALUES>.
  2676. *
  2677. * @parm IN LPCWSTR | pwsz |
  2678. *
  2679. * String to be validated.
  2680. *
  2681. * @parm UINT | cwch |
  2682. *
  2683. * Maximum string length.
  2684. *
  2685. * @parm LPCSTR | pszName |
  2686. *
  2687. * Field name.
  2688. *
  2689. * @returns
  2690. *
  2691. * Returns a COM error code. The following error codes are
  2692. * intended to be illustrative and not necessarily comprehensive.
  2693. *
  2694. * <c DI_OK> = <c S_OK>: The operation completed successfully.
  2695. *
  2696. * <c DIERR_INVALIDPARAM> = <c E_INVALIDARG>: One or more
  2697. * parameters was invalid.
  2698. *
  2699. *****************************************************************************/
  2700. #ifndef XDEBUG
  2701. #define hresFullValidUVStr_(pwsz, cwch, pszName, z, i) \
  2702. _hresFullValidUVStr_(pwsz, cwch) \
  2703. #endif
  2704. #define hresFullValidUVStr(pjuv, f, iarg) \
  2705. hresFullValidUVStr_(pjuv->f, cA(pjuv->f), #f, s_szProc,iarg)\
  2706. HRESULT INLINE
  2707. hresFullValidUVStr_(LPCWSTR pwsz, UINT cwch, LPCSTR pszName,
  2708. LPCSTR s_szProc, int iarg)
  2709. {
  2710. HRESULT hres;
  2711. if(SUCCEEDED(hres = hresFullValidReadStrW(pwsz, cwch, iarg)))
  2712. {
  2713. } else
  2714. {
  2715. #ifdef XDEBUG
  2716. RPF("%s: Invalid value for DIJOYUSERVALUES.%s", s_szProc, pszName);
  2717. #endif
  2718. }
  2719. return hres;
  2720. }
  2721. /*****************************************************************************
  2722. *
  2723. * @doc EXTERNAL
  2724. *
  2725. * @method HRESULT | IDirectInputJoyConfig8 | SetUserValues |
  2726. *
  2727. * Set the user settings for the joystick.
  2728. *
  2729. * @cwrap LPDIRECTINPUTJOYCONFIG8 | LPDIRECTINPUTJOYCONFIG8
  2730. *
  2731. * @parm IN LPCDIJOYUSERVALUES | pjuv |
  2732. *
  2733. * Contains information about the new user joystick settings.
  2734. *
  2735. * @parm DWORD | dwFlags |
  2736. *
  2737. * Zero or more <c DIJU_*> flags specifying which parts
  2738. * of the <t DIJOYUSERVALUES> structure contain values
  2739. * which are to be set.
  2740. *
  2741. * @returns
  2742. *
  2743. * Returns a COM error code. The following error codes are
  2744. * intended to be illustrative and not necessarily comprehensive.
  2745. *
  2746. * <c DI_OK> = <c S_OK>: The operation completed successfully.
  2747. *
  2748. * <c DIERR_NOTACQUIRED>: Joystick configuration has not been
  2749. * acquired. You must call <mf IDirectInputJoyConfig8::Acquire>
  2750. * before you can alter joystick configuration settings.
  2751. *
  2752. * <c DIERR_INVALIDPARAM> = <c E_INVALIDARG>: One or more
  2753. * parameters was invalid.
  2754. *
  2755. *****************************************************************************/
  2756. STDMETHODIMP
  2757. CJoyCfg_SetUserValues(PDJC pdjc, LPCDIJOYUSERVALUES pjuv, DWORD fl)
  2758. {
  2759. HRESULT hres;
  2760. EnterProcR(IDirectInputJoyConfig8::SetUserValues,
  2761. (_ "pp", pdjc, pjuv, fl));
  2762. if(SUCCEEDED(hres = hresPv(pdjc)) &&
  2763. SUCCEEDED(hres = hresFullValidReadPxCb(pjuv, DIJOYUSERVALUES, 2)) &&
  2764. fLimpFF(fl & DIJU_GLOBALDRIVER,
  2765. SUCCEEDED(hres = hresFullValidUVStr(pjuv,
  2766. wszGlobalDriver, 2))) &&
  2767. fLimpFF(fl & DIJU_GAMEPORTEMULATOR,
  2768. SUCCEEDED(hres = hresFullValidUVStr(pjuv,
  2769. wszGameportEmulator, 2))) &&
  2770. SUCCEEDED(hres = hresFullValidFl(fl, DIJU_SETVALID, 3)))
  2771. {
  2772. PJC this = _thisPvNm(pdjc, djc);
  2773. CJoyCfg_EnterCrit(this);
  2774. if(SUCCEEDED(hres = CJoyCfg_IsAcquired(this)))
  2775. {
  2776. hres = JoyReg_SetUserValues(pjuv, fl);
  2777. }
  2778. CJoyCfg_LeaveCrit(this);
  2779. }
  2780. ExitOleProcR();
  2781. return hres;
  2782. }
  2783. /*****************************************************************************
  2784. *
  2785. * @doc EXTERNAL
  2786. *
  2787. * @method HRESULT | IDirectInputJoyConfig8 | AddNewHardware |
  2788. *
  2789. * Displays the "Add New Hardware" dialog to
  2790. * guide the user through installing
  2791. * new game controller.
  2792. *
  2793. * @cwrap LPDIRECTINPUTJOYCONFIG8 | LPDIRECTINPUTJOYCONFIG8
  2794. *
  2795. * @parm HWND | hwndOwner |
  2796. *
  2797. * Window to act as owner window for UI.
  2798. *
  2799. * @parm REFGUID | rguidClass |
  2800. *
  2801. * <t GUID> which specifies the class of the hardware device
  2802. * to be added. DirectInput comes with the following
  2803. * class <t GUIDs> already defined:
  2804. *
  2805. * <c GUID_KeyboardClass>: Keyboard devices.
  2806. *
  2807. * <c GUID_MouseClass>: Mouse devices.
  2808. *
  2809. * <c GUID_MediaClass>: Media devices, including joysticks.
  2810. *
  2811. * <c GUID_HIDClass>: HID devices.
  2812. *
  2813. * @returns
  2814. *
  2815. * Returns a COM error code. The following error codes are
  2816. * intended to be illustrative and not necessarily comprehensive.
  2817. *
  2818. * <c DI_OK> = <c S_OK>: The operation completed successfully.
  2819. *
  2820. * <c DIERR_INVALIDPARAM> = <c E_INVALIDARG>: One or more
  2821. * parameters was invalid.
  2822. *
  2823. * <c DIERR_INVALIDCLASSINSTALLER>: The "media" class installer
  2824. * could not be found or is invalid.
  2825. *
  2826. * <c DIERR_CANCELLED>: The user cancelled the operation.
  2827. *
  2828. * <c DIERR_BADINF>: The INF file for the device the user
  2829. * selected could not be found or is invalid or is damaged.
  2830. *
  2831. * <c S_FALSE>: DirectInput could not determine whether the
  2832. * operation completed successfully.
  2833. *
  2834. *****************************************************************************/
  2835. STDMETHODIMP
  2836. CJoyCfg_AddNewHardware(PDJC pdjc, HWND hwnd, REFGUID rguid)
  2837. {
  2838. HRESULT hres;
  2839. EnterProcR(IDirectInputJoyConfig8::AddNewHardware,
  2840. (_ "pxG", pdjc, hwnd, rguid));
  2841. if(SUCCEEDED(hres = hresPv(pdjc)) &&
  2842. SUCCEEDED(hres = hresFullValidHwnd0(hwnd, 1)) &&
  2843. SUCCEEDED(hres = hresFullValidGuid(rguid, 2)))
  2844. {
  2845. PJC this = _thisPvNm(pdjc, djc);
  2846. hres = AddNewHardware(hwnd, rguid);
  2847. }
  2848. ExitOleProcR();
  2849. return hres;
  2850. }
  2851. /*****************************************************************************
  2852. *
  2853. * @doc EXTERNAL
  2854. *
  2855. * @method HRESULT | IDirectInputJoyConfig8 | OpenTypeKey |
  2856. *
  2857. * Open the registry key associated with a joystick type.
  2858. *
  2859. * Control panel applications can use this key to store
  2860. * per-type persistent information, such as global
  2861. * configuration parameters.
  2862. *
  2863. * Such private information should be kept in a subkey
  2864. * named "OEM"; do not store private information in the
  2865. * main type key.
  2866. *
  2867. * Control panel applications can also use this key to
  2868. * read configuration information, such as the strings
  2869. * to use for device calibration prompts.
  2870. *
  2871. * The application should use <f RegCloseKey> to close
  2872. * the registry key.
  2873. *
  2874. * @cwrap LPDIRECTINPUTJOYCONFIG8 | LPDIRECTINPUTJOYCONFIG8
  2875. *
  2876. * @parm LPCWSTR | pwszType |
  2877. *
  2878. * Points to the name of the type. The name of the type may
  2879. * not exceed <c MAX_PATH> characters, including the terminating
  2880. * null character.
  2881. *
  2882. * The name may not begin with
  2883. * a "#" character. Types beginning with "#" are reserved
  2884. * by DirectInput.
  2885. *
  2886. * @parm REGSAM | regsam |
  2887. *
  2888. * Registry security access mask. This can be any of the
  2889. * values permitted by the <f RegOpenKeyEx> function.
  2890. * If write access is requested, then joystick
  2891. * configuration must first have been acquired.
  2892. * If only read access is requested, then acquisition is
  2893. * not required.
  2894. *
  2895. * @parm PHKEY | phk |
  2896. *
  2897. * Receives the opened registry key on success.
  2898. *
  2899. * @returns
  2900. *
  2901. * Returns a COM error code. The following error codes are
  2902. * intended to be illustrative and not necessarily comprehensive.
  2903. *
  2904. * <c DI_OK> = <c S_OK>: The operation completed successfully.
  2905. *
  2906. * <c DIERR_NOTACQUIRED>: Joystick configuration has not been
  2907. * acquired. You must call <mf IDirectInputJoyConfig8::Acquire>
  2908. * before you can open a joystick type configuration key
  2909. * for writing.
  2910. *
  2911. * <c DIERR_INVALIDPARAM> = <c E_INVALIDARG>: One or more
  2912. * parameters was invalid.
  2913. *
  2914. * <c MAKE_HRESULT(SEVERITY_ERROR, FACILITY_WIN32, ErrorCode)>:
  2915. * A Win32 error code if access to the key is denied by
  2916. * registry permissions or some other external factor.
  2917. *
  2918. *****************************************************************************/
  2919. STDMETHODIMP
  2920. CJoyCfg_OpenTypeKey(PDJC pdjc, LPCWSTR pwszType, REGSAM sam, PHKEY phk)
  2921. {
  2922. HRESULT hres;
  2923. EnterProcR(IDirectInputJoyConfig8::OpenTypeKey,
  2924. (_ "pWx", pdjc, pwszType, sam));
  2925. if(SUCCEEDED(hres = hresPv(pdjc)) &&
  2926. SUCCEEDED(hres = hresFullValidReadStrW(pwszType, MAX_JOYSTRING, 1)) &&
  2927. SUCCEEDED(hres = hresFullValidPcbOut(phk, cbX(*phk), 3)))
  2928. {
  2929. PJC this = _thisPvNm(pdjc, djc);
  2930. if(pwszType[0] != TEXT('#'))
  2931. {
  2932. /*
  2933. * Attempting to get write access requires acquisition.
  2934. */
  2935. if(fLimpFF(IsWriteSam(sam),
  2936. SUCCEEDED(hres = CJoyCfg_IsAcquired(this))))
  2937. {
  2938. hres = JoyReg_OpenTypeKey(pwszType, sam, REG_OPTION_NON_VOLATILE, phk);
  2939. }
  2940. } else
  2941. {
  2942. RPF("%s: Invalid pwszType (predefined)", s_szProc);
  2943. hres = E_INVALIDARG;
  2944. }
  2945. }
  2946. ExitOleProcR();
  2947. return hres;
  2948. }
  2949. /*****************************************************************************
  2950. *
  2951. * @doc EXTERNAL
  2952. *
  2953. * @method HRESULT | IDirectInputJoyConfig8 | OpenAppStatusKey |
  2954. *
  2955. * Opens the root key of the application status registry keys.
  2956. *
  2957. * Hardware vendors can use the sub keys of this key to inspect the
  2958. * status of DirectInput applications with respect to the
  2959. * functionality they use. The key is opened with KEY_READ access.
  2960. *
  2961. * Vendors are cautioned against opening these keys directly (by
  2962. * finding the absolute path of the key rather than using this method)
  2963. * as the absolute registry path may vary on different Windows
  2964. * platforms or in future versions of DirectInput.
  2965. *
  2966. * The application should use <f RegCloseKey> to close
  2967. * the registry key.
  2968. *
  2969. * @cwrap LPDIRECTINPUTJOYCONFIG8 | LPDIRECTINPUTJOYCONFIG8
  2970. *
  2971. * @parm PHKEY | phk |
  2972. *
  2973. * Receives the opened registry key on success.
  2974. *
  2975. * @returns
  2976. *
  2977. * Returns a COM error code. The following error codes are
  2978. * intended to be illustrative and not necessarily comprehensive.
  2979. *
  2980. * <c DI_OK> = <c S_OK>: The operation completed successfully.
  2981. *
  2982. * <c DIERR_INVALIDPARAM> = <c E_INVALIDARG>: One or more
  2983. * parameters was invalid.
  2984. *
  2985. * <c DIERR_NOTFOUND>: The key is missing on this system.
  2986. * Applications should proceed as if the key were empty.
  2987. *
  2988. * <c MAKE_HRESULT(SEVERITY_ERROR, FACILITY_WIN32, ErrorCode)>:
  2989. * A Win32 error code if access to the key is denied by
  2990. * registry permissions or some other external factor.
  2991. *
  2992. *****************************************************************************/
  2993. STDMETHODIMP
  2994. CJoyCfg_OpenAppStatusKey(PDJC pdjc, PHKEY phk)
  2995. {
  2996. HRESULT hres;
  2997. EnterProcR(IDirectInputJoyConfig8::OpenAppStatusKey,
  2998. (_ "pp", pdjc, phk));
  2999. if(SUCCEEDED(hres = hresPv(pdjc)) &&
  3000. SUCCEEDED(hres = hresFullValidPcbOut(phk, cbX(*phk), 1)))
  3001. {
  3002. PJC this = _thisPvNm(pdjc, djc);
  3003. hres = hresMumbleKeyEx( HKEY_CURRENT_USER, REGSTR_PATH_DINPUT,
  3004. KEY_READ, REG_OPTION_NON_VOLATILE, phk);
  3005. }
  3006. ExitOleProcR();
  3007. return hres;
  3008. }
  3009. /*****************************************************************************
  3010. *
  3011. * CJoyCfg_New (constructor)
  3012. *
  3013. *****************************************************************************/
  3014. STDMETHODIMP
  3015. CJoyCfg_New(PUNK punkOuter, RIID riid, PPV ppvObj)
  3016. {
  3017. HRESULT hres;
  3018. EnterProcI(IDirectInputJoyConfig8::<constructor>,
  3019. (_ "p", ppvObj));
  3020. if (SUCCEEDED(hres = hresFullValidPcbOut(ppvObj, cbX(*ppvObj), 3)))
  3021. {
  3022. LPVOID pvTry = NULL;
  3023. hres = Common_NewRiid(CJoyCfg, punkOuter, riid, &pvTry);
  3024. if(SUCCEEDED(hres))
  3025. {
  3026. /* Must use _thisPv in case of aggregation */
  3027. PJC this = _thisPv(pvTry);
  3028. this->fCritInited = fInitializeCriticalSection(&this->crst);
  3029. if( this->fCritInited )
  3030. {
  3031. *ppvObj = pvTry;
  3032. hres = S_OK;
  3033. }
  3034. else
  3035. {
  3036. Common_Unhold(this);
  3037. *ppvObj = NULL;
  3038. hres = E_OUTOFMEMORY;
  3039. }
  3040. }
  3041. }
  3042. ExitOleProcPpvR(ppvObj);
  3043. return hres;
  3044. }
  3045. /*****************************************************************************
  3046. *
  3047. * The long-awaited vtbls and templates
  3048. *
  3049. *****************************************************************************/
  3050. #pragma BEGIN_CONST_DATA
  3051. #define CJoyCfg_Signature 0x6766434B /* "JCfg" */
  3052. Primary_Interface_Begin(CJoyCfg, IDirectInputJoyConfig8)
  3053. CJoyCfg_Acquire,
  3054. CJoyCfg_Unacquire,
  3055. CJoyCfg_SetCooperativeLevel,
  3056. CJoyCfg_SendNotify,
  3057. CJoyCfg_EnumTypes,
  3058. CJoyCfg_GetTypeInfo,
  3059. CJoyCfg_SetTypeInfo,
  3060. CJoyCfg_DeleteType,
  3061. CJoyCfg_GetConfig,
  3062. CJoyCfg_SetConfig,
  3063. CJoyCfg_DeleteConfig,
  3064. CJoyCfg_GetUserValues,
  3065. CJoyCfg_SetUserValues,
  3066. CJoyCfg_AddNewHardware,
  3067. CJoyCfg_OpenTypeKey,
  3068. CJoyCfg_OpenAppStatusKey,
  3069. Primary_Interface_End(CJoyCfg, IDirectInputJoyConfig8)