Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

3308 lines
100 KiB

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