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

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