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.

1316 lines
34 KiB

  1. /*****************************************************************************
  2. *
  3. * DIEShep.c
  4. *
  5. * Copyright (c) 1997 Microsoft Corporation. All Rights Reserved.
  6. *
  7. * Abstract:
  8. *
  9. * The IDirectInputEffectDriver shepherd.
  10. *
  11. * The shepherd does the annoying work of babysitting the
  12. * external IDirectInputDriver.
  13. *
  14. * It makes sure nobody parties on bad handles.
  15. *
  16. * It handles cross-process (or even intra-process) effect
  17. * management.
  18. *
  19. * It caches the joystick ID so you don't have to.
  20. *
  21. * Contents:
  22. *
  23. * CEShep_New
  24. *
  25. *****************************************************************************/
  26. #include "dinputpr.h"
  27. /*****************************************************************************
  28. *
  29. * The sqiffle for this file.
  30. *
  31. *****************************************************************************/
  32. #define sqfl sqflEShep
  33. #pragma BEGIN_CONST_DATA
  34. /*****************************************************************************
  35. *
  36. * Declare the interfaces we will be providing.
  37. *
  38. *****************************************************************************/
  39. Primary_Interface(CEShep, IDirectInputEffectShepherd);
  40. /*****************************************************************************
  41. *
  42. * @doc INTERNAL
  43. *
  44. * @struct CEShep |
  45. *
  46. * The <i IDirectInputEffectShepherd> object, which
  47. * babysits an <i IDirectInputEffectDriver>.
  48. *
  49. * @field IDirectInputEffectShepherd | des |
  50. *
  51. * DirectInputEffectShepherd object (containing vtbl).
  52. *
  53. * @field IDirectInputEffectDriver * | pdrv |
  54. *
  55. * Delegated effect driver interface.
  56. *
  57. * @field UINT | idJoy |
  58. *
  59. * Joystick identification number.
  60. *
  61. * @field HINSTANCE | hinst |
  62. *
  63. * The instance handle of the DLL that contains the effect
  64. * driver.
  65. *
  66. *****************************************************************************/
  67. typedef struct CEShep {
  68. /* Supported interfaces */
  69. IDirectInputEffectShepherd des;
  70. IDirectInputEffectDriver *pdrv;
  71. UINT idJoy;
  72. HINSTANCE hinst;
  73. } CEShep, ES, *PES;
  74. typedef IDirectInputEffectShepherd DES, *PDES;
  75. #define ThisClass CEShep
  76. #define ThisInterface IDirectInputEffectShepherd
  77. /*****************************************************************************
  78. *
  79. * @doc EXTERNAL
  80. *
  81. * @method HRESULT | IDirectInputEffectShepherd | QueryInterface |
  82. *
  83. * Gives a client access to other interfaces on an object.
  84. *
  85. * @cwrap LPDIRECTINPUT | lpDirectInput
  86. *
  87. * @parm IN REFIID | riid |
  88. *
  89. * The requested interface's IID.
  90. *
  91. * @parm OUT LPVOID * | ppvObj |
  92. *
  93. * Receives a pointer to the obtained interface.
  94. *
  95. * @returns
  96. *
  97. * Returns a COM error code.
  98. *
  99. * @xref OLE documentation for <mf IUnknown::QueryInterface>.
  100. *
  101. *//**************************************************************************
  102. *
  103. * @doc EXTERNAL
  104. *
  105. * @method HRESULT | IDirectInputEffectShepherd | AddRef |
  106. *
  107. * Increments the reference count for the interface.
  108. *
  109. * @cwrap LPDIRECTINPUT | lpDirectInput
  110. *
  111. * @returns
  112. *
  113. * Returns the object reference count.
  114. *
  115. * @xref OLE documentation for <mf IUnknown::AddRef>.
  116. *
  117. *****************************************************************************
  118. *
  119. * @doc EXTERNAL
  120. *
  121. * @method HRESULT | IDirectInputEffectShepherd | Release |
  122. *
  123. * Decrements the reference count for the interface.
  124. * If the reference count on the object falls to zero,
  125. * the object is freed from memory.
  126. *
  127. * @cwrap LPDIRECTINPUT | lpDirectInput
  128. *
  129. * @returns
  130. *
  131. * Returns the object reference count.
  132. *
  133. * @xref OLE documentation for <mf IUnknown::Release>.
  134. *
  135. *//**************************************************************************
  136. *
  137. * @doc INTERNAL
  138. *
  139. * @method HRESULT | IDirectInputEffectShepherd | QIHelper |
  140. *
  141. * We don't have any dynamic interfaces and simply forward
  142. * to <f Common_QIHelper>.
  143. *
  144. * @parm IN REFIID | riid |
  145. *
  146. * The requested interface's IID.
  147. *
  148. * @parm OUT LPVOID * | ppvObj |
  149. *
  150. * Receives a pointer to the obtained interface.
  151. *
  152. *//**************************************************************************
  153. *
  154. * @doc INTERNAL
  155. *
  156. * @method HRESULT | IDirectInputEffectShepherd | AppFinalize |
  157. *
  158. * We don't have any weak pointers, so we can just
  159. * forward to <f Common_Finalize>.
  160. *
  161. * @parm PV | pvObj |
  162. *
  163. * Object being released from the application's perspective.
  164. *
  165. *****************************************************************************/
  166. #ifdef DEBUG
  167. Default_QueryInterface(CEShep)
  168. Default_AddRef(CEShep)
  169. Default_Release(CEShep)
  170. #else
  171. #define CEShep_QueryInterface Common_QueryInterface
  172. #define CEShep_AddRef Common_AddRef
  173. #define CEShep_Release Common_Release
  174. #endif
  175. #define CEShep_QIHelper Common_QIHelper
  176. #define CEShep_AppFinalize Common_AppFinalize
  177. /*****************************************************************************
  178. *
  179. * @doc INTERNAL
  180. *
  181. * @func void | CEShep_Finalize |
  182. *
  183. * Clean up our instance data.
  184. *
  185. * @parm PV | pvObj |
  186. *
  187. * Object being released. Note that it may not have been
  188. * completely initialized, so everything should be done
  189. * carefully.
  190. *
  191. *****************************************************************************/
  192. void INTERNAL
  193. CEShep_Finalize(PV pvObj)
  194. {
  195. PES this = pvObj;
  196. Invoke_Release(&this->pdrv);
  197. if (this->hinst) {
  198. FreeLibrary(this->hinst);
  199. }
  200. }
  201. /*****************************************************************************
  202. *
  203. * @doc INTERNAL
  204. *
  205. * @method void | CEShep | UnlockDevice |
  206. *
  207. * Unlock the joystick table after we are finished messing
  208. * with the device.
  209. *
  210. *****************************************************************************/
  211. void INLINE
  212. CEShep_UnlockDevice(void)
  213. {
  214. ReleaseMutex(g_hmtxJoy);
  215. }
  216. /*****************************************************************************
  217. *
  218. * @doc INTERNAL
  219. *
  220. * @method HRESULT | CEShep | LockDevice |
  221. *
  222. * Validate that the the device access token is still valid.
  223. *
  224. * If so, then take the joystick mutex to prevent someone
  225. * from dorking with the device while we're using it.
  226. * Call <f CEShep_UnlockDevice> when done.
  227. *
  228. * If not, then try to steal ownership if requested.
  229. *
  230. * Else, fail.
  231. *
  232. * @cwrap LPDIRECTINPUTEFFECTSHEPHERD | lpShepherd
  233. *
  234. * @parm PSHEPHANDLE | psh |
  235. *
  236. * Handle to lock.
  237. *
  238. * @parm DWORD | dwAccess |
  239. *
  240. * If <c DISFFC_FORCERESET>, then force ownership of the device.
  241. * This is done as part of device acquisition to kick out the
  242. * previous owner.
  243. *
  244. * Otherwise, if the device belongs to somebody else, then
  245. * leave it alone.
  246. *
  247. *
  248. * @returns
  249. *
  250. * <c S_OK> if the operation completed successfully.
  251. *
  252. * <c DIERR_NOTEXCLUSIVEACQUIRED> if the lock failed.
  253. * Note that
  254. * <mf IDirectInputEffectDevice2::SetForceFeedbackState>
  255. * and
  256. * <mf IDirectInputEffectDevice2::GetForceFeedbackState>
  257. * are particularly keen on this error code.
  258. *
  259. *****************************************************************************/
  260. STDMETHODIMP
  261. CEShep_LockDevice(PES this, PSHEPHANDLE psh, DWORD dwAccess)
  262. {
  263. HRESULT hres;
  264. EnterProc(CEShep_LockDevice, (_ "puu", this, psh->dwTag, dwAccess));
  265. WaitForSingleObject(g_hmtxJoy, INFINITE);
  266. /*
  267. * Note that DISFFC_FORCERESET allows unconditional access.
  268. * DISFFC_FORCERESET is used when we perform the initial reset
  269. * after acquiring, so we can legitimately steal the device
  270. * from the previous owner.
  271. */
  272. if (dwAccess & DISFFC_FORCERESET) {
  273. hres = S_OK;
  274. } else if (g_psoh->rggjs[this->idJoy].dwTag == psh->dwTag) {
  275. hres = S_OK;
  276. } else {
  277. ReleaseMutex(g_hmtxJoy);
  278. hres = DIERR_NOTEXCLUSIVEACQUIRED;
  279. }
  280. ExitOleProc();
  281. return hres;
  282. }
  283. /*****************************************************************************
  284. *
  285. * @doc INTERNAL
  286. *
  287. * @method void | CEShep | UnlockEffect |
  288. *
  289. * Unlock the joystick table after we are finished messing
  290. * with an effect.
  291. *
  292. *****************************************************************************/
  293. void INLINE
  294. CEShep_UnlockEffect(void)
  295. {
  296. ReleaseMutex(g_hmtxJoy);
  297. }
  298. /*****************************************************************************
  299. *
  300. * @doc INTERNAL
  301. *
  302. * @method HRESULT | CEShep | LockEffect |
  303. *
  304. * Validate that the the effect handle is still valid.
  305. *
  306. * If so, then take the joystick mutex to prevent someone
  307. * from dorking with the device while we're using the handle.
  308. * Call <f CEShep_UnlockEffect> when done.
  309. *
  310. * If not, then set the effect handle to zero to indicate
  311. * that it's bogus. The
  312. * <mf IDirectInputEffectShepherd::DownloadEffect>
  313. * method relies on the zero-ness.
  314. * It is also asserted in <i IDirectInputEffect> to make
  315. * sure we don't accidentally leave effects on the device
  316. * when we leave.
  317. *
  318. * @cwrap LPDIRECTINPUTEFFECTSHEPHERD | lpShepherd
  319. *
  320. * @parm PSHEPHANDLE | psh |
  321. *
  322. * Handle to lock.
  323. *
  324. * @returns
  325. *
  326. * <c S_OK> if the operation completed successfully.
  327. *
  328. * <c DIERR_NOTDOWNLOADED> if the lock failed.
  329. * Note that
  330. * <mf IDirectInputEffectShepherd::DownloadEffect> and
  331. * <mf IDirectInputEffectShepherd::DestroyEffect> assume
  332. * that this is the only possible error code.
  333. *
  334. *****************************************************************************/
  335. STDMETHODIMP
  336. CEShep_LockEffect(PES this, PSHEPHANDLE psh)
  337. {
  338. HRESULT hres;
  339. EnterProc(CEShep_LockEffect, (_ "pux", this, psh->dwTag, psh->dwEffect));
  340. WaitForSingleObject(g_hmtxJoy, INFINITE);
  341. if (g_psoh->rggjs[this->idJoy].dwTag == psh->dwTag && psh->dwEffect) {
  342. hres = S_OK;
  343. } else {
  344. psh->dwEffect = 0;
  345. ReleaseMutex(g_hmtxJoy);
  346. hres = DIERR_NOTDOWNLOADED;
  347. }
  348. ExitOleProc();
  349. return hres;
  350. }
  351. /*****************************************************************************
  352. *
  353. * @doc INTERNAL
  354. *
  355. * @method HRESULT | IDirectInputEffectShepherd | DeviceID |
  356. *
  357. * Inform the driver of the identity of the device.
  358. *
  359. * For example, if a device driver is passed
  360. * <p dwExternalID> = 2 and <p dwInteralID> = 1,
  361. * then this means that unit 1 on the device
  362. * corresponds to joystick ID number 2.
  363. *
  364. * @cwrap LPDIRECTINPUTEFFECTSHEPHERD | lpShepherd
  365. *
  366. * @parm DWORD | dwExternalID |
  367. *
  368. * The joystick ID number being used.
  369. * The Windows joystick subsystem allocates external IDs.
  370. *
  371. * @parm DWORD | fBegin |
  372. *
  373. * Nonzero if access to the device is begining.
  374. * Zero if the access to the device is ending.
  375. *
  376. * @parm LPVOID | lpReserved |
  377. *
  378. * Reserved for future use (HID).
  379. *
  380. * @returns
  381. *
  382. * <c S_OK> if the operation completed successfully.
  383. *
  384. * An error code if something is wrong.
  385. *
  386. *****************************************************************************/
  387. STDMETHODIMP
  388. CEShep_DeviceID(PDES pdes, DWORD dwExternalID, DWORD fBegin, LPVOID pvReserved)
  389. {
  390. PES this;
  391. HRESULT hres;
  392. EnterProcI(IDirectInputEffectShepherd::DeviceID,
  393. (_ "puu", pdes, dwExternalID, fBegin));
  394. this = _thisPvNm(pdes, des);
  395. AssertF(dwExternalID < cJoyMax);
  396. if (dwExternalID < cJoyMax) {
  397. VXDINITPARMS vip;
  398. /*
  399. * If this device has never been used before,
  400. * go grab its global gain.
  401. */
  402. WaitForSingleObject(g_hmtxJoy, INFINITE);
  403. if (g_psoh->rggjs[dwExternalID].dwTag == 0) {
  404. DIJOYCONFIG cfg;
  405. g_psoh->rggjs[dwExternalID].dwTag = 1;
  406. hres = JoyReg_GetConfig(dwExternalID, &cfg, DIJC_GAIN);
  407. if (SUCCEEDED(hres)) {
  408. SquirtSqflPtszV(sqfl,
  409. TEXT("Joystick %d global gain = %d"),
  410. dwExternalID, cfg.dwGain);
  411. g_psoh->rggjs[dwExternalID].dwCplGain = cfg.dwGain;
  412. } else {
  413. g_psoh->rggjs[dwExternalID].dwCplGain = DI_FFNOMINALMAX;
  414. }
  415. /*
  416. * Set to DI_FFNOMINALMAX until we learn better.
  417. */
  418. g_psoh->rggjs[dwExternalID].dwDevGain = DI_FFNOMINALMAX;
  419. }
  420. ReleaseMutex(g_hmtxJoy);
  421. /*
  422. * Ask the HEL for the internal ID.
  423. */
  424. hres = Hel_Joy_GetInitParms(dwExternalID, &vip);
  425. if (SUCCEEDED(hres)) {
  426. this->idJoy = dwExternalID;
  427. hres = this->pdrv->lpVtbl->DeviceID(this->pdrv,
  428. DIRECTINPUT_VERSION,
  429. dwExternalID,
  430. fBegin, vip.dwId,
  431. pvReserved);
  432. }
  433. } else {
  434. hres = E_FAIL;
  435. }
  436. ExitOleProcR();
  437. return hres;
  438. }
  439. /*****************************************************************************
  440. *
  441. * @doc INTERNAL
  442. *
  443. * @method HRESULT | IDirectInputEffectShepherd | Escape |
  444. *
  445. * Escape to the driver. This method is called
  446. * in response to an application invoking the
  447. * <mf IDirectInputEffect::Escape> method.
  448. *
  449. * @cwrap LPDIRECTINPUTEFFECTSHEPHERD | lpShepherd
  450. *
  451. * @parm PSHEPHANDLE | psh |
  452. *
  453. * Information about the effect at which the command is directed.
  454. *
  455. * @parm LPDIEFFESCAPE | pesc |
  456. *
  457. * Command block.
  458. *
  459. * @returns
  460. *
  461. * <c S_OK> if the operation completed successfully.
  462. *
  463. * <c DIERR_NOTDOWNLOADED> if the effect is not downloaded.
  464. *
  465. *****************************************************************************/
  466. STDMETHODIMP
  467. CEShep_Escape(PDES pdes, PSHEPHANDLE psh, LPDIEFFESCAPE pesc)
  468. {
  469. PES this;
  470. HRESULT hres;
  471. EnterProcI(IDirectInputEffectShepherd::Escape,
  472. (_ "puxx", pdes, psh->dwTag, psh->dwEffect, pesc->dwCommand));
  473. this = _thisPvNm(pdes, des);
  474. if (SUCCEEDED(hres = CEShep_LockEffect(this, psh))) {
  475. if (psh->dwEffect) {
  476. hres = this->pdrv->lpVtbl->Escape(this->pdrv, this->idJoy,
  477. psh->dwEffect, pesc);
  478. } else {
  479. hres = DIERR_NOTDOWNLOADED;
  480. }
  481. CEShep_UnlockEffect();
  482. }
  483. ExitOleProcR();
  484. return hres;
  485. }
  486. /*****************************************************************************
  487. *
  488. * @doc INTERNAL
  489. *
  490. * @method HRESULT | IDirectInputEffectShepherd | DeviceEscape |
  491. *
  492. * Escape to the driver. This method is called
  493. * in response to an application invoking the
  494. * <mf IDirectInputDevice8::Escape> method.
  495. *
  496. * @cwrap LPDIRECTINPUTEFFECTSHEPHERD | lpShepherd
  497. *
  498. * @parm PSHEPHANDLE | psh |
  499. *
  500. * Information about the ownership of the device.
  501. *
  502. * @parm LPDIEFFESCAPE | pesc |
  503. *
  504. * Command block.
  505. *
  506. * @returns
  507. *
  508. * <c S_OK> if the operation completed successfully.
  509. *
  510. * An error code if something is wrong.
  511. *
  512. *****************************************************************************/
  513. STDMETHODIMP
  514. CEShep_DeviceEscape(PDES pdes, PSHEPHANDLE psh, LPDIEFFESCAPE pesc)
  515. {
  516. PES this;
  517. HRESULT hres;
  518. EnterProcI(IDirectInputEffectShepherd::DeviceEscape,
  519. (_ "pux", pdes, psh->dwTag, pesc->dwCommand));
  520. this = _thisPvNm(pdes, des);
  521. AssertF(psh->dwEffect == 0);
  522. WaitForSingleObject(g_hmtxJoy, INFINITE);
  523. if (g_psoh->rggjs[this->idJoy].dwTag == psh->dwTag) {
  524. hres = this->pdrv->lpVtbl->Escape(this->pdrv, this->idJoy,
  525. 0, pesc);
  526. } else {
  527. hres = DIERR_NOTEXCLUSIVEACQUIRED;
  528. }
  529. ReleaseMutex(g_hmtxJoy);
  530. ExitOleProcR();
  531. return hres;
  532. }
  533. /*****************************************************************************
  534. *
  535. * @doc INTERNAL
  536. *
  537. * @method HRESULT | CEShep | SetPhysGain |
  538. *
  539. * Set the physical gain based on the global gain
  540. * and the local gain.
  541. *
  542. * The caller must already have the global joystick lock.
  543. *
  544. *
  545. * @cwrap PES | this
  546. *
  547. * @returns
  548. *
  549. * <c S_OK> if the operation completed successfully.
  550. *
  551. * An error code if something is wrong.
  552. *
  553. *****************************************************************************/
  554. STDMETHODIMP
  555. CEShep_SetPhysGain(PES this)
  556. {
  557. HRESULT hres;
  558. hres = this->pdrv->lpVtbl->SetGain(
  559. this->pdrv, this->idJoy,
  560. MulDiv(g_psoh->rggjs[this->idJoy].dwDevGain,
  561. g_psoh->rggjs[this->idJoy].dwCplGain,
  562. DI_FFNOMINALMAX));
  563. return hres;
  564. }
  565. /*****************************************************************************
  566. *
  567. * @doc INTERNAL
  568. *
  569. * @method HRESULT | IDirectInputEffectShepherd | SetGlobalGain |
  570. *
  571. * Set the global gain.
  572. *
  573. * @cwrap LPDIRECTINPUTEFFECTSHEPHERD | lpShepherd
  574. *
  575. * @parm DWORD | dwCplGain |
  576. *
  577. * The new global gain value.
  578. *
  579. * @returns
  580. *
  581. * <c S_OK> if the operation completed successfully.
  582. *
  583. * An error code if something is wrong.
  584. *
  585. *****************************************************************************/
  586. STDMETHODIMP
  587. CEShep_SetGlobalGain(PDES pdes, DWORD dwCplGain)
  588. {
  589. PES this;
  590. HRESULT hres;
  591. EnterProcI(IDirectInputEffectShepherd::SetGlobalGain,
  592. (_ "pu", pdes, dwCplGain));
  593. this = _thisPvNm(pdes, des);
  594. WaitForSingleObject(g_hmtxJoy, INFINITE);
  595. g_psoh->rggjs[this->idJoy].dwCplGain = dwCplGain;
  596. hres = CEShep_SetPhysGain(this);
  597. ReleaseMutex(g_hmtxJoy);
  598. ExitOleProcR();
  599. return hres;
  600. }
  601. /*****************************************************************************
  602. *
  603. * @doc INTERNAL
  604. *
  605. * @method HRESULT | IDirectInputEffectShepherd | SetGain |
  606. *
  607. * Set the overall device gain.
  608. *
  609. * @cwrap LPDIRECTINPUTEFFECTSHEPHERD | lpShepherd
  610. *
  611. * @parm PSHEPHANDLE | psh |
  612. *
  613. * Information about device ownership.
  614. *
  615. * @parm DWORD | dwDevGain |
  616. *
  617. * The new local gain value.
  618. *
  619. * @returns
  620. *
  621. * <c S_OK> if the operation completed successfully.
  622. *
  623. * An error code if something is wrong.
  624. *
  625. *****************************************************************************/
  626. STDMETHODIMP
  627. CEShep_SetGain(PDES pdes, PSHEPHANDLE psh, DWORD dwDevGain)
  628. {
  629. PES this;
  630. HRESULT hres;
  631. EnterProcI(IDirectInputEffectShepherd::SetGain,
  632. (_ "puu", pdes, psh->dwTag, dwDevGain));
  633. this = _thisPvNm(pdes, des);
  634. if (SUCCEEDED(hres = CEShep_LockDevice(this, psh, DISFFC_NULL))) {
  635. g_psoh->rggjs[this->idJoy].dwDevGain = dwDevGain;
  636. hres = CEShep_SetPhysGain(this);
  637. CEShep_UnlockDevice();
  638. }
  639. ExitOleProcR();
  640. return hres;
  641. }
  642. /*****************************************************************************
  643. *
  644. * @doc INTERNAL
  645. *
  646. * @method HRESULT | IDirectInputEffectShepherd | SendForceFeedbackCommand |
  647. *
  648. * Send a command to the device.
  649. *
  650. * @cwrap LPDIRECTINPUTEFFECTSHEPHERD | lpShepherd
  651. *
  652. * @parm PSHEPHANDLE | psh |
  653. *
  654. * Information about device ownership.
  655. *
  656. * @parm DWORD | dwCmd |
  657. *
  658. * Command, one of the <c DISFFC_*> values.
  659. *
  660. * @returns
  661. * <c S_OK> on success.
  662. *
  663. * @devnote
  664. *
  665. * Semantics unclear.
  666. *
  667. *****************************************************************************/
  668. STDMETHODIMP
  669. CEShep_SetForceFeedbackState(PDES pdes, PSHEPHANDLE psh, DWORD dwCmd)
  670. {
  671. PES this;
  672. HRESULT hres;
  673. EnterProcI(IDirectInputEffectShepherd::SetForceFeedbackState,
  674. (_ "pux", pdes, psh->dwTag, dwCmd));
  675. this = _thisPvNm(pdes, des);
  676. if (SUCCEEDED(hres = CEShep_LockDevice(this, psh, dwCmd))) {
  677. if (dwCmd & DISFFC_FORCERESET) {
  678. dwCmd &= ~DISFFC_FORCERESET;
  679. dwCmd |= DISFFC_RESET;
  680. }
  681. hres = this->pdrv->lpVtbl->SendForceFeedbackCommand(
  682. this->pdrv, this->idJoy, dwCmd);
  683. if (SUCCEEDED(hres) && (dwCmd & DISFFC_RESET)) {
  684. psh->dwTag = ++g_psoh->rggjs[this->idJoy].dwTag;
  685. }
  686. CEShep_UnlockDevice();
  687. }
  688. ExitOleProcR();
  689. return hres;
  690. }
  691. /*****************************************************************************
  692. *
  693. * @doc INTERNAL
  694. *
  695. * @method HRESULT | IDirectInputEffectShepherd | GetForceFeedbackState |
  696. *
  697. * Retrieve the force feedback state for the device.
  698. *
  699. * @cwrap LPDIRECTINPUTEFFECTSHEPHERD | lpShepherd
  700. *
  701. * @parm PSHEPHANDLE | psh |
  702. *
  703. * Information about device ownership.
  704. *
  705. * @parm LPDIDEVICESTATE | pds |
  706. *
  707. * Receives device state.
  708. *
  709. * @returns
  710. * <c S_OK> on success.
  711. *
  712. * @devnote
  713. *
  714. * Semantics unclear.
  715. *
  716. *****************************************************************************/
  717. STDMETHODIMP
  718. CEShep_GetForceFeedbackState(PDES pdes, PSHEPHANDLE psh, LPDIDEVICESTATE pds)
  719. {
  720. PES this;
  721. HRESULT hres;
  722. EnterProcI(IDirectInputEffectShepherd::GetForceFeedbackState,
  723. (_ "pup", pdes, psh->dwTag, pds));
  724. this = _thisPvNm(pdes, des);
  725. if (SUCCEEDED(hres = CEShep_LockDevice(this, psh, DISFFC_NULL))) {
  726. hres = this->pdrv->lpVtbl->GetForceFeedbackState(
  727. this->pdrv, this->idJoy, pds);
  728. CEShep_UnlockDevice();
  729. }
  730. ExitOleProcR();
  731. return hres;
  732. }
  733. /*****************************************************************************
  734. *
  735. * @doc INTERNAL
  736. *
  737. * @method HRESULT | IDirectInputEffectShepherd | DownloadEffect |
  738. *
  739. * Send an effect to the device.
  740. *
  741. * @cwrap LPDIRECTINPUTEFFECTSHEPHERD | lpShepherd
  742. *
  743. * @parm DWORD | dwEffectId |
  744. *
  745. * Magic cookie dword that identifies the effect.
  746. *
  747. * @parm IN OUT PSHEPHANDLE | psh |
  748. *
  749. * On entry, contains the handle of the effect being
  750. * downloaded. If the value is zero, then a new effect
  751. * is downloaded. If the value is nonzero, then an
  752. * existing effect is modified.
  753. *
  754. * On exit, contains the new effect handle.
  755. *
  756. * @parm LPCDIEFFECT | peff |
  757. *
  758. * The new parameters for the effect. The axis and button
  759. * values have been converted to axis/button indexes.
  760. *
  761. * @returns
  762. * <c S_OK> on success.
  763. *
  764. * <c S_FALSE> if no change was made.
  765. *
  766. *****************************************************************************/
  767. STDMETHODIMP
  768. CEShep_DownloadEffect(PDES pdes, DWORD dwEffectId,
  769. PSHEPHANDLE psh, LPCDIEFFECT peff, DWORD fl)
  770. {
  771. PES this;
  772. HRESULT hres = S_OK;
  773. EnterProcI(IDirectInputEffectShepherd::DownloadEffect,
  774. (_ "pxuppx", pdes, dwEffectId, psh->dwTag,
  775. psh->dwEffect, peff, fl));
  776. this = _thisPvNm(pdes, des);
  777. /*
  778. * Downloading an effect is sufficiently different from all
  779. * other methods that we do the locking manually.
  780. */
  781. WaitForSingleObject(g_hmtxJoy, INFINITE);
  782. /*
  783. * If not downloading, then it doesn't matter whether or not
  784. * the tag matches. However, if the tag doesn't match, then
  785. * we must wipe out the download handle because it's dead.
  786. */
  787. if (g_psoh->rggjs[this->idJoy].dwTag == psh->dwTag) {
  788. } else {
  789. psh->dwEffect = 0;
  790. if (fl & DIEP_NODOWNLOAD) { /* It's okay if not downloading */
  791. } else {
  792. hres = DIERR_NOTEXCLUSIVEACQUIRED;
  793. goto done;
  794. }
  795. }
  796. /*
  797. * If downloading and creating a new effect,
  798. * then all parameters need to be downloaded.
  799. */
  800. if (!(fl & DIEP_NODOWNLOAD) && psh->dwEffect == 0) {
  801. fl |= DIEP_ALLPARAMS;
  802. }
  803. if (fl) {
  804. hres = this->pdrv->lpVtbl->DownloadEffect(
  805. this->pdrv, this->idJoy, dwEffectId,
  806. &psh->dwEffect, peff, fl);
  807. } else {
  808. hres = S_FALSE;
  809. }
  810. done:;
  811. ReleaseMutex(g_hmtxJoy);
  812. ExitOleProcR();
  813. return hres;
  814. }
  815. /*****************************************************************************
  816. *
  817. * @doc INTERNAL
  818. *
  819. * @method HRESULT | IDirectInputEffectShepherd | DestroyEffect |
  820. *
  821. * Remove an effect from the device.
  822. *
  823. * @cwrap LPDIRECTINPUTEFFECTSHEPHERD | lpShepherd
  824. *
  825. * @parm PSHEPHANDLE | psh |
  826. *
  827. * Information about the effect to be destroyed. On exit,
  828. * the <e SHEPHANDLE.dwEffect> is zero'd so nobody will use
  829. * it any more.
  830. *
  831. * @returns
  832. * <c S_OK> on success.
  833. *
  834. * <c S_FALSE> if the effect was already destroyed.
  835. *
  836. *****************************************************************************/
  837. STDMETHODIMP
  838. CEShep_DestroyEffect(PDES pdes, PSHEPHANDLE psh)
  839. {
  840. PES this;
  841. HRESULT hres;
  842. EnterProcI(IDirectInputEffectShepherd::DestroyEffect,
  843. (_ "pux", pdes, psh->dwTag, psh->dwEffect));
  844. this = _thisPvNm(pdes, des);
  845. if (SUCCEEDED(hres = CEShep_LockEffect(this, psh))) {
  846. DWORD dwEffect = psh->dwEffect;
  847. psh->dwEffect = 0;
  848. hres = this->pdrv->lpVtbl->DestroyEffect(
  849. this->pdrv, this->idJoy, dwEffect);
  850. CEShep_UnlockEffect();
  851. } else {
  852. hres = S_FALSE;
  853. }
  854. ExitOleProcR();
  855. return hres;
  856. }
  857. /*****************************************************************************
  858. *
  859. * @doc INTERNAL
  860. *
  861. * @method HRESULT | IDirectInputEffectShepherd | StartEffect |
  862. *
  863. * Begin playback of an effect.
  864. *
  865. * @cwrap LPDIRECTINPUTEFFECTSHEPHERD | lpShepherd
  866. *
  867. * @parm PSHEPHANDLE | psh |
  868. *
  869. * Information about the effect to be played.
  870. *
  871. * @parm DWORD | dwMode |
  872. *
  873. * How the effect is to affect other effects.
  874. *
  875. * @parm DWORD | dwCount |
  876. *
  877. * Number of times the effect is to be played.
  878. *
  879. * @returns
  880. * <c S_OK> on success.
  881. *
  882. *****************************************************************************/
  883. STDMETHODIMP
  884. CEShep_StartEffect(PDES pdes, PSHEPHANDLE psh, DWORD dwMode, DWORD dwCount)
  885. {
  886. PES this;
  887. HRESULT hres;
  888. EnterProcI(IDirectInputEffectShepherd::StartEffect,
  889. (_ "puxxu", pdes, psh->dwTag, psh->dwEffect, dwMode, dwCount));
  890. this = _thisPvNm(pdes, des);
  891. if (SUCCEEDED(hres = CEShep_LockEffect(this, psh))) {
  892. hres = this->pdrv->lpVtbl->StartEffect(this->pdrv, this->idJoy,
  893. psh->dwEffect, dwMode, dwCount);
  894. CEShep_UnlockEffect();
  895. }
  896. ExitOleProcR();
  897. return hres;
  898. }
  899. /*****************************************************************************
  900. *
  901. * @doc INTERNAL
  902. *
  903. * @method HRESULT | IDirectInputEffectShepherd | StopEffect |
  904. *
  905. * Halt playback of an effect.
  906. *
  907. * ISSUE-2001/03/29-timgill There is no way to pause an effect
  908. *
  909. * @cwrap LPDIRECTINPUTEFFECTSHEPHERD | lpShepherd
  910. *
  911. * @parm DWORD | dwId |
  912. *
  913. * The external joystick number being addressed.
  914. *
  915. * @parm PSHEPHANDLE | psh |
  916. *
  917. * Information about the effect to be stopped.
  918. *
  919. * @returns
  920. * <c S_OK> on success.
  921. *
  922. *****************************************************************************/
  923. STDMETHODIMP
  924. CEShep_StopEffect(PDES pdes, PSHEPHANDLE psh)
  925. {
  926. PES this;
  927. HRESULT hres;
  928. EnterProcI(IDirectInputEffectShepherd::StopEffect,
  929. (_ "pux", pdes, psh->dwTag, psh->dwEffect));
  930. this = _thisPvNm(pdes, des);
  931. if (SUCCEEDED(hres = CEShep_LockEffect(this, psh))) {
  932. hres = this->pdrv->lpVtbl->StopEffect(this->pdrv, this->idJoy,
  933. psh->dwEffect);
  934. CEShep_UnlockEffect();
  935. }
  936. ExitOleProcR();
  937. return hres;
  938. }
  939. /*****************************************************************************
  940. *
  941. * @doc INTERNAL
  942. *
  943. * @method HRESULT | IDirectInputEffectShepherd | GetEffectStatus |
  944. *
  945. * Obtain information about an effect.
  946. *
  947. * @cwrap LPDIRECTINPUTEFFECTSHEPHERD | lpShepherd
  948. *
  949. * @parm DWORD | dwId |
  950. *
  951. * The external joystick number being addressed.
  952. *
  953. * @parm PSHEPHANDLE | psh |
  954. *
  955. * Information about the effect to be queried.
  956. *
  957. * @parm LPDWORD | pdwStatus |
  958. *
  959. * Receives the effect status.
  960. *
  961. * @returns
  962. * <c S_OK> on success.
  963. *
  964. *****************************************************************************/
  965. STDMETHODIMP
  966. CEShep_GetEffectStatus(PDES pdes, PSHEPHANDLE psh, LPDWORD pdwStatus)
  967. {
  968. PES this;
  969. HRESULT hres;
  970. EnterProcI(IDirectInputEffectShepherd::GetEffectStatus,
  971. (_ "pux", pdes, psh->dwTag, psh->dwEffect));
  972. this = _thisPvNm(pdes, des);
  973. if (SUCCEEDED(hres = CEShep_LockEffect(this, psh))) {
  974. hres = this->pdrv->lpVtbl->GetEffectStatus(this->pdrv, this->idJoy,
  975. psh->dwEffect, pdwStatus);
  976. CEShep_UnlockEffect();
  977. }
  978. ExitOleProcR();
  979. return hres;
  980. }
  981. /*****************************************************************************
  982. *
  983. * @doc INTERNAL
  984. *
  985. * @method HRESULT | IDirectInputEffectShepherd | GetVersions |
  986. *
  987. * Obtain version information about the force feedback
  988. * hardware and driver.
  989. *
  990. * @cwrap LPDIRECTINPUTEFFECTSHEPHERD | lpShepherd
  991. *
  992. * @parm LPDIDRIVERVERSIONS | pvers |
  993. *
  994. * A structure which will be filled in with version information
  995. * describing the hardware, firmware, and driver.
  996. *
  997. * @returns
  998. * <c S_OK> on success.
  999. *
  1000. *****************************************************************************/
  1001. STDMETHODIMP
  1002. CEShep_GetVersions(PDES pdes, LPDIDRIVERVERSIONS pvers)
  1003. {
  1004. PES this;
  1005. HRESULT hres;
  1006. EnterProcI(IDirectInputEffectShepherd::GetVersions, (_ "p", pdes));
  1007. this = _thisPvNm(pdes, des);
  1008. AssertF(pvers->dwSize == cbX(*pvers));
  1009. hres = this->pdrv->lpVtbl->GetVersions(this->pdrv, pvers);
  1010. ExitOleProcR();
  1011. return hres;
  1012. }
  1013. /*****************************************************************************
  1014. *
  1015. * @doc INTERNAL
  1016. *
  1017. * @method HRESULT | CEShep | InitInstance |
  1018. *
  1019. * Initialize a new instance of
  1020. * an IDirectInputEffectShepherd object.
  1021. *
  1022. * If an in-proc OLE server is needed, then load it.
  1023. *
  1024. * Otherwise, use our private interface that goes down
  1025. * to our helper driver.
  1026. *
  1027. * @parm IN HKEY | hkFF |
  1028. *
  1029. * Force feedback registry key.
  1030. *
  1031. * @returns
  1032. *
  1033. * Standard OLE <t HRESULT>.
  1034. *
  1035. *****************************************************************************/
  1036. STDMETHODIMP
  1037. CEShep_InitInstance(PES this, HKEY hkFF)
  1038. {
  1039. LONG lRc;
  1040. HRESULT hres;
  1041. TCHAR tszClsid[ctchGuid];
  1042. EnterProcI(IDirectInputEffectShepherd::InitInstance, (_ "x", hkFF));
  1043. if( hkFF == 0x0 )
  1044. {
  1045. TCHAR tszName[ctchNameGuid];
  1046. NameFromGUID(tszName, &IID_IDirectInputPIDDriver );
  1047. memcpy(tszClsid, &tszName[ctchNamePrefix], cbX(tszClsid) );
  1048. lRc = ERROR_SUCCESS;
  1049. }else
  1050. {
  1051. lRc = RegQueryString(hkFF, TEXT("CLSID"), tszClsid, cA(tszClsid));
  1052. /*
  1053. * Prefix warns that tszClsid could be uninitialized through this
  1054. * path (mb:35346) however RegQueryString only returns ERROR_SUCCESS
  1055. * if a nul terminated string has been read into tszClsid.
  1056. */
  1057. }
  1058. if (lRc == ERROR_SUCCESS) {
  1059. hres = DICoCreateInstance(tszClsid, 0,
  1060. &IID_IDirectInputEffectDriver,
  1061. &this->pdrv,
  1062. &this->hinst);
  1063. /*
  1064. * If anything went wrong, change the error to
  1065. * E_NOTIMPL so the app won't see a wacky CoCreateInstance
  1066. * error code.
  1067. */
  1068. if (FAILED(hres)) {
  1069. SquirtSqflPtszV(sqfl | sqflBenign,
  1070. TEXT("Substituting E_NOTIMPL for FF driver CoCreateInstance error 0x%08x"),
  1071. hres );
  1072. hres = E_NOTIMPL;
  1073. }
  1074. } else {
  1075. #ifdef WINNT
  1076. hres = E_NOTIMPL;
  1077. #else
  1078. {
  1079. DWORD cb = 0;
  1080. lRc = RegQueryValueEx(hkFF, TEXT("VJoyD"), 0, 0, 0, &cb);
  1081. if (lRc == ERROR_SUCCESS || lRc == ERROR_MORE_DATA) {
  1082. hres = CEffVxd_New(0, &IID_IDirectInputEffectDriver, &this->pdrv);
  1083. } else {
  1084. hres = E_NOTIMPL;
  1085. }
  1086. }
  1087. #endif
  1088. }
  1089. ExitOleProcR();
  1090. return hres;
  1091. }
  1092. /*****************************************************************************
  1093. *
  1094. * @doc INTERNAL
  1095. *
  1096. * @method HRESULT | IDirectInputEffectShepherd | New |
  1097. *
  1098. * Create a new instance of an IDirectInputEffectShepherd object.
  1099. *
  1100. * @parm IN HKEY | hkFF |
  1101. *
  1102. * Force feedback registry key.
  1103. *
  1104. * @parm IN PUNK | punkOuter |
  1105. *
  1106. * Controlling unknown for aggregation.
  1107. *
  1108. * @parm IN RIID | riid |
  1109. *
  1110. * Desired interface to new object.
  1111. *
  1112. * @parm OUT PPV | ppvObj |
  1113. *
  1114. * Output pointer for new object.
  1115. *
  1116. * @returns
  1117. *
  1118. * Standard OLE <t HRESULT>.
  1119. *
  1120. *****************************************************************************/
  1121. STDMETHODIMP
  1122. CEShep_New(HKEY hkFF, PUNK punkOuter, RIID riid, PPV ppvObj)
  1123. {
  1124. HRESULT hres;
  1125. EnterProcR(IDirectInputEffectShepherd::<constructor>, (_ "G", riid));
  1126. AssertF(g_hmtxJoy);
  1127. hres = Common_NewRiid(CEShep, punkOuter, riid, ppvObj);
  1128. if (SUCCEEDED(hres)) {
  1129. /* Must use _thisPv in case of aggregation */
  1130. PES this = _thisPv(*ppvObj);
  1131. if (SUCCEEDED(hres = CEShep_InitInstance(this, hkFF))) {
  1132. } else {
  1133. Invoke_Release(ppvObj);
  1134. }
  1135. }
  1136. ExitOleProcPpvR(ppvObj);
  1137. return hres;
  1138. }
  1139. /*****************************************************************************
  1140. *
  1141. * The long-awaited vtbls and templates
  1142. *
  1143. *****************************************************************************/
  1144. #pragma BEGIN_CONST_DATA
  1145. #define CEShep_Signature 0x50454853 /* "SHEP" */
  1146. Interface_Template_Begin(CEShep)
  1147. Primary_Interface_Template(CEShep, IDirectInputEffectShepherd)
  1148. Interface_Template_End(CEShep)
  1149. Primary_Interface_Begin(CEShep, IDirectInputEffectShepherd)
  1150. CEShep_DeviceID,
  1151. CEShep_GetVersions,
  1152. CEShep_Escape,
  1153. CEShep_DeviceEscape,
  1154. CEShep_SetGain,
  1155. CEShep_SetForceFeedbackState,
  1156. CEShep_GetForceFeedbackState,
  1157. CEShep_DownloadEffect,
  1158. CEShep_DestroyEffect,
  1159. CEShep_StartEffect,
  1160. CEShep_StopEffect,
  1161. CEShep_GetEffectStatus,
  1162. CEShep_SetGlobalGain,
  1163. Primary_Interface_End(CEShep, IDirectInputEffectShepherd)