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.

815 lines
21 KiB

  1. /*****************************************************************************
  2. *
  3. * EffDrv.c
  4. *
  5. * Copyright (c) 1999 Microsoft Corporation. All Rights Reserved.
  6. *
  7. * Abstract:
  8. *
  9. * Effect driver.
  10. *
  11. * WARNING! Since the effect driver is marked ThreadingModel="Both",
  12. * all methods must be thread-safe.
  13. *
  14. *****************************************************************************/
  15. #include "PIDpr.h"
  16. #define sqfl (sqflEffDrv)
  17. /*****************************************************************************
  18. *
  19. * CPidDrv - Effect driver
  20. *
  21. *****************************************************************************/
  22. /*****************************************************************************
  23. *
  24. * PID_AddRef
  25. *
  26. * Increment our object reference count (thread-safely) and return
  27. * the new reference count.
  28. *
  29. *****************************************************************************/
  30. STDMETHODIMP_(ULONG)
  31. PID_AddRef(IDirectInputEffectDriver *ped)
  32. {
  33. CPidDrv *this = (CPidDrv *)ped;
  34. InterlockedIncrement((LPLONG)&this->cRef);
  35. return this->cRef;
  36. }
  37. /*****************************************************************************
  38. *
  39. * PID_Release
  40. *
  41. * Decrement our object reference count (thread-safely) and
  42. * destroy ourselves if there are no more references.
  43. *
  44. *****************************************************************************/
  45. STDMETHODIMP_(ULONG)
  46. PID_Release(IDirectInputEffectDriver *ped)
  47. {
  48. ULONG ulRc;
  49. CPidDrv *this = (CPidDrv *)ped;
  50. if(InterlockedDecrement((LPLONG)&this->cRef) == 0)
  51. {
  52. DllRelease();
  53. PID_Finalize(ped);
  54. LocalFree(this);
  55. ulRc = 0;
  56. } else
  57. {
  58. ulRc = this->cRef;
  59. }
  60. return ulRc;
  61. }
  62. /*****************************************************************************
  63. *
  64. * PID_QueryInterface
  65. *
  66. * Our QI is very simple because we support no interfaces beyond
  67. * ourselves.
  68. *
  69. * riid - Interface being requested
  70. * ppvOut - receives new interface (if successful)
  71. *
  72. *****************************************************************************/
  73. STDMETHODIMP
  74. PID_QueryInterface(IDirectInputEffectDriver *ped, REFIID riid, LPVOID *ppvOut)
  75. {
  76. HRESULT hres;
  77. if(IsEqualIID(riid, &IID_IUnknown) ||
  78. IsEqualIID(riid, &IID_IDirectInputEffectDriver))
  79. {
  80. PID_AddRef(ped);
  81. *ppvOut = ped;
  82. hres = S_OK;
  83. } else
  84. {
  85. *ppvOut = 0;
  86. hres = E_NOINTERFACE;
  87. }
  88. return hres;
  89. }
  90. /*****************************************************************************
  91. *
  92. * PID_DeviceID
  93. *
  94. * DirectInput uses this method to inform us of
  95. * the identity of the device.
  96. *
  97. * For example, if a device driver is passed
  98. * dwExternalID = 2 and dwInternalID = 1,
  99. * then this means the interface will be used to
  100. * communicate with joystick ID number 2, which
  101. * corresonds to physical unit 1 in VJOYD.
  102. *
  103. * dwDirectInputVersion
  104. *
  105. * The version of DirectInput that loaded the
  106. * effect driver.
  107. *
  108. * dwExternalID
  109. *
  110. * The joystick ID number being used.
  111. * The Windows joystick subsystem allocates external IDs.
  112. *
  113. * fBegin
  114. *
  115. * Nonzero if access to the device is beginning.
  116. * Zero if the access to the device is ending.
  117. *
  118. * dwInternalID
  119. *
  120. * Internal joystick id. The device driver manages
  121. * internal IDs.
  122. *
  123. * lpReserved
  124. *
  125. * Reserved for future use (HID).
  126. *
  127. * Returns:
  128. *
  129. * S_OK if the operation completed successfully.
  130. *
  131. * Any DIERR_* error code may be returned.
  132. *
  133. * Private driver-specific error codes in the range
  134. * DIERR_DRIVERFIRST through DIERR_DRIVERLAST
  135. * may be returned.
  136. *
  137. *****************************************************************************/
  138. STDMETHODIMP
  139. PID_DeviceID(IDirectInputEffectDriver *ped,
  140. DWORD dwDirectInputVersion,
  141. DWORD dwExternalID, DWORD fBegin,
  142. DWORD dwInternalID, LPVOID pvReserved)
  143. {
  144. CPidDrv *this = (CPidDrv *)ped;
  145. HRESULT hres = S_OK;
  146. LPDIHIDFFINITINFO init = (DIHIDFFINITINFO*)pvReserved;
  147. EnterProcI(PID_DeviceID, (_"xxxxxx", ped, dwDirectInputVersion, dwExternalID, fBegin, dwInternalID, pvReserved));
  148. DllEnterCrit();
  149. if( init == NULL )
  150. {
  151. SquirtSqflPtszV(sqfl | sqflError,
  152. TEXT("%s: FAIL init == NULL "),
  153. s_tszProc );
  154. hres = DIERR_PID_NOTINITIALIZED;
  155. }
  156. if( SUCCEEDED(hres)
  157. && (init->dwSize < cbX(*init) ) )
  158. {
  159. SquirtSqflPtszV(sqfl | sqflError,
  160. TEXT("%s: FAIL init->dwSize(%d) expecting(%d) "),
  161. s_tszProc, init->dwSize, cbX(*init) );
  162. hres = DIERR_PID_NOTINITIALIZED;
  163. }
  164. if( SUCCEEDED(hres) )
  165. {
  166. #ifdef UNICODE
  167. lstrcpy(this->tszDeviceInterface, init->pwszDeviceInterface );
  168. #else // !UNICODE
  169. {
  170. TCHAR tszDeviceInterface[MAX_DEVICEINTERFACE];
  171. UToA(tszDeviceInterface, MAX_DEVICEINTERFACE, init->pwszDeviceInterface);
  172. lstrcpy(this->tszDeviceInterface, tszDeviceInterface);
  173. }
  174. #endif
  175. if( FAILED(hres) )
  176. {
  177. SquirtSqflPtszV(sqfl | sqflError,
  178. TEXT("%s: FAIL:0x%x Invalid string(%s) "),
  179. s_tszProc, hres, init->pwszDeviceInterface );
  180. }
  181. if( SUCCEEDED(hres) && IsEqualGUID(&init->GuidInstance, &GUID_NULL ) )
  182. {
  183. hres = DIERR_PID_NOTINITIALIZED;
  184. SquirtSqflPtszV(sqfl | sqflError,
  185. TEXT("%s: FAIL:init->GuidInstance is NULL "),
  186. s_tszProc );
  187. }
  188. this->GuidInstance = init->GuidInstance;
  189. /* Record the DI version number */
  190. this->dwDirectInputVersion = dwDirectInputVersion;
  191. /* Keep the external ID as a cookie for access to the driver functionality */
  192. this->dwID = dwExternalID;
  193. }
  194. if( SUCCEEDED(hres) )
  195. {
  196. /* Ping the device to make sure it is fine */
  197. hres = PID_Init(ped);
  198. }
  199. /*
  200. * Remember the unit number because that tells us which of
  201. * our devices we are talking to. The DirectInput external
  202. * joystick number is useless to us. (We don't care if we
  203. * are joystick 1 or joystick 2.)
  204. *
  205. * Note that although our other methods are given an external
  206. * joystick Id, we don't use it. Instead, we use the unit
  207. * number that we were given here.
  208. *
  209. * Our hardware supports only MAX_UNITS units.
  210. */
  211. DllLeaveCrit();
  212. ExitOleProc();
  213. return hres;
  214. }
  215. /*****************************************************************************
  216. *
  217. * PID_GetVersions
  218. *
  219. * Obtain version information about the force feedback
  220. * hardware and driver.
  221. *
  222. * pvers
  223. *
  224. * A structure which should be filled in with version information
  225. * describing the hardware, firmware, and driver.
  226. *
  227. * DirectInput will set the dwSize field
  228. * to sizeof(DIDRIVERVERSIONS) before calling this method.
  229. *
  230. * Returns:
  231. *
  232. * S_OK if the operation completed successfully.
  233. *
  234. * E_NOTIMPL to indicate that DirectInput should retrieve
  235. * version information from the VxD driver instead.
  236. *
  237. * Any DIERR_* error code may be returned.
  238. *
  239. * Private driver-specific error codes in the range
  240. * DIERR_DRIVERFIRST through DIERR_DRIVERLAST
  241. * may be returned.
  242. *
  243. *****************************************************************************/
  244. STDMETHODIMP
  245. PID_GetVersions(IDirectInputEffectDriver *ped, LPDIDRIVERVERSIONS pvers)
  246. {
  247. CPidDrv *this = (CPidDrv *)ped;
  248. HRESULT hres;
  249. EnterProc(PID_GetVersions, (_"xx", ped, pvers));
  250. DllEnterCrit();
  251. if(pvers->dwSize >= sizeof(DIDRIVERVERSIONS))
  252. {
  253. /*
  254. * Tell DirectInput how much of the structure we filled in.
  255. */
  256. pvers->dwSize = sizeof(DIDRIVERVERSIONS);
  257. /*
  258. * In real life, we would detect the version of the hardware
  259. * that is connected to unit number this->dwUnit.
  260. */
  261. pvers->dwFirmwareRevision = 0x0;
  262. pvers->dwHardwareRevision = this->attr.ProductID;
  263. pvers->dwFFDriverVersion = PID_DRIVER_VERSION;
  264. hres = S_OK;
  265. } else
  266. {
  267. hres = E_INVALIDARG;
  268. }
  269. DllLeaveCrit();
  270. ExitOleProc();
  271. return hres;
  272. }
  273. /*****************************************************************************
  274. *
  275. * PID_Escape
  276. *
  277. * DirectInput uses this method to communicate
  278. * IDirectInputDevice2::Escape and
  279. * IDirectInputEFfect::Escape methods to the driver.
  280. *
  281. * dwId
  282. *
  283. * The joystick ID number being used.
  284. *
  285. * dwEffect
  286. *
  287. * If the application invoked the
  288. * IDirectInputEffect::Escape method, then
  289. * dwEffect contains the handle (returned by
  290. * mf IDirectInputEffectDriver::DownloadEffect)
  291. * of the effect at which the command is directed.
  292. *
  293. * If the application invoked the
  294. * mf IDirectInputDevice2::Escape method, then
  295. * dwEffect is zero.
  296. *
  297. * pesc
  298. *
  299. * Pointer to a DIEFFESCAPE structure which describes
  300. * the command to be sent. On success, the
  301. * cbOutBuffer field contains the number
  302. * of bytes of the output buffer actually used.
  303. *
  304. * DirectInput has already validated that the
  305. * lpvOutBuffer and lpvInBuffer and fields
  306. * point to valid memory.
  307. *
  308. * Returns:
  309. *
  310. * S_OK if the operation completed successfully.
  311. *
  312. * Any DIERR_* error code may be returned.
  313. *
  314. * Private driver-specific error codes in the range
  315. * DIERR_DRIVERFIRST through DIERR_DRIVERLAST
  316. * may be returned.
  317. *
  318. *****************************************************************************/
  319. STDMETHODIMP
  320. PID_Escape(IDirectInputEffectDriver *ped,
  321. DWORD dwId, DWORD dwEffect, LPDIEFFESCAPE pesc)
  322. {
  323. CPidDrv *this = (CPidDrv *)ped;
  324. HRESULT hres;
  325. EnterProc(PID_Escape, (_"xxxx", ped, dwId, dwEffect, pesc));
  326. hres = E_NOTIMPL;
  327. ExitOleProc();
  328. return hres;
  329. }
  330. /*****************************************************************************
  331. *
  332. * PID_GetForceFeedbackState
  333. *
  334. * Retrieve the force feedback state for the device.
  335. *
  336. * dwId
  337. *
  338. * The external joystick number being addressed.
  339. *
  340. * pds
  341. *
  342. * Receives device state.
  343. *
  344. * DirectInput will set the dwSize field
  345. * to sizeof(DIDEVICESTATE) before calling this method.
  346. *
  347. * Returns:
  348. *
  349. * S_OK on success.
  350. *
  351. * Any DIERR_* error code may be returned.
  352. *
  353. * Private driver-specific error codes in the range
  354. * DIERR_DRIVERFIRST through DIERR_DRIVERLAST
  355. * may be returned.
  356. *
  357. *****************************************************************************/
  358. STDMETHODIMP
  359. PID_GetForceFeedbackState(IDirectInputEffectDriver *ped,
  360. DWORD dwId, LPDIDEVICESTATE pds)
  361. {
  362. CPidDrv *this = (CPidDrv *)ped;
  363. HRESULT hres;
  364. USHORT LinkCollection;
  365. EnterProcI(PID_GetFFState, (_"xxx", ped, dwId, pds));
  366. DllEnterCrit();
  367. hres = PID_GetLinkCollectionIndex(ped,g_PoolReport.UsagePage,g_PoolReport.Collection,0x0,&LinkCollection);
  368. if (SUCCEEDED(hres))
  369. {
  370. hres = PID_GetReport
  371. (ped,
  372. &g_PoolReport,
  373. LinkCollection,
  374. this->pReport[g_PoolReport.HidP_Type],
  375. this->cbReport[g_PoolReport.HidP_Type]
  376. );
  377. if (SUCCEEDED(hres))
  378. {
  379. if (FAILED(PID_ParseReport
  380. (
  381. ped,
  382. &g_PoolReport,
  383. LinkCollection,
  384. &this->ReportPool,
  385. cbX(this->ReportPool),
  386. this->pReport[g_PoolReport.HidP_Type],
  387. this->cbReport[g_PoolReport.HidP_Type]
  388. )))
  389. {
  390. SquirtSqflPtszV(sqfl | sqflError,
  391. TEXT("%s: FAIL to parse report."),
  392. s_tszProc);
  393. }
  394. }
  395. else
  396. {
  397. SquirtSqflPtszV(sqfl | sqflError,
  398. TEXT("%s: FAIL to get report."),
  399. s_tszProc);
  400. }
  401. }
  402. else
  403. {
  404. SquirtSqflPtszV(sqfl | sqflError,
  405. TEXT("%s: FAIL to get Link Collection Index."),
  406. s_tszProc);
  407. }
  408. if( ((PUNITSTATE)(g_pshmem + this->iUnitStateOffset))->cEfDownloaded != this->ReportPool.uRomETCount )
  409. {
  410. SquirtSqflPtszV(sqfl | sqflError,
  411. TEXT("%s: PID driver downloaded %d effects, device claims it has %d"),
  412. s_tszProc, ((PUNITSTATE)(g_pshmem + this->iUnitStateOffset))->cEfDownloaded, this->ReportPool.uRomETCount );
  413. }
  414. if(SUCCEEDED(hres))
  415. {
  416. /*
  417. * Start out empty and then work our way up.
  418. */
  419. pds->dwState = this->dwState;
  420. /*
  421. * If there are no effects, then DIGFFS_EMPTY.
  422. */
  423. // ISSUE-2001/03/29-timgill Should use this->ReportPool.uRomETCount == 0x0
  424. if(((PUNITSTATE)(g_pshmem + this->iUnitStateOffset))->cEfDownloaded == 0x0 )
  425. {
  426. pds->dwState |= DIGFFS_EMPTY;
  427. // No effects playing and device is not paused
  428. if(!( pds->dwState & DIGFFS_PAUSED ) )
  429. {
  430. pds->dwState |= DIGFFS_STOPPED;
  431. }
  432. }
  433. //if everything has succeeded, this->ReportPool.uRamPoolSz shouldn't be 0.
  434. if (this->ReportPool.uRamPoolSz != 0)
  435. {
  436. if( this->uDeviceManaged & PID_DEVICEMANAGED )
  437. {
  438. pds->dwLoad = 100 * ( this->dwUsedMem / this->ReportPool.uRamPoolSz );
  439. }else
  440. {
  441. pds->dwLoad = 100 * ( ((PUNITSTATE)(g_pshmem + this->iUnitStateOffset))->cbAlloc / this->ReportPool.uRamPoolSz );
  442. }
  443. }
  444. else
  445. {
  446. SquirtSqflPtszV(sqfl | sqflError,
  447. TEXT("%s: this->ReportPool.uRamPoolSz = 0."),
  448. s_tszProc);
  449. hres = E_FAIL;
  450. }
  451. }
  452. DllLeaveCrit();
  453. ExitOleProc();
  454. return hres;
  455. }
  456. /*****************************************************************************
  457. *
  458. * PID_StartEffect
  459. *
  460. * Begin playback of an effect.
  461. *
  462. * If the effect is already playing, then it is restarted
  463. * from the beginning.
  464. *
  465. * @cwrap LPDIRECTINPUTEFFECTDRIVER | lpEffectDriver
  466. *
  467. * @parm DWORD | dwId |
  468. *
  469. * The external joystick number being addressed.
  470. *
  471. * @parm DWORD | dwEffect |
  472. *
  473. * The effect to be played.
  474. *
  475. * @parm DWORD | dwMode |
  476. *
  477. * How the effect is to affect other effects.
  478. *
  479. * This parameter consists of zero or more
  480. * DIES_* flags. Note, however, that the driver
  481. * will never receive the DIES_NODOWNLOAD flag;
  482. * the DIES_NODOWNLOAD flag is managed by
  483. * DirectInput and not the driver.
  484. *
  485. * @parm DWORD | dwCount |
  486. *
  487. * Number of times the effect is to be played.
  488. *
  489. * Returns:
  490. *
  491. * S_OK on success.
  492. *
  493. * Any other DIERR_* error code may be returned.
  494. *
  495. * Private driver-specific error codes in the range
  496. * DIERR_DRIVERFIRST through DIERR_DRIVERLAST
  497. * may be returned.
  498. *
  499. *
  500. *****************************************************************************/
  501. STDMETHODIMP
  502. PID_StartEffect(IDirectInputEffectDriver *ped, DWORD dwId, DWORD dwEffect,
  503. DWORD dwMode, DWORD dwCount)
  504. {
  505. CPidDrv *this = (CPidDrv *)ped;
  506. HRESULT hres;
  507. EnterProc(PID_StartEffect, (_"xxxxx", ped, dwId, dwEffect, dwMode, dwCount));
  508. DllEnterCrit();
  509. hres = PID_EffectOperation
  510. (
  511. ped,
  512. dwId,
  513. dwEffect,
  514. dwMode | PID_DIES_START,
  515. dwCount,
  516. TRUE,
  517. 0,
  518. 1
  519. );
  520. if (SUCCEEDED(hres))
  521. {
  522. //set the status to DIEGES_PLAYING.
  523. //we do this because of the following: if an app calls Start(), and then immediately
  524. //calls GetEffectStatus(), it might happen that our second thread (pidrd.c)
  525. //would not have time to update the status of the effect to DIEGES_PLAYING
  526. //(see Whistler bug 287035).
  527. //GetEffectStatus() returns (pEffectState->lEfState & DIEGES_PLAYING).
  528. //at this point, we know that the call to WriteFile() has succeeded, and that
  529. //all the data has been written (see PID_SendReportBl() in pidhid.c) --
  530. //so we might as well set the status.
  531. PEFFECTSTATE pEffectState = PeffectStateFromBlockIndex(this, dwEffect);
  532. pEffectState->lEfState |= DIEGES_PLAYING;
  533. }
  534. DllLeaveCrit();
  535. return hres;
  536. ExitOleProc();
  537. }
  538. /*****************************************************************************
  539. *
  540. * PID_StopEffect
  541. *
  542. * Halt playback of an effect.
  543. *
  544. * dwId
  545. *
  546. * The external joystick number being addressed.
  547. *
  548. * dwEffect
  549. *
  550. * The effect to be stopped.
  551. *
  552. * Returns:
  553. *
  554. * S_OK on success.
  555. *
  556. * Any other DIERR_* error code may be returned.
  557. *
  558. * Private driver-specific error codes in the range
  559. * DIERR_DRIVERFIRST through DIERR_DRIVERLAST
  560. * may be returned.
  561. *
  562. *
  563. *****************************************************************************/
  564. STDMETHODIMP
  565. PID_StopEffect(IDirectInputEffectDriver *ped, DWORD dwId, DWORD dwEffect)
  566. {
  567. CPidDrv *this = (CPidDrv *)ped;
  568. HRESULT hres;
  569. EnterProc(PID_StopEffect, (_"xxxx", ped, dwId, dwEffect));
  570. DllEnterCrit();
  571. hres = PID_EffectOperation
  572. (
  573. ped,
  574. dwId,
  575. dwEffect,
  576. PID_DIES_STOP,
  577. 0x0,
  578. TRUE,
  579. 0,
  580. 1
  581. );
  582. if (SUCCEEDED(hres))
  583. {
  584. //set the status to ~(DIEGES_PLAYING).
  585. //we do this because of the following: if an app calls Stop(), and then immediately
  586. //calls GetEffectStatus(), it might happen that our second thread (pidrd.c)
  587. //would not have time to update the status of the effect to DIEGES_PLAYING
  588. //(see Whistler bug 287035).
  589. //GetEffectStatus() returns (pEffectState->lEfState & DIEGES_PLAYING).
  590. //at this point, we know that the call to WriteFile() has succeeded, and that
  591. //all the data has been written (see PID_SendReportBl() in pidhid.c) --
  592. //so we might as well set the status.
  593. PEFFECTSTATE pEffectState = PeffectStateFromBlockIndex(this, dwEffect);
  594. pEffectState->lEfState &= ~(DIEGES_PLAYING);
  595. }
  596. ExitOleProc();
  597. DllLeaveCrit();
  598. return hres;
  599. }
  600. /*****************************************************************************
  601. *
  602. * PID_GetEffectStatus
  603. *
  604. * Obtain information about an effect.
  605. *
  606. * dwId
  607. *
  608. * The external joystick number being addressed.
  609. *
  610. * dwEffect
  611. *
  612. * The effect to be queried.
  613. *
  614. * pdwStatus
  615. *
  616. * Receives the effect status in the form of zero
  617. * or more DIEGES_* flags.
  618. *
  619. * Returns:
  620. *
  621. * S_OK on success.
  622. *
  623. * Any other DIERR_* error code may be returned.
  624. *
  625. * Private driver-specific error codes in the range
  626. * DIERR_DRIVERFIRST through DIERR_DRIVERLAST
  627. * may be returned.
  628. *
  629. *
  630. *****************************************************************************/
  631. STDMETHODIMP
  632. PID_GetEffectStatus(IDirectInputEffectDriver *ped, DWORD dwId, DWORD dwEffect,
  633. LPDWORD pdwStatus)
  634. {
  635. CPidDrv *this = (CPidDrv *)ped;
  636. HRESULT hres;
  637. EnterProc(PID_GetEffectStatus, (_"xxxx", ped, dwId, dwEffect, pdwStatus));
  638. DllEnterCrit();
  639. *pdwStatus = 0x0;
  640. hres = PID_ValidateEffectIndex(ped, dwEffect);
  641. if(SUCCEEDED(hres) )
  642. {
  643. PEFFECTSTATE pEffectState = PeffectStateFromBlockIndex(this,dwEffect);
  644. *pdwStatus = (pEffectState->lEfState & DIEGES_PLAYING);
  645. }
  646. DllLeaveCrit();
  647. ExitOleProc();
  648. return hres;
  649. }
  650. /*****************************************************************************
  651. *
  652. * The VTBL for our effect driver
  653. *
  654. *****************************************************************************/
  655. IDirectInputEffectDriverVtbl PID_Vtbl = {
  656. PID_QueryInterface,
  657. PID_AddRef,
  658. PID_Release,
  659. PID_DeviceID,
  660. PID_GetVersions,
  661. PID_Escape,
  662. PID_SetGain,
  663. PID_SendForceFeedbackCommand,
  664. PID_GetForceFeedbackState,
  665. PID_DownloadEffect,
  666. PID_DestroyEffect,
  667. PID_StartEffect,
  668. PID_StopEffect,
  669. PID_GetEffectStatus,
  670. };
  671. /*****************************************************************************
  672. *
  673. * PID_New
  674. *
  675. *****************************************************************************/
  676. STDMETHODIMP
  677. PID_New(REFIID riid, LPVOID *ppvOut)
  678. {
  679. HRESULT hres;
  680. CPidDrv *this;
  681. this = LocalAlloc(LPTR, sizeof(CPidDrv));
  682. if(this)
  683. {
  684. /*
  685. * Initialize the basic object management goo.
  686. */
  687. this->ed.lpVtbl = &PID_Vtbl;
  688. this->cRef = 1;
  689. DllAddRef();
  690. /*
  691. * !!IHV!! Do instance initialization here.
  692. *
  693. * (e.g., open the driver you are going to IOCTL to)
  694. *
  695. * DO NOT RESET THE DEVICE IN YOUR CONSTRUCTOR!
  696. *
  697. * Wait for the SendForceFeedbackCommand(SFFC_RESET)
  698. * to reset the device. Otherwise, you may reset
  699. * a device that another application is still using.
  700. */
  701. this->hdevOvrlp = this->hdev = INVALID_HANDLE_VALUE;
  702. /*
  703. * Attempt to obtain the desired interface. QueryInterface
  704. * will do an AddRef if it succeeds.
  705. */
  706. hres = PID_QueryInterface(&this->ed, riid, ppvOut);
  707. PID_Release(&this->ed);
  708. } else
  709. {
  710. hres = E_OUTOFMEMORY;
  711. }
  712. return hres;
  713. }