Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

3453 lines
110 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 = NULL;
  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. DWORD dwMaxSubKeyLen;
  1335. BOOL fRetry;
  1336. EnterProcI(CJoyCfg_SnapTypes, (_ "p", this));
  1337. RD(*ppwszz = 0);
  1338. /*
  1339. * If an analog configuration needs to be fixed, the enumeration is
  1340. * restarted because adding/removing keys may mess with the key indicies.
  1341. * Since registry keys can go stale, start from scratch.
  1342. */
  1343. do
  1344. {
  1345. fRetry=FALSE;
  1346. /*
  1347. * Note that it is not safe to cache the registry key in
  1348. * the object. If somebody deletes the registry key, our
  1349. * cached handle goes stale and becomes useless.
  1350. */
  1351. lRc = RegOpenKeyEx(HKEY_LOCAL_MACHINE,
  1352. REGSTR_PATH_JOYOEM, 0,
  1353. KEY_QUERY_VALUE | KEY_ENUMERATE_SUB_KEYS, &hkTypesR);
  1354. /*
  1355. * Note also that if the registry key is not available,
  1356. * we still want to return the predefined types.
  1357. */
  1358. if(lRc == ERROR_SUCCESS)
  1359. {
  1360. lRc = RegQueryInfoKey(hkTypesR, 0, 0, 0, &chkSub,
  1361. &dwMaxSubKeyLen, 0, 0, 0, 0, 0, 0);
  1362. if(lRc == ERROR_SUCCESS )
  1363. {
  1364. } else
  1365. {
  1366. chkSub = 0;
  1367. dwMaxSubKeyLen = 0;
  1368. }
  1369. } else
  1370. {
  1371. hkTypesR = 0;
  1372. chkSub = 0;
  1373. dwMaxSubKeyLen = 0;
  1374. }
  1375. /*
  1376. * Each predefined name is of the form #n\0,
  1377. * which is 3 characters.
  1378. */
  1379. hres = AllocCbPpv(cbCwch( chkSub * (dwMaxSubKeyLen+1) +
  1380. (JOY_HW_PREDEFMAX - JOY_HW_PREDEFMIN)
  1381. * 3 + 1), ppwszz);
  1382. // Not really a bug,we never get to this point with a NULL ptr,
  1383. // but lets keep prefix happy Manbugs: 29340
  1384. if(SUCCEEDED(hres) && *ppwszz != NULL ){
  1385. DWORD dw;
  1386. LPWSTR pwsz;
  1387. /*
  1388. * First add the predef keys.
  1389. */
  1390. for(dw = JOY_HW_PREDEFMIN, pwsz = *ppwszz;
  1391. dw < JOY_HW_PREDEFMAX; dw++)
  1392. {
  1393. *pwsz++ = L'#';
  1394. *pwsz++ = CJoyCfg_CharFromType(dw);
  1395. *pwsz++ = L'\0';
  1396. }
  1397. /*
  1398. * Now add the named keys.
  1399. */
  1400. for(dw = 0; dw < chkSub; dw++)
  1401. {
  1402. #ifdef UNICODE
  1403. lRc = RegEnumKey(hkTypesR, dw, pwsz, dwMaxSubKeyLen+1);
  1404. #else
  1405. CHAR sz[MAX_JOYSTRING];
  1406. lRc = RegEnumKey(hkTypesR, dw, sz, dwMaxSubKeyLen);
  1407. #endif
  1408. if(lRc == ERROR_SUCCESS )
  1409. {
  1410. #ifdef UNICODE
  1411. hres = JoyCfg_CheckTypeKey( hkTypesR, pwsz );
  1412. #else
  1413. hres = JoyCfg_CheckTypeKey( hkTypesR, sz );
  1414. #endif
  1415. if( FAILED( hres ) )
  1416. {
  1417. /*
  1418. * Had to fix type so restart
  1419. */
  1420. FreePpv( ppwszz );
  1421. break;
  1422. }
  1423. if( hres != S_OK )
  1424. {
  1425. /*
  1426. * Ignore this type
  1427. */
  1428. continue;
  1429. }
  1430. #ifdef UNICODE
  1431. pwsz += lstrlenW(pwsz) + 1;
  1432. #else
  1433. pwsz += AToU(pwsz, dwMaxSubKeyLen, sz);
  1434. #endif
  1435. }
  1436. else
  1437. {
  1438. }
  1439. }
  1440. if( SUCCEEDED( hres ) )
  1441. {
  1442. *pwsz = L'\0'; /* Make it ZZ */
  1443. hres = S_OK;
  1444. }
  1445. else
  1446. {
  1447. fRetry = TRUE;
  1448. }
  1449. }
  1450. if(hkTypesR)
  1451. {
  1452. RegCloseKey(hkTypesR);
  1453. }
  1454. } while( fRetry );
  1455. ExitOleProcPpv(ppwszz);
  1456. return hres;
  1457. }
  1458. /*****************************************************************************
  1459. *
  1460. * @doc EXTERNAL
  1461. *
  1462. * @method HRESULT | IDirectInputJoyConfig8 | EnumTypes |
  1463. *
  1464. * Enumerate the joystick types currently supported by
  1465. * DirectInput. A "joystick type" describes how DirectInput
  1466. * should communicate with a joystick device. It includes
  1467. * information such as the presence and
  1468. * locations of each of the axes and the number of buttons
  1469. * supported by the device.
  1470. *
  1471. * @cwrap LPDIRECTINPUTJOYCONFIG8 | LPDIRECTINPUTJOYCONFIG8
  1472. *
  1473. * @parm LPDIJOYTYPECALLBACK | lpCallback |
  1474. *
  1475. * Points to an application-defined callback function.
  1476. * For more information, see the description of the
  1477. * <f DIEnumJoyTypeProc> callback function.
  1478. *
  1479. * @parm IN LPVOID | pvRef |
  1480. *
  1481. * Specifies a 32-bit application-defined
  1482. * value to be passed to the callback function. This value
  1483. * may be any 32-bit value; it is prototyped as an <t LPVOID>
  1484. * for convenience.
  1485. *
  1486. * @returns
  1487. *
  1488. * Returns a COM error code. The following error codes are
  1489. * intended to be illustrative and not necessarily comprehensive.
  1490. *
  1491. * <c DI_OK> = <c S_OK>: The operation completed successfully.
  1492. * Note that if the callback stops the enumeration prematurely,
  1493. * the enumeration is considered to have succeeded.
  1494. *
  1495. * <c DIERR_INVALIDPARAM> = <c E_INVALIDARG>: The
  1496. * callback procedure returned an invalid status code.
  1497. *
  1498. * @cb BOOL CALLBACK | DIEnumJoyTypeProc |
  1499. *
  1500. * An application-defined callback function that receives
  1501. * DirectInput joystick types as a result of a call to the
  1502. * <om IDirectInputJoyConfig8::EnumTypes> method.
  1503. *
  1504. * @parm IN LPCWSTR | pwszTypeName |
  1505. *
  1506. * The name of the joystick type. A buffer of <c MAX_JOYSTRING>
  1507. * characters will be sufficient to hold the type name.
  1508. * The type name should never be shown to the end user; instead,
  1509. * the "display name" should be shown. Use
  1510. * <mf IDirectInputJoyConfig8::GetTypeInfo> to obtain the
  1511. * display name of a joystick type.
  1512. *
  1513. * Type names that begin with a sharp character ("#")
  1514. * represent predefined types which cannot be modified
  1515. * or deleted.
  1516. *
  1517. * @parm IN OUT LPVOID | pvRef |
  1518. * Specifies the application-defined value given in the
  1519. * <mf IDirectInputJoyConfig8::EnumTypes> function.
  1520. *
  1521. * @returns
  1522. *
  1523. * Returns <c DIENUM_CONTINUE> to continue the enumeration
  1524. * or <c DIENUM_STOP> to stop the enumeration.
  1525. *
  1526. * @devnote
  1527. *
  1528. * EnumTypes must snapshot because people will try to get/set/delete
  1529. * during the enumeration.
  1530. *
  1531. * EnumTypes enumerates the predefined types as "#digit".
  1532. *
  1533. *****************************************************************************/
  1534. STDMETHODIMP
  1535. CJoyCfg_EnumTypes(PDJC pdjc, LPDIJOYTYPECALLBACK ptc, LPVOID pvRef)
  1536. {
  1537. HRESULT hres;
  1538. EnterProcR(IDirectInputJoyConfig8::EnumTypes, (_ "ppx", pdjc, ptc, pvRef));
  1539. if(SUCCEEDED(hres = hresPv(pdjc)) &&
  1540. SUCCEEDED(hres = hresFullValidPfn(ptc, 1)))
  1541. {
  1542. PJC this = _thisPvNm(pdjc, djc);
  1543. LPWSTR pwszKeys;
  1544. hres = CJoyCfg_SnapTypes(this, &pwszKeys);
  1545. if(SUCCEEDED(hres))
  1546. {
  1547. LPWSTR pwsz;
  1548. /*
  1549. * Prefix warns that pwszKeys could be null (mb:34685)
  1550. * Little does it know that CJoyCfg_SnapTypes can only return a
  1551. * success if the pointer is not NULL.
  1552. */
  1553. AssertF( pwszKeys );
  1554. /*
  1555. * Surprise! Win95 implements lstrlenW.
  1556. */
  1557. for(pwsz = pwszKeys; *pwsz; pwsz += lstrlenW(pwsz) + 1)
  1558. {
  1559. BOOL fRc;
  1560. /*
  1561. * WARNING! "goto" here! Make sure that nothing
  1562. * is held while we call the callback.
  1563. */
  1564. fRc = Callback(ptc, pwsz, pvRef);
  1565. switch(fRc)
  1566. {
  1567. case DIENUM_STOP: goto enumdoneok;
  1568. case DIENUM_CONTINUE: break;
  1569. default:
  1570. RPF("%s: Invalid return value from callback", s_szProc);
  1571. ValidationException();
  1572. break;
  1573. }
  1574. }
  1575. FreePpv(&pwszKeys);
  1576. hres = DIPort_SnapTypes(&pwszKeys);
  1577. if(SUCCEEDED(hres))
  1578. {
  1579. /*
  1580. * Surprise! Win95 implements lstrlenW.
  1581. */
  1582. for(pwsz = pwszKeys; *pwsz; pwsz += lstrlenW(pwsz) + 1)
  1583. {
  1584. BOOL fRc;
  1585. /*
  1586. * WARNING! "goto" here! Make sure that nothing
  1587. * is held while we call the callback.
  1588. */
  1589. fRc = Callback(ptc, pwsz, pvRef);
  1590. switch(fRc)
  1591. {
  1592. case DIENUM_STOP: goto enumdoneok;
  1593. case DIENUM_CONTINUE: break;
  1594. default:
  1595. RPF("%s: Invalid return value from callback", s_szProc);
  1596. ValidationException();
  1597. break;
  1598. }
  1599. }
  1600. }
  1601. enumdoneok:;
  1602. FreePpv(&pwszKeys);
  1603. hres = S_OK;
  1604. }
  1605. hres = S_OK;
  1606. }
  1607. ExitOleProcR();
  1608. return hres;
  1609. }
  1610. /*****************************************************************************
  1611. *
  1612. * @doc EXTERNAL
  1613. *
  1614. * @method HRESULT | IDirectInputJoyConfig8 | GetTypeInfo |
  1615. *
  1616. * Obtain information about a joystick type.
  1617. *
  1618. * @cwrap LPDIRECTINPUTJOYCONFIG8 | LPDIRECTINPUTJOYCONFIG8
  1619. *
  1620. * @parm LPCWSTR | pwszTypeName |
  1621. *
  1622. * Points to the name of the type, previously obtained
  1623. * from a call to <mf IDirectInputJoyConfig8::EnumTypes>.
  1624. *
  1625. * @parm IN OUT LPDIJOYTYPEINFO | pjti |
  1626. *
  1627. * Receives information about the joystick type.
  1628. * The caller "must" initialize the <e DIJOYTYPEINFO.dwSize>
  1629. * field before calling this method.
  1630. *
  1631. * @parm DWORD | dwFlags |
  1632. *
  1633. * Zero or more <c DITC_*> flags
  1634. * which specify which parts of the structure pointed
  1635. * to by <p pjti> are to be filled in.
  1636. *
  1637. * @returns
  1638. *
  1639. * Returns a COM error code. The following error codes are
  1640. * intended to be illustrative and not necessarily comprehensive.
  1641. *
  1642. * <c DI_OK> = <c S_OK>: The operation completed successfully.
  1643. *
  1644. * <c DIERR_INVALIDPARAM> = <c E_INVALIDARG>: One or more
  1645. * parameters was invalid.
  1646. *
  1647. * <c DIERR_NOTFOUND>: The joystick type was not found.
  1648. *
  1649. *****************************************************************************/
  1650. STDMETHODIMP
  1651. CJoyCfg_GetTypeInfo(PDJC pdjc, LPCWSTR pwszType,
  1652. LPDIJOYTYPEINFO pjti, DWORD fl)
  1653. {
  1654. HRESULT hres;
  1655. EnterProcR(IDirectInputJoyConfig8::GetTypeInfo,
  1656. (_ "pWpx", pdjc, pwszType, pjti, fl));
  1657. if(SUCCEEDED(hres = hresPv(pdjc)) &&
  1658. SUCCEEDED(hres = hresFullValidReadStrW(pwszType, MAX_JOYSTRING, 1)) &&
  1659. SUCCEEDED(hres = hresFullValidWritePxCb3(pjti,
  1660. DIJOYTYPEINFO_DX8,
  1661. DIJOYTYPEINFO_DX6,
  1662. DIJOYTYPEINFO_DX5, 2)) &&
  1663. SUCCEEDED( (pjti->dwSize == cbX(DIJOYTYPEINFO_DX8) )
  1664. ? ( hres = hresFullValidFl(fl, DITC_GETVALID, 3) )
  1665. : (pjti->dwSize == cbX(DIJOYTYPEINFO_DX6 ) )
  1666. ? ( hres = hresFullValidFl(fl, DITC_GETVALID_DX6, 3) )
  1667. : ( hres = hresFullValidFl(fl, DITC_GETVALID_DX5, 3) ) ) )
  1668. {
  1669. PJC this = _thisPvNm(pdjc, djc);
  1670. GUID guid;
  1671. BOOL fParseGuid;
  1672. #ifndef UNICODE
  1673. TCHAR tszType[MAX_PATH/4];
  1674. UToT( tszType, cA(tszType), pwszType );
  1675. fParseGuid = ParseGUID(&guid, tszType);
  1676. #else
  1677. fParseGuid = ParseGUID(&guid, pwszType);
  1678. #endif
  1679. if(pwszType[0] == TEXT('#'))
  1680. {
  1681. hres = JoyReg_GetPredefTypeInfo(pwszType, pjti, fl);
  1682. } else if( fParseGuid )
  1683. {
  1684. hres = DIBusDevice_GetTypeInfo(&guid, pjti, fl);
  1685. }else
  1686. {
  1687. hres = JoyReg_GetTypeInfo(pwszType, pjti, fl);
  1688. }
  1689. }
  1690. ExitOleProcR();
  1691. return hres;
  1692. }
  1693. /*****************************************************************************
  1694. *
  1695. * @doc INTERNAL
  1696. *
  1697. * @func HRESULT | hresFullValidStructStr |
  1698. *
  1699. * Validate a string field in a struct.
  1700. *
  1701. * @parm IN LPCWSTR | pwsz |
  1702. *
  1703. * String to be validated.
  1704. *
  1705. * @parm UINT | cwch |
  1706. *
  1707. * Maximum string length.
  1708. *
  1709. * @parm LPCSTR | pszName |
  1710. *
  1711. * Field name.
  1712. *
  1713. * @returns
  1714. *
  1715. * Returns a COM error code. The following error codes are
  1716. * intended to be illustrative and not necessarily comprehensive.
  1717. *
  1718. * <c DI_OK> = <c S_OK>: The operation completed successfully.
  1719. *
  1720. * <c DIERR_INVALIDPARAM> = <c E_INVALIDARG>: One or more
  1721. * parameters was invalid.
  1722. *
  1723. *****************************************************************************/
  1724. #ifndef XDEBUG
  1725. \
  1726. #define hresFullValidStructStr_(pwsz, cwch, pszName, z, i) \
  1727. _hresFullValidStructStr_(pwsz, cwch) \
  1728. #endif
  1729. #define hresFullValidStructStr(Struct, f, iarg) \
  1730. hresFullValidStructStr_(Struct->f, cA(Struct->f), #f, s_szProc,iarg)\
  1731. HRESULT INLINE
  1732. hresFullValidStructStr_(LPCWSTR pwsz, UINT cwch, LPCSTR pszName,
  1733. LPCSTR s_szProc, int iarg)
  1734. {
  1735. HRESULT hres;
  1736. if(SUCCEEDED(hres = hresFullValidReadStrW(pwsz, cwch, iarg)))
  1737. {
  1738. } else
  1739. {
  1740. #ifdef XDEBUG
  1741. RPF("%s: Invalid value for %s", s_szProc, pszName);
  1742. #endif
  1743. }
  1744. return hres;
  1745. }
  1746. /*****************************************************************************
  1747. *
  1748. * @doc INTERNAL
  1749. *
  1750. * @func HRESULT | hresValidFlags2 |
  1751. *
  1752. * Validate the dwFlags2 value for SetTypeInfo.
  1753. *
  1754. * @parm IN DWORD | dwFlags2 |
  1755. *
  1756. * Flags to be validated.
  1757. *
  1758. * @returns
  1759. *
  1760. * <c DI_OK> = <c S_OK>: The flags appear to be valid.
  1761. *
  1762. * <c DIERR_INVALIDPARAM> = <c E_INVALIDARG>: The flags are invalid.
  1763. *
  1764. *****************************************************************************/
  1765. #ifdef XDEBUG
  1766. #define hresValidFlags2( flags, iarg ) hresValidFlags2_( flags, s_szProc, iarg )
  1767. HRESULT INLINE hresValidFlags2_
  1768. (
  1769. DWORD dwFlags2,
  1770. LPCSTR s_szProc,
  1771. int iarg
  1772. )
  1773. #else
  1774. #define hresValidFlags2( flags, iarg ) hresValidFlags2_( flags )
  1775. HRESULT hresValidFlags2_
  1776. (
  1777. DWORD dwFlags2
  1778. )
  1779. #endif
  1780. {
  1781. if( !( dwFlags2 & ~JOYTYPE_FLAGS2_SETVALID )
  1782. && ( ( GET_DIDEVICE_TYPEANDSUBTYPE( dwFlags2 ) == 0 )
  1783. || GetValidDI8DevType( dwFlags2, 0, 0 ) ) )
  1784. {
  1785. return S_OK;
  1786. }
  1787. else
  1788. {
  1789. #ifdef XDEBUG
  1790. if( dwFlags2 & ~JOYTYPE_FLAGS2_SETVALID )
  1791. {
  1792. RPF("%s: Invalid flags 0x%04x in HIWORD(dwFlags2) of arg %d",
  1793. s_szProc, HIWORD(dwFlags2), iarg);
  1794. }
  1795. if( GET_DIDEVICE_TYPEANDSUBTYPE( dwFlags2 )
  1796. &&!GetValidDI8DevType( dwFlags2, 127, JOY_HWS_HASPOV | JOY_HWS_HASZ ) )
  1797. {
  1798. RPF("%s: Invalid type:subtype 0x%02x:%02x in dwFlags2 of arg %d",
  1799. s_szProc, GET_DIDEVICE_TYPE( dwFlags2 ),
  1800. GET_DIDEVICE_SUBTYPE( dwFlags2 ), iarg );
  1801. }
  1802. #endif
  1803. return E_INVALIDARG;
  1804. }
  1805. }
  1806. /*****************************************************************************
  1807. *
  1808. * @doc EXTERNAL
  1809. *
  1810. * @method HRESULT | IDirectInputJoyConfig8 | SetTypeInfo |
  1811. *
  1812. * Creates a new joystick type
  1813. * or redefine information about an existing joystick type.
  1814. *
  1815. * @cwrap LPDIRECTINPUTJOYCONFIG8 | LPDIRECTINPUTJOYCONFIG8
  1816. *
  1817. * @parm LPCWSTR | pwszTypeName |
  1818. *
  1819. * Points to the name of the type. The name of the type may
  1820. * not exceed MAX_JOYSTRING characters, including the terminating
  1821. * null character.
  1822. *
  1823. * If the type name does not already exist, then it is created.
  1824. *
  1825. * You cannot change the type information for a predefined type.
  1826. *
  1827. * The name may not begin with
  1828. * a "#" character. Types beginning with "#" are reserved
  1829. * by DirectInput.
  1830. *
  1831. * @parm IN LPDIJOYTYPEINFO | pjti |
  1832. *
  1833. * Contains information about the joystick type.
  1834. *
  1835. * @parm DWORD | dwFlags |
  1836. *
  1837. * Zero or more <c DITC_*> flags
  1838. * which specify which parts of the structure pointed
  1839. * to by <p pjti> contain values which are to be set.
  1840. *
  1841. * @parm OUT LPWSTR | pwszVIDPIDTypeName |
  1842. * If the type name is an OEM type not in VID_xxxx&PID_yyyy format,
  1843. * pwszVIDPIDTypeName will return the name in VID_xxxx&PID_yyyy
  1844. * format that is assigned by Dinput.
  1845. * This VID_xxxx&PID_yyyy name should be used in DIJOYCONFIG.wszType
  1846. * field when calling SetConfig.
  1847. *
  1848. * @returns
  1849. *
  1850. * Returns a COM error code. The following error codes are
  1851. * intended to be illustrative and not necessarily comprehensive.
  1852. *
  1853. * <c DI_OK> = <c S_OK>: The operation completed successfully.
  1854. *
  1855. * <c DIERR_NOTACQUIRED>: Joystick configuration has not been
  1856. * acquired. You must call <mf IDirectInputJoyConfig8::Acquire>
  1857. * before you can alter joystick configuration settings.
  1858. *
  1859. * <c DIERR_INVALIDPARAM> = <c E_INVALIDARG>: One or more
  1860. * parameters was invalid.
  1861. *
  1862. * <c DIERR_READONLY>: Attempted to change a predefined type.
  1863. *
  1864. *****************************************************************************/
  1865. typedef struct _TYPENAME {
  1866. WCHAR wszRealTypeName[MAX_JOYSTRING];
  1867. WCHAR wszDITypeName[MAX_JOYSTRING/4];
  1868. } TYPENAME, *LPTYPENAME;
  1869. #ifdef WINNT
  1870. BOOL CALLBACK CJoyCfg_FindTypeProc( LPCWSTR pwszTypeName, LPVOID pv )
  1871. {
  1872. DIJOYTYPEINFO dijti;
  1873. LPTYPENAME lptype = (LPTYPENAME)pv;
  1874. ZeroMemory( &dijti, sizeof(dijti));
  1875. dijti.dwSize = sizeof(dijti);
  1876. if( pwszTypeName[0] == L'\0' || pwszTypeName[0] == L'#' )
  1877. {
  1878. return TRUE;
  1879. } else {
  1880. if( SUCCEEDED(JoyReg_GetTypeInfo(pwszTypeName, &dijti, DITC_REGHWSETTINGS | DITC_DISPLAYNAME)) )
  1881. {
  1882. if( !lstrcmpW(dijti.wszDisplayName, lptype->wszRealTypeName) ) {
  1883. lstrcpynW(lptype->wszDITypeName, pwszTypeName, sizeof(lptype->wszDITypeName)-1 );
  1884. return FALSE;
  1885. }
  1886. }
  1887. }
  1888. return(TRUE);
  1889. }
  1890. #endif // #ifdef WINNT
  1891. STDMETHODIMP
  1892. CJoyCfg_SetTypeInfo(PDJC pdjc, LPCWSTR pwszType,
  1893. LPCDIJOYTYPEINFO pjti, DWORD fl, LPWSTR pwszDITypeName)
  1894. {
  1895. HRESULT hres;
  1896. EnterProcR(IDirectInputJoyConfig8::SetTypeInfo,
  1897. (_ "pWpx", pdjc, pwszType, pjti, fl));
  1898. if(SUCCEEDED(hres = hresPv(pdjc)) &&
  1899. SUCCEEDED(hres = hresFullValidReadStrW(pwszType, MAX_JOYSTRING, 1)) &&
  1900. SUCCEEDED(hres = hresFullValidReadPxCb3((PV)pjti,
  1901. DIJOYTYPEINFO_DX8,
  1902. DIJOYTYPEINFO_DX6,
  1903. DIJOYTYPEINFO_DX5, 2)) &&
  1904. #ifdef WINNT
  1905. SUCCEEDED(hres = hresFullValidFl(pjti->dwFlags1, JOYTYPE_FLAGS1_SETVALID, 3) ) &&
  1906. #endif
  1907. SUCCEEDED( (pjti->dwSize == cbX(DIJOYTYPEINFO_DX8) )
  1908. ? ( hres = hresFullValidFl(fl, DITC_SETVALID, 3) )
  1909. : (pjti->dwSize == cbX(DIJOYTYPEINFO_DX6 ) )
  1910. ? ( hres = hresFullValidFl(fl, DITC_SETVALID_DX6, 3) )
  1911. : ( hres = hresFullValidFl(fl, DITC_SETVALID_DX5, 3) ) ) &&
  1912. fLimpFF(fl & DITC_HARDWAREID,
  1913. SUCCEEDED(hres = hresFullValidStructStr(pjti, wszHardwareId, 2))) &&
  1914. fLimpFF(fl & DITC_DISPLAYNAME,
  1915. SUCCEEDED(hres = hresFullValidStructStr(pjti, wszDisplayName, 2))) &&
  1916. #ifndef WINNT
  1917. fLimpFF(fl & DITC_CALLOUT,
  1918. SUCCEEDED(hres = hresFullValidStructStr(pjti, wszCallout, 2))) &&
  1919. #endif
  1920. fLimpFF(fl & DITC_FLAGS2,
  1921. SUCCEEDED(hres = hresValidFlags2( pjti->dwFlags2, 2)) ) &&
  1922. fLimpFF(fl & DITC_MAPFILE,
  1923. SUCCEEDED(hres = hresFullValidStructStr(pjti, wszMapFile, 2)))
  1924. )
  1925. {
  1926. PJC this = _thisPvNm(pdjc, djc);
  1927. CJoyCfg_EnterCrit(this);
  1928. if(SUCCEEDED(hres = CJoyCfg_IsAcquired(this)))
  1929. {
  1930. switch(pwszType[0])
  1931. {
  1932. case L'\0':
  1933. RPF("%s: Invalid pwszType (null)", s_szProc);
  1934. hres = E_INVALIDARG;
  1935. break;
  1936. case L'#':
  1937. RPF("%s: Invalid pwszType (predefined)", s_szProc);
  1938. hres = DIERR_READONLY;
  1939. break;
  1940. default:
  1941. hres = JoyReg_SetTypeInfo(this->hkTypesW, pwszType, pjti, fl);
  1942. if( SUCCEEDED(hres) ) {
  1943. #ifdef WINNT
  1944. TYPENAME type;
  1945. short DontCare;
  1946. if( (pjti->wszHardwareId[0] == TEXT('\0')) &&
  1947. !(ParseVIDPID(&DontCare, &DontCare, pwszType)) )
  1948. {
  1949. lstrcpyW(type.wszRealTypeName, pwszType);
  1950. hres = CJoyCfg_EnumTypes(pdjc, CJoyCfg_FindTypeProc, &type);
  1951. if( SUCCEEDED(hres) ) {
  1952. if( !IsBadWritePtr((LPVOID)pwszDITypeName, lstrlenW(type.wszDITypeName)) )
  1953. {
  1954. CharUpperW(type.wszDITypeName);
  1955. lstrcpyW(pwszDITypeName, type.wszDITypeName);
  1956. } else {
  1957. hres = ERROR_NOT_ENOUGH_MEMORY;
  1958. }
  1959. }
  1960. } else
  1961. #endif
  1962. {
  1963. if( !IsBadWritePtr((LPVOID)pwszDITypeName, lstrlenW(pwszType)) )
  1964. {
  1965. lstrcpyW(pwszDITypeName, pwszType);
  1966. } else {
  1967. hres = ERROR_NOT_ENOUGH_MEMORY;
  1968. }
  1969. }
  1970. }
  1971. break;
  1972. }
  1973. }
  1974. CJoyCfg_LeaveCrit(this);
  1975. }
  1976. ExitOleProcR();
  1977. return hres;
  1978. }
  1979. /*****************************************************************************
  1980. *
  1981. * @doc EXTERNAL
  1982. *
  1983. * @method HRESULT | IDirectInputJoyConfig8 | DeleteType |
  1984. *
  1985. * Removes information about a joystick type.
  1986. *
  1987. * Use this method with caution; it is the caller's responsibility
  1988. * to ensure that no joystick refers to the deleted type.
  1989. *
  1990. * @cwrap LPDIRECTINPUTJOYCONFIG8 | LPDIRECTINPUTJOYCONFIG8
  1991. *
  1992. * @parm LPCWSTR | pwszTypeName |
  1993. *
  1994. * Points to the name of the type. The name of the type may
  1995. * not exceed <c MAX_PATH> characters, including the terminating
  1996. * null character.
  1997. *
  1998. * The name may not begin with
  1999. * a "#" character. Types beginning with "#" are reserved
  2000. * by DirectInput.
  2001. *
  2002. * @returns
  2003. *
  2004. * Returns a COM error code. The following error codes are
  2005. * intended to be illustrative and not necessarily comprehensive.
  2006. *
  2007. * <c DI_OK> = <c S_OK>: The operation completed successfully.
  2008. *
  2009. * <c DIERR_NOTACQUIRED>: Joystick configuration has not been
  2010. * acquired. You must call <mf IDirectInputJoyConfig8::Acquire>
  2011. * before you can alter joystick configuration settings.
  2012. *
  2013. * <c DIERR_INVALIDPARAM> = <c E_INVALIDARG>: One or more
  2014. * parameters was invalid.
  2015. *
  2016. *****************************************************************************/
  2017. STDMETHODIMP
  2018. CJoyCfg_DeleteType(PDJC pdjc, LPCWSTR pwszType)
  2019. {
  2020. HRESULT hres;
  2021. EnterProcR(IDirectInputJoyConfig8::DeleteType, (_ "pW", pdjc, pwszType));
  2022. if(SUCCEEDED(hres = hresPv(pdjc)) &&
  2023. SUCCEEDED(hres = hresFullValidReadStrW( pwszType, MAX_JOYSTRING, 1)))
  2024. {
  2025. PJC this = _thisPvNm(pdjc, djc);
  2026. CJoyCfg_EnterCrit(this);
  2027. if(SUCCEEDED(hres = CJoyCfg_IsAcquired(this)))
  2028. {
  2029. LONG lRc;
  2030. switch(pwszType[0])
  2031. {
  2032. case L'\0':
  2033. RPF("%s: Invalid pwszType (null)", s_szProc);
  2034. hres = E_INVALIDARG;
  2035. break;
  2036. case L'#':
  2037. RPF("%s: Invalid pwszType (predefined)", s_szProc);
  2038. hres = DIERR_READONLY;
  2039. break;
  2040. default:
  2041. #ifdef WINNT
  2042. #ifdef UNICODE
  2043. lRc = DIWinnt_RegDeleteKey(this->hkTypesW, (LPTSTR)pwszType);
  2044. #else
  2045. {
  2046. CHAR sz[MAX_PATH];
  2047. UToA( sz, cA(sz), pwszType );
  2048. lRc = DIWinnt_RegDeleteKey(this->hkTypesW, (LPTSTR)sz);
  2049. }
  2050. #endif
  2051. #else
  2052. #ifdef UNICODE
  2053. lRc = RegDeleteKey(this->hkTypesW, (LPTSTR)pwszType);
  2054. #else
  2055. {
  2056. CHAR sz[MAX_PATH];
  2057. UToA( sz, cA(sz), pwszType );
  2058. lRc = RegDeleteKey(this->hkTypesW, (LPTSTR)sz);
  2059. }
  2060. #endif
  2061. #endif
  2062. /*
  2063. #ifdef WINNT
  2064. lRc = DIWinnt_RegDeleteKey(this->hkTypesW, pwszType);
  2065. #else
  2066. lRc = RegDeleteKeyW(this->hkTypesW, pwszType);
  2067. #endif
  2068. */
  2069. if(lRc == ERROR_SUCCESS)
  2070. {
  2071. hres = S_OK;
  2072. } else
  2073. {
  2074. if(lRc == ERROR_KEY_DELETED || lRc == ERROR_BADKEY)
  2075. {
  2076. lRc = ERROR_FILE_NOT_FOUND;
  2077. }
  2078. hres = hresLe(lRc);
  2079. }
  2080. break;
  2081. }
  2082. }
  2083. CJoyCfg_LeaveCrit(this);
  2084. }
  2085. ExitOleProcR();
  2086. return hres;
  2087. }
  2088. /*****************************************************************************
  2089. *
  2090. * @doc EXTERNAL
  2091. *
  2092. * @method HRESULT | IDirectInputJoyConfig8 | GetConfig |
  2093. *
  2094. * Obtain information about a joystick's configuration.
  2095. *
  2096. * @cwrap LPDIRECTINPUTJOYCONFIG8 | LPDIRECTINPUTJOYCONFIG8
  2097. *
  2098. * @parm UINT | uiJoy |
  2099. *
  2100. * Joystick identification number. This is a nonnegative
  2101. * integer. To enumerate joysticks, begin with joystick
  2102. * zero and increment the joystick number by one until the
  2103. * function returns <c DIERR_NOMOREITEMS>.
  2104. *
  2105. * Yes, it's different from all other DirectX enumerations.
  2106. *
  2107. *
  2108. * @parm IN OUT LPDIJOYCONFIG | pjc |
  2109. *
  2110. * Receives information about the joystick configuration.
  2111. * The caller "must" initialize the <e DIJOYCONFIG.dwSize>
  2112. * field before calling this method.
  2113. *
  2114. * @parm DWORD | dwFlags |
  2115. *
  2116. * Zero or more <c DIJC_*> flags
  2117. * which specify which parts of the structure pointed
  2118. * to by <p pjc> are to be filled in.
  2119. *
  2120. * @returns
  2121. *
  2122. * Returns a COM error code. The following error codes are
  2123. * intended to be illustrative and not necessarily comprehensive.
  2124. *
  2125. * <c DI_OK> = <c S_OK>: The operation completed successfully.
  2126. *
  2127. * <c S_FALSE>: The specified joystick has not yet been
  2128. * configured.
  2129. *
  2130. * <c DIERR_INVALIDPARAM> = <c E_INVALIDARG>: One or more
  2131. * parameters was invalid.
  2132. *
  2133. * <c DIERR_NOMOREITEMS>: No more joysticks.
  2134. *
  2135. *****************************************************************************/
  2136. STDMETHODIMP
  2137. CJoyCfg_GetConfig(PDJC pdjc, UINT uiJoy, LPDIJOYCONFIG pjc, DWORD fl)
  2138. {
  2139. HRESULT hres;
  2140. EnterProcR(IDirectInputJoyConfig8::GetConfig,
  2141. (_ "pupx", pdjc, uiJoy, pjc, fl));
  2142. if(SUCCEEDED(hres = hresPv(pdjc)) &&
  2143. SUCCEEDED(hres = hresFullValidWritePxCb2(pjc,
  2144. DIJOYCONFIG_DX6,
  2145. DIJOYCONFIG_DX5, 2)) &&
  2146. SUCCEEDED( (pjc->dwSize == cbX(DIJOYCONFIG)
  2147. ? (hres = hresFullValidFl(fl, DIJC_GETVALID, 3) )
  2148. : (hres = hresFullValidFl(fl, DIJC_GETVALID_DX5, 3)))) )
  2149. {
  2150. PJC this = _thisPvNm(pdjc, djc);
  2151. CJoyCfg_EnterCrit(this);
  2152. /*
  2153. * Note that we always get the DIJC_REGHWCONFIGTYPE because
  2154. * we need to check if the joystick type is "none".
  2155. */
  2156. hres = JoyReg_GetConfig(uiJoy, pjc, fl | DIJC_REGHWCONFIGTYPE);
  2157. if(SUCCEEDED(hres))
  2158. {
  2159. #ifndef WINNT
  2160. static WCHAR s_wszMSGAME[] = L"MSGAME.VXD";
  2161. if(memcmp(pjc->wszCallout, s_wszMSGAME, cbX(s_wszMSGAME)) == 0)
  2162. {
  2163. ; // do nothing
  2164. } else
  2165. #endif
  2166. if(fInOrder(JOY_HW_PREDEFMIN, pjc->hwc.dwType,
  2167. JOY_HW_PREDEFMAX))
  2168. {
  2169. pjc->wszType[0] = TEXT('#');
  2170. pjc->wszType[1] = CJoyCfg_CharFromType(pjc->hwc.dwType);
  2171. pjc->wszType[2] = TEXT('\0');
  2172. }
  2173. if(pjc->hwc.dwType == JOY_HW_NONE)
  2174. {
  2175. hres = S_FALSE;
  2176. } else
  2177. {
  2178. hres = S_OK;
  2179. }
  2180. /*
  2181. * In DEBUG, re-scramble the hwc and type if the caller
  2182. * didn't ask for it.
  2183. */
  2184. if(!(fl & DIJC_REGHWCONFIGTYPE))
  2185. {
  2186. ScrambleBuf(&pjc->hwc, cbX(pjc->hwc));
  2187. ScrambleBuf(&pjc->wszType, cbX(pjc->wszType));
  2188. }
  2189. }
  2190. CJoyCfg_LeaveCrit(this);
  2191. }
  2192. ExitBenignOleProcR();
  2193. return hres;
  2194. }
  2195. #if 0
  2196. /*****************************************************************************
  2197. *
  2198. * @doc INTERNAL
  2199. *
  2200. * @method HRESULT | CJoyCfg | UpdateGlobalGain |
  2201. *
  2202. * Create the device callback so we can talk to its driver and
  2203. * tell it to change the gain value.
  2204. *
  2205. * This function must be called under the object critical section.
  2206. *
  2207. * @cwrap PJC | this
  2208. *
  2209. * @parm DWORD | idJoy |
  2210. *
  2211. * The joystick identifier.
  2212. *
  2213. * @parm DWORD | dwCplGain |
  2214. *
  2215. * New global gain.
  2216. *
  2217. * @returns
  2218. *
  2219. * Returns a COM error code.
  2220. *
  2221. *****************************************************************************/
  2222. STDMETHODIMP
  2223. CJoyCfg_UpdateGlobalGain(PJC this, DWORD idJoy, DWORD dwCplGain)
  2224. {
  2225. HRESULT hres;
  2226. EnterProcI(CJoyCfg_UpdateGlobalGain, (_ "puu", this, idJoy, dwCplGain));
  2227. AssertF(CJoyCfg_InCrit(this));
  2228. /*
  2229. * Create the deviceeffect shepherd if we don't already have it.
  2230. */
  2231. if(this->pes && idJoy == this->idJoyCache)
  2232. {
  2233. hres = S_OK;
  2234. } else if(idJoy < cA(rgGUID_Joystick))
  2235. {
  2236. PCGUID rguid;
  2237. #ifdef DEBUG
  2238. CREATEDCB CreateDcb;
  2239. #endif
  2240. IDirectInputDeviceCallback *pdcb;
  2241. /*
  2242. * Assume the creation will work.
  2243. */
  2244. this->idJoyCache = idJoy;
  2245. /*
  2246. * Out with the old...
  2247. */
  2248. Invoke_Release(&this->pes);
  2249. /*
  2250. * And in with the new...
  2251. */
  2252. rguid = &rgGUID_Joystick[idJoy];
  2253. #ifdef DEBUG
  2254. hres = hresFindInstanceGUID(rguid, &CreateDcb, 1);
  2255. AssertF(SUCCEEDED(hres));
  2256. AssertF(CreateDcb == CJoy_New);
  2257. #endif
  2258. if(SUCCEEDED(hres = CJoy_New(0, rguid,
  2259. &IID_IDirectInputDeviceCallback,
  2260. (PPV)&pdcb)))
  2261. {
  2262. hres = pdcb->lpVtbl->CreateEffect(pdcb, &this->pes);
  2263. Invoke_Release(&pdcb);
  2264. }
  2265. } else
  2266. {
  2267. hres = DIERR_DEVICENOTREG;
  2268. }
  2269. /*
  2270. * If we have an effect shepherd, then tell it what the new
  2271. * global gain is.
  2272. */
  2273. if(SUCCEEDED(hres))
  2274. {
  2275. AssertF(this->pes && idJoy == this->idJoyCache);
  2276. hres = this->pes->lpVtbl->SetGlobalGain(this->pes, dwCplGain);
  2277. }
  2278. ExitOleProc();
  2279. return hres;
  2280. }
  2281. #endif
  2282. /*****************************************************************************
  2283. *
  2284. * @doc EXTERNAL
  2285. *
  2286. * @method HRESULT | IDirectInputJoyConfig8 | SetConfig |
  2287. *
  2288. * Create or redefine configuration information about a joystick.
  2289. *
  2290. * @cwrap LPDIRECTINPUTJOYCONFIG8 | LPDIRECTINPUTJOYCONFIG8
  2291. *
  2292. * @parm UINT | idJoy |
  2293. *
  2294. * Zero-based joystick identification number.
  2295. *
  2296. * @parm IN LPDIJOYCONFIG | pcfg |
  2297. *
  2298. * Contains information about the joystick.
  2299. *
  2300. * @parm DWORD | dwFlags |
  2301. *
  2302. * Zero or more <c DIJC_*> flags
  2303. * which specify which parts of the structure pointed
  2304. * to by <p pjc> contain information to be set.
  2305. *
  2306. * @returns
  2307. *
  2308. * Returns a COM error code. The following error codes are
  2309. * intended to be illustrative and not necessarily comprehensive.
  2310. *
  2311. * <c DI_OK> = <c S_OK>: The operation completed successfully.
  2312. *
  2313. * <c DIERR_NOTACQUIRED>: Joystick configuration has not been
  2314. * acquired. You must call <mf IDirectInputJoyConfig8::Acquire>
  2315. * before you can alter joystick configuration settings.
  2316. *
  2317. * <c DIERR_INVALIDPARAM> = <c E_INVALIDARG>: One or more
  2318. * parameters was invalid.
  2319. *
  2320. * @devnote
  2321. *
  2322. * This one is tricky. If the type begins with a sharp, then
  2323. * it's an internal type. And if it is null, then it's a
  2324. * custom type.
  2325. *
  2326. *
  2327. *****************************************************************************/
  2328. STDMETHODIMP
  2329. CJoyCfg_SetConfig(PDJC pdjc, UINT idJoy, LPCDIJOYCONFIG pcfg, DWORD fl)
  2330. {
  2331. HRESULT hres;
  2332. EnterProcR(IDirectInputJoyConfig8::SetConfig,
  2333. (_ "pupx", pdjc, idJoy, pcfg, fl));
  2334. if(SUCCEEDED(hres = hresPv(pdjc)) &&
  2335. SUCCEEDED(hres = hresFullValidReadPxCb2(pcfg,
  2336. DIJOYCONFIG_DX6,
  2337. DIJOYCONFIG_DX5, 2)) &&
  2338. SUCCEEDED( (pcfg->dwSize == cbX(DIJOYCONFIG)
  2339. ? ( hres = hresFullValidFl(fl, DIJC_SETVALID, 3) )
  2340. : ( hres = hresFullValidFl(fl, DIJC_SETVALID_DX5,3)) )) &&
  2341. fLimpFF(fl & DIJC_REGHWCONFIGTYPE,
  2342. SUCCEEDED(hres = hresFullValidStructStr(pcfg, wszType, 2))) &&
  2343. #ifndef WINNT
  2344. fLimpFF(fl & DIJC_CALLOUT,
  2345. SUCCEEDED(hres = hresFullValidStructStr(pcfg, wszCallout, 2))) &&
  2346. #endif
  2347. fLimpFF(fl & DIJC_WDMGAMEPORT,
  2348. SUCCEEDED(hres = hresFullValidGuid(&pcfg->guidGameport, 2)))
  2349. )
  2350. {
  2351. PJC this = _thisPvNm(pdjc, djc);
  2352. CJoyCfg_EnterCrit(this);
  2353. if(SUCCEEDED(hres = CJoyCfg_IsAcquired(this)))
  2354. {
  2355. JOYREGHWCONFIG jwc;
  2356. // We just ignore the DIJC_WDMGAMEPORT flag for Win9x passed by user.
  2357. // We will detect it ourself.
  2358. #ifndef WINNT
  2359. fl &= ~DIJC_WDMGAMEPORT;
  2360. #endif
  2361. if(fl & DIJC_REGHWCONFIGTYPE)
  2362. {
  2363. LPDWORD lpStart, lp;
  2364. jwc = pcfg->hwc;
  2365. /*
  2366. * Need to check whether the whole jwc is zero.
  2367. * If all are zero, we won't set it to JOY_HW_CUSTOM type.
  2368. * See manbug: 39542.
  2369. */
  2370. for( lpStart=(LPDWORD)&jwc, lp=(LPDWORD)&jwc.dwReserved; lp >= lpStart; lp-- ) {
  2371. if( *lp ) {
  2372. break;
  2373. }
  2374. }
  2375. if( lp < lpStart ) {
  2376. goto _CONTINUE_SET;
  2377. }
  2378. jwc.dwUsageSettings &= ~JOY_US_ISOEM;
  2379. if(pcfg->wszType[0] == TEXT('\0'))
  2380. {
  2381. jwc.dwType = JOY_HW_CUSTOM;
  2382. } else if(pcfg->wszType[0] == TEXT('#'))
  2383. {
  2384. jwc.dwType = CJoyCfg_TypeFromChar(pcfg->wszType[1]);
  2385. if(fInOrder(JOY_HW_PREDEFMIN, jwc.dwType,
  2386. JOY_HW_PREDEFMAX) &&
  2387. pcfg->wszType[2] == TEXT('\0'))
  2388. {
  2389. /*
  2390. * If we want to use WDM for predefined devices,
  2391. * then take away the comments.
  2392. *
  2393. * fl |= DIJC_WDMGAMEPORT;
  2394. */
  2395. } else
  2396. {
  2397. RPF("%s: Invalid predefined type \"%ls\"",
  2398. s_szProc, pcfg->wszType);
  2399. hres = E_INVALIDARG;
  2400. goto done;
  2401. }
  2402. } else
  2403. {
  2404. /*
  2405. * The precise value of jwc.dwType is not relevant.
  2406. * The Windows 95 joystick control panel sets the
  2407. * value to JOY_HW_PREDEFMAX + id, so we will too.
  2408. */
  2409. jwc.dwUsageSettings |= JOY_US_ISOEM;
  2410. jwc.dwType = JOY_HW_PREDEFMAX + idJoy;
  2411. #ifndef WINNT
  2412. if( !(fl & DIJC_WDMGAMEPORT) ) {
  2413. HKEY hk;
  2414. hres = JoyReg_OpenTypeKey(pcfg->wszType, MAXIMUM_ALLOWED, REG_OPTION_NON_VOLATILE, &hk);
  2415. if( SUCCEEDED( hres ) ) {
  2416. hres = JoyReg_IsWdmGameport( hk );
  2417. if( SUCCEEDED(hres) ) {
  2418. fl |= DIJC_WDMGAMEPORT;
  2419. }
  2420. RegCloseKey( hk );
  2421. }
  2422. }
  2423. #endif
  2424. }
  2425. }
  2426. _CONTINUE_SET:
  2427. #ifdef WINNT
  2428. fl |= DIJC_WDMGAMEPORT;
  2429. if(
  2430. #else
  2431. if( (fl & DIJC_WDMGAMEPORT) &&
  2432. #endif
  2433. (cbX(*pcfg) >= cbX(DIJOYCONFIG_DX6)) )
  2434. {
  2435. #ifndef WINNT
  2436. if( (pcfg->hwc.hws.dwFlags & JOY_HWS_ISANALOGPORTDRIVER) // USB joystick
  2437. && !fVjoydDeviceNotExist ) // WDM gameport joystick and no VJOYD is used.
  2438. {
  2439. /*
  2440. * This is in Win9X, and VJOYD devices are being used.
  2441. * We don't want to add WDM device at the same time.
  2442. */
  2443. hres = E_FAIL;
  2444. }
  2445. else
  2446. #endif
  2447. {
  2448. DIJOYCONFIG cfg;
  2449. GUID guidGameport = {0xcae56030, 0x684a, 0x11d0, 0xd6, 0xf6, 0x00, 0xa0, 0xc9, 0x0f, 0x57, 0xda};
  2450. if( fHasAllBitsFlFl( fl, DIJC_GUIDINSTANCE | DIJC_REGHWCONFIGTYPE | DIJC_GAIN | DIJC_WDMGAMEPORT ) )
  2451. {
  2452. memcpy( &cfg, pcfg, sizeof(DIJOYCONFIG) );
  2453. } else {
  2454. hres = JoyReg_GetConfig( idJoy, &cfg, DIJC_GUIDINSTANCE | DIJC_REGHWCONFIGTYPE | DIJC_GAIN | DIJC_WDMGAMEPORT);
  2455. if( SUCCEEDED(hres) ) {
  2456. if( fl & DIJC_GUIDINSTANCE ) {
  2457. cfg.guidInstance = pcfg->guidInstance;
  2458. }
  2459. if( fl & DIJC_GAIN ) {
  2460. cfg.dwGain = pcfg->dwGain;
  2461. }
  2462. if( fl & DIJC_REGHWCONFIGTYPE ) {
  2463. memcpy( &cfg.hwc, &pcfg->hwc, sizeof(JOYREGHWCONFIG) );
  2464. memcpy( &cfg.wszType, &pcfg->wszType, sizeof(pcfg->wszType) );
  2465. }
  2466. if( fl & DIJC_WDMGAMEPORT ) {
  2467. cfg.guidGameport = pcfg->guidGameport;
  2468. }
  2469. } else {
  2470. memcpy( &cfg, pcfg, sizeof(DIJOYCONFIG) );
  2471. }
  2472. }
  2473. /*
  2474. * use standard guidGameport if it is NULL.
  2475. */
  2476. if( IsEqualGUID(&cfg.guidGameport, &GUID_NULL) )
  2477. {
  2478. memcpy( &cfg.guidGameport, &guidGameport, sizeof(GUID) );
  2479. }
  2480. if( IsEqualGUID(&cfg.guidInstance, &GUID_NULL) )
  2481. {
  2482. DWORD i;
  2483. DIJOYCONFIG cfg2;
  2484. hres = DIWdm_SetConfig(idJoy, &jwc, &cfg, fl );
  2485. if( SUCCEEDED(hres) )
  2486. {
  2487. // We can't set the correct id from above call, so we have to find
  2488. // which id we set and try again.
  2489. for( i=0; i<16; i++ ) {
  2490. hres = JoyReg_GetConfig( i, &cfg2, DIJC_GUIDINSTANCE | DIJC_REGHWCONFIGTYPE | DIJC_GAIN | DIJC_WDMGAMEPORT);
  2491. if( SUCCEEDED(hres) && (i != idJoy) ) {
  2492. if( lstrcmpW(cfg.wszType, cfg2.wszType) == 0 ) {
  2493. hres = DIWdm_SetJoyId(&cfg2.guidInstance, idJoy);
  2494. break;
  2495. }
  2496. }
  2497. }
  2498. hres = JoyReg_SetConfig(idJoy, &jwc, &cfg, fl);
  2499. }
  2500. goto done;
  2501. } else
  2502. {
  2503. /*
  2504. * Since pcfg is not null, we set it here to avoid calling
  2505. * DIWdm_JoyHidMapping. Even if it fails, it doesn't hurt anything.
  2506. */
  2507. hres = JoyReg_SetConfig(idJoy, &jwc, &cfg, fl);
  2508. hres = DIWdm_SetJoyId(&cfg.guidInstance, idJoy);
  2509. hres = JoyReg_SetConfig(idJoy, &jwc, &cfg, fl);
  2510. }
  2511. }
  2512. } else {
  2513. hres = JoyReg_SetConfig(idJoy, &jwc, pcfg, DIJC_UPDATEALIAS | fl);
  2514. if (SUCCEEDED(hres)) {
  2515. #ifdef WINNT
  2516. PostMessage(HWND_BROADCAST, g_wmJoyChanged, idJoy+1, 0L);
  2517. #else
  2518. joyConfigChanged(0);
  2519. fVjoydDeviceNotExist = FALSE;
  2520. #endif
  2521. }
  2522. }
  2523. }
  2524. done:;
  2525. CJoyCfg_LeaveCrit(this);
  2526. }
  2527. ExitOleProcR();
  2528. return hres;
  2529. }
  2530. /*****************************************************************************
  2531. *
  2532. * @doc EXTERNAL
  2533. *
  2534. * @method HRESULT | IDirectInputJoyConfig8 | DeleteConfig |
  2535. *
  2536. * Delete configuration information about a joystick.
  2537. *
  2538. * @cwrap LPDIRECTINPUTJOYCONFIG8 | LPDIRECTINPUTJOYCONFIG8
  2539. *
  2540. * @parm UINT | idJoy |
  2541. *
  2542. * Zero-based joystick identification number.
  2543. *
  2544. * @returns
  2545. *
  2546. * Returns a COM error code. The following error codes are
  2547. * intended to be illustrative and not necessarily comprehensive.
  2548. *
  2549. * <c DI_OK> = <c S_OK>: The operation completed successfully.
  2550. *
  2551. * <c DIERR_NOTACQUIRED>: Joystick configuration has not been
  2552. * acquired. You must call <mf IDirectInputJoyConfig8::Acquire>
  2553. * before you can alter joystick configuration settings.
  2554. *
  2555. * <c DIERR_INVALIDPARAM> = <c E_INVALIDARG>: One or more
  2556. * parameters was invalid.
  2557. *
  2558. *****************************************************************************/
  2559. DIJOYCONFIG c_djcReset = {
  2560. cbX(c_djcReset), /* dwSize */
  2561. { 0}, /* guidInstance */
  2562. { 0}, /* hwc */
  2563. DI_FFNOMINALMAX, /* dwGain */
  2564. { 0}, /* wszType */
  2565. { 0}, /* wszCallout */
  2566. };
  2567. STDMETHODIMP
  2568. CJoyCfg_DeleteConfig(PDJC pdjc, UINT idJoy)
  2569. {
  2570. HRESULT hres;
  2571. EnterProcR(IDirectInputJoyConfig8::DeleteConfig, (_ "pu", pdjc, idJoy));
  2572. if(SUCCEEDED(hres = hresPv(pdjc)))
  2573. {
  2574. PJC this = _thisPvNm(pdjc, djc);
  2575. CJoyCfg_EnterCrit(this);
  2576. if(SUCCEEDED(hres = CJoyCfg_IsAcquired(this)))
  2577. {
  2578. HKEY hk;
  2579. TCHAR tsz[MAX_JOYSTRING];
  2580. DIJOYCONFIG dijcfg;
  2581. hres = DIWdm_DeleteConfig(idJoy);
  2582. #ifndef WINNT
  2583. if( hres == DIERR_DEVICENOTREG ) {
  2584. fVjoydDeviceNotExist = TRUE;
  2585. }
  2586. #endif
  2587. /*
  2588. * To delete it, set everything to the Reset values and
  2589. * delete the configuration subkey.
  2590. */
  2591. if( ( SUCCEEDED(hres) || hres == DIERR_DEVICENOTREG ) &&
  2592. SUCCEEDED(hres = JoyReg_SetConfig(idJoy, &c_djcReset.hwc,
  2593. &c_djcReset, DIJC_SETVALID)) &&
  2594. SUCCEEDED(hres = JoyReg_OpenConfigKey(idJoy, MAXIMUM_ALLOWED,
  2595. REG_OPTION_VOLATILE, &hk)))
  2596. {
  2597. wsprintf(tsz, TEXT("%u"), idJoy + 1);
  2598. // DIWinnt_RegDeleteKey:: name is a mismomer, the function
  2599. // recursively deletes the key and all subkeys.
  2600. DIWinnt_RegDeleteKey(hk, tsz);
  2601. RegCloseKey(hk);
  2602. #ifndef WINNT
  2603. joyConfigChanged(0);
  2604. #endif
  2605. hres = S_OK;
  2606. }
  2607. if( FAILED(hres) )
  2608. {
  2609. if( FAILED( JoyReg_GetConfig(idJoy, &dijcfg, DIJC_REGHWCONFIGTYPE | DIJC_GUIDINSTANCE) ) )
  2610. {
  2611. /* No config exists, so vacuous success on delete */
  2612. hres = S_FALSE;
  2613. }
  2614. }
  2615. }
  2616. CJoyCfg_LeaveCrit(this);
  2617. }
  2618. ExitOleProcR();
  2619. return hres;
  2620. }
  2621. /*****************************************************************************
  2622. *
  2623. * @doc EXTERNAL
  2624. *
  2625. * @method HRESULT | IDirectInputJoyConfig8 | GetUserValues |
  2626. *
  2627. * Obtain information about user settings for the joystick.
  2628. *
  2629. *
  2630. * @cwrap LPDIRECTINPUTJOYCONFIG8 | LPDIRECTINPUTJOYCONFIG8
  2631. *
  2632. * @parm IN OUT LPDIJOYUSERVALUES | pjuv |
  2633. *
  2634. * Receives information about the user joystick configuration.
  2635. * The caller "must" initialize the <e DIJOYUSERVALUES.dwSize>
  2636. * field before calling this method.
  2637. *
  2638. * @parm DWORD | dwFlags |
  2639. *
  2640. * Zero or more <c DIJU_*> flags specifying which parts
  2641. * of the <t DIJOYUSERVALUES> structure contain values
  2642. * which are to be retrieved.
  2643. *
  2644. * @returns
  2645. *
  2646. * Returns a COM error code. The following error codes are
  2647. * intended to be illustrative and not necessarily comprehensive.
  2648. *
  2649. * <c DI_OK> = <c S_OK>: The operation completed successfully.
  2650. *
  2651. * <c DIERR_INVALIDPARAM> = <c E_INVALIDARG>: One or more
  2652. * parameters was invalid.
  2653. *
  2654. *****************************************************************************/
  2655. STDMETHODIMP
  2656. CJoyCfg_GetUserValues(PDJC pdjc, LPDIJOYUSERVALUES pjuv, DWORD fl)
  2657. {
  2658. HRESULT hres;
  2659. EnterProcR(IDirectInputJoyConfig8::GetUserValues,
  2660. (_ "ppx", pdjc, pjuv, fl));
  2661. if(SUCCEEDED(hres = hresPv(pdjc)) &&
  2662. SUCCEEDED(hres = hresFullValidWritePxCb(pjuv, DIJOYUSERVALUES, 2)) &&
  2663. SUCCEEDED(hres = hresFullValidFl(fl, DIJU_GETVALID, 3)))
  2664. {
  2665. PJC this = _thisPvNm(pdjc, djc);
  2666. hres = JoyReg_GetUserValues(pjuv, fl);
  2667. }
  2668. ExitOleProcR();
  2669. return hres;
  2670. }
  2671. /*****************************************************************************
  2672. *
  2673. * @doc INTERNAL
  2674. *
  2675. * @func HRESULT | hresFullValidUVStr |
  2676. *
  2677. * Validate a string field in a <t DIJOYUSERVALUES>.
  2678. *
  2679. * @parm IN LPCWSTR | pwsz |
  2680. *
  2681. * String to be validated.
  2682. *
  2683. * @parm UINT | cwch |
  2684. *
  2685. * Maximum string length.
  2686. *
  2687. * @parm LPCSTR | pszName |
  2688. *
  2689. * Field name.
  2690. *
  2691. * @returns
  2692. *
  2693. * Returns a COM error code. The following error codes are
  2694. * intended to be illustrative and not necessarily comprehensive.
  2695. *
  2696. * <c DI_OK> = <c S_OK>: The operation completed successfully.
  2697. *
  2698. * <c DIERR_INVALIDPARAM> = <c E_INVALIDARG>: One or more
  2699. * parameters was invalid.
  2700. *
  2701. *****************************************************************************/
  2702. #ifndef XDEBUG
  2703. #define hresFullValidUVStr_(pwsz, cwch, pszName, z, i) \
  2704. _hresFullValidUVStr_(pwsz, cwch) \
  2705. #endif
  2706. #define hresFullValidUVStr(pjuv, f, iarg) \
  2707. hresFullValidUVStr_(pjuv->f, cA(pjuv->f), #f, s_szProc,iarg)\
  2708. HRESULT INLINE
  2709. hresFullValidUVStr_(LPCWSTR pwsz, UINT cwch, LPCSTR pszName,
  2710. LPCSTR s_szProc, int iarg)
  2711. {
  2712. HRESULT hres;
  2713. if(SUCCEEDED(hres = hresFullValidReadStrW(pwsz, cwch, iarg)))
  2714. {
  2715. } else
  2716. {
  2717. #ifdef XDEBUG
  2718. RPF("%s: Invalid value for DIJOYUSERVALUES.%s", s_szProc, pszName);
  2719. #endif
  2720. }
  2721. return hres;
  2722. }
  2723. /*****************************************************************************
  2724. *
  2725. * @doc EXTERNAL
  2726. *
  2727. * @method HRESULT | IDirectInputJoyConfig8 | SetUserValues |
  2728. *
  2729. * Set the user settings for the joystick.
  2730. *
  2731. * @cwrap LPDIRECTINPUTJOYCONFIG8 | LPDIRECTINPUTJOYCONFIG8
  2732. *
  2733. * @parm IN LPCDIJOYUSERVALUES | pjuv |
  2734. *
  2735. * Contains information about the new user joystick settings.
  2736. *
  2737. * @parm DWORD | dwFlags |
  2738. *
  2739. * Zero or more <c DIJU_*> flags specifying which parts
  2740. * of the <t DIJOYUSERVALUES> structure contain values
  2741. * which are to be set.
  2742. *
  2743. * @returns
  2744. *
  2745. * Returns a COM error code. The following error codes are
  2746. * intended to be illustrative and not necessarily comprehensive.
  2747. *
  2748. * <c DI_OK> = <c S_OK>: The operation completed successfully.
  2749. *
  2750. * <c DIERR_NOTACQUIRED>: Joystick configuration has not been
  2751. * acquired. You must call <mf IDirectInputJoyConfig8::Acquire>
  2752. * before you can alter joystick configuration settings.
  2753. *
  2754. * <c DIERR_INVALIDPARAM> = <c E_INVALIDARG>: One or more
  2755. * parameters was invalid.
  2756. *
  2757. *****************************************************************************/
  2758. STDMETHODIMP
  2759. CJoyCfg_SetUserValues(PDJC pdjc, LPCDIJOYUSERVALUES pjuv, DWORD fl)
  2760. {
  2761. HRESULT hres;
  2762. EnterProcR(IDirectInputJoyConfig8::SetUserValues,
  2763. (_ "pp", pdjc, pjuv, fl));
  2764. if(SUCCEEDED(hres = hresPv(pdjc)) &&
  2765. SUCCEEDED(hres = hresFullValidReadPxCb(pjuv, DIJOYUSERVALUES, 2)) &&
  2766. fLimpFF(fl & DIJU_GLOBALDRIVER,
  2767. SUCCEEDED(hres = hresFullValidUVStr(pjuv,
  2768. wszGlobalDriver, 2))) &&
  2769. fLimpFF(fl & DIJU_GAMEPORTEMULATOR,
  2770. SUCCEEDED(hres = hresFullValidUVStr(pjuv,
  2771. wszGameportEmulator, 2))) &&
  2772. SUCCEEDED(hres = hresFullValidFl(fl, DIJU_SETVALID, 3)))
  2773. {
  2774. PJC this = _thisPvNm(pdjc, djc);
  2775. CJoyCfg_EnterCrit(this);
  2776. if(SUCCEEDED(hres = CJoyCfg_IsAcquired(this)))
  2777. {
  2778. hres = JoyReg_SetUserValues(pjuv, fl);
  2779. }
  2780. CJoyCfg_LeaveCrit(this);
  2781. }
  2782. ExitOleProcR();
  2783. return hres;
  2784. }
  2785. /*****************************************************************************
  2786. *
  2787. * @doc EXTERNAL
  2788. *
  2789. * @method HRESULT | IDirectInputJoyConfig8 | AddNewHardware |
  2790. *
  2791. * Displays the "Add New Hardware" dialog to
  2792. * guide the user through installing
  2793. * new game controller.
  2794. *
  2795. * @cwrap LPDIRECTINPUTJOYCONFIG8 | LPDIRECTINPUTJOYCONFIG8
  2796. *
  2797. * @parm HWND | hwndOwner |
  2798. *
  2799. * Window to act as owner window for UI.
  2800. *
  2801. * @parm REFGUID | rguidClass |
  2802. *
  2803. * <t GUID> which specifies the class of the hardware device
  2804. * to be added. DirectInput comes with the following
  2805. * class <t GUIDs> already defined:
  2806. *
  2807. * <c GUID_KeyboardClass>: Keyboard devices.
  2808. *
  2809. * <c GUID_MouseClass>: Mouse devices.
  2810. *
  2811. * <c GUID_MediaClass>: Media devices, including joysticks.
  2812. *
  2813. * <c GUID_HIDClass>: HID devices.
  2814. *
  2815. * @returns
  2816. *
  2817. * Returns a COM error code. The following error codes are
  2818. * intended to be illustrative and not necessarily comprehensive.
  2819. *
  2820. * <c DI_OK> = <c S_OK>: The operation completed successfully.
  2821. *
  2822. * <c DIERR_INVALIDPARAM> = <c E_INVALIDARG>: One or more
  2823. * parameters was invalid.
  2824. *
  2825. * <c DIERR_INVALIDCLASSINSTALLER>: The "media" class installer
  2826. * could not be found or is invalid.
  2827. *
  2828. * <c DIERR_CANCELLED>: The user cancelled the operation.
  2829. *
  2830. * <c DIERR_BADINF>: The INF file for the device the user
  2831. * selected could not be found or is invalid or is damaged.
  2832. *
  2833. * <c S_FALSE>: DirectInput could not determine whether the
  2834. * operation completed successfully.
  2835. *
  2836. *****************************************************************************/
  2837. STDMETHODIMP
  2838. CJoyCfg_AddNewHardware(PDJC pdjc, HWND hwnd, REFGUID rguid)
  2839. {
  2840. HRESULT hres;
  2841. EnterProcR(IDirectInputJoyConfig8::AddNewHardware,
  2842. (_ "pxG", pdjc, hwnd, rguid));
  2843. if(SUCCEEDED(hres = hresPv(pdjc)) &&
  2844. SUCCEEDED(hres = hresFullValidHwnd0(hwnd, 1)) &&
  2845. SUCCEEDED(hres = hresFullValidGuid(rguid, 2)))
  2846. {
  2847. PJC this = _thisPvNm(pdjc, djc);
  2848. hres = AddNewHardware(hwnd, rguid);
  2849. }
  2850. ExitOleProcR();
  2851. return hres;
  2852. }
  2853. /*****************************************************************************
  2854. *
  2855. * @doc EXTERNAL
  2856. *
  2857. * @method HRESULT | IDirectInputJoyConfig8 | OpenTypeKey |
  2858. *
  2859. * Open the registry key associated with a joystick type.
  2860. *
  2861. * Control panel applications can use this key to store
  2862. * per-type persistent information, such as global
  2863. * configuration parameters.
  2864. *
  2865. * Such private information should be kept in a subkey
  2866. * named "OEM"; do not store private information in the
  2867. * main type key.
  2868. *
  2869. * Control panel applications can also use this key to
  2870. * read configuration information, such as the strings
  2871. * to use for device calibration prompts.
  2872. *
  2873. * The application should use <f RegCloseKey> to close
  2874. * the registry key.
  2875. *
  2876. * @cwrap LPDIRECTINPUTJOYCONFIG8 | LPDIRECTINPUTJOYCONFIG8
  2877. *
  2878. * @parm LPCWSTR | pwszType |
  2879. *
  2880. * Points to the name of the type. The name of the type may
  2881. * not exceed <c MAX_PATH> characters, including the terminating
  2882. * null character.
  2883. *
  2884. * The name may not begin with
  2885. * a "#" character. Types beginning with "#" are reserved
  2886. * by DirectInput.
  2887. *
  2888. * @parm REGSAM | regsam |
  2889. *
  2890. * Registry security access mask. This can be any of the
  2891. * values permitted by the <f RegOpenKeyEx> function.
  2892. * If write access is requested, then joystick
  2893. * configuration must first have been acquired.
  2894. * If only read access is requested, then acquisition is
  2895. * not required.
  2896. *
  2897. * @parm PHKEY | phk |
  2898. *
  2899. * Receives the opened registry key on success.
  2900. *
  2901. * @returns
  2902. *
  2903. * Returns a COM error code. The following error codes are
  2904. * intended to be illustrative and not necessarily comprehensive.
  2905. *
  2906. * <c DI_OK> = <c S_OK>: The operation completed successfully.
  2907. *
  2908. * <c DIERR_NOTACQUIRED>: Joystick configuration has not been
  2909. * acquired. You must call <mf IDirectInputJoyConfig8::Acquire>
  2910. * before you can open a joystick type configuration key
  2911. * for writing.
  2912. *
  2913. * <c DIERR_INVALIDPARAM> = <c E_INVALIDARG>: One or more
  2914. * parameters was invalid.
  2915. *
  2916. * <c MAKE_HRESULT(SEVERITY_ERROR, FACILITY_WIN32, ErrorCode)>:
  2917. * A Win32 error code if access to the key is denied by
  2918. * registry permissions or some other external factor.
  2919. *
  2920. *****************************************************************************/
  2921. STDMETHODIMP
  2922. CJoyCfg_OpenTypeKey(PDJC pdjc, LPCWSTR pwszType, REGSAM sam, PHKEY phk)
  2923. {
  2924. HRESULT hres;
  2925. EnterProcR(IDirectInputJoyConfig8::OpenTypeKey,
  2926. (_ "pWx", pdjc, pwszType, sam));
  2927. if(SUCCEEDED(hres = hresPv(pdjc)) &&
  2928. SUCCEEDED(hres = hresFullValidReadStrW(pwszType, MAX_JOYSTRING, 1)) &&
  2929. SUCCEEDED(hres = hresFullValidPcbOut(phk, cbX(*phk), 3)))
  2930. {
  2931. PJC this = _thisPvNm(pdjc, djc);
  2932. if(pwszType[0] != TEXT('#'))
  2933. {
  2934. /*
  2935. * Attempting to get write access requires acquisition.
  2936. */
  2937. if(fLimpFF(IsWriteSam(sam),
  2938. SUCCEEDED(hres = CJoyCfg_IsAcquired(this))))
  2939. {
  2940. hres = JoyReg_OpenTypeKey(pwszType, sam, REG_OPTION_NON_VOLATILE, phk);
  2941. }
  2942. } else
  2943. {
  2944. RPF("%s: Invalid pwszType (predefined)", s_szProc);
  2945. hres = E_INVALIDARG;
  2946. }
  2947. }
  2948. ExitOleProcR();
  2949. return hres;
  2950. }
  2951. /*****************************************************************************
  2952. *
  2953. * @doc EXTERNAL
  2954. *
  2955. * @method HRESULT | IDirectInputJoyConfig8 | OpenAppStatusKey |
  2956. *
  2957. * Opens the root key of the application status registry keys.
  2958. *
  2959. * Hardware vendors can use the sub keys of this key to inspect the
  2960. * status of DirectInput applications with respect to the
  2961. * functionality they use. The key is opened with KEY_READ access.
  2962. *
  2963. * Vendors are cautioned against opening these keys directly (by
  2964. * finding the absolute path of the key rather than using this method)
  2965. * as the absolute registry path may vary on different Windows
  2966. * platforms or in future versions of DirectInput.
  2967. *
  2968. * The application should use <f RegCloseKey> to close
  2969. * the registry key.
  2970. *
  2971. * @cwrap LPDIRECTINPUTJOYCONFIG8 | LPDIRECTINPUTJOYCONFIG8
  2972. *
  2973. * @parm PHKEY | phk |
  2974. *
  2975. * Receives the opened registry key on success.
  2976. *
  2977. * @returns
  2978. *
  2979. * Returns a COM error code. The following error codes are
  2980. * intended to be illustrative and not necessarily comprehensive.
  2981. *
  2982. * <c DI_OK> = <c S_OK>: The operation completed successfully.
  2983. *
  2984. * <c DIERR_INVALIDPARAM> = <c E_INVALIDARG>: One or more
  2985. * parameters was invalid.
  2986. *
  2987. * <c DIERR_NOTFOUND>: The key is missing on this system.
  2988. * Applications should proceed as if the key were empty.
  2989. *
  2990. * <c MAKE_HRESULT(SEVERITY_ERROR, FACILITY_WIN32, ErrorCode)>:
  2991. * A Win32 error code if access to the key is denied by
  2992. * registry permissions or some other external factor.
  2993. *
  2994. *****************************************************************************/
  2995. STDMETHODIMP
  2996. CJoyCfg_OpenAppStatusKey(PDJC pdjc, PHKEY phk)
  2997. {
  2998. HRESULT hres;
  2999. EnterProcR(IDirectInputJoyConfig8::OpenAppStatusKey,
  3000. (_ "pp", pdjc, phk));
  3001. if(SUCCEEDED(hres = hresPv(pdjc)) &&
  3002. SUCCEEDED(hres = hresFullValidPcbOut(phk, cbX(*phk), 1)))
  3003. {
  3004. PJC this = _thisPvNm(pdjc, djc);
  3005. hres = hresMumbleKeyEx( HKEY_CURRENT_USER, REGSTR_PATH_DINPUT,
  3006. KEY_READ, REG_OPTION_NON_VOLATILE, phk);
  3007. }
  3008. ExitOleProcR();
  3009. return hres;
  3010. }
  3011. /*****************************************************************************
  3012. *
  3013. * CJoyCfg_New (constructor)
  3014. *
  3015. *****************************************************************************/
  3016. STDMETHODIMP
  3017. CJoyCfg_New(PUNK punkOuter, RIID riid, PPV ppvObj)
  3018. {
  3019. HRESULT hres;
  3020. EnterProcI(IDirectInputJoyConfig8::<constructor>,
  3021. (_ "p", ppvObj));
  3022. if (SUCCEEDED(hres = hresFullValidPcbOut(ppvObj, cbX(*ppvObj), 3)))
  3023. {
  3024. LPVOID pvTry = NULL;
  3025. hres = Common_NewRiid(CJoyCfg, punkOuter, riid, &pvTry);
  3026. if(SUCCEEDED(hres))
  3027. {
  3028. /* Must use _thisPv in case of aggregation */
  3029. PJC this = _thisPv(pvTry);
  3030. this->fCritInited = fInitializeCriticalSection(&this->crst);
  3031. if( this->fCritInited )
  3032. {
  3033. *ppvObj = pvTry;
  3034. hres = S_OK;
  3035. }
  3036. else
  3037. {
  3038. Common_Unhold(this);
  3039. *ppvObj = NULL;
  3040. hres = E_OUTOFMEMORY;
  3041. }
  3042. }
  3043. }
  3044. ExitOleProcPpvR(ppvObj);
  3045. return hres;
  3046. }
  3047. /*****************************************************************************
  3048. *
  3049. * The long-awaited vtbls and templates
  3050. *
  3051. *****************************************************************************/
  3052. #pragma BEGIN_CONST_DATA
  3053. #define CJoyCfg_Signature 0x6766434B /* "JCfg" */
  3054. Primary_Interface_Begin(CJoyCfg, IDirectInputJoyConfig8)
  3055. CJoyCfg_Acquire,
  3056. CJoyCfg_Unacquire,
  3057. CJoyCfg_SetCooperativeLevel,
  3058. CJoyCfg_SendNotify,
  3059. CJoyCfg_EnumTypes,
  3060. CJoyCfg_GetTypeInfo,
  3061. CJoyCfg_SetTypeInfo,
  3062. CJoyCfg_DeleteType,
  3063. CJoyCfg_GetConfig,
  3064. CJoyCfg_SetConfig,
  3065. CJoyCfg_DeleteConfig,
  3066. CJoyCfg_GetUserValues,
  3067. CJoyCfg_SetUserValues,
  3068. CJoyCfg_AddNewHardware,
  3069. CJoyCfg_OpenTypeKey,
  3070. CJoyCfg_OpenAppStatusKey,
  3071. Primary_Interface_End(CJoyCfg, IDirectInputJoyConfig8)