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.

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