Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

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