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.

1342 lines
39 KiB

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