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.

1670 lines
49 KiB

  1. /*****************************************************************************
  2. *
  3. * DIDevEf.c
  4. *
  5. * Copyright (c) 1996 Microsoft Corporation. All Rights Reserved.
  6. *
  7. * Abstract:
  8. *
  9. * The part of IDirectInputDevice that worries about
  10. * IDirectInputEffect.
  11. *
  12. *****************************************************************************/
  13. #include "dinputpr.h"
  14. #include "didev.h"
  15. /*****************************************************************************
  16. *
  17. * @doc INTERNAL
  18. *
  19. * @method HRESULT | CDIDev | CreateEffectDriver |
  20. *
  21. * If we don't already have one, create the effect
  22. * driver shepherd
  23. * so we can do force feedback goo. If we already
  24. * have one, then there's nothing to do.
  25. *
  26. * @cwrap LPDIRECTINPUTDEVICE | lpDirectInputDevice
  27. *
  28. * @returns
  29. * Returns a COM error code. The following error codes are
  30. * intended to be illustrative and not necessarily comprehensive.
  31. *
  32. * <c DI_OK> = <c S_OK>: The operation completed successfully.
  33. *
  34. * <c DIERR_UNSUPPORTED> = <c E_NOTIMPL>: The device does
  35. * not support force feeback, or there was an error loading
  36. * the force feedback driver.
  37. *
  38. *****************************************************************************/
  39. HRESULT INTERNAL
  40. CDIDev_CreateEffectDriver(PDD this)
  41. {
  42. HRESULT hres;
  43. CDIDev_EnterCrit(this);
  44. if (this->pes) {
  45. hres = S_OK;
  46. } else {
  47. hres = this->pdcb->lpVtbl->CreateEffect(this->pdcb, &this->pes);
  48. /*
  49. * If we have acquisition, then do a force feedback
  50. * acquire to get everything back in sync.
  51. */
  52. if (SUCCEEDED(hres) && this->fAcquired) {
  53. CDIDev_FFAcquire(this);
  54. hres = S_OK;
  55. }
  56. }
  57. CDIDev_LeaveCrit(this);
  58. return hres;
  59. }
  60. /*****************************************************************************
  61. *
  62. * @doc EXTERNAL
  63. *
  64. * @method HRESULT | IDirectInputDevice8 | CreateEffect |
  65. *
  66. * Creates and initializes an instance of an effect
  67. * identified by the effect GUID.
  68. *
  69. * @cwrap LPDIRECTINPUTDEVICE | lpDirectInputDevice
  70. *
  71. * @parm IN REFGUID | rguid |
  72. *
  73. * The identity of the effect to be created. This can be
  74. * a predefined effect GUID, or it can be a GUID obtained
  75. * from <mf IDirectInputDevice8::EnumEffects>.
  76. *
  77. * @parm IN LPCDIEFFECT | lpeff |
  78. *
  79. * Pointer to a <t DIEFFECT> structure which provides
  80. * parameters for the created effect. This parameter
  81. * is optional. If it is <c NULL>, then the effect object
  82. * is created without parameters. The application must
  83. * call <mf IDirectInputEffect::SetParameters> to set
  84. * the parameters of the effect before it can download
  85. * the effect.
  86. *
  87. * @parm OUT LPDIRECTINPUTEFFECT * | ppdeff |
  88. *
  89. * Points to where to return
  90. * the pointer to the <i IDirectInputEffect> interface, if successful.
  91. *
  92. * @parm IN LPUNKNOWN | punkOuter |
  93. *
  94. * Pointer to controlling unknown
  95. * for OLE aggregation, or 0 if the interface is not aggregated.
  96. * Most callers will pass 0.
  97. *
  98. * @returns
  99. * Returns a COM error code. The following error codes are
  100. * intended to be illustrative and not necessarily comprehensive.
  101. *
  102. * <c DI_OK> = <c S_OK>: The object was created and initialized
  103. * successfully.
  104. *
  105. * <c DI_TRUNCATED>: The effect was successfully created,
  106. * but some of the effect parameters were
  107. * beyond the capabilities of the device and were truncated
  108. * to the nearest valid value.
  109. * Note that this is a success code, because the effect was
  110. * successfully created.
  111. *
  112. * <c DIERR_DEVICENOTREG>: The effect GUID is not supported
  113. * by the device.
  114. *
  115. * <c DIERR_DEVICEFULL>: The device is full.
  116. *
  117. * <c DIERR_INVALIDPARAM>: At least one of the parameters
  118. * was invalid.
  119. *
  120. *
  121. * @devnote
  122. *
  123. * Future versions of DirectX will allow <p lpeff> to be NULL,
  124. * indicating that the effect should not be initialized.
  125. * This is important to support effects which are created
  126. * but which aren't downloaded until the app explicitly
  127. * requests it.
  128. *
  129. *****************************************************************************/
  130. /*
  131. * Helper function which decides how many parameters to set,
  132. * based on the incoming DIEFFECT structure.
  133. */
  134. DWORD INLINE
  135. CDIDev_DiepFromPeff(LPCDIEFFECT peff)
  136. {
  137. /*
  138. * If we received a DIEFFECT_DX5, then we need to
  139. * pass DIEP_ALLPARAMS_DX5 instead of DIEP_ALLPARAMS.
  140. */
  141. return peff->dwSize < cbX(DIEFFECT_DX6)
  142. ? DIEP_ALLPARAMS_DX5
  143. : DIEP_ALLPARAMS;
  144. }
  145. STDMETHODIMP
  146. CDIDev_CreateEffect(PV pdd, REFGUID rguid, LPCDIEFFECT peff,
  147. LPDIRECTINPUTEFFECT *ppdeff, LPUNKNOWN punkOuter _THAT)
  148. {
  149. HRESULT hres;
  150. EnterProcR(IDirectInputDevice8::CreateEffect,
  151. (_ "pGpp", pdd, rguid, peff, punkOuter));
  152. /*
  153. * CDIEff_New will validate the ppdeff and punkOuter, but
  154. * we need to validate ppdeff because we're going to
  155. * shove a zero into it.
  156. *
  157. * We also need to check peff->dwSize as we need to test it
  158. * before calling IDirectInputEffect_SetParameters.
  159. *
  160. * CDIEff_Initialize will validate the rguid.
  161. *
  162. * CDIEff_SetParameters will validate the peff.
  163. */
  164. if (SUCCEEDED(hres = hresPvT(pdd)) &&
  165. SUCCEEDED(hres = (peff && IsBadReadPtr(&peff->dwSize, cbX(peff->dwSize))) ? E_POINTER : S_OK) &&
  166. SUCCEEDED(hres = hresFullValidPcbOut(ppdeff, cbX(*ppdeff), 4))) {
  167. PDD this = _thisPv(pdd);
  168. hres = CDIDev_CreateEffectDriver(this);
  169. *ppdeff = 0; /* If CDIDev_CreateEffectDriver fails */
  170. if (SUCCEEDED(hres)) {
  171. hres = CDIEff_New(this, this->pes, punkOuter,
  172. &IID_IDirectInputEffect, (PPV)ppdeff);
  173. /*
  174. * We assume that IDirectInputEffect is the primary interface.
  175. */
  176. AssertF(fLimpFF(SUCCEEDED(hres),
  177. (PV)*ppdeff == _thisPv(*ppdeff)));
  178. if (SUCCEEDED(hres) && punkOuter == 0) {
  179. LPDIRECTINPUTEFFECT pdeff = *ppdeff;
  180. hres = IDirectInputEffect_Initialize(pdeff, g_hinst,
  181. this->dwVersion, rguid);
  182. if (SUCCEEDED(hres)) {
  183. if (fLimpFF(peff,
  184. SUCCEEDED(hres =
  185. IDirectInputEffect_SetParameters(
  186. pdeff, peff,
  187. CDIDev_DiepFromPeff(peff))))) {
  188. /*
  189. * Woo-hoo, all is well.
  190. */
  191. hres = S_OK;
  192. } else {
  193. Invoke_Release(ppdeff);
  194. }
  195. } else {
  196. /*
  197. * Error initializing.
  198. */
  199. Invoke_Release(ppdeff);
  200. }
  201. } else {
  202. /*
  203. * Error creating, or object is aggregated and therefore
  204. * should not be initialized.
  205. */
  206. }
  207. } else {
  208. /*
  209. * Error creating effect driver, or no effect driver.
  210. */
  211. }
  212. }
  213. ExitOleProcPpv(ppdeff);
  214. return hres;
  215. }
  216. /*****************************************************************************
  217. *
  218. * @doc INTERNAL
  219. *
  220. * @method HRESULT | CDIDev | SyncShepHandle |
  221. *
  222. * Synchronize the caller's <t SHEPHANDLE> with the
  223. * <t SHEPHANDLE> of the parent. This lets
  224. * dieshep.c know that the two are talking about the same thing.
  225. *
  226. * @cwrap PDD | this
  227. *
  228. * @returns
  229. * Returns <c S_OK> if the tags already matched,
  230. * or <c S_FALSE> if the tag changed. If the tag changed,
  231. * then the handle inside the <t SHEPHANDLE> is zero'd.
  232. *
  233. * Note that <f CDIEff_DownloadWorker> assumes that the
  234. * return value is exactly <c S_OK> or <c S_FALSE>.
  235. *
  236. *****************************************************************************/
  237. STDMETHODIMP
  238. CDIDev_SyncShepHandle(PDD this, PSHEPHANDLE psh)
  239. {
  240. HRESULT hres;
  241. AssertF(CDIDev_InCrit(this));
  242. if (psh->dwTag == this->sh.dwTag) {
  243. hres = S_OK;
  244. } else {
  245. psh->dwTag = this->sh.dwTag;
  246. psh->dwEffect = 0;
  247. hres = S_FALSE;
  248. }
  249. return hres;
  250. }
  251. /*****************************************************************************
  252. *
  253. * @doc INTERNAL
  254. *
  255. * @method HRESULT | CDIDev | NotifyCreateEffect |
  256. *
  257. * Add the effect pointer to the list of effects that
  258. * have been created by the device.
  259. *
  260. * The device critical section must not be owned by the
  261. * calling thread.
  262. *
  263. * @cwrap PDD | this
  264. *
  265. * @parm IN struct CDIEff * | pdeff |
  266. *
  267. * The effect pointer to add.
  268. *
  269. * @returns
  270. * Returns a COM error code. The following error codes are
  271. * intended to be illustrative and not necessarily comprehensive.
  272. *
  273. * <c DI_OK> = <c S_OK>: Everything is okay.
  274. *
  275. * <c DIERR_OUTOFMEMORY> =
  276. * <c E_OUTOFMEMORY>: No memory to record the effect.
  277. *
  278. *****************************************************************************/
  279. HRESULT EXTERNAL
  280. CDIDev_NotifyCreateEffect(PDD this, struct CDIEff *pdeff)
  281. {
  282. HRESULT hres;
  283. AssertF(!CDIDev_InCrit(this));
  284. CDIDev_EnterCrit(this);
  285. hres = GPA_Append(&this->gpaEff, pdeff);
  286. CDIDev_LeaveCrit(this);
  287. /*
  288. * Note that we must leave the device critical section
  289. * before talking to the effect, in order to preserve
  290. * the synchronization hierarchy.
  291. */
  292. if (SUCCEEDED(hres)) {
  293. Common_Hold(pdeff);
  294. hres = S_OK;
  295. }
  296. return hres;
  297. }
  298. /*****************************************************************************
  299. *
  300. * @doc INTERNAL
  301. *
  302. * @method HRESULT | CDIDev | NotifyDestroyEffect |
  303. *
  304. * Remove the effect pointer from the list of effects that
  305. * have been created by the device.
  306. *
  307. * The device critical section must not be owned by the
  308. * calling thread.
  309. *
  310. * @cwrap PDD | this
  311. *
  312. * @parm IN struct CDIEff * | pdeff |
  313. *
  314. * The effect pointer to remove.
  315. *
  316. * @returns
  317. *
  318. * Returns a COM error code on failure.
  319. *
  320. * On success, returns the number of items left in the GPA.
  321. *
  322. *****************************************************************************/
  323. HRESULT EXTERNAL
  324. CDIDev_NotifyDestroyEffect(PDD this, struct CDIEff *pdeff)
  325. {
  326. HRESULT hres;
  327. AssertF(!CDIDev_InCrit(this));
  328. CDIDev_EnterCrit(this);
  329. hres = GPA_DeletePtr(&this->gpaEff, pdeff);
  330. CDIDev_LeaveCrit(this);
  331. /*
  332. * Note that we must leave the device critical section
  333. * before talking to the effect, in order to preserve
  334. * the synchronization hierarchy.
  335. *
  336. * Note that there you might think there's a deadlock here if
  337. * effect A notifies us, and we in turn try to unhold
  338. * effect B. But that won't happen, because we only
  339. * unhold the effect that notified us.
  340. */
  341. if (SUCCEEDED(hres)) {
  342. Common_Unhold(pdeff);
  343. hres = S_OK;
  344. }
  345. return hres;
  346. }
  347. /*****************************************************************************
  348. *
  349. * @doc INTERNAL
  350. *
  351. * @method HRESULT | CDIDev | FindEffectGUID |
  352. *
  353. * Look for an effect <t GUID>; if found, fetch associated
  354. * information.
  355. *
  356. * @cwrap LPDIRECTINPUTDEVICE | lpDirectInputDevice
  357. *
  358. * @parm REFGUID | rguid |
  359. *
  360. * Effect <t GUID> to locate.
  361. *
  362. * @parm PEFFECTMAPINFO | pemi |
  363. *
  364. * Receives associated information for the effect.
  365. * We must return a copy instead of a pointer, because
  366. * the original might disappear suddenly if the
  367. * device gets <mf CDIDev::Reset>().
  368. *
  369. * @returns
  370. *
  371. * Returns a COM error code. The following error codes are
  372. * intended to be illustrative and not necessarily comprehensive.
  373. *
  374. * <c DI_OK> = <c S_OK>: The operation completed successfully.
  375. *
  376. * <c DIERR_OUTOFMEMORY> = <c E_OUTOFMEMORY>: Out of memory.
  377. *
  378. * <c DIERR_DEVICENOTREG> = <c REGDB_E_CLASSNOTREG>:
  379. * The effect is not supported by the device.
  380. *
  381. *****************************************************************************/
  382. STDMETHODIMP
  383. CDIDev_FindEffectGUID_(PDD this, REFGUID rguid, PEFFECTMAPINFO pemi,
  384. LPCSTR s_szProc, int iarg)
  385. {
  386. UINT iemi;
  387. HRESULT hres;
  388. D(iarg);
  389. CDIDev_EnterCrit(this);
  390. for (iemi = 0; iemi < this->cemi; iemi++) {
  391. if (IsEqualGUID(rguid, &this->rgemi[iemi].guid)) {
  392. *pemi = this->rgemi[iemi];
  393. hres = S_OK;
  394. goto found;
  395. }
  396. }
  397. RPF("%s: Effect not supported by device", s_szProc);
  398. hres = DIERR_DEVICENOTREG; /* Effect not found */
  399. found:;
  400. CDIDev_LeaveCrit(this);
  401. return hres;
  402. }
  403. /*****************************************************************************
  404. *
  405. * @doc INTERNAL
  406. *
  407. * @method void | CDIDev | GetEffectInfoHelper |
  408. *
  409. * Transfer information from an
  410. * <t EFFECTMAPINFO> to a <t DIEFFECTINFOW>.
  411. *
  412. * @cwrap PDD | this
  413. *
  414. * @parm LPDIEFFECTINFOW | pdeiW |
  415. *
  416. * Destination.
  417. *
  418. * @parm PCEFFECTMAPINFO | pemi |
  419. *
  420. * Source.
  421. *
  422. *****************************************************************************/
  423. void INTERNAL
  424. CDIDev_GetEffectInfoHelper(PDD this, LPDIEFFECTINFOW pdeiW,
  425. PCEFFECTMAPINFO pemi)
  426. {
  427. AssertF(pdeiW->dwSize == cbX(*pdeiW));
  428. pdeiW->guid = pemi->guid;
  429. pdeiW->dwEffType = pemi->attr.dwEffType;
  430. pdeiW->dwStaticParams = pemi->attr.dwStaticParams;
  431. pdeiW->dwDynamicParams = pemi->attr.dwDynamicParams;
  432. CAssertF(cbX(pdeiW->tszName) == cbX(pemi->wszName));
  433. CopyMemory(pdeiW->tszName, pemi->wszName, cbX(pemi->wszName));
  434. }
  435. /*****************************************************************************
  436. *
  437. * @doc EXTERNAL
  438. *
  439. * @method HRESULT | IDirectInputDevice8 | EnumEffects |
  440. *
  441. * Enumerates all of the effects supported by the force
  442. * feedback system on the device. The enumerated GUIDs
  443. * may represent predefined effects as well as effects
  444. * peculiar to the device manufacturer.
  445. *
  446. * An application
  447. * can use the <e DIEFFECTINFO.dwEffType> field of the
  448. * <t DIEFFECTINFO> structure to obtain general
  449. * information about the effect, such as its type and
  450. * which envelope and condition parameters are supported
  451. * by the effect.
  452. *
  453. * In order to exploit an effect to its fullest,
  454. * you must contact the device manufacturer to obtain
  455. * information on the semantics of the effect and its
  456. * effect-specific parameters.
  457. *
  458. * @cwrap LPDIRECTINPUTDEVICE | lpDirectInputDevice
  459. *
  460. * @parm LPDIENUMEFFECTSCALLBACK | lpCallback |
  461. *
  462. * Points to an application-defined callback function.
  463. * For more information, see the description of the
  464. * <f DIEnumEffectsProc> callback function.
  465. *
  466. * @parm LPVOID | pvRef |
  467. *
  468. * Specifies a 32-bit application-defined
  469. * value to be passed to the callback function. This value
  470. * may be any 32-bit value; it is prototyped as an <t LPVOID>
  471. * for convenience.
  472. *
  473. * @parm DWORD | dwEffType |
  474. *
  475. * Effect type filter. If <c DIEFT_ALL>, then all
  476. * effect types are
  477. * enumerated. Otherwise, it is a <c DIEFT_*> value,
  478. * indicating the device type that should be enumerated.
  479. *
  480. * @returns
  481. *
  482. * Returns a COM error code. The following error codes are
  483. * intended to be illustrative and not necessarily comprehensive.
  484. *
  485. * <c DI_OK> = <c S_OK>: The operation completed successfully.
  486. * Note that if the callback stops the enumeration prematurely,
  487. * the enumeration is considered to have succeeded.
  488. *
  489. * <c DIERR_INVALIDPARAM> = <c E_INVALIDARG>: The
  490. * <p fl> parameter contains invalid flags, or the callback
  491. * procedure returned an invalid status code.
  492. *
  493. * @cb BOOL CALLBACK | DIEnumEffectsProc |
  494. *
  495. * An application-defined callback function that receives
  496. * device effects as a result of a call to the
  497. * <om IDirectInputDevice8::EnumEffects> method.
  498. *
  499. * @parm IN LPCDIEFFECTINFO | pdei |
  500. *
  501. * A <t DIEFFECTINFO> structure that describes the enumerated
  502. * effect.
  503. *
  504. * @parm IN OUT LPVOID | pvRef |
  505. *
  506. * Specifies the application-defined value given in the
  507. * <mf IDirectInputDevice8::EnumEffects> function.
  508. *
  509. * @returns
  510. *
  511. * Returns <c DIENUM_CONTINUE> to continue the enumeration
  512. * or <c DIENUM_STOP> to stop the enumeration.
  513. *
  514. *//**************************************************************************
  515. *
  516. * In DEBUG/RDEBUG, if the callback returns a bogus value, raise
  517. * a validation exception.
  518. *
  519. *****************************************************************************/
  520. STDMETHODIMP
  521. CDIDev_EnumEffectsW
  522. (PV pddW, LPDIENUMEFFECTSCALLBACKW pecW, PV pvRef, DWORD dwEffType)
  523. {
  524. HRESULT hres;
  525. EnterProcR(IDirectInputDevice8W::EnumEffects,
  526. (_ "pppx", pddW, pecW, pvRef, dwEffType));
  527. if (SUCCEEDED(hres = hresPvW(pddW)) &&
  528. SUCCEEDED(hres = hresFullValidPfn(pecW, 1)) &&
  529. SUCCEEDED(hres = hresFullValidFl(dwEffType, DIEFT_ENUMVALID, 3))) {
  530. PDD this = _thisPvNm(pddW, ddW);
  531. PEFFECTMAPINFO rgemi;
  532. UINT iemi, cemi;
  533. /*
  534. * We need to make a private copy of the GUID list,
  535. * because somebody else might suddenly Reset() the
  536. * device and mess up everything.
  537. *
  538. * Indeed, it might've been Reset() during this comment!
  539. * That's why we need to create the private copy
  540. * while under the critical section.
  541. */
  542. CDIDev_EnterCrit(this);
  543. cemi = this->cemi;
  544. hres = AllocCbPpv(cbCxX(this->cemi, EFFECTMAPINFO), &rgemi);
  545. if (SUCCEEDED(hres)) {
  546. if (this->cemi) {
  547. CopyMemory(rgemi, this->rgemi,
  548. cbCxX(this->cemi, EFFECTMAPINFO));
  549. }
  550. }
  551. CDIDev_LeaveCrit(this);
  552. if (SUCCEEDED(hres)) {
  553. for (iemi = 0; iemi < cemi; iemi++) {
  554. PEFFECTMAPINFO pemi = &rgemi[iemi];
  555. if (fLimpFF(dwEffType,
  556. dwEffType == LOBYTE(pemi->attr.dwEffType))) {
  557. BOOL fRc;
  558. DIEFFECTINFOW deiW;
  559. deiW.dwSize = cbX(deiW);
  560. CDIDev_GetEffectInfoHelper(this, &deiW, pemi);
  561. fRc = Callback(pecW, &deiW, pvRef);
  562. switch (fRc) {
  563. case DIENUM_STOP: goto enumdoneok;
  564. case DIENUM_CONTINUE: break;
  565. default:
  566. RPF("%s: Invalid return value from callback",
  567. s_szProc);
  568. ValidationException();
  569. break;
  570. }
  571. }
  572. }
  573. enumdoneok:;
  574. FreePpv(&rgemi);
  575. hres = S_OK;
  576. }
  577. }
  578. ExitOleProc();
  579. return hres;
  580. }
  581. /*****************************************************************************
  582. *
  583. * @doc INTERNAL
  584. *
  585. * @method HRESULT | IDirectInputDevice8A | EnumEffectsCallbackA |
  586. *
  587. * Custom callback that wraps
  588. * <mf IDirectInputDevice8::EnumObjects> which
  589. * translates the UNICODE string to an ANSI string.
  590. *
  591. * @parm IN LPCDIEFFECTINFOA | pdoiA |
  592. *
  593. * Structure to be translated to ANSI.
  594. *
  595. * @parm IN LPVOID | pvRef |
  596. *
  597. * Pointer to <t struct ENUMEFFECTSINFO> which describes
  598. * the original callback.
  599. *
  600. * @returns
  601. *
  602. * Returns whatever the original callback returned.
  603. *
  604. *****************************************************************************/
  605. typedef struct ENUMEFFECTSINFO {
  606. LPDIENUMEFFECTSCALLBACKA pecA;
  607. PV pvRef;
  608. } ENUMEFFECTSINFO, *PENUMEFFECTSINFO;
  609. BOOL CALLBACK
  610. CDIDev_EnumEffectsCallbackA(LPCDIEFFECTINFOW pdeiW, PV pvRef)
  611. {
  612. PENUMEFFECTSINFO peei = pvRef;
  613. BOOL fRc;
  614. DIEFFECTINFOA deiA;
  615. EnterProc(CDIObj_EnumObjectsCallbackA,
  616. (_ "GxWp", &pdeiW->guid,
  617. &pdeiW->dwEffType,
  618. pdeiW->tszName, pvRef));
  619. deiA.dwSize = cbX(deiA);
  620. EffectInfoWToA(&deiA, pdeiW);
  621. fRc = peei->pecA(&deiA, peei->pvRef);
  622. ExitProcX(fRc);
  623. return fRc;
  624. }
  625. /*****************************************************************************
  626. *
  627. * @doc INTERNAL
  628. *
  629. * @method HRESULT | IDirectInputDevice8A | EnumEffects |
  630. *
  631. * Enumerate the effects available on a device, in ANSI.
  632. * See <mf IDirectInputDevice8::EnumEffects> for more information.
  633. *
  634. * @cwrap LPDIRECTINPUTDEVICE | lpDirectInputDevice
  635. *
  636. * @parm IN LPDIENUMEFFECTSCALLBACKA | lpCallback |
  637. *
  638. * Same as <mf IDirectInputDevice8W::EnumObjects>, except in ANSI.
  639. *
  640. * @parm IN LPVOID | pvRef |
  641. *
  642. * Same as <mf IDirectInputDevice8W::EnumObjects>.
  643. *
  644. * @parm IN DWORD | fl |
  645. *
  646. * Same as <mf IDirectInputDevice8W::EnumObjects>.
  647. *
  648. *****************************************************************************/
  649. STDMETHODIMP
  650. CDIDev_EnumEffectsA
  651. (PV pddA, LPDIENUMEFFECTSCALLBACKA pecA, PV pvRef, DWORD dwEffType)
  652. {
  653. HRESULT hres;
  654. EnterProcR(IDirectInputDevice8A::EnumEffects,
  655. (_ "pppx", pddA, pecA, pvRef, dwEffType));
  656. /*
  657. * EnumEffectsW will validate the rest.
  658. */
  659. if (SUCCEEDED(hres = hresPvA(pddA)) &&
  660. SUCCEEDED(hres = hresFullValidPfn(pecA, 1))) {
  661. ENUMEFFECTSINFO eei = { pecA, pvRef };
  662. PDD this = _thisPvNm(pddA, ddA);
  663. hres = CDIDev_EnumEffectsW(&this->ddW, CDIDev_EnumEffectsCallbackA,
  664. &eei, dwEffType);
  665. }
  666. ExitOleProcR();
  667. return hres;
  668. }
  669. /*****************************************************************************
  670. *
  671. * @doc EXTERNAL
  672. *
  673. * @method HRESULT | IDirectInputDevice8 | GetEffectInfo |
  674. *
  675. * Obtains information about an effect.
  676. *
  677. * @cwrap LPDIRECTINPUTDEVICE | lpDirectInputDevice
  678. *
  679. * @parm OUT LPDIEFFECTINFO | pdei |
  680. *
  681. * Receives information about the effect.
  682. * The caller "must" initialize the <e DIEFFECTINFO.dwSize>
  683. * field before calling this method.
  684. *
  685. * @parm REFGUID | rguid |
  686. *
  687. * Identifies the effect for which information is being requested.
  688. *
  689. * @returns
  690. *
  691. * Returns a COM error code. The following error codes are
  692. * intended to be illustrative and not necessarily comprehensive.
  693. *
  694. * <c DI_OK> = <c S_OK>: The operation completed successfully.
  695. *
  696. * <c DIERR_INVALIDPARAM> = <c E_INVALIDARG>: One or more
  697. * parameters was invalid.
  698. *
  699. * <c DIERR_DEVICENOTREG>: The effect GUID does not exist
  700. * on the current device.
  701. *
  702. *****************************************************************************/
  703. STDMETHODIMP
  704. CDIDev_GetEffectInfoW(PV pddW, LPDIEFFECTINFOW pdeiW, REFGUID rguid)
  705. {
  706. HRESULT hres;
  707. EnterProcR(IDirectInputDevice8W::GetEffectInfo,
  708. (_ "ppG", pddW, pdeiW, rguid));
  709. if (SUCCEEDED(hres = hresPvW(pddW)) &&
  710. SUCCEEDED(hres = hresFullValidWritePxCb(pdeiW,
  711. DIEFFECTINFOW, 1))) {
  712. PDD this = _thisPvNm(pddW, ddW);
  713. EFFECTMAPINFO emi;
  714. if (SUCCEEDED(hres = CDIDev_FindEffectGUID(this, rguid, &emi, 2))) {
  715. CDIDev_GetEffectInfoHelper(this, pdeiW, &emi);
  716. hres = S_OK;
  717. }
  718. if (FAILED(hres)) {
  719. ScrambleBuf(&pdeiW->guid,
  720. cbX(DIEFFECTINFOW) - FIELD_OFFSET(DIEFFECTINFOW, guid));
  721. }
  722. }
  723. ExitOleProcR();
  724. return hres;
  725. }
  726. /*****************************************************************************
  727. *
  728. * @doc INTERNAL
  729. *
  730. * @method HRESULT | IDirectInputDevice8A | GetEffectInfo |
  731. *
  732. * ANSI version of same.
  733. *
  734. * @cwrap LPDIRECTINPUTDEVICE | lpDirectInputDevice
  735. *
  736. * @parm OUT LPDIEFFECTINFO | pdei |
  737. *
  738. * Receives information about the effect.
  739. * The caller "must" initialize the <e DIEFFECTINFO.dwSize>
  740. * field before calling this method.
  741. *
  742. * @parm REFGUID | rguid |
  743. *
  744. * Identifies the effect for which information is being requested.
  745. *
  746. * @returns
  747. *
  748. * Returns a COM error code. The following error codes are
  749. * intended to be illustrative and not necessarily comprehensive.
  750. *
  751. * <c DI_OK> = <c S_OK>: The operation completed successfully.
  752. *
  753. * <c DIERR_INVALIDPARAM> = <c E_INVALIDARG>: One or more
  754. * parameters was invalid.
  755. *
  756. * <c DIERR_DEVICENOTREG>: The effect GUID does not exist
  757. * on the current device.
  758. *
  759. *****************************************************************************/
  760. STDMETHODIMP
  761. CDIDev_GetEffectInfoA(PV pddA, LPDIEFFECTINFOA pdeiA, REFGUID rguid)
  762. {
  763. HRESULT hres;
  764. EnterProcR(IDirectInputDevice8A::GetEffectInfo,
  765. (_ "ppG", pddA, pdeiA, rguid));
  766. if (SUCCEEDED(hres = hresPvA(pddA)) &&
  767. SUCCEEDED(hres = hresFullValidWritePxCb(pdeiA,
  768. DIEFFECTINFOA, 1))) {
  769. PDD this = _thisPvNm(pddA, ddA);
  770. DIEFFECTINFOW deiW;
  771. deiW.dwSize = cbX(deiW);
  772. hres = CDIDev_GetEffectInfoW(&this->ddW, &deiW, rguid);
  773. if (SUCCEEDED(hres)) {
  774. EffectInfoWToA(pdeiA, &deiW);
  775. hres = S_OK;
  776. } else {
  777. ScrambleBuf(&pdeiA->guid,
  778. cbX(DIEFFECTINFOA) - FIELD_OFFSET(DIEFFECTINFOA, guid));
  779. }
  780. }
  781. ExitOleProcR();
  782. return hres;
  783. }
  784. /*****************************************************************************
  785. *
  786. * @doc EXTERNAL
  787. *
  788. * @method HRESULT | IDirectInputDevice8 | GetForceFeedbackState |
  789. *
  790. * Retrieves the state of the device's force feedback system.
  791. * The device must be acquired for this method to succeed.
  792. *
  793. * @cwrap LPDIRECTINPUTDEVICE | lpDirectInputDevice
  794. *
  795. * @parm LPDWORD | pdwOut |
  796. *
  797. * Receives a <t DWORD> of flags which describe the current
  798. * state of the device's force feedback system.
  799. *
  800. * The value is a combination of zero or more <c DIGFFS_*>
  801. * flags.
  802. *
  803. * Note that future versions of DirectInput may define
  804. * additional flags. Applications should ignore any flags
  805. * that are not currently defined.
  806. *
  807. * @returns
  808. *
  809. * Returns a COM error code. The following error codes are
  810. * intended to be illustrative and not necessarily comprehensive.
  811. *
  812. * <c DI_OK> = <c S_OK>: The operation completed successfully.
  813. *
  814. * <c DIERR_INVALIDPARAM> = <c E_INVALIDARG>: The
  815. * <p pdwOut> parameter is not a valid pointer.
  816. *
  817. * <c DIERR_INPUTLOST>: Acquisition has been lost.
  818. *
  819. * <c DIERR_NOTEXCLUSIVEACQUIRED>: The device is acquired,
  820. * but not exclusively, or the device is not acquired
  821. * at all.
  822. *
  823. * <c DIERR_UNSUPPORTED> = <c E_NOTIMPL>: The device
  824. * does not support force feedback.
  825. *
  826. *****************************************************************************/
  827. STDMETHODIMP
  828. CDIDev_GetForceFeedbackState(PV pdd, LPDWORD pdwOut _THAT)
  829. {
  830. HRESULT hres;
  831. EnterProcR(IDirectInputDevice8::GetForceFeedbackState, (_ "p", pdd));
  832. if (SUCCEEDED(hres = hresPvT(pdd)) &&
  833. SUCCEEDED(hres = hresFullValidPcbOut(pdwOut, cbX(*pdwOut), 1))) {
  834. PDD this = _thisPv(pdd);
  835. /*
  836. * I just know people aren't going to check the error code,
  837. * so don't let them see garbage.
  838. */
  839. *pdwOut = 0;
  840. hres = CDIDev_CreateEffectDriver(this);
  841. if (SUCCEEDED(hres)) {
  842. DIDEVICESTATE ds;
  843. CDIDev_EnterCrit(this);
  844. /*
  845. * Note that it isn't necessary to check
  846. * CDIDev_IsExclAcquired(), because the effect shepherd
  847. * will deny us access to a device we don't own.
  848. *
  849. * ISSUE-2001/03/29-timgill Need to handle DIERR_INPUTLOST case
  850. */
  851. ds.dwSize = cbX(ds);
  852. /*
  853. * Prefix raises a warning (mb:34564) that this->pes could
  854. * be NULL however CDIDev_CreateEffectDriver only succeeds
  855. * if it is not.
  856. */
  857. hres = this->pes->lpVtbl->
  858. GetForceFeedbackState(this->pes, &this->sh, &ds);
  859. /*
  860. * We put as many flags in matching places in
  861. * DISFFC_* and DIGFFS_* because I just know
  862. * app writers are going to mess it up.
  863. */
  864. if (SUCCEEDED(hres)) {
  865. CAssertF(DISFFC_RESET == DIGFFS_EMPTY);
  866. CAssertF(DISFFC_STOPALL == DIGFFS_STOPPED);
  867. CAssertF(DISFFC_PAUSE == DIGFFS_PAUSED);
  868. CAssertF(DISFFC_SETACTUATORSON == DIGFFS_ACTUATORSON);
  869. CAssertF(DISFFC_SETACTUATORSOFF == DIGFFS_ACTUATORSOFF);
  870. *pdwOut = ds.dwState;
  871. hres = S_OK;
  872. }
  873. CDIDev_LeaveCrit(this);
  874. }
  875. ScrambleBit(pdwOut, DIGFFS_RANDOM);
  876. }
  877. /*
  878. * Can't use ExitOleProcPpv here because pdwOut might have
  879. * DIFFS_RANDOM set in it, even on error.
  880. */
  881. ExitOleProc();
  882. return hres;
  883. }
  884. /*****************************************************************************
  885. *
  886. * @doc EXTERNAL
  887. *
  888. * @method HRESULT | IDirectInputDevice8 | SendForceFeedbackCommand |
  889. *
  890. * Sends a command to the the device's force feedback system.
  891. * The device must be acquired for this method to succeed.
  892. *
  893. * @cwrap LPDIRECTINPUTDEVICE | lpDirectInputDevice
  894. *
  895. * @parm DWORD | dwCommand |
  896. *
  897. * One of the <c DISFFC_*> values indicating
  898. * the command to send.
  899. *
  900. * @returns
  901. *
  902. * Returns a COM error code. The following error codes are
  903. * intended to be illustrative and not necessarily comprehensive.
  904. *
  905. * <c DI_OK> = <c S_OK>: The operation completed successfully.
  906. *
  907. * <c DIERR_INVALIDPARAM> = <c E_INVALIDARG>: The
  908. * <p dwFlags> parameter is invalid.
  909. *
  910. * <c DIERR_INPUTLOST>: Acquisition has been lost.
  911. *
  912. * <c DIERR_NOTEXCLUSIVEACQUIRED>: The device is acquired,
  913. * but not exclusively, or the device is not acquired
  914. * at all.
  915. *
  916. * <c DIERR_UNSUPPORTED> = <c E_NOTIMPL>: The device
  917. * does not support force feedback.
  918. *
  919. *****************************************************************************/
  920. HRESULT INLINE
  921. CDIDev_SendForceFeedbackCommand_IsValidCommand(DWORD dwCmd)
  922. {
  923. HRESULT hres;
  924. RD(static char s_szProc[] = "IDirectInputDevice8::SendForceFeedbackCommand");
  925. /*
  926. * dwCmd must not be zero (therefore at least one bit set).
  927. * !(dwCmd & (dwCmd - 1)) checks that at most one bit is set.
  928. * (dwCmd & ~DISFFC_VALID) checks that no bad bits are set.
  929. */
  930. if (dwCmd && !(dwCmd & ~DISFFC_VALID) && !(dwCmd & (dwCmd - 1))) {
  931. hres = S_OK;
  932. } else {
  933. RPF("ERROR %s: arg %d: invalid command", s_szProc, 1);
  934. hres = E_INVALIDARG;
  935. }
  936. return hres;
  937. }
  938. STDMETHODIMP
  939. CDIDev_SendForceFeedbackCommand(PV pdd, DWORD dwCmd _THAT)
  940. {
  941. HRESULT hres;
  942. EnterProcR(IDirectInputDevice8::SendForceFeedbackCommand,
  943. (_ "px", pdd, dwCmd));
  944. if (SUCCEEDED(hres = hresPvT(pdd)) &&
  945. SUCCEEDED(hres = CDIDev_SendForceFeedbackCommand_IsValidCommand
  946. (dwCmd))) {
  947. PDD this = _thisPv(pdd);
  948. hres = CDIDev_CreateEffectDriver(this);
  949. if (SUCCEEDED(hres)) {
  950. CDIDev_EnterCrit(this);
  951. /*
  952. * Note that it isn't necessary to check
  953. * CDIDev_IsExclAcquired(), because the effect shepherd
  954. * will deny us access to a device we don't own.
  955. *
  956. * ISSUE-2001/03/29-timgill Need to handle DIERR_INPUTLOST case
  957. */
  958. /*
  959. * Prefix raises a warning (mb:34564) that this->pes could
  960. * be NULL however CDIDev_CreateEffectDriver only succeeds
  961. * if it is not.
  962. */
  963. hres = this->pes->lpVtbl->
  964. SendForceFeedbackCommand(this->pes,
  965. &this->sh, dwCmd);
  966. if (SUCCEEDED(hres) && (dwCmd & DISFFC_RESET)) {
  967. /*
  968. * Re-establish the gain after a reset.
  969. */
  970. CDIDev_RefreshGain(this);
  971. }
  972. CDIDev_LeaveCrit(this);
  973. }
  974. }
  975. ExitOleProc();
  976. return hres;
  977. }
  978. /*****************************************************************************
  979. *
  980. * @doc EXTERNAL
  981. *
  982. * @method HRESULT | IDirectInputDevice8 | EnumCreatedEffectObjects |
  983. *
  984. * Enumerates all of the currently created effect objects for
  985. * this device. Effect objects created via
  986. * <mf IDirectInputDevice::CreateEffect>
  987. * are enumerated.
  988. *
  989. * Note that results will be unpredictable if you destroy
  990. * or create an effect object while an enumeration is in progress.
  991. * The sole exception is that the callback function itself
  992. * <f DIEnumCreatedEffectObjectsProc> is permitted to
  993. * <mf IDirectInputEffect::Release> the effect that it is
  994. * passed as its first parameter.
  995. *
  996. * @cwrap LPDIRECTINPUTDEVICE | lpDirectInputDevice
  997. *
  998. * @parm IN LPDIENUMCREATEDEFFECTOBJECTSCALLBACK | lpCallback |
  999. *
  1000. * Callback function.
  1001. *
  1002. * @parm IN LPVOID | pvRef |
  1003. *
  1004. * Reference data (context) for callback.
  1005. *
  1006. * @parm IN DWORD | fl |
  1007. *
  1008. * No flags are currently defined. This parameter must be 0.
  1009. *
  1010. * @returns
  1011. *
  1012. * Returns a COM error code. The following error codes are
  1013. * intended to be illustrative and not necessarily comprehensive.
  1014. *
  1015. * Returns a COM error code. The following error codes are
  1016. * intended to be illustrative and not necessarily comprehensive.
  1017. *
  1018. * <c DI_OK> = <c S_OK>: The operation completed successfully.
  1019. * Note that if the callback stops the enumeration prematurely,
  1020. * the enumeration is considered to have succeeded.
  1021. *
  1022. * <c DIERR_INVALIDPARAM> = <c E_INVALIDARG>: The
  1023. * <p fl> parameter contains invalid flags, or the callback
  1024. * procedure returned an invalid status code.
  1025. *
  1026. * @cb BOOL CALLBACK | DIEnumCreatedEffectObjectsProc |
  1027. *
  1028. * An application-defined callback function that receives
  1029. * IDirectInputEffect effect objects as a result of a call to the
  1030. * <om IDirectInputDevice8::EnumCreatedEffects> method.
  1031. *
  1032. * @parm LPDIRECTINPUTEFFECT | peff |
  1033. *
  1034. * A pointer to an effect object that has been created.
  1035. *
  1036. * @parm LPVOID | pvRef |
  1037. * Specifies the application-defined value given in the
  1038. * <mf IDirectInputDevice8::EnumCreatedEffectObjects> function.
  1039. *
  1040. * @returns
  1041. *
  1042. * Returns <c DIENUM_CONTINUE> to continue the enumeration
  1043. * or <c DIENUM_STOP> to stop the enumeration.
  1044. *
  1045. *****************************************************************************/
  1046. STDMETHODIMP
  1047. CDIDev_EnumCreatedEffectObjects(PV pdd,
  1048. LPDIENUMCREATEDEFFECTOBJECTSCALLBACK pec,
  1049. LPVOID pvRef, DWORD fl _THAT)
  1050. {
  1051. HRESULT hres;
  1052. EnterProcR(IDirectInputDevice8::EnumCreatedEffects,
  1053. (_ "ppx", pdd, pec, fl));
  1054. if (SUCCEEDED(hres = hresPvT(pdd)) &&
  1055. SUCCEEDED(hres = hresFullValidPfn(pec, 1)) &&
  1056. SUCCEEDED(hres = hresFullValidFl(fl, DIECEFL_VALID, 3))) {
  1057. PDD this = _thisPv(pdd);
  1058. GPA gpaEff;
  1059. CDIDev_EnterCrit(this);
  1060. /*
  1061. * We must snapshot the list to make sure we don't run
  1062. * with a stale handle later. Actually, we also need
  1063. * to Hold the guys as we transfer them across so they
  1064. * won't vanish until we're ready.
  1065. *
  1066. * Note: It is important that we Hold and not AddRef,
  1067. * because AddRef will talk to the controlling unknown,
  1068. * which is not safe to do while holding a critical
  1069. * section.
  1070. */
  1071. hres = GPA_Clone(&gpaEff, &this->gpaEff);
  1072. if (SUCCEEDED(hres)) {
  1073. int ipv;
  1074. for (ipv = 0; ipv < gpaEff.cpv; ipv++) {
  1075. Common_Hold(gpaEff.rgpv[ipv]);
  1076. }
  1077. }
  1078. CDIDev_LeaveCrit(this);
  1079. if (SUCCEEDED(hres)) {
  1080. int ipv;
  1081. for (ipv = 0; ipv < gpaEff.cpv; ipv++) {
  1082. BOOL fRc;
  1083. fRc = Callback(pec, gpaEff.rgpv[ipv], pvRef);
  1084. switch (fRc) {
  1085. case DIENUM_STOP: goto enumdoneok;
  1086. case DIENUM_CONTINUE: break;
  1087. default:
  1088. RPF("%s: Invalid return value from callback", s_szProc);
  1089. ValidationException();
  1090. break;
  1091. }
  1092. }
  1093. enumdoneok:;
  1094. for (ipv = 0; ipv < gpaEff.cpv; ipv++) {
  1095. Common_Unhold(gpaEff.rgpv[ipv]);
  1096. }
  1097. GPA_Term(&gpaEff);
  1098. }
  1099. hres = S_OK;
  1100. }
  1101. ExitOleProc();
  1102. return hres;
  1103. }
  1104. /*****************************************************************************
  1105. *
  1106. * @doc INTERNAL
  1107. *
  1108. * @method HRESULT | CDIDev | GetLoad |
  1109. *
  1110. * Retrieve the memory load setting for the device.
  1111. *
  1112. * @cwrap PDD | this
  1113. *
  1114. * @parm LPDWORD | pdwLoad |
  1115. *
  1116. * Receives memory load.
  1117. *
  1118. * @returns
  1119. *
  1120. * Returns a COM error code. The following error codes are
  1121. * intended to be illustrative and not necessarily comprehensive.
  1122. *
  1123. * <c DI_OK> = <c S_OK>: The operation completed successfully.
  1124. *
  1125. * <c DIERR_NOTEXCLUSIVEACQUIRED>: The device is acquired,
  1126. * but not exclusively, or the device is not acquired
  1127. * at all.
  1128. *
  1129. * <c DIERR_UNSUPPORTED> = <c E_NOTIMPL>: The device
  1130. * does not support force feedback.
  1131. *
  1132. *****************************************************************************/
  1133. STDMETHODIMP
  1134. CDIDev_GetLoad(PDD this, LPDWORD pdwOut)
  1135. {
  1136. HRESULT hres;
  1137. EnterProc(CDIDev_GetLoad, (_ "p", this));
  1138. hres = CDIDev_CreateEffectDriver(this);
  1139. if (SUCCEEDED(hres)) {
  1140. DIDEVICESTATE ds;
  1141. CDIDev_EnterCrit(this);
  1142. /*
  1143. * Note that it isn't necessary to check
  1144. * CDIDev_IsExclAcquired(), because the effect shepherd
  1145. * will deny us access to a device we don't own.
  1146. *
  1147. * ISSUE-2001/03/29-timgill Need to handle DIERR_INPUTLOST case
  1148. */
  1149. ds.dwSize = cbX(ds);
  1150. /*
  1151. * Prefix raises a warning (mb:34564) that this->pes could
  1152. * be NULL however CDIDev_CreateEffectDriver only succeeds
  1153. * if it is not.
  1154. */
  1155. hres = this->pes->lpVtbl->
  1156. GetForceFeedbackState(this->pes, &this->sh, &ds);
  1157. *pdwOut = ds.dwLoad;
  1158. CDIDev_LeaveCrit(this);
  1159. }
  1160. /*
  1161. * Can't use ExitOleProcPpv here because pdwOut is garbage on error.
  1162. */
  1163. ExitOleProc();
  1164. return hres;
  1165. }
  1166. /*****************************************************************************
  1167. *
  1168. * @doc INTERNAL
  1169. *
  1170. * @method HRESULT | CDIDev | Escape |
  1171. *
  1172. * Send a hardware-specific command to the driver.
  1173. *
  1174. * @cwrap PDD | this
  1175. *
  1176. * @parm LPDIEFFESCAPE | pesc |
  1177. *
  1178. * Pointer to a <t DIEFFESCAPE> structure which describes
  1179. * the command to be sent. On success, the
  1180. * <e DIEFFESCAPE.cbOutBuffer> field contains the number
  1181. * of bytes of the output buffer actually used.
  1182. *
  1183. * @returns
  1184. *
  1185. * Returns a COM error code. The following error codes are
  1186. * intended to be illustrative and not necessarily comprehensive.
  1187. *
  1188. * <c DI_OK> = <c S_OK>: The operation completed successfully.
  1189. *
  1190. * <c DIERR_NOTEXCLUSIVEACQUIRED>: The device is acquired,
  1191. * but not exclusively, or the device is not acquired
  1192. * at all.
  1193. *
  1194. * <c DIERR_UNSUPPORTED> = <c E_NOTIMPL>: The device
  1195. * does not support force feedback.
  1196. *
  1197. *****************************************************************************/
  1198. STDMETHODIMP
  1199. CDIDev_Escape(PV pdd, LPDIEFFESCAPE pesc _THAT)
  1200. {
  1201. HRESULT hres;
  1202. EnterProcR(IDirectInputDevice8::Escape, (_ "p", pdd));
  1203. if (SUCCEEDED(hres = hresPvT(pdd)) &&
  1204. SUCCEEDED(hres = hresFullValidPesc(pesc, 1))) {
  1205. PDD this = _thisPv(pdd);
  1206. AssertF(this->sh.dwEffect == 0);
  1207. hres = CDIDev_CreateEffectDriver(this);
  1208. if (SUCCEEDED(hres)) {
  1209. CDIDev_EnterCrit(this);
  1210. /*
  1211. * Note that it isn't necessary to check
  1212. * CDIDev_IsExclAcquired(), because the effect shepherd
  1213. * will deny us access to a device we don't own.
  1214. *
  1215. * ISSUE-2001/03/29-timgill Need to handle DIERR_INPUTLOST case
  1216. */
  1217. /*
  1218. * Prefix raises a warning (mb:34564) that this->pes could
  1219. * be NULL however CDIDev_CreateEffectDriver only succeeds
  1220. * if it is not.
  1221. */
  1222. hres = IDirectInputEffectShepherd_DeviceEscape(
  1223. this->pes, &this->sh, pesc);
  1224. CDIDev_LeaveCrit(this);
  1225. }
  1226. }
  1227. ExitOleProcR();
  1228. return hres;
  1229. }
  1230. /*****************************************************************************
  1231. *
  1232. * @doc INTERNAL
  1233. *
  1234. * @method HRESULT | CDIDev | RefreshGain |
  1235. *
  1236. * Set the device gain setting appropriately.
  1237. *
  1238. * The device shepherd will take care of muxing in the
  1239. * global gain.
  1240. *
  1241. * @cwrap PDD | this
  1242. *
  1243. * @returns
  1244. *
  1245. * Returns a COM error code. The following error codes are
  1246. * intended to be illustrative and not necessarily comprehensive.
  1247. *
  1248. * <c DI_OK> = <c S_OK>: The operation completed successfully.
  1249. *
  1250. * <c DIERR_NOTEXCLUSIVEACQUIRED>: The device is acquired,
  1251. * but not exclusively, or the device is not acquired
  1252. * at all.
  1253. *
  1254. * <c DIERR_UNSUPPORTED> = <c E_NOTIMPL>: The device
  1255. * does not support force feedback.
  1256. *
  1257. *****************************************************************************/
  1258. STDMETHODIMP
  1259. CDIDev_RefreshGain(PDD this)
  1260. {
  1261. HRESULT hres;
  1262. AssertF(CDIDev_InCrit(this));
  1263. if (this->pes) {
  1264. hres = this->pes->lpVtbl->SetGain(this->pes, &this->sh, this->dwGain);
  1265. } else {
  1266. hres = S_OK;
  1267. }
  1268. return hres;
  1269. }
  1270. /*****************************************************************************
  1271. *
  1272. * @doc INTERNAL
  1273. *
  1274. * @method void | CDIDev | SnapOneEffect |
  1275. *
  1276. * Read one force feedback effect key and record the
  1277. * information stored therein. We also tally the
  1278. * flag into the <e CDIDev.didcFF> so we can return
  1279. * the global flags from <mf IDirectInputDevice::GetCapabilities>.
  1280. *
  1281. * The <e CDIDev.rgemi> field already points to a
  1282. * preallocated array
  1283. * of <t EFFECTMAPINFO> structures, and
  1284. * the <e CDIDev.cemi> field contains the number
  1285. * of entries in that array which are already in use.
  1286. *
  1287. * @cwrap PDD | this
  1288. *
  1289. * @parm HKEY | hkEffects |
  1290. *
  1291. * The registry key containing the effects.
  1292. *
  1293. * @parm DWORD | iKey |
  1294. *
  1295. * Index number of the subkey.
  1296. *
  1297. * @returns
  1298. *
  1299. * None.
  1300. *
  1301. * If the specified subkey is damaged, it is skipped.
  1302. *
  1303. *****************************************************************************/
  1304. void INTERNAL
  1305. CDIDev_SnapOneEffect(PDD this, HKEY hkEffects, DWORD ihk)
  1306. {
  1307. TCHAR tszGuid[ctchGuid];
  1308. LONG lRc;
  1309. PEFFECTMAPINFO pemi;
  1310. /*
  1311. * Make sure that DIEFT_* and DIDC_* agree where they overlap.
  1312. */
  1313. CAssertF(DIEFT_FORCEFEEDBACK == DIDC_FORCEFEEDBACK);
  1314. CAssertF(DIEFT_FFATTACK == DIDC_FFATTACK);
  1315. CAssertF(DIEFT_FFFADE == DIDC_FFFADE);
  1316. CAssertF(DIEFT_SATURATION == DIDC_SATURATION);
  1317. CAssertF(DIEFT_POSNEGCOEFFICIENTS == DIDC_POSNEGCOEFFICIENTS);
  1318. CAssertF(DIEFT_POSNEGSATURATION == DIDC_POSNEGSATURATION);
  1319. pemi = &this->rgemi[this->cemi];
  1320. /*
  1321. * First get the GUID for the effect.
  1322. */
  1323. lRc = RegEnumKey(hkEffects, ihk, tszGuid, cA(tszGuid));
  1324. if (lRc == ERROR_SUCCESS &&
  1325. ParseGUID(&pemi->guid, tszGuid)) {
  1326. HKEY hk;
  1327. /*
  1328. * Note that we don't need to check for duplicates.
  1329. * The registry itself does not allow two keys to have
  1330. * the same name.
  1331. */
  1332. lRc = RegOpenKeyEx(hkEffects, tszGuid, 0, KEY_QUERY_VALUE, &hk);
  1333. if (lRc == ERROR_SUCCESS) {
  1334. DWORD cb;
  1335. cb = cbX(pemi->wszName);
  1336. lRc = RegQueryStringValueW(hk, 0, pemi->wszName, &cb);
  1337. if (lRc == ERROR_SUCCESS) {
  1338. HRESULT hres;
  1339. hres = JoyReg_GetValue(hk, TEXT("Attributes"), REG_BINARY,
  1340. &pemi->attr, cbX(pemi->attr));
  1341. if (SUCCEEDED(hres) &&
  1342. (pemi->attr.dwCoords & DIEFF_COORDMASK)) {
  1343. this->didcFF |= (pemi->attr.dwEffType & DIEFT_VALIDFLAGS);
  1344. this->cemi++;
  1345. }
  1346. }
  1347. RegCloseKey(hk);
  1348. }
  1349. }
  1350. }
  1351. /*****************************************************************************
  1352. *
  1353. * @doc INTERNAL
  1354. *
  1355. * @method HRESULT | CDIDev | InitFF |
  1356. *
  1357. * Initialize the force-feedback portion of the device.
  1358. *
  1359. * Collect the force feedback attributes.
  1360. *
  1361. * Snapshot the list of force feedback effects.
  1362. *
  1363. * @cwrap LPDIRECTINPUTDEVICE | lpDirectInputDevice
  1364. *
  1365. * @returns
  1366. *
  1367. * Returns a COM error code. The following error codes are
  1368. * intended to be illustrative and not necessarily comprehensive.
  1369. *
  1370. * <c DI_OK> = <c S_OK>: The operation completed successfully.
  1371. *
  1372. * <c DIERR_OUTOFMEMORY> = <c E_OUTOFMEMORY>: Out of memory.
  1373. *
  1374. * <c DIERR_UNSUPPORTED> = <c E_NOTIMPL>: The device
  1375. * does not support force feedback.
  1376. *
  1377. *****************************************************************************/
  1378. STDMETHODIMP
  1379. CDIDev_InitFF(PDD this)
  1380. {
  1381. HKEY hkFF;
  1382. HRESULT hres;
  1383. EnterProcI(CDIDev_InitFF, (_ "p", this));
  1384. AssertF(this->didcFF == 0);
  1385. hres = this->pdcb->lpVtbl->GetFFConfigKey(this->pdcb,
  1386. KEY_QUERY_VALUE | KEY_ENUMERATE_SUB_KEYS,
  1387. &hkFF);
  1388. if( hres == S_FALSE )
  1389. {
  1390. /*
  1391. * Try causing the driver to be loaded so that it can initialize
  1392. * the effects in the registry before we proceed.
  1393. *
  1394. * Need to exercise caution here. A driver that expects to use this
  1395. * functionality cannot call into Dinput query for device attributes.
  1396. * Can result in endless loop where we call the driver and the driver
  1397. * calls us back
  1398. */
  1399. hres = CDIDev_CreateEffectDriver(this);
  1400. if( SUCCEEDED( hres ) )
  1401. {
  1402. hres = this->pdcb->lpVtbl->GetFFConfigKey(this->pdcb,
  1403. KEY_QUERY_VALUE | KEY_ENUMERATE_SUB_KEYS,
  1404. &hkFF);
  1405. if( hres == S_FALSE )
  1406. {
  1407. hres = E_FAIL;
  1408. }
  1409. }
  1410. }
  1411. if (SUCCEEDED(hres)) {
  1412. DWORD chk;
  1413. HKEY hkEffects;
  1414. LONG lRc;
  1415. AssertF( hkFF );
  1416. lRc = JoyReg_GetValue(hkFF, TEXT("Attributes"),
  1417. REG_BINARY, &this->ffattr, cbX(this->ffattr));
  1418. if (lRc != S_OK) {
  1419. ZeroX(this->ffattr);
  1420. }
  1421. lRc = RegOpenKeyEx(hkFF, TEXT("Effects"), 0,
  1422. KEY_QUERY_VALUE | KEY_ENUMERATE_SUB_KEYS,
  1423. &hkEffects);
  1424. if (lRc == ERROR_SUCCESS) {
  1425. lRc = RegQueryInfoKey(hkEffects, 0, 0, 0, &chk,
  1426. 0, 0, 0, 0, 0, 0, 0);
  1427. if (lRc == ERROR_SUCCESS) {
  1428. hres = AllocCbPpv(cbCxX(chk, EFFECTMAPINFO),
  1429. &this->rgemi);
  1430. if (SUCCEEDED(hres)) {
  1431. DWORD ihk;
  1432. this->cemi = 0;
  1433. for (ihk = 0; ihk < chk; ihk++) {
  1434. CDIDev_SnapOneEffect(this, hkEffects, ihk);
  1435. }
  1436. this->didcFF &= DIDC_FFFLAGS;
  1437. /*
  1438. * Note that we mark DIDC_FORCEFEEDBACK only if
  1439. * we actually find any effects.
  1440. */
  1441. if (this->cemi) {
  1442. this->didcFF |= DIDC_FORCEFEEDBACK;
  1443. }
  1444. hres = S_OK;
  1445. } else {
  1446. RPF("Warning: Insufficient memory for force feedback");
  1447. }
  1448. } else {
  1449. hres = E_FAIL;
  1450. }
  1451. RegCloseKey(hkEffects);
  1452. } else {
  1453. hres = E_NOTIMPL;
  1454. }
  1455. RegCloseKey(hkFF);
  1456. }
  1457. ExitBenignOleProc();
  1458. return hres;
  1459. }