Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

1974 lines
56 KiB

  1. /*****************************************************************************
  2. *
  3. * DIEm.c
  4. *
  5. * Copyright (c) 1996 Microsoft Corporation. All Rights Reserved.
  6. *
  7. * Abstract:
  8. *
  9. * DirectInput VxD emulation layer. (I.e., do the things that
  10. * dinput.vxd normally does.) You may find large chunks of this
  11. * code familiar: It's exactly the same thing that happens in
  12. * the VxD.
  13. *
  14. * Contents:
  15. *
  16. * CEm_AcquireInstance
  17. * CEm_UnacquireInstance
  18. * CEm_SetBufferSize
  19. * CEm_DestroyInstance
  20. * CEm_SetDataFormat
  21. *
  22. *****************************************************************************/
  23. #include "dinputpr.h"
  24. /*****************************************************************************
  25. *
  26. * The sqiffle for this file.
  27. *
  28. *****************************************************************************/
  29. #define sqfl sqflEm
  30. #define ThisClass CEm
  31. #define CEM_SIGNATURE 0x4D4D4545 /* "EEMM" */
  32. PEM g_pemFirst;
  33. #ifdef WORKER_THREAD
  34. PLLTHREADSTATE g_plts; /* The currently active input thread */
  35. #ifdef USE_WM_INPUT
  36. BOOL g_fFromKbdMse;
  37. #endif
  38. #endif /* WORKER_THREAD */
  39. /*****************************************************************************
  40. *
  41. * @doc INTERNAL
  42. *
  43. * @func void | CEm_FreeInstance |
  44. *
  45. * It's really gone now.
  46. *
  47. * @parm PEM | this |
  48. *
  49. * The victim.
  50. *
  51. *****************************************************************************/
  52. void EXTERNAL
  53. CEm_FreeInstance(PEM this)
  54. {
  55. PEM *ppem;
  56. EnterProc(CEm_FreeInstance, (_ "p", this));
  57. AssertF(this->dwSignature == CEM_SIGNATURE);
  58. AssertF(this->cRef == 0);
  59. /*
  60. * It is the owner's responsibility to unacquire before releasing.
  61. */
  62. AssertF(!(this->vi.fl & VIFL_ACQUIRED));
  63. /*
  64. * If this device has a reference to a hook, then remove
  65. * the reference.
  66. */
  67. #ifdef WORKER_THREAD
  68. if (this->fWorkerThread) {
  69. PLLTHREADSTATE plts;
  70. DWORD idThread;
  71. /*
  72. * Protect test and access of g_plts with DLLCrit
  73. */
  74. DllEnterCrit();
  75. plts = g_plts;
  76. if (plts ) {
  77. AssertF(plts->cRef);
  78. /*
  79. * Note that we need to keep the thread ID because
  80. * the InterlockedDecrement might cause us to lose
  81. * the object.
  82. *
  83. * Note that this opens a race condition where the
  84. * thread might decide to kill itself before we
  85. * post it the nudge message. That's okay, because
  86. * even if the thread ID gets recycled, the message
  87. * that appears is a dummy WM_NULL message that
  88. * causes no harm.
  89. */
  90. idThread = plts->idThread; /* Must save before we dec */
  91. if( InterlockedDecrement(&plts->cRef) == 0 ) {
  92. g_plts = 0;
  93. }
  94. }
  95. DllLeaveCrit();
  96. if( plts )
  97. {
  98. NudgeWorkerThread(idThread);
  99. }
  100. }
  101. #endif
  102. /*
  103. * Unlink the node from the master list.
  104. */
  105. DllEnterCrit();
  106. for (ppem = &g_pemFirst; *ppem; ppem = &(*ppem)->pemNext) {
  107. AssertF((*ppem)->dwSignature == CEM_SIGNATURE);
  108. if (*ppem == this) {
  109. *ppem = (*ppem)->pemNext;
  110. break;
  111. }
  112. }
  113. AssertF(ppem);
  114. DllLeaveCrit();
  115. FreePpv(&this->rgdwDf);
  116. FreePpv(&this->vi.pBuffer);
  117. if( InterlockedDecrement(&this->ped->cRef) == 0x0 )
  118. {
  119. FreePpv(&this->ped->pDevType);
  120. }
  121. D(this->dwSignature++);
  122. FreePv(this);
  123. ExitProc();
  124. }
  125. /*****************************************************************************
  126. *
  127. * @doc INTERNAL
  128. *
  129. * @func HRESULT | CEm_CreateInstance |
  130. *
  131. * Create a device thing.
  132. *
  133. * @parm PVXDDEVICEFORMAT | pdevf |
  134. *
  135. * What the object should look like.
  136. *
  137. * @parm PVXDINSTANCE * | ppviOut |
  138. *
  139. * The answer goes here.
  140. *
  141. * @parm PED | ped |
  142. *
  143. * Descriptor.
  144. *
  145. *****************************************************************************/
  146. HRESULT EXTERNAL
  147. CEm_CreateInstance(PVXDDEVICEFORMAT pdevf, PVXDINSTANCE *ppviOut, PED ped)
  148. {
  149. HRESULT hres;
  150. EnterProc(CEm_CreateInstance, (_ "pp", pdevf, ped));
  151. AssertF(pdevf->cbData == ped->cbData);
  152. CAssertF(FIELD_OFFSET(CEm, vi) == 0);
  153. hres = AllocCbPpv(cbX(CEm), ppviOut);
  154. if (SUCCEEDED(hres)) {
  155. PEM pem = (PV)*ppviOut;
  156. D(pem->dwSignature = CEM_SIGNATURE);
  157. pem->dwExtra = pdevf->dwExtra;
  158. pem->ped = ped;
  159. pem->cAcquire = -1;
  160. /*
  161. * Make sure these functions are inverses.
  162. */
  163. AssertF(DIGETEMFL(DIMAKEEMFL(pdevf->dwEmulation)) ==
  164. pdevf->dwEmulation);
  165. pem->vi.fl = VIFL_EMULATED | DIMAKEEMFL(pdevf->dwEmulation);
  166. pem->vi.pState = ped->pState;
  167. CEm_AddRef(pem);
  168. DllEnterCrit();
  169. /*
  170. * Build the devtype array. This consists of one dword
  171. * for each byte in the data format.
  172. *
  173. * Someday: Do the button thing too.
  174. */
  175. if (ped->pDevType == 0) {
  176. hres = ReallocCbPpv(cbCdw(pdevf->cbData), &ped->pDevType);
  177. if (SUCCEEDED(hres)) {
  178. UINT iobj;
  179. /*
  180. * If HID is messed up, we will end up with
  181. * entries whose dwType is zero (because HID
  182. * said they existed, but when we went around
  183. * enumerating, they never showed up).
  184. *
  185. * And don't put no-data items into the array!
  186. */
  187. for (iobj = 0; iobj < pdevf->cObj; iobj++) {
  188. if (pdevf->rgodf[iobj].dwType &&
  189. !(pdevf->rgodf[iobj].dwType & DIDFT_NODATA)) {
  190. ped->pDevType[pdevf->rgodf[iobj].dwOfs] =
  191. pdevf->rgodf[iobj].dwType;
  192. }
  193. }
  194. }
  195. } else {
  196. hres = S_OK;
  197. }
  198. if (SUCCEEDED(hres)) {
  199. /*
  200. * Link this node into the list. This must be done
  201. * under the critical section.
  202. */
  203. pem->pemNext = g_pemFirst;
  204. g_pemFirst = pem;
  205. InterlockedIncrement(&ped->cRef);
  206. *ppviOut = &pem->vi;
  207. } else {
  208. FreePpv(ppviOut);
  209. }
  210. DllLeaveCrit();
  211. }
  212. ExitOleProcPpv(ppviOut);
  213. return hres;
  214. }
  215. /*****************************************************************************
  216. *
  217. * @doc INTERNAL
  218. *
  219. * @func DWORD | CEm_NextSequence |
  220. *
  221. * Increment the sequence number wherever it may be.
  222. *
  223. *****************************************************************************/
  224. DWORD INTERNAL
  225. CEm_NextSequence(void)
  226. {
  227. /*
  228. * Stashing the value into a local tells the compiler that
  229. * the value can be cached. Otherwise, the compiler has
  230. * to assume that InterlockedIncrement can modify g_pdwSequence
  231. * so it keeps reloading it.
  232. */
  233. LPDWORD pdwSequence = g_pdwSequence;
  234. AssertF(pdwSequence);
  235. /*
  236. * Increment through zero.
  237. */
  238. if (InterlockedIncrement((LPLONG)pdwSequence) == 0) {
  239. InterlockedIncrement((LPLONG)pdwSequence);
  240. }
  241. return *pdwSequence;
  242. }
  243. /*****************************************************************************
  244. *
  245. * @doc INTERNAL
  246. *
  247. * @func PEM | CEm_BufferEvent |
  248. *
  249. * Add a single event to the device, returning the next device
  250. * on the global list.
  251. *
  252. * This routine is entered with the global critical section
  253. * taken exactly once.
  254. *
  255. *****************************************************************************/
  256. PEM INTERNAL
  257. CEm_BufferEvent(PEM pem, DWORD dwData, DWORD dwOfs, DWORD tm, DWORD dwSeq)
  258. {
  259. PEM pemNext;
  260. /*
  261. * We must release the global critical section in order to take
  262. * the device critical section.
  263. */
  264. CEm_AddRef(pem); /* Make sure it doesn't vanish */
  265. DllLeaveCrit();
  266. AssertF(!InCrit());
  267. /*
  268. * ---Windows Bug 238305---
  269. * Run the buffering code in __try block so that if an
  270. * input is receive after the device is released, we can
  271. * catch the AV and clean up from there.
  272. */
  273. __try
  274. {
  275. CDIDev_EnterCrit(pem->vi.pdd);
  276. AssertF(dwOfs < pem->ped->cbData);
  277. AssertF(pem->rgdwDf);
  278. /*
  279. * If the user cares about the object...
  280. */
  281. if (pem->rgdwDf[dwOfs] != 0xFFFFFFFF) {
  282. LPDIDEVICEOBJECTDATA pdod = pem->vi.pHead;
  283. /*
  284. * Set the node value.
  285. */
  286. pdod->dwOfs = pem->rgdwDf[dwOfs];
  287. pdod->dwData = dwData;
  288. pdod->dwTimeStamp = tm;
  289. pdod->dwSequence = dwSeq;
  290. /*
  291. * Append the node to the list if there is room.
  292. * Note that we rely above on the fact that the list is
  293. * never totally full.
  294. */
  295. pdod++;
  296. AssertF(pdod <= pem->vi.pEnd);
  297. if (pdod >= pem->vi.pEnd) {
  298. pdod = pem->vi.pBuffer;
  299. }
  300. /*
  301. * always keep the new data
  302. */
  303. pem->vi.pHead = pdod;
  304. if (pdod == pem->vi.pTail) {
  305. if (!pem->vi.fOverflow) {
  306. RPF("Buffer overflow; discard old data");
  307. }
  308. pem->vi.pTail++;
  309. if (pem->vi.pTail == pem->vi.pEnd) {
  310. pem->vi.pTail = pem->vi.pBuffer;
  311. }
  312. pem->vi.fOverflow = 1;
  313. }
  314. }
  315. CDIDev_LeaveCrit(pem->vi.pdd);
  316. }
  317. /*
  318. * If we get an AV, most likely input is received after the device has
  319. * been released. In this case, we clean up the thread and exit as
  320. * soon as possible.
  321. */
  322. __except( GetExceptionCode() == EXCEPTION_ACCESS_VIOLATION ?
  323. EXCEPTION_EXECUTE_HANDLER :
  324. EXCEPTION_CONTINUE_SEARCH )
  325. {
  326. /* Do nothing here, so we clean up the thread and exit below. */
  327. RPF("CEm_BufferEvent: Access Violation catched! Most likely the device has been released");
  328. }
  329. DllEnterCrit();
  330. pemNext = pem->pemNext;
  331. AssertF(fLimpFF(pemNext, pemNext->dwSignature == CEM_SIGNATURE));
  332. CEm_Release(pem);
  333. return pemNext;
  334. }
  335. /*****************************************************************************
  336. *
  337. * @doc EXTERNAL
  338. *
  339. * @func HRESULT | CEm_ContinueEvent |
  340. *
  341. * Add a single event to the queues of all acquired devices
  342. * of the indicated type.
  343. *
  344. * @returns
  345. *
  346. * TRUE if someone is interested in this data (even if they are not
  347. * buffered).
  348. *
  349. *****************************************************************************/
  350. BOOL EXTERNAL
  351. CEm_ContinueEvent(PED ped, DWORD dwData, DWORD dwOfs, DWORD tm, DWORD dwSeq)
  352. {
  353. DWORD ddwData; /* delta in dwData */
  354. DWORD dwNativeData; /* delta for rel, dwData for abs */
  355. BOOL fRtn = FALSE;
  356. AssertF(!InCrit());
  357. /* Sanity check: Make sure the ped has been initialized */
  358. if (ped->pDevType) {
  359. PEM pem, pemNext;
  360. if (ped->pDevType[dwOfs] & DIDFT_DWORDOBJS) {
  361. DWORD UNALIGNED *pdw = pvAddPvCb(ped->pState, dwOfs);
  362. if (*pdw != dwData) {
  363. if (ped->pDevType[dwOfs] & DIDFT_POV) {
  364. ddwData = dwData; /* Don't do deltas for POV */
  365. } else {
  366. ddwData = dwData - *pdw;
  367. }
  368. *pdw = dwData;
  369. /*
  370. * Assert that if it's not a relative axis, its a POV or
  371. * an absolute axis, both of which should be absolute.
  372. */
  373. CAssertF( DIDFT_DWORDOBJS
  374. == ( DIDFT_ABSAXIS | DIDFT_RELAXIS | DIDFT_POV ) );
  375. /*
  376. * DX7 had series of bugs, the net result of which was
  377. * that emulated devices only report data in their native
  378. * mode. If that behavior is required make it so here.
  379. */
  380. if( ped->pDevType[dwOfs] & DIDFT_RELAXIS )
  381. {
  382. dwNativeData = ddwData; /* Always use relative */
  383. }
  384. else
  385. {
  386. dwNativeData = dwData; /* Always use absolute */
  387. }
  388. } else {
  389. goto nop;
  390. }
  391. } else {
  392. LPBYTE pb = pvAddPvCb(ped->pState, dwOfs);
  393. AssertF((dwData & ~0x80) == 0);
  394. if (*pb != (BYTE)dwData) {
  395. *pb = (BYTE)dwData;
  396. dwNativeData = ddwData = dwData; /* Don't do deltas for buttons */
  397. /* Someday: Button sequences go here */
  398. } else {
  399. goto nop;
  400. }
  401. }
  402. AssertF(!InCrit()); /* You can never be too paranoid */
  403. DllEnterCrit();
  404. for (pem = g_pemFirst; pem; pem = pemNext) {
  405. AssertF(pem->dwSignature == CEM_SIGNATURE);
  406. if ((pem->vi.fl & (VIFL_ACQUIRED|VIFL_INITIALIZE)) && pem->ped == ped) {
  407. if (pem->vi.pBuffer) {
  408. if( pem->vi.fl & VIFL_MODECOMPAT )
  409. {
  410. pemNext = CEm_BufferEvent(pem, dwNativeData, dwOfs, tm, dwSeq);
  411. }
  412. else if( pem->vi.fl & VIFL_RELATIVE )
  413. {
  414. pemNext = CEm_BufferEvent(pem, ddwData, dwOfs, tm, dwSeq);
  415. }
  416. else
  417. {
  418. pemNext = CEm_BufferEvent(pem, dwData, dwOfs, tm, dwSeq);
  419. }
  420. AssertF(fLimpFF(pemNext,
  421. pemNext->dwSignature == CEM_SIGNATURE));
  422. } else {
  423. pemNext = pem->pemNext;
  424. AssertF(fLimpFF(pemNext,
  425. pemNext->dwSignature == CEM_SIGNATURE));
  426. }
  427. /*
  428. * Since this happens only when the device is acquired,
  429. * we don't need to worry about the notify event changing
  430. * asynchronously.
  431. *
  432. * UPDATE 1/5/01 Winbug 270403 (jacklin): Moved call to CDIDev_SetNotifyEvent
  433. * below so the buffer is updated before the event is set.
  434. *
  435. * It would be easy to avoid setting the event if nothing
  436. * was buffered for better performance but people will be
  437. * relying on getting events now, even when they are not
  438. * using a buffer.
  439. */
  440. fRtn = TRUE;
  441. } else {
  442. pemNext = pem->pemNext;
  443. AssertF(fLimpFF(pemNext,
  444. pemNext->dwSignature == CEM_SIGNATURE));
  445. }
  446. }
  447. DllLeaveCrit();
  448. }
  449. nop:;
  450. return fRtn;
  451. }
  452. /*****************************************************************************
  453. *
  454. * @doc INTERNAL
  455. *
  456. * @func DWORD | CEm_AddEvent |
  457. *
  458. * Increment the DirectInput sequence number, then
  459. * add a single event to the queues of all acquired devices
  460. * of the indicated type.
  461. *
  462. * @parm PED | ped |
  463. *
  464. * Device which is adding the event.
  465. *
  466. * @parm DWORD | dwData |
  467. *
  468. * The event data.
  469. *
  470. * @parm DWORD | dwOfs |
  471. *
  472. * Device data format-relative offset for <p dwData>.
  473. *
  474. * @parm DWORD | tm |
  475. *
  476. * Time the event was generated.
  477. *
  478. * @returns
  479. *
  480. * Returns the sequence number added, so that it may be
  481. * continued.
  482. *
  483. *****************************************************************************/
  484. DWORD EXTERNAL
  485. CEm_AddEvent(PED ped, DWORD dwData, DWORD dwOfs, DWORD tm)
  486. {
  487. PEM pem, pemNext;
  488. DWORD dwSeq = CEm_NextSequence();
  489. AssertF(!InCrit()); /* You can never be too paranoid */
  490. if( CEm_ContinueEvent(ped, dwData, dwOfs, tm, dwSeq) )
  491. {
  492. DllEnterCrit();
  493. for (pem = g_pemFirst; pem; pem = pemNext) {
  494. AssertF(pem->dwSignature == CEM_SIGNATURE);
  495. if ((pem->vi.fl & VIFL_ACQUIRED) && pem->ped == ped) {
  496. CDIDev_SetNotifyEvent(pem->vi.pdd);
  497. }
  498. pemNext = pem->pemNext;
  499. AssertF(fLimpFF(pemNext,
  500. pemNext->dwSignature == CEM_SIGNATURE));
  501. }
  502. DllLeaveCrit();
  503. }
  504. return dwSeq;
  505. }
  506. /*****************************************************************************
  507. *
  508. * @doc INTERNAL
  509. *
  510. * @func HRESULT | CEm_AddState |
  511. *
  512. * Record a brand new device state.
  513. *
  514. * @parm PED | ped |
  515. *
  516. * Device which has changed state.
  517. *
  518. * @parm DWORD | dwData |
  519. *
  520. * The value to record.
  521. *
  522. * @parm DWORD | tm |
  523. *
  524. * Time the state change was generated.
  525. *
  526. *****************************************************************************/
  527. void EXTERNAL
  528. CEm_AddState(PED ped, LPVOID pvData, DWORD tm)
  529. {
  530. DWORD dwSeq = CEm_NextSequence();
  531. /* Sanity check: Make sure the ped has been initialized */
  532. if (ped->pDevType) {
  533. DWORD dwOfs;
  534. BOOL fEvent = FALSE;
  535. /*
  536. * Note, it is too late to improve performance by only doing events
  537. * if somebody is listening.
  538. */
  539. dwOfs = 0;
  540. while (dwOfs < ped->cbData) {
  541. /*
  542. * There shouldn't be any no-data items.
  543. */
  544. AssertF(!(ped->pDevType[dwOfs] & DIDFT_NODATA));
  545. if (ped->pDevType[dwOfs] & DIDFT_DWORDOBJS) {
  546. DWORD UNALIGNED *pdw = pvAddPvCb(pvData, dwOfs);
  547. if( CEm_ContinueEvent(ped, *pdw, dwOfs, tm, dwSeq) ) {
  548. fEvent = TRUE;
  549. }
  550. dwOfs += cbX(DWORD);
  551. } else {
  552. LPBYTE pb = pvAddPvCb(pvData, dwOfs);
  553. if( CEm_ContinueEvent(ped, *pb, dwOfs, tm, dwSeq) ) {
  554. fEvent = TRUE;
  555. }
  556. dwOfs++;
  557. }
  558. }
  559. if( fEvent ) {
  560. PEM pem, pemNext;
  561. AssertF(!InCrit()); /* You can never be too paranoid */
  562. DllEnterCrit();
  563. for (pem = g_pemFirst; pem; pem = pemNext) {
  564. AssertF(pem->dwSignature == CEM_SIGNATURE);
  565. if ((pem->vi.fl & VIFL_ACQUIRED) && pem->ped == ped) {
  566. CDIDev_SetNotifyEvent(pem->vi.pdd);
  567. }
  568. pemNext = pem->pemNext;
  569. AssertF(fLimpFF(pemNext,
  570. pemNext->dwSignature == CEM_SIGNATURE));
  571. }
  572. DllLeaveCrit();
  573. }
  574. }
  575. }
  576. #if 0
  577. /*****************************************************************************
  578. *
  579. * @doc INTERNAL
  580. *
  581. * @func HRESULT | CEm_InputLost |
  582. *
  583. * Remove global hooks because something weird happened.
  584. *
  585. * We don't need to do anything because our hooks are local.
  586. *
  587. *****************************************************************************/
  588. HRESULT INLINE
  589. CEm_InputLost(LPVOID pvIn, LPVOID pvOut)
  590. {
  591. return S_OK;
  592. }
  593. #endif
  594. /*****************************************************************************
  595. *
  596. * @doc INTERNAL
  597. *
  598. * @func HRESULT | CEm_UnacquirePem |
  599. *
  600. * Unacquire the device in the device-specific way.
  601. *
  602. * @parm PEM | pem |
  603. *
  604. * Information about the gizmo being mangled.
  605. *
  606. * @parm UINT | fdufl |
  607. *
  608. * Assorted flags describing why we are being unacquired.
  609. *
  610. *****************************************************************************/
  611. HRESULT INTERNAL
  612. CEm_UnacquirePem(PEM this, UINT fdufl)
  613. {
  614. HRESULT hres;
  615. #ifdef DEBUG
  616. EnterProcR(CEm_UnacquirePem, (_ "px", this, fdufl));
  617. #else
  618. EnterProcR(IDirectInputDevice::Unacquire, (_ "p", this));
  619. #endif
  620. AssertF(this->dwSignature == CEM_SIGNATURE);
  621. AssertF((fdufl & ~FDUFL_UNPLUGGED) == 0);
  622. CAssertF(FDUFL_UNPLUGGED == VIFL_UNPLUGGED);
  623. if (this->vi.fl & VIFL_ACQUIRED) {
  624. this->vi.fl &= ~VIFL_ACQUIRED;
  625. this->vi.fl |= fdufl;
  626. if (InterlockedDecrement(&this->cAcquire) < 0) {
  627. InterlockedDecrement(&this->ped->cAcquire);
  628. hres = this->ped->Acquire(this, 0);
  629. } else {
  630. SquirtSqflPtszV(sqfl, TEXT("%S: Still acquired %d"),
  631. s_szProc, this->cAcquire);
  632. hres = S_OK;
  633. }
  634. } else {
  635. SquirtSqflPtszV(sqfl, TEXT("%S: Not acquired %d"),
  636. s_szProc, this->cAcquire);
  637. hres = S_OK;
  638. }
  639. ExitOleProc();
  640. return hres;
  641. }
  642. /*****************************************************************************
  643. *
  644. * @doc INTERNAL
  645. *
  646. * @func void | CEm_ForceDeviceUnacquire |
  647. *
  648. * Force all users of a device to unacquire.
  649. *
  650. * @parm PEM | pem |
  651. *
  652. * Information about the gizmo being mangled.
  653. *
  654. * @parm UINT | fdufl |
  655. *
  656. * Assorted flags describing why we are being unacquired.
  657. *
  658. *****************************************************************************/
  659. void EXTERNAL
  660. CEm_ForceDeviceUnacquire(PED ped, UINT fdufl)
  661. {
  662. PEM pem, pemNext;
  663. AssertF((fdufl & ~FDUFL_UNPLUGGED) == 0);
  664. AssertF(!DllInCrit());
  665. DllEnterCrit();
  666. for (pem = g_pemFirst; pem; pem = pemNext) {
  667. AssertF(pem->dwSignature == CEM_SIGNATURE);
  668. if (pem->ped == ped && (pem->vi.fl & VIFL_ACQUIRED)) {
  669. CEm_AddRef(pem);
  670. DllLeaveCrit();
  671. CEm_UnacquirePem(pem, fdufl);
  672. CDIDev_SetForcedUnacquiredFlag(pem->vi.pdd);
  673. /*
  674. * Since this happens only when the device is acquired,
  675. * we don't need to worry about the notify event changing
  676. * asynchronously.
  677. */
  678. CDIDev_SetNotifyEvent(pem->vi.pdd);
  679. DllEnterCrit();
  680. pemNext = pem->pemNext;
  681. AssertF(pem->dwSignature == CEM_SIGNATURE);
  682. CEm_Release(pem);
  683. } else {
  684. pemNext = pem->pemNext;
  685. AssertF(pem->dwSignature == CEM_SIGNATURE);
  686. }
  687. }
  688. DllLeaveCrit();
  689. }
  690. /*****************************************************************************
  691. *
  692. * @doc INTERNAL
  693. *
  694. * @func HRESULT | CEm_DestroyInstance |
  695. *
  696. * Clean up an instance.
  697. *
  698. *****************************************************************************/
  699. HRESULT EXTERNAL
  700. CEm_DestroyInstance(PVXDINSTANCE *ppvi)
  701. {
  702. HRESULT hres;
  703. PEM this = _thisPvNm(*ppvi, vi);
  704. EnterProc(CEm_DestroyInstance, (_ "p", *ppvi));
  705. AssertF(this->dwSignature == CEM_SIGNATURE);
  706. AssertF((PV)this == (PV)*ppvi);
  707. if (this) {
  708. CEm_Release(this);
  709. }
  710. hres = S_OK;
  711. ExitOleProc();
  712. return hres;
  713. }
  714. /*****************************************************************************
  715. *
  716. * @doc INTERNAL
  717. *
  718. * @func HRESULT | CEm_SetDataFormat |
  719. *
  720. * Record the application data format in the device so that
  721. * we can translate it for buffering purposes.
  722. *
  723. * @parm PVXDDATAFORMAT | pvdf |
  724. *
  725. * Information about the gizmo being mangled.
  726. *
  727. *****************************************************************************/
  728. HRESULT INTERNAL
  729. CEm_SetDataFormat(PVXDDATAFORMAT pvdf)
  730. {
  731. HRESULT hres;
  732. PEM this = _thisPvNm(pvdf->pvi, vi);
  733. EnterProc(CEm_SetDataFormat, (_ "p", pvdf->pvi));
  734. AssertF(this->dwSignature == CEM_SIGNATURE);
  735. hres = ReallocCbPpv( cbCdw(pvdf->cbData), &this->rgdwDf);
  736. if (SUCCEEDED(hres)) {
  737. AssertF(pvdf->cbData == this->ped->cbData);
  738. memcpy(this->rgdwDf, pvdf->pDfOfs, cbCdw(pvdf->cbData) );
  739. }
  740. ExitOleProc();
  741. return hres;
  742. }
  743. /*****************************************************************************
  744. *
  745. * @doc INTERNAL
  746. *
  747. * @func HRESULT | CEm_AcquireInstance |
  748. *
  749. * Acquire the device in the device-specific way.
  750. *
  751. * @parm PVXDINSTANCE * | ppvi |
  752. *
  753. * The instance to acquire.
  754. *
  755. *****************************************************************************/
  756. HRESULT INTERNAL
  757. CEm_AcquireInstance(PVXDINSTANCE *ppvi)
  758. {
  759. HRESULT hres;
  760. PEM this = _thisPvNm(*ppvi, vi);
  761. #ifdef DEBUG
  762. EnterProc(CEm_AcquireInstance, (_ "p", *ppvi));
  763. #else
  764. EnterProcR(IDirectInputDevice::Acquire, (_ "p", *ppvi));
  765. #endif
  766. AssertF(this->dwSignature == CEM_SIGNATURE);
  767. this->vi.fl |= VIFL_ACQUIRED;
  768. if (InterlockedIncrement(&this->cAcquire) == 0) {
  769. InterlockedIncrement(&this->ped->cAcquire);
  770. hres = this->ped->Acquire(this, 1);
  771. if (FAILED(hres)) {
  772. this->vi.fl &= ~VIFL_ACQUIRED;
  773. InterlockedDecrement(&this->cAcquire);
  774. }
  775. } else {
  776. SquirtSqflPtszV(sqfl, TEXT("%S: Already acquired %d"),
  777. s_szProc, this->cAcquire);
  778. hres = S_OK;
  779. }
  780. ExitOleProc();
  781. return hres;
  782. }
  783. /*****************************************************************************
  784. *
  785. * @doc INTERNAL
  786. *
  787. * @func HRESULT | CEm_UnacquireInstance |
  788. *
  789. * Unacquire the device in the device-specific way.
  790. *
  791. * @parm PVXDINSTANCE * | ppvi |
  792. *
  793. * Information about the gizmo being mangled.
  794. *
  795. *****************************************************************************/
  796. HRESULT INTERNAL
  797. CEm_UnacquireInstance(PVXDINSTANCE *ppvi)
  798. {
  799. HRESULT hres;
  800. PEM this = _thisPvNm(*ppvi, vi);
  801. EnterProc(CEm_UnacquireInstance, (_ "p", *ppvi));
  802. hres = CEm_UnacquirePem(this, FDUFL_NORMAL);
  803. ExitOleProc();
  804. return hres;
  805. }
  806. /*****************************************************************************
  807. *
  808. * @doc INTERNAL
  809. *
  810. * @func HRESULT | CEm_SetBufferSize |
  811. *
  812. * Allocate a buffer of the appropriate size.
  813. *
  814. * @parm PVXDDWORDDATA | pvdd |
  815. *
  816. * The <p dwData> is the buffer size.
  817. *
  818. *****************************************************************************/
  819. HRESULT INTERNAL
  820. CEm_SetBufferSize(PVXDDWORDDATA pvdd)
  821. {
  822. HRESULT hres;
  823. PEM this = _thisPvNm(pvdd->pvi, vi);
  824. EnterProc(CEm_SetBufferSize, (_ "px", pvdd->pvi, pvdd->dw));
  825. AssertF(this->dwSignature == CEM_SIGNATURE);
  826. hres = ReallocCbPpv(cbCxX(pvdd->dw, DIDEVICEOBJECTDATA),
  827. &this->vi.pBuffer);
  828. if (SUCCEEDED(hres)) {
  829. this->vi.pHead = this->vi.pBuffer;
  830. this->vi.pTail = this->vi.pBuffer;
  831. this->vi.pEnd = &this->vi.pBuffer[pvdd->dw];
  832. }
  833. ExitOleProc();
  834. return hres;
  835. }
  836. #ifdef USE_SLOW_LL_HOOKS
  837. /*****************************************************************************
  838. *
  839. * @struct LLHOOKINFO |
  840. *
  841. * Information about how to install a low-level hook.
  842. *
  843. * @field int | idHook |
  844. *
  845. * The Windows hook identifier.
  846. *
  847. * @field HOOKPROC | hp |
  848. *
  849. * The hook procedure itself.
  850. *
  851. *****************************************************************************/
  852. typedef struct LLHOOKINFO {
  853. int idHook;
  854. HOOKPROC hp;
  855. } LLHOOKINFO, *PLLHOOKINFO;
  856. typedef const LLHOOKINFO *PCLLHOOKINFO;
  857. #pragma BEGIN_CONST_DATA
  858. const LLHOOKINFO c_rgllhi[] = {
  859. { WH_KEYBOARD_LL, CEm_LL_KbdHook }, /* LLTS_KBD */
  860. { WH_MOUSE_LL, CEm_LL_MseHook }, /* LLTS_MSE */
  861. };
  862. #pragma END_CONST_DATA
  863. /*****************************************************************************
  864. *
  865. * @doc INTERNAL
  866. *
  867. * @func void | CEm_LL_SyncHook |
  868. *
  869. * Install or remove a hook as needed.
  870. *
  871. * @parm UINT | ilts |
  872. *
  873. * Which hook is being handled?
  874. *
  875. * @parm PLLTHREADSTATE | plts |
  876. *
  877. * Thread hook state containing hook information to synchronize.
  878. *
  879. *****************************************************************************/
  880. void INTERNAL
  881. CEm_LL_SyncHook(PLLTHREADSTATE plts, UINT ilts)
  882. {
  883. PLLHOOKSTATE plhs = &plts->rglhs[ilts];
  884. if (!fLeqvFF(plhs->cHook, plhs->hhk)) {
  885. if (plhs->hhk) {
  886. UnhookWindowsHookEx(plhs->hhk);
  887. plhs->hhk = 0;
  888. } else {
  889. PCLLHOOKINFO pllhi = &c_rgllhi[ilts];
  890. plhs->hhk = SetWindowsHookEx(pllhi->idHook, pllhi->hp, g_hinst, 0);
  891. }
  892. }
  893. }
  894. #endif /* USE_SLOW_LL_HOOKS */
  895. #ifdef WORKER_THREAD
  896. /*****************************************************************************
  897. *
  898. * @doc INTERNAL
  899. *
  900. * @func DWORD | FakeMsgWaitForMultipleObjectsEx |
  901. *
  902. * Stub function which emulates
  903. * <f MsgWaitForMultipleObjectsEx>
  904. * on platforms that do not support it.
  905. *
  906. * Such platforms (namely, Windows 95) do not support HID
  907. * and therefore the inability to go into an alertable
  908. * wait state constitutes no loss of amenity.
  909. *
  910. * @parm DWORD | nCount |
  911. *
  912. * Number of handles in handle array.
  913. *
  914. * @parm LPHANDLE | pHandles |
  915. *
  916. * Pointer to an object-handle array.
  917. *
  918. * @parm DWORD | ms |
  919. *
  920. * Time-out interval in milliseconds.
  921. *
  922. * @parm DWORD | dwWakeMask |
  923. *
  924. * Type of input events to wait for.
  925. *
  926. * @parm DWORD | dwFlags |
  927. *
  928. * Wait flags.
  929. *
  930. * @returns
  931. *
  932. * Same as <f MsgWaitForMultipleObjectsEx>.
  933. *
  934. *****************************************************************************/
  935. DWORD WINAPI
  936. FakeMsgWaitForMultipleObjectsEx(
  937. DWORD nCount,
  938. LPHANDLE pHandles,
  939. DWORD ms,
  940. DWORD dwWakeMask,
  941. DWORD dwFlags)
  942. {
  943. /*
  944. * We merely call the normal MsgWaitForMultipleObjects because
  945. * the only way we can get here is on a platform that doesn't
  946. * support HID.
  947. */
  948. return MsgWaitForMultipleObjects(nCount, pHandles,
  949. dwFlags & MWMO_WAITALL, ms, dwWakeMask);
  950. }
  951. #ifdef WINNT
  952. // On win2k non-exclusive mode user thinks the Dinput thread is hung.
  953. // In order to fix this we set a TimerEvent and wake up every so
  954. // often and execute the FakeTimerProc. This keeps user happy and
  955. // keeps dinput thread from being marked as hung and we can get
  956. // events to our low level hooks
  957. VOID CALLBACK FakeTimerProc(
  958. HWND hwnd, // handle to window
  959. UINT uMsg, // WM_TIMER message
  960. UINT_PTR idEvent, // timer identifier
  961. DWORD dwTime // current system time
  962. )
  963. {
  964. }
  965. #endif
  966. #ifdef USE_WM_INPUT
  967. #pragma BEGIN_CONST_DATA
  968. TCHAR c_szEmClassName[] = TEXT("DIEmWin");
  969. #pragma END_CONST_DATA
  970. /****************************************************************************
  971. *
  972. * CEm_WndProc
  973. *
  974. * Window procedure for simple sample.
  975. *
  976. ****************************************************************************/
  977. LRESULT CALLBACK
  978. CEm_WndProc( HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam )
  979. {
  980. switch (msg) {
  981. //case WM_INPUT:
  982. // RPF("in WM_INPUT message");
  983. // break;
  984. default:
  985. break;
  986. }
  987. return DefWindowProc(hwnd, msg, wParam, lParam);
  988. }
  989. HWND
  990. CEm_InitWindow(void)
  991. {
  992. HWND hwnd;
  993. WNDCLASS wc;
  994. static BOOL fFirstTime = TRUE;
  995. if( fFirstTime ) {
  996. wc.hCursor = LoadCursor(0, IDC_ARROW);
  997. wc.hIcon = LoadIcon(NULL, MAKEINTRESOURCE(IDI_APPLICATION));
  998. wc.lpszMenuName = NULL;
  999. wc.lpszClassName = c_szEmClassName;
  1000. wc.hbrBackground = 0;
  1001. wc.hInstance = g_hinst;
  1002. wc.style = 0;
  1003. wc.lpfnWndProc = CEm_WndProc;
  1004. wc.cbClsExtra = 0;
  1005. wc.cbWndExtra = 0;
  1006. if (!RegisterClass(&wc)) {
  1007. return NULL;
  1008. }
  1009. fFirstTime = FALSE;
  1010. }
  1011. hwnd = CreateWindow(
  1012. c_szEmClassName, // Class name
  1013. TEXT("DIEmWin"), // Caption
  1014. WS_OVERLAPPEDWINDOW, // Style
  1015. -1, -1, // Position
  1016. 1, 1, // Size
  1017. NULL, //parent
  1018. NULL, // No menu
  1019. g_hinst, // inst handle
  1020. 0 // no params
  1021. );
  1022. if( !hwnd ) {
  1023. RPF("CreateWindow failed.");
  1024. }
  1025. return hwnd;
  1026. }
  1027. #endif
  1028. /*****************************************************************************
  1029. *
  1030. * @doc INTERNAL
  1031. *
  1032. * @func VOID | CEm_LL_ThreadProc |
  1033. *
  1034. * The thread that manages our low-level hooks.
  1035. *
  1036. * ThreadProcs are prototyped to return a DWORD but since the return
  1037. * would follow some form of ExitThread, it will never be reached so
  1038. * this function is declared to return VOID and cast.
  1039. *
  1040. * When we get started, and whenever we receive any message
  1041. * whatsoever, re-check to see which hooks should be installed
  1042. * and re-synchronize ourselves with them.
  1043. *
  1044. * Note that restarting can be slow, since it happens only
  1045. * when we get nudged by a client.
  1046. *
  1047. * @parm PLLTHREADSTATE | plts |
  1048. *
  1049. * The thread state to use.
  1050. *
  1051. *****************************************************************************/
  1052. VOID INTERNAL
  1053. CEm_LL_ThreadProc(PLLTHREADSTATE plts)
  1054. {
  1055. MSG msg;
  1056. DWORD dwRc;
  1057. #ifdef USE_WM_INPUT
  1058. HWND hwnd = NULL;
  1059. #endif
  1060. AssertF(plts->idThread == GetCurrentThreadId());
  1061. SquirtSqflPtszV(sqflLl, TEXT("CEm_LL_ThreadProc: Thread started"));
  1062. #ifdef USE_SLOW_LL_HOOKS
  1063. /*
  1064. * Refresh the mouse acceleration values.
  1065. *
  1066. * ISSUE-2001/03/29-timgill Need a window to listen for WM_SETTINGCHANGE
  1067. * We need to create a window to listen for
  1068. * WM_SETTINGCHANGE so we can refresh the mouse acceleration
  1069. * as needed.
  1070. */
  1071. CEm_Mouse_OnMouseChange();
  1072. #endif
  1073. /*
  1074. * Create ourselves a queue before we go into our "hey what happened
  1075. * before I got here?" phase. The thread that created us is waiting on
  1076. * the thread event, holding DLLCrit, so let it go as soon as the queue
  1077. * is ready. We create the queue by calling a function that requires a
  1078. * queue. We use this very simple one.
  1079. */
  1080. GetInputState();
  1081. #ifdef WINNT
  1082. // Look at comment block in FakeTimerProc
  1083. SetTimer(NULL, 0, 2 * 1000 /*2 seconds*/, FakeTimerProc);
  1084. #endif
  1085. SetEvent(plts->hEvent);
  1086. #ifdef USE_WM_INPUT
  1087. ResetEvent( g_hEventThread );
  1088. if( g_fRawInput ) {
  1089. hwnd = CEm_InitWindow();
  1090. if (!hwnd) {
  1091. g_fRawInput = FALSE;
  1092. }
  1093. }
  1094. g_hwndThread = hwnd;
  1095. // Tell CEm_LL_Acquire that windows has been created.
  1096. SetEvent( g_hEventAcquire );
  1097. if( g_fFromKbdMse ) {
  1098. DWORD rc;
  1099. rc = WaitForSingleObject(g_hEventThread, INFINITE);
  1100. g_fFromKbdMse = FALSE;
  1101. }
  1102. #endif
  1103. #ifdef USE_SLOW_LL_HOOKS
  1104. /*
  1105. * Note carefully that we sync the hooks before entering our
  1106. * fake GetMessage loop. This is necessary to avoid the race
  1107. * condition when CEm_LL_Acquire posts us a thread message
  1108. * before our thread gets a queue. By sync'ing the hooks
  1109. * first, we do what the lost message would've had us do
  1110. * anyway.
  1111. * ISSUE-2001/03/29-timgill Following branch should be no longer necessary
  1112. * This is should not be needed now that CEm_GetWorkerThread waits for
  1113. * this thread to respond before continuing on to post any messages.
  1114. */
  1115. #endif /* USE_SLOW_LL_HOOKS */
  1116. do {
  1117. #ifdef USE_SLOW_LL_HOOKS
  1118. if( !g_fRawInput ) {
  1119. CEm_LL_SyncHook(plts, LLTS_KBD);
  1120. CEm_LL_SyncHook(plts, LLTS_MSE);
  1121. }
  1122. #endif
  1123. /*
  1124. * We can wake up for three reasons.
  1125. *
  1126. * 1. We received an APC due to an I/o completion.
  1127. * Just go back to sleep.
  1128. *
  1129. * 2. We need to call Peek/GetMessage so that
  1130. * USER can dispatch a low-level hook or SendMessage.
  1131. * Go into a PeekMessage loop to let that happen.
  1132. *
  1133. * 3. A message got posted to us.
  1134. * Go into a PeekMessage loop to process it.
  1135. */
  1136. do {
  1137. dwRc = _MsgWaitForMultipleObjectsEx(0, 0, INFINITE, QS_ALLINPUT,
  1138. MWMO_ALERTABLE);
  1139. } while (dwRc == WAIT_IO_COMPLETION);
  1140. while (PeekMessage(&msg, 0, 0, 0, PM_REMOVE)) {
  1141. #ifdef HID_SUPPORT
  1142. if (msg.hwnd == 0 && msg.message == WM_NULL && msg.lParam)
  1143. {
  1144. /*
  1145. * See if maybe the lParam is a valid PEM that we're
  1146. * processing.
  1147. */
  1148. PEM pem = (PEM)msg.lParam;
  1149. if( pem && pem == plts->pemCheck )
  1150. {
  1151. AssertF(GPA_FindPtr(&plts->gpaHid, pem));
  1152. CEm_HID_Sync(plts, pem);
  1153. plts->pemCheck = NULL;
  1154. SetEvent(plts->hEvent);
  1155. #ifdef USE_WM_INPUT
  1156. if( g_fRawInput ) {
  1157. SetEvent(g_hEventHid);
  1158. }
  1159. #endif
  1160. continue;
  1161. }
  1162. }
  1163. #ifdef USE_WM_INPUT
  1164. else if ( g_fRawInput && msg.message == WM_INPUT &&
  1165. (msg.wParam == RIM_INPUT || msg.wParam == RIM_INPUTSINK) )
  1166. {
  1167. CDIRaw_OnInput(&msg);
  1168. }
  1169. #endif
  1170. #endif //ifdef HID_SUPPORT
  1171. TranslateMessage(&msg);
  1172. DispatchMessage(&msg);
  1173. }
  1174. } while (plts->cRef);
  1175. #ifdef USE_SLOW_LL_HOOKS
  1176. /*
  1177. * Remove our hooks before we go.
  1178. *
  1179. * It is possible that there was a huge flurry of disconnects,
  1180. * causing us to notice that our refcount disappeared before
  1181. * we got a chance to remove the hooks in our message loop.
  1182. */
  1183. AssertF(plts->rglhs[LLTS_KBD].cHook == 0);
  1184. AssertF(plts->rglhs[LLTS_KBD].cExcl == 0);
  1185. AssertF(plts->rglhs[LLTS_MSE].cHook == 0);
  1186. AssertF(plts->rglhs[LLTS_MSE].cExcl == 0);
  1187. if( !g_fRawInput ) {
  1188. if (plts->rglhs[LLTS_KBD].hhk) {
  1189. UnhookWindowsHookEx(plts->rglhs[LLTS_KBD].hhk);
  1190. }
  1191. if (plts->rglhs[LLTS_MSE].hhk) {
  1192. UnhookWindowsHookEx(plts->rglhs[LLTS_MSE].hhk);
  1193. }
  1194. }
  1195. #endif /* USE_SLOW_LL_HOOKS */
  1196. #ifdef USE_WM_INPUT
  1197. if( g_hwndThread ) {
  1198. DestroyWindow( g_hwndThread );
  1199. g_hwndThread = NULL;
  1200. }
  1201. ResetEvent( g_hEventAcquire );
  1202. ResetEvent( g_hEventHid );
  1203. #endif
  1204. if( plts->gpaHid.rgpv ) {
  1205. FreePpv(&plts->gpaHid.rgpv);
  1206. }
  1207. if( plts->hEvent ) {
  1208. CloseHandle( plts->hEvent );
  1209. }
  1210. if( plts->hThread) {
  1211. CloseHandle(plts->hThread);
  1212. }
  1213. FreePpv( &plts );
  1214. SquirtSqflPtszV(sqflLl, TEXT("CEm_LL_ThreadProc: Thread terminating"));
  1215. FreeLibraryAndExitThread(g_hinst, 0);
  1216. /*NOTREACHED*/
  1217. }
  1218. /*****************************************************************************
  1219. *
  1220. * @doc INTERNAL
  1221. *
  1222. * @func HRESULT | CEm_GetWorkerThread |
  1223. *
  1224. * Piggyback off the existing worker thread if possible;
  1225. * else create a new one.
  1226. *
  1227. * @parm PEM | pem |
  1228. *
  1229. * Emulation state which requires a worker thread.
  1230. *
  1231. * @parm PLLTHREADSTATE * | pplts |
  1232. *
  1233. * Receives thread state for worker thread.
  1234. *
  1235. *****************************************************************************/
  1236. STDMETHODIMP
  1237. CEm_GetWorkerThread(PEM pem, PLLTHREADSTATE *pplts)
  1238. {
  1239. PLLTHREADSTATE plts;
  1240. HRESULT hres;
  1241. DllEnterCrit();
  1242. /*
  1243. * Normally, we can piggyback off the one we already have.
  1244. */
  1245. plts = g_plts;
  1246. /*
  1247. * If we already have a ref to a worker thread, then use it.
  1248. */
  1249. if (pem->fWorkerThread) {
  1250. /*
  1251. * The reference we created when we created the worker thread
  1252. * ensures that g_plts is valid.
  1253. */
  1254. AssertF(plts);
  1255. AssertF(plts->cRef);
  1256. if (plts) {
  1257. hres = S_OK;
  1258. } else {
  1259. AssertF(0); /* Can't happen */
  1260. hres = E_FAIL;
  1261. }
  1262. } else
  1263. if (plts) {
  1264. /*
  1265. * Create a reference to the existing thread.
  1266. */
  1267. pem->fWorkerThread = TRUE;
  1268. InterlockedIncrement(&plts->cRef);
  1269. hres = S_OK;
  1270. } else {
  1271. /*
  1272. * There is no worker thread (or it is irretrievably
  1273. * on its way out) so create a new one.
  1274. */
  1275. hres = AllocCbPpv(cbX(LLTHREADSTATE), &plts);
  1276. if (SUCCEEDED(hres)) {
  1277. DWORD dwRc = 0;
  1278. TCHAR tsz[MAX_PATH];
  1279. /*
  1280. * Assume the worst unless we find otherwise
  1281. */
  1282. hres = E_FAIL;
  1283. if( GetModuleFileName(g_hinst, tsz, cA(tsz))
  1284. && ( LoadLibrary(tsz) == g_hinst ) )
  1285. {
  1286. /*
  1287. * Must set up everything to avoid racing with
  1288. * the incoming thread.
  1289. */
  1290. g_plts = plts;
  1291. InterlockedIncrement(&plts->cRef);
  1292. plts->hEvent = CreateEvent(0x0, 0, 0, 0x0);
  1293. if( plts->hEvent )
  1294. {
  1295. plts->hThread = CreateThread(0, 0, (LPTHREAD_START_ROUTINE)CEm_LL_ThreadProc, plts,
  1296. 0, &plts->idThread);
  1297. if( plts->hThread )
  1298. {
  1299. /*
  1300. * Boost our priority to make sure we
  1301. * can handle the messages.
  1302. *
  1303. * RaymondC commented this out saying that it does not
  1304. * help but we're hoping that it may on Win2k.
  1305. */
  1306. SetThreadPriority(plts->hThread, THREAD_PRIORITY_HIGHEST);
  1307. /*
  1308. * Wait for the thread to signal that it is up and running
  1309. * or for it to terminate.
  1310. * This means that we don't have to consider the
  1311. * possibility that the thread is not yet running in
  1312. * NotifyWorkerThreadPem so we know a failure there is
  1313. * terminal and don't retry.
  1314. *
  1315. * Assert that the handle fields make a two handle array.
  1316. */
  1317. CAssertF( FIELD_OFFSET( LLTHREADSTATE, hThread) + sizeof(plts->hThread)
  1318. == FIELD_OFFSET( LLTHREADSTATE, hEvent) );
  1319. /*
  1320. * According to a comment in CEm_LL_ThreadProc Win95 may
  1321. * fail with an invalid parameter error, so if it does,
  1322. * keep trying. (Assume no valid case will occur.)
  1323. *
  1324. * ISSUE-2001/03/29-timgill Need to minimise waits while holding sync. objects
  1325. * Waiting whilst holding DLLCrit is bad.
  1326. */
  1327. do
  1328. {
  1329. dwRc = WaitForMultipleObjects( 2, &plts->hThread, FALSE, INFINITE);
  1330. } while ( ( dwRc == WAIT_FAILED ) && ( GetLastError() == ERROR_INVALID_PARAMETER ) );
  1331. if( dwRc == WAIT_OBJECT_0 ) {
  1332. SquirtSqflPtszV(sqfl | sqflError,
  1333. TEXT("CEm_GetWorkerThread: Created Thread terminated on first wait") );
  1334. } else {
  1335. pem->fWorkerThread = TRUE;
  1336. hres = S_OK;
  1337. if( dwRc != WAIT_OBJECT_0 + 1 )
  1338. {
  1339. /*
  1340. * This would be a bad thing if it ever happened
  1341. * but we have to assume that the thread is still
  1342. * running so we return a success anyway.
  1343. */
  1344. SquirtSqflPtszV(sqfl | sqflError,
  1345. TEXT("CEm_GetWorkerThread: First wait returned 0x%08x with LastError %d"),
  1346. dwRc, GetLastError() );
  1347. }
  1348. }
  1349. }
  1350. else
  1351. {
  1352. SquirtSqflPtszV(sqfl | sqflError,
  1353. TEXT("CEm_GetWorkerThread: CreateThread failed with error %d"),
  1354. GetLastError() );
  1355. }
  1356. }
  1357. else
  1358. {
  1359. SquirtSqflPtszV(sqfl | sqflError,
  1360. TEXT("CEm_GetWorkerThread: CreateEvent failed with error %d"),
  1361. GetLastError() );
  1362. }
  1363. if( FAILED( hres ) )
  1364. {
  1365. if( plts->hEvent ) {
  1366. CloseHandle( plts->hEvent );
  1367. }
  1368. FreeLibrary(g_hinst);
  1369. }
  1370. }
  1371. else
  1372. {
  1373. RPF( "CEm_GetWorkerThread: failed to LoadLibrary( self ), le = %d", GetLastError() );
  1374. }
  1375. if( FAILED( hres ) )
  1376. {
  1377. FreePv(plts);
  1378. g_plts = 0;
  1379. }
  1380. }
  1381. }
  1382. DllLeaveCrit();
  1383. *pplts = plts;
  1384. return hres;
  1385. }
  1386. #endif /* WORKER_THREAD */
  1387. #ifdef USE_SLOW_LL_HOOKS
  1388. /*****************************************************************************
  1389. *
  1390. * @doc INTERNAL
  1391. *
  1392. * @func HRESULT | CEm_LL_Acquire |
  1393. *
  1394. * Acquire/unacquire a mouse or keyboard via low-level hooks.
  1395. *
  1396. * @parm PEM | pem |
  1397. *
  1398. * Device being acquired.
  1399. *
  1400. * @parm BOOL | fAcquire |
  1401. *
  1402. * Whether the device is being acquired or unacquired.
  1403. *
  1404. * @parm ULONG | fl |
  1405. *
  1406. * Flags in VXDINSTANCE (vi.fl).
  1407. *
  1408. * @parm UINT | ilts |
  1409. *
  1410. * LLTS_KBD or LLTS_MSE, depending on which is happening.
  1411. *
  1412. *****************************************************************************/
  1413. STDMETHODIMP
  1414. CEm_LL_Acquire(PEM this, BOOL fAcquire, ULONG fl, UINT ilts)
  1415. {
  1416. PLLTHREADSTATE plts;
  1417. BOOL fExclusive = fl & VIFL_CAPTURED;
  1418. BOOL fNoWinkey = fl & VIFL_NOWINKEY;
  1419. HRESULT hres = S_OK;
  1420. EnterProc(CEm_LL_Acquire, (_ "puuu", this, fAcquire, fExclusive, ilts));
  1421. AssertF(this->dwSignature == CEM_SIGNATURE);
  1422. AssertF(ilts==LLTS_KBD || ilts==LLTS_MSE);
  1423. #ifdef USE_WM_INPUT
  1424. g_fFromKbdMse = fAcquire ? TRUE : FALSE;
  1425. ResetEvent( g_hEventAcquire );
  1426. #endif
  1427. hres = CEm_GetWorkerThread(this, &plts);
  1428. if (SUCCEEDED(hres)) {
  1429. AssertF( plts->rglhs[ilts].cHook >= plts->rglhs[ilts].cExcl );
  1430. #ifdef USE_WM_INPUT
  1431. if( g_fRawInput && !g_hwndThread) {
  1432. DWORD dwRc;
  1433. dwRc = WaitForSingleObject(g_hEventAcquire, INFINITE);
  1434. }
  1435. #endif
  1436. if (fAcquire) {
  1437. InterlockedIncrement(&plts->rglhs[ilts].cHook);
  1438. if (fExclusive) {
  1439. InterlockedIncrement(&plts->rglhs[ilts].cExcl);
  1440. }
  1441. #ifdef USE_WM_INPUT
  1442. if( g_hwndThread ) {
  1443. if( fExclusive ) {
  1444. hres = CDIRaw_RegisterRawInputDevice(1-ilts, DIRAW_EXCL, g_hwndThread);
  1445. }
  1446. else if( fNoWinkey ) {
  1447. AssertF( ilts == 0 );
  1448. if( ilts == 0 ) {
  1449. hres = CDIRaw_RegisterRawInputDevice(1-ilts, DIRAW_NOHOTKEYS, g_hwndThread);
  1450. } else {
  1451. hres = E_FAIL;
  1452. }
  1453. }
  1454. else {
  1455. hres = CDIRaw_RegisterRawInputDevice(1-ilts, DIRAW_NONEXCL, g_hwndThread);
  1456. }
  1457. if(FAILED(hres)) {
  1458. hres = S_FALSE;
  1459. g_fRawInput = FALSE;
  1460. RPF("CEm_LL_Acquire: RegisterRawInput failed.");
  1461. }
  1462. }
  1463. #endif
  1464. } else { /* Remove the hook */
  1465. AssertF(plts->cRef);
  1466. if (fExclusive) {
  1467. InterlockedDecrement(&plts->rglhs[ilts].cExcl);
  1468. }
  1469. InterlockedDecrement(&plts->rglhs[ilts].cHook);
  1470. #ifdef USE_WM_INPUT
  1471. if( g_fRawInput ) {
  1472. CDIRaw_UnregisterRawInputDevice(1-ilts, g_hwndThread);
  1473. if( plts->rglhs[ilts].cHook ) {
  1474. CDIRaw_RegisterRawInputDevice(1-ilts, 0, g_hwndThread);
  1475. }
  1476. }
  1477. #endif
  1478. }
  1479. NudgeWorkerThread(plts->idThread);
  1480. // tell CEm_LL_ThreadProc that acquire finished.
  1481. #ifdef USE_WM_INPUT
  1482. SetEvent( g_hEventThread );
  1483. #endif
  1484. }
  1485. ExitOleProc();
  1486. return hres;
  1487. }
  1488. #endif /* USE_SLOW_LL_HOOKS */
  1489. /*****************************************************************************
  1490. *
  1491. * Joystick emulation
  1492. *
  1493. *****************************************************************************/
  1494. /*****************************************************************************
  1495. *
  1496. * @doc INTERNAL
  1497. *
  1498. * @func HRESULT | CEm_Joy_Acquire |
  1499. *
  1500. * Acquire a joystick. Nothing happens.
  1501. *
  1502. * @parm PEM | pem |
  1503. *
  1504. * Device being acquired.
  1505. *
  1506. *****************************************************************************/
  1507. STDMETHODIMP
  1508. CEm_Joy_Acquire(PEM this, BOOL fAcquire)
  1509. {
  1510. AssertF(this->dwSignature == CEM_SIGNATURE);
  1511. return S_OK;
  1512. }
  1513. /*****************************************************************************
  1514. *
  1515. * Joystick globals
  1516. *
  1517. * Since we don't use joystick emulation by default, we allocate
  1518. * the emulation variables dynamically so we don't blow a page
  1519. * of memory on them.
  1520. *
  1521. *****************************************************************************/
  1522. typedef struct JOYEMVARS {
  1523. ED rged[cJoyMax];
  1524. DIJOYSTATE2 rgjs2[cJoyMax];
  1525. } JOYEMVARS, *PJOYEMVARS;
  1526. static PJOYEMVARS s_pjev;
  1527. /*****************************************************************************
  1528. *
  1529. * @doc INTERNAL
  1530. *
  1531. * @func HRESULT | CEm_Joy_CreateInstance |
  1532. *
  1533. * Create a joystick thing.
  1534. *
  1535. * @parm PVXDDEVICEFORMAT | pdevf |
  1536. *
  1537. * What the object should look like.
  1538. *
  1539. * @parm PVXDINSTANCE * | ppviOut |
  1540. *
  1541. * The answer goes here.
  1542. *
  1543. *****************************************************************************/
  1544. #define OBJAT(T, v) (*(T *)(v))
  1545. #define PUN(T, v) OBJAT(T, &(v))
  1546. HRESULT INTERNAL
  1547. CEm_Joy_CreateInstance(PVXDDEVICEFORMAT pdevf, PVXDINSTANCE *ppviOut)
  1548. {
  1549. HRESULT hres;
  1550. DllEnterCrit();
  1551. if (s_pjev == 0) {
  1552. DWORD uiJoy;
  1553. hres = AllocCbPpv(cbX(JOYEMVARS), &s_pjev);
  1554. if (SUCCEEDED(hres)) {
  1555. for (uiJoy = 0; uiJoy < cJoyMax; uiJoy++) {
  1556. PUN(PV, s_pjev->rged[uiJoy].pState) = &s_pjev->rgjs2[uiJoy];
  1557. s_pjev->rged[uiJoy].Acquire = CEm_Joy_Acquire;
  1558. s_pjev->rged[uiJoy].cbData = cbX(s_pjev->rgjs2[uiJoy]);
  1559. s_pjev->rged[uiJoy].cRef = 0x0;
  1560. }
  1561. }
  1562. } else {
  1563. hres = S_OK;
  1564. }
  1565. DllLeaveCrit();
  1566. if (SUCCEEDED(hres)) {
  1567. hres = CEm_CreateInstance(pdevf, ppviOut,
  1568. &s_pjev->rged[pdevf->dwExtra]);
  1569. }
  1570. return hres;
  1571. }
  1572. /*****************************************************************************
  1573. *
  1574. * @doc INTERNAL
  1575. *
  1576. * @func HRESULT | CEm_Joy_Ping |
  1577. *
  1578. * Read data from the joystick.
  1579. *
  1580. * @parm PVXDINSTANCE * | ppvi |
  1581. *
  1582. * Information about the gizmo being mangled.
  1583. *
  1584. *****************************************************************************/
  1585. HRESULT INTERNAL
  1586. CEm_Joy_Ping(PVXDINSTANCE *ppvi)
  1587. {
  1588. HRESULT hres;
  1589. JOYINFOEX ji;
  1590. MMRESULT mmrc;
  1591. PEM this = _thisPvNm(*ppvi, vi);
  1592. AssertF(this->dwSignature == CEM_SIGNATURE);
  1593. ji.dwSize = cbX(ji);
  1594. ji.dwFlags = JOY_RETURNALL + JOY_RETURNRAWDATA;
  1595. ji.dwPOV = JOY_POVCENTERED; /* joyGetPosEx forgets to set this */
  1596. mmrc = joyGetPosEx((DWORD)(UINT_PTR)this->dwExtra, &ji);
  1597. if (mmrc == JOYERR_NOERROR) {
  1598. DIJOYSTATE2 js;
  1599. UINT uiButtons;
  1600. ZeroX(js); /* Wipe out the bogus things */
  1601. js.lX = ji.dwXpos;
  1602. js.lY = ji.dwYpos;
  1603. js.lZ = ji.dwZpos;
  1604. js.lRz = ji.dwRpos;
  1605. js.rglSlider[0] = ji.dwUpos;
  1606. js.rglSlider[1] = ji.dwVpos;
  1607. js.rgdwPOV[0] = ji.dwPOV;
  1608. js.rgdwPOV[1] = JOY_POVCENTERED;
  1609. js.rgdwPOV[2] = JOY_POVCENTERED;
  1610. js.rgdwPOV[3] = JOY_POVCENTERED;
  1611. for (uiButtons = 0; uiButtons < 32; uiButtons++) {
  1612. if (ji.dwButtons & (1 << uiButtons)) {
  1613. js.rgbButtons[uiButtons] = 0x80;
  1614. }
  1615. }
  1616. CEm_AddState(&s_pjev->rged[this->dwExtra], &js, GetTickCount());
  1617. hres = S_OK;
  1618. } else {
  1619. CEm_ForceDeviceUnacquire(&s_pjev->rged[this->dwExtra],
  1620. FDUFL_UNPLUGGED);
  1621. hres = MAKE_HRESULT(SEVERITY_ERROR, FACILITY_WIN32,
  1622. ERROR_DEV_NOT_EXIST);
  1623. }
  1624. return hres;
  1625. }
  1626. HRESULT EXTERNAL
  1627. NotifyWorkerThreadPem(DWORD idThread, PEM pem)
  1628. {
  1629. PLLTHREADSTATE plts;
  1630. HRESULT hres;
  1631. hres = CEm_GetWorkerThread(pem, &plts);
  1632. if( SUCCEEDED(hres) )
  1633. {
  1634. AssertF(plts->idThread == idThread);
  1635. hres = NudgeWorkerThreadPem( plts, pem );
  1636. }
  1637. return hres;
  1638. }
  1639. HRESULT EXTERNAL
  1640. NudgeWorkerThreadPem( PLLTHREADSTATE plts, PEM pem )
  1641. {
  1642. //PREFIX: using uninitialized memory 'hres'
  1643. // Millen Bug#129163, 29345
  1644. HRESULT hres = S_FALSE;
  1645. plts->pemCheck = pem;
  1646. if( !PostWorkerMessage(plts->idThread, pem))
  1647. {
  1648. SquirtSqflPtszV(sqfl | sqflBenign,
  1649. TEXT("NudgeWorkerThreadPem: PostThreadMessage Failed with error %d"),
  1650. GetLastError() );
  1651. hres = S_FALSE;
  1652. }
  1653. else if( pem )
  1654. {
  1655. DWORD dwRc;
  1656. SquirtSqflPtszV(sqfl | sqflVerbose,
  1657. TEXT("NudgeWorkerThreadPem: PostThreadMessage SUCCEEDED, waiting for event ... "));
  1658. /*
  1659. * According to a comment in CEm_LL_ThreadProc Win95 may
  1660. * fail with an invalid parameter error, so if it does,
  1661. * keep trying. (Assume no valid case will occur.)
  1662. */
  1663. do
  1664. {
  1665. dwRc = WaitForMultipleObjects( 2, &plts->hThread, FALSE, INFINITE);
  1666. } while ( ( dwRc == WAIT_FAILED ) && ( GetLastError() == ERROR_INVALID_PARAMETER ) );
  1667. switch( dwRc )
  1668. {
  1669. case WAIT_OBJECT_0:
  1670. SquirtSqflPtszV(sqfl | sqflBenign,
  1671. TEXT("NotifyWorkerThreadPem: Not expecting response from dead worker thread") );
  1672. hres = S_FALSE;
  1673. break;
  1674. case WAIT_OBJECT_0 + 1:
  1675. /*
  1676. * The worker thread responded OK
  1677. */
  1678. hres = S_OK;
  1679. AssertF(plts->pemCheck == NULL );
  1680. break;
  1681. default:
  1682. SquirtSqflPtszV(sqfl | sqflError,
  1683. TEXT("NotifyWorkerThreadPem: WaitForMultipleObjects returned 0x%08x with LastError %d"),
  1684. dwRc, GetLastError() );
  1685. hres = E_FAIL;
  1686. break;
  1687. }
  1688. }
  1689. return hres;
  1690. }