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.

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