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.

5645 lines
165 KiB

  1. /*****************************************************************************
  2. *
  3. * DIDev.c
  4. *
  5. * Copyright (c) 1996 Microsoft Corporation. All Rights Reserved.
  6. *
  7. * Abstract:
  8. *
  9. * The standard implementation of IDirectInputDevice.
  10. *
  11. * This is the device-independent part. the device-dependent
  12. * part is handled by the IDirectInputDeviceCallback.
  13. *
  14. * And the IDirectInputEffect support lives in didevef.c.
  15. *
  16. * Contents:
  17. *
  18. * CDIDev_CreateInstance
  19. *
  20. *****************************************************************************/
  21. #include "dinputpr.h"
  22. #define INCLUDED_BY_DIDEV
  23. #include "didev.h"
  24. /*****************************************************************************
  25. *
  26. * Declare the interfaces we will be providing.
  27. *
  28. *****************************************************************************/
  29. Interface_Template_Begin(CDIDev)
  30. Primary_Interface_Template(CDIDev, TFORM(ThisInterfaceT))
  31. Secondary_Interface_Template(CDIDev, SFORM(ThisInterfaceT))
  32. Interface_Template_End(CDIDev)
  33. /*****************************************************************************
  34. *
  35. * @doc INTERNAL
  36. *
  37. * @global PDD * | g_rgpddForeground |
  38. *
  39. * A list of all devices which have obtained foreground
  40. * acquisition. Items on the list have been
  41. * held (not AddRef'd).
  42. *
  43. * @global UINT | g_cpddForeground |
  44. *
  45. * The number of entries in <p g_rgpddForeground>. When foreground
  46. * activation is lost, all objects in the array are unacquired.
  47. *
  48. *
  49. * @global UINT | g_cpddForegroundMax |
  50. *
  51. * The size of the <p g_rgpddForeground> array, including dummy
  52. * spaces that are not yet in use.
  53. *
  54. *****************************************************************************/
  55. #ifdef IDirectInputDevice2Vtbl
  56. /*
  57. * ISSUE-2001/03/29-timgill We assume that all-zeros is a valid initialization.
  58. */
  59. GPA g_gpaExcl;
  60. #define g_hgpaExcl (&g_gpaExcl)
  61. #else
  62. //
  63. // ISSUE-2001/03/29-timgill The following variables should go into diexcl.c or didevex.c
  64. //
  65. PDD *g_rgpddForeground;
  66. UINT g_cpddForeground;
  67. UINT g_cpddForegroundMax;
  68. #endif
  69. /*****************************************************************************
  70. *
  71. * @doc INTERNAL
  72. *
  73. * @method HRESULT | IDirectInputDevice | NotAcquired |
  74. *
  75. * Check that the device is not acquired.
  76. *
  77. * @cwrap LPDIRECTINPUTDEVICE | lpDirectInputDevice
  78. *
  79. * @returns
  80. *
  81. * Returns
  82. * <c S_OK> if all is well, or <c DIERR_ACQUIRED> if
  83. * the device is acquired.
  84. *
  85. *****************************************************************************/
  86. #ifndef XDEBUG
  87. #define IDirectInputDevice_NotAcquired_(pdd, z) \
  88. _IDirectInputDevice_NotAcquired_(pdd) \
  89. #endif
  90. HRESULT INLINE
  91. IDirectInputDevice_NotAcquired_(PDD this, LPCSTR s_szProc)
  92. {
  93. HRESULT hres;
  94. if(!this->fAcquired)
  95. {
  96. hres = S_OK;
  97. } else
  98. {
  99. RPF("ERROR %s: May not be called while device is acquired", s_szProc);
  100. hres = DIERR_ACQUIRED;
  101. }
  102. return hres;
  103. }
  104. #define IDirectInputDevice_NotAcquired(pdd) \
  105. IDirectInputDevice_NotAcquired_(pdd, s_szProc) \
  106. /*****************************************************************************
  107. *
  108. * @doc INTERNAL
  109. *
  110. * @method HRESULT | CDIDev | IsExclAcquired |
  111. *
  112. * Check that the device is acquired exclusively.
  113. *
  114. * The device critical section must already be held.
  115. *
  116. * @cwrap PDD | this
  117. *
  118. * @returns
  119. *
  120. * <c S_OK> if the device is exclusively acquired.
  121. *
  122. * <c DIERR_INPUTLOST> if acquisition has been lost.
  123. *
  124. * <c DIERR_NOTEXCLUSIVEACQUIRED> the device is acquired,
  125. * but not exclusively, or if the device is not acquired
  126. * at all.
  127. *
  128. *****************************************************************************/
  129. STDMETHODIMP
  130. CDIDev_IsExclAcquired_(PDD this, LPCSTR s_szProc)
  131. {
  132. HRESULT hres;
  133. AssertF(CDIDev_InCrit(this));
  134. if(this->discl & DISCL_EXCLUSIVE)
  135. {
  136. if(this->fAcquired)
  137. {
  138. hres = S_OK;
  139. } else
  140. {
  141. hres = this->hresNotAcquired;
  142. if(hres == DIERR_NOTACQUIRED)
  143. {
  144. hres = DIERR_NOTEXCLUSIVEACQUIRED;
  145. }
  146. }
  147. } else
  148. {
  149. hres = DIERR_NOTEXCLUSIVEACQUIRED;
  150. }
  151. if(s_szProc && hres == DIERR_NOTEXCLUSIVEACQUIRED)
  152. {
  153. RPF("ERROR %s: Device is not acquired in exclusive mode", s_szProc);
  154. }
  155. return hres;
  156. }
  157. /*****************************************************************************
  158. *
  159. * @doc INTERNAL
  160. *
  161. * @method void | IDirectInputDevice | EnterCrit |
  162. *
  163. * Enter the object critical section.
  164. *
  165. * @cwrap LPDIRECTINPUTDEVICE | lpDirectInputDevice
  166. *
  167. *****************************************************************************/
  168. void EXTERNAL
  169. CDIDev_EnterCrit_(struct CDIDev *this, LPCTSTR lptszFile, UINT line)
  170. {
  171. #ifdef XDEBUG
  172. if( ! _TryEnterCritSec(&this->crst) )
  173. {
  174. SquirtSqflPtszV(sqflCrit, TEXT("Device CritSec blocked @%s,%d"), lptszFile, line);
  175. EnterCriticalSection(&this->crst);
  176. }
  177. SquirtSqflPtszV(sqflCrit, TEXT("Device CritSec Entered @%s,%d"), lptszFile, line);
  178. #else
  179. EnterCriticalSection(&this->crst);
  180. #endif
  181. this->thidCrit = GetCurrentThreadId();
  182. InterlockedIncrement(&this->cCrit);
  183. }
  184. /*****************************************************************************
  185. *
  186. * @doc INTERNAL
  187. *
  188. * @method void | IDirectInputDevice | LeaveCrit |
  189. *
  190. * Leave the object critical section.
  191. *
  192. * @cwrap LPDIRECTINPUTDEVICE | lpDirectInputDevice
  193. *
  194. *****************************************************************************/
  195. void EXTERNAL
  196. CDIDev_LeaveCrit_(struct CDIDev *this, LPCTSTR lptszFile, UINT line)
  197. {
  198. #ifdef XDEBUG
  199. AssertF(this->cCrit);
  200. AssertF(this->thidCrit == GetCurrentThreadId());
  201. SquirtSqflPtszV(sqflCrit | sqflVerbose, TEXT("Device CritSec Leaving @%s,%d"), lptszFile, line);
  202. #endif
  203. if(InterlockedDecrement(&this->cCrit) == 0)
  204. {
  205. this->thidCrit = 0;
  206. }
  207. LeaveCriticalSection(&this->crst);
  208. }
  209. /*****************************************************************************
  210. *
  211. * @doc INTERNAL
  212. *
  213. * @method void | IDirectInputDevice | SetNotifyEvent |
  214. *
  215. * Set the event associated with the device, if any.
  216. *
  217. * @cwrap LPDIRECTINPUTDEVICE | lpDirectInputDevice
  218. *
  219. *****************************************************************************/
  220. void EXTERNAL
  221. CDIDev_SetNotifyEvent(PDD this)
  222. {
  223. if(this->hNotify)
  224. {
  225. SetEvent(this->hNotify);
  226. }
  227. }
  228. /*****************************************************************************
  229. *
  230. * @doc INTERNAL
  231. *
  232. * @method void | IDirectInputDevice | SetForcedUnacquiredFlag |
  233. *
  234. * When forced unacquired happens, set the fOnceForcedUnacquired flag.
  235. *
  236. *****************************************************************************/
  237. void EXTERNAL
  238. CDIDev_SetForcedUnacquiredFlag(PDD this)
  239. {
  240. /*
  241. * This is an internal interface, so we can skimp on validation.
  242. */
  243. this->fOnceForcedUnacquired = 1;
  244. }
  245. /*****************************************************************************
  246. *
  247. * @doc INTERNAL
  248. *
  249. * @method BOOL | CDIDev | InCrit |
  250. *
  251. * Nonzero if we are in the critical section.
  252. *
  253. *****************************************************************************/
  254. #ifdef DEBUG
  255. BOOL INTERNAL
  256. CDIDev_InCrit(PDD this)
  257. {
  258. return this->cCrit && this->thidCrit == GetCurrentThreadId();
  259. }
  260. #endif
  261. #ifdef DEBUG
  262. /*****************************************************************************
  263. *
  264. * @doc INTERNAL
  265. *
  266. * @method BOOL | IDirectInputDevice | IsConsistent |
  267. *
  268. * Check that various state variables are consistent.
  269. *
  270. * @cwrap LPDIRECTINPUTDEVICE | lpDirectInputDevice
  271. *
  272. *****************************************************************************/
  273. #define VerifyF(f) if (!(f)) fRc = 0
  274. BOOL INTERNAL
  275. CDIDev_IsConsistent(PDD this)
  276. {
  277. BOOL fRc = 1;
  278. /*
  279. * If acquired, then we must have a translation table, a state manager,
  280. * and a device callback.
  281. */
  282. if(this->fAcquired)
  283. {
  284. VerifyF(this->pdix && this->GetState && this->pdcb != c_pdcbNil);
  285. }
  286. /*
  287. * If buffering, then must have a device callback.
  288. */
  289. if(this->celtBuf)
  290. {
  291. VerifyF(this->pdcb != c_pdcbNil);
  292. }
  293. /*
  294. * If managing an instance, then make sure buffer variables are
  295. * consistent.
  296. */
  297. if(this->pvi)
  298. {
  299. if(this->celtBuf)
  300. {
  301. VerifyF( this->pvi->pBuffer
  302. && this->pvi->pEnd
  303. && this->pvi->pHead
  304. && this->pvi->pTail);
  305. VerifyF(this->pvi->pBuffer < this->pvi->pEnd);
  306. VerifyF(fInOrder((DWORD)(UINT_PTR)this->pvi->pBuffer,
  307. (DWORD)(UINT_PTR)this->pvi->pHead,
  308. (DWORD)(UINT_PTR)this->pvi->pEnd));
  309. VerifyF(fInOrder((DWORD)(UINT_PTR)this->pvi->pBuffer,
  310. (DWORD)(UINT_PTR)this->pvi->pTail,
  311. (DWORD)(UINT_PTR)this->pvi->pEnd));
  312. } else
  313. {
  314. VerifyF( this->pvi->pBuffer == 0
  315. && this->pvi->pEnd == 0
  316. && this->pvi->pHead == 0
  317. && this->pvi->pTail == 0);
  318. }
  319. }
  320. /*
  321. * The cooperative levels must match the cached window handle.
  322. */
  323. VerifyF(fLimpFF(this->discl & (DISCL_FOREGROUND | DISCL_EXCLUSIVE),
  324. this->hwnd));
  325. return fRc;
  326. }
  327. #undef VerifyF
  328. #endif
  329. /*****************************************************************************
  330. *
  331. * @doc EXTERNAL
  332. *
  333. * @method HRESULT | IDirectInputDevice | QueryInterface |
  334. *
  335. * Gives a client access to other interfaces on an object.
  336. *
  337. * @cwrap LPDIRECTINPUTDEVICE | lpDirectInputDevice
  338. *
  339. * @parm IN REFIID | riid |
  340. *
  341. * The requested interface's IID.
  342. *
  343. * @parm OUT LPVOID * | ppvObj |
  344. *
  345. * Receives a pointer to the obtained interface.
  346. *
  347. * @returns
  348. *
  349. * Returns a COM error code.
  350. *
  351. * @xref OLE documentation for <mf IUnknown::QueryInterface>.
  352. *
  353. *****************************************************************************
  354. *
  355. * @doc EXTERNAL
  356. *
  357. * @method HRESULT | IDirectInputDevice | AddRef |
  358. *
  359. * Increments the reference count for the interface.
  360. *
  361. * @cwrap LPDIRECTINPUTDEVICE | lpDirectInputDevice
  362. *
  363. * @returns
  364. *
  365. * Returns the object reference count.
  366. *
  367. * @xref OLE documentation for <mf IUnknown::AddRef>.
  368. *
  369. *****************************************************************************
  370. *
  371. * @doc EXTERNAL
  372. *
  373. * @method HRESULT | IDirectInputDevice | Release |
  374. *
  375. * Decrements the reference count for the interface.
  376. * If the reference count on the object falls to zero,
  377. * the object is freed from memory.
  378. *
  379. * @cwrap LPDIRECTINPUTDEVICE | lpDirectInputDevice
  380. *
  381. * @returns
  382. *
  383. * Returns the object reference count.
  384. *
  385. * @xref OLE documentation for <mf IUnknown::Release>.
  386. *
  387. *****************************************************************************/
  388. #ifdef DEBUG
  389. Default_QueryInterface(CDIDev)
  390. Default_AddRef(CDIDev)
  391. Default_Release(CDIDev)
  392. #else
  393. #define CDIDev_QueryInterface Common_QueryInterface
  394. #define CDIDev_AddRef Common_AddRef
  395. #define CDIDev_Release Common_Release
  396. #endif
  397. #ifdef IDirectInputDevice2Vtbl
  398. /*****************************************************************************
  399. *
  400. * @doc INTERNAL
  401. *
  402. * @method HRESULT | IDirectInput | QIHelper |
  403. *
  404. * Support the original IDirectInputDevice interfaces as well
  405. * as the new IDirectInputDevice2 interfaces.
  406. *
  407. * @parm IN REFIID | riid |
  408. *
  409. * The requested interface's IID.
  410. *
  411. * @parm OUT LPVOID * | ppvObj |
  412. *
  413. * Receives a pointer to the obtained interface.
  414. *
  415. *****************************************************************************/
  416. STDMETHODIMP
  417. CDIDev_QIHelper(PDD this, RIID riid, PPV ppvObj)
  418. {
  419. HRESULT hres;
  420. EnterProcI(CDIDev_QIHelper, (_ "pG", this, riid));
  421. if(IsEqualIID(riid, &IID_IDirectInputDeviceA))
  422. {
  423. *ppvObj = &this->ddA;
  424. OLE_AddRef(this);
  425. hres = S_OK;
  426. } else if(IsEqualIID(riid, &IID_IDirectInputDeviceW))
  427. {
  428. *ppvObj = &this->ddW;
  429. OLE_AddRef(this);
  430. hres = S_OK;
  431. #ifdef IDirectInputDevice7Vtbl
  432. } else if(IsEqualIID(riid, &IID_IDirectInputDevice2A))
  433. {
  434. *ppvObj = &this->ddA;
  435. OLE_AddRef(this);
  436. hres = S_OK;
  437. } else if(IsEqualIID(riid, &IID_IDirectInputDevice2W))
  438. {
  439. *ppvObj = &this->ddW;
  440. OLE_AddRef(this);
  441. hres = S_OK;
  442. #endif
  443. } else
  444. {
  445. hres = Common_QIHelper(this, riid, ppvObj);
  446. }
  447. ExitOleProcPpv(ppvObj);
  448. return hres;
  449. }
  450. #else
  451. #define CDIDev_QIHelper Common_QIHelper
  452. #endif
  453. /*****************************************************************************
  454. *
  455. * @doc INTERNAL
  456. *
  457. * @func HRESULT | CDIDev_Reset |
  458. *
  459. * Releases all the resources of a generic device that
  460. * are associated with a particular device instance.
  461. *
  462. * This method is called in preparation for reinitialization.
  463. *
  464. * It is the responsibility of the caller to have taken
  465. * any necessary critical sections.
  466. *
  467. *
  468. * @parm PV | pvObj |
  469. *
  470. * Object being reset. Note that it may not have been
  471. * completely initialized, so everything should be done
  472. * carefully.
  473. *
  474. *****************************************************************************/
  475. STDMETHODIMP
  476. CDIDev_Reset(PDD this)
  477. {
  478. HRESULT hres;
  479. if(!this->fAcquired)
  480. {
  481. /*
  482. * Note! that we must release the driver before releasing
  483. * the callback, because the callback will unload the
  484. * driver DLL.
  485. *
  486. * We cannot allow people to reset the device
  487. * while there are still effects outstanding,
  488. * because that would cause us to throw away the
  489. * callback while the effects are still using
  490. * the effect driver!
  491. */
  492. #ifdef IDirectInputDevice2Vtbl
  493. if(this->gpaEff.cpv == 0)
  494. {
  495. Invoke_Release(&this->pes);
  496. #endif
  497. Invoke_Release(&this->pdcb);
  498. this->pdcb = c_pdcbNil;
  499. FreePpv(&this->pdix);
  500. FreePpv(&this->rgiobj);
  501. #ifdef BUGGY_DX7_WINNT
  502. FreePpv(&this->pdix2);
  503. FreePpv(&this->rgiobj2);
  504. #endif //BUGGY_DX7_WINNT
  505. FreePpv(&this->pvBuffer);
  506. FreePpv(&this->pvLastBuffer);
  507. FreePpv(&this->rgdwAxesOfs);
  508. #ifdef IDirectInputDevice2Vtbl
  509. FreePpv(&this->rgemi);
  510. #endif
  511. FreePpv(&this->rgdwPOV);
  512. AssertF(!this->fAcquired);
  513. AssertF(!this->fAcquiredInstance);
  514. if(this->hNotify)
  515. {
  516. CloseHandle(this->hNotify);
  517. }
  518. ZeroBuf(&this->hwnd, FIELD_OFFSET(DD, celtBufMax) -
  519. FIELD_OFFSET(DD, hwnd));
  520. ZeroX(this->guid);
  521. this->celtBufMax = 1023;
  522. this->GetDeviceState = CDIDev_GetAbsDeviceState;
  523. this->hresNotAcquired = DIERR_NOTACQUIRED;
  524. this->fCook = 0;
  525. AssertF(this->hNotify == 0);
  526. #ifdef IDirectInputDevice2Vtbl
  527. AssertF(this->cemi == 0);
  528. AssertF(this->didcFF == 0);
  529. this->dwGain = 10000; /* Default to full gain */
  530. this->dwAutoCenter = DIPROPAUTOCENTER_ON; /* Default to centered */
  531. GPA_InitFromZero(&this->gpaEff);
  532. #endif
  533. /*
  534. * If the app does not initialize, then assume DX 3.
  535. */
  536. this->didftInstance = 0x0000FF00;
  537. hres = S_OK;
  538. #ifdef IDirectInputDevice2Vtbl
  539. } else
  540. {
  541. RPF("IDirectInputDevice::Initialize: Device still has effects");
  542. hres = DIERR_HASEFFECTS;
  543. }
  544. #endif
  545. } else
  546. {
  547. RPF("IDirectInputDevice::Initialize: Device is busy");
  548. hres = DIERR_ACQUIRED;
  549. }
  550. return hres;
  551. }
  552. /*****************************************************************************
  553. *
  554. * @doc INTERNAL
  555. *
  556. * @func void | CDIDev_AppFinalize |
  557. *
  558. * The application has performed its final release.
  559. *
  560. * If the device is acquired, then unacquire it.
  561. *
  562. #ifdef IDirectInputDevice2Vtbl
  563. * Release the holds on all the created effects that
  564. * we have been hanging onto for enumeration purposes.
  565. #endif
  566. *
  567. * @parm PV | pvObj |
  568. *
  569. * Object being released. Note that it may not have been
  570. * completely initialized, so everything should be done
  571. * carefully.
  572. *
  573. *****************************************************************************/
  574. void INTERNAL
  575. CDIDev_AppFinalize(PV pvObj)
  576. {
  577. PDD this = pvObj;
  578. if(this->fAcquired)
  579. {
  580. RPF("IDirectInputDevice::Release: Forgot to call Unacquire()");
  581. CDIDev_InternalUnacquire(pvObj);
  582. }
  583. #ifdef IDirectInputDevice2Vtbl
  584. if(this->fCritInited)
  585. {
  586. /*
  587. * Stop all the effects, if they are playing.
  588. *
  589. * Then unhold them (because we're done).
  590. *
  591. * ISSUE-2001/03/29-timgill Need to totally remove all effects created by a destroyed device
  592. * We also need to neuter them so they don't
  593. * do anything any more. Otherwise, an app might
  594. * destroy the parent device and then try to mess with
  595. * an effect created by that device after the device
  596. * is gone.
  597. *
  598. * Note that we cannot call the effect while inside our
  599. * private little critical section, because the effect
  600. * may need to do crazy things to stop itself.
  601. *
  602. * (It will almost certainly call back up into the device
  603. * to remove itself from the list of created effects.)
  604. */
  605. UINT ipdie;
  606. PPDIE rgpdie;
  607. UINT cpdie;
  608. CDIDev_EnterCrit(this);
  609. rgpdie = (PV)this->gpaEff.rgpv;
  610. cpdie = this->gpaEff.cpv;
  611. GPA_Init(&this->gpaEff);
  612. CDIDev_LeaveCrit(this);
  613. for(ipdie = 0; ipdie < cpdie; ipdie++)
  614. {
  615. AssertF(rgpdie[ipdie]);
  616. // 7/19/2000(a-JiTay): IA64: Use %p format specifier for 32/64-bit pointers.
  617. SquirtSqflPtszV(sqfl | sqflError,
  618. TEXT("Device %p forgot to destroy effect %08x"),
  619. this, rgpdie[ipdie]);
  620. IDirectInputEffect_Stop(rgpdie[ipdie]);
  621. Common_Unhold(rgpdie[ipdie]);
  622. }
  623. FreePpv(&rgpdie);
  624. }
  625. #endif
  626. }
  627. /*****************************************************************************
  628. *
  629. * @doc INTERNAL
  630. *
  631. * @func void | CDIDev_Finalize |
  632. *
  633. * Releases the resources of a generic device.
  634. *
  635. * @parm PV | pvObj |
  636. *
  637. * Object being released. Note that it may not have been
  638. * completely initialized, so everything should be done
  639. * carefully.
  640. *
  641. *****************************************************************************/
  642. void INTERNAL
  643. CDIDev_Finalize(PV pvObj)
  644. {
  645. HRESULT hres;
  646. PDD this = pvObj;
  647. #ifdef XDEBUG
  648. if(this->cCrit)
  649. {
  650. RPF("IDirectInputDevice::Release: Another thread is using the object; crash soon!");
  651. }
  652. #endif
  653. AssertF(!this->fAcquired);
  654. /*
  655. * Note that we cannot take the critical section because it
  656. * might not exist. (We might've died during initialization.)
  657. * Fortunately, we finalize only after every possible client
  658. * (both internal and external) has done its final Release(),
  659. * so it's impossible for any other method to get called at
  660. * this point.
  661. */
  662. hres = CDIDev_Reset(this);
  663. AssertF(SUCCEEDED(hres));
  664. if(this->fCritInited)
  665. {
  666. DeleteCriticalSection(&this->crst);
  667. }
  668. }
  669. /*****************************************************************************
  670. *
  671. * @doc INTERNAL
  672. *
  673. * @method void | CDIDev | GetVersions |
  674. *
  675. * Obtain version information from the device.
  676. *
  677. * First try to get it from the effect driver. If
  678. * that doesn't work, then get it from the VxD.
  679. * And if that doesn't work, then tough.
  680. *
  681. * @parm IN OUT LPDIDRIVERVERSIONS | pvers |
  682. *
  683. * Receives version information.
  684. *
  685. *****************************************************************************/
  686. void INLINE
  687. CDIDev_GetVersions(PDD this, LPDIDRIVERVERSIONS pvers)
  688. {
  689. HRESULT hres;
  690. /*
  691. * Pre-fill with zeros in case nobody implements GetVersions.
  692. */
  693. pvers->dwSize = cbX(*pvers);
  694. pvers->dwFirmwareRevision = 0;
  695. pvers->dwHardwareRevision = 0;
  696. pvers->dwFFDriverVersion = 0;
  697. hres = CDIDev_CreateEffectDriver(this);
  698. if(SUCCEEDED(hres) &&
  699. SUCCEEDED(hres = this->pes->lpVtbl->
  700. GetVersions(this->pes, pvers)))
  701. {
  702. } else
  703. {
  704. hres = this->pdcb->lpVtbl->GetVersions(this->pdcb, pvers);
  705. }
  706. }
  707. /*****************************************************************************
  708. *
  709. * @doc EXTERNAL
  710. *
  711. * @method HRESULT | IDirectInputDevice | GetCapabilities |
  712. *
  713. * Obtains information about the device.
  714. *
  715. * @cwrap LPDIRECTINPUTDEVICE | lpDirectInputDevice
  716. *
  717. * @parm IN OUT LPDIDEVCAPS | lpdc |
  718. *
  719. * Points to a <t DIDEVCAPS> structure that is filled in
  720. * by the function. The <e DIDEVCAPS.dwSize>
  721. * field "must" be filled in
  722. * by the application before calling this method.
  723. * See the documentation of the <t DIDEVCAPS> structure
  724. * for additional information.
  725. *
  726. * @returns
  727. *
  728. * Returns a COM error code. The following error codes are
  729. * intended to be illustrative and not necessarily comprehensive.
  730. *
  731. * <c DI_OK> = <c S_OK>: The operation completed successfully.
  732. *
  733. * <c DIERR_INVALIDPARAM> = <c E_INVALIDARG>: The
  734. * <p lpDirectInputDevice> or
  735. * <p lpdc> parameter is invalid.
  736. *
  737. *****************************************************************************/
  738. STDMETHODIMP
  739. CDIDev_GetCapabilities(PV pdd, LPDIDEVCAPS pdc _THAT)
  740. {
  741. HRESULT hres;
  742. EnterProcR(IDirectInputDevice::GetCapabilities, (_ "pp", pdd, pdc));
  743. if(SUCCEEDED(hres = hresPvT(pdd)) &&
  744. SUCCEEDED(hres = hresFullValidWritePxCb2(pdc,
  745. DIDEVCAPS_DX5,
  746. DIDEVCAPS_DX3, 1)))
  747. {
  748. PDD this = _thisPv(pdd);
  749. CDIDev_EnterCrit(this);
  750. /*
  751. * For the convenience of the callback, zero out all the fields,
  752. * save for the dwSize.
  753. */
  754. ZeroBuf(pvAddPvCb(pdc, cbX(DWORD)), pdc->dwSize - cbX(DWORD));
  755. hres = this->pdcb->lpVtbl->GetCapabilities(this->pdcb, pdc);
  756. if(SUCCEEDED(hres))
  757. {
  758. /*
  759. * We'll handle the DIDC_EMULATED and
  760. * DIDC_POLLEDDATAFORMAT bits to save the callback
  761. * some trouble.
  762. */
  763. AssertF(this->pvi);
  764. if(this->pvi->fl & VIFL_EMULATED)
  765. {
  766. pdc->dwFlags |= DIDC_EMULATED;
  767. }
  768. if(this->fPolledDataFormat)
  769. {
  770. pdc->dwFlags |= DIDC_POLLEDDATAFORMAT;
  771. }
  772. #ifdef IDirectInputDevice2Vtbl
  773. /*
  774. * Add in the force feedback flags, too.
  775. */
  776. pdc->dwFlags |= this->didcFF;
  777. /*
  778. * If the caller wants force feedback parameters, then
  779. * set them, too.
  780. */
  781. if(pdc->dwSize >= cbX(DIDEVCAPS_DX5))
  782. {
  783. DIDRIVERVERSIONS vers;
  784. pdc->dwFFSamplePeriod = this->ffattr.dwFFSamplePeriod;
  785. pdc->dwFFMinTimeResolution = this->ffattr.dwFFMinTimeResolution;
  786. CDIDev_GetVersions(this, &vers);
  787. pdc->dwFirmwareRevision = vers.dwFirmwareRevision;
  788. pdc->dwHardwareRevision = vers.dwHardwareRevision;
  789. pdc->dwFFDriverVersion = vers.dwFFDriverVersion;
  790. }
  791. #endif
  792. hres = S_OK;
  793. }
  794. CDIDev_LeaveCrit(this);
  795. ScrambleBit(&pdc->dwDevType, DIDEVTYPE_RANDOM);
  796. ScrambleBit(&pdc->dwFlags, DIDC_RANDOM);
  797. }
  798. ExitOleProcR();
  799. return hres;
  800. }
  801. #ifdef XDEBUG
  802. CSET_STUBS(GetCapabilities, (PV pdd, LPDIDEVCAPS pdc), (pdd, pdc THAT_))
  803. #else
  804. #define CDIDev_GetCapabilitiesA CDIDev_GetCapabilities
  805. #define CDIDev_GetCapabilitiesW CDIDev_GetCapabilities
  806. #endif
  807. /*****************************************************************************
  808. *
  809. * @doc INTERNAL
  810. *
  811. * @method HRESULT | CDIDev | GetDataFormat |
  812. *
  813. * Get the data format for the device if we don't have it already.
  814. *
  815. * @parm PDD | this |
  816. *
  817. * Device object.
  818. *
  819. * @returns
  820. *
  821. * COM return code.
  822. *
  823. *****************************************************************************/
  824. STDMETHODIMP
  825. CDIDev_GetDataFormat(PDD this)
  826. {
  827. HRESULT hres;
  828. LPDIDATAFORMAT pdf;
  829. /*
  830. * If the DIDATAFORMAT structure changes, you also need to invent
  831. * a new DCB message (DIDM_GETDATAFORMAT2), and then do
  832. * the right thing when faced with a mix of old and new.
  833. */
  834. hres = this->pdcb->lpVtbl->GetDataFormat(this->pdcb, &pdf);
  835. /*
  836. * Note! We don't support external drivers in this release,
  837. * so it's okay to treat these are Assert's and not try to recover.
  838. */
  839. if(SUCCEEDED(hres))
  840. {
  841. AssertF(pdf->dwSize == sizeof(this->df));
  842. this->df = *pdf;
  843. AssertF(!IsBadReadPtr(pdf->rgodf, cbCxX(pdf->dwNumObjs, ODF)));
  844. /*
  845. * Prepare the axis goo in case the app sets relative mode.
  846. */
  847. if(SUCCEEDED(hres = ReallocCbPpv(pdf->dwDataSize,
  848. &this->pvLastBuffer)) &&
  849. SUCCEEDED(hres = ReallocCbPpv(cbCdw(pdf->dwNumObjs),
  850. &this->rgdwAxesOfs)))
  851. {
  852. UINT iobj;
  853. this->cAxes = 0;
  854. for(iobj = 0; iobj < pdf->dwNumObjs; iobj++)
  855. {
  856. AssertF(pdf->rgodf[iobj].dwOfs < pdf->dwDataSize);
  857. if(pdf->rgodf[iobj].dwType & DIDFT_AXIS)
  858. {
  859. this->rgdwAxesOfs[this->cAxes++] = pdf->rgodf[iobj].dwOfs;
  860. }
  861. }
  862. }
  863. }
  864. return hres;
  865. }
  866. /*****************************************************************************
  867. *
  868. * @doc INTERNAL
  869. *
  870. * @method HRESULT | CDIDev | GetPolled |
  871. *
  872. * Determine whether the device is polled.
  873. *
  874. * @parm PDD | this |
  875. *
  876. * Device object.
  877. *
  878. * @returns
  879. *
  880. * COM result code.
  881. *
  882. *****************************************************************************/
  883. STDMETHODIMP
  884. CDIDev_GetPolled(PDD this)
  885. {
  886. HRESULT hres;
  887. DIDEVCAPS_DX3 dc;
  888. /*
  889. * We intentionally use a DIDEVCAPS_DX3 because going for
  890. * a full DIDEVCAPS_DX5 requires us to load the force
  891. * feedback driver which is pointless for our current
  892. * goal.
  893. */
  894. ZeroX(dc);
  895. dc.dwSize = cbX(dc);
  896. hres = this->pdcb->lpVtbl->GetCapabilities(this->pdcb, (PV)&dc);
  897. if(SUCCEEDED(hres))
  898. {
  899. if(dc.dwFlags & DIDC_POLLEDDEVICE)
  900. {
  901. this->hresPolled = DI_POLLEDDEVICE;
  902. } else
  903. {
  904. this->hresPolled = S_OK;
  905. }
  906. }
  907. return hres;
  908. }
  909. /*****************************************************************************
  910. *
  911. * @doc INTERNAL
  912. *
  913. * @method HRESULT | CDIDev | GetObjectInfoHelper |
  914. *
  915. * Set up all the information we can deduce ourselves and
  916. * have the callback finish.
  917. *
  918. * @cwrap LPDIRECTINPUTDEVICE | lpDirectInputDevice
  919. *
  920. * @parm LPCDIPROPINFO | ppropi |
  921. *
  922. * Object descriptor.
  923. *
  924. * @parm LPDIDEVICEOBJECTINSTANCEW | pdoiW |
  925. *
  926. * Structure to receive result.
  927. *
  928. *****************************************************************************/
  929. STDMETHODIMP
  930. CDIDev_GetObjectInfoHelper(PDD this, LPCDIPROPINFO ppropi,
  931. LPDIDEVICEOBJECTINSTANCEW pdoiW)
  932. {
  933. HRESULT hres;
  934. AssertF(IsValidSizeDIDEVICEOBJECTINSTANCEW(pdoiW->dwSize));
  935. pdoiW->guidType = *this->df.rgodf[ppropi->iobj].pguid;
  936. pdoiW->dwType = this->df.rgodf[ppropi->iobj].dwType;
  937. pdoiW->dwFlags = this->df.rgodf[ppropi->iobj].dwFlags;
  938. ScrambleBit(&pdoiW->dwFlags, DIDOI_RANDOM);
  939. if( this->pdix )
  940. {
  941. /* User data format offset */
  942. pdoiW->dwOfs = this->pdix[ppropi->iobj].dwOfs;
  943. } else
  944. {
  945. #ifdef BUGGY_DX7_WINNT
  946. if( (this->dwVersion < 0x700) && (this->dwVersion != 0x5B2) &&
  947. this->pdix2 )
  948. {
  949. pdoiW->dwOfs = this->pdix2[ppropi->iobj].dwOfs;
  950. } else
  951. #endif //BUGGY_DX7_WINNT
  952. {
  953. /* Internal data format offset */
  954. pdoiW->dwOfs = this->df.rgodf[ppropi->iobj].dwOfs;
  955. }
  956. }
  957. /*
  958. * Wipe out everything starting at tszName.
  959. */
  960. ZeroBuf(&pdoiW->tszName,
  961. pdoiW->dwSize - FIELD_OFFSET(DIDEVICEOBJECTINSTANCEW, tszName));
  962. hres = this->pdcb->lpVtbl->GetObjectInfo(this->pdcb, ppropi, pdoiW);
  963. return hres;
  964. }
  965. /*****************************************************************************
  966. *
  967. * @doc EXTERNAL
  968. *
  969. * @method HRESULT | IDirectInputDevice | EnumObjects |
  970. *
  971. * Enumerate the input sources (buttons, axes)
  972. * available on a device.
  973. *
  974. * @cwrap LPDIRECTINPUTDEVICE | lpDirectInputDevice
  975. *
  976. * @parm IN LPDIENUMDEVICEOBJECTSCALLBACK | lpCallback |
  977. *
  978. * Callback function.
  979. *
  980. * @parm IN LPVOID | pvRef |
  981. *
  982. * Reference data (context) for callback.
  983. *
  984. * @parm IN DWORD | fl |
  985. *
  986. * Flags specifying the type(s) of objects to be enumerated.
  987. * See the section "DirectInput Data Format Types" for a
  988. * list of flags that can be passed.
  989. *
  990. * Furthermore, the enumeration can be restricted to objects
  991. * from a single HID link collection by using the
  992. * <f DIDFT_ENUMCOLLECTION> macro.
  993. *
  994. * @returns
  995. *
  996. * Returns a COM error code. The following error codes are
  997. * intended to be illustrative and not necessarily comprehensive.
  998. *
  999. * <c DI_OK> = <c S_OK>: The operation completed successfully.
  1000. * Note that if the callback stops the enumeration prematurely,
  1001. * the enumeration is considered to have succeeded.
  1002. *
  1003. * <c DIERR_INVALIDPARAM> = <c E_INVALIDARG>: The
  1004. * <p fl> parameter contains invalid flags, or the callback
  1005. * procedure returned an invalid status code.
  1006. *
  1007. * @cb BOOL CALLBACK | DIEnumDeviceObjectsProc |
  1008. *
  1009. * An application-defined callback function that receives
  1010. * DirectInputDevice objects as a result of a call to the
  1011. * <om IDirectInputDevice::EnumObjects> method.
  1012. *
  1013. * @parm IN LPCDIDEVICEOBJECTINSTANCE | lpddoi |
  1014. *
  1015. * A <t DIDEVICEOBJECTINSTANCE> structure which describes
  1016. * the object being enumerated.
  1017. *
  1018. * @parm IN OUT LPVOID | pvRef |
  1019. * Specifies the application-defined value given in the
  1020. * <mf IDirectInputDevice::EnumObjects> function.
  1021. *
  1022. * @returns
  1023. *
  1024. * Returns <c DIENUM_CONTINUE> to continue the enumeration
  1025. * or <c DIENUM_STOP> to stop the enumeration.
  1026. *
  1027. * @ex
  1028. *
  1029. * To enumerate all axis objects:
  1030. *
  1031. * |
  1032. *
  1033. * // C++
  1034. * HRESULT hr = pDevice->EnumObjects(EnumProc, RefData, DIDFT_AXIS);
  1035. *
  1036. * // C
  1037. * hr = IDirectInputDevice_EnumObjects(pDevice, EnumProc, RefData,
  1038. * DIDFT_AXIS);
  1039. *
  1040. * @ex
  1041. *
  1042. * To enumerate all objects in the third HID link collection:
  1043. *
  1044. * |
  1045. *
  1046. * // C++
  1047. * HRESULT hr = pDevice->EnumObjects(EnumProc, RefData,
  1048. * DIDFT_ENUMCOLLECTION(3));
  1049. *
  1050. * // C
  1051. * hr = IDirectInputDevice_EnumObjects(pDevice, EnumProc, RefData,
  1052. * DIDFT_ENUMCOLLECTION(3));
  1053. *
  1054. *****************************************************************************/
  1055. STDMETHODIMP
  1056. CDIDev_EnumObjectsW
  1057. (PV pddW, LPDIENUMDEVICEOBJECTSCALLBACKW pec, LPVOID pvRef, DWORD fl)
  1058. {
  1059. HRESULT hres;
  1060. EnterProcR(IDirectInputDevice::EnumObjectsW, (_ "ppx", pddW, pec, fl));
  1061. if(SUCCEEDED(hres = hresPvW(pddW)) &&
  1062. SUCCEEDED(hres = hresFullValidPfn(pec, 1)) &&
  1063. SUCCEEDED(hres = hresFullValidFl(fl, DIDFT_ENUMVALID, 3)))
  1064. {
  1065. PDD this = _thisPvNm(pddW, ddW);
  1066. DWORD flExclude;
  1067. WORD wCollection;
  1068. /*
  1069. * We snapshot the object information underneath the critical
  1070. * section so we don't blow up if another thread Reset()s
  1071. * the device in the middle of an enumeration. The DIDATAFORMAT
  1072. * contains pointers to the dcb, so we need to AddRef the
  1073. * dcb as well.
  1074. */
  1075. AssertF(!CDIDev_InCrit(this));
  1076. CDIDev_EnterCrit(this);
  1077. if(this->pdcb != c_pdcbNil)
  1078. {
  1079. DIPROPINFO propi;
  1080. DIDATAFORMAT df;
  1081. IDirectInputDeviceCallback *pdcb;
  1082. pdcb = this->pdcb;
  1083. OLE_AddRef(pdcb);
  1084. df = this->df;
  1085. CDIDev_LeaveCrit(this);
  1086. AssertF(!CDIDev_InCrit(this));
  1087. /*
  1088. * If the client is DX3, don't enumerate things that
  1089. * didn't exist in DX3.
  1090. */
  1091. if(this->dwVersion <= 0x0300)
  1092. {
  1093. flExclude = DIDFT_ALLOBJS & ~DIDFT_ALLOBJS_DX3;
  1094. } else
  1095. {
  1096. flExclude = 0;
  1097. /* Exclude alises if necessary */
  1098. if( !(fl & DIDFT_ALIAS) )
  1099. {
  1100. flExclude |= DIDFT_ALIAS;
  1101. } else
  1102. {
  1103. fl &= ~DIDFT_ALIAS;
  1104. }
  1105. /* Exclude Vendor Defined fields */
  1106. if( !(fl & DIDFT_VENDORDEFINED) )
  1107. {
  1108. flExclude |= DIDFT_VENDORDEFINED;
  1109. } else
  1110. {
  1111. fl &= ~DIDFT_VENDORDEFINED;
  1112. }
  1113. }
  1114. if(fl == DIDFT_ALL)
  1115. {
  1116. fl = DIDFT_ALLOBJS;
  1117. }
  1118. /*
  1119. * Pull out the link collection we are enumerating.
  1120. * Note: Backwards compatibility hack. We can't
  1121. * use link collection 0 to mean "no parent" because
  1122. * 0 means "don't care". So instead, we use 0xFFFF
  1123. * to mean "no parent". This means that we need to
  1124. * interchange 0 and 0xFFFF before entering the main
  1125. * loop.
  1126. */
  1127. wCollection = DIDFT_GETCOLLECTION(fl);
  1128. switch(wCollection)
  1129. {
  1130. case 0:
  1131. wCollection = 0xFFFF;
  1132. break;
  1133. case DIDFT_GETCOLLECTION(DIDFT_NOCOLLECTION):
  1134. wCollection = 0;
  1135. break;
  1136. }
  1137. propi.pguid = 0;
  1138. #ifdef BUGGY_DX7_WINNT
  1139. //Whistler bug 151479 - for pre-DX7 apps on WINNT only, make sure that the
  1140. //enumeration order is same as the winmm one
  1141. if( (this->dwVersion < 0x700) && (this->dwVersion != 0x5B2) &&
  1142. (this->pdix2) && (this->rgiobj2))
  1143. {
  1144. UINT iobj;
  1145. for(iobj = 0; iobj < this->dwDataSize2; iobj++)
  1146. {
  1147. propi.iobj = this->rgiobj2[iobj];
  1148. if (propi.iobj == -1)
  1149. {
  1150. continue;
  1151. }
  1152. propi.dwDevType = df.rgodf[propi.iobj].dwType;
  1153. if((propi.dwDevType & fl & DIDFT_TYPEMASK) &&
  1154. fHasAllBitsFlFl(propi.dwDevType, fl & DIDFT_ATTRMASK) &&
  1155. !(propi.dwDevType & flExclude))
  1156. {
  1157. DIDEVICEOBJECTINSTANCEW doiW;
  1158. doiW.dwSize = cbX(doiW);
  1159. hres = CDIDev_GetObjectInfoHelper(this, &propi, &doiW);
  1160. if(SUCCEEDED(hres) &&
  1161. fLimpFF(wCollection != 0xFFFF,
  1162. doiW.wCollectionNumber == wCollection))
  1163. {
  1164. BOOL fRc = Callback(pec, &doiW, pvRef);
  1165. switch(fRc)
  1166. {
  1167. case DIENUM_STOP: goto enumdoneok;
  1168. case DIENUM_CONTINUE: break;
  1169. default:
  1170. RPF("IDirectInputDevice::EnumObjects: Invalid return value from enumeration callback");
  1171. ValidationException();
  1172. break;
  1173. }
  1174. } else
  1175. {
  1176. goto enumdonefail;
  1177. }
  1178. }
  1179. }
  1180. }
  1181. else
  1182. #endif //BUGGY_DX7_WINNT
  1183. {
  1184. for(propi.iobj = 0; propi.iobj < df.dwNumObjs; propi.iobj++)
  1185. {
  1186. propi.dwDevType = df.rgodf[propi.iobj].dwType;
  1187. if((propi.dwDevType & fl & DIDFT_TYPEMASK) &&
  1188. fHasAllBitsFlFl(propi.dwDevType, fl & DIDFT_ATTRMASK) &&
  1189. !(propi.dwDevType & flExclude))
  1190. {
  1191. DIDEVICEOBJECTINSTANCEW doiW;
  1192. doiW.dwSize = cbX(doiW);
  1193. hres = CDIDev_GetObjectInfoHelper(this, &propi, &doiW);
  1194. if(SUCCEEDED(hres) &&
  1195. fLimpFF(wCollection != 0xFFFF,
  1196. doiW.wCollectionNumber == wCollection))
  1197. {
  1198. BOOL fRc = Callback(pec, &doiW, pvRef);
  1199. switch(fRc)
  1200. {
  1201. case DIENUM_STOP: goto enumdoneok;
  1202. case DIENUM_CONTINUE: break;
  1203. default:
  1204. RPF("IDirectInputDevice::EnumObjects: Invalid return value from enumeration callback");
  1205. ValidationException();
  1206. break;
  1207. }
  1208. } else
  1209. {
  1210. goto enumdonefail;
  1211. }
  1212. }
  1213. }
  1214. }
  1215. enumdoneok:;
  1216. hres = S_OK;
  1217. enumdonefail:;
  1218. OLE_Release(pdcb);
  1219. } else
  1220. {
  1221. CDIDev_LeaveCrit(this);
  1222. RPF("ERROR: IDirectInputDevice: Not initialized");
  1223. hres = DIERR_NOTINITIALIZED;
  1224. }
  1225. }
  1226. ExitOleProcR();
  1227. return hres;
  1228. }
  1229. #define CDIDev_EnumObjects2W CDIDev_EnumObjectsW
  1230. /*****************************************************************************
  1231. *
  1232. * @doc INTERNAL
  1233. *
  1234. * @method HRESULT | IDirectInputDeviceA | EnumObjectsCallbackA |
  1235. *
  1236. * Custom callback that wraps
  1237. * <mf IDirectInputDeviceW::EnumObjects> which
  1238. * translates the UNICODE string to ANSI.
  1239. *
  1240. * @parm IN LPCDIENUMDEVICEOBJECTINSTANCE | pdoiW |
  1241. *
  1242. * Structure to be translated to ANSI.
  1243. *
  1244. * @parm IN LPVOID | pvRef |
  1245. *
  1246. * Pointer to <t struct ENUMDEVICEOBJECTINFO> which describes
  1247. * the original callback.
  1248. *
  1249. * @returns
  1250. *
  1251. * Returns whatever the original callback returned.
  1252. *
  1253. *****************************************************************************/
  1254. typedef struct ENUMOBJECTSINFO
  1255. {
  1256. LPDIENUMDEVICEOBJECTSCALLBACKA pecA;
  1257. PV pvRef;
  1258. } ENUMOBJECTSINFO, *PENUMOBJECTSINFO;
  1259. BOOL CALLBACK
  1260. CDIDev_EnumObjectsCallbackA(LPCDIDEVICEOBJECTINSTANCEW pdoiW, PV pvRef)
  1261. {
  1262. PENUMOBJECTSINFO peoi = pvRef;
  1263. BOOL fRc;
  1264. DIDEVICEOBJECTINSTANCEA doiA;
  1265. EnterProc(CDIDev_EnumObjectsCallbackA,
  1266. (_ "GxxWp", &pdoiW->guidType,
  1267. pdoiW->dwOfs,
  1268. pdoiW->dwType,
  1269. pdoiW->tszName, pvRef));
  1270. doiA.dwSize = cbX(doiA);
  1271. ObjectInfoWToA(&doiA, pdoiW);
  1272. fRc = peoi->pecA(&doiA, peoi->pvRef);
  1273. ExitProcX(fRc);
  1274. return fRc;
  1275. }
  1276. /*****************************************************************************
  1277. *
  1278. * @doc INTERNAL
  1279. *
  1280. * @method HRESULT | IDirectInputDeviceA | EnumObjects |
  1281. *
  1282. * Enumerate the input sources (buttons, axes)
  1283. * available on a device, in ANSI.
  1284. * See <mf IDirectInputDevice::EnumObjects> for more information.
  1285. *
  1286. * @cwrap LPDIRECTINPUTDEVICE | lpDirectInputDevice
  1287. *
  1288. * @parm IN LPDIENUMDEVICEOBJECTSCALLBACK | lpCallback |
  1289. *
  1290. * Same as <mf IDirectInputDeviceW::EnumObjects>, except in ANSI.
  1291. *
  1292. * @parm IN LPVOID | pvRef |
  1293. *
  1294. * Same as <mf IDirectInputDeviceW::EnumObjects>.
  1295. *
  1296. * @parm IN DWORD | fl |
  1297. *
  1298. * Same as <mf IDirectInputDeviceW::EnumObjects>.
  1299. *
  1300. *****************************************************************************/
  1301. STDMETHODIMP
  1302. CDIDev_EnumObjectsA
  1303. (PV pddA, LPDIENUMDEVICEOBJECTSCALLBACKA pec, LPVOID pvRef, DWORD fl)
  1304. {
  1305. HRESULT hres;
  1306. EnterProcR(IDirectInputDeviceA::EnumDevices,
  1307. (_ "pppx", pddA, pec, pvRef, fl));
  1308. /*
  1309. * EnumObjectsW will validate the rest.
  1310. */
  1311. if(SUCCEEDED(hres = hresPvA(pddA)) &&
  1312. SUCCEEDED(hres = hresFullValidPfn(pec, 1)))
  1313. {
  1314. ENUMOBJECTSINFO eoi = { pec, pvRef};
  1315. PDD this = _thisPvNm(pddA, ddA);
  1316. hres = CDIDev_EnumObjectsW(&this->ddW, CDIDev_EnumObjectsCallbackA,
  1317. &eoi, fl);
  1318. }
  1319. ExitOleProcR();
  1320. return hres;
  1321. }
  1322. #define CDIDev_EnumObjects2A CDIDev_EnumObjectsA
  1323. /*****************************************************************************
  1324. *
  1325. * @doc EXTERNAL
  1326. *
  1327. * @method HRESULT | IDirectInputDevice | SetEventNotification |
  1328. *
  1329. * Specify the event that should be set when the device
  1330. * state changes, or turns off such notifications.
  1331. *
  1332. * A device state change is defined as any of the following:
  1333. *
  1334. * - A change in the position of an axis.
  1335. *
  1336. * - A change in the state (pressed or released) of a button.
  1337. *
  1338. * - A change in the direction of a POV control.
  1339. *
  1340. * - Loss of acquisition.
  1341. *
  1342. * "It is an error" to call <f CloseHandle> on the event
  1343. * while it has been selected into an <i IDirectInputDevice>
  1344. * object. You must call
  1345. * <mf IDirectInputDevice::SetEventNotification> with the
  1346. * <p hEvent> parameter set to NULL before closing the
  1347. * event handle.
  1348. *
  1349. * The event notification handle cannot be changed while the
  1350. * device is acquired.
  1351. *
  1352. * If the function is successful, then the application can
  1353. * use the event handle in the same manner as any other
  1354. * Win32 event handle. Examples of usage are shown below.
  1355. * For additional information on using Win32 wait functions,
  1356. * see the Win32 SDK and related documentation.
  1357. *
  1358. * @cwrap LPDIRECTINPUTDEVICE | lpDirectInputDevice
  1359. *
  1360. * @parm IN HANDLE | hEvent |
  1361. *
  1362. * Specifies the event handle which will be set when the
  1363. * device state changes. It "must" be an event
  1364. * handle. DirectInput will <f SetEvent> the handle when
  1365. * the state of the device changes.
  1366. *
  1367. * The application should create the handle via the
  1368. * <f CreateEvent> function. If the event is created as
  1369. * an automatic-reset event, then the operating system will
  1370. * automatically reset the event once a wait has been
  1371. * satisfied. If the event is created as a manual-reset
  1372. * event, then it is the application's responsibility to
  1373. * call <f ResetEvent> to reset it. DirectInput will not
  1374. * call <f ResetEvent> for event notification handles.
  1375. *
  1376. * If the <p hEvent> is zero, then notification is disabled.
  1377. *
  1378. * @returns
  1379. *
  1380. * Returns a COM error code. The following error codes are
  1381. * intended to be illustrative and not necessarily comprehensive.
  1382. *
  1383. * <c DI_OK> = <c S_OK>: The operation completed successfully.
  1384. *
  1385. * <c DIERR_HANDLEEXISTS>: The <i IDirectInputDevice> object
  1386. * already has an event notification handle
  1387. * associated with it. DirectInput supports only one event
  1388. * notification handle per <i IDirectInputDevice> object.
  1389. *
  1390. * <c DIERR_ACQUIRED>: The <i IDirectInputDevice> object
  1391. * has been acquired. You must <mf IDirectInputDevice::Unacquire>
  1392. * the device before you can change the notification state.
  1393. *
  1394. * <c E_INVALIDARG>: The thing isn't an event handle.
  1395. *
  1396. * @ex
  1397. *
  1398. * To check if the handle is currently set without blocking:
  1399. *
  1400. * |
  1401. *
  1402. * dwResult = WaitForSingleObject(hEvent, 0);
  1403. * if (dwResult == WAIT_OBJECT_0) {
  1404. * // Event is set. If the event was created as
  1405. * // automatic-reset, then it has also been reset.
  1406. * }
  1407. *
  1408. * @ex
  1409. *
  1410. * The following example illustrates blocking
  1411. * indefinitely until the event is set. Note that this
  1412. * behavior is <y strongly> discouraged because the thread
  1413. * will not respond to the system until the wait is
  1414. * satisfied. (In particular, the thread will not respond
  1415. * to Windows messages.)
  1416. *
  1417. * |
  1418. *
  1419. * dwResult = WaitForSingleObject(hEvent, INFINITE);
  1420. * if (dwResult == WAIT_OBJECT_0) {
  1421. * // Event has been set. If the event was created as
  1422. * // automatic-reset, then it has also been reset.
  1423. * }
  1424. *
  1425. * @ex
  1426. *
  1427. * The following example illustrates a typical message loop
  1428. * for a message-based application that uses two events.
  1429. *
  1430. * |
  1431. *
  1432. * HANDLE ah[2] = { hEvent1, hEvent2 };
  1433. *
  1434. * while (TRUE) {
  1435. *
  1436. * dwResult = MsgWaitForMultipleObjects(2, ah, FALSE,
  1437. * INFINITE, QS_ALLINPUT);
  1438. * switch (dwResult) {
  1439. * case WAIT_OBJECT_0:
  1440. * // Event 1 has been set. If the event was created as
  1441. * // automatic-reset, then it has also been reset.
  1442. * ProcessInputEvent1();
  1443. * break;
  1444. *
  1445. * case WAIT_OBJECT_0 + 1:
  1446. * // Event 2 has been set. If the event was created as
  1447. * // automatic-reset, then it has also been reset.
  1448. * ProcessInputEvent2();
  1449. * break;
  1450. *
  1451. * case WAIT_OBJECT_0 + 2:
  1452. * // A Windows message has arrived. Process messages
  1453. * // until there aren't any more.
  1454. * while (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)) {
  1455. * if (msg.message == WM_QUIT) {
  1456. * goto exitapp;
  1457. * }
  1458. * TranslateMessage(&msg);
  1459. * DispatchMessage(&msg);
  1460. * }
  1461. * break;
  1462. *
  1463. * default:
  1464. * // Unexpected error.
  1465. * Panic();
  1466. * break;
  1467. * }
  1468. * }
  1469. *
  1470. * @ex
  1471. *
  1472. * The following example illustrates a typical application loop
  1473. * for a non-message-based application that uses two events.
  1474. *
  1475. * |
  1476. *
  1477. * HANDLE ah[2] = { hEvent1, hEvent2 };
  1478. * DWORD dwWait = 0;
  1479. *
  1480. * while (TRUE) {
  1481. *
  1482. * dwResult = MsgWaitForMultipleObjects(2, ah, FALSE,
  1483. * dwWait, QS_ALLINPUT);
  1484. * dwWait = 0;
  1485. *
  1486. * switch (dwResult) {
  1487. * case WAIT_OBJECT_0:
  1488. * // Event 1 has been set. If the event was created as
  1489. * // automatic-reset, then it has also been reset.
  1490. * ProcessInputEvent1();
  1491. * break;
  1492. *
  1493. * case WAIT_OBJECT_0 + 1:
  1494. * // Event 2 has been set. If the event was created as
  1495. * // automatic-reset, then it has also been reset.
  1496. * ProcessInputEvent2();
  1497. * break;
  1498. *
  1499. * case WAIT_OBJECT_0 + 2:
  1500. * // A Windows message has arrived. Process messages
  1501. * // until there aren't any more.
  1502. * while (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)) {
  1503. * if (msg.message == WM_QUIT) {
  1504. * goto exitapp;
  1505. * }
  1506. * TranslateMessage(&msg);
  1507. * DispatchMessage(&msg);
  1508. * }
  1509. * break;
  1510. *
  1511. * default:
  1512. * // No input or messages waiting.
  1513. * // Do a frame of the game.
  1514. * // If the game is idle, then tell the next wait
  1515. * // to wait indefinitely for input or a message.
  1516. * if (!DoGame()) {
  1517. * dwWait = INFINITE;
  1518. * }
  1519. * // Poll for data in case the device is not
  1520. * // interrupt-driven.
  1521. * IDirectInputDevice2_Poll(pdev);
  1522. * break;
  1523. * }
  1524. * }
  1525. *
  1526. *
  1527. *****************************************************************************/
  1528. STDMETHODIMP
  1529. CDIDev_SetEventNotification(PV pdd, HANDLE h _THAT)
  1530. {
  1531. HRESULT hres;
  1532. EnterProcR(IDirectInputDevice::SetEventNotification, (_ "px", pdd, h));
  1533. if(SUCCEEDED(hres = hresPvT(pdd)))
  1534. {
  1535. PDD this = _thisPv(pdd);
  1536. /*
  1537. * Must protect with the critical section to prevent somebody from
  1538. * acquiring or setting a new event handle while we're changing it.
  1539. */
  1540. CDIDev_EnterCrit(this);
  1541. if(!this->fAcquired)
  1542. {
  1543. /*
  1544. * Don't operate on the original handle because the app
  1545. * might decide to do something to it on another thread.
  1546. */
  1547. hres = DupEventHandle(h, &h);
  1548. if(SUCCEEDED(hres))
  1549. {
  1550. /*
  1551. * Resetting the event serves two purposes.
  1552. *
  1553. * 1. It performs parameter validation for us, and
  1554. * 2. The event must be reset while the device is
  1555. * not acquired.
  1556. */
  1557. if(fLimpFF(h, ResetEvent(h)))
  1558. {
  1559. if(!this->hNotify || !h)
  1560. {
  1561. hres = this->pdcb->lpVtbl->
  1562. SetEventNotification(this->pdcb, h);
  1563. /*
  1564. * All dcb's use default handling for now so
  1565. * assert the callback returns S_FALSE
  1566. * so we are reminded to change this if need be.
  1567. * An uninitialized device would fail but don't
  1568. * break if we hit one of those, just assert that
  1569. * we won't accidentally call a HEL on it.
  1570. */
  1571. AssertF( ( hres == S_FALSE )
  1572. || ( ( hres == DIERR_NOTINITIALIZED ) && !this->pvi ) );
  1573. if(this->pvi)
  1574. {
  1575. VXDDWORDDATA vhd;
  1576. vhd.pvi = this->pvi;
  1577. vhd.dw = (DWORD)(UINT_PTR)h;
  1578. hres = Hel_SetNotifyHandle(&vhd);
  1579. AssertF(SUCCEEDED(hres)); /* Should never fail */
  1580. h = (HANDLE)(UINT_PTR)pvExchangePpvPv64(&this->hNotify, (UINT_PTR)h);
  1581. hres = this->hresPolled;
  1582. }
  1583. else
  1584. {
  1585. /*
  1586. * ISSUE-2001/03/29-timgill Is this actually an error case?
  1587. * Can this ever validly occur?
  1588. * if yes, don't we need any of the above?
  1589. */
  1590. RPF( "Device internal data missing on SetEventNotification" );
  1591. }
  1592. } else
  1593. {
  1594. /*
  1595. * Note, this is a change in behavior as 3.0 didn't
  1596. * mind if you replaced an existing handle .
  1597. * Nobody seems to have noticed yet though.
  1598. */
  1599. hres = DIERR_HANDLEEXISTS;
  1600. }
  1601. } else
  1602. {
  1603. RPF( "Handle not for Event in SetEventNotification" );
  1604. hres = E_HANDLE;
  1605. }
  1606. /*
  1607. * Close the old handle if we swapped one out
  1608. * or our duplicate if something went wrong
  1609. */
  1610. if(h != 0)
  1611. {
  1612. CloseHandle(h);
  1613. }
  1614. }
  1615. } else
  1616. {
  1617. hres = DIERR_ACQUIRED;
  1618. }
  1619. CDIDev_LeaveCrit(this);
  1620. }
  1621. ExitOleProc();
  1622. return hres;
  1623. }
  1624. #ifdef XDEBUG
  1625. CSET_STUBS(SetEventNotification, (PV pdd, HANDLE h), (pdd, h THAT_))
  1626. #else
  1627. #define CDIDev_SetEventNotificationA CDIDev_SetEventNotification
  1628. #define CDIDev_SetEventNotificationW CDIDev_SetEventNotification
  1629. #endif
  1630. /*****************************************************************************
  1631. *
  1632. * @doc INTERNAL
  1633. *
  1634. * @method HRESULT | IDirectInputDevice | hresMapHow |
  1635. *
  1636. * Map the <p dwObj> and <p dwHow> fields into an object index.
  1637. *
  1638. * @parm DWORD | dwObj |
  1639. *
  1640. * Object identifier.
  1641. *
  1642. * @parm DWORD | dwHow |
  1643. *
  1644. * How <p dwObj> should be interpreted.
  1645. *
  1646. * @parm OUT LPDIPROPINFO | ppropi |
  1647. *
  1648. * Receives object index and <p dwDevType>.
  1649. *
  1650. *****************************************************************************/
  1651. #ifndef XDEBUG
  1652. #define CDIDev_hresMapHow_(this, dwObj, dwHow, ppropi, z) \
  1653. _CDIDev_hresMapHow_(this, dwObj, dwHow, ppropi) \
  1654. #endif
  1655. STDMETHODIMP
  1656. CDIDev_hresMapHow_(PDD this, DWORD dwObj, DWORD dwHow,
  1657. LPDIPROPINFO ppropi, LPCSTR s_szProc)
  1658. {
  1659. HRESULT hres;
  1660. if(this->pdcb != c_pdcbNil)
  1661. {
  1662. int iobj = 0;
  1663. switch(dwHow)
  1664. {
  1665. case DIPH_DEVICE:
  1666. if(dwObj == 0)
  1667. {
  1668. ppropi->iobj = 0xFFFFFFFF;
  1669. ppropi->dwDevType = 0;
  1670. hres = S_OK;
  1671. } else
  1672. {
  1673. RPF("%s: dwObj must be zero if DIPH_DEVICE", s_szProc);
  1674. hres = E_INVALIDARG;
  1675. }
  1676. break;
  1677. case DIPH_BYOFFSET:
  1678. if(this->pdix && this->rgiobj)
  1679. {
  1680. if(dwObj < this->dwDataSize)
  1681. {
  1682. iobj = this->rgiobj[dwObj];
  1683. if(iobj >= 0)
  1684. {
  1685. AssertF(this->pdix[iobj].dwOfs == dwObj);
  1686. ppropi->iobj = iobj;
  1687. ppropi->dwDevType = this->df.rgodf[iobj].dwType;
  1688. hres = S_OK;
  1689. goto done;
  1690. } else
  1691. {
  1692. AssertF(iobj == -1);
  1693. }
  1694. }
  1695. SquirtSqflPtszV(sqfl | sqflBenign,
  1696. TEXT("%S: Invalid offset in dwObj. You may use DIPH_BYID to enum it."), s_szProc);
  1697. //RPF("%s: Invalid offset in dwObj", s_szProc);
  1698. } else
  1699. {
  1700. RPF("%s: Must have a data format to use if DIPH_BYOFFSET", s_szProc);
  1701. }
  1702. hres = DIERR_OBJECTNOTFOUND;
  1703. goto done;
  1704. case DIPH_BYID:
  1705. for(iobj = this->df.dwNumObjs; --iobj >= 0; )
  1706. {
  1707. if(DIDFT_FINDMATCH(this->df.rgodf[iobj].dwType, dwObj))
  1708. {
  1709. ppropi->iobj = iobj;
  1710. ppropi->dwDevType = this->df.rgodf[iobj].dwType;
  1711. hres = S_OK;
  1712. goto done;
  1713. }
  1714. }
  1715. RPF("%s: Invalid ID in dwObj", s_szProc);
  1716. hres = DIERR_OBJECTNOTFOUND;
  1717. break;
  1718. case DIPH_BYUSAGE:
  1719. hres = IDirectInputDeviceCallback_MapUsage(this->pdcb,
  1720. dwObj, &ppropi->iobj);
  1721. if(SUCCEEDED(hres))
  1722. {
  1723. ppropi->dwDevType = this->df.rgodf[ppropi->iobj].dwType;
  1724. }
  1725. break;
  1726. default:
  1727. RPF("%s: Invalid dwHow", s_szProc);
  1728. hres = E_INVALIDARG;
  1729. break;
  1730. }
  1731. done:;
  1732. } else
  1733. {
  1734. RPF("ERROR: IDirectInputDevice: Not initialized");
  1735. hres = DIERR_NOTINITIALIZED;
  1736. }
  1737. return hres;
  1738. }
  1739. #define CDIDev_hresMapHow(this, dwObj, dwHow, pdwOut) \
  1740. CDIDev_hresMapHow_(this, dwObj, dwHow, pdwOut, s_szProc) \
  1741. /*****************************************************************************
  1742. *
  1743. * @doc EXTERNAL
  1744. *
  1745. * @method HRESULT | IDirectInputDevice | GetObjectInfo |
  1746. *
  1747. * Obtains information about an object.
  1748. *
  1749. * @cwrap LPDIRECTINPUTDEVICE | lpDirectInputDevice
  1750. *
  1751. * @parm OUT LPDIDEVICEOBJECTINSTANCE | pdidoi |
  1752. *
  1753. * Receives information about the object.
  1754. * The caller "must" initialize the <e DIDEVICEOBJECTINSTANCE.dwSize>
  1755. * field before calling this method.
  1756. *
  1757. * @parm DWORD | dwObj |
  1758. *
  1759. * Identifies the object for which the property is to be
  1760. * accessed. The meaning of this value depends on the
  1761. * value of the <p dwHow> parameter.
  1762. * See the documentation of the <t DIPROPHEADER>
  1763. * structure for additional information.
  1764. *
  1765. * @parm DWORD | dwHow |
  1766. *
  1767. * Identifies how <p dwObj> is to be interpreted.
  1768. * It must be one of the <c DIPH_*> values.
  1769. * See the documentation of the <t DIPROPHEADER>
  1770. * structure for additional information.
  1771. *
  1772. * @returns
  1773. *
  1774. * Returns a COM error code. The following error codes are
  1775. * intended to be illustrative and not necessarily comprehensive.
  1776. *
  1777. * <c DI_OK> = <c S_OK>: The operation completed successfully.
  1778. *
  1779. * <c DIERR_INVALIDPARAM> = <c E_INVALIDARG>: One or more
  1780. * parameters was invalid.
  1781. *
  1782. * <c DIERR_OBJECTNOTFOUND>: The specified object does not
  1783. * exist.
  1784. *
  1785. *****************************************************************************/
  1786. STDMETHODIMP
  1787. CDIDev_GetObjectInfoW(PV pddW, LPDIDEVICEOBJECTINSTANCEW pdoiW,
  1788. DWORD dwObj, DWORD dwHow)
  1789. {
  1790. HRESULT hres;
  1791. EnterProcR(IDirectInputDevice::GetObjectInfo,
  1792. (_ "ppxx", pddW, pdoiW, dwObj, dwHow));
  1793. if(SUCCEEDED(hres = hresPvW(pddW)) &&
  1794. SUCCEEDED(hres = hresFullValidWritePxCb2(pdoiW,
  1795. DIDEVICEOBJECTINSTANCE_DX5W,
  1796. DIDEVICEOBJECTINSTANCE_DX3W, 1)))
  1797. {
  1798. PDD this = _thisPvNm(pddW, ddW);
  1799. DIPROPINFO propi;
  1800. /*
  1801. * Must protect with the critical section to prevent
  1802. * another thread from Reset()ing behind our back.
  1803. */
  1804. CDIDev_EnterCrit(this);
  1805. propi.pguid = 0;
  1806. hres = CDIDev_hresMapHow(this, dwObj, dwHow, &propi);
  1807. if(SUCCEEDED(hres))
  1808. {
  1809. if(dwHow != DIPH_DEVICE)
  1810. {
  1811. hres = CDIDev_GetObjectInfoHelper(this, &propi, pdoiW);
  1812. } else
  1813. {
  1814. RPF("%s: Invalid dwHow", s_szProc);
  1815. hres = E_INVALIDARG;
  1816. }
  1817. }
  1818. if(FAILED(hres))
  1819. {
  1820. ScrambleBuf(&pdoiW->guidType,
  1821. pdoiW->dwSize -
  1822. FIELD_OFFSET(DIDEVICEOBJECTINSTANCEW, guidType));
  1823. }
  1824. CDIDev_LeaveCrit(this);
  1825. }
  1826. ExitBenignOleProcR();
  1827. return hres;
  1828. }
  1829. #define CDIDev_GetObjectInfo2W CDIDev_GetObjectInfoW
  1830. /*****************************************************************************
  1831. *
  1832. * @doc INTERNAL
  1833. *
  1834. * @method HRESULT | IDirectInputDeviceA | GetObjectInfo |
  1835. *
  1836. * ANSI version of same.
  1837. *
  1838. * @cwrap LPDIRECTINPUTDEVICE | lpDirectInputDevice
  1839. *
  1840. * @parm OUT LPDIDEVICEOBJECTINSTANCEA | pdoiA |
  1841. *
  1842. * Receives information about the device's identity.
  1843. *
  1844. * @parm DWORD | dwObj |
  1845. *
  1846. * Identifies the object for which the property is to be
  1847. * accessed.
  1848. *
  1849. * @parm DWORD | dwHow |
  1850. *
  1851. * Identifies how <p dwObj> is to be interpreted.
  1852. *
  1853. * @returns
  1854. *
  1855. * Returns a COM error code. The following error codes are
  1856. * intended to be illustrative and not necessarily comprehensive.
  1857. *
  1858. * <c DI_OK> = <c S_OK>: The operation completed successfully.
  1859. *
  1860. * <c DIERR_INVALIDPARAM> = <c E_INVALIDARG>: One or more
  1861. * parameters was invalid.
  1862. *
  1863. *****************************************************************************/
  1864. STDMETHODIMP
  1865. CDIDev_GetObjectInfoA(PV pddA, LPDIDEVICEOBJECTINSTANCEA pdoiA,
  1866. DWORD dwObj, DWORD dwHow)
  1867. {
  1868. HRESULT hres;
  1869. EnterProcR(IDirectInputDevice::GetObjectInfo,
  1870. (_ "ppxx", pddA, pdoiA, dwObj, dwHow));
  1871. if(SUCCEEDED(hres = hresPvA(pddA)) &&
  1872. SUCCEEDED(hres = hresFullValidWritePxCb2(pdoiA,
  1873. DIDEVICEOBJECTINSTANCE_DX5A,
  1874. DIDEVICEOBJECTINSTANCE_DX3A, 1)))
  1875. {
  1876. PDD this = _thisPvNm(pddA, ddA);
  1877. DIDEVICEOBJECTINSTANCEW doiW;
  1878. doiW.dwSize = cbX(DIDEVICEOBJECTINSTANCEW);
  1879. hres = CDIDev_GetObjectInfoW(&this->ddW, &doiW, dwObj, dwHow);
  1880. if(SUCCEEDED(hres))
  1881. {
  1882. ObjectInfoWToA(pdoiA, &doiW);
  1883. hres = S_OK;
  1884. }
  1885. }
  1886. ExitBenignOleProcR();
  1887. return hres;
  1888. }
  1889. #define CDIDev_GetObjectInfo2A CDIDev_GetObjectInfoA
  1890. /*****************************************************************************
  1891. *
  1892. * @doc EXTERNAL
  1893. *
  1894. * @method HRESULT | IDirectInputDevice | GetDeviceInfo |
  1895. *
  1896. * Obtains information about the device's identity.
  1897. *
  1898. * @cwrap LPDIRECTINPUTDEVICE | lpDirectInputDevice
  1899. *
  1900. * @parm OUT LPDIDEVICEINSTANCE | pdidi |
  1901. *
  1902. * Receives information about the device's identity.
  1903. * The caller "must" initialize the <e DIDEVICEINSTANCE.dwSize>
  1904. * field before calling this method.
  1905. *
  1906. * If <e DIDEVICEINSTANCE.dwSize> is equal to the size of
  1907. * the <t DIDEVICEINSTANCE_DX3> structure, then a
  1908. * DirectX 3.0-compatible structure is returned instead of
  1909. * a DirectX 5.0 structure.
  1910. *
  1911. * @returns
  1912. *
  1913. * Returns a COM error code. The following error codes are
  1914. * intended to be illustrative and not necessarily comprehensive.
  1915. *
  1916. * <c DI_OK> = <c S_OK>: The operation completed successfully.
  1917. *
  1918. * <c DIERR_INVALIDPARAM> = <c E_INVALIDARG>: One or more
  1919. * parameters was invalid.
  1920. *
  1921. *****************************************************************************/
  1922. STDMETHODIMP
  1923. CDIDev_GetDeviceInfoW(PV pddW, LPDIDEVICEINSTANCEW pdidiW)
  1924. {
  1925. HRESULT hres;
  1926. EnterProcR(IDirectInputDevice::GetDeviceInfo, (_ "pp", pddW, pdidiW));
  1927. if(SUCCEEDED(hres = hresPvW(pddW)) &&
  1928. SUCCEEDED(hres = hresFullValidWritePxCb2(pdidiW,
  1929. DIDEVICEINSTANCE_DX5W,
  1930. DIDEVICEINSTANCE_DX3W, 1)))
  1931. {
  1932. PDD this = _thisPvNm(pddW, ddW);
  1933. /*
  1934. * Must protect with the critical section to prevent
  1935. * another thread from Reset()ing behind our back.
  1936. */
  1937. CDIDev_EnterCrit(this);
  1938. pdidiW->guidInstance = this->guid;
  1939. pdidiW->guidProduct = this->guid;
  1940. /*
  1941. * Don't overwrite the dwSize, guidInstance, or guidProduct.
  1942. * Start at the dwDevType.
  1943. */
  1944. ZeroBuf(&pdidiW->dwDevType,
  1945. pdidiW->dwSize - FIELD_OFFSET(DIDEVICEINSTANCEW, dwDevType));
  1946. hres = this->pdcb->lpVtbl->GetDeviceInfo(this->pdcb, pdidiW);
  1947. if(FAILED(hres))
  1948. {
  1949. ScrambleBuf(&pdidiW->guidInstance,
  1950. cbX(DIDEVICEINSTANCEW) -
  1951. FIELD_OFFSET(DIDEVICEINSTANCEW, guidInstance));
  1952. }
  1953. CDIDev_LeaveCrit(this);
  1954. }
  1955. ExitOleProcR();
  1956. return hres;
  1957. }
  1958. /*****************************************************************************
  1959. *
  1960. * @doc INTERNAL
  1961. *
  1962. * @method HRESULT | IDirectInputDeviceA | GetDeviceInfo |
  1963. *
  1964. * ANSI version of same.
  1965. *
  1966. * @cwrap LPDIRECTINPUTDEVICE | lpDirectInputDevice
  1967. *
  1968. * @parm OUT LPDIDEVICEINSTANCEA | pdidiA |
  1969. *
  1970. * Receives information about the device's identity.
  1971. *
  1972. * @returns
  1973. *
  1974. * Returns a COM error code. The following error codes are
  1975. * intended to be illustrative and not necessarily comprehensive.
  1976. *
  1977. * <c DI_OK> = <c S_OK>: The operation completed successfully.
  1978. *
  1979. * <c DIERR_INVALIDPARAM> = <c E_INVALIDARG>: One or more
  1980. * parameters was invalid.
  1981. *
  1982. *****************************************************************************/
  1983. STDMETHODIMP
  1984. CDIDev_GetDeviceInfoA(PV pddA, LPDIDEVICEINSTANCEA pdidiA)
  1985. {
  1986. HRESULT hres;
  1987. EnterProcR(IDirectInputDevice::GetDeviceInfo, (_ "pp", pddA, pdidiA));
  1988. if(SUCCEEDED(hres = hresPvA(pddA)) &&
  1989. SUCCEEDED(hres = hresFullValidWritePxCb2(pdidiA,
  1990. DIDEVICEINSTANCE_DX5A,
  1991. DIDEVICEINSTANCE_DX3A, 1)))
  1992. {
  1993. PDD this = _thisPvNm(pddA, ddA);
  1994. DIDEVICEINSTANCEW diW;
  1995. diW.dwSize = cbX(DIDEVICEINSTANCEW);
  1996. hres = CDIDev_GetDeviceInfoW(&this->ddW, &diW);
  1997. if(SUCCEEDED(hres))
  1998. {
  1999. DeviceInfoWToA(pdidiA, &diW);
  2000. hres = S_OK;
  2001. }
  2002. }
  2003. ExitOleProcR();
  2004. return hres;
  2005. }
  2006. /*****************************************************************************
  2007. *
  2008. * @doc INTERNAL
  2009. *
  2010. * @method void | CDIDev | UnhookCwp |
  2011. *
  2012. * Remove the CallWndProc handler.
  2013. *
  2014. * See <mf CDIDev::InstallCwp> for details.
  2015. *
  2016. *****************************************************************************/
  2017. HWND g_hwndExclusive;
  2018. HHOOK g_hhkCwp;
  2019. void INTERNAL
  2020. CDIDev_UnhookCwp(void)
  2021. {
  2022. DllEnterCrit();
  2023. if(g_hhkCwp)
  2024. {
  2025. UnhookWindowsHookEx(g_hhkCwp);
  2026. g_hhkCwp = 0;
  2027. g_hwndExclusive = 0;
  2028. }
  2029. DllLeaveCrit();
  2030. }
  2031. /*****************************************************************************
  2032. *
  2033. * @doc INTERNAL
  2034. *
  2035. * @method HRESULT | CDIDev | AddForegroundDevice |
  2036. *
  2037. * Add ourselves to the list of devices that need to be
  2038. * unacquired when the window loses foreground activation.
  2039. *
  2040. * @parm PDD | this |
  2041. *
  2042. * Device to be added.
  2043. *
  2044. * @devnote
  2045. *
  2046. * Note that we do not need to AddRef the device, because
  2047. * <f CDIDev_Finalize> will unacquire the device for us
  2048. * automatically, so we will never be freed while still
  2049. * acquired.
  2050. *
  2051. * (Note that if we did choose to AddRef, it must be done
  2052. * outside the DLL critical
  2053. * section, in order to preserve the semaphore hierarchy.)
  2054. *
  2055. *****************************************************************************/
  2056. STDMETHODIMP
  2057. CDIDev_AddForegroundDevice(PDD this)
  2058. {
  2059. HRESULT hres;
  2060. DllEnterCrit();
  2061. #ifdef IDirectInputDevice2Vtbl
  2062. hres = GPA_Append(g_hgpaExcl, this);
  2063. Common_Hold(this);
  2064. #else
  2065. if(g_cpddForeground >= g_cpddForegroundMax)
  2066. {
  2067. AssertF(g_cpddForeground == g_cpddForegroundMax);
  2068. hres = ReallocCbPpv(cbCxX(g_cpddForeground + 10, PDD),
  2069. &g_rgpddForeground);
  2070. if(FAILED(hres))
  2071. {
  2072. goto failed;
  2073. }
  2074. g_cpddForegroundMax = g_cpddForeground + 10;
  2075. }
  2076. AssertF(g_cpddForeground < g_cpddForegroundMax);
  2077. g_rgpddForeground[g_cpddForeground++] = this;
  2078. Common_Hold(this);
  2079. hres = S_OK;
  2080. failed:;
  2081. #endif
  2082. DllLeaveCrit();
  2083. return hres;
  2084. }
  2085. /*****************************************************************************
  2086. *
  2087. * @doc INTERNAL
  2088. *
  2089. * @method void | CDIDev | DelForegroundDevice |
  2090. *
  2091. * Remove ourselves from the list, if we're there.
  2092. * It is not an error if we aren't on the list, because
  2093. * in the case of forced unacquire, the list is blanked
  2094. * out in order to avoid race conditions where somebody
  2095. * tries to acquire a device immediately upon receiving
  2096. * foreground activation, before we get a chance to
  2097. * unacquire all the old guys completely.
  2098. *
  2099. * @parm PDD | this |
  2100. *
  2101. * Device to be removed.
  2102. *
  2103. * @devnote
  2104. *
  2105. * Note that the Unhold must be done outside the DLL critical
  2106. * section, in order to preserve the semaphore hierarchy.
  2107. *
  2108. * Theoretically, the unhold will never drop the reference count
  2109. * to zero (because the latest it could be called is during
  2110. * the AppFinalize, where there is stll the outstanding refcount
  2111. * from the external ref that hasn't been released yet).
  2112. *
  2113. * But it's better to play it safe and always release the
  2114. * object outside.
  2115. *
  2116. *****************************************************************************/
  2117. void INTERNAL
  2118. CDIDev_DelForegroundDevice(PDD this)
  2119. {
  2120. #ifdef IDirectInputDevice2Vtbl
  2121. HRESULT hres;
  2122. #else
  2123. UINT idd;
  2124. #endif
  2125. DllEnterCrit();
  2126. #ifdef IDirectInputDevice2Vtbl
  2127. hres = GPA_DeletePtr(g_hgpaExcl, this);
  2128. if(hres == hresUs(0))
  2129. { /* If the last one went away */
  2130. GPA_Term(g_hgpaExcl); /* Free the tracking memory */
  2131. CDIDev_UnhookCwp(); /* Then unhook ourselves */
  2132. }
  2133. #else
  2134. for(idd = 0; idd < g_cpddForeground; idd++)
  2135. {
  2136. if(g_rgpddForeground[idd] == this)
  2137. {
  2138. g_rgpddForeground[idd] = g_rgpddForeground[--g_cpddForeground];
  2139. if(g_cpddForeground == 0)
  2140. {
  2141. CDIDev_UnhookCwp();
  2142. }
  2143. break;
  2144. }
  2145. }
  2146. #endif
  2147. DllLeaveCrit();
  2148. #ifdef IDirectInputDevice2Vtbl
  2149. if(SUCCEEDED(hres))
  2150. {
  2151. Common_Unhold(this);
  2152. }
  2153. #endif
  2154. }
  2155. /*****************************************************************************
  2156. *
  2157. * @doc INTERNAL
  2158. *
  2159. * @func LRESULT | CDIDev_CallWndProc |
  2160. *
  2161. * Thread-specific CallWndProc handler.
  2162. *
  2163. * Note that we need only one of these, since only the foreground
  2164. * window will require a hook.
  2165. *
  2166. * @parm int | nCode |
  2167. *
  2168. * Notification code.
  2169. *
  2170. * @parm WPARAM | wp |
  2171. *
  2172. * "Specifies whether the message is sent by the current process."
  2173. * We don't care.
  2174. *
  2175. * @parm LPARAM | lp |
  2176. *
  2177. * Points to a <t CWPSTRUCT> which describes the message.
  2178. *
  2179. * @returns
  2180. *
  2181. * Always chains to the next hook.
  2182. *
  2183. *****************************************************************************/
  2184. LRESULT CALLBACK
  2185. CDIDev_CallWndProc(int nCode, WPARAM wp, LPARAM lp)
  2186. {
  2187. LPCWPSTRUCT pcwp = (LPCWPSTRUCT)lp;
  2188. #ifdef WINNT
  2189. static BOOL fKillFocus = FALSE;
  2190. static BOOL fIconic = FALSE;
  2191. fIconic = FALSE;
  2192. /*
  2193. * This part of code is to fix Windows bug 430051.
  2194. * The logic is: if WM_KILLFOCUS is followed by WM_SIZE(minimized),
  2195. * then the app is minimized from full screen mode.
  2196. * This combination should only happen to full screen mode game using DDraw.
  2197. */
  2198. if(pcwp->message == WM_KILLFOCUS)
  2199. {
  2200. fKillFocus = TRUE;
  2201. } else if(pcwp->message == WM_SETFOCUS)
  2202. {
  2203. fKillFocus = FALSE;
  2204. } else if (pcwp->message == WM_SIZE)
  2205. {
  2206. if(pcwp->wParam == SIZE_MINIMIZED){
  2207. if( fKillFocus ) {
  2208. fIconic = TRUE;
  2209. fKillFocus = FALSE;
  2210. }else{
  2211. fKillFocus = FALSE;
  2212. }
  2213. } else {
  2214. fKillFocus = FALSE;
  2215. }
  2216. }
  2217. #endif
  2218. if( nCode == HC_ACTION && (pcwp->message == WM_ACTIVATE
  2219. #ifdef WINNT
  2220. || fIconic
  2221. #endif
  2222. )
  2223. )
  2224. {
  2225. PDD *rgpdid;
  2226. UINT ipdid, cpdid;
  2227. HHOOK hhk;
  2228. #ifdef WINNT
  2229. fIconic = FALSE;
  2230. #endif
  2231. /*
  2232. * We cannot mess with items while inside the DLL critical section,
  2233. * because that would violate our semaphore hierarchy.
  2234. *
  2235. * Instead, we stash the active item list and replace it with
  2236. * an empty list. Then, outside the DLL critical section, we
  2237. * calmly operate on each item.
  2238. */
  2239. DllEnterCrit();
  2240. #ifdef IDirectInputDevice2Vtbl
  2241. rgpdid = (PV)g_hgpaExcl->rgpv;
  2242. cpdid = g_hgpaExcl->cpv;
  2243. GPA_Init(g_hgpaExcl);
  2244. #else
  2245. rgpdid = g_rgpddForeground;
  2246. cpdid = g_cpddForeground;
  2247. g_rgpddForeground = 0;
  2248. g_cpddForeground = 0;
  2249. g_cpddForegroundMax = 0;
  2250. #endif
  2251. /*
  2252. * Some sanity checking here.
  2253. */
  2254. for(ipdid = 0; ipdid < cpdid; ipdid++)
  2255. {
  2256. AssertF(rgpdid[ipdid]);
  2257. }
  2258. DllLeaveCrit();
  2259. /*
  2260. * Note that InternalUnacquire will set the notification
  2261. * event so the app knows that input was lost.
  2262. */
  2263. for(ipdid = 0; ipdid < cpdid; ipdid++)
  2264. {
  2265. AssertF(rgpdid[ipdid]);
  2266. SquirtSqflPtszV(sqfl,
  2267. TEXT("Forcing unacquire of %08x due to focus loss"),
  2268. rgpdid[ipdid]);
  2269. CDIDev_InternalUnacquire(rgpdid[ipdid]);
  2270. Common_Unhold(rgpdid[ipdid]);
  2271. }
  2272. FreePpv(&rgpdid);
  2273. hhk = g_hhkCwp;
  2274. CDIDev_UnhookCwp();
  2275. return CallNextHookEx(hhk, nCode, wp, lp);
  2276. }
  2277. return CallNextHookEx(g_hhkCwp, nCode, wp, lp);
  2278. }
  2279. /*****************************************************************************
  2280. *
  2281. * @doc INTERNAL
  2282. *
  2283. * @method HRESULT | CDIDev | CanAcquire |
  2284. *
  2285. * Determine whether the device may be acquired exclusively.
  2286. *
  2287. * If exclusive access is not requested, then the function
  2288. * succeeds vacuously.
  2289. *
  2290. * If exclusive access is requested, then the window must
  2291. * be the foreground window and must belong to the current
  2292. * process.
  2293. *
  2294. *****************************************************************************/
  2295. STDMETHODIMP
  2296. CDIDev_CanAcquire(PDD this)
  2297. {
  2298. HRESULT hres;
  2299. AssertF(CDIDev_IsConsistent(this));
  2300. if(this->discl & DISCL_FOREGROUND)
  2301. {
  2302. HWND hwndForeground = GetForegroundWindow();
  2303. AssertF(this->hwnd);
  2304. /*
  2305. * Note that we don't have to do an IsWindow() on this->hwnd,
  2306. * because GetForegroundWindow() will always return a valid
  2307. * window or NULL. Since we already tested this->hwnd != 0
  2308. * above, the only way the equality can occur is if the window
  2309. * handle is indeed valid.
  2310. */
  2311. if(this->hwnd == hwndForeground && !IsIconic(this->hwnd))
  2312. {
  2313. /*
  2314. * Need to make sure that the window "still" belongs to
  2315. * this process, in case the window handle got recycled.
  2316. */
  2317. DWORD idProcess;
  2318. GetWindowThreadProcessId(this->hwnd, &idProcess);
  2319. if(idProcess == GetCurrentProcessId())
  2320. {
  2321. hres = S_OK;
  2322. } else
  2323. {
  2324. /*
  2325. * Put a permanently invalid handle here so that we
  2326. * won't accidentally take a new window that happens
  2327. * to get a recycled handle value.
  2328. */
  2329. this->hwnd = INVALID_HANDLE_VALUE;
  2330. RPF("Error: Window destroyed while associated with a device");
  2331. hres = E_INVALIDARG;
  2332. }
  2333. } else
  2334. {
  2335. hres = DIERR_OTHERAPPHASPRIO;
  2336. }
  2337. } else
  2338. { /* No window; vacuous success */
  2339. hres = S_OK;
  2340. }
  2341. return hres;
  2342. }
  2343. /*****************************************************************************
  2344. *
  2345. * @doc INTERNAL
  2346. *
  2347. * @method HRESULT | CDIDev | InstallCwp |
  2348. *
  2349. * Install the CallWndProc handler.
  2350. *
  2351. * There is a bit of subtlety in the way this works.
  2352. * Since only foreground windows may acquire exclusive access,
  2353. * we need only one hook (for there is but one foreground
  2354. * window in the system).
  2355. *
  2356. * _NT_: Does NT handle this correctly in the face of
  2357. * multiple window stations?
  2358. *
  2359. * The tricky part is that input loss occurs asynchronously.
  2360. * So a device that registers a <f CallWindowProc> hook doesn't
  2361. * find out that the input has been lost until the app next
  2362. * calls <f Unacquire>.
  2363. *
  2364. * So the way this is done is via a collection of global
  2365. * variables (which must be accessed atomically).
  2366. *
  2367. * <p g_hhkCwp> is the hook handle itself. It is zero when
  2368. * no hook is installed.
  2369. *
  2370. * Note that we install the windows hook while inside both the
  2371. * object critical section and the DLL critical section.
  2372. * You might think we'd risk deadlocking with the hook procedure,
  2373. * in case the window asynchronously deactivates while we're
  2374. * installing the hook. But your worries are unfounded:
  2375. * If the window is on the current thread, then window messages
  2376. * won't be dispatched because we never call <f GetMessage> or
  2377. * go into a modal loop. And if the window is on another thread,
  2378. * then that other thread will simply have to wait until we're done.
  2379. *
  2380. *****************************************************************************/
  2381. STDMETHODIMP
  2382. CDIDev_InstallCwp(PDD this)
  2383. {
  2384. HRESULT hres;
  2385. if(this->discl & DISCL_FOREGROUND)
  2386. {
  2387. AssertF(this->hwnd);
  2388. hres = CDIDev_CanAcquire(this);
  2389. if(SUCCEEDED(hres))
  2390. {
  2391. hres = CDIDev_AddForegroundDevice(this);
  2392. if(SUCCEEDED(hres))
  2393. {
  2394. DllEnterCrit();
  2395. if(!g_hhkCwp)
  2396. { /* We're the first one */
  2397. g_hwndExclusive = this->hwnd;
  2398. g_hhkCwp = SetWindowsHookEx(WH_CALLWNDPROC,
  2399. CDIDev_CallWndProc, g_hinst,
  2400. GetWindowThreadProcessId(this->hwnd, 0));
  2401. } else
  2402. {
  2403. AssertF(g_hwndExclusive == this->hwnd);
  2404. }
  2405. DllLeaveCrit();
  2406. /*
  2407. * There is a race condition up above, where the foreground
  2408. * window can change between the call to CanAcquire() and
  2409. * the call to SetWindowsHookEx(). Close the window by
  2410. * checking a second time after the hook is installed.
  2411. *
  2412. * If we leave the window open, it's possible that we will
  2413. * perform a physical acquire while the wrong window has
  2414. * foreground activation. Then, of course, we are never told
  2415. * that *our* window lost activation, and the physical device
  2416. * remains acquired forever.
  2417. */
  2418. hres = CDIDev_CanAcquire(this);
  2419. if(SUCCEEDED(hres))
  2420. {
  2421. } else
  2422. {
  2423. SquirtSqflPtszV(sqflError,
  2424. TEXT("Window no longer foreground; ")
  2425. TEXT("punting acquire"));
  2426. CDIDev_InternalUnacquire(this);
  2427. }
  2428. }
  2429. } else
  2430. {
  2431. hres = DIERR_OTHERAPPHASPRIO;
  2432. }
  2433. } else
  2434. { /* No window; vacuous success */
  2435. hres = S_OK;
  2436. }
  2437. return hres;
  2438. }
  2439. /*****************************************************************************
  2440. *
  2441. * @doc INTERNAL
  2442. *
  2443. * @method HRESULT | IDirectInputDevice | RealUnacquire |
  2444. *
  2445. * Release access to the device, even if the device was only
  2446. * partially acquired.
  2447. *
  2448. * @cwrap LPDIRECTINPUTDEVICE | lpDirectInputDevice
  2449. *
  2450. * @returns
  2451. *
  2452. * None.
  2453. *
  2454. *****************************************************************************/
  2455. STDMETHODIMP
  2456. CDIDev_RealUnacquire(PDD this)
  2457. {
  2458. HRESULT hres;
  2459. hres = this->pdcb->lpVtbl->Unacquire(this->pdcb);
  2460. if(hres == S_FALSE)
  2461. {
  2462. if(this->fAcquiredInstance)
  2463. {
  2464. this->fAcquiredInstance = 0;
  2465. hres = Hel_UnacquireInstance(this->pvi);
  2466. AssertF(SUCCEEDED(hres));
  2467. } else
  2468. {
  2469. hres = S_OK;
  2470. }
  2471. }
  2472. return hres;
  2473. }
  2474. #ifdef IDirectInputDevice2Vtbl
  2475. /*****************************************************************************
  2476. *
  2477. * @doc INTERNAL
  2478. *
  2479. * @method HRESULT | CDIDev | FFAcquire |
  2480. *
  2481. * The device has been successfully acquired. Do any
  2482. * necessary force feedback related acquisition goo.
  2483. *
  2484. * @cwrap PDD | pdd
  2485. *
  2486. *****************************************************************************/
  2487. STDMETHODIMP
  2488. CDIDev_FFAcquire(PDD this)
  2489. {
  2490. HRESULT hres;
  2491. AssertF(CDIDev_InCrit(this));
  2492. if(this->pes && (this->discl & DISCL_EXCLUSIVE))
  2493. {
  2494. if(SUCCEEDED(hres = this->pes->lpVtbl->SendForceFeedbackCommand(
  2495. this->pes, &this->sh,
  2496. DISFFC_FORCERESET)))
  2497. {
  2498. CDIDev_RefreshGain(this);
  2499. /*
  2500. * If the center spring is to be disabled,
  2501. * then disable the center spring.
  2502. */
  2503. if(!this->dwAutoCenter)
  2504. {
  2505. this->pes->lpVtbl->SendForceFeedbackCommand(
  2506. this->pes, &this->sh,
  2507. DISFFC_STOPALL);
  2508. }
  2509. hres = S_OK;
  2510. }
  2511. } else
  2512. {
  2513. hres = S_OK;
  2514. }
  2515. return hres;
  2516. }
  2517. #endif
  2518. /*****************************************************************************
  2519. *
  2520. * @doc EXTERNAL
  2521. *
  2522. * @method HRESULT | IDirectInputDevice | Acquire |
  2523. *
  2524. * Obtains access to the device.
  2525. *
  2526. * Device acquisition does not reference-count. If a device is
  2527. * acquired twice then unacquired once, the device is unacquired.
  2528. *
  2529. * Before the device can be acquired, a data format must
  2530. * first be set via the <mf IDirectInputDevice::SetDataFormat>
  2531. * method.
  2532. *
  2533. * @cwrap LPDIRECTINPUTDEVICE | lpDirectInputDevice
  2534. *
  2535. * @returns
  2536. *
  2537. * Returns a COM error code. The following error codes are
  2538. * intended to be illustrative and not necessarily comprehensive.
  2539. *
  2540. * <c DI_OK> = <c S_OK>: The operation completed successfully.
  2541. *
  2542. * <c S_FALSE>: The device has already been acquired. Note
  2543. * that this value is a success code.
  2544. *
  2545. * <c DIERR_OTHERAPPHASPRIO>: Access to the device was not granted.
  2546. * The most common cause of this is attempting to acquire a
  2547. * device with the <c DISCL_FOREGROUND> cooperative level when
  2548. * the associated window is not foreground.
  2549. *
  2550. * This error code is also returned if an attempt to
  2551. * acquire a device in exclusive mode fails because the device
  2552. * is already acquired in exclusive mode by somebody else.
  2553. *
  2554. * <c DIERR_INVALIDPARAM> = <c E_INVALIDARG>: The device
  2555. * does not have a selected data format.
  2556. */
  2557. /*
  2558. * The point at which we take the exclusive semaphore is important.
  2559. * We should do it after preliminary validation of foreground
  2560. * permission, so that we don't accidentally lock out somebody
  2561. * else who legitimately has permission.
  2562. *
  2563. *****************************************************************************/
  2564. STDMETHODIMP
  2565. CDIDev_Acquire(PV pdd _THAT)
  2566. {
  2567. HRESULT hres;
  2568. EnterProcR(IDirectInputDevice::Acquire, (_ "p", pdd));
  2569. if(SUCCEEDED(hres = hresPvT(pdd)))
  2570. {
  2571. PDD this = _thisPv(pdd);
  2572. /*
  2573. * Must protect with the critical section to prevent somebody from
  2574. * acquiring or changing the data format while we're acquiring.
  2575. */
  2576. CDIDev_EnterCrit(this);
  2577. /*
  2578. * The app explicitly messed with acquisition. Any problems
  2579. * retrieving data are now the apps' fault.
  2580. */
  2581. this->hresNotAcquired = DIERR_NOTACQUIRED;
  2582. //We now need a pvi even in where the device doesn't use VxDs
  2583. if(this->pdix && this->pvi)
  2584. {
  2585. if(this->pvi->fl & VIFL_ACQUIRED)
  2586. {
  2587. hres = S_FALSE;
  2588. } else if(SUCCEEDED(hres = CDIDev_CanAcquire(this)))
  2589. {
  2590. hres = Excl_Acquire(&this->guid, this->hwnd, this->discl);
  2591. if(SUCCEEDED(hres))
  2592. {
  2593. #ifdef IDirectInputDevice2Vtbl
  2594. if(SUCCEEDED(hres = CDIDev_FFAcquire(this)))
  2595. {
  2596. #endif
  2597. hres = this->pdcb->lpVtbl->Acquire(this->pdcb);
  2598. if(SUCCEEDED(hres))
  2599. {
  2600. if(hres == S_FALSE)
  2601. {
  2602. hres = Hel_AcquireInstance(this->pvi);
  2603. if(SUCCEEDED(hres))
  2604. {
  2605. this->fAcquiredInstance = 1;
  2606. /*
  2607. * If relative mode, need to prime the
  2608. * pvLastBuffer with the current state.
  2609. */
  2610. if(this->pvi->fl & VIFL_RELATIVE)
  2611. {
  2612. hres = this->pdcb->lpVtbl->GetDeviceState(
  2613. this->pdcb, this->pvLastBuffer);
  2614. if(FAILED(hres))
  2615. {
  2616. goto unacquire;
  2617. }
  2618. }
  2619. } else
  2620. {
  2621. goto unacquire;
  2622. }
  2623. }
  2624. /*
  2625. * Note that InstallCwp must be the last thing
  2626. * we do, because it will add us to the foreground
  2627. * list, and none of our error exit paths remove us.
  2628. */
  2629. hres = CDIDev_InstallCwp(this);
  2630. if(SUCCEEDED(hres))
  2631. {
  2632. this->fAcquired = 1;
  2633. this->fOnceAcquired = 1;
  2634. /*
  2635. * From now on, if we lose acquisition,
  2636. * it's not the app's fault.
  2637. */
  2638. this->hresNotAcquired = DIERR_INPUTLOST;
  2639. hres = S_OK;
  2640. } else
  2641. {
  2642. goto unacquire;
  2643. }
  2644. } else
  2645. {
  2646. unacquire:;
  2647. CDIDev_RealUnacquire(this);
  2648. }
  2649. #ifdef IDirectInputDevice2Vtbl
  2650. }
  2651. #endif
  2652. }
  2653. }
  2654. } else
  2655. {
  2656. hres = E_INVALIDARG;
  2657. }
  2658. // For some apps (e.g. "Sonic R") we need to always succeed Acquire() -- see Windows bug 15085
  2659. if ((this->diHacks.fSucceedAcquire ) && (FAILED(hres)))
  2660. {
  2661. this->fOnceAcquired = 1;
  2662. hres = S_OK;
  2663. }
  2664. CDIDev_LeaveCrit(this);
  2665. }
  2666. ExitOleProcR();
  2667. return hres;
  2668. }
  2669. #ifdef XDEBUG
  2670. CSET_STUBS(Acquire, (PV pdd), (pdd THAT_))
  2671. #else
  2672. #define CDIDev_AcquireA CDIDev_Acquire
  2673. #define CDIDev_AcquireW CDIDev_Acquire
  2674. #endif
  2675. /*****************************************************************************
  2676. *
  2677. * @doc INTERNAL
  2678. *
  2679. * @method HRESULT | IDirectInputDevice | InternalUnacquire |
  2680. *
  2681. * This does the real work of unacquiring. The internal
  2682. * version bypasses the "the app requested this" flag,
  2683. * so when the app goes to request something, it gets
  2684. * <c DIERR_INPUTLOST> instead of <c DIERR_NOTACQUIRED>.
  2685. *
  2686. * If the application error code is <c DIERR_INPUTLOST>, then
  2687. * we will also signal the associated event so that it knows
  2688. * that the state changed.
  2689. *
  2690. * @cwrap LPDIRECTINPUTDEVICE | lpDirectInputDevice
  2691. *
  2692. *****************************************************************************/
  2693. STDMETHODIMP
  2694. CDIDev_InternalUnacquire(PDD this)
  2695. {
  2696. HRESULT hres;
  2697. EnterProcR(IDirectInputDevice::InternalUnacquire, (_ "p", this));
  2698. /*
  2699. * Must protect with the critical section to prevent confusing other
  2700. * methods which change their behavior depending on whether the device
  2701. * is acquired.
  2702. */
  2703. CDIDev_EnterCrit(this);
  2704. if(this->fAcquired)
  2705. {
  2706. AssertF(this->pdcb != c_pdcbNil);
  2707. this->fAcquired = 0;
  2708. Excl_Unacquire(&this->guid, this->hwnd, this->discl);
  2709. if(this->discl & DISCL_FOREGROUND)
  2710. {
  2711. AssertF(this->hwnd);
  2712. CDIDev_DelForegroundDevice(this);
  2713. #ifdef WINNT
  2714. if( IsIconic(this->hwnd) ) {
  2715. this->fUnacquiredWhenIconic = 1;
  2716. }
  2717. #endif
  2718. }
  2719. #ifdef IDirectInputDevice2Vtbl
  2720. /*
  2721. * ISSUE-2001/03/29-timgill multithreading means we cannot rely on Excl_Unaquire() return values
  2722. * We cannot trust the return value (if we made one)
  2723. * of Excl_Unacquire, because another instance may have
  2724. * snuck in and acquired the device after we Excl_Unacquire'd
  2725. * it and started doing force feedback on it.
  2726. *
  2727. * We need to fix this with the joystick mutex.
  2728. */
  2729. if(this->pes && (this->discl & DISCL_EXCLUSIVE))
  2730. {
  2731. this->pes->lpVtbl->SendForceFeedbackCommand(
  2732. this->pes, &this->sh, DISFFC_RESET);
  2733. this->sh.dwTag = 0;
  2734. }
  2735. #endif
  2736. hres = CDIDev_RealUnacquire(this);
  2737. if(this->hresNotAcquired == DIERR_INPUTLOST)
  2738. {
  2739. CDIDev_SetNotifyEvent(this);
  2740. }
  2741. } else
  2742. {
  2743. hres = S_FALSE;
  2744. }
  2745. CDIDev_LeaveCrit(this);
  2746. ExitOleProcR();
  2747. return hres;
  2748. }
  2749. /*****************************************************************************
  2750. *
  2751. * @doc EXTERNAL
  2752. *
  2753. * @method HRESULT | IDirectInputDevice | Unacquire |
  2754. *
  2755. * Release access to the device.
  2756. *
  2757. * @cwrap LPDIRECTINPUTDEVICE | lpDirectInputDevice
  2758. *
  2759. * @returns
  2760. *
  2761. * Returns a COM error code. The following error codes are
  2762. * intended to be illustrative and not necessarily comprehensive.
  2763. *
  2764. * <c DI_OK> = <c S_OK>: The operation completed successfully.
  2765. *
  2766. * <c S_FALSE>: The object is not currently acquired.
  2767. * This may have been caused by a prior loss of input.
  2768. * Note that this is a success code.
  2769. *
  2770. *****************************************************************************/
  2771. STDMETHODIMP
  2772. CDIDev_Unacquire(PV pdd _THAT)
  2773. {
  2774. HRESULT hres;
  2775. EnterProcR(IDirectInputDevice::Unacquire, (_ "p", pdd));
  2776. if(SUCCEEDED(hres = hresPvT(pdd)))
  2777. {
  2778. PDD this = _thisPv(pdd);
  2779. /*
  2780. * The app explicitly messed with acquisition. Any problems
  2781. * retrieving data are now the apps' fault.
  2782. */
  2783. this->hresNotAcquired = DIERR_NOTACQUIRED;
  2784. hres = CDIDev_InternalUnacquire(this);
  2785. }
  2786. ExitOleProcR();
  2787. return hres;
  2788. }
  2789. #ifdef XDEBUG
  2790. CSET_STUBS(Unacquire, (PV pdd), (pdd THAT_))
  2791. #else
  2792. #define CDIDev_UnacquireA CDIDev_Unacquire
  2793. #define CDIDev_UnacquireW CDIDev_Unacquire
  2794. #endif
  2795. /*****************************************************************************
  2796. *
  2797. * @doc INTERNAL
  2798. *
  2799. * @method PDIPROPVALIDINFO | IDirectInputDevice | ppviFind |
  2800. *
  2801. * Locate the DIPROPVALIDINFO structure that describes
  2802. * the predefined property.
  2803. *
  2804. * @parm const GUID * | pguid |
  2805. *
  2806. * Property guid, or predefined property.
  2807. *
  2808. * @returns
  2809. *
  2810. * Pointer to a const <t DIPROPVALIDINFO> that describes
  2811. * what is and is not valid for this property.
  2812. *
  2813. * Returns 0 if the property is not one of the predefined
  2814. * properties.
  2815. *
  2816. *****************************************************************************/
  2817. #pragma BEGIN_CONST_DATA
  2818. typedef struct DIPROPVALIDINFO
  2819. {
  2820. PCGUID pguid; /* Property name */
  2821. DWORD dwSize; /* expected size */
  2822. DWORD fl; /* flags */
  2823. } DIPROPVALIDINFO, *PDIPROPVALIDINFO;
  2824. /*
  2825. * Note that the flags are negative in sense.
  2826. * This makes validation easier.
  2827. */
  2828. #define DIPVIFL_NOTDEVICE 0x00000001 /* Cannot be device */
  2829. #define DIPVIFL_NOTOBJECT 0x00000002 /* Cannot be object */
  2830. #define DIPVIFL_READONLY 0x00000004 /* Cannot be set */
  2831. #define DIPVIFL_NOTPRIVATE 0x00000008 /* Cannot handle private pvi */
  2832. #define DIPVIFL_NOTACQUIRED 0x00000010 /* Cannot modify while acquired */
  2833. DIPROPVALIDINFO c_rgpvi[] = {
  2834. {
  2835. DIPROP_BUFFERSIZE,
  2836. cbX(DIPROPDWORD),
  2837. DIPVIFL_NOTOBJECT | DIPVIFL_NOTPRIVATE | DIPVIFL_NOTACQUIRED,
  2838. },
  2839. {
  2840. DIPROP_AXISMODE,
  2841. cbX(DIPROPDWORD),
  2842. DIPVIFL_NOTOBJECT | DIPVIFL_NOTPRIVATE | DIPVIFL_NOTACQUIRED,
  2843. },
  2844. {
  2845. DIPROP_GRANULARITY,
  2846. cbX(DIPROPDWORD),
  2847. DIPVIFL_NOTDEVICE | DIPVIFL_READONLY | DIPVIFL_NOTACQUIRED,
  2848. },
  2849. {
  2850. DIPROP_RANGE,
  2851. cbX(DIPROPRANGE),
  2852. DIPVIFL_NOTDEVICE | DIPVIFL_NOTACQUIRED,
  2853. },
  2854. /*
  2855. * Note that you can set the dead zone on the entire device.
  2856. * This is the same as applying it to each axis individually.
  2857. */
  2858. {
  2859. DIPROP_DEADZONE,
  2860. cbX(DIPROPDWORD),
  2861. DIPVIFL_NOTACQUIRED,
  2862. },
  2863. /*
  2864. * Note that you can set the saturation on the entire device.
  2865. * This is the same as applying it to each axis individually.
  2866. */
  2867. {
  2868. DIPROP_SATURATION,
  2869. cbX(DIPROPDWORD),
  2870. DIPVIFL_NOTACQUIRED,
  2871. },
  2872. /*
  2873. * Note that you can change the gain either while acquired
  2874. * or not. Your choice.
  2875. */
  2876. {
  2877. DIPROP_FFGAIN,
  2878. cbX(DIPROPDWORD),
  2879. DIPVIFL_NOTOBJECT,
  2880. },
  2881. /*
  2882. * Note that the FF load is meaningful only when acquired,
  2883. * so we'd better not complain if they access it while acquired!
  2884. */
  2885. {
  2886. DIPROP_FFLOAD,
  2887. cbX(DIPROPDWORD),
  2888. DIPVIFL_NOTOBJECT | DIPVIFL_READONLY,
  2889. },
  2890. {
  2891. DIPROP_AUTOCENTER,
  2892. cbX(DIPROPDWORD),
  2893. DIPVIFL_NOTOBJECT | DIPVIFL_NOTACQUIRED,
  2894. },
  2895. {
  2896. DIPROP_CALIBRATIONMODE,
  2897. cbX(DIPROPDWORD),
  2898. DIPVIFL_NOTOBJECT | DIPVIFL_NOTACQUIRED,
  2899. },
  2900. {
  2901. DIPROP_CALIBRATION,
  2902. cbX(DIPROPCAL),
  2903. DIPVIFL_NOTDEVICE | DIPVIFL_NOTACQUIRED,
  2904. },
  2905. {
  2906. DIPROP_GUIDANDPATH,
  2907. cbX(DIPROPGUIDANDPATH),
  2908. DIPVIFL_NOTOBJECT | DIPVIFL_READONLY,
  2909. },
  2910. {
  2911. DIPROP_INSTANCENAME,
  2912. cbX(DIPROPSTRING),
  2913. DIPVIFL_NOTOBJECT,
  2914. },
  2915. {
  2916. DIPROP_PRODUCTNAME,
  2917. cbX(DIPROPSTRING),
  2918. DIPVIFL_NOTOBJECT,
  2919. },
  2920. {
  2921. DIPROP_MAXBUFFERSIZE,
  2922. cbX(DIPROPDWORD),
  2923. DIPVIFL_NOTOBJECT | DIPVIFL_NOTPRIVATE | DIPVIFL_NOTACQUIRED,
  2924. },
  2925. {
  2926. DIPROP_JOYSTICKID,
  2927. cbX(DIPROPDWORD),
  2928. DIPVIFL_NOTOBJECT | DIPVIFL_NOTACQUIRED,
  2929. },
  2930. {
  2931. DIPROP_GETPORTDISPLAYNAME,
  2932. cbX(DIPROPSTRING),
  2933. DIPVIFL_NOTOBJECT | DIPVIFL_READONLY,
  2934. },
  2935. /*
  2936. * Note that you can change the report ID while acquired
  2937. * or not. Your choice.
  2938. */
  2939. {
  2940. DIPROP_ENABLEREPORTID,
  2941. cbX(DIPROPDWORD),
  2942. 0x0,
  2943. },
  2944. #if 0
  2945. {
  2946. DIPROP_SPECIFICCALIBRATION,
  2947. cbX(DIPROPCAL),
  2948. DIPVIFL_NOTDEVICE | DIPVIFL_NOTACQUIRED,
  2949. },
  2950. #endif
  2951. };
  2952. #pragma END_CONST_DATA
  2953. STDMETHODIMP_(PDIPROPVALIDINFO)
  2954. CDIDev_ppviFind(PCGUID pguid)
  2955. {
  2956. PDIPROPVALIDINFO ppvi;
  2957. UINT ipvi;
  2958. for(ipvi = 0, ppvi = c_rgpvi; ipvi < cA(c_rgpvi); ipvi++, ppvi++)
  2959. {
  2960. if(ppvi->pguid == pguid)
  2961. {
  2962. goto found;
  2963. }
  2964. }
  2965. ppvi = 0;
  2966. found:
  2967. return ppvi;
  2968. }
  2969. /*****************************************************************************
  2970. *
  2971. * @doc INTERNAL
  2972. *
  2973. * @method HRESULT | IDirectInputDevice | hresValidProp |
  2974. *
  2975. * Check that the property structure makes sense.
  2976. * Returns the object index for further processing.
  2977. *
  2978. * @parm const GUID * | pguid |
  2979. *
  2980. * Property guid, or predefined property.
  2981. *
  2982. * @parm LPCDIPROPHEADER | pdiph |
  2983. *
  2984. * Propery header structure.
  2985. *
  2986. * @parm BOOL | fWrite |
  2987. *
  2988. * Whether property should be validate for writing.
  2989. *
  2990. * @parm OUT LPDIPROPINFO | ppropi |
  2991. *
  2992. * Receives object index.
  2993. *
  2994. *****************************************************************************/
  2995. typedef BOOL (WINAPI *PFNBAD)(PCV pv, UINT cb);
  2996. STDMETHODIMP
  2997. CDIDev_hresValidProp(PDD this, const GUID *pguid, LPCDIPROPHEADER pdiph,
  2998. BOOL fWrite, LPDIPROPINFO ppropi)
  2999. {
  3000. HRESULT hres;
  3001. PFNBAD pfnBad;
  3002. EnterProcR(IDirectInputDevice::Get/SetProperty,
  3003. (_ "pxpx", this, pguid, pdiph, fWrite));
  3004. AssertF(CDIDev_InCrit(this));
  3005. if(fWrite)
  3006. {
  3007. pfnBad = (PFNBAD)IsBadWritePtr;
  3008. } else
  3009. {
  3010. pfnBad = (PFNBAD)IsBadReadPtr;
  3011. }
  3012. if(!pfnBad(pdiph, cbX(DIPROPHEADER)) &&
  3013. pdiph->dwHeaderSize == cbX(DIPROPHEADER) &&
  3014. pdiph->dwSize % 4 == 0 &&
  3015. pdiph->dwSize >= pdiph->dwHeaderSize &&
  3016. !pfnBad(pdiph, pdiph->dwSize))
  3017. {
  3018. if(fWrite)
  3019. {
  3020. ScrambleBuf((PV)(pdiph+1), pdiph->dwSize - cbX(DIPROPHEADER));
  3021. }
  3022. /*
  3023. * Now convert the item descriptor into an index.
  3024. */
  3025. hres = CDIDev_hresMapHow(this, pdiph->dwObj, pdiph->dwHow, ppropi);
  3026. if(SUCCEEDED(hres))
  3027. {
  3028. /*
  3029. * Now validate the property id or guid.
  3030. */
  3031. if(HIWORD((UINT_PTR)pguid) == 0)
  3032. {
  3033. PDIPROPVALIDINFO ppvi;
  3034. ppvi = CDIDev_ppviFind(pguid);
  3035. /*
  3036. * Note that if we don't find the GUID in our list,
  3037. * we fail it straight away. This prevents ISVs
  3038. * from trying to create properties in the Microsoft
  3039. * Reserved range.
  3040. */
  3041. if(ppvi)
  3042. {
  3043. if( ppvi->pguid == DIPROP_CALIBRATION ) {
  3044. if( pdiph->dwSize == ppvi->dwSize ||
  3045. pdiph->dwSize == cbX(DIPROPCALPOV) )
  3046. {
  3047. hres = S_OK;
  3048. } else {
  3049. RPF("%s: Arg 2: Invalid dwSize for property", s_szProc);
  3050. hres = E_INVALIDARG;
  3051. }
  3052. } else if( pdiph->dwSize == ppvi->dwSize )
  3053. {
  3054. hres = S_OK;
  3055. } else
  3056. {
  3057. RPF("%s: Arg 2: Invalid dwSize for property", s_szProc);
  3058. hres = E_INVALIDARG;
  3059. }
  3060. } else
  3061. {
  3062. RPF("%s: Arg 1: Unknown property", s_szProc);
  3063. hres = E_NOTIMPL;
  3064. }
  3065. } else
  3066. {
  3067. hres = hresFullValidGuid(pguid, 1);
  3068. }
  3069. }
  3070. } else
  3071. {
  3072. RPF("%s: Arg 2: Invalid pointer", s_szProc);
  3073. hres = E_INVALIDARG;
  3074. }
  3075. return hres;
  3076. }
  3077. /*****************************************************************************
  3078. *
  3079. * @doc INTERNAL
  3080. *
  3081. * @method HRESULT | CDIDev | hresValidDefProp |
  3082. *
  3083. * Determine whether the property is something we can handle
  3084. * in the default property handler.
  3085. *
  3086. * @parm IN LPCDIPROPINFO | ppropi |
  3087. *
  3088. * Information describing the property being retrieved.
  3089. *
  3090. * @parm DWORD | dwFlags |
  3091. *
  3092. * Flags for forbidden things.
  3093. * <c DIPVIFL_READONLY> if being validated for writing.
  3094. *
  3095. * @returns
  3096. *
  3097. * Returns a COM error code. The following error codes are
  3098. * intended to be illustrative and not necessarily comprehensive.
  3099. *
  3100. * <c DI_OK> = <c S_OK>: Passes validation.
  3101. *
  3102. * <c E_NOTIMPL>: Not something we handle.
  3103. *
  3104. *
  3105. *****************************************************************************/
  3106. HRESULT INTERNAL
  3107. CDIDev_hresValidDefProp(PDD this, LPCDIPROPINFO ppropi, DWORD dwFlags)
  3108. {
  3109. HRESULT hres;
  3110. PDIPROPVALIDINFO ppvi;
  3111. EnterProc(CDIDev_hresValidDefProp,
  3112. (_ "pGxx", this, ppropi->pguid, ppropi->dwDevType, dwFlags));
  3113. /*
  3114. * Note that it's okay if the device is acquired. We want to
  3115. * allow GetProperty to succeed on an acquired device.
  3116. */
  3117. AssertF(CDIDev_InCrit(this));
  3118. ppvi = CDIDev_ppviFind(ppropi->pguid);
  3119. if(ppvi)
  3120. {
  3121. if(ppropi->iobj == 0xFFFFFFFF)
  3122. {
  3123. dwFlags |= DIPVIFL_NOTDEVICE; /* Fail if devices forbidden */
  3124. } else
  3125. {
  3126. dwFlags |= DIPVIFL_NOTOBJECT; /* Fail if objects forbidden */
  3127. }
  3128. if(this->pvi == 0)
  3129. {
  3130. dwFlags |= DIPVIFL_NOTPRIVATE; /* Fail if privates forbidden */
  3131. }
  3132. /*
  3133. * If attempting to modify property and we are acquired,
  3134. * then also set the "but not while acquired" filter.
  3135. */
  3136. if((dwFlags & DIPVIFL_READONLY) && this->fAcquired)
  3137. {
  3138. dwFlags |= DIPVIFL_NOTACQUIRED; /* Fail if r/o while acq'd */
  3139. }
  3140. if((ppvi->fl & dwFlags) == 0)
  3141. {
  3142. hres = S_OK; /* Seems reasonable */
  3143. } else
  3144. {
  3145. if(ppvi->fl & dwFlags & DIPVIFL_READONLY)
  3146. {
  3147. RPF("SetProperty: Property is read-only");
  3148. hres = DIERR_READONLY;
  3149. } else if(ppvi->fl & dwFlags & DIPVIFL_NOTACQUIRED)
  3150. {
  3151. RPF("SetProperty: Cannot change property while acquired");
  3152. hres = DIERR_ACQUIRED;
  3153. } else
  3154. {
  3155. RPF("Get/SetProperty: Property does not exist for that object");
  3156. hres = E_NOTIMPL; /* Cannot do that */
  3157. }
  3158. }
  3159. } else
  3160. {
  3161. RPF("Get/SetProperty: Property does not exist");
  3162. hres = E_NOTIMPL; /* Definitely way out */
  3163. }
  3164. ExitOleProc();
  3165. return hres;
  3166. }
  3167. /*****************************************************************************
  3168. *
  3169. * @doc INTERNAL
  3170. *
  3171. * @method HRESULT | CDIDev | DefGetProperty |
  3172. *
  3173. * Default implementation of <mf IDirectInputDevice::GetProperty>
  3174. * to handle properties which the device decides not to implement.
  3175. *
  3176. * @parm IN LPCDIPROPINFO | ppropi |
  3177. *
  3178. * Information describing the property being retrieved.
  3179. *
  3180. * @parm OUT LPDIPROPHEADER | pdiph |
  3181. *
  3182. * Where to put the property value.
  3183. *
  3184. * @returns
  3185. *
  3186. * Returns a COM error code. The following error codes are
  3187. * intended to be illustrative and not necessarily comprehensive.
  3188. *
  3189. * <c DI_OK> = <c S_OK>: The operation completed successfully.
  3190. *
  3191. * <c DIERR_INVALIDPARAM> = <c E_INVALIDARG>: The
  3192. * <p pdiph> parameter is not a valid pointer.
  3193. *
  3194. *
  3195. *****************************************************************************/
  3196. STDMETHODIMP
  3197. CDIDev_DefGetProperty(PDD this, LPCDIPROPINFO ppropi, LPDIPROPHEADER pdiph)
  3198. {
  3199. HRESULT hres;
  3200. EnterProc(CDIDev_DefGetProperty,
  3201. (_ "pGx", this, ppropi->pguid, ppropi->dwDevType));
  3202. AssertF(CDIDev_InCrit(this));
  3203. hres = CDIDev_hresValidDefProp(this, ppropi, 0);
  3204. if(SUCCEEDED(hres))
  3205. {
  3206. LPDIPROPDWORD pdipdw = (PV)pdiph;
  3207. LPDIPROPRANGE pdiprg = (PV)pdiph;
  3208. switch((DWORD)(UINT_PTR)ppropi->pguid)
  3209. {
  3210. case (DWORD)(UINT_PTR)DIPROP_BUFFERSIZE:
  3211. AssertF(this->pvi); /* Validation should've caught this */
  3212. pdipdw->dwData = this->celtBuf;
  3213. hres = S_OK;
  3214. break;
  3215. case (DWORD)(UINT_PTR)DIPROP_AXISMODE:
  3216. AssertF(this->pvi); /* Validation should've caught this */
  3217. if(this->pvi->fl & VIFL_RELATIVE)
  3218. {
  3219. pdipdw->dwData = DIPROPAXISMODE_REL;
  3220. } else
  3221. {
  3222. pdipdw->dwData = DIPROPAXISMODE_ABS;
  3223. }
  3224. hres = S_OK;
  3225. break;
  3226. case (DWORD)(UINT_PTR)DIPROP_GRANULARITY:
  3227. if(DIDFT_GETTYPE(ppropi->dwDevType) & DIDFT_AXIS)
  3228. {
  3229. /* Default axis granularity is 1 */
  3230. pdipdw->dwData = 1;
  3231. hres = S_OK;
  3232. } else
  3233. {
  3234. /*
  3235. * Buttons don't have granularity.
  3236. * POVs must be handled by device driver.
  3237. */
  3238. RPF("GetProperty: Object doesn't have a granularity");
  3239. hres = E_NOTIMPL;
  3240. }
  3241. break;
  3242. case (DWORD)(UINT_PTR)DIPROP_RANGE:
  3243. if(DIDFT_GETTYPE(ppropi->dwDevType) & DIDFT_RELAXIS)
  3244. {
  3245. /* Default rel-axis range is infinite */
  3246. pdiprg->lMin = DIPROPRANGE_NOMIN;
  3247. pdiprg->lMax = DIPROPRANGE_NOMAX;
  3248. hres = S_OK;
  3249. } else
  3250. {
  3251. /*
  3252. * Device driver must handle abs axis range.
  3253. * Buttons and POVs don't have range.
  3254. */
  3255. RPF("GetProperty: Object doesn't have a range");
  3256. hres = E_NOTIMPL;
  3257. }
  3258. break;
  3259. case (DWORD)(UINT_PTR)DIPROP_MAXBUFFERSIZE:
  3260. pdipdw->dwData = this->celtBufMax;
  3261. hres = S_OK;
  3262. break;
  3263. #ifdef IDirectInputDevice2Vtbl
  3264. case (DWORD)(UINT_PTR)DIPROP_FFGAIN:
  3265. pdipdw->dwData = this->dwGain;
  3266. hres = S_OK;
  3267. break;
  3268. case (DWORD)(UINT_PTR)DIPROP_FFLOAD:
  3269. hres = CDIDev_GetLoad(this, &pdipdw->dwData);
  3270. break;
  3271. case (DWORD)(UINT_PTR)DIPROP_AUTOCENTER:
  3272. if(this->didcFF & DIDC_FORCEFEEDBACK)
  3273. {
  3274. pdipdw->dwData = this->dwAutoCenter;
  3275. hres = S_OK;
  3276. } else
  3277. {
  3278. hres = E_NOTIMPL;
  3279. }
  3280. break;
  3281. #endif
  3282. default:
  3283. /*
  3284. * The user is asking for some property that simply
  3285. * makes no sense here. E.g., asking for the dead
  3286. * zone on a keyboard.
  3287. */
  3288. SquirtSqflPtszV(sqfl | sqflBenign,
  3289. TEXT("GetProperty: Property 0x%08x not supported on device"),
  3290. (DWORD)(UINT_PTR)ppropi->pguid );
  3291. hres = E_NOTIMPL;
  3292. break;
  3293. }
  3294. }
  3295. ExitOleProc();
  3296. return hres;
  3297. }
  3298. /*****************************************************************************
  3299. *
  3300. * @doc EXTERNAL
  3301. *
  3302. * @method HRESULT | IDirectInputDevice | GetProperty |
  3303. *
  3304. * Obtain information about a device or object in a device.
  3305. *
  3306. * @cwrap LPDIRECTINPUTDEVICE | lpDirectInputDevice
  3307. *
  3308. * @parm IN REFGUID | rguidProp |
  3309. *
  3310. * The identity of the property to be obtained. This can be
  3311. * one of the predefined <c DIPROP_*> values, or it may
  3312. * be a private GUID.
  3313. *
  3314. * @parm IN LPDIPROPHEADER | pdiph |
  3315. *
  3316. * Points to the <t DIPROPHEADER> portion of a structure
  3317. * which dependson the property.
  3318. *
  3319. * @returns
  3320. *
  3321. * Returns a COM error code. The following error codes are
  3322. * intended to be illustrative and not necessarily comprehensive.
  3323. *
  3324. * <c DI_OK> = <c S_OK>: The operation completed successfully.
  3325. *
  3326. * <c DIERR_INVALIDPARAM> = <c E_INVALIDARG>: The
  3327. * <p pdiph> parameter is not a valid pointer, or the
  3328. * <p dwHow> field is invalid, or the <p dwObj> field
  3329. * is not zero when <p dwHow> is set to <c DIPH_DEVICE>.
  3330. *
  3331. * <c DIERR_OBJECTNOTFOUND>: The specified object does not
  3332. * exist.
  3333. *
  3334. * <c DIERR_UNSUPPORTED> = <c E_NOTIMPL>: The property
  3335. * is not supported by the device or object.
  3336. *
  3337. * @ex
  3338. *
  3339. * The following "C" code fragment illustrates how to obtain
  3340. * the value of the <c DIPROP_BUFFERSIZE> property.
  3341. *
  3342. * |
  3343. *
  3344. * DIPROPDWORD dipdw;
  3345. * HRESULT hres;
  3346. * dipdw.diph.dwSize = sizeof(DIPROPDWORD);
  3347. * dipdw.diph.dwHeaderSize = sizeof(DIPROPHEADER);
  3348. * dipdw.diph.dwObj = 0; // device property
  3349. * hres = IDirectInputDevice_GetProperty(pdid, DIPROP_BUFFERSIZE, &dipdw.diph);
  3350. * if (SUCCEEDED(hres)) {
  3351. * // dipdw.dwData contains the value of the property
  3352. * }
  3353. *
  3354. *****************************************************************************/
  3355. STDMETHODIMP
  3356. CDIDev_GetProperty(PV pdd, REFGUID rguid, LPDIPROPHEADER pdiph _THAT)
  3357. {
  3358. HRESULT hres;
  3359. EnterProcR(IDirectInputDevice::GetProperty, (_ "pxp", pdd, rguid, pdiph));
  3360. if(SUCCEEDED(hres = hresPvT(pdd)))
  3361. {
  3362. PDD this = _thisPv(pdd);
  3363. DIPROPINFO propi;
  3364. /*
  3365. * Must protect with the critical section to prevent somebody
  3366. * acquiring or changing the property we are reading. We need
  3367. * to do this before validating, to prevent an acquisition.
  3368. */
  3369. CDIDev_EnterCrit(this);
  3370. propi.pguid = rguid;
  3371. if(SUCCEEDED(hres = CDIDev_hresValidProp(this, rguid, pdiph,
  3372. 1, &propi)))
  3373. {
  3374. hres = this->pdcb->lpVtbl->GetProperty(this->pdcb, &propi, pdiph);
  3375. if(hres == E_NOTIMPL)
  3376. {
  3377. hres = CDIDev_DefGetProperty(this, &propi, pdiph);
  3378. }
  3379. }
  3380. CDIDev_LeaveCrit(this);
  3381. }
  3382. ExitBenignOleProcR();
  3383. return hres;
  3384. }
  3385. #ifdef XDEBUG
  3386. CSET_STUBS(GetProperty, (PV pdm, REFGUID rguid, LPDIPROPHEADER pdiph),
  3387. (pdm, rguid, pdiph THAT_))
  3388. #else
  3389. #define CDIDev_GetPropertyA CDIDev_GetProperty
  3390. #define CDIDev_GetPropertyW CDIDev_GetProperty
  3391. #endif
  3392. /*****************************************************************************
  3393. *
  3394. * @doc INTERNAL
  3395. *
  3396. * @method HRESULT | CDIDev | SetAxisMode |
  3397. *
  3398. * Default handler for clients trying to set the axis mode.
  3399. * If the device doesn't handle axis modes natively, then
  3400. * we'll fake it ourselves.
  3401. *
  3402. * @parm DWORD | dwMode |
  3403. *
  3404. * Desired new mode.
  3405. *
  3406. * @returns
  3407. *
  3408. * Returns a COM error code. The following error codes are
  3409. * intended to be illustrative and not necessarily comprehensive.
  3410. *
  3411. * <c DI_OK> = <c S_OK>: The operation completed successfully.
  3412. *
  3413. *****************************************************************************/
  3414. STDMETHODIMP
  3415. CDIDev_SetAxisMode(PDD this, DWORD dwMode)
  3416. {
  3417. HRESULT hres;
  3418. EnterProcR(IDirectInputDevice::SetProperty(AXISMODE),
  3419. (_ "px", this, dwMode));
  3420. AssertF(this->pvi); /* Validation should've caught this */
  3421. hres = hresFullValidFl(dwMode, DIPROPAXISMODE_VALID, 2);
  3422. if(SUCCEEDED(hres))
  3423. {
  3424. if(dwMode & DIPROPAXISMODE_REL)
  3425. {
  3426. this->GetDeviceState = CDIDev_GetRelDeviceState;
  3427. this->pvi->fl |= VIFL_RELATIVE;
  3428. } else
  3429. {
  3430. this->GetDeviceState = CDIDev_GetAbsDeviceState;
  3431. this->pvi->fl &= ~VIFL_RELATIVE;
  3432. }
  3433. if( this->diHacks.fNativeAxisOnly )
  3434. {
  3435. this->pvi->fl |= VIFL_MODECOMPAT;
  3436. }
  3437. if(this->cAxes)
  3438. {
  3439. hres = S_OK;
  3440. } else
  3441. {
  3442. hres = DI_PROPNOEFFECT;
  3443. }
  3444. }
  3445. ExitOleProc();
  3446. return hres;
  3447. }
  3448. #ifdef IDirectInputDevice2Vtbl
  3449. /*****************************************************************************
  3450. *
  3451. * @doc INTERNAL
  3452. *
  3453. * @method HRESULT | CDIDev | SetAutoCenter |
  3454. *
  3455. * Default handler for clients trying to set the
  3456. * auto-center property.
  3457. *
  3458. * If the device doesn't have control over the
  3459. * auto-center spring, then we fail.
  3460. *
  3461. * @parm DWORD | dwMode |
  3462. *
  3463. * Desired new mode.
  3464. *
  3465. * @returns
  3466. *
  3467. * Returns a COM error code. The following error codes are
  3468. * intended to be illustrative and not necessarily comprehensive.
  3469. *
  3470. * <c DI_OK> = <c S_OK>: The operation completed successfully.
  3471. *
  3472. *****************************************************************************/
  3473. STDMETHODIMP
  3474. CDIDev_SetAutoCenter(PDD this, DWORD dwMode)
  3475. {
  3476. HRESULT hres;
  3477. EnterProcR(IDirectInputDevice::SetProperty(AUTOCENTER),
  3478. (_ "px", this, dwMode));
  3479. hres = hresFullValidFl(dwMode, DIPROPAUTOCENTER_VALID, 2);
  3480. if(SUCCEEDED(hres))
  3481. {
  3482. if(this->didcFF & DIDC_FORCEFEEDBACK)
  3483. {
  3484. /*
  3485. * We need to create the effect driver if disabling
  3486. * autocenter so that CDIDev_FFAcquire will set the feedback
  3487. * mode properly.
  3488. */
  3489. if(fLimpFF(dwMode == DIPROPAUTOCENTER_OFF,
  3490. SUCCEEDED(hres = CDIDev_CreateEffectDriver(this))))
  3491. {
  3492. this->dwAutoCenter = dwMode;
  3493. hres = S_OK;
  3494. }
  3495. } else
  3496. {
  3497. hres = E_NOTIMPL;
  3498. }
  3499. }
  3500. ExitOleProc();
  3501. return hres;
  3502. }
  3503. #endif
  3504. /*****************************************************************************
  3505. *
  3506. * @doc INTERNAL
  3507. *
  3508. * @method HRESULT | CDIDev | SetGlobalAxisProp |
  3509. *
  3510. * Default implementation of <mf IDirectInputDevice::SetProperty>
  3511. * to handle properties which can be applied globally to all
  3512. * absolute axes.
  3513. *
  3514. * @parm IN LPDIPROPINFO | ppropi |
  3515. *
  3516. * Information describing the property being set.
  3517. * We edit it to avoid reallocating memory all the time.
  3518. *
  3519. * @parm IN LPCDIPROPHEADER | pdiph |
  3520. *
  3521. * The property itself.
  3522. *
  3523. * @returns
  3524. *
  3525. * We consider the property-set a success if all candidates
  3526. * succeeded. <c E_NOTIMPL> counts as success, on the assumption
  3527. * that the property is not meaningful on the candidate.
  3528. *
  3529. *****************************************************************************/
  3530. STDMETHODIMP
  3531. CDIDev_SetGlobalAxisProp(PDD this, LPDIPROPINFO ppropi, LPCDIPROPHEADER pdiph)
  3532. {
  3533. HRESULT hres;
  3534. for(ppropi->iobj = 0; ppropi->iobj < this->df.dwNumObjs; ppropi->iobj++)
  3535. {
  3536. DWORD dwType = this->df.rgodf[ppropi->iobj].dwType;
  3537. if(dwType & DIDFT_ABSAXIS)
  3538. {
  3539. ppropi->dwDevType = this->df.rgodf[ppropi->iobj].dwType;
  3540. hres = this->pdcb->lpVtbl->SetProperty(this->pdcb, ppropi, pdiph);
  3541. if(FAILED(hres) && hres != E_NOTIMPL)
  3542. {
  3543. goto done;
  3544. }
  3545. }
  3546. }
  3547. hres = S_OK;
  3548. done:;
  3549. return hres;
  3550. }
  3551. /*****************************************************************************
  3552. *
  3553. * @doc INTERNAL
  3554. *
  3555. * @method HRESULT | CDIDev | DefSetProperty |
  3556. *
  3557. * Default implementation of <mf IDirectInputDevice::SetProperty>
  3558. * to handle properties which the device decides not to implement.
  3559. *
  3560. * @parm IN LPDIPROPINFO | ppropi |
  3561. *
  3562. * Information describing the property being set.
  3563. * We edit it to avoid reallocating memory all the time.
  3564. *
  3565. * @parm OUT LPCDIPROPHEADER | pdiph |
  3566. *
  3567. * Where to put the property value.
  3568. *
  3569. * @returns
  3570. *
  3571. * Returns a COM error code. The following error codes are
  3572. * intended to be illustrative and not necessarily comprehensive.
  3573. *
  3574. * <c DI_OK> = <c S_OK>: The operation completed successfully.
  3575. *
  3576. * <c DI_POLLEDDEVICE>: The device is polled, so the result
  3577. * might not be meaningful. (This return code is used when
  3578. * you attempt to set the buffer size property.)
  3579. *
  3580. * <c DIERR_INVALIDPARAM> = <c E_INVALIDARG>: The
  3581. * <p pdiph> parameter is not a valid pointer.
  3582. *
  3583. *
  3584. *****************************************************************************/
  3585. STDMETHODIMP
  3586. CDIDev_DefSetProperty(PDD this, LPDIPROPINFO ppropi, LPCDIPROPHEADER pdiph)
  3587. {
  3588. HRESULT hres;
  3589. EnterProc(CDIDev_DefSetProperty,
  3590. (_ "pGx", this, ppropi->pguid, ppropi->dwDevType));
  3591. AssertF(CDIDev_InCrit(this));
  3592. /*
  3593. * Note: The indentation here is historical; I left it this way
  3594. * to keep the diff size down.
  3595. */
  3596. hres = CDIDev_hresValidDefProp(this, ppropi, DIPVIFL_READONLY);
  3597. if(SUCCEEDED(hres))
  3598. {
  3599. LPDIPROPDWORD pdipdw = (PV)pdiph;
  3600. LPDIPROPRANGE pdiprg = (PV)pdiph;
  3601. VXDDWORDDATA vdd;
  3602. switch((DWORD)(UINT_PTR)ppropi->pguid)
  3603. {
  3604. case (DWORD)(UINT_PTR)DIPROP_BUFFERSIZE:
  3605. AssertF(this->pvi); /* Validation should've caught this */
  3606. vdd.pvi = this->pvi;
  3607. if( pdipdw->dwData > this->celtBufMax )
  3608. {
  3609. RPF( "DIPROP_BUFFERSIZE: requested size %d is larger than maximum %d, using %d",
  3610. pdipdw->dwData, this->celtBufMax, this->celtBufMax );
  3611. vdd.dw = this->celtBufMax;
  3612. }
  3613. else
  3614. {
  3615. vdd.dw = pdipdw->dwData;
  3616. }
  3617. hres = Hel_SetBufferSize(&vdd);
  3618. #ifdef DEBUG_STICKY
  3619. {
  3620. TCHAR tszDbg[80];
  3621. wsprintf( tszDbg, TEXT("SetBufferSize(0x%08x) returned 0x%08x\r\n"), vdd.dw, hres );
  3622. OutputDebugString( tszDbg );
  3623. }
  3624. #endif /* DEBUG_STICKY */
  3625. if(SUCCEEDED(hres))
  3626. {
  3627. this->celtBuf = pdipdw->dwData;
  3628. hres = this->hresPolled;
  3629. }
  3630. break;
  3631. case (DWORD)(UINT_PTR)DIPROP_AXISMODE:
  3632. hres = CDIDev_SetAxisMode(this, pdipdw->dwData);
  3633. break;
  3634. /*
  3635. * We will handle these global properties
  3636. * if the callback doesn't want to.
  3637. */
  3638. case (DWORD)(UINT_PTR)DIPROP_RANGE:
  3639. case (DWORD)(UINT_PTR)DIPROP_DEADZONE:
  3640. case (DWORD)(UINT_PTR)DIPROP_SATURATION:
  3641. case (DWORD)(UINT_PTR)DIPROP_CALIBRATIONMODE:
  3642. case (DWORD)(UINT_PTR)DIPROP_CALIBRATION:
  3643. if(ppropi->dwDevType == 0)
  3644. { /* For device */
  3645. hres = CDIDev_SetGlobalAxisProp(this, ppropi, pdiph);
  3646. } else
  3647. {
  3648. goto _default;
  3649. }
  3650. break;
  3651. case (DWORD)(UINT_PTR)DIPROP_MAXBUFFERSIZE:
  3652. this->celtBufMax = pdipdw->dwData;
  3653. hres = S_OK;
  3654. break;
  3655. #ifdef IDirectInputDevice2Vtbl
  3656. case (DWORD)(UINT_PTR)DIPROP_FFGAIN:
  3657. if(ISVALIDGAIN(pdipdw->dwData))
  3658. {
  3659. this->dwGain = pdipdw->dwData;
  3660. CDIDev_RefreshGain(this);
  3661. hres = S_OK;
  3662. } else
  3663. {
  3664. RPF("ERROR: SetProperty(DIPROP_FFGAIN): Gain out of range");
  3665. hres = E_INVALIDARG;
  3666. }
  3667. break;
  3668. case (DWORD)(UINT_PTR)DIPROP_AUTOCENTER:
  3669. hres = CDIDev_SetAutoCenter(this, pdipdw->dwData);
  3670. break;
  3671. #endif
  3672. _default:;
  3673. default:
  3674. /*
  3675. * The validation filter already failed invalid properties.
  3676. * So what's left is that the property is valid but cannot
  3677. * be set, because it doesn't exist on the device (e.g.,
  3678. * dead zone) or because it is read-only.
  3679. */
  3680. SquirtSqflPtszV(sqfl | sqflBenign,
  3681. TEXT("SetProperty: Property 0x%08x not supported on device"),
  3682. (DWORD)(UINT_PTR)ppropi->pguid );
  3683. hres = E_NOTIMPL;
  3684. break;
  3685. }
  3686. }
  3687. ExitOleProc();
  3688. return hres;
  3689. }
  3690. /*****************************************************************************
  3691. *
  3692. * @doc INTERNAL
  3693. *
  3694. * @method HRESULT | IDirectInputDevice | RealSetProperty |
  3695. *
  3696. * The function that does the real work.
  3697. *
  3698. * <mf IDirectInputDevice::SetDataFormat> will internally
  3699. * set the axis mode property, so it needs this backdoor
  3700. * entry point.
  3701. *
  3702. * @cwrap LPDIRECTINPUTDEVICE | lpDirectInputDevice
  3703. *
  3704. * @parm IN REFGUID | rguidProp |
  3705. *
  3706. * The identity of the property to be set.
  3707. *
  3708. * @parm IN LPDIPROPHEADER | pdiph |
  3709. *
  3710. * Points to the <t DIPROPHEADER> portion of a structure
  3711. * which depends on the property.
  3712. *
  3713. *****************************************************************************/
  3714. STDMETHODIMP
  3715. CDIDev_RealSetProperty(PDD this, REFGUID rguid, LPCDIPROPHEADER pdiph)
  3716. {
  3717. HRESULT hres;
  3718. DIPROPINFO propi;
  3719. EnterProcR(IDirectInputDevice::SetProperty, (_ "pxp", this, rguid, pdiph));
  3720. /*
  3721. * Must protect with the critical section to prevent somebody
  3722. * acquiring or changing the property we are reading. We need
  3723. * to do this before validating, to prevent an acquisition.
  3724. */
  3725. CDIDev_EnterCrit(this);
  3726. propi.pguid = rguid;
  3727. if(SUCCEEDED(hres = CDIDev_hresValidProp(this, rguid, pdiph,
  3728. 0, &propi)))
  3729. {
  3730. hres = this->pdcb->lpVtbl->SetProperty(this->pdcb, &propi, pdiph);
  3731. if(hres == E_NOTIMPL)
  3732. {
  3733. hres = CDIDev_DefSetProperty(this, &propi, pdiph);
  3734. }
  3735. }
  3736. CDIDev_LeaveCrit(this);
  3737. ExitOleProc();
  3738. return hres;
  3739. }
  3740. /*****************************************************************************
  3741. *
  3742. * @doc EXTERNAL
  3743. *
  3744. * @method HRESULT | IDirectInputDevice | SetProperty |
  3745. *
  3746. * Set information about a device or object in a device.
  3747. *
  3748. * @cwrap LPDIRECTINPUTDEVICE | lpDirectInputDevice
  3749. *
  3750. * @parm IN REFGUID | rguidProp |
  3751. *
  3752. * The identity of the property to be set. This can be
  3753. * one of the predefined <c DIPROP_*> values, or it may
  3754. * be a pointer to a private GUID.
  3755. *
  3756. * @parm IN LPDIPROPHEADER | pdiph |
  3757. *
  3758. * Points to the <t DIPROPHEADER> portion of a structure
  3759. * which depends on the property.
  3760. *
  3761. * @returns
  3762. *
  3763. * Returns a COM error code. The following error codes are
  3764. * intended to be illustrative and not necessarily comprehensive.
  3765. *
  3766. * <c DI_OK> = <c S_OK>: The operation completed successfully.
  3767. *
  3768. * <c DI_PROPNOEFFECT> <c S_FALSE>: The operation completed
  3769. * successfully but
  3770. * had no effect. For example, changing the axis mode
  3771. * on a device with no axes will return this value.
  3772. *
  3773. * <c DIERR_INVALIDPARAM> = <c E_INVALIDARG>: The
  3774. * <p pdiph> parameter is not a valid pointer, or the
  3775. * <p dwHow> field is invalid, or the <p dwObj> field
  3776. * is not zero when <p dwHow> is set to <c DIPH_DEVICE>.
  3777. *
  3778. * <c DIERR_OBJECTNOTFOUND>: The specified object does not
  3779. * exist.
  3780. *
  3781. * <c DIERR_UNSUPPORTED> = <c E_NOTIMPL>: The property
  3782. * is not supported by the device or object.
  3783. *
  3784. *****************************************************************************/
  3785. STDMETHODIMP
  3786. CDIDev_SetProperty(PV pdd, REFGUID rguid, LPCDIPROPHEADER pdiph _THAT)
  3787. {
  3788. HRESULT hres;
  3789. EnterProcR(IDirectInputDevice::SetProperty, (_ "pxp", pdd, rguid, pdiph));
  3790. if(SUCCEEDED(hres = hresPvT(pdd)))
  3791. {
  3792. PDD this = _thisPv(pdd);
  3793. hres = CDIDev_RealSetProperty(this, rguid, pdiph);
  3794. }
  3795. ExitOleProcR();
  3796. return hres;
  3797. }
  3798. #ifdef XDEBUG
  3799. CSET_STUBS(SetProperty, (PV pdm, REFGUID rguid, LPCDIPROPHEADER pdiph),
  3800. (pdm, rguid, pdiph THAT_))
  3801. #else
  3802. #define CDIDev_SetPropertyA CDIDev_SetProperty
  3803. #define CDIDev_SetPropertyW CDIDev_SetProperty
  3804. #endif
  3805. /*****************************************************************************
  3806. *
  3807. * @doc EXTERNAL
  3808. *
  3809. * @method HRESULT | IDirectInputDevice | SetCooperativeLevel |
  3810. *
  3811. * Establish the cooperativity level for the instance of
  3812. * the device.
  3813. *
  3814. * The cooperativity level determines how the instance of
  3815. * the device interacts with other instances of the device
  3816. * and the rest of the system.
  3817. *
  3818. * Note that if the system mouse is acquired in exclusive
  3819. * mode, then the mouse cursor will be removed from the screen
  3820. * until the device is unacquired.
  3821. *
  3822. * @cwrap LPDIRECTINPUTDEVICE | lpDirectInputDevice
  3823. *
  3824. * @parm HWND | hwnd |
  3825. *
  3826. * The window associated with the device.
  3827. * The window must be a top-level window.
  3828. *
  3829. * It is an error to destroy the window while it is still
  3830. * active in a DirectInput device.
  3831. *
  3832. * @parm DWORD | dwFlags |
  3833. *
  3834. * Flags which describe the cooperativity level associated
  3835. * with the device.
  3836. *
  3837. * It consists of <c DISCL_*> flags, documented separately.
  3838. *
  3839. * @returns
  3840. *
  3841. * Returns a COM error code. The following error codes are
  3842. * intended to be illustrative and not necessarily comprehensive.
  3843. *
  3844. * <c DI_OK> = <c S_OK>: The operation completed successfully.
  3845. *
  3846. * <c DIERR_INVALIDPARAM> = <c E_INVALIDARG>: The
  3847. * <p hwnd> parameter is not a valid pointer.
  3848. *
  3849. *****************************************************************************/
  3850. HRESULT INLINE
  3851. CDIDev_SetCooperativeLevel_IsValidFl(DWORD dwFlags)
  3852. {
  3853. HRESULT hres;
  3854. RD(static char s_szProc[] = "IDirectInputDevice::SetCooperativeLevel");
  3855. if(!(dwFlags & ~DISCL_VALID))
  3856. {
  3857. if((dwFlags & DISCL_EXCLMASK) == DISCL_EXCLUSIVE ||
  3858. (dwFlags & DISCL_EXCLMASK) == DISCL_NONEXCLUSIVE)
  3859. {
  3860. if((dwFlags & DISCL_GROUNDMASK) == DISCL_FOREGROUND ||
  3861. (dwFlags & DISCL_GROUNDMASK) == DISCL_BACKGROUND)
  3862. {
  3863. hres = S_OK;
  3864. } else
  3865. {
  3866. RPF("ERROR %s: arg %d: Must set exactly one of "
  3867. "DISCL_FOREGROUND or DISCL_BACKGROUND", s_szProc, 2);
  3868. hres = E_INVALIDARG;
  3869. }
  3870. } else
  3871. {
  3872. RPF("ERROR %s: arg %d: Must set exactly one of "
  3873. "DISCL_EXCLUSIVE or DISCL_NONEXCLUSIVE", s_szProc, 2);
  3874. hres = E_INVALIDARG;
  3875. }
  3876. } else
  3877. {
  3878. RPF("ERROR %s: arg %d: invalid flags", s_szProc, 2);
  3879. hres = E_INVALIDARG;
  3880. }
  3881. return hres;
  3882. }
  3883. HRESULT INLINE
  3884. CDIDev_SetCooperativeLevel_IsValidHwnd(HWND hwnd, DWORD dwFlags)
  3885. {
  3886. HRESULT hres;
  3887. RD(static char s_szProc[] = "IDirectInputDevice::SetCooperativeLevel");
  3888. #if DIRECTINPUT_VERSION == 0x0300
  3889. if(dwFlags & DISCL_FOREGROUND)
  3890. {
  3891. if(SUCCEEDED(hres = hresFullValidHwnd(hwnd, 1)))
  3892. {
  3893. /*
  3894. * The window must be a top-level window to be activated.
  3895. */
  3896. if(!(GetWindowLong(hwnd, GWL_STYLE) & WS_CHILD))
  3897. {
  3898. hres = S_OK;
  3899. } else
  3900. {
  3901. RPF("ERROR %s: window may not be a child window", s_szProc);
  3902. hres = E_HANDLE;
  3903. }
  3904. }
  3905. } else if(dwFlags & DISCL_EXCLUSIVE)
  3906. {
  3907. RPF("IDirectInputDevice::SetCooperativeLevel: "
  3908. "DISCL_EXCLUSIVE requires DISCL_FOREGROUND");
  3909. hres = E_NOTIMPL;
  3910. } else
  3911. {
  3912. hres = S_OK;
  3913. }
  3914. #else
  3915. /*
  3916. * If a window handle is passed, it must be valid.
  3917. *
  3918. * The window must be a top-level window to be activated.
  3919. *
  3920. * The window must belong to the calling process so we can
  3921. * hook it.
  3922. */
  3923. if(hwnd)
  3924. {
  3925. hres = hresFullValidHwnd(hwnd, 1);
  3926. if(SUCCEEDED(hres))
  3927. {
  3928. if(!(GetWindowLong(hwnd, GWL_STYLE) & WS_CHILD))
  3929. {
  3930. if(GetWindowPid(hwnd) == GetCurrentProcessId())
  3931. {
  3932. } else
  3933. {
  3934. RPF("ERROR %s: window must belong to current process",
  3935. s_szProc);
  3936. hres = E_HANDLE;
  3937. }
  3938. } else
  3939. {
  3940. RPF("ERROR %s: window may not be a child window", s_szProc);
  3941. hres = E_HANDLE;
  3942. goto done;
  3943. }
  3944. } else
  3945. {
  3946. goto done;
  3947. }
  3948. }
  3949. /*
  3950. * Foreground mode or exclusive mode both require a window handle.
  3951. */
  3952. if(dwFlags & (DISCL_FOREGROUND | DISCL_EXCLUSIVE))
  3953. {
  3954. if(hwnd)
  3955. {
  3956. } else
  3957. {
  3958. RPF("ERROR %s: window handle required "
  3959. "if DISCL_EXCLUSIVE or DISCL_FOREGROUND", s_szProc);
  3960. hres = E_HANDLE;
  3961. goto done;
  3962. }
  3963. }
  3964. hres = S_OK;
  3965. done:;
  3966. #endif
  3967. return hres;
  3968. }
  3969. STDMETHODIMP
  3970. CDIDev_SetCooperativeLevel(PV pdd, HWND hwnd, DWORD dwFlags _THAT)
  3971. {
  3972. HRESULT hres;
  3973. EnterProcR(IDirectInputDevice::SetCooperativeLevel,
  3974. (_ "pxx", pdd, hwnd, dwFlags));
  3975. if(SUCCEEDED(hres = hresPvT(pdd)))
  3976. {
  3977. PDD this = _thisPv(pdd);
  3978. /*
  3979. * Must protect with the critical section to prevent somebody
  3980. * acquiring or Reset()ing behind our back.
  3981. */
  3982. CDIDev_EnterCrit(this);
  3983. if(SUCCEEDED(hres = IDirectInputDevice_NotAcquired(this)) &&
  3984. SUCCEEDED(hres = CDIDev_SetCooperativeLevel_IsValidFl(dwFlags)) &&
  3985. SUCCEEDED(hres = CDIDev_SetCooperativeLevel_IsValidHwnd(hwnd, dwFlags)))
  3986. {
  3987. AssertF(CDIDev_IsConsistent(this));
  3988. /*
  3989. * For DX7 post Gold fix, check version against co-op level.
  3990. * Note, GetCaps is non-trivial on a HID but this is no time
  3991. * for a rewrite.
  3992. */
  3993. if( this->dwVersion < 0x0700 )
  3994. {
  3995. if( dwFlags & DISCL_NOWINKEY )
  3996. {
  3997. hres = E_INVALIDARG;
  3998. }
  3999. else if( dwFlags & DISCL_EXCLUSIVE )
  4000. {
  4001. DIDEVCAPS_DX3 dc;
  4002. dc.dwSize = cbX(dc);
  4003. if( SUCCEEDED( this->pdcb->lpVtbl->GetCapabilities( this->pdcb, (PV)&dc) ) )
  4004. {
  4005. /*
  4006. * Don't allow keyboard exclusive mode pre-DX7
  4007. */
  4008. if( GET_DIDEVICE_TYPE(dc.dwDevType) == DIDEVTYPE_KEYBOARD )
  4009. {
  4010. hres = E_INVALIDARG;
  4011. }
  4012. }
  4013. else
  4014. {
  4015. /*
  4016. * PS/2 Mouse and keyboard GetCaps are trivial so
  4017. * won't fail. HID is unlikely to fail for a mouse
  4018. * or keyboard as they generally stay plugged in so
  4019. * assume a failure to GetCaps means a joystick.
  4020. */
  4021. }
  4022. }
  4023. }
  4024. if( SUCCEEDED( hres ) )
  4025. {
  4026. hres = this->pdcb->lpVtbl->SetCooperativeLevel(
  4027. this->pdcb, hwnd, dwFlags);
  4028. if(SUCCEEDED(hres))
  4029. {
  4030. this->discl = dwFlags;
  4031. this->hwnd = hwnd;
  4032. if(this->pvi)
  4033. {
  4034. this->pvi->hwnd = hwnd;
  4035. }
  4036. }
  4037. }
  4038. else
  4039. {
  4040. AssertF( hres == E_INVALIDARG );
  4041. RPF("ERROR %s: arg %d: invalid flags", s_szProc, 2);
  4042. }
  4043. AssertF(CDIDev_IsConsistent(this));
  4044. }
  4045. CDIDev_LeaveCrit(this);
  4046. }
  4047. ExitOleProcR();
  4048. return hres;
  4049. }
  4050. #ifdef XDEBUG
  4051. CSET_STUBS(SetCooperativeLevel, (PV pdm, HWND hwnd, DWORD fl),
  4052. (pdm, hwnd, fl THAT_))
  4053. #else
  4054. #define CDIDev_SetCooperativeLevelA CDIDev_SetCooperativeLevel
  4055. #define CDIDev_SetCooperativeLevelW CDIDev_SetCooperativeLevel
  4056. #endif
  4057. /*****************************************************************************
  4058. *
  4059. * @doc EXTERNAL
  4060. *
  4061. * @method HRESULT | IDirectInputDevice | RunControlPanel |
  4062. *
  4063. * Run the DirectInput control panel for the device.
  4064. *
  4065. * @cwrap LPDIRECTINPUTDEVICE | lpDirectInputDevice
  4066. *
  4067. * @parm IN HWND | hwndOwner |
  4068. *
  4069. * Identifies the window handle that will be used as the
  4070. * parent window for subsequent UI. NULL is a valid parameter,
  4071. * indicating that there is no parent window.
  4072. *
  4073. * @parm DWORD | dwFlags |
  4074. *
  4075. * No flags are currently defined. This parameter "must" be
  4076. * zero.
  4077. *
  4078. * @returns
  4079. * Returns a COM error code. The following error codes are
  4080. * intended to be illustrative and not necessarily comprehensive.
  4081. *
  4082. * <c DI_OK> = <c S_OK>: The device is attached.
  4083. *
  4084. * @devnote
  4085. *
  4086. * The <p dwFlags> is eventually going to allow
  4087. * <c DIRCP_MODAL> to request a modal control panel.
  4088. *
  4089. *****************************************************************************/
  4090. STDMETHODIMP
  4091. CDIDev_RunControlPanel(PV pdd, HWND hwndOwner, DWORD fl _THAT)
  4092. {
  4093. HRESULT hres;
  4094. EnterProcR(IDirectInputDevice::RunControlPanel,
  4095. (_ "pxx", pdd, hwndOwner, fl));
  4096. if(SUCCEEDED(hres = hresPvT(pdd)) &&
  4097. SUCCEEDED(hres = hresFullValidHwnd0(hwndOwner, 1)) &&
  4098. SUCCEEDED(hres = hresFullValidFl(fl, DIRCP_VALID, 2)))
  4099. {
  4100. PDD this = _thisPv(pdd);
  4101. IDirectInputDeviceCallback *pdcb;
  4102. /*
  4103. * Must protect with the critical section to prevent somebody
  4104. * Reset()ing behind our back. However, we cannot hold the
  4105. * critical section during the control panel callback, because
  4106. * that will yield.
  4107. *
  4108. * So we copy/addref the pdcb inside the critical section,
  4109. * then run the control panel outside the critical section,
  4110. * then release the pdcb when we're finally done.
  4111. */
  4112. CDIDev_EnterCrit(this);
  4113. pdcb = this->pdcb;
  4114. OLE_AddRef(pdcb);
  4115. CDIDev_LeaveCrit(this);
  4116. hres = pdcb->lpVtbl->RunControlPanel(pdcb, hwndOwner, fl);
  4117. OLE_Release(pdcb);
  4118. }
  4119. ExitOleProc();
  4120. return hres;
  4121. }
  4122. #ifdef XDEBUG
  4123. CSET_STUBS(RunControlPanel, (PV pdd, HWND hwndOwner, DWORD fl),
  4124. (pdd, hwndOwner, fl THAT_))
  4125. #else
  4126. #define CDIDev_RunControlPanelA CDIDev_RunControlPanel
  4127. #define CDIDev_RunControlPanelW CDIDev_RunControlPanel
  4128. #endif
  4129. /*****************************************************************************
  4130. *
  4131. * @doc EXTERNAL
  4132. *
  4133. * @method HRESULT | IDirectInputDevice | Initialize |
  4134. *
  4135. * Initialize a DirectInputDevice object.
  4136. *
  4137. * Note that if this method fails, the underlying object should
  4138. * be considered to be an an indeterminate state and needs to
  4139. * be reinitialized before it can be subsequently used.
  4140. *
  4141. * The <mf IDirectInput::CreateDevice> method automatically
  4142. * initializes the device after creating it. Applications
  4143. * normally do not need to call this function.
  4144. *
  4145. * @cwrap LPDIRECTINPUTDEVICE | lpDirectInputDevice
  4146. *
  4147. * @parm IN HINSTANCE | hinst |
  4148. *
  4149. * Instance handle of the application or DLL that is creating
  4150. * the DirectInput object.
  4151. *
  4152. * See the section titled "Initialization and Versions"
  4153. * for more information.
  4154. *
  4155. * @parm DWORD | dwVersion |
  4156. *
  4157. * Version number of the dinput.h header file that was used.
  4158. *
  4159. * See the section titled "Initialization and Versions"
  4160. * for more information.
  4161. *
  4162. * @parm IN REFGUID | rguid |
  4163. *
  4164. * Identifies the instance of the device for which the interface
  4165. * should be associated.
  4166. * The <mf IDirectInput::EnumDevices> method
  4167. * can be used to determine which instance GUIDs are supported by
  4168. * the system.
  4169. *
  4170. * @returns
  4171. * Returns a COM error code. The following error codes are
  4172. * intended to be illustrative and not necessarily comprehensive.
  4173. *
  4174. * <c DI_OK> = <c S_OK>: The operation completed successfully.
  4175. *
  4176. * <c S_FALSE>: The device had already been initialized with
  4177. * the instance GUID passed in <p lpGUID>.
  4178. *
  4179. * <c DIERR_ACQUIRED>: The device cannot be initialized while
  4180. * it is acquired.
  4181. *
  4182. * <c DIERR_DEVICENOTREG>: The instance GUID does not exist
  4183. * on the current machine.
  4184. *
  4185. * <c DIERR_HASEFFECTS>:
  4186. * The device cannot be reinitialized because there are
  4187. * still effects attached to it.
  4188. *
  4189. *****************************************************************************/
  4190. STDMETHODIMP
  4191. CDIDev_Initialize(PV pdd, HINSTANCE hinst, DWORD dwVersion, REFGUID rguid _THAT)
  4192. {
  4193. HRESULT hres;
  4194. EnterProcR(IDirectInputDevice::Initialize,
  4195. (_ "pxxG", pdd, hinst, dwVersion, rguid));
  4196. if(SUCCEEDED(hres = hresPvT(pdd)) &&
  4197. SUCCEEDED(hres = hresFullValidGuid(rguid, 1)))
  4198. {
  4199. PDD this = _thisPv(pdd);
  4200. CREATEDCB CreateDcb;
  4201. IDirectInputDeviceCallback *pdcb;
  4202. /*
  4203. * Must take the critical section to avoid Reset()ing
  4204. * the device (or generally speaking, screwing with the
  4205. * internal state variables) while somebody else is
  4206. * messing with it.
  4207. */
  4208. CDIDev_EnterCrit(this);
  4209. if(SUCCEEDED(hres = hresValidInstanceVer(hinst, dwVersion)) &&
  4210. SUCCEEDED(hres = hresFindInstanceGUID(rguid, &CreateDcb, 1)) &&
  4211. SUCCEEDED(hres = CDIDev_Reset(this)))
  4212. {
  4213. hres = CreateDcb(0, rguid, &IID_IDirectInputDeviceCallback,
  4214. (PPV)&pdcb);
  4215. if(SUCCEEDED(hres))
  4216. {
  4217. this->pdcb = pdcb;
  4218. AssertF(this->pvi == 0);
  4219. if(SUCCEEDED(hres = CDIDev_GetDataFormat(this)) &&
  4220. SUCCEEDED(hres = CDIDev_GetPolled(this)) &&
  4221. SUCCEEDED(hres = this->pdcb->lpVtbl->GetInstance(
  4222. this->pdcb, &this->pvi)))
  4223. {
  4224. #ifdef IDirectInputDevice2Vtbl
  4225. this->dwVersion = dwVersion;
  4226. #if (DIRECTINPUT_VERSION > 0x061A)
  4227. AhGetAppHacks( &this->diHacks );
  4228. #endif
  4229. this->pdcb->lpVtbl->SetDIData(this->pdcb, dwVersion, &this->diHacks);
  4230. #ifdef BUGGY_DX7_WINNT
  4231. if( (this->dwVersion < 0x700) && (this->dwVersion != 0x5B2) ) {
  4232. if( GET_DIDEVICE_TYPE(this->diHacks.dwDevType) == DIDEVTYPE_JOYSTICK ) {
  4233. hres = CDIDev_ParseDataFormatInternal(this, &c_dfDIJoystick);
  4234. }
  4235. }
  4236. #endif //BUGGY_DX7_WINNT
  4237. #endif //IDirectInputDevice2Vtbl
  4238. if(dwVersion >= DIRECTINPUT_VERSION)
  4239. {
  4240. this->didftInstance = DIDFT_ANYINSTANCE;
  4241. }
  4242. this->guid = *rguid;
  4243. if(this->pvi && (this->pvi->fl & VIFL_EMULATED))
  4244. {
  4245. this->pvi->pdd = this;
  4246. }
  4247. hres = this->pdcb->lpVtbl->CookDeviceData(this->pdcb, 0, 0);
  4248. if(SUCCEEDED(hres))
  4249. {
  4250. this->fCook = 1;
  4251. }
  4252. #ifdef IDirectInputDevice2Vtbl
  4253. CDIDev_InitFF(this);
  4254. #endif
  4255. hres = S_OK;
  4256. } else
  4257. {
  4258. RPF("Device driver didn't provide a data format");
  4259. }
  4260. } else
  4261. {
  4262. #ifdef NOISY
  4263. RPF("Cannot create device");
  4264. #endif
  4265. }
  4266. }
  4267. CDIDev_LeaveCrit(this);
  4268. }
  4269. ExitOleProc();
  4270. return hres;
  4271. }
  4272. #ifdef XDEBUG
  4273. CSET_STUBS(Initialize,
  4274. (PV pdd, HINSTANCE hinst, DWORD dwVersion, REFGUID rguid),
  4275. (pdd, hinst, dwVersion, rguid THAT_))
  4276. #else
  4277. #define CDIDev_InitializeA CDIDev_Initialize
  4278. #define CDIDev_InitializeW CDIDev_Initialize
  4279. #endif
  4280. /*****************************************************************************
  4281. *
  4282. * @doc INTERNAL
  4283. *
  4284. * @method void | IDirectInputDevice | Init |
  4285. *
  4286. * Initialize the internal parts of the DirectInputDevice object.
  4287. *
  4288. *****************************************************************************/
  4289. void INLINE
  4290. CDIDev_Init(PDD this)
  4291. {
  4292. /*
  4293. * The critical section must be the very first thing we do,
  4294. * because only Finalize checks for its existence.
  4295. *
  4296. * (We might be finalized without being initialized if the user
  4297. * passed a bogus interface to CDIDev_New.)
  4298. */
  4299. this->fCritInited = fInitializeCriticalSection(&this->crst);
  4300. if( this->fCritInited )
  4301. {
  4302. this->celtBufMax = 1023; /* Default maximum buffer size */
  4303. this->pdcb = c_pdcbNil;
  4304. #ifdef IDirectInputDevice2Vtbl
  4305. GPA_InitFromZero(&this->gpaEff);
  4306. #endif
  4307. }
  4308. }
  4309. /*****************************************************************************
  4310. *
  4311. * @doc INTERNAL
  4312. *
  4313. * @method HRESULT | IDirectInputDevice | New |
  4314. *
  4315. * Create a new DirectInputDevice object, uninitialized.
  4316. *
  4317. * @parm IN PUNK | punkOuter |
  4318. *
  4319. * Controlling unknown for aggregation.
  4320. *
  4321. * @parm IN RIID | riid |
  4322. *
  4323. * Desired interface to new object.
  4324. *
  4325. * @parm OUT PPV | ppvObj |
  4326. *
  4327. * Output pointer for new object.
  4328. *
  4329. *****************************************************************************/
  4330. STDMETHODIMP
  4331. CDIDev_New(PUNK punkOuter, RIID riid, PPV ppvObj)
  4332. {
  4333. HRESULT hres;
  4334. EnterProcR(IDirectInputDevice::<constructor>, (_ "Gp", riid, punkOuter));
  4335. if (SUCCEEDED(hres = hresFullValidPcbOut(ppvObj, cbX(*ppvObj), 3)))
  4336. {
  4337. hres = Excl_Init();
  4338. if(SUCCEEDED(hres))
  4339. {
  4340. LPVOID pvTry = NULL;
  4341. hres = Common_NewRiid(CDIDev, punkOuter, riid, &pvTry);
  4342. if(SUCCEEDED(hres))
  4343. {
  4344. PDD this = _thisPv(pvTry);
  4345. CDIDev_Init(this);
  4346. if( this->fCritInited )
  4347. {
  4348. *ppvObj = pvTry;
  4349. }
  4350. else
  4351. {
  4352. Common_Unhold(this);
  4353. *ppvObj = NULL;
  4354. hres = E_OUTOFMEMORY;
  4355. }
  4356. }
  4357. }
  4358. }
  4359. ExitOleProcPpvR(ppvObj);
  4360. return hres;
  4361. }
  4362. /*****************************************************************************
  4363. *
  4364. * @doc INTERNAL
  4365. *
  4366. * @method HRESULT | CDIDev_ModifyEffectParams |
  4367. *
  4368. * Modifies parameters of DIEFFECT structure to fit the current FF device
  4369. *
  4370. * @cwrap LPDIRECTINPUTDEVICE | lpDirectInputDevice
  4371. *
  4372. *
  4373. * @parm IN OUT LPDIEFFECT | peff |
  4374. *
  4375. * Pointer to the effect structure
  4376. *
  4377. * @parm IN GUID | effGUID |
  4378. *
  4379. * GUID for the effect
  4380. *
  4381. * @returns
  4382. *
  4383. * Returns a COM error code. The following error codes are
  4384. * intended to be illustrative and not necessarily comprehensive.
  4385. *
  4386. * <c DI_OK> = <c S_OK>: The operation completed successfully.
  4387. *
  4388. * <c DIERR_UNSUPPORTED>: The effect can't be supported by the current device
  4389. * (e.g. the number of FF axes on the device is 0)
  4390. *
  4391. * <c DIERR_INVALIDPARAM>: Can't create the effect even with the modified parameters
  4392. *
  4393. *****************************************************************************/
  4394. HRESULT CDIDev_ModifyEffectParams
  4395. (
  4396. PV pdd,
  4397. LPDIEFFECT peff,
  4398. GUID effGUID
  4399. )
  4400. {
  4401. HRESULT hres = S_OK;
  4402. HRESULT hresCreate = S_OK;
  4403. LPDIRECTINPUTEFFECT pdeff;
  4404. PDD this = _thisPv(pdd);
  4405. EnterProcR(CDIDev_ModifyEffectParams, (_ "p", pdd));
  4406. // Check to make sure that effects we enumerate will
  4407. // actually get created on the device.
  4408. // try creating the effect.
  4409. #ifdef XDEBUG
  4410. hresCreate = CDIDev_CreateEffect(this, &effGUID, peff, &pdeff, NULL, ((LPUNKNOWN)this)->lpVtbl);
  4411. #else
  4412. hresCreate = CDIDev_CreateEffect(this, &effGUID, peff, &pdeff, NULL);
  4413. #endif
  4414. if(SUCCEEDED(hresCreate))
  4415. {
  4416. Invoke_Release(&pdeff);
  4417. }
  4418. else
  4419. {
  4420. if (hresCreate == DIERR_INVALIDPARAM)
  4421. {
  4422. //two things can give DIERR_INVALIDPARAM:
  4423. //invalid axes and invalid trigger button
  4424. //check the axes first, then the trigger buttons
  4425. //try to eliminate all DIERR_INVALIDPARAMS
  4426. LPDIOBJECTDATAFORMAT lpObjDat = this->df.rgodf;
  4427. DWORD dwNum = this->df.dwNumObjs;
  4428. DWORD nCount;
  4429. LPDWORD lpAxes;
  4430. LPDWORD lpThisAxis;
  4431. LPDWORD lpEffAxis;
  4432. DWORD nAxes = 0;
  4433. DWORD dwTrigger = DIJOFS_BUTTON(0);
  4434. BOOL bTriggerCorrect = FALSE;
  4435. AllocCbPpv(sizeof(DWORD)*dwNum, &lpAxes);
  4436. lpThisAxis = lpAxes;
  4437. for (nCount = 0; nCount < dwNum; nCount ++)
  4438. {
  4439. AssertF(lpObjDat != NULL);
  4440. //check the axes
  4441. if ((lpObjDat->dwType & (DIDFT_AXIS | DIDFT_FFACTUATOR) & DIDFT_TYPEMASK) &&
  4442. (fHasAllBitsFlFl(lpObjDat->dwType, (DIDFT_AXIS | DIDFT_FFACTUATOR) & DIDFT_ATTRMASK)))
  4443. {
  4444. *lpAxes = lpObjDat->dwOfs;
  4445. nAxes++;
  4446. lpAxes++;
  4447. }
  4448. else
  4449. {
  4450. //check the trigger button, if there's one
  4451. if ((peff->dwTriggerButton != DIEB_NOTRIGGER) &&
  4452. (lpObjDat->dwType & DIDFT_FFEFFECTTRIGGER & DIDFT_TYPEMASK) &&
  4453. (fHasAllBitsFlFl(lpObjDat->dwType, DIDFT_FFEFFECTTRIGGER & DIDFT_ATTRMASK)))
  4454. {
  4455. if (lpObjDat->dwOfs == peff->dwTriggerButton)
  4456. {
  4457. //the trigger is valid
  4458. bTriggerCorrect = TRUE;
  4459. }
  4460. else
  4461. {
  4462. //remember the trigger offset for the future
  4463. dwTrigger = lpObjDat->dwOfs;
  4464. }
  4465. }
  4466. }
  4467. lpObjDat++;
  4468. }
  4469. //first, chack if there are any FF axes
  4470. if (nAxes == 0)
  4471. {
  4472. //return an error if no FF axes on device
  4473. hres = DIERR_UNSUPPORTED;
  4474. }
  4475. else
  4476. {
  4477. //trigger buttons are checked for validity before axes,
  4478. //so set the trigger button, if needed,
  4479. //because if it is invalid, this is what caused the error
  4480. if ((peff->dwTriggerButton != DIEB_NOTRIGGER) && (bTriggerCorrect == FALSE))
  4481. {
  4482. peff->dwTriggerButton = dwTrigger;
  4483. // and try creating again
  4484. #ifdef XDEBUG
  4485. hresCreate = CDIDev_CreateEffect(this, &effGUID, peff, &pdeff, NULL, ((LPUNKNOWN)this)->lpVtbl);
  4486. #else
  4487. hresCreate = CDIDev_CreateEffect(this, &effGUID, peff, &pdeff, NULL);
  4488. #endif
  4489. if(SUCCEEDED(hresCreate))
  4490. {
  4491. Invoke_Release(&pdeff);
  4492. }
  4493. }
  4494. if (hresCreate == DIERR_INVALIDPARAM)
  4495. {
  4496. HRESULT hresInfo = S_OK;
  4497. EFFECTMAPINFO emi;
  4498. //this time, set the axes
  4499. if (peff->cAxes > nAxes)
  4500. {
  4501. //change the number of axes
  4502. peff->cAxes = nAxes;
  4503. //change the flags
  4504. if ((nAxes < 3) && (peff->dwFlags & DIEFF_SPHERICAL))
  4505. {
  4506. peff->dwFlags &= ~DIEFF_SPHERICAL;
  4507. peff->dwFlags |= DIEFF_POLAR;
  4508. }
  4509. else
  4510. {
  4511. if ((nAxes < 2) && (peff->dwFlags & DIEFF_POLAR))
  4512. {
  4513. peff->dwFlags &= ~DIEFF_POLAR;
  4514. peff->dwFlags |= DIEFF_CARTESIAN;
  4515. }
  4516. }
  4517. }
  4518. //check if size of type-specific param structures is not bigger then number of axes,
  4519. //since this can also give us invalid params in type-specific .
  4520. //need to do this only for conditions
  4521. if (SUCCEEDED(hresInfo = CDIDev_FindEffectGUID(this, &effGUID, &emi, 2)))
  4522. {
  4523. //do the conditions
  4524. if (emi.attr.dwEffType & DIEFT_CONDITION)
  4525. {
  4526. if (peff->cbTypeSpecificParams/(sizeof(DICONDITION)) > peff->cAxes)
  4527. {
  4528. peff->cbTypeSpecificParams = peff->cAxes*(sizeof(DICONDITION));
  4529. }
  4530. }
  4531. //don't need to do anything for custom forces,
  4532. //since DInput doesn't check number of channels against number of axes anyway
  4533. }
  4534. //write over the axes
  4535. lpEffAxis = peff->rgdwAxes;
  4536. for (nCount = 0; nCount < nAxes, nCount < peff->cAxes; nCount ++)
  4537. {
  4538. *(lpEffAxis) = *(lpThisAxis);
  4539. lpThisAxis ++;
  4540. lpEffAxis++;
  4541. }
  4542. // and try creating again
  4543. #ifdef XDEBUG
  4544. hresCreate = CDIDev_CreateEffect(this, &effGUID, peff, &pdeff, NULL, ((LPUNKNOWN)this)->lpVtbl);
  4545. #else
  4546. hresCreate = CDIDev_CreateEffect(this, &effGUID, peff, &pdeff, NULL);
  4547. #endif
  4548. if(SUCCEEDED(hresCreate))
  4549. {
  4550. Invoke_Release(&pdeff);
  4551. }
  4552. }
  4553. }
  4554. //free the axes array
  4555. FreePpv(&lpAxes);
  4556. }
  4557. }
  4558. if ((SUCCEEDED(hres)) && (hresCreate == DIERR_INVALIDPARAM))
  4559. {
  4560. hres = hresCreate;
  4561. }
  4562. ExitOleProc();
  4563. return hres;
  4564. }
  4565. /*****************************************************************************
  4566. *
  4567. * @doc INTERNAL
  4568. *
  4569. * @method BOOL | CDIDev_IsStandardEffect |
  4570. *
  4571. * Checks if the effect GUID belongs to a standard DI effect
  4572. *
  4573. * @parm IN GUID | effGUID |
  4574. *
  4575. * GUID for the effect
  4576. *
  4577. * @returns BOOL
  4578. *
  4579. * TRUE if it is a standard DI effect;
  4580. * FALSE otherwise.
  4581. *
  4582. *
  4583. *****************************************************************************/
  4584. BOOL CDIDev_IsStandardEffect
  4585. (GUID effGUID)
  4586. {
  4587. BOOL bStandard = TRUE;
  4588. //check all the standard DX7 GUIDs
  4589. if ((IsEqualGUID(&effGUID, &GUID_Sine)) ||
  4590. (IsEqualGUID(&effGUID, &GUID_Triangle)) ||
  4591. (IsEqualGUID(&effGUID, &GUID_ConstantForce)) ||
  4592. (IsEqualGUID(&effGUID, &GUID_RampForce)) ||
  4593. (IsEqualGUID(&effGUID, &GUID_Square)) ||
  4594. (IsEqualGUID(&effGUID, &GUID_SawtoothUp)) ||
  4595. (IsEqualGUID(&effGUID, &GUID_SawtoothDown)) ||
  4596. (IsEqualGUID(&effGUID, &GUID_Spring)) ||
  4597. (IsEqualGUID(&effGUID, &GUID_Damper)) ||
  4598. (IsEqualGUID(&effGUID, &GUID_Inertia)) ||
  4599. (IsEqualGUID(&effGUID, &GUID_Friction)) ||
  4600. (IsEqualGUID(&effGUID, &GUID_CustomForce)))
  4601. {
  4602. bStandard = TRUE;
  4603. }
  4604. else
  4605. {
  4606. bStandard = FALSE;
  4607. }
  4608. return bStandard;
  4609. }
  4610. /*****************************************************************************
  4611. *
  4612. * @doc EXTERNAL
  4613. *
  4614. * @method HRESULT | IDirectInputDevice | EnumEffectsInFile |
  4615. *
  4616. * Enumerates DIEFFECT struct(s) and effect GUID from file.
  4617. * An application can use this in order to create pre-authored
  4618. * force effects.
  4619. *
  4620. * @cwrap LPDIRECTINPUTDEVICE | lpDirectInputDevice
  4621. *
  4622. * @parm LPCSTR | lpszFileName |
  4623. *
  4624. * Name of the RIFF file that contains collection of effects.
  4625. *
  4626. * @parm IN OUT LPENUMEFFECTSCALLBACK | pec |
  4627. *
  4628. * The callback function.
  4629. *
  4630. * @parm IN OUT LPVOID | pvRef |
  4631. * Specifies the application-defined value given in the
  4632. * <mf IDirectInputDevice::EnumObjects> function.
  4633. *
  4634. * @parm IN DWORD | dwFlags |
  4635. *
  4636. * Flags which control the enumeration.
  4637. *
  4638. * It consists of <c DIFEF_*> flags, documented separately.
  4639. *
  4640. * @returns
  4641. *
  4642. * Returns a COM error code. The following error codes are
  4643. * intended to be illustrative and not necessarily comprehensive.
  4644. *
  4645. * <c DI_OK> = <c S_OK>: The operation completed successfully.
  4646. *
  4647. * <c DIERR_INVALIDPARAM> = <c E_INVALIDARG>: The
  4648. * <p lpDirectInputDevice> or
  4649. * <p lpdc> parameter is invalid.
  4650. *
  4651. * @cb BOOL CALLBACK | DIEnumEffectsCallback |
  4652. *
  4653. * An application-defined callback function that receives
  4654. * effect GUID, DIEFFECT and repeat count as a result of a call to the
  4655. * <om IDirectInputDevice::EnumEffectsInFile> method.
  4656. *
  4657. * @parm OUT LPCDIFILEEFFECT | lpDiFileEf |
  4658. *
  4659. * Pointer to a DIFILEEFFECT structure.
  4660. *
  4661. *
  4662. * @parm IN OUT LPVOID | pvRef |
  4663. * Specifies the application-defined value given in the
  4664. * <mf IDirectInputDevice::EnumObjects> function.
  4665. *
  4666. * @returns
  4667. *
  4668. * Returns <c DIENUM_CONTINUE> to continue the enumeration
  4669. * or <c DIENUM_STOP> to stop the enumeration.
  4670. *
  4671. *****************************************************************************/
  4672. HRESULT CDIDev_EnumEffectsInFileA
  4673. (
  4674. PV pddA,
  4675. LPCSTR lpszFileName,
  4676. LPDIENUMEFFECTSINFILECALLBACK pec,
  4677. LPVOID pvRef,
  4678. DWORD dwFlags
  4679. )
  4680. {
  4681. HRESULT hres = E_FAIL;
  4682. EnterProcR(IDirectInputDevice::EnumEffectsInFile, (_ "s", lpszFileName));
  4683. /* Validate incoming parameters */
  4684. if(SUCCEEDED(hres = hresPvA(pddA)) &&
  4685. SUCCEEDED(hres = hresFullValidReadStrA(lpszFileName, MAX_JOYSTRING,1)) &&
  4686. SUCCEEDED(hres = hresFullValidPfn(pec, 2)) &&
  4687. SUCCEEDED(hres = hresFullValidFl(dwFlags, DIFEF_ENUMVALID, 3)) )
  4688. {
  4689. PDD this = _thisPvNm(pddA, ddA);
  4690. HMMIO hmmio;
  4691. MMCKINFO mmck;
  4692. DWORD dwEffectSz;
  4693. hres = RIFF_Open(lpszFileName, MMIO_READ | MMIO_ALLOCBUF , &hmmio, &mmck, &dwEffectSz);
  4694. if(SUCCEEDED(hres))
  4695. {
  4696. HRESULT hresRead;
  4697. DIEFFECT effect;
  4698. DIFILEEFFECT DiFileEf;
  4699. DIENVELOPE diEnvelope;
  4700. DWORD rgdwAxes[DIEFFECT_MAXAXES];
  4701. LONG rglDirection[DIEFFECT_MAXAXES];
  4702. effect.rgdwAxes = rgdwAxes;
  4703. effect.rglDirection = rglDirection;
  4704. effect.lpEnvelope = &diEnvelope;
  4705. DiFileEf.dwSize = cbX(DiFileEf);
  4706. DiFileEf.lpDiEffect = &effect;
  4707. while ((SUCCEEDED(hres)) && (SUCCEEDED(hresRead = RIFF_ReadEffect(hmmio, &DiFileEf))))
  4708. {
  4709. BOOL fRc = DIENUM_CONTINUE;
  4710. BOOL bInclude = TRUE;
  4711. HRESULT hresModify = DI_OK;
  4712. //modify if needed
  4713. if (dwFlags & DIFEF_MODIFYIFNEEDED)
  4714. {
  4715. hresModify = CDIDev_ModifyEffectParams(this, &effect, DiFileEf.GuidEffect);
  4716. }
  4717. //if necessary, check whether effect is standard
  4718. if (!(dwFlags & DIFEF_INCLUDENONSTANDARD))
  4719. {
  4720. bInclude = CDIDev_IsStandardEffect(DiFileEf.GuidEffect);
  4721. }
  4722. //call back only if all the conditions posed by the flags are satisfied
  4723. if ((SUCCEEDED(hresModify)) && (bInclude == TRUE))
  4724. {
  4725. fRc = Callback(pec, &DiFileEf, pvRef);
  4726. }
  4727. //free type-specific only if allocated
  4728. if(effect.cbTypeSpecificParams > 0)
  4729. {
  4730. FreePv(effect.lpvTypeSpecificParams);
  4731. effect.cbTypeSpecificParams = 0x0;
  4732. }
  4733. if(fRc == DIENUM_STOP)
  4734. {
  4735. break;
  4736. } else if(fRc == DIENUM_CONTINUE)
  4737. {
  4738. continue;
  4739. } else
  4740. {
  4741. RPF("IDirectInputDevice::EnumEffectsInFile: Invalid return value from enumeration callback");
  4742. ValidationException();
  4743. break;
  4744. }
  4745. }
  4746. RIFF_Close(hmmio, 0);
  4747. //if hresRead failed because couldn't descend into the chunk, it means the end of file,
  4748. //so everything is OK;
  4749. //else return this error
  4750. if (SUCCEEDED(hres))
  4751. {
  4752. if (hresRead == hresLe(ERROR_SECTOR_NOT_FOUND))
  4753. {
  4754. hres = S_OK;
  4755. }
  4756. else
  4757. {
  4758. hres = hresRead;
  4759. }
  4760. }
  4761. }
  4762. }
  4763. ExitOleProc();
  4764. return hres;
  4765. }
  4766. HRESULT CDIDev_EnumEffectsInFileW
  4767. (
  4768. PV pddW,
  4769. LPCWSTR lpszFileName,
  4770. LPDIENUMEFFECTSINFILECALLBACK pec,
  4771. LPVOID pvRef,
  4772. DWORD dwFlags
  4773. )
  4774. {
  4775. HRESULT hres = E_FAIL;
  4776. EnterProcR(IDirectInputDevice::EnumEffectsInFileW, (_ "s", lpszFileName));
  4777. /* Validate incoming parameters */
  4778. if(SUCCEEDED(hres = hresPvW(pddW)) &&
  4779. SUCCEEDED(hres = hresFullValidReadStrW(lpszFileName, MAX_JOYSTRING,1)) &&
  4780. SUCCEEDED(hres = hresFullValidPfn(pec, 2)) &&
  4781. SUCCEEDED(hres = hresFullValidFl(dwFlags, DIFEF_ENUMVALID, 3)) )
  4782. {
  4783. CHAR szFileName[MAX_PATH];
  4784. PDD this = _thisPvNm(pddW, ddW);
  4785. UToA(szFileName, MAX_PATH, lpszFileName);
  4786. hres = CDIDev_EnumEffectsInFileA(&this->ddA, szFileName, pec, pvRef, dwFlags);
  4787. }
  4788. return hres;
  4789. }
  4790. /*****************************************************************************
  4791. *
  4792. * @doc EXTERNAL
  4793. *
  4794. * @method HRESULT | IDirectInputDevice | WriteEffectToFile |
  4795. *
  4796. * Writes DIEFFECT struct(s) and effect GUID to a file.
  4797. * An application can use this in order to create pre-authored
  4798. * force effects.
  4799. *
  4800. * @cwrap LPDIRECTINPUTDEVICE | lpDirectInputDevice
  4801. *
  4802. * @parm LPCSTR | lpszFileName |
  4803. *
  4804. * Name of the RIFF file that contains collection of effects.
  4805. *
  4806. * @parm IN DWORD | dwEntries |
  4807. *
  4808. * Number of <t DIFILEEFFECT> structures in the array.
  4809. *
  4810. * @parm IN LPCDIFILEEFFECT | rgDiFileEft |
  4811. *
  4812. * Array of <t DIFILEEFFECT> structure.
  4813. *
  4814. *
  4815. * @parm IN DWORD | dwFlags |
  4816. *
  4817. * Flags which control how the effect should be written.
  4818. *
  4819. * It consists of <c DIFEF_*> flags, documented separately.
  4820. *
  4821. * @returns
  4822. *
  4823. * Returns a COM error code. The following error codes are
  4824. * intended to be illustrative and not necessarily comprehensive.
  4825. *
  4826. * <c DI_OK> = <c S_OK>: The operation completed successfully.
  4827. *
  4828. * <c DIERR_INVALIDPARAM> = <c E_INVALIDARG>: The
  4829. * <p lpDirectInputDevice> or
  4830. * <p lpdc> parameter is invalid.
  4831. *
  4832. *****************************************************************************/
  4833. HRESULT CDIDev_WriteEffectToFileA
  4834. (
  4835. PV pddA,
  4836. LPCSTR lpszFileName,
  4837. DWORD dwEntries,
  4838. LPDIFILEEFFECT rgDiFileEffect,
  4839. DWORD dwFlags
  4840. )
  4841. {
  4842. HRESULT hres = E_NOTIMPL;
  4843. EnterProcR(IDirectInputDevice:cd inc
  4844. :WriteEffectToFileA, (_ "s", lpszFileName));
  4845. /* Validate incoming parameters */
  4846. if(SUCCEEDED(hres = hresPvA(pddA)) &&
  4847. SUCCEEDED(hres = hresFullValidReadStrA(lpszFileName, MAX_JOYSTRING,1))&&
  4848. SUCCEEDED(hres = hresFullValidFl(dwFlags, DIFEF_ENUMVALID, 3)) &&
  4849. SUCCEEDED(hres = (IsBadReadPtr(rgDiFileEffect, cbX(*rgDiFileEffect))) ? E_POINTER : S_OK))
  4850. {
  4851. PDD this = _thisPvNm(pddA, ddA);
  4852. HMMIO hmmio;
  4853. MMCKINFO mmck;
  4854. DWORD dwEffectSz;
  4855. hres = RIFF_Open(lpszFileName, MMIO_CREATE | MMIO_WRITE | MMIO_ALLOCBUF , &hmmio, &mmck, &dwEffectSz);
  4856. if(SUCCEEDED(hres))
  4857. {
  4858. UINT nCount;
  4859. LPDIFILEEFFECT lpDiFileEf = rgDiFileEffect;
  4860. //write out the effects
  4861. for(nCount = 0; nCount < dwEntries; nCount++)
  4862. {
  4863. BOOL bInclude = TRUE;
  4864. hres = (IsBadReadPtr(lpDiFileEf, cbX(*lpDiFileEf))) ? E_POINTER : S_OK;
  4865. if (FAILED(hres))
  4866. {
  4867. break;
  4868. }
  4869. //if necessary, check whether the effect is standard
  4870. if (!(dwFlags & DIFEF_INCLUDENONSTANDARD))
  4871. {
  4872. bInclude = CDIDev_IsStandardEffect(lpDiFileEf->GuidEffect);
  4873. }
  4874. if ((SUCCEEDED(hres)) && (bInclude == TRUE))
  4875. {
  4876. hres = RIFF_WriteEffect(hmmio, lpDiFileEf);
  4877. }
  4878. if(FAILED(hres))
  4879. {
  4880. break;
  4881. }
  4882. lpDiFileEf++;
  4883. }
  4884. RIFF_Close(hmmio, 0);
  4885. }
  4886. }
  4887. ExitOleProc();
  4888. return hres;
  4889. }
  4890. HRESULT CDIDev_WriteEffectToFileW
  4891. (
  4892. PV pddW,
  4893. LPCWSTR lpszFileName,
  4894. DWORD dwEntries,
  4895. LPDIFILEEFFECT lpDiFileEffect,
  4896. DWORD dwFlags
  4897. )
  4898. {
  4899. HRESULT hres = E_FAIL;
  4900. EnterProcR(IDirectInputDevice::WriteEffectToFile, (_ "s", lpszFileName));
  4901. /* Validate incoming parameters */
  4902. if(SUCCEEDED(hres = hresPvW(pddW)) &&
  4903. SUCCEEDED(hres = hresFullValidReadStrW(lpszFileName, MAX_JOYSTRING,1)))
  4904. {
  4905. CHAR szFileName[MAX_PATH];
  4906. PDD this = _thisPvNm(pddW, ddW);
  4907. UToA(szFileName, MAX_PATH, lpszFileName);
  4908. hres = CDIDev_WriteEffectToFileA(&this->ddA, szFileName, dwEntries, lpDiFileEffect, dwFlags);
  4909. }
  4910. return hres;
  4911. }
  4912. /*****************************************************************************
  4913. *
  4914. * The long-awaited vtbls and templates
  4915. *
  4916. *****************************************************************************/
  4917. #pragma BEGIN_CONST_DATA
  4918. #define CDIDev_Signature 0x20564544 /* "DEV " */
  4919. Primary_Interface_Begin(CDIDev, TFORM(ThisInterfaceT))
  4920. TFORM(CDIDev_GetCapabilities),
  4921. TFORM(CDIDev_EnumObjects),
  4922. TFORM(CDIDev_GetProperty),
  4923. TFORM(CDIDev_SetProperty),
  4924. TFORM(CDIDev_Acquire),
  4925. TFORM(CDIDev_Unacquire),
  4926. TFORM(CDIDev_GetDeviceState),
  4927. TFORM(CDIDev_GetDeviceData),
  4928. TFORM(CDIDev_SetDataFormat),
  4929. TFORM(CDIDev_SetEventNotification),
  4930. TFORM(CDIDev_SetCooperativeLevel),
  4931. TFORM(CDIDev_GetObjectInfo),
  4932. TFORM(CDIDev_GetDeviceInfo),
  4933. TFORM(CDIDev_RunControlPanel),
  4934. TFORM(CDIDev_Initialize),
  4935. #ifdef IDirectInputDevice2Vtbl
  4936. TFORM(CDIDev_CreateEffect),
  4937. TFORM(CDIDev_EnumEffects),
  4938. TFORM(CDIDev_GetEffectInfo),
  4939. TFORM(CDIDev_GetForceFeedbackState),
  4940. TFORM(CDIDev_SendForceFeedbackCommand),
  4941. TFORM(CDIDev_EnumCreatedEffectObjects),
  4942. TFORM(CDIDev_Escape),
  4943. TFORM(CDIDev_Poll),
  4944. TFORM(CDIDev_SendDeviceData),
  4945. #ifdef IDirectInputDevice7Vtbl
  4946. TFORM(CDIDev_EnumEffectsInFile),
  4947. TFORM(CDIDev_WriteEffectToFile),
  4948. #endif
  4949. #endif
  4950. Primary_Interface_End(CDIDev, TFORM(ThisInterfaceT))
  4951. Secondary_Interface_Begin(CDIDev, SFORM(ThisInterfaceT), SFORM(dd))
  4952. SFORM(CDIDev_GetCapabilities),
  4953. SFORM(CDIDev_EnumObjects),
  4954. SFORM(CDIDev_GetProperty),
  4955. SFORM(CDIDev_SetProperty),
  4956. SFORM(CDIDev_Acquire),
  4957. SFORM(CDIDev_Unacquire),
  4958. SFORM(CDIDev_GetDeviceState),
  4959. SFORM(CDIDev_GetDeviceData),
  4960. SFORM(CDIDev_SetDataFormat),
  4961. SFORM(CDIDev_SetEventNotification),
  4962. SFORM(CDIDev_SetCooperativeLevel),
  4963. SFORM(CDIDev_GetObjectInfo),
  4964. SFORM(CDIDev_GetDeviceInfo),
  4965. SFORM(CDIDev_RunControlPanel),
  4966. SFORM(CDIDev_Initialize),
  4967. #ifdef IDirectInputDevice2Vtbl
  4968. SFORM(CDIDev_CreateEffect),
  4969. SFORM(CDIDev_EnumEffects),
  4970. SFORM(CDIDev_GetEffectInfo),
  4971. SFORM(CDIDev_GetForceFeedbackState),
  4972. SFORM(CDIDev_SendForceFeedbackCommand),
  4973. SFORM(CDIDev_EnumCreatedEffectObjects),
  4974. TFORM(CDIDev_Escape),
  4975. SFORM(CDIDev_Poll),
  4976. SFORM(CDIDev_SendDeviceData),
  4977. #ifdef IDirectInputDevice7Vtbl
  4978. SFORM(CDIDev_EnumEffectsInFile),
  4979. SFORM(CDIDev_WriteEffectToFile),
  4980. #endif
  4981. #endif
  4982. Secondary_Interface_End(CDIDev, SFORM(ThisInterfaceT), SFORM(dd))