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.

1361 lines
39 KiB

  1. /*****************************************************************************
  2. *
  3. * DInput.c
  4. *
  5. * Copyright (c) 1996 - 2000 Microsoft Corporation. All Rights Reserved.
  6. *
  7. * Abstract:
  8. *
  9. *
  10. *
  11. * Contents:
  12. *
  13. * DirectInput8Create()
  14. * DllGetClassObject()
  15. * DllCanUnloadNow()
  16. * DllMain()
  17. *
  18. *****************************************************************************/
  19. #include "dinputpr.h"
  20. /*****************************************************************************
  21. *
  22. * The sqiffle for this file.
  23. *
  24. *****************************************************************************/
  25. #define sqfl sqflDll
  26. /***************************************************************************
  27. *
  28. * @doc INTERNAL
  29. *
  30. * @topic The DirectInput synchronization hierarchy |
  31. *
  32. * Extreme caution must be exercised to ensure that the synchronization
  33. * hierarchy is preserved. Failure to observe these rules will result
  34. * in a deadlock.
  35. *
  36. * @ex
  37. *
  38. * In the following list, locks must be taken in the order specified.
  39. * Furthermore, the Dll critical section and the cross-process mutexes
  40. * may never be taken simultaneously. (They should be considered
  41. * to be at the bottom of the hierarchy.)
  42. *
  43. * |
  44. *
  45. * DirectInputEffect
  46. * DirectInputDevice
  47. * Dll critical section
  48. * The cross-process global mutex
  49. * The cross-process joystick mutex
  50. *
  51. ***************************************************************************/
  52. /*****************************************************************************
  53. *
  54. * @doc INTERNAL
  55. *
  56. * @global DWORD | g_cRef |
  57. *
  58. * DLL reference count.
  59. *
  60. * @global HINSTANCE | g_hinst |
  61. *
  62. * DLL instance handle.
  63. *
  64. * @global LONG | g_lLoadLibrary |
  65. *
  66. * Number of times we have been artificially <f LoadLibrary>'d
  67. * to prevent ourselves from being unloaded by a non-OLE
  68. * application. Actually, it's the number of times minus one,
  69. * so we can use the interlocked functions to tell whether
  70. * the first <f LoadLibrary> is happening or the last
  71. * <f FreeLibrary> is happening.
  72. *
  73. * We perform a physical <f LoadLibrary> or <f FreeLibrary>
  74. * only on the transition, so as to avoid overflowing the
  75. * counter in KERNEL32.
  76. *
  77. * @global HANDLE | g_hVxD |
  78. *
  79. * Handle to VxD, if available. Win9x only!
  80. *
  81. * @global OPENVXDHANDLE | OpenVxDHandle |
  82. *
  83. * Address of Win9x-only KERNEL32 entry point to convert
  84. * a process handle into a VxD handle. Win9x only!
  85. *
  86. * @global DWORD | g_dwLastBonusPoll |
  87. *
  88. * Last time a bonus poll was made to tickle the SideWinder
  89. * drivers. Win9x only!
  90. *
  91. * @global CRITICAL_SECTION | g_crstDll |
  92. *
  93. * Per-process critical section to protect process-global
  94. * variables.
  95. *
  96. * @global DWORD | g_flEmulation |
  97. *
  98. * Flags that describe what levels of forced emulation are
  99. * active.
  100. *
  101. * @global HHOOK | g_hhkLLHookCheck |
  102. *
  103. * Used only temporarily to test whether low-level hooks
  104. * are supported on the system.
  105. *
  106. * @global HANDLE | g_hmtxGlobal |
  107. *
  108. * System-global mutex that protects shared memory blocks
  109. * which describe device exclusive acquisition information.
  110. *
  111. * @global HANDLE | g_hfm |
  112. *
  113. * Handle to the file mapping that describes the shared
  114. * memory block. NT requires us to keep the handle open
  115. * so that the associated name remains in the namespace.
  116. *
  117. * @global PSHAREDOBJECTPAGE | g_psop |
  118. *
  119. * Pointer to the shared memory block itself.
  120. *
  121. * @global HANDLE | g_hmtxJoy |
  122. *
  123. * System-global mutex that protects shared memory blocks
  124. * which describe joystick effects.
  125. *
  126. * @global UINT | g_wmJoyChanged |
  127. *
  128. * Registered window message which is broadcast when joysticks
  129. * are reconfigured.
  130. *
  131. * @global LONG | g_lWheelGranularity |
  132. *
  133. * The wheel granularity. One hardware "click" of the mouse
  134. * wheel results in this much reported motion.
  135. *
  136. * @global int | g_cdtoMax |
  137. *
  138. * Total number of elements in the g_pdto array.
  139. *
  140. * @global int | g_cdto |
  141. *
  142. * Number of occupied elements in the g_pdto array.
  143. *
  144. * @global PDWORD | g_rgdwCRCTable |
  145. *
  146. * Pointer to the array of values used for CRC generation.
  147. *
  148. * @global PDEVICETOUSER | g_pdto |
  149. *
  150. * Pointer to the device to owner array.
  151. *
  152. * @global BOOL | g_fCritInited |
  153. *
  154. * True if g_crstDll has been initialized.
  155. *
  156. * @global DIAPPHACKS | g_AppHacks |
  157. *
  158. * Application hacks. Initialized to:
  159. * fReacquire FALSE
  160. * fNoSubClass FALSE
  161. * nMaxDeviceNameLength MAX_PATH
  162. *
  163. * @global DWORD | g_dwAppDate |
  164. *
  165. * Application link date stamp, used in generating application ID
  166. *
  167. * @global DWORD | g_dwAppFileLen |
  168. *
  169. * Application file length, used in generating application ID
  170. *
  171. * @global DWORD | g_dwLastMsgSent |
  172. *
  173. * Last message WPARAM broadcast in a g_wmDInputNotify message.
  174. * This is one of the DIMSGWP_* values or zero if no message has yet
  175. * been broadcast. This value only ever increases as applications
  176. * cannot become less identifed as they proceed. This value is used
  177. * as a test of
  178. *
  179. * @global UINT | g_wmDInputNotify |
  180. *
  181. * Registered window message which is broadcast when a change of
  182. * application status is detected.
  183. *
  184. *
  185. *****************************************************************************/
  186. DWORD g_cRef;
  187. HINSTANCE g_hinst;
  188. HINSTANCE g_hinstDbg;
  189. LONG g_lLoadLibrary = -1;
  190. #ifndef WINNT
  191. HANDLE g_hVxD = INVALID_HANDLE_VALUE;
  192. OPENVXDHANDLE _OpenVxDHandle;
  193. DWORD g_dwLastBonusPoll;
  194. #endif
  195. CRITICAL_SECTION g_crstDll;
  196. DWORD g_flEmulation;
  197. LPDWORD g_pdwSequence;
  198. #ifdef USE_SLOW_LL_HOOKS
  199. HHOOK g_hhkLLHookCheck;
  200. #endif
  201. HANDLE g_hmtxGlobal;
  202. HANDLE g_hfm;
  203. struct SHAREDOBJECTPAGE *g_psop;
  204. HANDLE g_hmtxJoy;
  205. UINT g_wmJoyChanged;
  206. LONG g_lWheelGranularity;
  207. int g_cdtoMax;
  208. int g_cdto;
  209. struct _DEVICETOUSER *g_pdto;
  210. PDWORD g_rgdwCRCTable;
  211. BOOL g_fCritInited;
  212. #ifdef WORKER_THREAD
  213. MSGWAITFORMULTIPLEOBJECTSEX _MsgWaitForMultipleObjectsEx =
  214. FakeMsgWaitForMultipleObjectsEx;
  215. #endif
  216. CANCELIO _CancelIO = FakeCancelIO;
  217. #ifdef XDEBUG
  218. TRYENTERCRITICALSECTION _TryEnterCritSec = FakeTryEnterCriticalSection;
  219. int g_cCrit = -1;
  220. UINT g_thidCrit;
  221. HANDLE g_thhandleCrit;
  222. #endif
  223. #ifdef DEBUG
  224. TCHAR g_tszLogFile[MAX_PATH];
  225. #endif
  226. DIAPPHACKS g_AppHacks = {FALSE,FALSE,MAX_PATH};
  227. DWORD g_dwAppDate;
  228. DWORD g_dwAppFileLen;
  229. DWORD g_dwLastMsgSent;
  230. UINT g_wmDInputNotify;
  231. BOOL g_fRawInput;
  232. #ifdef USE_WM_INPUT
  233. HWND g_hwndThread;
  234. HANDLE g_hEventAcquire;
  235. HANDLE g_hEventThread;
  236. HANDLE g_hEventHid;
  237. #endif
  238. /*****************************************************************************
  239. *
  240. * @doc INTERNAL
  241. *
  242. * @func void | DllEnterCrit |
  243. *
  244. * Take the DLL critical section.
  245. *
  246. * The DLL critical section is the lowest level critical section.
  247. * You may not attempt to acquire any other critical sections or
  248. * yield while the DLL critical section is held. Failure to
  249. * comply is a violation of the semaphore hierarchy and will
  250. * lead to deadlocks.
  251. *
  252. *****************************************************************************/
  253. void EXTERNAL
  254. DllEnterCrit_(LPCTSTR lptszFile, UINT line)
  255. {
  256. #ifdef XDEBUG
  257. if ( ! _TryEnterCritSec(&g_crstDll) )
  258. {
  259. SquirtSqflPtszV(sqflCrit, TEXT("Dll CritSec blocked @%s,%d"), lptszFile, line);
  260. EnterCriticalSection(&g_crstDll);
  261. }
  262. if (++g_cCrit == 0)
  263. {
  264. g_thidCrit = GetCurrentThreadId();
  265. g_thhandleCrit = GetCurrentThread();
  266. SquirtSqflPtszV(sqflCrit, TEXT("Dll CritSec Entered @%s,%d"), lptszFile, line);
  267. }
  268. AssertF(g_thidCrit == GetCurrentThreadId());
  269. #else
  270. EnterCriticalSection(&g_crstDll);
  271. #endif
  272. }
  273. /*****************************************************************************
  274. *
  275. * @doc INTERNAL
  276. *
  277. * @func BOOL | IsThreadActive |
  278. *
  279. * Check if the thread is still active.
  280. *
  281. *****************************************************************************/
  282. BOOL IsThreadActive( HANDLE hThread )
  283. {
  284. DWORD dwExitCode = 0;
  285. return (NULL != hThread
  286. && GetExitCodeThread(hThread, &dwExitCode)
  287. && STILL_ACTIVE == dwExitCode
  288. );
  289. }
  290. /*****************************************************************************
  291. *
  292. * @doc INTERNAL
  293. *
  294. * @func void | DllLeaveCrit |
  295. *
  296. * Leave the DLL critical section.
  297. *
  298. *****************************************************************************/
  299. void EXTERNAL
  300. DllLeaveCrit_(LPCTSTR lptszFile, UINT line)
  301. {
  302. #ifdef XDEBUG
  303. if( IsThreadActive(g_thhandleCrit) ) {
  304. AssertF(g_thidCrit == GetCurrentThreadId());
  305. } else {
  306. SquirtSqflPtszV(sqflCrit, TEXT("Current thread has died."));
  307. }
  308. AssertF(g_cCrit >= 0);
  309. if (--g_cCrit < 0)
  310. {
  311. g_thidCrit = 0;
  312. }
  313. SquirtSqflPtszV(sqflCrit, TEXT("Dll CritSec Leaving @%s,%d"), lptszFile, line);
  314. #endif
  315. LeaveCriticalSection(&g_crstDll);
  316. }
  317. /*****************************************************************************
  318. *
  319. * @doc INTERNAL
  320. *
  321. * @func void | DllInCrit |
  322. *
  323. * Nonzero if we are in the DLL critical section.
  324. *
  325. *****************************************************************************/
  326. #ifdef XDEBUG
  327. BOOL INTERNAL
  328. DllInCrit(void)
  329. {
  330. return g_cCrit >= 0 && g_thidCrit == GetCurrentThreadId();
  331. }
  332. #endif
  333. /*****************************************************************************
  334. *
  335. * @doc INTERNAL
  336. *
  337. * @func void | DllAddRef |
  338. *
  339. * Increment the reference count on the DLL.
  340. *
  341. *****************************************************************************/
  342. void EXTERNAL
  343. DllAddRef(void)
  344. {
  345. InterlockedIncrement((LPLONG)&g_cRef);
  346. SquirtSqflPtszV(sqfl, TEXT("DllAddRef -> %d"), g_cRef);
  347. }
  348. /*****************************************************************************
  349. *
  350. * @doc INTERNAL
  351. *
  352. * @func void | DllRelease |
  353. *
  354. * Decrement the reference count on the DLL.
  355. *
  356. *****************************************************************************/
  357. void EXTERNAL
  358. DllRelease(void)
  359. {
  360. InterlockedDecrement((LPLONG)&g_cRef);
  361. SquirtSqflPtszV(sqfl, TEXT("DllRelease -> %d"), g_cRef);
  362. }
  363. /*****************************************************************************
  364. *
  365. * @doc INTERNAL
  366. *
  367. * @func BOOL | DllLoadLibrary |
  368. *
  369. * Increment the DLL load count.
  370. *
  371. * This is to prevent a non-OLE application from unloading us
  372. * while we still have windows subclassed.
  373. *
  374. *****************************************************************************/
  375. BOOL EXTERNAL
  376. DllLoadLibrary(void)
  377. {
  378. BOOL fRes = TRUE;
  379. AssertF(InCrit());
  380. if (InterlockedIncrement(&g_lLoadLibrary) == 0)
  381. {
  382. TCHAR tsz[MAX_PATH - 1];
  383. /*
  384. * See hresValidInstanceVer_ for an explanation of why
  385. * we need to pass cA() - 1 instead of cA().
  386. */
  387. if ( !GetModuleFileName(g_hinst, tsz, cA(tsz) - 1)
  388. || !LoadLibrary(tsz) )
  389. {
  390. /*
  391. * Restore the refcount.
  392. * There is no race condition here because we are always called
  393. * InCrit so the refcount after the restore can only be the same
  394. * as it was when we entered. If this should change, we would
  395. * need to take extra precautions as two threads could try to
  396. * LoadLibrary at the same time. As only one would do the
  397. * physical load, there is no way to let the other know if the
  398. * load failed.
  399. */
  400. InterlockedDecrement(&g_lLoadLibrary);
  401. fRes = FALSE;
  402. RPF( "LoadLibrary( self ) failed!, le = %d", GetLastError() );
  403. }
  404. }
  405. SquirtSqflPtszV(sqfl, TEXT("DllLoadLibrary -> %d"), g_lLoadLibrary);
  406. return fRes;
  407. }
  408. /*****************************************************************************
  409. *
  410. * @doc INTERNAL
  411. *
  412. * @func void | DllFreeLibraryAndExitThread |
  413. *
  414. * Worker thread which frees the library in a less dangerous
  415. * (I'm loathe to say "safe") manner.
  416. *
  417. * ThreadProcs are prototyped to return a void but since the return
  418. * would follow some form of ExitThread, it will never be reached so
  419. * this function is declared to return void and cast.
  420. *
  421. * @parm LPVOID | pvContext |
  422. *
  423. * Unused context information.
  424. *
  425. *****************************************************************************/
  426. void INTERNAL
  427. DllFreeLibraryAndExitThread(LPVOID pvContext)
  428. {
  429. /*
  430. * Sleep for one extra second to make extra sure that the
  431. * DllFreeLibrary thread is out and gone.
  432. */
  433. SleepEx(1000, FALSE);
  434. FreeLibraryAndExitThread(g_hinst, 0);
  435. /*NOTREACHED*/
  436. }
  437. /*****************************************************************************
  438. *
  439. * @doc INTERNAL
  440. *
  441. * @func void | DllFreeLibrary |
  442. *
  443. * Decrement the DLL load count.
  444. *
  445. * This undoes a previous <f DllLoadLibrary>.
  446. *
  447. * We can't blindly do a <f FreeLibrary>, because we might
  448. * be freeing our last reference, and then we will die because
  449. * we won't exist when the <f FreeLibrary> returns.
  450. *
  451. * If we are in the wacky case, then we spin a low-priority
  452. * thread whose job is to free us. We create it at low priority
  453. * so it will lose the race with this thread, which is busy
  454. * getting out of the way.
  455. *
  456. *****************************************************************************/
  457. void EXTERNAL
  458. DllFreeLibrary(void)
  459. {
  460. if (InterlockedDecrement(&g_lLoadLibrary) < 0)
  461. {
  462. if (g_cRef)
  463. {
  464. /*
  465. * There are other references to us, so we can just
  466. * go away quietly.
  467. */
  468. FreeLibrary(g_hinst);
  469. } else
  470. {
  471. /*
  472. * This is the last reference, so we need to create a
  473. * worker thread which will call <f FreeLibraryAndExitThread>.
  474. */
  475. DWORD thid;
  476. HANDLE hth;
  477. hth = CreateThread(0, 0, (LPTHREAD_START_ROUTINE)DllFreeLibraryAndExitThread,
  478. 0, CREATE_SUSPENDED, &thid);
  479. if (hth)
  480. {
  481. SetThreadPriority(hth, THREAD_PRIORITY_IDLE);
  482. ResumeThread(hth);
  483. CloseHandle(hth);
  484. }
  485. }
  486. }
  487. SquirtSqflPtszV(sqfl, TEXT("DllFreeLibrary -> %d"), g_lLoadLibrary);
  488. }
  489. /*****************************************************************************
  490. *
  491. * @doc INTERNAL
  492. *
  493. * @func HRESULT | DllGetClassObject |
  494. *
  495. * Create an <i IClassFactory> instance for this DLL.
  496. *
  497. * @parm REFCLSID | rclsid |
  498. *
  499. * The object being requested.
  500. *
  501. * @parm RIID | riid |
  502. *
  503. * The desired interface on the object.
  504. *
  505. * @parm PPV | ppvOut |
  506. *
  507. * Output pointer.
  508. *
  509. * @comm
  510. * The artificial refcount inside <f DllClassObject> helps
  511. * to avoid the race condition described in <f DllCanUnloadNow>.
  512. * It's not perfect, but it makes the race window smaller.
  513. *
  514. *****************************************************************************/
  515. #pragma BEGIN_CONST_DATA
  516. #ifdef DEMONSTRATION_FFDRIVER
  517. /*
  518. * Build the fake force feedback driver for internal testing.
  519. */
  520. GUID CLSID_EffectDriver = {
  521. 0x25E609E2,0xB259,0x11CF,0xBF,0xC7,0x44,0x45,0x53,0x54,0x00,0x00
  522. };
  523. #endif
  524. CLSIDMAP c_rgclsidmap[cclsidmap] = {
  525. { &CLSID_DirectInput8, CDIObj_New, IDS_DIRECTINPUT8,},
  526. { &CLSID_DirectInputDevice8, CDIDev_New, IDS_DIRECTINPUTDEVICE8,},
  527. #ifdef DEMONSTRATION_FFDRIVER
  528. { &CLSID_EffectDriver, CJoyEff_New, 0,},
  529. #endif
  530. };
  531. #pragma END_CONST_DATA
  532. STDAPI
  533. DllGetClassObject(REFCLSID rclsid, RIID riid, PPV ppvObj)
  534. {
  535. HRESULT hres;
  536. UINT iclsidmap;
  537. EnterProcR(DllGetClassObject, (_ "G", rclsid));
  538. if ( g_fCritInited )
  539. {
  540. DllAddRef();
  541. for (iclsidmap = 0; iclsidmap < cA(c_rgclsidmap); iclsidmap++)
  542. {
  543. if (IsEqualIID(rclsid, c_rgclsidmap[iclsidmap].rclsid))
  544. {
  545. hres = CDIFactory_New(c_rgclsidmap[iclsidmap].pfnCreate,
  546. riid, ppvObj);
  547. goto done;
  548. }
  549. }
  550. SquirtSqflPtszV(sqfl | sqflError, TEXT("%S: Wrong CLSID"), s_szProc);
  551. *ppvObj = 0;
  552. hres = CLASS_E_CLASSNOTAVAILABLE;
  553. done:;
  554. ExitOleProcPpv(ppvObj);
  555. DllRelease();
  556. } else
  557. {
  558. hres = E_OUTOFMEMORY;
  559. RPF( "Failing DllGetClassObject due to lack of DLL critical section" );
  560. }
  561. return hres;
  562. }
  563. /*****************************************************************************
  564. *
  565. * @doc INTERNAL
  566. *
  567. * @func HRESULT | DllCanUnloadNow |
  568. *
  569. * Determine whether the DLL has any outstanding interfaces.
  570. *
  571. * There is an unavoidable race condition between
  572. * <f DllCanUnloadNow> and the creation of a new
  573. * <i IClassFactory>: Between the time we return from
  574. * <f DllCanUnloaDNow> and the caller inspects the value,
  575. * another thread in the same process may decide to call
  576. * <f DllGetClassObject>, thus suddenly creating an object
  577. * in this DLL when there previously was none.
  578. *
  579. * It is the caller's responsibility to prepare for this
  580. * possibility; there is nothing we can do about it.
  581. *
  582. * @returns
  583. *
  584. * Returns <c S_OK> if the DLL can unload, <c S_FALSE> if
  585. * it is not safe to unload.
  586. *
  587. *****************************************************************************/
  588. STDMETHODIMP
  589. DllCanUnloadNow(void)
  590. {
  591. HRESULT hres;
  592. #ifdef DEBUG
  593. if (IsSqflSet(sqfl))
  594. {
  595. SquirtSqflPtszV(sqfl, TEXT("DllCanUnloadNow() - g_cRef = %d"), g_cRef);
  596. Common_DumpObjects();
  597. }
  598. #endif
  599. hres = g_cRef ? S_FALSE : S_OK;
  600. return hres;
  601. }
  602. #ifdef USE_SLOW_LL_HOOKS
  603. /*****************************************************************************
  604. *
  605. * @doc INTERNAL
  606. *
  607. * @func LRESULT | DllLlHookTest |
  608. *
  609. * Tiny hook procedure used to test whether LL hooks are
  610. * supported by the operating system.
  611. *
  612. * This function is almost never called. We install the
  613. * hook and immediately remove it. The only time it
  614. * manages to get called is if the user moves the mouse
  615. * or presses a key during the microsecond that we exist.
  616. *
  617. * Wait! In fact, this function is *never* called. We
  618. * do not process messages at any point the hook is installed,
  619. * so in fact nothing happens at all.
  620. *
  621. * @parm int | nCode |
  622. *
  623. * Hook code.
  624. *
  625. * @parm WPARAM | wp |
  626. *
  627. * Hook-specific code.
  628. *
  629. * @parm LPARAM | lp |
  630. *
  631. * Hook-specific code.
  632. *
  633. * @returns
  634. *
  635. * Always chains to previous hook.
  636. *
  637. *****************************************************************************/
  638. LRESULT CALLBACK
  639. DllLlHookTest(int nCode, WPARAM wp, LPARAM lp)
  640. {
  641. /*
  642. * Note that there is not actually anything wrong here,
  643. * but it is a theoretically impossible condition, so I want to
  644. * know when it happens.
  645. */
  646. AssertF(!TEXT("DllLlHookTest - Unexpected hook"));
  647. return CallNextHookEx(g_hhkLLHookCheck, nCode, wp, lp);
  648. }
  649. #endif
  650. /*****************************************************************************
  651. *
  652. * @doc INTERNAL
  653. *
  654. * @func void | DllProcessAttach |
  655. *
  656. * Called when the DLL is loaded.
  657. *
  658. * We are not interested in thread attaches and detaches,
  659. * so we disable thread notifications for performance reasons.
  660. *
  661. *****************************************************************************/
  662. #pragma BEGIN_CONST_DATA
  663. TCHAR c_tszKernel32[] = TEXT("KERNEL32");
  664. #ifndef WINNT
  665. char c_szOpenVxDHandle[] = "OpenVxDHandle";
  666. #endif
  667. void INTERNAL
  668. DllProcessAttach(void)
  669. {
  670. HINSTANCE hinstK32;
  671. #ifdef DEBUG
  672. WriteProfileString(0, 0, 0); /* Flush the win.ini cache */
  673. Sqfl_Init();
  674. GetProfileString(TEXT("DEBUG"), TEXT("LogFile"), TEXT(""),
  675. g_tszLogFile, cA(g_tszLogFile));
  676. SquirtSqflPtszV(sqfl, TEXT("LoadDll - DInput"));
  677. SquirtSqflPtszV(sqfl, TEXT("Version %x"), DIRECTINPUT_VERSION );
  678. SquirtSqflPtszV(sqfl, TEXT("Built %s at %s\n"), TEXT(__DATE__), TEXT(__TIME__) );
  679. #endif
  680. /*
  681. * Disabling thread library calls is important so that
  682. * we don't deadlock with ourselves over the critical
  683. * section when we spin up the worker thread to handle
  684. * low-level hooks.
  685. */
  686. DisableThreadLibraryCalls(g_hinst);
  687. g_fCritInited = fInitializeCriticalSection(&g_crstDll);
  688. if ( !g_fCritInited )
  689. {
  690. RPF( "Failed to initialize DLL critical section" );
  691. }
  692. hinstK32 = GetModuleHandle( c_tszKernel32 );
  693. {
  694. CANCELIO tmp;
  695. tmp = (CANCELIO)GetProcAddress(hinstK32, "CancelIo");
  696. if (tmp)
  697. {
  698. _CancelIO = tmp;
  699. } else
  700. {
  701. AssertF(_CancelIO == FakeCancelIO);
  702. }
  703. }
  704. #ifdef WINNT
  705. /*
  706. * For now, only look for TryEnterCriticalSection on NT as it is not
  707. * implemented on 9x but the stub is annoying on 98 with dbg kernels.
  708. */
  709. {
  710. #ifdef XDEBUG
  711. TRYENTERCRITICALSECTION tmpCrt;
  712. tmpCrt = (TRYENTERCRITICALSECTION)GetProcAddress(hinstK32, "TryEnterCriticalSection");
  713. if (tmpCrt)
  714. {
  715. _TryEnterCritSec = tmpCrt;
  716. } else
  717. {
  718. AssertF(_TryEnterCritSec == FakeTryEnterCriticalSection);
  719. }
  720. #endif
  721. }
  722. #else
  723. _OpenVxDHandle = (OPENVXDHANDLE)GetProcAddress(hinstK32, c_szOpenVxDHandle);
  724. #endif
  725. #ifdef WORKER_THREAD
  726. {
  727. MSGWAITFORMULTIPLEOBJECTSEX tmp;
  728. tmp = (MSGWAITFORMULTIPLEOBJECTSEX)
  729. GetProcAddress(GetModuleHandle(TEXT("USER32")),
  730. "MsgWaitForMultipleObjectsEx");
  731. if (tmp)
  732. {
  733. _MsgWaitForMultipleObjectsEx = tmp;
  734. } else
  735. {
  736. AssertF(_MsgWaitForMultipleObjectsEx ==
  737. FakeMsgWaitForMultipleObjectsEx);
  738. }
  739. }
  740. /*
  741. * We cannot initialize g_hmtxGlobal here, because we
  742. * have no way to report the error back to the caller.
  743. */
  744. #endif
  745. #ifdef USE_SLOW_LL_HOOKS
  746. /*
  747. * Determine whether low-level input hooks are supported.
  748. */
  749. g_hhkLLHookCheck = SetWindowsHookEx(WH_MOUSE_LL, DllLlHookTest,
  750. g_hinst, 0);
  751. if (g_hhkLLHookCheck)
  752. {
  753. UnhookWindowsHookEx(g_hhkLLHookCheck);
  754. }
  755. #endif
  756. /*
  757. * Warning! Do not call ExtDll_Init during PROCESS_ATTACH!
  758. */
  759. g_wmJoyChanged = RegisterWindowMessage(MSGSTR_JOYCHANGED);
  760. g_wmDInputNotify = RegisterWindowMessage(DIRECTINPUT_NOTIFICATION_MSGSTRING);
  761. #ifdef USE_WM_INPUT
  762. g_fRawInput = (DIGetOSVersion() == WINWH_OS);
  763. if( g_fRawInput ) {
  764. g_hEventAcquire = CreateEvent(0x0, 0, 0, 0x0);
  765. g_hEventThread = CreateEvent(0x0, 0, 0, 0x0);
  766. g_hEventHid = CreateEvent(0x0, 0, 0, 0x0);
  767. }
  768. #endif
  769. }
  770. /*****************************************************************************
  771. *
  772. * @doc INTERNAL
  773. *
  774. * @func void | DllProcessDetach |
  775. *
  776. * Called when the DLL is unloaded.
  777. *
  778. *****************************************************************************/
  779. void INTERNAL
  780. DllProcessDetach(void)
  781. {
  782. extern PLLTHREADSTATE g_plts;
  783. SquirtSqflPtszV(sqfl | sqflMajor,
  784. TEXT("DINPUT8: ProcessDetach. PID:%08x, TID:%08x."),
  785. GetCurrentProcessId(), GetCurrentThreadId() );
  786. #ifdef USE_WM_INPUT
  787. if (g_hEventAcquire)
  788. {
  789. CloseHandle(g_hEventAcquire);
  790. }
  791. if (g_hEventThread)
  792. {
  793. CloseHandle(g_hEventThread);
  794. }
  795. if (g_hEventHid)
  796. {
  797. CloseHandle(g_hEventHid);
  798. }
  799. #endif
  800. #ifndef WINNT
  801. if (g_hVxD != INVALID_HANDLE_VALUE)
  802. {
  803. CloseHandle(g_hVxD);
  804. }
  805. #endif
  806. if (g_psop)
  807. {
  808. UnmapViewOfFile(g_psop);
  809. }
  810. if (g_hfm)
  811. {
  812. CloseHandle(g_hfm);
  813. }
  814. if (g_hmtxGlobal)
  815. {
  816. CloseHandle(g_hmtxGlobal);
  817. }
  818. if (g_hmtxJoy)
  819. {
  820. CloseHandle(g_hmtxJoy);
  821. }
  822. FreePpv( &g_pdto );
  823. FreePpv( &g_rgdwCRCTable );
  824. ExtDll_Term();
  825. if ( g_fCritInited )
  826. {
  827. DeleteCriticalSection(&g_crstDll);
  828. }
  829. if ( g_hinstDbg )
  830. {
  831. FreeLibrary(g_hinstDbg);
  832. }
  833. /*
  834. * Output message last so that anything that follows is known to be bad.
  835. */
  836. if (g_cRef )
  837. {
  838. RPF("unloaded before all objects released. (cRef:%d)\r\n", g_cRef);
  839. }
  840. }
  841. /*****************************************************************************
  842. *
  843. * @doc INTERNAL
  844. *
  845. * @func BOOL | DllMain |
  846. *
  847. * Called to notify the DLL about various things that can happen.
  848. *
  849. * @parm HINSTANCE | hinst |
  850. *
  851. * The instance handle of this DLL.
  852. *
  853. * @parm DWORD | dwReason |
  854. *
  855. * Notification code.
  856. *
  857. * @parm LPVOID | lpReserved |
  858. *
  859. * Not used.
  860. *
  861. * @returns
  862. *
  863. * Returns <c TRUE> to allow the DLL to load.
  864. *
  865. *****************************************************************************/
  866. BOOL APIENTRY
  867. DllMain(HINSTANCE hinst, DWORD dwReason, LPVOID lpReserved)
  868. {
  869. switch (dwReason)
  870. {
  871. case DLL_PROCESS_ATTACH:
  872. g_hinst = hinst;
  873. DllProcessAttach();
  874. SquirtSqflPtszV(sqfl | sqflMajor,
  875. TEXT("DINPUT8: DLL_PROCESS_ATTACH hinst=0x%p, lpReserved=0x%p"),
  876. hinst, lpReserved );
  877. break;
  878. case DLL_PROCESS_DETACH:
  879. DllProcessDetach();
  880. SquirtSqflPtszV(sqfl | sqflMajor,
  881. TEXT("DINPUT8: DLL_PROCESS_DETACH hinst=0x%p, lpReserved=0x%p"),
  882. hinst, lpReserved );
  883. break;
  884. }
  885. return 1;
  886. }
  887. /*****************************************************************************
  888. *
  889. * @doc EXTERNAL
  890. *
  891. * @topic Definitions and Ground Rules |
  892. *
  893. * The phrase "undefined behavior" refers to behavior which is not
  894. * covered by this specification due to violations of a constraint.
  895. * No constraint is imposed by the specification as to the result of
  896. * undefined behavior. It may range from silently ignoring the
  897. * situation to a complete system crash.
  898. *
  899. * If this specification does not prescribe a behavior for a particular
  900. * situation, the behavior is "undefined".
  901. *
  902. * The phrase "It is an error" indicates that failure to comply
  903. * is a violation of the DirectInput specification and results
  904. * in "undefined behavior".
  905. *
  906. * The word "shall" is to be interpreted as a
  907. * requirement on an application; conversely, "shall not" is to be
  908. * interpreted as a prohibition. Violation of a requirement or
  909. * prohibition "is an error".
  910. *
  911. * The word "may" indicates that the indicated behavior is possible
  912. * but is not required.
  913. *
  914. * The word "should" indicates a strong suggestion.
  915. * If the application violates a "should" requirement, then DirectInput
  916. * "may" fail the operation.
  917. *
  918. * Pointer parameters to functions "shall not" be NULL unless explicitly
  919. * documented as OPTIONAL. "It is an error" to pass a pointer to an object
  920. * of the wrong type, to an object which is not allocated, or to an
  921. * object which has been freed or <f Release>d.
  922. *
  923. * Unless indicated otherwise,
  924. * an object pointed to by a pointer parameter documented as an
  925. * IN parameter "shall not" be modified by the called procedure.
  926. * Conversely, a pointer parameter documented
  927. * as an OUT parameter "shall" point to a modifiable object.
  928. *
  929. * When a bitmask of flags is defined, all bits not defined by this
  930. * specification are reserved. Applications "shall not" set reserved
  931. * bits and "shall" ignore reserved bits should they be received.
  932. *
  933. *****************************************************************************/
  934. /*****************************************************************************
  935. *
  936. * @doc EXTERNAL
  937. *
  938. * @topic Initialization and Versions |
  939. *
  940. * In several places, DirectInput requires you to pass an instance
  941. * handle and a version number.
  942. *
  943. * The instance handle must correspond to the application or
  944. * DLL that is initializing the DirectInput object.
  945. *
  946. * DirectInput uses this value to determine whether the
  947. * application or DLL has been certified and to establish
  948. * any special behaviors that may be necessary for
  949. * backwards-compatibility.
  950. *
  951. * It is an error for a DLL to pass the handle of the
  952. * parent application. For example, an ActiveX control
  953. * embedded in a web page which uses DirectInput must
  954. * pass its own instance handle and not the handle of the
  955. * web browser. This ensures that DirectInput recognizes
  956. * the control and can enable any special behaviors
  957. * for the control the behave properly.
  958. *
  959. * The version number parameter specifies which version of
  960. * DirectInput the DirectInput subsystem should emulate.
  961. *
  962. * Applications designed for the latest version of DirectInput
  963. * should pass the value <c DIRECTINPUT_VERSION> as defined
  964. * in dinput.h.
  965. *
  966. * Applications designed for previous versions of DirectInput
  967. * should pass a value corresponding to the version of
  968. * DirectInput they were designed for. For example, an
  969. * application that was designed to run on DirectInput 3.0
  970. * should pass a value of 0x0300.
  971. *
  972. * If you #define <c DIRECTINPUT_VERSION> to 0x0300 before
  973. * including the dinput.h header file, then the dinput.h
  974. * header file will generate DirectInput 3.0-compatible
  975. * structure definitions.
  976. *
  977. *****************************************************************************/
  978. /*****************************************************************************
  979. *
  980. * @doc INTERNAL
  981. *
  982. * @func HRESULT | DirectInputCreateHelper |
  983. *
  984. * This function creates a new DirectInput object
  985. * which supports the <i IDirectInput> COM interface.
  986. *
  987. * On success, the function returns a pointer to the new object in
  988. * *<p lplpDirectInput>.
  989. *
  990. * @parm IN HINSTANCE | hinst |
  991. *
  992. * Instance handle of the application or DLL that is creating
  993. * the DirectInput object.
  994. *
  995. * @parm DWORD | dwVersion |
  996. *
  997. * Version number of the dinput.h header file that was used.
  998. *
  999. * @parm OUT PPV | ppvObj |
  1000. * Points to where to return
  1001. * the pointer to the <i IDirectInput> interface, if successful.
  1002. *
  1003. * @parm IN LPUNKNOWN | punkOuter | Pointer to controlling unknown.
  1004. *
  1005. * @parm RIID | riid |
  1006. *
  1007. * The interface the application wants to create. This will
  1008. * be either <i IDirectInputA> or <i IDirectInputW>.
  1009. * If the object is aggregated, then this parameter is ignored.
  1010. *
  1011. * @returns
  1012. *
  1013. * Returns a COM error code. The following error codes are
  1014. * intended to be illustrative and not necessarily comprehensive.
  1015. *
  1016. * <c DI_OK> = <c S_OK>: The operation completed successfully.
  1017. *
  1018. * <c DIERR_INVALIDPARAM>
  1019. *
  1020. * <c DIERR_OUTOFMEMORY> = <c E_OUTOFMEMORY>:
  1021. * Out of memory.
  1022. *
  1023. *****************************************************************************/
  1024. STDMETHODIMP
  1025. DirectInputCreateHelper(HINSTANCE hinst, DWORD dwVer,
  1026. PPV ppvObj, PUNK punkOuter, RIID riid)
  1027. {
  1028. HRESULT hres;
  1029. EnterProc(DirectInputCreateHelper,
  1030. (_ "xxxG", hinst, dwVer, punkOuter, riid));
  1031. if (SUCCEEDED(hres = hresFullValidPcbOut(ppvObj, cbX(*ppvObj), 3)))
  1032. {
  1033. if( g_fCritInited )
  1034. {
  1035. LPVOID pvTry = NULL;
  1036. hres = CDIObj_New(punkOuter,
  1037. punkOuter ? &IID_IUnknown : riid, &pvTry);
  1038. if( SUCCEEDED( hres ) )
  1039. {
  1040. AhAppRegister( dwVer, 0x0 );
  1041. }
  1042. if (SUCCEEDED(hres) && punkOuter == 0)
  1043. {
  1044. LPDIRECTINPUT pdi = pvTry;
  1045. hres = pdi->lpVtbl->Initialize(pdi, hinst, dwVer);
  1046. if (SUCCEEDED(hres))
  1047. {
  1048. *ppvObj = pvTry;
  1049. } else
  1050. {
  1051. Invoke_Release(&pvTry);
  1052. *ppvObj = NULL;
  1053. }
  1054. }
  1055. } else
  1056. {
  1057. RPF( "Failing DirectInputCreate due to lack of DLL critical section" );
  1058. hres = E_OUTOFMEMORY;
  1059. }
  1060. }
  1061. ExitOleProcPpv(ppvObj);
  1062. return hres;
  1063. }
  1064. /*****************************************************************************
  1065. *
  1066. * @doc EXTERNAL
  1067. *
  1068. * @func HRESULT | DirectInput8Create |
  1069. *
  1070. * <bnew> This function creates a new DirectInput8 object
  1071. * which supports the <i IDirectInput8> COM interfaces. This function
  1072. * allows the app to pass an IID so it does not have to do an extra
  1073. * QI off some initial interface in order to obtain the one it
  1074. * really wanted.
  1075. *
  1076. * On success, the function returns a pointer to the new object in
  1077. * *<p ppvOut>.
  1078. * <enew>
  1079. *
  1080. * @parm IN HINSTANCE | hinst |
  1081. *
  1082. * Instance handle of the application or DLL that is creating
  1083. * the DirectInput object.
  1084. *
  1085. * See the section titled "Initialization and Versions"
  1086. * for more information.
  1087. *
  1088. * @parm DWORD | dwVersion |
  1089. *
  1090. * Version number of the dinput.h header file that was used.
  1091. *
  1092. * See the section titled "Initialization and Versions"
  1093. * for more information.
  1094. *
  1095. * @parm REFIID | riidtlf |
  1096. *
  1097. * The desired interface interface. Currently, valid values are
  1098. * IID_IDirectInput8A and IID_IDirectInput8W.
  1099. *
  1100. * @parm OUT LPVOID | *ppvOut |
  1101. *
  1102. * Points to where to return
  1103. * the pointer to the <i IDirectInput8> interface, if successful.
  1104. *
  1105. * @parm IN LPUNKNOWN | punkOuter | Pointer to controlling unknown
  1106. * for OLE aggregation, or 0 if the interface is not aggregated.
  1107. * Most callers will pass 0.
  1108. *
  1109. * Note that if aggregation is requested, the object returned
  1110. * in *<p lplpDirectInput> will be a pointer to an
  1111. * <i IUnknown> rather than an <i IDirectInput8>, as required
  1112. * by OLE aggregation.
  1113. *
  1114. * @returns
  1115. *
  1116. * Returns a COM error code. The following error codes are
  1117. * intended to be illustrative and not necessarily comprehensive.
  1118. *
  1119. * <c DI_OK> = <c S_OK>: The operation completed successfully.
  1120. *
  1121. * <c DIERR_INVALIDPARAM> = <c E_INVALIDARG>: The
  1122. * <p lplpDirectInput> parameter is not a valid pointer.
  1123. *
  1124. * <c DIERR_OUTOFMEMORY> = <c E_OUTOFMEMORY>:
  1125. * Out of memory.
  1126. *
  1127. * <c DIERR_DIERR_OLDDIRECTINPUTVERSION>: The application
  1128. * requires a newer version of DirectInput.
  1129. *
  1130. * <c DIERR_DIERR_BETADIRECTINPUTVERSION>: The application
  1131. * was written for an unsupported prerelease version
  1132. * of DirectInput.
  1133. *
  1134. * @comm Calling this function with <p punkOuter> = NULL
  1135. * is equivalent to creating the object via
  1136. * <f CoCreateInstance>(&CLSID_DirectInput8, <p punkOuter>,
  1137. * CLSCTX_INPROC_SERVER, <p refiid>, <p lplpDirectInput>);
  1138. * then initializing it with <f Initialize>.
  1139. *
  1140. * Calling this function with <p punkOuter> != NULL
  1141. * is equivalent to creating the object via
  1142. * <f CoCreateInstance>(&CLSID_DirectInput8, <p punkOuter>,
  1143. * CLSCTX_INPROC_SERVER, &IID_IUnknown, <p lplpDirectInput>).
  1144. * The aggregated object must be initialized manually.
  1145. *
  1146. * Since the IID is passed, there is no need for separate ANSI and
  1147. * UNICODE versions of this service however as with other system
  1148. * services which are sensitive to character set issues,
  1149. * macros in the header file map a generic version of the IID name
  1150. * to the appropriate IID for the character set variation.
  1151. *
  1152. *****************************************************************************/
  1153. STDMETHODIMP
  1154. DirectInput8Create(HINSTANCE hinst, DWORD dwVer, REFIID riidltf, LPVOID *ppvOut, LPUNKNOWN punkOuter)
  1155. {
  1156. HRESULT hres = E_NOINTERFACE;
  1157. #ifndef XDEBUG
  1158. TCHAR tszGuid[ctchNameGuid];
  1159. TCHAR tszKey[ctchGuid + 40]; /* 40 is more than enough */
  1160. ULONG lRc;
  1161. HKEY hk;
  1162. #endif
  1163. EnterProc(DirectInput8Create, (_ "xxGx", hinst, dwVer, riidltf, ppvOut, punkOuter));
  1164. /* Need to maintain a refcount to keep the Dll Around */
  1165. DllAddRef();
  1166. #ifndef XDEBUG
  1167. /*
  1168. * To provide the Dx CPL with a mechanism to allow developers to hot swap dinput8
  1169. * retail and debug bits
  1170. * In the retail version, we will check the CLSID//"CLSID_DirectInput8"/InProcServer32
  1171. * If it is found that the last n characters of the Dll name matches "Dinput8D.dll" then
  1172. * we will LoadLibrary Dinput8.dll and call the DirectInput8Create function in dinput8d.dll
  1173. *
  1174. */
  1175. // Convert guid to name
  1176. NameFromGUID(tszGuid, &CLSID_DirectInput8);
  1177. // The NameFromGUID function adds a prefix, which is easily gotten rid of
  1178. wsprintf(tszKey, TEXT("CLSID\\%s\\InProcServer32"), tszGuid+ctchNamePrefix);
  1179. // Open the CLSID registry key
  1180. lRc = RegOpenKeyEx(HKEY_CLASSES_ROOT, tszKey, 0,
  1181. KEY_QUERY_VALUE, &hk);
  1182. if (lRc == ERROR_SUCCESS)
  1183. {
  1184. TCHAR tszDll[MAX_PATH];
  1185. int cb;
  1186. cb = cbX(tszDll);
  1187. lRc = RegQueryValue(hk, 0, tszDll, &cb);
  1188. if (lRc == ERROR_SUCCESS)
  1189. {
  1190. // We are only interested in the last few TCHARs for our comparison
  1191. cb = lstrlen(tszDll ) - lstrlen(TEXT("dinput8d.dll"));
  1192. if ( ( cb >= 0x0 ) &&
  1193. ( 0x0 == lstrcmpi(TEXT("dinput8d.dll"), &tszDll[cb])) )
  1194. {
  1195. // We should use the debug binary
  1196. g_hinstDbg = LoadLibrary(tszDll);
  1197. if (g_hinstDbg)
  1198. {
  1199. typedef HRESULT ( WINAPI * DIRECTINPUTCREATE8) ( HINSTANCE hinst, DWORD dwVersion, REFIID riidltf, LPVOID *ppvOut, LPUNKNOWN punkOuter);
  1200. DIRECTINPUTCREATE8 _DirectInputCreate8;
  1201. AssertF(g_hinstDbg != g_hinst );
  1202. _DirectInputCreate8 = (DIRECTINPUTCREATE8)GetProcAddress( g_hinstDbg, "DirectInput8Create");
  1203. if ( _DirectInputCreate8 &&
  1204. g_hinstDbg != g_hinst )
  1205. {
  1206. hres = _DirectInputCreate8(hinst, dwVer, riidltf, ppvOut, punkOuter);
  1207. }
  1208. }
  1209. }
  1210. }
  1211. RegCloseKey(hk);
  1212. }
  1213. if( hres == E_NOINTERFACE)
  1214. #endif /* XDEBUG */
  1215. //Can't create an IDirectInputJoyConfig8 interface through this mechanism, only IDirectInput8 interface!
  1216. if (!IsEqualIID(riidltf, &IID_IDirectInputJoyConfig8))
  1217. {
  1218. hres = DirectInputCreateHelper(hinst, dwVer, ppvOut, punkOuter,
  1219. riidltf);
  1220. }
  1221. DllRelease();
  1222. ExitOleProcPpv(ppvOut);
  1223. return hres;
  1224. }