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.

4814 lines
145 KiB

  1. /*****************************************************************************
  2. *
  3. * DIEff.c
  4. *
  5. * Copyright (c) 1996 Microsoft Corporation. All Rights Reserved.
  6. *
  7. * Abstract:
  8. *
  9. * The standard implementation of IDirectInputEffect.
  10. *
  11. * This is the device-independent part. the device-dependent
  12. * part is handled by the IDirectInputEffectShepherd.
  13. *
  14. * Contents:
  15. *
  16. * CDIEff_CreateInstance
  17. *
  18. *****************************************************************************/
  19. #include "dinputpr.h"
  20. #ifdef IDirectInputDevice2Vtbl
  21. /*****************************************************************************
  22. *
  23. * Note!
  24. *
  25. * Out of laziness, all effects share the same critical section as
  26. * their parent device. This saves us from all sorts of race
  27. * conditions. Not all of them, but a big chunk of them.
  28. *
  29. * A common race condition that this protects us against is
  30. * where an application tries to download an effect at the same
  31. * time another thread decides to unacquire the device.
  32. *
  33. *****************************************************************************/
  34. /*****************************************************************************
  35. *
  36. * More laziness: "TypeSpecificParams" is such a long thing.
  37. *
  38. *****************************************************************************/
  39. #define cbTSP cbTypeSpecificParams
  40. #define lpvTSP lpvTypeSpecificParams
  41. /*****************************************************************************
  42. *
  43. * The sqiffle for this file.
  44. *
  45. *****************************************************************************/
  46. #define sqfl sqflEff
  47. /*****************************************************************************
  48. *
  49. * The flags for dwMessage
  50. *
  51. *****************************************************************************/
  52. #define EFF_DEFAULT 0
  53. #define EFF_PLAY 1
  54. #define EFF_STOP 2
  55. /*****************************************************************************
  56. *
  57. * Declare the interfaces we will be providing.
  58. *
  59. *****************************************************************************/
  60. Primary_Interface(CDIEff, IDirectInputEffect);
  61. Interface_Template_Begin(CDIEff)
  62. Primary_Interface_Template(CDIEff, IDirectInputEffect)
  63. Interface_Template_End(CDIEff)
  64. /*****************************************************************************
  65. *
  66. * @doc INTERNAL
  67. *
  68. * @struct CDIEff |
  69. *
  70. * The generic <i IDirectInputEffect> object.
  71. *
  72. * @field IDirectInputEffect | def |
  73. *
  74. * <i DirectInputEffect> object (containing vtbl).
  75. *
  76. * @field struct CDIDev * | pdev |
  77. *
  78. * Reference to parent device tracked via <f Common_Hold>.
  79. *
  80. * @field DICREATEEFFECTINFO | cei |
  81. *
  82. * Parameters that tell us how to talk to the effect driver.
  83. *
  84. * @field BOOL | fInitialized:1 |
  85. *
  86. * Do we know who we are?
  87. *
  88. * @field BOOL | fDadNotified:1 |
  89. *
  90. * Does our parent know that we exist?
  91. *
  92. * @field BOOL | fDadDead:1 |
  93. *
  94. * Has our parent been destroyed (from the app's point of view)?
  95. *
  96. * @field TSDPROC | hresValidTsd |
  97. *
  98. * Callback function that validates the type-specific data.
  99. *
  100. * @field DIEFFECTATTRIBUTES | dEffAttributes |
  101. *
  102. * Attributes of the effect (includes dwEffectType and dwEffectId, among others).
  103. *
  104. * @field HANDLE | hEventDelete |
  105. *
  106. * Event to signal to the timer thread that the app performed final release on the effect.
  107. *
  108. * @field HANDLE | hEventThreadDead |
  109. *
  110. * Event to signal AppFinalize to perform the final release on the effect.
  111. *
  112. * @field HANDLE | hEventGeneral |
  113. *
  114. * Event to signal to the timer thread that the app called Start(...) or Stop() the effect.
  115. *
  116. * @field DWORD | dwMessage |
  117. *
  118. * Message to the thread as to which event hEventGeneral is actually signaling.
  119. * Can be EFF_DEFAULT, EFF_PLAY or EFF_STOP>
  120. *
  121. * @field DWORD | dwcLoop|
  122. *
  123. * Loop count for playing the effect (passed in the call to Start(...))
  124. *
  125. * @field DWORD | dwFlags |
  126. *
  127. * Flags for playing the effect (passed in the call to Start(...))
  128. *
  129. * @field DWORD | diepDirty |
  130. *
  131. * The parts of the effect which are "dirty" and need to
  132. * be updated by the next <mf IDirectInputEffect::Download>.
  133. *
  134. * @field DWORD | diepUnset |
  135. *
  136. * The parts of the effect which have yet to be set by the
  137. * application. Items which we can set decent defaults for
  138. * are not counted.
  139. *
  140. * @field DWORD | dwDirFlags |
  141. *
  142. * Flags that record the direction format the application
  143. * last set.
  144. *
  145. * @field DWORD | dwCoords |
  146. *
  147. * Coordinate systems supported by device.
  148. *
  149. * @field LPVOID | lpvTSP |
  150. *
  151. * Temporary buffer used to cache type-specific parameters
  152. * during Try'ing of proposed effect parameters.
  153. *
  154. * @field SHEPHANDLE | sh |
  155. *
  156. * Effect handle information.
  157. *
  158. * @field DIEFFECT | eff |
  159. *
  160. * Cached effect parameters as they exist (or should exist)
  161. * on the device.
  162. * Direction parameters are in device-preferred coordinates.
  163. *
  164. * @field DIENVELOPE | env |
  165. *
  166. * Cached envelope parameters as they exist (or should exist)
  167. * on the device.
  168. *
  169. * @field LONG | rglDirApp[DIEFFECT_MAXAXES] |
  170. *
  171. * Cached direction list, in application native format.
  172. * The format of this array is kept in the
  173. * <e CDIEff.dwDirFlags> field.
  174. *
  175. * @field DWORD | rgdwAxes[DIEFFECT_MAXAXES] |
  176. *
  177. * Cached axis list, stored as item numbers.
  178. *
  179. * @field LONG | rglDirDev[DIEFFECT_MAXAXES] |
  180. *
  181. * Cached direction list, in device native format.
  182. * The format of this array is kept in the
  183. * <e DIEFFECT.dwFlags> field of the
  184. * <e CDIEff.eff>.
  185. *
  186. * @field GUID | guid |
  187. *
  188. * Identity.
  189. *
  190. *****************************************************************************/
  191. typedef STDMETHOD(TSDPROC)(LPCDIEFFECT peff, DWORD cAxes);
  192. typedef struct CDIEff {
  193. /* Supported interfaces */
  194. IDirectInputEffect def;
  195. struct CDIDev *pdev;
  196. LPDIRECTINPUTEFFECTSHEPHERD pes;
  197. BOOL fDadNotified:1;
  198. BOOL fDadDead:1;
  199. BOOL fInitialized:1;
  200. TSDPROC hresValidTsd;
  201. /* WARNING! EVERYTHING AFTER THIS LINE IS ZERO'd ON A RESET */
  202. DIEFFECTATTRIBUTES dEffAttributes;
  203. HANDLE hEventDelete;
  204. HANDLE hEventGeneral;
  205. HANDLE hEventThreadDead;
  206. DWORD dwMessage;
  207. DWORD dwcLoop;
  208. DWORD dwFlags;
  209. DWORD diepDirty;
  210. DWORD diepUnset;
  211. DWORD dwDirFlags;
  212. DWORD dwCoords;
  213. LPVOID lpvTSP;
  214. SHEPHANDLE sh;
  215. DIEFFECT effDev;
  216. DIEFFECT effTry;
  217. DIENVELOPE env;
  218. GUID guid;
  219. LONG rglDirApp[DIEFFECT_MAXAXES];
  220. DWORD rgdwAxes[DIEFFECT_MAXAXES];
  221. LONG rglDirDev[DIEFFECT_MAXAXES];
  222. LONG rglDirTry[DIEFFECT_MAXAXES];
  223. /* WARNING! EVERYTHING ABOVE THIS LINE IS ZERO'd ON A RESET */
  224. /*
  225. * The Reset() function assumes that the entire remainder
  226. * of the structure is to be zero'd out, so if you add a field
  227. * here, make sure to adjust Reset() accordingly.
  228. */
  229. } CDIEff, DE, *PDE;
  230. #define ThisClass CDIEff
  231. #define ThisInterface IDirectInputEffect
  232. /*****************************************************************************
  233. *
  234. * Forward declarations
  235. *
  236. * These are out of laziness, not out of necessity.
  237. *
  238. *****************************************************************************/
  239. STDMETHODIMP CDIEff_IsValidUnknownTsd(LPCDIEFFECT peff, DWORD cAxes);
  240. /*****************************************************************************
  241. *
  242. * @doc EXTERNAL
  243. *
  244. * @method HRESULT | IDirectInputEffect | QueryInterface |
  245. *
  246. * Gives a client access to other interfaces on an object.
  247. *
  248. * @cwrap LPDIRECTINPUTEFFECT | lpDirectInputEffect
  249. *
  250. * @parm IN REFIID | riid |
  251. *
  252. * The requested interface's IID.
  253. *
  254. * @parm OUT LPVOID * | ppvObj |
  255. *
  256. * Receives a pointer to the obtained interface.
  257. *
  258. * @returns
  259. *
  260. * Returns a COM error code.
  261. *
  262. * @xref OLE documentation for <mf IUnknown::QueryInterface>.
  263. *
  264. *****************************************************************************
  265. *
  266. * @doc EXTERNAL
  267. *
  268. * @method HRESULT | IDirectInputEffect | AddRef |
  269. *
  270. * Increments the reference count for the interface.
  271. *
  272. * @cwrap LPDIRECTINPUTEFFECT | lpDirectInputEffect
  273. *
  274. * @returns
  275. *
  276. * Returns the object reference count.
  277. *
  278. * @xref OLE documentation for <mf IUnknown::AddRef>.
  279. *
  280. *****************************************************************************
  281. *
  282. * @doc EXTERNAL
  283. *
  284. * @method HRESULT | IDirectInputEffect | Release |
  285. *
  286. * Decrements the reference count for the interface.
  287. * If the reference count on the object falls to zero,
  288. * the object is freed from memory.
  289. *
  290. * @cwrap LPDIRECTINPUTEFFECT | lpDirectInputEffect
  291. *
  292. * @returns
  293. *
  294. * Returns the object reference count.
  295. *
  296. * @xref OLE documentation for <mf IUnknown::Release>.
  297. *
  298. *****************************************************************************/
  299. #ifdef DEBUG
  300. Default_QueryInterface(CDIEff)
  301. Default_AddRef(CDIEff)
  302. Default_Release(CDIEff)
  303. #else
  304. #define CDIEff_QueryInterface Common_QueryInterface
  305. #define CDIEff_AddRef Common_AddRef
  306. #define CDIEff_Release Common_Release
  307. #endif
  308. #define CDIEff_QIHelper Common_QIHelper
  309. /*****************************************************************************
  310. *
  311. * @doc INTERNAL
  312. *
  313. * @method void | CDIEff | EnterCrit |
  314. *
  315. * Enter the object critical section.
  316. *
  317. * @cwrap PDE | this
  318. *
  319. *****************************************************************************/
  320. void INLINE
  321. CDIEff_EnterCrit(PDE this)
  322. {
  323. AssertF(this->pdev);
  324. CDIDev_EnterCrit(this->pdev);
  325. }
  326. /*****************************************************************************
  327. *
  328. * @doc INTERNAL
  329. *
  330. * @method void | CDIEff | LeaveCrit |
  331. *
  332. * Leave the object critical section.
  333. *
  334. * @cwrap PDE | this
  335. *
  336. *****************************************************************************/
  337. void INLINE
  338. CDIEff_LeaveCrit(PDE this)
  339. {
  340. AssertF(this->pdev);
  341. CDIDev_LeaveCrit(this->pdev);
  342. }
  343. /*****************************************************************************
  344. *
  345. * @doc INTERNAL
  346. *
  347. * @method void | CDIEff | CanAccess |
  348. *
  349. * Check if the effect can be accessed. For this to succeeed,
  350. * the effect must be initialized, and the parent device
  351. * must be acquired in exclusive mode.
  352. *
  353. * @cwrap PDE | this
  354. *
  355. * @returns
  356. *
  357. * <c S_OK> if the device is exclusively acquired.
  358. *
  359. * <c DIERR_INPUTLOST> if acquisition has been lost.
  360. *
  361. * <c DIERR_NOTEXCLUSIVEACQUIRED> the device is acquired,
  362. * but not exclusively, or if the device is not acquired
  363. * at all.
  364. *
  365. * <c DIERR_NOTINITIALIZED> if the effect object has not
  366. * yet been initialized.
  367. *
  368. *****************************************************************************/
  369. #ifndef XDEBUG
  370. #define CDIEff_CanAccess_(this, z) \
  371. _CDIEff_CanAccess_(this) \
  372. #endif
  373. STDMETHODIMP
  374. CDIEff_CanAccess_(PDE this, LPCSTR s_szProc)
  375. {
  376. HRESULT hres;
  377. AssertF(this->pdev);
  378. AssertF(CDIDev_InCrit(this->pdev));
  379. if (this->fInitialized) {
  380. hres = CDIDev_IsExclAcquired(this->pdev);
  381. } else {
  382. if (s_szProc) {
  383. RPF("ERROR %s: Effect not initialized", s_szProc);
  384. }
  385. hres = DIERR_NOTINITIALIZED;
  386. }
  387. return hres;
  388. }
  389. #define CDIEff_CanAccess(this) \
  390. CDIEff_CanAccess_(this, s_szProc) \
  391. /*****************************************************************************
  392. *
  393. * @doc INTERNAL
  394. *
  395. * @func HRESULT | CDIEff_Reset |
  396. *
  397. * Releases all the resources of a generic effect that
  398. * are associated with a particular device effect instance.
  399. *
  400. * This method is called in preparation for reinitialization.
  401. *
  402. * @parm PV | pvObj |
  403. *
  404. * Object being reset. Note that it may not have been
  405. * completely initialized, so everything should be done
  406. * carefully.
  407. *
  408. *****************************************************************************/
  409. STDMETHODIMP
  410. CDIEff_Reset(PDE this)
  411. {
  412. HRESULT hres;
  413. AssertF(this->pdev);
  414. CDIEff_EnterCrit(this);
  415. /*
  416. * Destroying an effect implicitly stops it.
  417. *
  418. * It's okay if this fails (and in fact it usually will).
  419. * We're just playing it safe.
  420. */
  421. hres = IDirectInputEffectShepherd_DestroyEffect(this->pes, &this->sh);
  422. AssertF(this->lpvTSP == 0);
  423. FreePpv(&this->effDev.lpvTSP);
  424. //rezero the entire DIEFFECTATTRIBUTES!
  425. ZeroBuf(&this->dEffAttributes,
  426. cbX(DE) -
  427. FIELD_OFFSET(DE, dEffAttributes));
  428. //rezero effect's event handles
  429. if (this->hEventDelete != NULL)
  430. {
  431. CloseHandle(this->hEventDelete);
  432. this->hEventDelete = NULL;
  433. }
  434. if (this->hEventGeneral != NULL)
  435. {
  436. CloseHandle(this->hEventGeneral);
  437. this->hEventGeneral = NULL;
  438. }
  439. if (this->hEventThreadDead != NULL)
  440. {
  441. CloseHandle(this->hEventThreadDead);
  442. this->hEventThreadDead = NULL;
  443. }
  444. this->dwMessage = EFF_DEFAULT;
  445. this->effDev.dwSize = cbX(this->effDev);
  446. this->env.dwSize = cbX(this->env);
  447. /*
  448. * DIEP_DURATION - Defaults to zero.
  449. * DIEP_SAMPLEPERIOD - Defaults to zero.
  450. * DIEP_GAIN - Defaults to zero.
  451. * DIEP_TRIGGERBUTTON - Defaults to DIEB_NOTRIGGER.
  452. * DIEP_TRIGGERREPEATINTERVAL - Defaults to INFINITE (no autorepeat).
  453. * DIEP_AXES - Must be set manually.
  454. * DIEP_DIRECTION - Must be set manually.
  455. * DIEP_ENVELOPE - No envelope.
  456. * DIEP_TYPESPECIFICPARAMS - Must be set manually.
  457. #if DIRECTINPUT_VERSION >= 0x0600
  458. * DIEP_STARTDELAY - Defaults to zero.
  459. #endif
  460. */
  461. this->effDev.dwTriggerButton = DIEB_NOTRIGGER;
  462. this->diepUnset = DIEP_AXES |
  463. DIEP_DIRECTION |
  464. DIEP_TYPESPECIFICPARAMS;
  465. this->effDev.rgdwAxes = this->rgdwAxes;
  466. this->effDev.rglDirection = this->rglDirDev;
  467. this->fInitialized = 0;
  468. CDIEff_LeaveCrit(this);
  469. hres = S_OK;
  470. return hres;
  471. }
  472. /*****************************************************************************
  473. *
  474. * @doc INTERNAL
  475. *
  476. * @method HRESULT | CDIEff | UnloadWorker |
  477. *
  478. * Remove the effect from the device. All parameters have
  479. * been validated.
  480. *
  481. * @cwrap PDE | this
  482. *
  483. * @returns
  484. *
  485. * Returns a COM error code. The following error codes are
  486. * intended to be illustrative and not necessarily comprehensive.
  487. *
  488. * <c DI_OK> = <c S_OK>: The operation completed successfully.
  489. *
  490. * <c S_FALSE>: The effect was not previously downloaded,
  491. * so there was nothing to unload. Note that this is a
  492. * success code.
  493. *
  494. * <c DI_PROPNOEFFECT> = <c S_FALSE>: The effect was not
  495. * previously downloaded.
  496. *
  497. * <c DIERR_NOTINITIALIZED>: The <i IDirectInputEffect> object
  498. * has not yet been <mf IDirectInputEffect::Initialize>d.
  499. *
  500. * <c DIERR_INPUTLOST> if acquisition has been lost.
  501. *
  502. * <c DIERR_NOTEXCLUSIVEACQUIRED> the device is acquired,
  503. * but not exclusively, or if the device is not acquired
  504. * at all.
  505. *
  506. *****************************************************************************/
  507. #ifndef XDEBUG
  508. #define CDIEff_UnloadWorker_(this, z) \
  509. _CDIEff_UnloadWorker_(this) \
  510. #endif
  511. HRESULT INTERNAL
  512. CDIEff_UnloadWorker_(PDE this, LPCSTR s_szProc)
  513. {
  514. HRESULT hres;
  515. AssertF(CDIDev_InCrit(this->pdev));
  516. if (SUCCEEDED(hres = CDIEff_CanAccess(this))) {
  517. /*
  518. * The effect driver will stop the effect (if it is playing)
  519. * before destroying it.
  520. */
  521. hres = IDirectInputEffectShepherd_DestroyEffect(
  522. this->pes, &this->sh);
  523. } else {
  524. /*
  525. * The effect is dead. Long live the effect.
  526. */
  527. this->sh.dwEffect = 0;
  528. }
  529. this->diepDirty = DIEP_ALLPARAMS;
  530. return hres;
  531. }
  532. #define CDIEff_UnloadWorker(this) \
  533. CDIEff_UnloadWorker_(this, s_szProc) \
  534. /*****************************************************************************
  535. *
  536. * @doc INTERNAL
  537. *
  538. * @func void | CDIEff_AppFinalize |
  539. *
  540. * The application has performed its final release.
  541. *
  542. * Tell our parent that we are officially dead, so that
  543. * dad will stop tracking us and release its hold on us.
  544. *
  545. * @parm PV | pvObj |
  546. *
  547. * Object being released. Note that it may not have been
  548. * completely initialized, so everything should be done
  549. * carefully.
  550. *
  551. *****************************************************************************/
  552. void INTERNAL
  553. CDIEff_AppFinalize(PV pvObj)
  554. {
  555. PDE this = pvObj;
  556. DWORD dwRc = 0xFFFFFFFF;
  557. EnterProcR(CDIEff_AppFinalize, (_ "p", pvObj));
  558. if (this->fDadNotified) {
  559. this->fDadNotified = 0;
  560. CDIEff_EnterCrit(this);
  561. /*
  562. * Kill the timer thread, if any.
  563. * For this, fire off the effect's event.
  564. */
  565. if (this->hEventDelete != NULL) {
  566. if( SetEvent(this->hEventDelete) && this->hEventThreadDead != NULL )
  567. {
  568. do
  569. {
  570. dwRc = WaitForSingleObject(this->hEventThreadDead, INFINITE);
  571. } while( dwRc != WAIT_OBJECT_0 );
  572. CloseHandle(this->hEventThreadDead);
  573. this->hEventThreadDead = NULL;
  574. }
  575. }
  576. CDIEff_UnloadWorker_(this, 0);
  577. CDIEff_LeaveCrit(this);
  578. CDIDev_NotifyDestroyEffect(this->pdev, this);
  579. }
  580. ExitProcR();
  581. }
  582. /*****************************************************************************
  583. *
  584. * @doc INTERNAL
  585. *
  586. * @func void | CDIEff_Finalize |
  587. *
  588. * Releases the resources of an effect.
  589. *
  590. * @parm PV | pvObj |
  591. *
  592. * Object being released. Note that it may not have been
  593. * completely initialized, so everything should be done
  594. * carefully.
  595. *
  596. *****************************************************************************/
  597. void INTERNAL
  598. CDIEff_Finalize(PV pvObj)
  599. {
  600. HRESULT hres;
  601. PDE this = pvObj;
  602. #if 0 // def XDEBUG
  603. if (this->cCrit) {
  604. RPF("IDirectInputEffect::Release: Another thread is using the object; crash soon!");
  605. }
  606. #endif
  607. AssertF(this->sh.dwEffect == 0);
  608. if (this->pdev) {
  609. hres = CDIEff_Reset(this);
  610. AssertF(SUCCEEDED(hres));
  611. }
  612. Invoke_Release(&this->pes);
  613. Common_Unhold(this->pdev);
  614. }
  615. /*****************************************************************************
  616. *
  617. * @doc EXTERNAL
  618. *
  619. * @method HRESULT | IDirectInputEffect | GetEffectGuid |
  620. *
  621. * Retrieve the GUID for the effect represented by the
  622. * <i IDirectInputEffect> object. Additional information
  623. * about the effect can be obtained by passing the
  624. * <t GUID> to <mf IDirectInputDevice2::GetEffectInfo>.
  625. *
  626. * @cwrap LPDIRECTINPUTEFFECT | lpDirectInputEffect
  627. *
  628. * @parm OUT LPGUID | pguid |
  629. *
  630. * Points to a <t GUID> structure that is filled in
  631. * by the function.
  632. *
  633. * @returns
  634. *
  635. * Returns a COM error code. The following error codes are
  636. * intended to be illustrative and not necessarily comprehensive.
  637. *
  638. * <c DI_OK> = <c S_OK>: The operation completed successfully.
  639. *
  640. * <c DIERR_NOTINITIALIZED>: The <i IDirectInputEffect> object
  641. * has not yet been <mf IDirectInputEffect::Initialize>d.
  642. *
  643. * <c DIERR_INVALIDPARAM> = <c E_INVALIDARG>: The
  644. * <p lpDirectInputEffect> or
  645. * <p lpdc> parameter is invalid.
  646. *
  647. *****************************************************************************/
  648. STDMETHODIMP
  649. CDIEff_GetEffectGuid(PDIE pdie, LPGUID pguid)
  650. {
  651. HRESULT hres;
  652. EnterProcR(IDirectInputEffect::GetEffectGuid, (_ "p", pdie));
  653. if (SUCCEEDED(hres = hresPv(pdie)) &&
  654. SUCCEEDED(hres = hresFullValidWritePguid(pguid, 1))) {
  655. PDE this = _thisPvNm(pdie, def);
  656. /*
  657. * Race condition: If the caller reinitializes and
  658. * does a GetEffectGuid simultaneously, the return value
  659. * is random. That's okay; it's the caller's problem.
  660. */
  661. if (this->fInitialized) {
  662. *pguid = this->guid;
  663. hres = S_OK;
  664. } else {
  665. hres = DIERR_NOTINITIALIZED;
  666. }
  667. }
  668. ExitOleProcR();
  669. return hres;
  670. }
  671. /*****************************************************************************
  672. *
  673. * @doc INTERNAL
  674. *
  675. * @func __int64 | _ftol |
  676. *
  677. * Convert a floating point number to an integer.
  678. *
  679. * We do it ourselves because the C runtime has been known to do a
  680. * poor job of this.
  681. *
  682. * It's the caller's job to worry about the rounding mode.
  683. *
  684. * @parm double | lf |
  685. *
  686. * Floating point number to convert.
  687. *
  688. *****************************************************************************/
  689. #if defined(WIN95)
  690. #pragma warning(disable:4035) /* no return value (duh) */
  691. BYTE _fltused;
  692. __declspec(naked) __int64 __cdecl
  693. _ftol(double lf)
  694. {
  695. lf;
  696. _asm {
  697. sub esp, 8
  698. fistp qword ptr [esp]
  699. pop eax
  700. pop edx
  701. ret
  702. }
  703. }
  704. #pragma warning(default:4035)
  705. #endif
  706. /*
  707. * The floating point type we use for intermediates.
  708. */
  709. typedef long double FPTYPE;
  710. /*****************************************************************************
  711. *
  712. * @doc INTERNAL
  713. *
  714. * @func FPTYPE | CDIEff_IntToAngle |
  715. *
  716. * Convert an integer angle to a floating point angle.
  717. *
  718. * @parm LONG | l |
  719. *
  720. * Integer angle to convert.
  721. *
  722. *****************************************************************************/
  723. #ifndef M_PI
  724. #define M_PI 3.1415926535897932384
  725. #endif
  726. FPTYPE INLINE
  727. CDIEff_IntToAngle(LONG l)
  728. {
  729. FPTYPE theta;
  730. /*
  731. * 2pi radians equals 360 degrees.
  732. */
  733. theta = l * (2 * M_PI) / (360 * DI_DEGREES);
  734. return theta;
  735. }
  736. /*****************************************************************************
  737. *
  738. * @doc INTERNAL
  739. *
  740. * @func LONG | CDIEff_IntAtan2 |
  741. *
  742. * Compute the floating point arctangent of y/x and
  743. * convert the resulting angle to an integer in DI_DEGREES.
  744. *
  745. * @parm FPTYPE | y |
  746. *
  747. * Vertical coordinate.
  748. *
  749. * @parm FPTYPE | x |
  750. *
  751. * Horizontal coordinate.
  752. *
  753. * @returns
  754. *
  755. * A value in the range [ 0 .. 360 * DI_DEGREES ).
  756. *
  757. *****************************************************************************/
  758. LONG INLINE
  759. CDIEff_IntAtan2(FPTYPE y, FPTYPE x)
  760. {
  761. FPTYPE theta;
  762. LONG l;
  763. #if defined(_X86_)
  764. /*
  765. * The Intel FPU doesn't care about (0, 0).
  766. */
  767. theta = atan2(y, x);
  768. #else
  769. /*
  770. * The Alpha gets really upset about (0, 0).
  771. */
  772. if (y != 0.0 || x != 0.0) {
  773. theta = atan2(y, x);
  774. } else {
  775. theta = 0.0;
  776. }
  777. #endif
  778. /*
  779. * atan2 returns a value in the range -M_PI to +M_PI.
  780. * On the Intel x86, there are four rounding modes:
  781. *
  782. * Round to nearest or even
  783. * Round towards minus infinity
  784. * Round towards plus infinity
  785. * Round towards zero
  786. *
  787. * By ensuring that the value being rounded is positive, we
  788. * reduce to three cases:
  789. *
  790. * Round to nearest or even
  791. * Round down
  792. * Round up
  793. *
  794. * And as long as the app doesn't change its rounding mode
  795. * (few do), the values will be consistent. (Whereas if we
  796. * let negative numbers through, you would get weird behavior
  797. * as the angle neared M_PI aka -M_PI.)
  798. *
  799. * Method 1:
  800. *
  801. * if (theta < 0) theta += 2 * M_PI;
  802. * l = convert(theta);
  803. * return l;
  804. *
  805. * This is bad because if theta starts out as -epsilon, then
  806. * we end up converting 2 * M_PI - epsilon, which might get
  807. * rounded up to 360 * DI_DEGREES. But our return value
  808. * must be in the range 0 <= l < 360 * DI_DEGREES.
  809. *
  810. * So instead, we use method 2:
  811. *
  812. * l = convert(theta + 2 * M_PI);
  813. * if (l >= 360 * DI_DEGREES) l -= 360 * DI_DEGREES;
  814. *
  815. * The value being converted ends up in the range M_PI .. 3 * M_PI,
  816. * which after rounding becomes 180 * DI_DEGREES .. 540 * DI_DEGREES.
  817. * The final check then pulls the value into range.
  818. */
  819. /*
  820. * 2pi radians equals 360 degrees.
  821. */
  822. l = (LONG)((theta + 2 * M_PI) * (360 * DI_DEGREES) / (2 * M_PI));
  823. if (l >= 360 * DI_DEGREES) {
  824. l -= 360 * DI_DEGREES;
  825. }
  826. return l;
  827. }
  828. /*****************************************************************************
  829. *
  830. * @doc INTERNAL
  831. *
  832. * @func FPTYPE | atan2Z |
  833. *
  834. * Just like <f atan2>, except it doesn't barf on
  835. * (0, 0).
  836. *
  837. * @parm FPTYPE | y |
  838. *
  839. * Vertical coordinate.
  840. *
  841. * @parm FPTYPE | x |
  842. *
  843. * Horizontal coordinate.
  844. *
  845. *****************************************************************************/
  846. FPTYPE INLINE
  847. atan2Z(FPTYPE y, FPTYPE x)
  848. {
  849. #if defined(_X86_)
  850. /*
  851. * The Intel FPU doesn't care about (0, 0).
  852. */
  853. return atan2(y, x);
  854. #else
  855. /*
  856. * The Alpha gets really upset about (0, 0).
  857. */
  858. if (y != 0.0 || x != 0.0) {
  859. return atan2(y, x);
  860. } else {
  861. return 0.0;
  862. }
  863. #endif
  864. }
  865. /*****************************************************************************
  866. *
  867. * @doc INTERNAL
  868. *
  869. * @func HRESULT | CDIEff_CartToAngles |
  870. *
  871. * Convert cartesian coordinates to angle-based coordinates
  872. * (either polar or spherical). Note that the resulting
  873. * angles have not been normalized.
  874. *
  875. * @parm DWORD | cAxes |
  876. *
  877. * Number of axes involved, never zero.
  878. *
  879. * @parm LPLONG | rglAngles |
  880. *
  881. * Buffer to receive angle-base coordinates.
  882. * The final entry of the array contains nothing of interest.
  883. *
  884. * @parm LPCLONG | rglCart |
  885. *
  886. * Buffer containing existing cartesian coordinates.
  887. *
  888. * @parm DWORD | dieff |
  889. *
  890. * Flags specifying whether the target coordinates should
  891. * be <c DIEFF_POLAR> or <c DIEFF_SPHERICAL>.
  892. *
  893. * Polar and spherical coordinates differ only in their
  894. * treatment of the first angle.
  895. *
  896. *****************************************************************************/
  897. STDMETHODIMP
  898. CDIEff_CartToAngles(DWORD cAxes,
  899. LPLONG rglAngles, const LONG *rglCart, DWORD dieff)
  900. {
  901. HRESULT hres;
  902. FPTYPE r;
  903. DWORD iAxis;
  904. AssertF(cAxes);
  905. AssertF(dieff == DIEFF_POLAR || dieff == DIEFF_SPHERICAL);
  906. /*
  907. * If we're converting a 1-axis cartesian effect
  908. * the value of rglAngles[0] will not be overwritten;
  909. * the value that is put there initially can be random,
  910. * since rglAngles is never initialized (Whistler bug 228280).
  911. * but we can't change this behaviour without potentially
  912. * breaking compatibility w/ some devices.
  913. * The best we can do is to print out a warning in debug.
  914. */
  915. if (cAxes == 1)
  916. {
  917. RPF("Warning: converting a 1-axis cartesian effect to polar or spherical coordinates: the results will be undefined.");
  918. }
  919. /*
  920. * Prime the pump.
  921. */
  922. r = rglCart[0];
  923. /*
  924. * Then walk the coordinates, converting to angles as we go.
  925. */
  926. for (iAxis = 1; iAxis < cAxes; iAxis++) {
  927. FPTYPE y = rglCart[iAxis];
  928. rglAngles[iAxis-1] = CDIEff_IntAtan2(y, r);
  929. r = sqrt(r * r + y * y);
  930. }
  931. /*
  932. * The last coordinate is left garbage.
  933. *
  934. * NOTE! Mathematically, the last coordinate is r.
  935. */
  936. /*
  937. * Adjust for DIEFF_POLAR.
  938. *
  939. * theta(polar) = theta(spherical) + 90deg
  940. */
  941. if (dieff & DIEFF_POLAR) {
  942. rglAngles[0] += 90 * DI_DEGREES;
  943. }
  944. hres = S_OK;
  945. return hres;
  946. }
  947. /*****************************************************************************
  948. *
  949. * @doc INTERNAL
  950. *
  951. * @func HRESULT | CDIEff_AnglesToCart |
  952. *
  953. * Convert angle-based coordinates
  954. * (either polar or spherical)
  955. * to cartesian coordinates.
  956. *
  957. * @parm DWORD | cAxes |
  958. *
  959. * Number of axes involved, never zero.
  960. *
  961. * @parm LPLONG | rglCart |
  962. *
  963. * Buffer to receive cartesian coordinates.
  964. *
  965. * @parm LPCLONG | rglAngles |
  966. *
  967. * Buffer containing existing angle-base coordinates.
  968. *
  969. * @parm DWORD | dieff |
  970. *
  971. * Flags specifying whether the source coordinates are
  972. * <c DIEFF_POLAR> or <c DIEFF_SPHERICAL>.
  973. *
  974. * Polar and spherical coordinates differ only in their
  975. * treatment of the first angle.
  976. *
  977. *****************************************************************************/
  978. STDMETHODIMP
  979. CDIEff_AnglesToCart(DWORD cAxes,
  980. LPLONG rglCart, const LONG *rglAngles, DWORD dieff)
  981. {
  982. HRESULT hres;
  983. FPTYPE x[DIEFFECT_MAXAXES];
  984. DWORD iAxis;
  985. DWORD lAngle;
  986. AssertF(cAxes);
  987. AssertF(cAxes <= DIEFFECT_MAXAXES);
  988. AssertF(dieff == DIEFF_POLAR || dieff == DIEFF_SPHERICAL);
  989. /*
  990. * Prime the pump.
  991. */
  992. x[0] = 1.0;
  993. /*
  994. * For each angle, rotate in that direction.
  995. *
  996. * If polar, then the first angle is biased by 90deg,
  997. * so unbias it.
  998. *
  999. * theta(spherical) = theta(polar) - 90deg
  1000. */
  1001. lAngle = rglAngles[0];
  1002. if (dieff & DIEFF_POLAR) {
  1003. lAngle -= 90 * DI_DEGREES;
  1004. }
  1005. for (iAxis = 1; iAxis < cAxes; iAxis++) {
  1006. DWORD iX;
  1007. FPTYPE theta, costh;
  1008. theta = CDIEff_IntToAngle(lAngle);
  1009. x[iAxis] = sin(theta);
  1010. /*
  1011. * Compiler wont hoist this expression.
  1012. *
  1013. * It also wont use the FSINCOS instruction.
  1014. */
  1015. costh = cos(theta);
  1016. for (iX = 0; iX < iAxis; iX++) {
  1017. x[iX] *= costh;
  1018. }
  1019. /*
  1020. * Note that this is safe because the angle array
  1021. * always contains an extra zero.
  1022. */
  1023. lAngle = rglAngles[iAxis];
  1024. }
  1025. /*
  1026. * Now convert the floating point values to scaled integers.
  1027. */
  1028. for (iAxis = 0; iAxis < cAxes; iAxis++) {
  1029. rglCart[iAxis] = (LONG)(x[iAxis] * DI_FFNOMINALMAX);
  1030. }
  1031. hres = S_OK;
  1032. return hres;
  1033. }
  1034. /*****************************************************************************
  1035. *
  1036. * @doc INTERNAL
  1037. *
  1038. * @func DWORD | CDIEff_ConvertDirection |
  1039. *
  1040. * Given coordinates in a source system and a target system,
  1041. * convert them.
  1042. *
  1043. * There are three possible source systems and three
  1044. * possible destination systems.
  1045. *
  1046. * Yes, this is the most annoying thing you could imagine.
  1047. *
  1048. * @parm DWORD | cAxes |
  1049. *
  1050. * Number of axes involved, never zero.
  1051. *
  1052. * @parm LPLONG | rglDst |
  1053. *
  1054. * Buffer to receive target coordinates.
  1055. *
  1056. * @parm DWORD | dieffDst |
  1057. *
  1058. * Coordinate systems supported by target. As many bits
  1059. * may be set as are supported by the target, but at least
  1060. * one must be set.
  1061. *
  1062. * @parm LPCLONG | rglSrc |
  1063. *
  1064. * Buffer containing source coordinates.
  1065. *
  1066. * @parm DWORD | dieffSrc |
  1067. *
  1068. * Coordinate system of source. Exactly one bit should be set.
  1069. *
  1070. * @returns
  1071. *
  1072. * Returns the coordinate system stored into the target.
  1073. *
  1074. *****************************************************************************/
  1075. DWORD INTERNAL
  1076. CDIEff_ConvertDirection(DWORD cAxes,
  1077. LPLONG rglDst, DWORD dieffDst,
  1078. const LONG *rglSrc, DWORD dieffSrc)
  1079. {
  1080. DWORD dieffRc;
  1081. HRESULT hres;
  1082. dieffSrc &= DIEFF_COORDMASK;
  1083. dieffDst &= DIEFF_COORDMASK;
  1084. AssertF(cAxes);
  1085. AssertF(dieffDst);
  1086. AssertF(dieffSrc == DIEFF_CARTESIAN ||
  1087. dieffSrc == DIEFF_POLAR ||
  1088. dieffSrc == DIEFF_SPHERICAL);
  1089. if (dieffSrc & dieffDst) {
  1090. /*
  1091. * The easy case: The two are directly compatible.
  1092. *
  1093. * Just slam the bits across and copy the format.
  1094. */
  1095. CopyMemory(rglDst, rglSrc, cbCdw(cAxes));
  1096. dieffRc = dieffSrc;
  1097. } else
  1098. /*
  1099. * If they two are not directly compatible, see if
  1100. * the source is cartesian.
  1101. */
  1102. if (dieffSrc & DIEFF_CARTESIAN) {
  1103. /*
  1104. * Source is cartesian, dest is something angular.
  1105. * Choose DIEFF_SPHERICAL if possible.
  1106. */
  1107. AssertF(dieffDst & DIEFF_ANGULAR);
  1108. dieffRc = dieffDst & DIEFF_SPHERICAL;
  1109. if (dieffRc == 0) {
  1110. AssertF(dieffDst & DIEFF_POLAR);
  1111. dieffRc = DIEFF_POLAR;
  1112. }
  1113. hres = CDIEff_CartToAngles(cAxes, rglDst, rglSrc, dieffRc);
  1114. AssertF(SUCCEEDED(hres));
  1115. } else
  1116. /*
  1117. * The two are not directly compatible, and the source is
  1118. * not cartesian. This means that the source is one of the
  1119. * angular forms. The destination is a combination of
  1120. * the other angular form or cartesian.
  1121. */
  1122. if (dieffDst & DIEFF_ANGULAR) {
  1123. /*
  1124. * Source is angular, dest is the other angular.
  1125. */
  1126. AssertF(dieffSrc & DIEFF_ANGULAR);
  1127. AssertF((dieffSrc & dieffDst) == 0);
  1128. /*
  1129. * First copy everything over,
  1130. */
  1131. CopyMemory(rglDst, rglSrc, cbCdw(cAxes));
  1132. /*
  1133. * Now rotate left or right, depending on which way
  1134. * we're going.
  1135. */
  1136. if (dieffSrc & DIEFF_POLAR) {
  1137. /*
  1138. * Polar to spherical: Subtract 90deg.
  1139. */
  1140. rglDst[0] -= 90 * DI_DEGREES;
  1141. } else {
  1142. /*
  1143. * Spherical to polar: Add 90deg.
  1144. */
  1145. rglDst[0] += 90 * DI_DEGREES;
  1146. }
  1147. dieffRc = dieffDst & DIEFF_ANGULAR;
  1148. } else
  1149. /*
  1150. * All that's left is the source is angular and the destination
  1151. * is cartesian.
  1152. */
  1153. {
  1154. AssertF(dieffSrc & DIEFF_ANGULAR);
  1155. AssertF(dieffDst & DIEFF_CARTESIAN);
  1156. hres = CDIEff_AnglesToCart(cAxes, rglDst, rglSrc, dieffSrc);
  1157. dieffRc = DIEFF_CARTESIAN;
  1158. }
  1159. /*
  1160. * If the resulting coordinate system is angular, then
  1161. * normalize all the angles.
  1162. */
  1163. if (dieffRc & DIEFF_ANGULAR) {
  1164. DWORD iAxis;
  1165. /*
  1166. * Remember, the last entry is not a direction.
  1167. */
  1168. for (iAxis = 0; iAxis < cAxes - 1; iAxis++) {
  1169. /*
  1170. * An annoying artifact of the C language is that
  1171. * the sign of the result of a % operation when the
  1172. * numerator is negative and the denominator is
  1173. * positive is implementation-defined. The standard
  1174. * does require that the absolute value of the result
  1175. * not exceed the denominator, so a quick final
  1176. * check brings things back into focus.
  1177. */
  1178. rglDst[iAxis] %= 360 * DI_DEGREES;
  1179. if (rglDst[iAxis] < 0) {
  1180. rglDst[iAxis] += 360 * DI_DEGREES;
  1181. }
  1182. }
  1183. /*
  1184. * As always, the last coordinate is zero.
  1185. */
  1186. rglDst[cAxes - 1] = 0;
  1187. }
  1188. return dieffRc;
  1189. }
  1190. /*****************************************************************************
  1191. *
  1192. * @doc INTERNAL
  1193. *
  1194. * @method HRESULT | CDIEff | SyncShepHandle |
  1195. *
  1196. * Synchronize our private <t SHEPHANDLE> with the
  1197. * <t SHEPHANDLE> of the parent device. If they were
  1198. * out of sync, then mark the efect as completely dirty
  1199. * so it will get re-downloaded in full.
  1200. *
  1201. * @cwrap PDE | this
  1202. *
  1203. * @returns
  1204. *
  1205. * <c DI_OK> = <c S_OK>: The two were already in sync.
  1206. *
  1207. * <c S_FALSE>: The two were not in sync and are now in sync.
  1208. *
  1209. *****************************************************************************/
  1210. HRESULT INTERNAL
  1211. CDIEff_SyncShepHandle(PDE this)
  1212. {
  1213. HRESULT hres;
  1214. hres = CDIDev_SyncShepHandle(this->pdev, &this->sh);
  1215. if (hres == S_OK) {
  1216. } else {
  1217. /*
  1218. * We were out of sync with our dad. CDIDev_SyncShepHandle
  1219. * already sync'd us with dad and wiped out the effect handle.
  1220. * All that's left is to dirty everything because there is
  1221. * nothing to update.
  1222. */
  1223. AssertF(hres == S_FALSE);
  1224. this->diepDirty = DIEP_ALLPARAMS;
  1225. }
  1226. return hres;
  1227. }
  1228. /*****************************************************************************
  1229. *
  1230. * @doc INTERNAL
  1231. *
  1232. * @method HRESULT | CDIEff | DownloadWorker |
  1233. *
  1234. * Place the effect on the device. All parameters have
  1235. * been validated and the critical section has already been
  1236. * taken.
  1237. *
  1238. * @cwrap PDE | this
  1239. *
  1240. * @parm LPCDIEFFECT | peff |
  1241. *
  1242. * Effect to send down to the device.
  1243. *
  1244. * If we are downloading for real, then this is the
  1245. * <e CDIEff.effDev>.
  1246. *
  1247. * If we are hoping to download, then this is the
  1248. * <e CDIEff.effTry>.
  1249. *
  1250. * @parm DWORD | fl |
  1251. *
  1252. * Flags which specify which parameters are to be sent down
  1253. * to the driver as changed since last time.
  1254. *
  1255. * @returns
  1256. *
  1257. * Returns a COM error code. The following error codes are
  1258. * intended to be illustrative and not necessarily comprehensive.
  1259. *
  1260. * <c DI_OK> = <c S_OK>: The operation completed successfully.
  1261. *
  1262. * <c DIERR_NOTINITIALIZED>: The <i IDirectInputEffect> object
  1263. * has not yet been <mf IDirectInputEffect::Initialize>d.
  1264. *
  1265. * <c DIERR_DEVICEFULL>: The device does not have enough
  1266. * available memory to download the effect.
  1267. *
  1268. * <c DIERR_INPUTLOST> if acquisition has been lost.
  1269. *
  1270. * <c DIERR_NOTEXCLUSIVEACQUIRED> the device is acquired,
  1271. * but not exclusively, or if the device is not acquired
  1272. * at all.
  1273. *
  1274. *****************************************************************************/
  1275. #ifndef XDEBUG
  1276. #define CDIEff_DownloadWorker_(this, peff, fl, z) \
  1277. _CDIEff_DownloadWorker_(this, peff, fl) \
  1278. #endif
  1279. HRESULT INTERNAL
  1280. CDIEff_DownloadWorker_(PDE this, LPCDIEFFECT peff, DWORD fl, LPCSTR s_szProc)
  1281. {
  1282. HRESULT hres;
  1283. AssertF(CDIDev_InCrit(this->pdev));
  1284. /*
  1285. * If we do not have acquisition, but we are coming from
  1286. * SetParameters, then turn it into a DIEP_NODOWNLOAD so
  1287. * the call will go through.
  1288. */
  1289. hres = CDIEff_CanAccess(this);
  1290. if ((hres == DIERR_INPUTLOST || hres == DIERR_NOTEXCLUSIVEACQUIRED) &&
  1291. peff == &this->effTry) {
  1292. fl |= DIEP_NODOWNLOAD;
  1293. hres = S_OK;
  1294. }
  1295. if (SUCCEEDED(hres)) {
  1296. hres = CDIEff_SyncShepHandle(this);
  1297. if (!(fl & DIEP_NODOWNLOAD)) { /* If we are downloading */
  1298. /*
  1299. * If there are still unset bits, then barf.
  1300. */
  1301. if (this->diepUnset & ~fl) {
  1302. RPF("%s: Effect still incomplete; "
  1303. "DIEP flags %08x need to be set",
  1304. s_szProc, this->diepUnset);
  1305. hres = DIERR_INCOMPLETEEFFECT;
  1306. goto done;
  1307. }
  1308. /*
  1309. * Since we are downloading, pass down all dirty bits.
  1310. */
  1311. fl |= this->diepDirty;
  1312. }
  1313. /*
  1314. * Now call the driver to do the validation or
  1315. * the download (accordingly).
  1316. *
  1317. * Note that if nothing is to be done, then there is no need
  1318. * to call the driver.
  1319. */
  1320. hres = IDirectInputEffectShepherd_DownloadEffect(
  1321. this->pes, (this->dEffAttributes).dwEffectId, &this->sh, peff, fl);
  1322. if (SUCCEEDED(hres)) {
  1323. if (fl & DIEP_NODOWNLOAD) {
  1324. hres = DI_DOWNLOADSKIPPED;
  1325. } else {
  1326. this->diepDirty = 0;
  1327. }
  1328. }
  1329. AssertF(hres != DIERR_NOTDOWNLOADED);
  1330. }
  1331. done:;
  1332. return hres;
  1333. }
  1334. #define CDIEff_DownloadWorker(this, peff, fl) \
  1335. CDIEff_DownloadWorker_(this, peff, fl, s_szProc) \
  1336. /*****************************************************************************
  1337. *
  1338. * @doc EXTERNAL
  1339. *
  1340. * @method HRESULT | IDirectInputEffect | Download |
  1341. *
  1342. * Place the effect on the device. If the effect is already
  1343. * on the device, then the existing effect is updated to
  1344. * match the values set via <mf IDirectInputEffect::SetParameters>.
  1345. *
  1346. * It is valid to update an effect while it is playing.
  1347. * The semantics of such an operation are explained in the
  1348. * documentation for <mf IDirectInputEffect::SetParameters>.
  1349. *
  1350. * @cwrap LPDIRECTINPUTEFFECT | lpDirectInputEffect
  1351. *
  1352. * @returns
  1353. *
  1354. * Returns a COM error code. The following error codes are
  1355. * intended to be illustrative and not necessarily comprehensive.
  1356. *
  1357. * <c DI_OK> = <c S_OK>: The operation completed successfully.
  1358. *
  1359. * <c S_FALSE>: The effect has already been downloaded to the
  1360. * device. Note that this is a success code.
  1361. *
  1362. * <c DIERR_NOTINITIALIZED>: The <i IDirectInputEffect> object
  1363. * has not yet been <mf IDirectInputEffect::Initialize>d.
  1364. *
  1365. * <c DIERR_DEVICEFULL>: The device does not have enough
  1366. * available memory to download the effect.
  1367. *
  1368. * <c DIERR_INPUTLOST> if acquisition has been lost.
  1369. *
  1370. * <c DIERR_NOTEXCLUSIVEACQUIRED> the device is acquired,
  1371. * but not exclusively, or if the device is not acquired
  1372. * at all.
  1373. *
  1374. * <c DIERR_INVALIDPARAM> = <c E_INVALIDARG>: At least one
  1375. * of the parameters is invalid.
  1376. *
  1377. * <c DIERR_EFFECTPLAYING>: The parameters were updated in
  1378. * memory but were not downloaded to the device because
  1379. * the device does not support updating an effect while
  1380. * it is still playing. In such case, you must stop the
  1381. * effect, change its parameters, and restart it.
  1382. *
  1383. *****************************************************************************/
  1384. STDMETHODIMP
  1385. CDIEff_Download(PDIE pdie)
  1386. {
  1387. HRESULT hres;
  1388. EnterProcR(IDirectInputEffect::Download, (_ "p", pdie));
  1389. if (SUCCEEDED(hres = hresPv(pdie))) {
  1390. PDE this = _thisPvNm(pdie, def);
  1391. CDIEff_EnterCrit(this);
  1392. hres = CDIEff_DownloadWorker(this, &this->effDev, 0);
  1393. CDIEff_LeaveCrit(this);
  1394. }
  1395. ExitOleProcR();
  1396. return hres;
  1397. }
  1398. /*****************************************************************************
  1399. *
  1400. * @doc EXTERNAL
  1401. *
  1402. * @method HRESULT | IDirectInputEffect | Unload |
  1403. *
  1404. * Remove the effect from the device.
  1405. *
  1406. * If the effect is playing, it is automatically stopped before
  1407. * it is unloaded.
  1408. *
  1409. * @cwrap LPDIRECTINPUTEFFECT | lpDirectInputEffect
  1410. *
  1411. * @returns
  1412. *
  1413. * Returns a COM error code. The following error codes are
  1414. * intended to be illustrative and not necessarily comprehensive.
  1415. *
  1416. * <c DI_OK> = <c S_OK>: The operation completed successfully.
  1417. *
  1418. * <c DIERR_NOTINITIALIZED>: The <i IDirectInputEffect> object
  1419. * has not yet been <mf IDirectInputEffect::Initialize>d.
  1420. *
  1421. * <c DIERR_INPUTLOST> if acquisition has been lost.
  1422. *
  1423. * <c DIERR_NOTEXCLUSIVEACQUIRED> the device is acquired,
  1424. * but not exclusively, or if the device is not acquired
  1425. * at all.
  1426. *
  1427. * <c DIERR_INVALIDPARAM> = <c E_INVALIDARG>: At least one
  1428. * of the parameters is invalid.
  1429. *
  1430. *****************************************************************************/
  1431. STDMETHODIMP
  1432. CDIEff_Unload(PDIE pdie)
  1433. {
  1434. HRESULT hres;
  1435. EnterProcR(IDirectInputEffect::Unload, (_ "p", pdie));
  1436. if (SUCCEEDED(hres = hresPv(pdie))) {
  1437. PDE this = _thisPvNm(pdie, def);
  1438. CDIEff_EnterCrit(this);
  1439. hres = CDIEff_UnloadWorker(this);
  1440. CDIEff_LeaveCrit(this);
  1441. }
  1442. ExitOleProcR();
  1443. return hres;
  1444. }
  1445. /*****************************************************************************
  1446. *
  1447. * @doc INTERNAL
  1448. *
  1449. * @func HRESULT | hresFullValidWritePeff |
  1450. *
  1451. * Verify that the recipient buffer is valid to receive
  1452. * effect information.
  1453. *
  1454. * @cwrap LPDIRECTINPUTEFFECT | lpDirectInputEffect
  1455. *
  1456. * @parm LPDIEFFECT | peff |
  1457. *
  1458. * Structure that receives effect information. It has
  1459. * already been validate in size and for general writeability.
  1460. *
  1461. * @parm DWORD | fl |
  1462. *
  1463. * Zero or more <c DIEP_*> flags specifying which
  1464. * portions of the effect information is to be retrieved.
  1465. *
  1466. * @returns
  1467. *
  1468. * Returns a COM error code. The following error codes are
  1469. * intended to be illustrative and not necessarily comprehensive.
  1470. *
  1471. * <c DI_OK> = <c S_OK>: The operation completed successfully.
  1472. *
  1473. * <c DIERR_INVALIDPARAM> = <c E_INVALIDARG>: At least one
  1474. * of the parameters is invalid.
  1475. *
  1476. *****************************************************************************/
  1477. #ifndef XDEBUG
  1478. #define hresFullValidWritePeff_(this, peff, fl, z, i) \
  1479. _hresFullValidWritePeff_(this, peff, fl) \
  1480. #endif
  1481. #define hresFullValidWritePeff(this, peff, fl, iarg) \
  1482. hresFullValidWritePeff_(this, peff, fl, s_szProc, iarg) \
  1483. HRESULT INTERNAL
  1484. hresFullValidWritePeff_(PDE this, LPDIEFFECT peff, DWORD fl,
  1485. LPCSTR s_szProc, int iarg)
  1486. {
  1487. HRESULT hres;
  1488. AssertF(CDIDev_InCrit(this->pdev));
  1489. /*
  1490. * You can't get the parameters of a nonexistent effect.
  1491. */
  1492. if (!this->fInitialized) {
  1493. hres = DIERR_NOTINITIALIZED;
  1494. goto done;
  1495. }
  1496. /*
  1497. * Flags are always validated.
  1498. */
  1499. if (peff->dwFlags & ~DIEFF_VALID) {
  1500. RPF("ERROR %s: arg %d: Invalid value 0x%08x in DIEFFECT.dwFlags",
  1501. s_szProc, iarg, peff->dwFlags);
  1502. hres = E_INVALIDARG;
  1503. goto done;
  1504. }
  1505. /*
  1506. * If requesting something that requires object ids or offsets,
  1507. * make sure the caller picks one or the other.
  1508. */
  1509. if (fl & DIEP_USESOBJECTS) {
  1510. switch (peff->dwFlags & DIEFF_OBJECTMASK) {
  1511. case DIEFF_OBJECTIDS:
  1512. case DIEFF_OBJECTOFFSETS:
  1513. break;
  1514. default:
  1515. RPF("ERROR %s: arg %d: Must specify one of "
  1516. "DIEFF_OBJECTIDS or DIEFF_OBJECTOFFSETS", s_szProc, iarg);
  1517. hres = E_INVALIDARG;
  1518. goto done;
  1519. }
  1520. }
  1521. /*
  1522. * If requesting something that requires direction coordinates,
  1523. * make sure the caller picks something we can return.
  1524. */
  1525. if (fl & DIEP_USESCOORDS) {
  1526. /*
  1527. * Polar coordinates require cAxes == 2. If not, then
  1528. * turn off DIEFF_POLAR so we won't return it.
  1529. *
  1530. * But the place where we check the number of axes is
  1531. * in the effect itself, not in the input buffer.
  1532. * The reason is that the caller might be passing cAxes=0
  1533. * intending to ping the number of axes, and I don't
  1534. * want to return an error or the app will get confused
  1535. * and panic.
  1536. */
  1537. if (this->effDev.cAxes != 2 && (peff->dwFlags & DIEFF_POLAR)) {
  1538. RPF("WARNING %s: arg %d: DIEFF_POLAR requires DIEFFECT.cAxes=2",
  1539. s_szProc, 1);
  1540. peff->dwFlags &= ~DIEFF_POLAR;
  1541. }
  1542. /*
  1543. * There'd better be a coordinate system left.
  1544. */
  1545. if ((peff->dwFlags & DIEFF_COORDMASK) == 0) {
  1546. RPF("ERROR %s: arg %d: No (valid) coordinate system "
  1547. "in DIEFFECT.dwFlags", s_szProc, 1);
  1548. hres = E_INVALIDARG;
  1549. goto done;
  1550. }
  1551. }
  1552. /*
  1553. * DIEP_DURATION
  1554. * DIEP_SAMPLEPERIOD
  1555. * DIEP_GAIN
  1556. * DIEP_TRIGGERBUTTON
  1557. * DIEP_TRIGGERREPEATINTERVAL
  1558. * - Simple dwords. No extra validation needed.
  1559. */
  1560. #if DIRECTINPUT_VERSION >= 0x0600
  1561. /*
  1562. * DIEP_STARTDELAY
  1563. * - Although this is a simple DWORD, we do some
  1564. * sanity warnings because vendors will probably
  1565. * forget to initialize it. Also, you can't pass
  1566. * this flag if your structure isn't big enough.
  1567. */
  1568. if (fl & DIEP_STARTDELAY) {
  1569. if (peff->dwSize < cbX(DIEFFECT_DX6)) {
  1570. RPF("ERROR %s: arg %d: Can't use DIEP_STARTDELAY with "
  1571. "DIEFFECT_DX5 structure", s_szProc, 1);
  1572. }
  1573. /*
  1574. * Sanity checks. A delay that isn't a multiple of 50ms is
  1575. * probably a bug.
  1576. */
  1577. if (peff->dwStartDelay % 50000) {
  1578. RPF("WARNING %s: DIEFFECT.dwStartDelay = %d seems odd",
  1579. s_szProc, peff->dwStartDelay);
  1580. }
  1581. }
  1582. #endif
  1583. /*
  1584. * DIEP_TYPESPECIFICPARAMS
  1585. * - Validate that the buffer is big enough.
  1586. */
  1587. AssertF(this->hresValidTsd);
  1588. if ((fl & DIEP_TYPESPECIFICPARAMS) &&
  1589. FAILED(hres = hresFullValidWritePvCb(peff->lpvTypeSpecificParams,
  1590. peff->cbTypeSpecificParams,
  1591. iarg))) {
  1592. RPF("ERROR %s: arg %d: Invalid pointer in "
  1593. "DIEFFECT.lpvTypeSpecificParams", s_szProc, iarg);
  1594. goto done;
  1595. }
  1596. /*
  1597. * DIEP_AXES
  1598. * DIEP_DIRECTION
  1599. * - The buffers must be of necessary size.
  1600. */
  1601. if ((fl & DIEP_AXES) &&
  1602. FAILED(hres = hresFullValidWritePvCb(peff->rgdwAxes,
  1603. cbCdw(peff->cAxes), iarg))) {
  1604. RPF("ERROR %s: arg %d: Invalid pointer in DIEFFECT.rgdwAxes",
  1605. s_szProc, iarg);
  1606. goto done;
  1607. }
  1608. if ((fl & DIEP_DIRECTION) &&
  1609. FAILED(hres = hresFullValidWritePvCb(peff->rglDirection,
  1610. cbCdw(peff->cAxes), iarg))) {
  1611. RPF("ERROR %s: arg %d: Invalid pointer in DIEFFECT.rglDirection",
  1612. s_szProc, iarg);
  1613. goto done;
  1614. }
  1615. /*
  1616. * DIEP_ENVELOPE - The pointer must be valid to receive the envelope.
  1617. */
  1618. if ((fl & DIEP_ENVELOPE) &&
  1619. FAILED(hres = hresFullValidWritePxCb(peff->lpEnvelope,
  1620. DIENVELOPE, iarg))) {
  1621. RPF("ERROR %s: arg %d: Invalid pointer in DIEFFECT.lpEnvelope",
  1622. s_szProc, iarg);
  1623. goto done;
  1624. }
  1625. hres = S_OK;
  1626. done:;
  1627. return hres;
  1628. }
  1629. /*****************************************************************************
  1630. *
  1631. * @doc INTERNAL
  1632. *
  1633. * @method HRESULT | CDIEff | MapDwords |
  1634. *
  1635. * Map a few <t DWORD>s based on the desired mapping mode
  1636. * of the caller.
  1637. *
  1638. * @cwrap PDE | this
  1639. *
  1640. * @parm DWORD | dwFlags |
  1641. *
  1642. * The mapping mode desired by the caller.
  1643. *
  1644. * @parm UINT | cdw |
  1645. *
  1646. * Number of items to convert.
  1647. *
  1648. * @parm LPDWORD | rgdwOut |
  1649. *
  1650. * Destination buffer.
  1651. *
  1652. * @parm LPCDWORD | rgdwIn |
  1653. *
  1654. * Source buffer.
  1655. *
  1656. * @parm UINT | devco |
  1657. *
  1658. * Conversion code describing what we're converting.
  1659. *
  1660. * @returns
  1661. *
  1662. * Returns a COM error code. The following error codes are
  1663. * intended to be illustrative and not necessarily comprehensive.
  1664. *
  1665. * <c DI_OK> = <c S_OK>: The operation completed successfully.
  1666. *
  1667. * <c DIERR_INVALIDPARAM> = <c E_INVALIDARG>: The caller
  1668. * requested offsets but there is no data format selected.
  1669. *
  1670. *****************************************************************************/
  1671. #if 0
  1672. #ifndef XDEBUG
  1673. #define CDIEff_MapDwords_(this, fl, cdw, rgdwOut, rgdwIn, devco, z, i) \
  1674. _CDIEff_MapDwords_(this, fl, cdw, rgdwOut, rgdwIn, devco) \
  1675. #endif
  1676. #define CDIEff_MapDwords(this, fl, cdw, rgdwOut, rgdwIn, devco, i) \
  1677. CDIEff_MapDwords_(this, fl, cdw, rgdwOut, rgdwIn, devco, s_szProc, i) \
  1678. #endif
  1679. HRESULT INTERNAL
  1680. CDIEff_MapDwords(PDE this, DWORD dwFlags,
  1681. UINT cdw, LPDWORD rgdwOut, const DWORD *rgdwIn, UINT devco)
  1682. {
  1683. HRESULT hres;
  1684. AssertF(CDIDev_InCrit(this->pdev));
  1685. if (cdw) {
  1686. CopyMemory(rgdwOut, rgdwIn, cbCdw(cdw));
  1687. /*
  1688. * Okay, now things get weird. We internally keep the
  1689. * items as item IDs, because that's what drivers
  1690. * want. So we need to convert them to whatever the
  1691. * caller really wants.
  1692. */
  1693. if (dwFlags & DIEFF_OBJECTOFFSETS) {
  1694. if (devco & DEVCO_FROMID) {
  1695. devco |= DEVCO_TOOFFSET;
  1696. } else {
  1697. AssertF(devco & DEVCO_TOID);
  1698. devco |= DEVCO_FROMOFFSET;
  1699. }
  1700. } else {
  1701. AssertF(dwFlags & DIEFF_OBJECTIDS);
  1702. if (devco & DEVCO_FROMID) {
  1703. devco |= DEVCO_TOID;
  1704. } else {
  1705. AssertF(devco & DEVCO_TOID);
  1706. devco |= DEVCO_FROMID;
  1707. }
  1708. }
  1709. hres = CDIDev_ConvertObjects(this->pdev, cdw, rgdwOut, devco);
  1710. } else {
  1711. /* Vacuous success */
  1712. hres = S_OK;
  1713. }
  1714. return hres;
  1715. }
  1716. /*****************************************************************************
  1717. *
  1718. * @doc INTERNAL
  1719. *
  1720. * @method void | CDIEff | GetDirectionParameters |
  1721. *
  1722. * Retrieve information about the direction of an effect.
  1723. *
  1724. * If no direction has yet been set, then wipe out the
  1725. * direction pointer and erase the coordinate system.
  1726. *
  1727. * Always convert from the cached application coordinate
  1728. * system instead of the device coordinate system, in
  1729. * order to maximize fidelity.
  1730. *
  1731. * @cwrap PDE | this
  1732. *
  1733. * @parm LPDIEFFECT | peff |
  1734. *
  1735. * Structure to receive effect information.
  1736. *
  1737. * @parm DWORD | cAxes |
  1738. *
  1739. * Number of axes to return.
  1740. *
  1741. * @returns
  1742. *
  1743. * Returns a COM error code. The following error codes are
  1744. * intended to be illustrative and not necessarily comprehensive.
  1745. *
  1746. * <c DI_OK> = <c S_OK>: The operation completed successfully.
  1747. *
  1748. * <c DIERR_INVALIDPARAM> = <c E_INVALIDARG>: At least one
  1749. * of the parameters is invalid.
  1750. *
  1751. *****************************************************************************/
  1752. #ifndef XDEBUG
  1753. #define CDIEff_GetDirectionParameters_(this, peff, cAxes, z, iarg) \
  1754. _CDIEff_GetDirectionParameters_(this, peff, cAxes) \
  1755. #endif
  1756. #define CDIEff_GetDirectionParameters(this, peff, cAxes, iarg) \
  1757. CDIEff_GetDirectionParameters_(this, peff, cAxes, s_szProc, iarg) \
  1758. void INTERNAL
  1759. CDIEff_GetDirectionParameters_(PDE this, LPDIEFFECT peff, DWORD cAxes,
  1760. LPCSTR s_szProc, int iarg)
  1761. {
  1762. AssertF(CDIDev_InCrit(this->pdev));
  1763. /*
  1764. * Make sure there are no non-coordinate bits in dwDirFlags.
  1765. * And validation should've made sure the app is asking for *something*.
  1766. */
  1767. AssertF((this->dwDirFlags & ~DIEFF_COORDMASK) == 0);
  1768. AssertF(peff->dwFlags & DIEFF_COORDMASK);
  1769. AssertF(cAxes <= DIEFFECT_MAXAXES);
  1770. if (this->dwDirFlags) {
  1771. DWORD dieffRc;
  1772. LONG rgl[DIEFFECT_MAXAXES]; /* Holding buffer */
  1773. /*
  1774. * We must double-buffer in case the target is not big enough.
  1775. */
  1776. /*
  1777. * Prefix does not like the lack of initialization of rgl (Manbugs 34566, Whistler 228280 --
  1778. * althought the bugs refer to dinput8.dll, the same problem is present in dinput.dll).
  1779. * but unfortunately we can't fix it without potentially breaking compatibility
  1780. * with some devices. See comment in CDIEff_CartToAngles() about this issue.
  1781. */
  1782. dieffRc = CDIEff_ConvertDirection(
  1783. this->effDev.cAxes,
  1784. rgl, peff->dwFlags,
  1785. this->rglDirApp, this->dwDirFlags);
  1786. peff->dwFlags = (peff->dwFlags & ~DIEFF_COORDMASK) | dieffRc;
  1787. CopyMemory(peff->rglDirection, rgl, cbCdw(cAxes));
  1788. } else {
  1789. /*
  1790. * No direction set; vacuous success.
  1791. */
  1792. RPF("Warning: %s: arg %d: Effect has no direction", s_szProc, iarg);
  1793. peff->rglDirection = 0;
  1794. peff->dwFlags &= ~DIEFF_COORDMASK;
  1795. }
  1796. }
  1797. /*****************************************************************************
  1798. *
  1799. * @doc EXTERNAL
  1800. *
  1801. * @method HRESULT | IDirectInputEffect | GetParameters |
  1802. *
  1803. * Retrieve information about an effect.
  1804. *
  1805. * @cwrap LPDIRECTINPUTEFFECT | lpDirectInputEffect
  1806. *
  1807. * @parm LPDIEFFECT | peff |
  1808. *
  1809. * Structure that receives effect information.
  1810. * The <e DIEFFECT.dwSize> field must be filled in by
  1811. * the application before calling this function.
  1812. *
  1813. * @parm DWORD | dwFlags |
  1814. *
  1815. * Zero or more <c DIEP_*> flags specifying which
  1816. * portions of the effect information is to be retrieved.
  1817. *
  1818. *
  1819. * @returns
  1820. *
  1821. * Returns a COM error code. The following error codes are
  1822. * intended to be illustrative and not necessarily comprehensive.
  1823. *
  1824. * <c DI_OK> = <c S_OK>: The operation completed successfully.
  1825. *
  1826. * <c DIERR_NOTINITIALIZED>: The <i IDirectInputEffect> object
  1827. * has never had any effect parameters set into it.
  1828. *
  1829. * <c DIERR_INVALIDPARAM> = <c E_INVALIDARG>: At least one
  1830. * of the parameters is invalid. Common errors include
  1831. * not setting the <e DIEFFECT.dwSize> field of the
  1832. * <t DIEFFECT> structure, passing invalid flags,
  1833. * or not setting up the fields in the <t DIEFFECT> structure
  1834. * properly in preparation for receiving the effect information.
  1835. *
  1836. *
  1837. *****************************************************************************/
  1838. STDMETHODIMP
  1839. CDIEff_GetParameters(PDIE pdie, LPDIEFFECT peff, DWORD fl)
  1840. {
  1841. HRESULT hres;
  1842. EnterProcR(IDirectInputEffect::GetParameters, (_ "ppx", pdie, peff, fl));
  1843. /*
  1844. * Note that we cannot use hresFullValidWritePxCb() because
  1845. * that will scramble the buffer, but we still need the values
  1846. * in it.
  1847. */
  1848. if (SUCCEEDED(hres = hresPv(pdie)) &&
  1849. #if DIRECTINPUT_VERSION >= 0x0600
  1850. SUCCEEDED( hres = ( IsBadReadPtr(&peff->dwSize, cbX(peff->dwSize)) ) ? E_POINTER : S_OK ) &&
  1851. ( ( (peff->dwSize != cbX(DIEFFECT_DX5)) &&
  1852. SUCCEEDED(hres = hresFullValidWriteNoScramblePxCb(peff, DIEFFECT_DX6, 1) ) &&
  1853. SUCCEEDED(hres = hresFullValidFl(fl, DIEP_GETVALID, 2)) )
  1854. ||
  1855. ( SUCCEEDED(hres = hresFullValidWriteNoScramblePxCb(peff, DIEFFECT_DX5, 1)) &&
  1856. SUCCEEDED(hres = hresFullValidFl(fl, DIEP_GETVALID_DX5, 2)) )
  1857. ) ) {
  1858. #else
  1859. SUCCEEDED(hres = hresFullValidWriteNoScramblePxCb(peff, DIEFFECT_DX5, 1)) &&
  1860. SUCCEEDED(hres = hresFullValidFl(fl, DIEP_GETVALID_DX5, 2))) {
  1861. #endif
  1862. PDE this = _thisPvNm(pdie, def);
  1863. CDIEff_EnterCrit(this);
  1864. if (SUCCEEDED(hres = hresFullValidWritePeff(this, peff, fl, 1))) {
  1865. if (fl == 0) {
  1866. RPF("Warning: %s(dwFlags=0) is pretty useless",
  1867. s_szProc);
  1868. }
  1869. /*
  1870. * Assume everything is okay.
  1871. */
  1872. hres = S_OK;
  1873. /*
  1874. * Pull out the effect parameters.
  1875. */
  1876. if (fl & DIEP_DURATION) {
  1877. peff->dwDuration = this->effDev.dwDuration;
  1878. }
  1879. if (fl & DIEP_SAMPLEPERIOD) {
  1880. peff->dwSamplePeriod = this->effDev.dwSamplePeriod;
  1881. }
  1882. if (fl & DIEP_GAIN) {
  1883. peff->dwGain = this->effDev.dwGain;
  1884. }
  1885. #if DIRECTINPUT_VERSION >= 0x0600
  1886. if (fl & DIEP_STARTDELAY) {
  1887. peff->dwStartDelay = this->effDev.dwStartDelay;
  1888. }
  1889. #endif
  1890. if (fl & DIEP_TRIGGERBUTTON) {
  1891. peff->dwTriggerButton = this->effDev.dwTriggerButton;
  1892. if (peff->dwTriggerButton != DIEB_NOTRIGGER) {
  1893. hres = CDIEff_MapDwords(this, peff->dwFlags, 1,
  1894. &peff->dwTriggerButton,
  1895. &peff->dwTriggerButton,
  1896. DEVCO_BUTTON |
  1897. DEVCO_FROMID);
  1898. /*
  1899. * We should never allow a bad id to sneak in.
  1900. */
  1901. AssertF(SUCCEEDED(hres));
  1902. if (FAILED(hres)) {
  1903. goto done;
  1904. }
  1905. }
  1906. }
  1907. if (fl & DIEP_TRIGGERREPEATINTERVAL) {
  1908. peff->dwTriggerRepeatInterval =
  1909. this->effDev.dwTriggerRepeatInterval;
  1910. }
  1911. if (fl & DIEP_TYPESPECIFICPARAMS) {
  1912. DWORD cb = this->effDev.cbTSP;
  1913. if (peff->cbTSP < this->effDev.cbTSP) {
  1914. cb = peff->cbTSP;
  1915. hres = DIERR_MOREDATA;
  1916. }
  1917. peff->cbTSP = this->effDev.cbTSP;
  1918. CopyMemory(peff->lpvTSP, this->effDev.lpvTSP, cb);
  1919. }
  1920. if (fl & DIEP_ENVELOPE) {
  1921. if (this->effDev.lpEnvelope) {
  1922. *peff->lpEnvelope = *this->effDev.lpEnvelope;
  1923. } else {
  1924. /*
  1925. * Zero out the envelope because apps won't
  1926. * check whether peff->lpEnvelope == 0;
  1927. * they're just going to peek at the envelope
  1928. * even if the effect doesn't have one.
  1929. */
  1930. ZeroMemory(pvAddPvCb(peff->lpEnvelope,
  1931. cbX(peff->lpEnvelope->dwSize)),
  1932. cbX(DIENVELOPE) -
  1933. cbX(peff->lpEnvelope->dwSize));
  1934. peff->lpEnvelope = this->effDev.lpEnvelope;
  1935. }
  1936. }
  1937. /*
  1938. * Do axes and direction last because weird error
  1939. * codes can come out of here.
  1940. */
  1941. if (fl & (DIEP_AXES | DIEP_DIRECTION)) {
  1942. DWORD cAxes = this->effDev.cAxes;
  1943. if (peff->cAxes < this->effDev.cAxes) {
  1944. cAxes = peff->cAxes;
  1945. peff->cAxes = this->effDev.cAxes;
  1946. hres = DIERR_MOREDATA;
  1947. }
  1948. peff->cAxes = this->effDev.cAxes;
  1949. if (fl & DIEP_AXES) {
  1950. HRESULT hresT;
  1951. hresT = CDIEff_MapDwords(this, peff->dwFlags, cAxes,
  1952. peff->rgdwAxes,
  1953. this->effDev.rgdwAxes,
  1954. DEVCO_AXIS |
  1955. DEVCO_FROMID);
  1956. if (FAILED(hresT)) {
  1957. RPF("ERROR: %s: arg %d: Axes not in data format",
  1958. s_szProc, 1);
  1959. hres = hresT;
  1960. goto done;
  1961. }
  1962. }
  1963. if (fl & DIEP_DIRECTION) {
  1964. CDIEff_GetDirectionParameters(this, peff, cAxes, 1);
  1965. }
  1966. }
  1967. }
  1968. done:;
  1969. CDIEff_LeaveCrit(this);
  1970. }
  1971. ExitOleProc();
  1972. return hres;
  1973. }
  1974. /*****************************************************************************
  1975. *
  1976. * @doc INTERNAL
  1977. *
  1978. * @func HRESULT | CDIEff_IsValidUnknownTsd |
  1979. *
  1980. * Verify that the buffer is a valid buffer for unknown
  1981. * type-specific data. Since we don't know what it is,
  1982. * the buffer is assumed valid because we can't validate it.
  1983. *
  1984. * @parm LPCDIEFFECT | peff |
  1985. *
  1986. * Structure that contains effect information.
  1987. * The type-specific parameters have already been validated
  1988. * for access.
  1989. *
  1990. * @parm DWORD | cAxes |
  1991. *
  1992. * Number of axes associated with the type-specific parameters.
  1993. *
  1994. * @returns
  1995. *
  1996. * Returns a COM error code. The following error codes are
  1997. * intended to be illustrative and not necessarily comprehensive.
  1998. *
  1999. * <c DI_OK> = <c S_OK>: The operation completed successfully.
  2000. *
  2001. * <c DIERR_INVALIDPARAM> = <c E_INVALIDARG>: At least one
  2002. * of the parameters is invalid.
  2003. *
  2004. *****************************************************************************/
  2005. STDMETHODIMP
  2006. CDIEff_IsValidUnknownTsd(LPCDIEFFECT peff, DWORD cAxes)
  2007. {
  2008. HRESULT hres;
  2009. peff;
  2010. cAxes;
  2011. hres = S_OK;
  2012. return hres;
  2013. }
  2014. /*****************************************************************************
  2015. *
  2016. * @doc INTERNAL
  2017. *
  2018. * @func HRESULT | CDIEff_IsValidConstantTsd |
  2019. *
  2020. * Verify that the buffer is a valid
  2021. * <t DICONSTANTFORCE> structure.
  2022. *
  2023. * @parm LPCDIEFFECT | peff |
  2024. *
  2025. * Structure that contains effect information.
  2026. * The type-specific parameters have already been validated
  2027. * for access.
  2028. *
  2029. * @parm DWORD | cAxes |
  2030. *
  2031. * Number of axes associated with the type-specific parameters.
  2032. *
  2033. * @returns
  2034. *
  2035. * Returns a COM error code. The following error codes are
  2036. * intended to be illustrative and not necessarily comprehensive.
  2037. *
  2038. * <c DI_OK> = <c S_OK>: The operation completed successfully.
  2039. *
  2040. * <c DIERR_INVALIDPARAM> = <c E_INVALIDARG>: At least one
  2041. * of the parameters is invalid.
  2042. *
  2043. *****************************************************************************/
  2044. STDMETHODIMP
  2045. CDIEff_IsValidConstantTsd(LPCDIEFFECT peff, DWORD cAxes)
  2046. {
  2047. HRESULT hres;
  2048. cAxes;
  2049. if (peff->cbTypeSpecificParams == cbX(DICONSTANTFORCE)) {
  2050. hres = S_OK;
  2051. } else {
  2052. hres = E_INVALIDARG;
  2053. }
  2054. return hres;
  2055. }
  2056. /*****************************************************************************
  2057. *
  2058. * @doc INTERNAL
  2059. *
  2060. * @func HRESULT | CDIEff_IsValidRampTsd |
  2061. *
  2062. * Verify that the buffer is a valid
  2063. * <t DIRAMPFORCE> structure.
  2064. *
  2065. * @parm LPCDIEFFECT | peff |
  2066. *
  2067. * Structure that contains effect information.
  2068. * The type-specific parameters have already been validated
  2069. * for access.
  2070. *
  2071. * @parm DWORD | cAxes |
  2072. *
  2073. * Number of axes associated with the type-specific parameters.
  2074. *
  2075. * @returns
  2076. *
  2077. * Returns a COM error code. The following error codes are
  2078. * intended to be illustrative and not necessarily comprehensive.
  2079. *
  2080. * <c DI_OK> = <c S_OK>: The operation completed successfully.
  2081. *
  2082. * <c DIERR_INVALIDPARAM> = <c E_INVALIDARG>: At least one
  2083. * of the parameters is invalid.
  2084. *
  2085. *****************************************************************************/
  2086. STDMETHODIMP
  2087. CDIEff_IsValidRampTsd(LPCDIEFFECT peff, DWORD cAxes)
  2088. {
  2089. HRESULT hres;
  2090. cAxes;
  2091. if (peff->cbTypeSpecificParams == cbX(DIRAMPFORCE)) {
  2092. hres = S_OK;
  2093. } else {
  2094. hres = E_INVALIDARG;
  2095. }
  2096. return hres;
  2097. }
  2098. /*****************************************************************************
  2099. *
  2100. * @doc INTERNAL
  2101. *
  2102. * @func HRESULT | CDIEff_IsValidPeriodicTsd |
  2103. *
  2104. * Verify that the buffer is a valid
  2105. * <t DIPERIODIC> structure.
  2106. *
  2107. * @parm LPCDIEFFECT | peff |
  2108. *
  2109. * Structure that contains effect information.
  2110. * The type-specific parameters have already been validated
  2111. * for access.
  2112. *
  2113. * @parm DWORD | cAxes |
  2114. *
  2115. * Number of axes associated with the type-specific parameters.
  2116. *
  2117. * @returns
  2118. *
  2119. * Returns a COM error code. The following error codes are
  2120. * intended to be illustrative and not necessarily comprehensive.
  2121. *
  2122. * <c DI_OK> = <c S_OK>: The operation completed successfully.
  2123. *
  2124. * <c DIERR_INVALIDPARAM> = <c E_INVALIDARG>: At least one
  2125. * of the parameters is invalid.
  2126. *
  2127. *****************************************************************************/
  2128. STDMETHODIMP
  2129. CDIEff_IsValidPeriodicTsd(LPCDIEFFECT peff, DWORD cAxes)
  2130. {
  2131. HRESULT hres;
  2132. cAxes;
  2133. if (peff->cbTypeSpecificParams == cbX(DIPERIODIC)) {
  2134. hres = S_OK;
  2135. } else {
  2136. hres = E_INVALIDARG;
  2137. }
  2138. return hres;
  2139. }
  2140. /*****************************************************************************
  2141. *
  2142. * @doc INTERNAL
  2143. *
  2144. * @func HRESULT | CDIEff_IsValidConditionTsd |
  2145. *
  2146. * Verify that the buffer is a valid
  2147. * <t DICONDITION> structure.
  2148. *
  2149. * @parm LPCDIEFFECT | peff |
  2150. *
  2151. * Structure that contains effect information.
  2152. * The type-specific parameters have already been validated
  2153. * for access.
  2154. *
  2155. * @parm DWORD | cAxes |
  2156. *
  2157. * Number of axes associated with the type-specific parameters.
  2158. *
  2159. * @returns
  2160. *
  2161. * Returns a COM error code. The following error codes are
  2162. * intended to be illustrative and not necessarily comprehensive.
  2163. *
  2164. * <c DI_OK> = <c S_OK>: The operation completed successfully.
  2165. *
  2166. * <c DIERR_INVALIDPARAM> = <c E_INVALIDARG>: At least one
  2167. * of the parameters is invalid.
  2168. *
  2169. *****************************************************************************/
  2170. STDMETHODIMP
  2171. CDIEff_IsValidConditionTsd(LPCDIEFFECT peff, DWORD cAxes)
  2172. {
  2173. HRESULT hres;
  2174. /*
  2175. * Conditions are weird. The size of the type-specific data
  2176. * must be equal to cAxes * cbX(DICONDITION) or equal to
  2177. * exactly one cbX(DICONDITION), depending on whether you want
  2178. * multiple conditions on multiple axes or a single condition
  2179. * rotated across multiple axes.
  2180. *
  2181. * Note that we do not enforce that the parameters are in range;
  2182. * this allows for "overgain"-type behaviors.
  2183. */
  2184. if (peff->cbTypeSpecificParams == cbX(DICONDITION) ||
  2185. peff->cbTypeSpecificParams == cAxes * cbX(DICONDITION)) {
  2186. hres = S_OK;
  2187. } else {
  2188. RPF("IDirectInputEffect::SetParameters: "
  2189. "Size of type-specific data (%d) "
  2190. "not compatible with number of axes (%d)",
  2191. peff->cbTypeSpecificParams, cAxes);
  2192. hres = E_INVALIDARG;
  2193. }
  2194. return hres;
  2195. }
  2196. /*****************************************************************************
  2197. *
  2198. * @doc INTERNAL
  2199. *
  2200. * @func HRESULT | CDIEff_IsValidCustomForceTsd |
  2201. *
  2202. * Verify that the buffer is a valid
  2203. * <t DICUSTOMFORCE> structure.
  2204. *
  2205. * @parm LPCDIEFFECT | peff |
  2206. *
  2207. * Structure that contains effect information.
  2208. * The type-specific parameters have already been validated
  2209. * for access.
  2210. *
  2211. * @parm DWORD | cAxes |
  2212. *
  2213. * Number of axes associated with the type-specific parameters.
  2214. *
  2215. * @returns
  2216. *
  2217. * Returns a COM error code. The following error codes are
  2218. * intended to be illustrative and not necessarily comprehensive.
  2219. *
  2220. * <c DI_OK> = <c S_OK>: The operation completed successfully.
  2221. *
  2222. * <c DIERR_INVALIDPARAM> = <c E_INVALIDARG>: At least one
  2223. * of the parameters is invalid.
  2224. *
  2225. *****************************************************************************/
  2226. STDMETHODIMP
  2227. CDIEff_IsValidCustomForceTsd(LPCDIEFFECT peff, DWORD cAxes)
  2228. {
  2229. HRESULT hres;
  2230. cAxes;
  2231. if (peff->cbTypeSpecificParams == cbX(DICUSTOMFORCE)) {
  2232. LPCDICUSTOMFORCE pcf = peff->lpvTypeSpecificParams;
  2233. if (pcf->cChannels == 0) {
  2234. RPF("ERROR: IDirectInputEffect::SetParameters: "
  2235. "DICUSTOMFORCE.cChannels == 0 is invalid");
  2236. hres = E_INVALIDARG;
  2237. } else if (pcf->cSamples % pcf->cChannels != 0) {
  2238. RPF("ERROR: IDirectInputEffect::SetParameters: "
  2239. "DICUSTOMFORCE.cSamples must be multiple of "
  2240. "DICUSTOMFORCE.cChannels");
  2241. hres = E_INVALIDARG;
  2242. } else if (IsBadReadPtr(pcf->rglForceData,
  2243. cbCxX((pcf->cSamples)*(pcf->cChannels), LONG))) {
  2244. RPF("ERROR: IDirectInputEffect::SetParameters: "
  2245. "DICUSTOMFORCE.rglForceData invalid");
  2246. hres = E_INVALIDARG;
  2247. } else {
  2248. hres = S_OK;
  2249. }
  2250. } else {
  2251. hres = E_INVALIDARG;
  2252. }
  2253. return hres;
  2254. }
  2255. #if DIRECTINPUT_VERSION >= 0x0800
  2256. /*****************************************************************************
  2257. *
  2258. * @doc INTERNAL
  2259. *
  2260. * @func HRESULT | CDIEff_IsValidRandomTsd |
  2261. *
  2262. * Verify that the buffer is a valid
  2263. * <t DIRANDOM> structure.
  2264. *
  2265. * @parm LPCDIEFFECT | peff |
  2266. *
  2267. * Structure that contains effect information.
  2268. * The type-specific parameters have already been validated
  2269. * for access.
  2270. *
  2271. * @parm DWORD | cAxes |
  2272. *
  2273. * Number of axes associated with the type-specific parameters.
  2274. *
  2275. * @returns
  2276. *
  2277. * Returns a COM error code. The following error codes are
  2278. * intended to be illustrative and not necessarily comprehensive.
  2279. *
  2280. * <c DI_OK> = <c S_OK>: The operation completed successfully.
  2281. *
  2282. * <c DIERR_INVALIDPARAM> = <c E_INVALIDARG>: At least one
  2283. * of the parameters is invalid.
  2284. *
  2285. *****************************************************************************/
  2286. STDMETHODIMP
  2287. CDIEff_IsValidRandomTsd(LPCDIEFFECT peff, DWORD cAxes)
  2288. {
  2289. HRESULT hres;
  2290. cAxes;
  2291. if (peff->cbTypeSpecificParams == cbX(DIRANDOM)) {
  2292. hres = S_OK;
  2293. } else {
  2294. hres = E_INVALIDARG;
  2295. }
  2296. return hres;
  2297. }
  2298. /*****************************************************************************
  2299. *
  2300. * @doc INTERNAL
  2301. *
  2302. * @func HRESULT | CDIEff_IsValidAbsoluteTsd |
  2303. *
  2304. * Verify that the buffer is a valid
  2305. * <t DIABSOLUTE> structure.
  2306. *
  2307. * @parm LPCDIEFFECT | peff |
  2308. *
  2309. * Structure that contains effect information.
  2310. * The type-specific parameters have already been validated
  2311. * for access.
  2312. *
  2313. * @parm DWORD | cAxes |
  2314. *
  2315. * Number of axes associated with the type-specific parameters.
  2316. *
  2317. * @returns
  2318. *
  2319. * Returns a COM error code. The following error codes are
  2320. * intended to be illustrative and not necessarily comprehensive.
  2321. *
  2322. * <c DI_OK> = <c S_OK>: The operation completed successfully.
  2323. *
  2324. * <c DIERR_INVALIDPARAM> = <c E_INVALIDARG>: At least one
  2325. * of the parameters is invalid.
  2326. *
  2327. *****************************************************************************/
  2328. STDMETHODIMP
  2329. CDIEff_IsValidAbsoluteTsd(LPCDIEFFECT peff, DWORD cAxes)
  2330. {
  2331. HRESULT hres;
  2332. cAxes;
  2333. /*
  2334. * Unlike other effects, "overgain" is not permitted for absolute effects.
  2335. */
  2336. if (peff->cbTypeSpecificParams == cbX(DIABSOLUTE))
  2337. {
  2338. LPCDIABSOLUTE pabs = peff->lpvTypeSpecificParams;
  2339. if( fInOrder( -10000, pabs->lTarget, 10000 ) )
  2340. {
  2341. hres = S_OK;
  2342. }
  2343. else
  2344. {
  2345. RPF("ERROR: IDirectInputEffect::SetParameters: "
  2346. "DIABSOLUTE.lTarget %d not in range -10000 to 100000",
  2347. pabs->lTarget );
  2348. hres = E_INVALIDARG;
  2349. }
  2350. } else {
  2351. hres = E_INVALIDARG;
  2352. }
  2353. return hres;
  2354. }
  2355. /*****************************************************************************
  2356. *
  2357. * @doc INTERNAL
  2358. *
  2359. * @func HRESULT | CDIEff_IsValidBumpForceTsd |
  2360. *
  2361. * Verify that the buffer is a valid
  2362. * <t DIBUMPFORCE> structure.
  2363. *
  2364. * @parm LPCDIEFFECT | peff |
  2365. *
  2366. * Structure that contains effect information.
  2367. * The type-specific parameters have already been validated
  2368. * for access.
  2369. *
  2370. * @parm DWORD | cAxes |
  2371. *
  2372. * Number of axes associated with the type-specific parameters.
  2373. *
  2374. * @returns
  2375. *
  2376. * Returns a COM error code. The following error codes are
  2377. * intended to be illustrative and not necessarily comprehensive.
  2378. *
  2379. * <c DI_OK> = <c S_OK>: The operation completed successfully.
  2380. *
  2381. * <c DIERR_INVALIDPARAM> = <c E_INVALIDARG>: At least one
  2382. * of the parameters is invalid.
  2383. *
  2384. *****************************************************************************/
  2385. STDMETHODIMP
  2386. CDIEff_IsValidBumpForceTsd(LPCDIEFFECT peff, DWORD cAxes)
  2387. {
  2388. HRESULT hres;
  2389. cAxes;
  2390. if (peff->cbTypeSpecificParams == cbX(DIBUMPFORCE)) {
  2391. LPCDIBUMPFORCE pbf = peff->lpvTypeSpecificParams;
  2392. if (pbf->cChannels == 0) {
  2393. RPF("ERROR: IDirectInputEffect::SetParameters: "
  2394. "DIBUMPFORCE.cChannels == 0 is invalid");
  2395. hres = E_INVALIDARG;
  2396. } else if (pbf->cSamples % pbf->cChannels != 0) {
  2397. RPF("ERROR: IDirectInputEffect::SetParameters: "
  2398. "DIBUMPFORCE.cSamples must be multiple of "
  2399. "DIBUMPFORCE.cChannels");
  2400. hres = E_INVALIDARG;
  2401. } else if (IsBadReadPtr(pbf->rglForceData,
  2402. cbCxX(pbf->cSamples, LONG))) {
  2403. RPF("ERROR: IDirectInputEffect::SetParameters: "
  2404. "DIBUMPFORCE.rglForceData invalid");
  2405. hres = E_INVALIDARG;
  2406. } else {
  2407. hres = S_OK;
  2408. }
  2409. } else {
  2410. hres = E_INVALIDARG;
  2411. }
  2412. return hres;
  2413. }
  2414. /*****************************************************************************
  2415. *
  2416. * @doc INTERNAL
  2417. *
  2418. * @func HRESULT | CDIEff_IsValidConditionExTsd |
  2419. *
  2420. * Verify that the buffer is a valid
  2421. * <t DICONDITIONEX> structure.
  2422. *
  2423. * @parm LPCDIEFFECT | peff |
  2424. *
  2425. * Structure that contains effect information.
  2426. * The type-specific parameters have already been validated
  2427. * for access.
  2428. *
  2429. * @parm DWORD | cAxes |
  2430. *
  2431. * Number of axes associated with the type-specific parameters.
  2432. *
  2433. * @returns
  2434. *
  2435. * Returns a COM error code. The following error codes are
  2436. * intended to be illustrative and not necessarily comprehensive.
  2437. *
  2438. * <c DI_OK> = <c S_OK>: The operation completed successfully.
  2439. *
  2440. * <c DIERR_INVALIDPARAM> = <c E_INVALIDARG>: At least one
  2441. * of the parameters is invalid.
  2442. *
  2443. *****************************************************************************/
  2444. STDMETHODIMP
  2445. CDIEff_IsValidConditionExTsd(LPCDIEFFECT peff, DWORD cAxes)
  2446. {
  2447. HRESULT hres;
  2448. /*
  2449. * Extended conditions, like conditions are weird.
  2450. * The size of the type-specific data
  2451. * must be equal to cAxes * cbX(DICONDITIONEX) or equal to
  2452. * exactly one cbX(DICONDITIONEX), depending on whether you want
  2453. * multiple conditions on multiple axes or a single condition
  2454. * rotated across multiple axes.
  2455. *
  2456. * Note that we do not enforce that the parameters are in range;
  2457. * this allows for "overgain"-type behaviors.
  2458. */
  2459. if (peff->cbTypeSpecificParams == cbX(DICONDITIONEX) ||
  2460. peff->cbTypeSpecificParams == cAxes * cbX(DICONDITIONEX)) {
  2461. hres = S_OK;
  2462. } else {
  2463. RPF("IDirectInputEffect::SetParameters: "
  2464. "Size of type-specific data (%d) "
  2465. "not compatible with number of axes (%d)",
  2466. peff->cbTypeSpecificParams, cAxes);
  2467. hres = E_INVALIDARG;
  2468. }
  2469. return hres;
  2470. }
  2471. #endif /* DIRECTINPUT_VERSION >= 0x0800 */
  2472. /*****************************************************************************
  2473. *
  2474. * @doc INTERNAL
  2475. *
  2476. * @func HRESULT | hresFullValidPeff |
  2477. *
  2478. * Verify that the recipient buffer contains valid information.
  2479. *
  2480. * @cwrap PDE | this
  2481. *
  2482. * @parm LPCDIEFFECT | peff |
  2483. *
  2484. * Structure that contains effect information. It has
  2485. * already been validate in size and for general readability.
  2486. *
  2487. * @parm DWORD | fl |
  2488. *
  2489. * Zero or more <c DIEP_*> flags specifying which
  2490. * portions of the effect information should be validated.
  2491. *
  2492. * @returns
  2493. *
  2494. * Returns a COM error code. The following error codes are
  2495. * intended to be illustrative and not necessarily comprehensive.
  2496. *
  2497. * <c DI_OK> = <c S_OK>: The operation completed successfully.
  2498. *
  2499. * <c DIERR_INVALIDPARAM> = <c E_INVALIDARG>: At least one
  2500. * of the parameters is invalid.
  2501. *
  2502. *****************************************************************************/
  2503. #ifndef XDEBUG
  2504. #define hresFullValidPeff_(this, peff, fl, z, i) \
  2505. _hresFullValidPeff_(this, peff, fl) \
  2506. #endif
  2507. #define hresFullValidPeff(this, peff, fl, iarg) \
  2508. hresFullValidPeff_(this, peff, fl, s_szProc, iarg) \
  2509. HRESULT INTERNAL
  2510. hresFullValidPeff_(PDE this, LPCDIEFFECT peff, DWORD fl,
  2511. LPCSTR s_szProc, int iarg)
  2512. {
  2513. HRESULT hres;
  2514. DWORD cAxes;
  2515. AssertF(CDIDev_InCrit(this->pdev));
  2516. /*
  2517. * You can't set the parameters of a nonexistent effect.
  2518. */
  2519. if (!this->fInitialized) {
  2520. hres = DIERR_NOTINITIALIZED;
  2521. goto done;
  2522. }
  2523. /*
  2524. * Flags are always validated.
  2525. */
  2526. if (peff->dwFlags & ~DIEFF_VALID) {
  2527. RPF("ERROR %s: arg %d: Invalid flags specific parms in DIEFFECT",
  2528. s_szProc, iarg);
  2529. hres = E_INVALIDARG;
  2530. goto done;
  2531. }
  2532. /*
  2533. * If setting something that requires object ids or offsets,
  2534. * make sure the caller picks one or the other.
  2535. */
  2536. if (fl & DIEP_USESOBJECTS) {
  2537. switch (peff->dwFlags & DIEFF_OBJECTMASK) {
  2538. case DIEFF_OBJECTIDS:
  2539. case DIEFF_OBJECTOFFSETS:
  2540. break;
  2541. default:
  2542. RPF("ERROR %s: arg %d: Must specify one of "
  2543. "DIEFF_OBJECTIDS or DIEFF_OBJECTOFFSETS", s_szProc, iarg);
  2544. hres = E_INVALIDARG;
  2545. goto done;
  2546. }
  2547. }
  2548. /*
  2549. * If setting something that requires direction coordinates,
  2550. * make sure the caller picks exactly one.
  2551. */
  2552. if (fl & DIEP_USESCOORDS) {
  2553. switch (peff->dwFlags & DIEFF_COORDMASK) {
  2554. case DIEFF_CARTESIAN:
  2555. case DIEFF_SPHERICAL:
  2556. break;
  2557. /*
  2558. * Polar coordinates mandate two (and only two) axes.
  2559. */
  2560. case DIEFF_POLAR:
  2561. if (peff->cAxes != 2) {
  2562. RPF("ERROR %s: arg %d: DIEFF_POLAR requires DIEFFECT.cAxes=2",
  2563. s_szProc, 1);
  2564. hres = E_INVALIDARG;
  2565. goto done;
  2566. }
  2567. break;
  2568. default:
  2569. RPF("ERROR %s: arg %d: Must specify one of "
  2570. "DIEFF_CARTESIAN, DIEFF_POLAR, or DIEFF_SPHERICAL",
  2571. s_szProc, iarg);
  2572. hres = E_INVALIDARG;
  2573. goto done;
  2574. }
  2575. }
  2576. /*
  2577. * DIEP_DURATION
  2578. * DIEP_SAMPLEPERIOD
  2579. * DIEP_GAIN
  2580. * DIEP_TRIGGERBUTTON
  2581. * - Simple dwords. No extra validation needed.
  2582. */
  2583. /*
  2584. * DIEP_AXES
  2585. * DIEP_DIRECTION
  2586. * - The buffers must be of necessary size.
  2587. *
  2588. * We will validate the other goo later, because there
  2589. * are annoying interactions between them.
  2590. */
  2591. AssertF(fLeqvFF(this->effDev.cAxes == 0, this->diepUnset & DIEP_AXES));
  2592. cAxes = this->effDev.cAxes;
  2593. if (fl & (DIEP_AXES | DIEP_DIRECTION)) {
  2594. /*
  2595. * The number of axes had better not be zero.
  2596. */
  2597. if (peff->cAxes == 0) {
  2598. RPF("ERROR %s: arg %d: DIEFFECT.cAxes = 0 is invalid",
  2599. s_szProc, iarg);
  2600. hres = E_INVALIDARG;
  2601. goto done;
  2602. }
  2603. /*
  2604. * And it better not be too big either.
  2605. */
  2606. if (peff->cAxes > DIEFFECT_MAXAXES) {
  2607. RPF("ERROR %s: arg %d: DIEFFECT.cAxes = %d is too large (max %d)",
  2608. s_szProc, iarg, peff->cAxes, DIEFFECT_MAXAXES);
  2609. hres = E_INVALIDARG;
  2610. goto done;
  2611. }
  2612. if (fl & DIEP_AXES) {
  2613. /*
  2614. * If the axes have already been set (which we know because
  2615. * this->effDev.cAxes will be nonzero), then don't
  2616. * let the caller change them.
  2617. */
  2618. if (this->effDev.cAxes) {
  2619. RPF("ERROR %s: arg %d: Cannot change axes once set",
  2620. s_szProc, iarg);
  2621. hres = DIERR_ALREADYINITIALIZED;
  2622. goto done;
  2623. }
  2624. cAxes = peff->cAxes;
  2625. if (IsBadReadPtr(peff->rgdwAxes, cbCdw(peff->cAxes))) {
  2626. RPF("ERROR %s: arg %d: Invalid rgdwAxes in DIEFFECT",
  2627. s_szProc, iarg);
  2628. hres = E_INVALIDARG;
  2629. goto done;
  2630. }
  2631. }
  2632. if (fl & DIEP_DIRECTION) {
  2633. /*
  2634. * We want to disallow cAxes == 0 as well,
  2635. * but we get that for free because
  2636. * peff->cAxes != cAxes, and peff->cAxes is already
  2637. * validated as nonzero.
  2638. */
  2639. if (peff->cAxes != cAxes) {
  2640. if (cAxes) {
  2641. RPF("ERROR %s: arg %d: Wrong number of DIEFFECT.cAxes",
  2642. s_szProc, 1);
  2643. } else {
  2644. RPF("ERROR %s: arg %d: "
  2645. "Must set number of axes before directions", s_szProc);
  2646. }
  2647. hres = E_INVALIDARG;
  2648. goto done;
  2649. }
  2650. /*
  2651. * Direction validation should've already checked above.
  2652. */
  2653. AssertF(fLimpFF(peff->dwFlags & DIEFF_POLAR, peff->cAxes == 2));
  2654. if (IsBadReadPtr(peff->rglDirection, cbCdw(peff->cAxes))) {
  2655. RPF("ERROR %s: arg %d: Invalid rglDirection in DIEFFECT",
  2656. s_szProc, iarg);
  2657. hres = E_INVALIDARG;
  2658. goto done;
  2659. }
  2660. }
  2661. }
  2662. /*
  2663. * DIEP_TYPESPECIFICPARAMS
  2664. * - Validate that the buffer is valid
  2665. * and passes type-specific tests.
  2666. *
  2667. * This must be done after axes so we know how many
  2668. * axes there are.
  2669. */
  2670. AssertF(this->hresValidTsd);
  2671. if (fl & DIEP_TYPESPECIFICPARAMS) {
  2672. hres = hresFullValidReadPvCb(peff->lpvTypeSpecificParams,
  2673. peff->cbTypeSpecificParams, iarg);
  2674. if (FAILED(hres)) {
  2675. RPF("ERROR %s: arg %d: Invalid pointer in "
  2676. "DIEFFECT.lpvTypeSpecificParams",
  2677. s_szProc, iarg);
  2678. hres = E_INVALIDARG;
  2679. goto done;
  2680. }
  2681. hres = this->hresValidTsd(peff, cAxes);
  2682. if (FAILED(hres)) {
  2683. RPF("ERROR %s: arg %d: Invalid type-specific data",
  2684. s_szProc, iarg);
  2685. goto done;
  2686. }
  2687. }
  2688. /*
  2689. * DIEP_ENVELOPE - The pointer must be valid if present.
  2690. */
  2691. if ((fl & DIEP_ENVELOPE) &&
  2692. peff->lpEnvelope &&
  2693. FAILED(hres = hresFullValidReadPxCb(peff->lpEnvelope,
  2694. DIENVELOPE, iarg))) {
  2695. RPF("ERROR %s: arg %d: Invalid lpEnvelope in DIEFFECT",
  2696. s_szProc, iarg);
  2697. hres = E_INVALIDARG;
  2698. goto done;
  2699. }
  2700. hres = S_OK;
  2701. done:;
  2702. return hres;
  2703. }
  2704. /*****************************************************************************
  2705. *
  2706. * @doc INTERNAL
  2707. *
  2708. * @method HRESULT | CDIEff | TryTriggerButton |
  2709. *
  2710. * Set information about the trigger button for an effect into the
  2711. * temporary buffer.
  2712. *
  2713. * @cwrap PDE | this
  2714. *
  2715. * @parm LPCDIEFFECT | peff |
  2716. *
  2717. * Structure that contains effect information.
  2718. *
  2719. * @returns
  2720. *
  2721. * Returns a COM error code. The following error codes are
  2722. * intended to be illustrative and not necessarily comprehensive.
  2723. *
  2724. * <c DI_OK> = <c S_OK>: The operation completed successfully.
  2725. *
  2726. * <c DIERR_INVALIDPARAM> = <c E_INVALIDARG>: At least one
  2727. * of the parameters is invalid.
  2728. *
  2729. *****************************************************************************/
  2730. #ifndef XDEBUG
  2731. #define CDIEff_TryTriggerButton_(this, peff, z, iarg) \
  2732. _CDIEff_TryTriggerButton_(this, peff) \
  2733. #endif
  2734. #define CDIEff_TryTriggerButton(this, peff, iarg) \
  2735. CDIEff_TryTriggerButton_(this, peff, s_szProc, iarg) \
  2736. STDMETHODIMP
  2737. CDIEff_TryTriggerButton_(PDE this, LPCDIEFFECT peff, LPCSTR s_szProc, int iarg)
  2738. {
  2739. HRESULT hres;
  2740. AssertF(CDIDev_InCrit(this->pdev));
  2741. /*
  2742. * We can copy directly in, because if something goes wrong,
  2743. * we just throw away effTry without damaging effDev.
  2744. */
  2745. this->effTry.dwTriggerButton = peff->dwTriggerButton;
  2746. if (fLimpFF(this->effTry.dwTriggerButton != DIEB_NOTRIGGER,
  2747. SUCCEEDED(hres = CDIEff_MapDwords(this, peff->dwFlags, 1,
  2748. &this->effTry.dwTriggerButton,
  2749. &this->effTry.dwTriggerButton,
  2750. DEVCO_BUTTON |
  2751. DEVCO_FFEFFECTTRIGGER |
  2752. DEVCO_TOID)))) {
  2753. hres = S_OK;
  2754. } else {
  2755. RPF("ERROR %s: Invalid button identifier/offset "
  2756. "or button is not DIEB_NOTRIGGER",
  2757. s_szProc);
  2758. }
  2759. return hres;
  2760. }
  2761. /*****************************************************************************
  2762. *
  2763. * @doc INTERNAL
  2764. *
  2765. * @method HRESULT | CDIEff | TryAxis |
  2766. *
  2767. * Set information about the axes of an effect into the
  2768. * temporary buffer. Note that since you can't change the
  2769. * axes once they've been set, we can put our try directly
  2770. * into the final buffer.
  2771. *
  2772. * The only tricky thing is making sure no axes are repeated
  2773. * in the array.
  2774. *
  2775. * @cwrap PDE | this
  2776. *
  2777. * @parm LPCDIEFFECT | peff |
  2778. *
  2779. * Structure that contains effect information.
  2780. *
  2781. * @returns
  2782. *
  2783. * Returns a COM error code. The following error codes are
  2784. * intended to be illustrative and not necessarily comprehensive.
  2785. *
  2786. * <c DI_OK> = <c S_OK>: The operation completed successfully.
  2787. *
  2788. * <c DIERR_INVALIDPARAM> = <c E_INVALIDARG>: At least one
  2789. * of the parameters is invalid.
  2790. *
  2791. *****************************************************************************/
  2792. #ifndef XDEBUG
  2793. #define CDIEff_TryAxis_(this, peff, z, iarg) \
  2794. _CDIEff_TryAxis_(this, peff) \
  2795. #endif
  2796. #define CDIEff_TryAxis(this, peff, iarg) \
  2797. CDIEff_TryAxis_(this, peff, s_szProc, iarg) \
  2798. STDMETHODIMP
  2799. CDIEff_TryAxis_(PDE this, LPCDIEFFECT peff, LPCSTR s_szProc, int iarg)
  2800. {
  2801. HRESULT hres;
  2802. UINT idw;
  2803. AssertF(CDIDev_InCrit(this->pdev));
  2804. /*
  2805. * You can change the axes only once. Therefore, rgdwAxes
  2806. * always points to this->rgdwAxes.
  2807. */
  2808. AssertF(this->effDev.cAxes == 0);
  2809. AssertF(this->effTry.cAxes == 0);
  2810. AssertF(this->effDev.rgdwAxes == this->effTry.rgdwAxes);
  2811. AssertF(this->effTry.rgdwAxes == this->rgdwAxes);
  2812. hres = CDIEff_MapDwords(this, peff->dwFlags, peff->cAxes,
  2813. this->effTry.rgdwAxes, peff->rgdwAxes,
  2814. DEVCO_AXIS | DEVCO_FFACTUATOR | DEVCO_TOID);
  2815. if (FAILED(hres)) {
  2816. RPF("ERROR %s: Invalid axis identifiers/offsets"
  2817. "or axes are not all DIDFT_FFACTUATOR", s_szProc);
  2818. goto done;
  2819. }
  2820. /*
  2821. * Make sure there are no dups in the axis list.
  2822. *
  2823. * The outer loop starts at 1 because the 0'th axis
  2824. * can't possibly conflict with any others.
  2825. */
  2826. for (idw = 1; idw < peff->cAxes; idw++) {
  2827. DWORD idwT;
  2828. for (idwT = 0; idwT < idw; idwT++) {
  2829. if (this->effTry.rgdwAxes[idw] == this->effTry.rgdwAxes[idwT]) {
  2830. RPF("ERROR %s: arg %d: Duplicate axes in axis array",
  2831. s_szProc, iarg);
  2832. hres = E_INVALIDARG;
  2833. goto done;
  2834. }
  2835. }
  2836. }
  2837. this->effTry.cAxes = peff->cAxes;
  2838. done:;
  2839. return hres;
  2840. }
  2841. /*****************************************************************************
  2842. *
  2843. * @doc INTERNAL
  2844. *
  2845. * @method HRESULT | CDIEff | TryDirection |
  2846. *
  2847. * Set information about the direction of an effect into the
  2848. * temporary buffer.
  2849. *
  2850. * This is particularly gruesome, because we need to keep
  2851. * two sets of books: The values passed by the app (which
  2852. * we regurgitate back when queried) and the values passed
  2853. * to the driver.
  2854. *
  2855. * We must keep two sets of books, because I just know
  2856. * that some apps are going to act up if the
  2857. * parameters they read back do not <y exactly> match
  2858. * the values they set in. For example, they might
  2859. * read the value, subtract five, and write it back.
  2860. * Due to rounding, <y n> and <y n>-5 have the same
  2861. * value in the driver, so if we translated down and
  2862. * back, the value wouldn't change, and the app would
  2863. * get stuck in an infinite loop.
  2864. *
  2865. * @cwrap PDE | this
  2866. *
  2867. * @parm LPCDIEFFECT | peff |
  2868. *
  2869. * Structure that contains effect information.
  2870. *
  2871. * @returns
  2872. *
  2873. * Returns a COM error code. The following error codes are
  2874. * intended to be illustrative and not necessarily comprehensive.
  2875. *
  2876. * <c DI_OK> = <c S_OK>: The operation completed successfully.
  2877. *
  2878. * <c DIERR_INVALIDPARAM> = <c E_INVALIDARG>: At least one
  2879. * of the parameters is invalid.
  2880. *
  2881. *****************************************************************************/
  2882. #ifndef XDEBUG
  2883. #define CDIEff_TryDirection_(this, peff, z, iarg) \
  2884. _CDIEff_TryDirection_(this, peff) \
  2885. #endif
  2886. #define CDIEff_TryDirection(this, peff, iarg) \
  2887. CDIEff_TryDirection_(this, peff, s_szProc, iarg) \
  2888. STDMETHODIMP
  2889. CDIEff_TryDirection_(PDE this, LPCDIEFFECT peff, LPCSTR s_szProc, int iarg)
  2890. {
  2891. HRESULT hres;
  2892. DWORD dieffRc;
  2893. AssertF(CDIDev_InCrit(this->pdev));
  2894. /*
  2895. * These should've been caught by validation.
  2896. */
  2897. AssertF(this->effTry.cAxes);
  2898. AssertF(peff->cAxes == this->effTry.cAxes);
  2899. AssertF(fLimpFF(peff->dwFlags & DIEFF_POLAR, peff->cAxes == 2));
  2900. /*
  2901. * Translate the coordinates into device coordinates.
  2902. */
  2903. AssertF((this->dwCoords & ~DIEFF_COORDMASK) == 0);
  2904. AssertF(this->dwCoords);
  2905. this->effTry.rglDirection = this->rglDirTry;
  2906. dieffRc = CDIEff_ConvertDirection(
  2907. this->effTry.cAxes,
  2908. this->rglDirTry, this->dwCoords,
  2909. peff->rglDirection, peff->dwFlags & DIEFF_COORDMASK);
  2910. AssertF(dieffRc);
  2911. this->effTry.dwFlags = (this->effTry.dwFlags & ~DIEFF_COORDMASK) | dieffRc;
  2912. hres = S_OK;
  2913. return hres;
  2914. }
  2915. /*****************************************************************************
  2916. *
  2917. * @doc EXTERNAL
  2918. *
  2919. * @method void | CDIEff | TryParameters |
  2920. *
  2921. * Build the Try structure based on the new parameters.
  2922. *
  2923. * @cwrap PDE | this
  2924. *
  2925. * @parm LPCDIEFFECT | peff |
  2926. *
  2927. * The original effect structure passed by the application.
  2928. *
  2929. * @parm DWORD | fl |
  2930. *
  2931. * The <c DIEP_*> flags which specify what changed.
  2932. *
  2933. *****************************************************************************/
  2934. HRESULT INTERNAL
  2935. CDIEff_TryParameters(PDE this, LPCDIEFFECT peff, DWORD fl)
  2936. {
  2937. HRESULT hres = S_OK;
  2938. EnterProcR(IDirectInputEffect::SetParameters, (_ "ppx", this, peff, fl));
  2939. AssertF(this->lpvTSP == 0);
  2940. /*
  2941. * Copy the current device parameters so we
  2942. * can modify the copy without damaging the original.
  2943. */
  2944. this->effTry = this->effDev;
  2945. /*
  2946. * Install the appropriate effect parameters.
  2947. */
  2948. if (fl & DIEP_DURATION) {
  2949. this->effTry.dwDuration = peff->dwDuration;
  2950. }
  2951. if (fl & DIEP_SAMPLEPERIOD) {
  2952. this->effTry.dwSamplePeriod = peff->dwSamplePeriod;
  2953. }
  2954. if (fl & DIEP_GAIN) {
  2955. this->effTry.dwGain = peff->dwGain;
  2956. }
  2957. #if DIRECTINPUT_VERSION >= 0x0600
  2958. if (fl & DIEP_STARTDELAY) {
  2959. this->effTry.dwStartDelay = peff->dwStartDelay;
  2960. }
  2961. #endif
  2962. if (fl & DIEP_TRIGGERBUTTON) {
  2963. hres = CDIEff_TryTriggerButton(this, peff, 1);
  2964. if (FAILED(hres)) {
  2965. goto done;
  2966. }
  2967. }
  2968. if (fl & DIEP_TRIGGERREPEATINTERVAL) {
  2969. this->effTry.dwTriggerRepeatInterval =
  2970. peff->dwTriggerRepeatInterval;
  2971. }
  2972. if (fl & DIEP_TYPESPECIFICPARAMS) {
  2973. this->effTry.cbTSP = peff->cbTSP;
  2974. this->effTry.lpvTSP = peff->lpvTSP;
  2975. /*
  2976. * Preallocate memory to hold the type-specific parameters
  2977. * to make sure we can proceed on success.
  2978. */
  2979. if (this->effDev.cbTSP != this->effTry.cbTSP) {
  2980. hres = AllocCbPpv(this->effTry.cbTSP, &this->lpvTSP);
  2981. if (FAILED(hres)) {
  2982. goto done;
  2983. }
  2984. }
  2985. }
  2986. /*
  2987. * Must do axes before directions because directions
  2988. * depends on the number of axes.
  2989. */
  2990. if (fl & DIEP_AXES) {
  2991. hres = CDIEff_TryAxis(this, peff, 1);
  2992. if (FAILED(hres)) {
  2993. goto done;
  2994. }
  2995. }
  2996. if (fl & DIEP_DIRECTION) {
  2997. hres = CDIEff_TryDirection(this, peff, 1);
  2998. if (FAILED(hres)) {
  2999. goto done;
  3000. }
  3001. }
  3002. if (fl & DIEP_ENVELOPE) {
  3003. this->effTry.lpEnvelope = peff->lpEnvelope;
  3004. }
  3005. done:;
  3006. ExitOleProc();
  3007. return hres;
  3008. }
  3009. /*****************************************************************************
  3010. *
  3011. * @doc EXTERNAL
  3012. *
  3013. * @method void | CDIEff | SaveTry |
  3014. *
  3015. * A Try'd effect worked. Save its parameters in the
  3016. * driver parameter cache.
  3017. *
  3018. * @cwrap PDE | this
  3019. *
  3020. * @parm LPCDIEFFECT | peff |
  3021. *
  3022. * The original effect structure passed by the application.
  3023. *
  3024. * @parm DWORD | fl |
  3025. *
  3026. * The <c DIEP_*> flags which specify what changed.
  3027. *
  3028. *****************************************************************************/
  3029. void INTERNAL
  3030. CDIEff_SaveTry(PDE this, LPCDIEFFECT peff, DWORD fl)
  3031. {
  3032. /*
  3033. * For the easy stuff, just copy them blindly.
  3034. * It doesn't hurt to copy something that didn't change.
  3035. */
  3036. this->effDev.dwDuration = this->effTry.dwDuration;
  3037. this->effDev.dwSamplePeriod = this->effTry.dwSamplePeriod;
  3038. this->effDev.dwGain = this->effTry.dwGain;
  3039. this->effDev.dwTriggerButton = this->effTry.dwTriggerButton;
  3040. this->effDev.dwTriggerRepeatInterval = this->effTry.dwTriggerRepeatInterval;
  3041. #if DIRECTINPUT_VERSION >= 0x0600
  3042. this->effDev.dwStartDelay = this->effTry.dwStartDelay;
  3043. #endif
  3044. /*
  3045. * Axes count as "easy" because CDIEff_TryAxes put the
  3046. * axis info directly into this->rgdwAxes.
  3047. */
  3048. this->effDev.cAxes = this->effTry.cAxes;
  3049. /*
  3050. * Now the hard parts: The things that require
  3051. * memory allocation or block copying.
  3052. */
  3053. if (fl & DIEP_TYPESPECIFICPARAMS) {
  3054. if (this->effDev.cbTSP == this->effTry.cbTSP) {
  3055. AssertF(this->lpvTSP == 0);
  3056. } else {
  3057. AssertF(this->lpvTSP);
  3058. this->effDev.cbTSP = this->effTry.cbTSP;
  3059. FreePpv(&this->effDev.lpvTSP);
  3060. this->effDev.lpvTSP = this->lpvTSP;
  3061. this->lpvTSP = 0;
  3062. }
  3063. CopyMemory(this->effDev.lpvTSP, this->effTry.lpvTSP,
  3064. this->effTry.cbTSP);
  3065. }
  3066. if (fl & DIEP_DIRECTION) {
  3067. /*
  3068. * Save the app coordinate and the coordinate system into our cache.
  3069. */
  3070. this->dwDirFlags = peff->dwFlags & DIEFF_COORDMASK;
  3071. CopyMemory(this->rglDirApp, peff->rglDirection,
  3072. cbCdw(this->effDev.cAxes));
  3073. /*
  3074. * And propagate the Try'd coordinates into the Drv coordinates.
  3075. */
  3076. this->effDev.dwFlags= this->effTry.dwFlags;
  3077. CopyMemory(this->rglDirDev, this->rglDirTry, cbX(this->rglDirTry));
  3078. }
  3079. if (fl & DIEP_ENVELOPE) {
  3080. if (this->effTry.lpEnvelope) {
  3081. this->effDev.lpEnvelope = &this->env;
  3082. this->env = *this->effTry.lpEnvelope;
  3083. } else {
  3084. this->effDev.lpEnvelope = 0;
  3085. }
  3086. }
  3087. }
  3088. /*****************************************************************************
  3089. *
  3090. * @doc EXTERNAL
  3091. *
  3092. * @method HRESULT | IDirectInputEffect | SetParameters |
  3093. *
  3094. * Set information about an effect.
  3095. *
  3096. * It is valid to update the parameters of an effect while
  3097. * it is playing. The new parameters take effect immediately
  3098. * upon download if the device supports dynamic updating of effect
  3099. * parameters. The <mf IDirectInputEffect::SetParameters>
  3100. * method automatically downloads the effect, but this behavior
  3101. * can be suppressed by setting the <c DIEP_NODOWNLOAD> flag.
  3102. *
  3103. * If automatic download has been suppressed, then you can
  3104. * manually download the effect by invoking the
  3105. * <mf IDirectInputEffect::Download> method.
  3106. *
  3107. * If the effect is playing while the parameters are changed,
  3108. * then the new parameters take effect as if they were the
  3109. * parameters when the effect started.
  3110. *
  3111. * For example, suppose a periodic effect with a duration
  3112. * of three seconds is started.
  3113. * After two seconds, the direction of the effect is changed.
  3114. * The effect will then continue for one additional second
  3115. * in the new direction. The envelope, phase, amplitude,
  3116. * and other parameters of the effect continue smoothly
  3117. * as if the direction had not changed.
  3118. *
  3119. * In the same scenario, if after two seconds, the duration
  3120. * of the effect were changed to 1.5 seconds, then the effect
  3121. * would stop, because two seconds have already elapsed from
  3122. * the beginning of effect playback.
  3123. *
  3124. * Two additional flags control the download behavior.
  3125. * The <c DIEP_START> flag indicates that the effect should
  3126. * be started (or restarted if it is currently playing) after
  3127. * the parameters are updated. By default, the play state
  3128. * of the effect is not altered.
  3129. *
  3130. * Normally, if the driver cannot update the parameters
  3131. * of a playing effect, it is permitted to stop the effect,
  3132. * update the parameters, and then restart the effect.
  3133. * Passing the <c DIEP_NORESTART> flag suppresses this
  3134. * behavior. If the driver cannot update the parameters
  3135. * of an effect while it is playing, the error code
  3136. * <c DIERR_EFFECTPLAYING> is returned and the parameters
  3137. * are not updated.
  3138. *
  3139. * To summarize the behavior of the three flags that control
  3140. * download and playback behavior:
  3141. *
  3142. * If <c DIEP_NODOWNLOAD> is set, then the effect parameters
  3143. * are updated but not downloaded to the device.
  3144. *
  3145. * Otherwise, the <c DIEP_NODOWNLOAD> flag is clear.
  3146. *
  3147. * If the <c DIEP_START> flag is set, then the effect
  3148. * parameters are updated and downloaded to the device,
  3149. * and the effect is started,
  3150. * as if the <mf IDirectInputEffect::Start> method were
  3151. * called. Combining the update with <c DIEP_START> is
  3152. * slightly faster than calling
  3153. * <mf IDirectInputEffect::Start> separately, because
  3154. * it requires less information to be transmitted to the
  3155. * device.
  3156. *
  3157. * Otherwise, both the <c DIEP_NODOWNLOAD> and
  3158. * <c DIEP_START> flags are clear.
  3159. *
  3160. * If the effect is not playing, then the parameters
  3161. * are updated and downloaded to the device.
  3162. *
  3163. * Otherwise, both the <c DIEP_NODOWNLOAD> and
  3164. * <c DIEP_START> flags are clear, and the effect is
  3165. * already playing.
  3166. *
  3167. * If the parameters of the effect can be updated
  3168. * "on the fly", then the update is so performed.
  3169. *
  3170. * Otherwise, both the <c DIEP_NODOWNLOAD> and
  3171. * <c DIEP_START> flags are clear, and the effect is
  3172. * already playing, and the parameters cannot be updated
  3173. * while the effect is playing.
  3174. *
  3175. * If the <c DIEP_NORESTART> flag is set, then the
  3176. * error code <c DIERR_EFFECTPLAYING> is returned.
  3177. *
  3178. * Otherwise, all three of the flags
  3179. * <c DIEP_NODOWNLOAD>, <c DIEP_START> and
  3180. * <c DIEP_NORESTART> are clear, and the effect is
  3181. * already playing, and the parameters cannot be
  3182. * updated while the effect is playing.
  3183. *
  3184. * The effect is stopped, the parameters updated, and
  3185. * the effect is restarted. The return code is
  3186. * <c DI_EFFECTRESTARTED>.
  3187. *
  3188. * @cwrap LPDIRECTINPUTEFFECT | lpDirectInputEffect
  3189. *
  3190. * @parm LPCDIEFFECT | peff |
  3191. *
  3192. * Structure that contains effect information.
  3193. * The <e DIEFFECT.dwSize> field must be filled in by
  3194. * the application before calling this function, as well
  3195. * as any fields specified by corresponding bits in
  3196. * the <p dwFlags> parameter.
  3197. *
  3198. * @parm DWORD | dwFlags |
  3199. *
  3200. * Zero or more <c DIEP_*> flags specifying which
  3201. * portions of the effect information is to be set
  3202. * and how the downloading of the effect parameters
  3203. * should be handled.
  3204. *
  3205. * @returns
  3206. *
  3207. * Returns a COM error code. The following error codes are
  3208. * intended to be illustrative and not necessarily comprehensive.
  3209. *
  3210. * <c DI_OK> = <c S_OK>: The operation completed successfully.
  3211. *
  3212. * <c DI_NOTDOWNLOADED>: The parameters of the effect were
  3213. * successfully
  3214. * updated, but the effect could not be downloaded because
  3215. * the associated device is not acquired in exclusive mode.
  3216. * Note that this is a success code, because the
  3217. * parameters were successfully updated.
  3218. *
  3219. * <c DI_TRUNCATED>: The parameters of the effect were
  3220. * successfully updated,
  3221. * but some of the effect parameters were
  3222. * beyond the capabilities of the device and were truncated
  3223. * to the nearest valid value.
  3224. * Note that this is a success code, because the
  3225. * parameters were successfully updated.
  3226. *
  3227. * <c DI_EFFECTRESTARTED>: The parameters of the effect
  3228. * were successfully updated, and the effect was restarted.
  3229. * Note that this is a success code, because the
  3230. * parameters were successfully updated.
  3231. *
  3232. * <c DI_TRUNCATEDANDRESTARTED>: The parameters of the effect
  3233. * were successfully updated, but some of the effect parameters
  3234. * were truncated, and the effect was restarted. This code
  3235. * combines <c DI_TRUNCATED> and <c DI_EFFECTRESTARTED>.
  3236. * Note that this is a success code, because the
  3237. * parameters were successfully updated.
  3238. *
  3239. * <c DIERR_NOTINITIALIZED>: The <i IDirectInputEffect> object
  3240. * has not been initialized.
  3241. *
  3242. * <c DIERR_INVALIDPARAM> = <c E_INVALIDARG>: At least one
  3243. * of the parameters is invalid.
  3244. *
  3245. * <c DIERR_EFFECTPLAYING>: The parameters were not updated
  3246. * because
  3247. * the device does not support updating an effect while
  3248. * it is still playing, and the <c DIEP_NORESTART> flag was
  3249. * passed, prohibiting the driver from stopping the effect,
  3250. * updating its parameters, and restarting it.
  3251. *
  3252. *****************************************************************************/
  3253. STDMETHODIMP
  3254. CDIEff_SetParameters(PDIE pdie, LPCDIEFFECT peff, DWORD fl)
  3255. {
  3256. HRESULT hres;
  3257. EnterProcR(IDirectInputEffect::SetParameters, (_ "ppx", pdie, peff, fl));
  3258. if (SUCCEEDED(hres = hresPv(pdie)) &&
  3259. #if DIRECTINPUT_VERSION >= 0x0600
  3260. SUCCEEDED(hres = hresFullValidReadPxCb2(peff,
  3261. DIEFFECT_DX6,
  3262. DIEFFECT_DX5, 1)) &&
  3263. SUCCEEDED(hres = hresFullValidFl(fl, ((peff->dwSize == cbX(DIEFFECT_DX6))
  3264. ? DIEP_SETVALID : DIEP_SETVALID_DX5 ), 2))) {
  3265. #else
  3266. SUCCEEDED(hres = hresFullValidReadPxCb(peff, DIEFFECT, 1)) &&
  3267. SUCCEEDED(hres = hresFullValidFl(fl, DIEP_SETVALID_DX5, 2))) {
  3268. #endif
  3269. PDE this = _thisPvNm(pdie, def);
  3270. CDIEff_EnterCrit(this);
  3271. if (SUCCEEDED(hres = hresFullValidPeff(this, peff, fl, 1))) {
  3272. BOOL fChangeEmulatedStartDelay = FALSE;
  3273. /*
  3274. * Note that if fl == 0 (or nearly so),
  3275. * TryParameters doesn't do anything,
  3276. * albeit rather inefficiently.
  3277. */
  3278. hres = CDIEff_TryParameters(this, peff, fl);
  3279. if (FAILED(hres)) {
  3280. goto done;
  3281. }
  3282. /*
  3283. * Special case for DIEP_STARTDELAY.
  3284. */
  3285. if (fl & DIEP_STARTDELAY)
  3286. {
  3287. if (this->dEffAttributes.dwStaticParams & DIEP_STARTDELAY)
  3288. {
  3289. /*
  3290. * Driver supports it, so don't worry.
  3291. */
  3292. ;
  3293. }
  3294. else
  3295. {
  3296. /*
  3297. * Driver doesn't support it.
  3298. * Take start delay out...
  3299. */
  3300. fl &= ~(DIEP_STARTDELAY);
  3301. this->diepUnset &= ~(DIEP_STARTDELAY);
  3302. /*
  3303. * ...but remember that we may need to do something
  3304. */
  3305. fChangeEmulatedStartDelay = ( this->effDev.dwStartDelay != this->effTry.dwStartDelay );
  3306. if (fl == 0)
  3307. {
  3308. hres = DI_OK;
  3309. goto save;
  3310. }
  3311. }
  3312. }
  3313. /*
  3314. * Now pass the effTry to the device driver for
  3315. * final validation.
  3316. *
  3317. * Passing fl=0 is a really slow way of downloading
  3318. * the effect, except that we return DI_DOWNLOADSKIPPED
  3319. * instead of an error code if the device is not exclusive
  3320. * acquired.
  3321. *
  3322. * Passing fl=DIEP_NODOWNLOAD is a really slow NOP.
  3323. *
  3324. * Note that inability to download due to lack of
  3325. * proper acquisition is not an error, merely a warning.
  3326. */
  3327. hres = CDIEff_DownloadWorker_(this, &this->effTry, fl, 0);
  3328. AssertF(hres != DIERR_NOTDOWNLOADED);
  3329. /*
  3330. * If the driver approves, then make the changes permanent.
  3331. * but first a check on the emulated driver
  3332. */
  3333. save:;
  3334. if( SUCCEEDED(hres) )
  3335. {
  3336. if( fChangeEmulatedStartDelay )
  3337. {
  3338. /*
  3339. * The start delay for parameter has been changed, so
  3340. * any future iteration is OK also the driver has
  3341. * SUCCEEDED any other changes.
  3342. */
  3343. if( this->dwMessage != EFF_PLAY )
  3344. {
  3345. /*
  3346. * We're not in the delay, so declare everything OK.
  3347. */
  3348. }
  3349. else
  3350. {
  3351. /*
  3352. * If the download was skipped don't bother.
  3353. */
  3354. if( hres != DI_DOWNLOADSKIPPED )
  3355. {
  3356. if( fl & DIEP_NORESTART )
  3357. {
  3358. /*
  3359. * We don't support changing the delay during the
  3360. * delay. Since the driver has already had its
  3361. * parameters changed, only fail this if the
  3362. * delay was the only change requested.
  3363. */
  3364. if( fl == 0 )
  3365. {
  3366. hres = DIERR_EFFECTPLAYING;
  3367. }
  3368. }
  3369. else
  3370. {
  3371. /*
  3372. * Since we don't support modifying the delay
  3373. * whilst we're in it, restart with the new
  3374. * delay.
  3375. * If we were being really smart, we could
  3376. * try to adjust the delay without restarting.
  3377. */
  3378. if( this->hEventDelete && this->hEventGeneral )
  3379. {
  3380. this->dwMessage = EFF_PLAY;
  3381. ResetEvent(this->hEventGeneral);
  3382. SetEvent(this->hEventGeneral);
  3383. if( ( hres & ~DI_TRUNCATEDANDRESTARTED ) == 0 )
  3384. {
  3385. hres |= DI_EFFECTRESTARTED;
  3386. }
  3387. else if( hres == DI_NOEFFECT )
  3388. {
  3389. hres = DI_EFFECTRESTARTED;
  3390. }
  3391. }
  3392. else
  3393. {
  3394. AssertF( !"Effect synchronization event(s) NULL" );
  3395. }
  3396. }
  3397. }
  3398. }
  3399. }
  3400. else
  3401. {
  3402. /*
  3403. * If there was no change to an emulated start delay then
  3404. * the result we have is already what we need.
  3405. */
  3406. }
  3407. }
  3408. if (SUCCEEDED(hres)) {
  3409. this->diepUnset &= ~fl; /* No longer unset */
  3410. /*
  3411. * If we didn't download, then the parameters are
  3412. * dirty and need to be downloaded later.
  3413. */
  3414. if (hres == DI_DOWNLOADSKIPPED) {
  3415. this->diepDirty |= (fl & DIEP_ALLPARAMS);
  3416. }
  3417. CDIEff_SaveTry(this, peff, fl); /* Save permanently */
  3418. }
  3419. done:;
  3420. FreePpv(&this->lpvTSP);
  3421. }
  3422. CDIEff_LeaveCrit(this);
  3423. }
  3424. ExitOleProc();
  3425. return hres;
  3426. }
  3427. /*****************************************************************************
  3428. *
  3429. * @doc INTERNAL
  3430. *
  3431. * @method HRESULT | IDirectInputEffect | RealStart |
  3432. *
  3433. * Actually begin playing an effect. The parent device must
  3434. * be acquired.
  3435. *
  3436. * If the effect is already playing, then it is restarted
  3437. * from the beginning.
  3438. *
  3439. * If the effect has not been downloaded or has been
  3440. * modified since its last download, then it will be
  3441. * downloaded before being started. This default
  3442. * behavior can be suppressed by passing the
  3443. * <c DIES_NODOWNLOAD> flag.
  3444. *
  3445. * @cwrap LPDIRECTINPUTEFFECT | lpDirectInputEffect
  3446. *
  3447. * @parm DWORD | dwIterations |
  3448. *
  3449. * Number of times to play the effect in sequence.
  3450. * The envelope is re-articulated with each iteration.
  3451. *
  3452. * To play the effect exactly once, pass 1.
  3453. *
  3454. * To play the effect repeatedly until explicitly stopped,
  3455. * pass <c INFINITE>.
  3456. *
  3457. * To play the effect until explicitly stopped without
  3458. * re-articulating the envelope, modify the effect
  3459. * parameters via <mf IDirectInputEffect::SetParameters>
  3460. * and change its <e DIEFFECT.dwDuration> to <c INFINITE>.
  3461. *
  3462. * @parm DWORD | dwFlags |
  3463. *
  3464. * Flags that describe how the effect should be played
  3465. * by the device. It can be zero or more of the
  3466. * <c DIES_*> flags.
  3467. *
  3468. * @returns
  3469. *
  3470. * Returns a COM error code. The following error codes are
  3471. * intended to be illustrative and not necessarily comprehensive.
  3472. *
  3473. * <c DI_OK> = <c S_OK>: The operation completed successfully.
  3474. *
  3475. * <c DIERR_NOTINITIALIZED>: The <i IDirectInputEffect> object
  3476. * has not been initialized or no effect parameters have been
  3477. * set.
  3478. *
  3479. * <c DIERR_INVALIDPARAM> = <c E_INVALIDARG>: At least one
  3480. * of the parameters is invalid.
  3481. *
  3482. *****************************************************************************/
  3483. STDMETHODIMP
  3484. CDIEff_RealStart(PDIE pdie, DWORD dwcLoop, DWORD fl)
  3485. {
  3486. HRESULT hres;
  3487. EnterProcR(IDirectInputEffect::Start, (_ "ppx", pdie, dwcLoop, fl));
  3488. if (SUCCEEDED(hres = hresPv(pdie)) &&
  3489. SUCCEEDED(hres = hresFullValidFl(fl, DIES_VALID, 2))) {
  3490. PDE this = _thisPvNm(pdie, def);
  3491. if( SUCCEEDED( hres= (IsBadReadPtr(this, cbX(this))) ? E_POINTER : S_OK ) )
  3492. {
  3493. CDIEff_EnterCrit(this);
  3494. if (SUCCEEDED(hres = CDIEff_CanAccess(this))) {
  3495. if (fl & DIES_NODOWNLOAD) {
  3496. /*
  3497. * App wants fine control. Let him have it.
  3498. */
  3499. hres = IDirectInputEffectShepherd_StartEffect(
  3500. this->pes, &this->sh, fl & DIES_DRIVER, dwcLoop);
  3501. } else {
  3502. /*
  3503. * App wants us to do the work. First thing to do
  3504. * is see if the effect needs to be downloaded.
  3505. *
  3506. * SyncShepHandle checks if the effect is downloaded.
  3507. */
  3508. hres = CDIEff_SyncShepHandle(this);
  3509. if (this->diepDirty == 0 && this->sh.dwEffect) {
  3510. /*
  3511. * Effect is clean and downloaded.
  3512. * Just start it normally.
  3513. */
  3514. hres = IDirectInputEffectShepherd_StartEffect(
  3515. this->pes, &this->sh,
  3516. fl & DIES_DRIVER, dwcLoop);
  3517. } else {
  3518. /*
  3519. * Effect needs to be downloaded. We can
  3520. * optimize it if no special flags are set
  3521. * and the loop count is exactly unity.
  3522. */
  3523. if (fl == 0 && dwcLoop == 1) {
  3524. hres = CDIEff_DownloadWorker(this, &this->effDev,
  3525. DIEP_START);
  3526. } else {
  3527. /*
  3528. * Cannot optimize; must do separate download
  3529. * followed by Start.
  3530. */
  3531. hres = CDIEff_DownloadWorker(this, &this->effDev, 0);
  3532. if (SUCCEEDED(hres)) {
  3533. hres = IDirectInputEffectShepherd_StartEffect(
  3534. this->pes, &this->sh,
  3535. fl & DIES_DRIVER, dwcLoop);
  3536. }
  3537. }
  3538. }
  3539. }
  3540. }
  3541. CDIEff_LeaveCrit(this);
  3542. }
  3543. }
  3544. ExitOleProcR();
  3545. return hres;
  3546. }
  3547. /*****************************************************************************
  3548. *
  3549. * @doc INTERNAL
  3550. *
  3551. * @method DWORD | WINAPI | CDIEff_ThreadProc |
  3552. *
  3553. * Used to simulate dwStartDelay for drivers that do not support it.
  3554. * Begin playing an effect that has already been downloaded. The parent device must
  3555. * be acquired.
  3556. *
  3557. * If the effect is already playing, then it is restarted
  3558. * from the beginning.
  3559. *
  3560. * If the effect has not been downloaded or has been
  3561. * modified since its last download, then it will be
  3562. * downloaded before being started. This default
  3563. * behavior can be suppressed by passing the
  3564. * <c DIES_NODOWNLOAD> flag.
  3565. *
  3566. * After starting the effect, kills the timer whose event activated CDIEff_TimerProc
  3567. *
  3568. *
  3569. * @parm LPVOID | lpParameter |
  3570. *
  3571. * LPDIRECTINPUTEFFECT pointer.
  3572. *
  3573. * @returns
  3574. *
  3575. * 0 if succeeded in starting the effect, or if the effect has been deleted by the app.
  3576. * -1 otherwise
  3577. *
  3578. *****************************************************************************/
  3579. DWORD WINAPI CDIEff_ThreadProc(LPVOID lpParameter)
  3580. {
  3581. LPDIRECTINPUTEFFECT pdie = (LPDIRECTINPUTEFFECT) lpParameter;
  3582. HRESULT hres = E_FAIL;
  3583. DWORD dwWait;
  3584. HANDLE hArray[2];
  3585. BOOL startCalled = FALSE;
  3586. PDE this = _thisPvNm(pdie, def);
  3587. if( SUCCEEDED( hres= (IsBadReadPtr(this, cbX(this))) ? E_POINTER : S_OK ) )
  3588. {
  3589. if( this->hEventDelete != NULL && this->hEventThreadDead != NULL )
  3590. {
  3591. hArray[0] = this->hEventDelete;
  3592. hArray[1] = this->hEventGeneral;
  3593. ResetEvent( this->hEventThreadDead );
  3594. /*
  3595. * Wait till the timeout expires, or till one of the events happens --
  3596. * the effect is deleted by the app (hEventDelete) or the effect is started (hEventStart),
  3597. * or the effect is stopped (hEventStop).
  3598. */
  3599. dwWait = WAIT_TIMEOUT;
  3600. while (dwWait != WAIT_OBJECT_0 && dwWait != WAIT_FAILED)
  3601. {
  3602. if (dwWait == WAIT_TIMEOUT)
  3603. {
  3604. if (startCalled)
  3605. {
  3606. /*
  3607. * Start have been called, and timeout has expired.
  3608. * Start the effect. And wait again.
  3609. */
  3610. hres = CDIEff_RealStart(pdie, this->dwcLoop, this->dwFlags);
  3611. startCalled = FALSE;
  3612. this->dwMessage = EFF_DEFAULT;
  3613. }
  3614. }
  3615. else
  3616. {
  3617. if (dwWait == (WAIT_OBJECT_0 + 1))
  3618. {
  3619. /*
  3620. * App called Start on the effect.
  3621. * Set flag and start waiting anew.
  3622. */
  3623. if (this->dwMessage == EFF_PLAY)
  3624. {
  3625. if ((this->effDev).dwStartDelay/1000 == 0)
  3626. {
  3627. /*
  3628. * If time delay is 0 ms, start immediately.
  3629. */
  3630. hres = CDIEff_RealStart(pdie, this->dwcLoop, this->dwFlags);
  3631. startCalled = FALSE;
  3632. this->dwMessage = EFF_DEFAULT;
  3633. }
  3634. else
  3635. {
  3636. startCalled = TRUE;
  3637. }
  3638. }
  3639. else
  3640. {
  3641. if (this->dwMessage == EFF_STOP)
  3642. {
  3643. startCalled = FALSE;
  3644. this->dwMessage = EFF_DEFAULT;
  3645. }
  3646. }
  3647. ResetEvent(this->hEventGeneral);
  3648. }
  3649. }
  3650. /*
  3651. * And wait again.
  3652. */
  3653. if (startCalled == TRUE) {
  3654. dwWait = WaitForMultipleObjects(2, hArray, FALSE, (this->effDev).dwStartDelay/1000);
  3655. } else {
  3656. dwWait = WaitForMultipleObjects(2, hArray, FALSE, INFINITE);
  3657. }
  3658. }
  3659. SetEvent( this->hEventThreadDead );
  3660. }
  3661. /*
  3662. * App has deleted the effect.
  3663. * Exit.
  3664. */
  3665. hres = DI_OK;
  3666. }
  3667. if (SUCCEEDED(hres))
  3668. return 0;
  3669. else
  3670. return -1;
  3671. }
  3672. /*****************************************************************************
  3673. *
  3674. * @doc EXTERNAL
  3675. *
  3676. * @method HRESULT | IDirectInputEffect | Start |
  3677. *
  3678. * Begin playing an effect. The parent device must
  3679. * be acquired.
  3680. *
  3681. * If the effect is already playing, then it is restarted
  3682. * from the beginning.
  3683. *
  3684. * If the effect has not been downloaded or has been
  3685. * modified since its last download, then it will be
  3686. * downloaded before being started. This default
  3687. * behavior can be suppressed by passing the
  3688. * <c DIES_NODOWNLOAD> flag.
  3689. *
  3690. * @cwrap LPDIRECTINPUTEFFECT | lpDirectInputEffect
  3691. *
  3692. * @parm DWORD | dwIterations |
  3693. *
  3694. * Number of times to play the effect in sequence.
  3695. * The envelope is re-articulated with each iteration.
  3696. *
  3697. * To play the effect exactly once, pass 1.
  3698. *
  3699. * To play the effect repeatedly until explicitly stopped,
  3700. * pass <c INFINITE>.
  3701. *
  3702. * To play the effect until explicitly stopped without
  3703. * re-articulating the envelope, modify the effect
  3704. * parameters via <mf IDirectInputEffect::SetParameters>
  3705. * and change its <e DIEFFECT.dwDuration> to <c INFINITE>.
  3706. *
  3707. * @parm DWORD | dwFlags |
  3708. *
  3709. * Flags that describe how the effect should be played
  3710. * by the device. It can be zero or more of the
  3711. * <c DIES_*> flags.
  3712. *
  3713. * @returns
  3714. *
  3715. * Returns a COM error code. The following error codes are
  3716. * intended to be illustrative and not necessarily comprehensive.
  3717. *
  3718. * <c DI_OK> = <c S_OK>: The operation completed successfully.
  3719. *
  3720. * <c DIERR_NOTINITIALIZED>: The <i IDirectInputEffect> object
  3721. * has not been initialized or no effect parameters have been
  3722. * set.
  3723. *
  3724. * <c DIERR_INVALIDPARAM> = <c E_INVALIDARG>: At least one
  3725. * of the parameters is invalid.
  3726. *
  3727. *****************************************************************************/
  3728. STDMETHODIMP
  3729. CDIEff_Start(PDIE pdie, DWORD dwcLoop, DWORD fl)
  3730. {
  3731. HRESULT hres;
  3732. EnterProcR(IDirectInputEffect::Start, (_ "ppx", pdie, dwcLoop, fl));
  3733. if (SUCCEEDED(hres = hresPv(pdie)) &&
  3734. SUCCEEDED(hres = hresFullValidFl(fl, DIES_VALID, 2))) {
  3735. PDE this = _thisPvNm(pdie, def);
  3736. if( SUCCEEDED( hres= (IsBadReadPtr(this, cbX(this))) ? E_POINTER : S_OK ) )
  3737. {
  3738. CDIEff_EnterCrit(this);
  3739. if (SUCCEEDED(hres = CDIEff_CanAccess(this))) {
  3740. this->dwcLoop = dwcLoop;
  3741. this->dwFlags = fl;
  3742. if (this->hEventDelete == NULL)
  3743. hres = CDIEff_RealStart(pdie, dwcLoop, fl);
  3744. else
  3745. {
  3746. /*
  3747. * Activate the thread's waiting period
  3748. */
  3749. hres = CDIEff_DownloadWorker(this, &this->effDev, 0);
  3750. if (this->hEventGeneral != NULL)
  3751. {
  3752. this->dwMessage = EFF_PLAY;
  3753. ResetEvent(this->hEventGeneral);
  3754. SetEvent(this->hEventGeneral);
  3755. }
  3756. }
  3757. }
  3758. CDIEff_LeaveCrit(this);
  3759. }
  3760. }
  3761. ExitOleProcR();
  3762. return hres;
  3763. }
  3764. /*****************************************************************************
  3765. *
  3766. * @doc EXTERNAL
  3767. *
  3768. * @method HRESULT | IDirectInputEffect | Stop |
  3769. *
  3770. * Stop playing an effect. The parent device must
  3771. * be acquired.
  3772. *
  3773. * @cwrap LPDIRECTINPUTEFFECT | lpDirectInputEffect
  3774. *
  3775. * @returns
  3776. *
  3777. * Returns a COM error code. The following error codes are
  3778. * intended to be illustrative and not necessarily comprehensive.
  3779. *
  3780. * <c DI_OK> = <c S_OK>: The operation completed successfully.
  3781. *
  3782. * <c DIERR_NOTINITIALIZED>: The <i IDirectInputEffect> object
  3783. * has not been initialized or no effect parameters have been
  3784. * set.
  3785. *
  3786. *****************************************************************************/
  3787. STDMETHODIMP
  3788. CDIEff_Stop(PDIE pdie)
  3789. {
  3790. HRESULT hres;
  3791. EnterProcR(IDirectInputEffect::Stop, (_ "p", pdie));
  3792. if (SUCCEEDED(hres = hresPv(pdie))) {
  3793. PDE this = _thisPvNm(pdie, def);
  3794. CDIEff_EnterCrit(this);
  3795. if (SUCCEEDED(hres = CDIEff_CanAccess(this))) {
  3796. hres = IDirectInputEffectShepherd_StopEffect(this->pes, &this->sh);
  3797. }
  3798. if (this->hEventGeneral != NULL)
  3799. {
  3800. this->dwMessage = EFF_STOP;
  3801. ResetEvent(this->hEventGeneral);
  3802. SetEvent(this->hEventGeneral);
  3803. }
  3804. CDIEff_LeaveCrit(this);
  3805. }
  3806. ExitOleProcR();
  3807. return hres;
  3808. }
  3809. /*****************************************************************************
  3810. *
  3811. * @doc EXTERNAL
  3812. *
  3813. * @method HRESULT | IDirectInputEffect | GetEffectStatus |
  3814. *
  3815. * Retrieves the status of an effect.
  3816. *
  3817. * @cwrap LPDIRECTINPUTEFFECT | lpDirectInputEffect
  3818. *
  3819. * @parm LPDWORD | pdwFlags |
  3820. *
  3821. * Receives the status flags for the effect. It may
  3822. * consist of zero or more <c DIEGES_*> flag values.
  3823. *
  3824. * @returns
  3825. *
  3826. * Returns a COM error code. The following error codes are
  3827. * intended to be illustrative and not necessarily comprehensive.
  3828. *
  3829. * <c DI_OK> = <c S_OK>: The operation completed successfully.
  3830. *
  3831. * <c DIERR_NOTINITIALIZED>: The <i IDirectInputEffect> object
  3832. * has not been initialized or no effect parameters have been
  3833. * set.
  3834. *
  3835. * <c DIERR_INVALIDPARAM> = <c E_INVALIDARG>: At least one
  3836. * of the parameters is invalid.
  3837. *
  3838. *****************************************************************************/
  3839. STDMETHODIMP
  3840. CDIEff_GetEffectStatus(PDIE pdie, LPDWORD pdwOut)
  3841. {
  3842. HRESULT hres;
  3843. EnterProcR(IDirectInputEffect::Stop, (_ "p", pdie));
  3844. if (SUCCEEDED(hres = hresPv(pdie)) &&
  3845. SUCCEEDED(hres = hresFullValidPcbOut(pdwOut, cbX(*pdwOut), 1))) {
  3846. PDE this = _thisPvNm(pdie, def);
  3847. CAssertF(DEV_STS_EFFECT_RUNNING == DIEGES_PLAYING);
  3848. CDIEff_EnterCrit(this);
  3849. if (SUCCEEDED(hres = CDIEff_CanAccess(this))) {
  3850. /*
  3851. * Check the dwMessage first --
  3852. * if it says PLAYING, report DIEGES_PLAYING
  3853. */
  3854. if (this->dwMessage == EFF_PLAY)
  3855. {
  3856. *pdwOut = DIEGES_PLAYING;
  3857. hres = DI_OK;
  3858. }
  3859. else
  3860. {
  3861. hres = IDirectInputEffectShepherd_GetEffectStatus(
  3862. this->pes, &this->sh, pdwOut);
  3863. }
  3864. }
  3865. CDIEff_LeaveCrit(this);
  3866. }
  3867. ExitOleProcR();
  3868. return hres;
  3869. }
  3870. /*****************************************************************************
  3871. *
  3872. * @doc EXTERNAL
  3873. *
  3874. * @method HRESULT | IDirectInputEffect | Escape |
  3875. *
  3876. * Send a hardware-specific command to the driver.
  3877. *
  3878. * @cwrap LPDIRECTINPUTEFFECT | lpDirectInputEffect
  3879. *
  3880. * @parm LPDIEFFESCAPE | pesc |
  3881. *
  3882. * Pointer to a <t DIEFFESCAPE> structure which describes
  3883. * the command to be sent. On success, the
  3884. * <e DIEFFESCAPE.cbOutBuffer> field contains the number
  3885. * of bytes of the output buffer actually used.
  3886. *
  3887. * @returns
  3888. *
  3889. * Returns a COM error code. The following error codes are
  3890. * intended to be illustrative and not necessarily comprehensive.
  3891. *
  3892. * <c DI_OK> = <c S_OK>: The operation completed successfully.
  3893. *
  3894. * <c DIERR_NOTDOWNLOADED>: The effect is not downloaded.
  3895. *
  3896. * <c DIERR_NOTINITIALIZED>: The <i IDirectInputEffect> object
  3897. * has not yet been <mf IDirectInputEffect::Initialize>d.
  3898. *
  3899. *****************************************************************************/
  3900. STDMETHODIMP
  3901. CDIEff_Escape(PDIE pdie, LPDIEFFESCAPE pesc)
  3902. {
  3903. HRESULT hres;
  3904. EnterProcR(IDirectInputEffect::Escape, (_ "p", pdie));
  3905. /*
  3906. * The output buffer is NoScramble because some people like
  3907. * to pass overlapping in and out buffers.
  3908. */
  3909. if (SUCCEEDED(hres = hresPv(pdie)) &&
  3910. SUCCEEDED(hres = hresFullValidPesc(pesc, 1))) {
  3911. PDE this = _thisPvNm(pdie, def);
  3912. CDIEff_EnterCrit(this);
  3913. /*
  3914. * Download the effect if it isn't downloaded yet,
  3915. * so we have a valid effect to Escape on.
  3916. */
  3917. hres = CDIEff_DownloadWorker(this, &this->effDev, 0);
  3918. if (SUCCEEDED(hres)) {
  3919. hres = IDirectInputEffectShepherd_Escape(
  3920. this->pes, &this->sh, pesc);
  3921. } else {
  3922. hres = DIERR_NOTDOWNLOADED;
  3923. }
  3924. CDIEff_LeaveCrit(this);
  3925. }
  3926. ExitOleProcR();
  3927. return hres;
  3928. }
  3929. /*****************************************************************************
  3930. *
  3931. * @doc EXTERNAL
  3932. *
  3933. * @method HRESULT | IDirectInputEffect | Initialize |
  3934. *
  3935. * Initialize a DirectInputEffect object.
  3936. *
  3937. * Note that if this method fails, the underlying object should
  3938. * be considered to be an an indeterminate state and needs to
  3939. * be reinitialized before it can be subsequently used.
  3940. *
  3941. * The <mf IDirectInputDevice::CreateEffect> method automatically
  3942. * initializes the device after creating it. Applications
  3943. * normally do not need to call this function.
  3944. *
  3945. * @cwrap LPDIRECTINPUTEFFECT | lpDirectInputEffect
  3946. *
  3947. * @parm IN HINSTANCE | hinst |
  3948. *
  3949. * Instance handle of the application or DLL that is creating
  3950. * the DirectInputEffect object.
  3951. *
  3952. * See the section titled "Initialization and Versions"
  3953. * for more information.
  3954. *
  3955. * @parm DWORD | dwVersion |
  3956. *
  3957. * Version number of the dinput.h header file that was used.
  3958. *
  3959. * See the section titled "Initialization and Versions"
  3960. * for more information.
  3961. *
  3962. * @parm IN REFGUID | rguid |
  3963. *
  3964. * Identifies the effect for which the interface
  3965. * should be associated.
  3966. * The <mf IDirectInputDevice::EnumEffects> method
  3967. * can be used to determine which effect GUIDs are supported by
  3968. * the device.
  3969. *
  3970. * @returns
  3971. * Returns a COM error code. The following error codes are
  3972. * intended to be illustrative and not necessarily comprehensive.
  3973. *
  3974. * <c DI_OK> = <c S_OK>: The operation completed successfully.
  3975. *
  3976. * <c DIERR_DEVICENOTREG>: The effect GUID does not exist
  3977. * on the current device.
  3978. *
  3979. *****************************************************************************/
  3980. #pragma BEGIN_CONST_DATA
  3981. TSDPROC c_rgtsd[] = {
  3982. CDIEff_IsValidConstantTsd, /* DIEFT_CONSTANTFORCE */
  3983. CDIEff_IsValidRampTsd, /* DIEFT_RAMPFORCE */
  3984. CDIEff_IsValidPeriodicTsd, /* DIEFT_PERIODIC */
  3985. CDIEff_IsValidConditionTsd, /* DIEFT_CONDITION */
  3986. CDIEff_IsValidCustomForceTsd, /* DIEFT_CUSTOMFORCE */
  3987. #if DIRECTINPUT_VERSION >= 0x0800
  3988. CDIEff_IsValidRandomTsd, /* DIEFT_RANDOM */
  3989. CDIEff_IsValidAbsoluteTsd, /* DIEFT_ABSOLUTE */
  3990. CDIEff_IsValidBumpForceTsd, /* DIEFT_BUMPFORCE */
  3991. CDIEff_IsValidConditionExTsd, /* DIEFT_CONDITIONEX */
  3992. #endif /* DIRECTINPUT_VERSION >= 0x0800 */
  3993. };
  3994. STDMETHODIMP
  3995. CDIEff_Initialize(PDIE pdie, HINSTANCE hinst, DWORD dwVersion, REFGUID rguid)
  3996. {
  3997. HRESULT hres;
  3998. EnterProcR(IDirectInputEffect::Initialize,
  3999. (_ "pxxG", pdie, hinst, dwVersion, rguid));
  4000. if (SUCCEEDED(hres = hresPv(pdie)) &&
  4001. SUCCEEDED(hres = hresValidInstanceVer(hinst, dwVersion)) &&
  4002. SUCCEEDED(hres = hresFullValidGuid(rguid, 1))) {
  4003. PDE this = _thisPv(pdie);
  4004. EFFECTMAPINFO emi;
  4005. AssertF(this->pes);
  4006. /*
  4007. * Don't let somebody mess with the effect while we're
  4008. * resetting it.
  4009. */
  4010. CDIEff_EnterCrit(this);
  4011. if (SUCCEEDED(hres = CDIDev_FindEffectGUID(this->pdev, rguid,
  4012. &emi, 3)) &&
  4013. SUCCEEDED(hres = CDIEff_Reset(this))) {
  4014. /*
  4015. * ISSUE-2001/03/29-timgill Need to check for actual hardware FF effect support
  4016. */
  4017. /*
  4018. * Initialize dEffAttributes
  4019. */
  4020. this->fInitialized = 1;
  4021. this->dEffAttributes = emi.attr;
  4022. this->guid = *rguid;
  4023. /*
  4024. * Check if the app is using DX6 or above structure.
  4025. * If not, no dwStartDelay is being requested by the app.
  4026. *
  4027. * Check if the driver supports dwStartDelay.
  4028. * If it does, no need for us to do anything in that respect.
  4029. */
  4030. if ((dwVersion < 0x0600) ||
  4031. ((this->dEffAttributes).dwStaticParams & DIEP_STARTDELAY))
  4032. {
  4033. /*
  4034. * No need to emulate dwStartDelay.
  4035. */
  4036. ;
  4037. }
  4038. else
  4039. {
  4040. /*
  4041. * Driver doesn't support start delay.
  4042. * Start a thread that will emulate dwStartDelay.
  4043. */
  4044. DWORD dwThreadId;
  4045. HANDLE hThread;
  4046. this->hEventDelete = CreateEvent(NULL, TRUE, FALSE, NULL);
  4047. this->hEventThreadDead = CreateEvent(NULL, TRUE, FALSE, NULL);
  4048. hThread = CreateThread(NULL, 0, CDIEff_ThreadProc, (LPVOID)pdie, 0, &dwThreadId);
  4049. if (hThread == NULL)
  4050. {
  4051. /* Failed to create the thread.
  4052. * Clean up all our preparations.
  4053. */
  4054. CloseHandle(this->hEventDelete);
  4055. this->hEventDelete = NULL;
  4056. CloseHandle(this->hEventThreadDead);
  4057. this->hEventThreadDead = NULL;
  4058. hres = hresLe(GetLastError());
  4059. }
  4060. else
  4061. {
  4062. /*
  4063. * Create an event to signal effect started or stopped
  4064. */
  4065. this->hEventGeneral = CreateEvent(NULL, TRUE, FALSE, NULL);
  4066. }
  4067. }
  4068. this->dwCoords = emi.attr.dwCoords & DIEFF_COORDMASK;
  4069. AssertF(this->dwCoords);
  4070. /*
  4071. * Note, we allow non-hardware specific types that are not
  4072. * recognized to pass through untested. This effects to be run
  4073. * from a device which has newer effects than this version of
  4074. * DInput can check. However if this DInput recognizes the
  4075. * effect type, it will be checked, even if the application was
  4076. * written for a version that could not check it.
  4077. */
  4078. if (fInOrder(DIEFT_PREDEFMIN, DIEFT_GETTYPE(emi.attr.dwEffType),
  4079. DIEFT_PREDEFMAX)) {
  4080. this->hresValidTsd = c_rgtsd[
  4081. DIEFT_GETTYPE(emi.attr.dwEffType) -
  4082. DIEFT_PREDEFMIN];
  4083. } else {
  4084. this->hresValidTsd = CDIEff_IsValidUnknownTsd;
  4085. }
  4086. hres = S_OK;
  4087. }
  4088. CDIEff_LeaveCrit(this);
  4089. }
  4090. ExitOleProcR();
  4091. return hres;
  4092. }
  4093. /*****************************************************************************
  4094. *
  4095. * @doc INTERNAL
  4096. *
  4097. * @method HRESULT | IDirectInputEffect | Init |
  4098. *
  4099. * Initialize the internal parts of the DirectInputEffect object.
  4100. *
  4101. * @parm LPDIRECTINPUTEFFECTSHEPHERD | pes |
  4102. *
  4103. * The shepherd that lets us talk to the driver.
  4104. *
  4105. *****************************************************************************/
  4106. HRESULT INLINE
  4107. CDIEff_Init(struct CDIDev *pdev, LPDIRECTINPUTEFFECTSHEPHERD pes, PDE this)
  4108. {
  4109. HRESULT hres;
  4110. /*
  4111. * The critical section must be the very first thing we do,
  4112. * because only Finalize checks for its existence.
  4113. *
  4114. * (We might be finalized without being initialized if the user
  4115. * passed a bogus interface to CDIEff_New.)
  4116. */
  4117. this->pdev = pdev;
  4118. Common_Hold(this->pdev);
  4119. this->pes = pes;
  4120. OLE_AddRef(this->pes);
  4121. hres = CDIDev_NotifyCreateEffect(this->pdev, this);
  4122. if (SUCCEEDED(hres)) {
  4123. this->fDadNotified = 1;
  4124. }
  4125. return hres;
  4126. }
  4127. /*****************************************************************************
  4128. *
  4129. * @doc INTERNAL
  4130. *
  4131. * @method HRESULT | IDirectInputEffect | New |
  4132. *
  4133. * Create a new DirectInputEffect object, uninitialized.
  4134. *
  4135. * @parm IN struct CDIDev * | pdd |
  4136. *
  4137. * Parent device, which we keep a <f Common_Hold> on.
  4138. *
  4139. * @parm LPDIRECTINPUTEFFECTSHEPHERD | pes |
  4140. *
  4141. * The shepherd that lets us talk to the driver.
  4142. *
  4143. * @parm IN PUNK | punkOuter |
  4144. *
  4145. * Controlling unknown for aggregation.
  4146. *
  4147. * @parm IN RIID | riid |
  4148. *
  4149. * Desired interface to new object.
  4150. *
  4151. * @parm OUT PPV | ppvObj |
  4152. *
  4153. * Output pointer for new object.
  4154. *
  4155. *****************************************************************************/
  4156. STDMETHODIMP
  4157. CDIEff_New(struct CDIDev *pdev, LPDIRECTINPUTEFFECTSHEPHERD pes,
  4158. PUNK punkOuter, RIID riid, PPV ppvObj)
  4159. {
  4160. HRESULT hres;
  4161. EnterProcR(IDirectInputEffect::<constructor>,
  4162. (_ "ppGp", pdev, pes, riid, punkOuter));
  4163. if (SUCCEEDED(hres = hresFullValidPcbOut(ppvObj, cbX(*ppvObj), 5)))
  4164. {
  4165. LPVOID pvTry = NULL;
  4166. hres = Common_NewRiid(CDIEff, punkOuter, riid, &pvTry);
  4167. if (SUCCEEDED(hres)) {
  4168. PDE this = _thisPv(pvTry);
  4169. hres = CDIEff_Init(pdev, pes, this);
  4170. if (SUCCEEDED(hres)) {
  4171. *ppvObj = pvTry;
  4172. } else {
  4173. Invoke_Release(&pvTry);
  4174. *ppvObj = NULL;
  4175. }
  4176. }
  4177. }
  4178. ExitOleProcPpvR(ppvObj);
  4179. return hres;
  4180. }
  4181. /*****************************************************************************
  4182. *
  4183. * The long-awaited vtbls and templates
  4184. *
  4185. *****************************************************************************/
  4186. #pragma BEGIN_CONST_DATA
  4187. #define CDIEff_Signature 0x20464643 /* "EFF " */
  4188. Primary_Interface_Begin(CDIEff, IDirectInputEffect)
  4189. CDIEff_Initialize,
  4190. CDIEff_GetEffectGuid,
  4191. CDIEff_GetParameters,
  4192. CDIEff_SetParameters,
  4193. CDIEff_Start,
  4194. CDIEff_Stop,
  4195. CDIEff_GetEffectStatus,
  4196. CDIEff_Download,
  4197. CDIEff_Unload,
  4198. CDIEff_Escape,
  4199. Primary_Interface_End(CDIEff, IDirectInputEffect)
  4200. #endif