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.

846 lines
21 KiB

  1. /*****************************************************************************
  2. *
  3. * DIExcl.c
  4. *
  5. * Copyright (c) 1997 Microsoft Corporation. All Rights Reserved.
  6. *
  7. * Abstract:
  8. *
  9. * Management and negotiation of exclusive access.
  10. *
  11. * Contents:
  12. *
  13. * Excl_Acquire
  14. * Excl_Unacquire
  15. *
  16. *****************************************************************************/
  17. #include "dinputpr.h"
  18. /*****************************************************************************
  19. *
  20. * The sqiffle for this file.
  21. *
  22. *****************************************************************************/
  23. #define sqfl sqflExcl
  24. #pragma BEGIN_CONST_DATA
  25. #ifndef WINNT
  26. TCHAR c_tszVxd[] = TEXT("\\\\.\\DINPUT.VXD");
  27. #endif
  28. #if DIRECTINPUT_VERSION > 0x0300
  29. /*****************************************************************************
  30. *
  31. * @doc INTERNAL
  32. *
  33. * @struct SHAREDOBJECT |
  34. *
  35. * Each object that can be taken exclusively receives one of
  36. * these structures. This structure is shared across processes,
  37. * so you must protect access with the global DLL mutex.
  38. *
  39. * You would think that we could just use a named semaphore.
  40. * Well, that won't work because if the app crashes, nobody
  41. * will release the semaphore token and the device will be
  42. * unavailable forever.
  43. *
  44. * And we can't use a named mutex because mutexes are tracked
  45. * on a per-thread basis, but device acquisition is maintained
  46. * on a per-process basis.
  47. *
  48. * So instead we have to roll our own "process-level mutex".
  49. *
  50. * To conserve memory, we dump all our tiny <t SHAREDOBJECT>
  51. * structures into a single page. This means that we cannot
  52. * support more than about 4000 / sizeof(SHAREDOBJECT) =
  53. * 140 devices simultaneously acquired exclusively.
  54. *
  55. * Since USB maxes out at 64 devices, we've got plenty of room.
  56. *
  57. * WARNING! This structure may not change between DEBUG and
  58. * RETAIL. Otherwise, you have problems if one DirectInput
  59. * app is using DEBUG and another is using RETAIL.
  60. *
  61. * @field GUID | guid |
  62. *
  63. * The identifier for the device that is acquired exclusively.
  64. *
  65. * @field HWND | hwndOwner |
  66. *
  67. * The window handle associated with the device that has
  68. * obtained exclusive access.
  69. *
  70. * @field DWORD | pidOwner |
  71. *
  72. * The process ID of the owner window. This is used as a
  73. * cross-check against <f hwndOwner> in case the application
  74. * which is the owner suddenly crashes.
  75. *
  76. * @field DWORD | discl |
  77. *
  78. * Cooperative level with which the device was acquired.
  79. * We care about foreground-ness so that
  80. * we can steal acquisition from a window that
  81. * has stopped responding.
  82. *
  83. *****************************************************************************/
  84. typedef struct SHAREDOBJECT
  85. {
  86. GUID guid;
  87. HWND hwndOwner;
  88. DWORD pidOwner;
  89. DWORD discl;
  90. } SHAREDOBJECT, *PSHAREDOBJECT;
  91. typedef const SHAREDOBJECT *PCSHAREDOBJECT;
  92. /*****************************************************************************
  93. *
  94. * @doc INTERNAL
  95. *
  96. * @define csoMax | (cbShared - cbX(SHAREDOBJECTHEADER)) / cbX(SHAREDOBJECT) |
  97. *
  98. * The maximum number of simultaneously acquired devices.
  99. *
  100. *****************************************************************************/
  101. #define cbShared 4096
  102. #define csoMax ((cbShared - cbX(SHAREDOBJECTHEADER)) / cbX(SHAREDOBJECT))
  103. /*****************************************************************************
  104. *
  105. * @doc INTERNAL
  106. *
  107. * @struct SHAREDOBJECTPAGE |
  108. *
  109. * A header followed by an array of shared objects.
  110. *
  111. * The header must be first. <c g_soh> relies on it.
  112. *
  113. * @field SHAREDOBJECTHEADER | soh |
  114. *
  115. * The header.
  116. *
  117. * @field SHAREDOBJECT | rgso[csoMax] |
  118. *
  119. * Array of shared object structures.
  120. *
  121. *****************************************************************************/
  122. typedef struct SHAREDOBJECTPAGE
  123. {
  124. SHAREDOBJECTHEADER soh;
  125. SHAREDOBJECT rgso[csoMax];
  126. } SHAREDOBJECTPAGE, *PSHAREDOBJECTPAGE;
  127. void INLINE
  128. CheckSharedObjectPageSize(void)
  129. {
  130. CAssertF(cbX(SHAREDOBJECTPAGE) <= cbShared);
  131. CAssertF(cbX(SHAREDOBJECTPAGE) + cbX(SHAREDOBJECT) > cbShared);
  132. }
  133. /*****************************************************************************
  134. *
  135. * @doc INTERNAL
  136. *
  137. * @func PSHAREDOBJECT | Excl_FindGuid |
  138. *
  139. * Locate a GUID in the shared object array.
  140. *
  141. * The shared global mutex must already be taken.
  142. *
  143. * @parm PCGUID | pguid |
  144. *
  145. * The GUID to locate.
  146. *
  147. * @returns
  148. *
  149. * A pointer to the entry, or 0 if not found.
  150. *
  151. *
  152. *****************************************************************************/
  153. PSHAREDOBJECT INTERNAL
  154. Excl_FindGuid(PCGUID pguid)
  155. {
  156. PSHAREDOBJECTPAGE psop;
  157. PSHAREDOBJECT pso, psoMax;
  158. DWORD Data1;
  159. EnterProcI(Excl_FindGuid, (_ "G", pguid));
  160. psop = g_psop;
  161. Data1 = pguid->Data1;
  162. AssertF(g_psop);
  163. for(pso = &psop->rgso[0], psoMax = &psop->rgso[psop->soh.cso];
  164. pso < psoMax; pso++)
  165. {
  166. if(pso->guid.Data1 == Data1 && IsEqualGUID(pguid, &pso->guid))
  167. {
  168. goto done;
  169. }
  170. }
  171. pso = 0;
  172. done:;
  173. ExitProcX((UINT_PTR)pso);
  174. return pso;
  175. }
  176. /*****************************************************************************
  177. *
  178. * @doc INTERNAL
  179. *
  180. * @func HRESULT | Excl_CanStealPso |
  181. *
  182. * Determine whether the <t SHAREDOBJECT> is self-consistent
  183. * and represents an instance which validly holds the
  184. * exclusive acquisition. If so, then it cannot be stolen.
  185. * Else, it is dead and can be stolen.
  186. *
  187. * @parm PCSHAREDOBJECT | pso |
  188. *
  189. * The <t SHAREDOBJECT> structure to validate.
  190. *
  191. * @returns
  192. *
  193. * <c S_OK> if acquisition can be stolen, or
  194. * <c DIERR_OTHERAPPHASPRIO> if acquisition is validly
  195. * held by another instance.
  196. *
  197. *****************************************************************************/
  198. STDMETHODIMP
  199. Excl_CanStealPso(PCSHAREDOBJECT pso)
  200. {
  201. HRESULT hres = S_OK;
  202. /*
  203. * The window handle should be valid and still refer to the pid.
  204. */
  205. if(GetWindowPid(pso->hwndOwner) == pso->pidOwner)
  206. {
  207. if( pso->discl & DISCL_FOREGROUND )
  208. {
  209. if( GetForegroundWindow() != pso->hwndOwner)
  210. {
  211. // 7/19/2000(a-JiTay): IA64: Use %p format specifier for 32/64-bit pointers.
  212. RPF("Acquire: can't steal Pso because it belongs to another app. (current hwnd=0x%p)",
  213. pso->hwndOwner);
  214. hres = DIERR_OTHERAPPHASPRIO;
  215. } else
  216. {
  217. // 7/19/2000(a-JiTay): IA64: Use %p format specifier for 32/64-bit pointers.
  218. RPF("Acquire: Current owner hwnd=0x%p has priority; "
  219. "stealing", pso->hwndOwner);
  220. hres = S_OK;
  221. }
  222. }
  223. } else
  224. {
  225. /*
  226. * App died. Can steal.
  227. */
  228. RPF("Acquire: Previous owner pid=0x%08x mysteriously died; "
  229. "stealing", pso->pidOwner);
  230. hres = S_OK;
  231. }
  232. return hres;
  233. }
  234. /*****************************************************************************
  235. *
  236. * @doc INTERNAL
  237. *
  238. * @func HRESULT | Excl_Acquire |
  239. *
  240. * Attempt to acquire the device exclusively.
  241. *
  242. * @parm PCGUID | pguid |
  243. *
  244. * The GUID to acquire.
  245. *
  246. * @parm HWND | hwnd |
  247. *
  248. * Window handle with which to associate the device.
  249. *
  250. * @parm DWORD | discl |
  251. *
  252. * Flags describing cooperative level.
  253. * We are interested only in devices acquired exclusively.
  254. *
  255. * @returns
  256. *
  257. * S_OK on success, or
  258. *
  259. * DIERR_OTHERAPPHASPRIO
  260. * hresLe(ERROR_INVALID_WINDOW_HANDLE)
  261. *
  262. *
  263. *****************************************************************************/
  264. STDMETHODIMP
  265. Excl_Acquire(PCGUID pguid, HWND hwnd, DWORD discl)
  266. {
  267. HRESULT hres;
  268. AssertF(g_psop);
  269. if(discl & DISCL_EXCLUSIVE)
  270. {
  271. /*
  272. * Window must be owned by this process.
  273. */
  274. if(GetWindowPid(hwnd) == GetCurrentProcessId())
  275. {
  276. PSHAREDOBJECT pso;
  277. WaitForSingleObject(g_hmtxGlobal, INFINITE);
  278. pso = Excl_FindGuid(pguid);
  279. /*
  280. * If we found a match, then it might be a sharing violation.
  281. */
  282. if(pso)
  283. {
  284. hres = Excl_CanStealPso(pso);
  285. } else
  286. {
  287. /*
  288. * Allocate a slot for it.
  289. */
  290. if(g_psop->soh.cso < csoMax)
  291. {
  292. pso = &g_psop->rgso[g_psop->soh.cso++];
  293. pso->guid = *pguid;
  294. hres = S_OK;
  295. } else
  296. {
  297. //ISSUE-2001/03/29-timgill hard limit on number of exclusive devices
  298. //Can be annoying
  299. RPF("Too many devices acquired exclusively");
  300. hres = E_FAIL;
  301. }
  302. }
  303. if(SUCCEEDED(hres))
  304. {
  305. pso->hwndOwner = hwnd;
  306. pso->pidOwner = GetCurrentProcessId();
  307. pso->discl = discl;
  308. hres = S_OK;
  309. }
  310. ReleaseMutex(g_hmtxGlobal);
  311. } else
  312. {
  313. hres = hresLe(ERROR_INVALID_WINDOW_HANDLE);
  314. }
  315. } else
  316. {
  317. hres = S_OK;
  318. }
  319. return hres;
  320. }
  321. /*****************************************************************************
  322. *
  323. * @doc INTERNAL
  324. *
  325. * @func void | Excl_Unacquire |
  326. *
  327. * Undo the effects of an acquire.
  328. *
  329. * @parm PCGUID | pguid |
  330. *
  331. * The GUID to acquire.
  332. *
  333. * @parm HWND | hwnd |
  334. *
  335. * Window handle with which to associate the device.
  336. *
  337. * @parm DWORD | discl |
  338. *
  339. * Flags describing cooperative level.
  340. * We are interested only in devices acquired exclusively.
  341. *
  342. *****************************************************************************/
  343. void EXTERNAL
  344. Excl_Unacquire(PCGUID pguid, HWND hwnd, DWORD discl)
  345. {
  346. AssertF(g_psop);
  347. if(discl & DISCL_EXCLUSIVE)
  348. {
  349. PSHAREDOBJECT pso;
  350. WaitForSingleObject(g_hmtxGlobal, INFINITE);
  351. pso = Excl_FindGuid(pguid);
  352. /*
  353. * Make sure it's really ours.
  354. */
  355. if(pso && pso->hwndOwner == hwnd &&
  356. pso->pidOwner == GetCurrentProcessId())
  357. {
  358. /*
  359. * Delete the entry and close up the gap.
  360. */
  361. *pso = g_psop->rgso[--g_psop->soh.cso];
  362. }
  363. ReleaseMutex(g_hmtxGlobal);
  364. }
  365. }
  366. /*****************************************************************************
  367. *
  368. * @doc INTERNAL
  369. *
  370. * @func HRESULT | Excl_Init |
  371. *
  372. * Initialize the exclusive device manager.
  373. *
  374. * @returns
  375. *
  376. * <c S_OK> if all is well.
  377. *
  378. * <c E_FAIL> if something is horribly wrong.
  379. *
  380. *****************************************************************************/
  381. STDMETHODIMP
  382. Excl_Init(void)
  383. {
  384. HRESULT hres;
  385. TCHAR tszName[ctchNameGuid];
  386. DllEnterCrit();
  387. /*
  388. * Create the global mutex used to gate access to shared memory.
  389. */
  390. if(g_hmtxGlobal == 0)
  391. {
  392. NameFromGUID(tszName, &IID_IDirectInputW);
  393. g_hmtxGlobal = CreateMutex(0, TRUE, tszName);
  394. if(g_hmtxGlobal)
  395. {
  396. /*
  397. * If we need to do smth only once, we can do:
  398. * if ( GetLastError() != ERROR_ALREADY_EXISTS )
  399. * {
  400. * do our stuff
  401. * }
  402. */
  403. g_flEmulation = RegQueryDIDword(NULL, REGSTR_VAL_EMULATION, 0);
  404. #ifndef WINNT
  405. /*
  406. * We have to open the VxD while we own the global mutex in order
  407. * to avoid a race condition that occurs when two processes try
  408. * to open a VxD at the same time. See DInput VxD for details.
  409. */
  410. if (_OpenVxDHandle)
  411. {
  412. /*
  413. * CreateFile on a \\.\ name does not check the dwCreationDisposition
  414. * parameter but BoundsChecker does so use a valid value.
  415. */
  416. g_hVxD = CreateFile(c_tszVxd, 0, 0, 0, OPEN_EXISTING, FILE_FLAG_DELETE_ON_CLOSE, 0);
  417. if( g_hVxD != INVALID_HANDLE_VALUE )
  418. {
  419. LONG lGranularity;
  420. /*
  421. * If we can't get the sequence number (weird), then set it
  422. * back to NULL so it will point at the shared memory
  423. * block just like on NT.
  424. */
  425. if (FAILED(IoctlHw(IOCTL_GETSEQUENCEPTR, 0, 0,
  426. &g_pdwSequence, cbX(g_pdwSequence))))
  427. {
  428. g_pdwSequence = 0;
  429. }
  430. if (SUCCEEDED(IoctlHw(IOCTL_MOUSE_GETWHEEL, 0, 0,
  431. &lGranularity, cbX(lGranularity))))
  432. {
  433. g_lWheelGranularity = lGranularity;
  434. }
  435. }
  436. else
  437. {
  438. RPF( "ERROR: Cannot load %s", &c_tszVxd[4] );
  439. }
  440. }
  441. #endif
  442. /*
  443. * We defer ExtDll work until now, because it is not safe to
  444. * call LoadLibrary during PROCESS_ATTACH.
  445. *
  446. * We also steal g_hmtxGlobal to protect us from doing it twice.
  447. */
  448. ExtDll_Init();
  449. ReleaseMutex(g_hmtxGlobal);
  450. }
  451. else
  452. {
  453. RPF("Cannot create shared semaphore %s", tszName);
  454. hres = E_FAIL;
  455. goto fail;
  456. }
  457. }
  458. /*
  459. * Create the shared memory.
  460. *
  461. * Warning! The file mapping handle must be kept alive
  462. * so its name stays alive. NT destroys the file mapping
  463. * object when you close the handle; as a result, the
  464. * name goes away with it and another instance of
  465. * DirectInput fails to find it.
  466. */
  467. if(g_psop == 0)
  468. {
  469. NameFromGUID(tszName, &IID_IDirectInputDeviceW);
  470. g_hfm = CreateFileMapping(INVALID_HANDLE_VALUE, 0,
  471. PAGE_READWRITE, 0,
  472. cbShared, tszName);
  473. if(g_hfm)
  474. {
  475. g_psop = MapViewOfFile(g_hfm, FILE_MAP_WRITE | FILE_MAP_READ,
  476. 0, 0, 0);
  477. if(g_psop)
  478. {
  479. } else
  480. {
  481. RPF("Cannot map shared memory block %s", tszName);
  482. hres = E_FAIL;
  483. goto fail;
  484. }
  485. } else
  486. {
  487. RPF("Cannot create shared memory block %s", tszName);
  488. hres = E_FAIL;
  489. goto fail;
  490. }
  491. }
  492. #ifdef IDirectInputDevice2Vtbl
  493. /*
  494. * Create the global mutex used to gate access to joystick info.
  495. */
  496. if(g_hmtxJoy == 0)
  497. {
  498. NameFromGUID(tszName, &IID_IDirectInputDevice2A);
  499. g_hmtxJoy = CreateMutex(0, 0, tszName);
  500. if(g_hmtxJoy)
  501. {
  502. } else
  503. {
  504. RPF("Cannot create shared semaphore %s", tszName);
  505. hres = E_FAIL;
  506. goto fail;
  507. }
  508. /*
  509. * We shall steal the joystick Mutex to build the Bus list
  510. * for the first time.
  511. * It is very unlikely that the list will change. ( PCMCIA cards ! )
  512. * And when it does change we can expect the joyConfig interface will
  513. * be pinged.
  514. */
  515. DIBus_BuildList(FALSE);
  516. }
  517. #endif
  518. /*
  519. * If we don't have a global sequence number from the driver,
  520. * then use the one in the shared memory block instead.
  521. */
  522. if(g_pdwSequence == 0)
  523. {
  524. g_pdwSequence = &g_psoh->dwSequence;
  525. }
  526. hres = S_OK;
  527. fail:;
  528. DllLeaveCrit();
  529. return hres;
  530. }
  531. /*****************************************************************************
  532. *
  533. * @doc INTERNAL
  534. *
  535. * @func LONG | Excl_UniqueGuidInteger |
  536. *
  537. * Generate a unique number used by DICreateGuid to make sure
  538. * that we don't generate two pseudoGUIDs with the same value.
  539. *
  540. * @returns
  541. *
  542. * An integer that has not been returned by this function
  543. * yet.
  544. *
  545. *****************************************************************************/
  546. LONG EXTERNAL
  547. Excl_UniqueGuidInteger(void)
  548. {
  549. LONG lRc;
  550. AssertF(g_hmtxGlobal);
  551. WaitForSingleObject(g_hmtxGlobal, INFINITE);
  552. AssertF(g_psop);
  553. lRc = ++g_psop->soh.cguid;
  554. ReleaseMutex(g_hmtxGlobal);
  555. return lRc;
  556. }
  557. /*****************************************************************************
  558. *
  559. * @doc INTERNAL
  560. *
  561. * @func DWORD | Excl_GetConfigChangedTime |
  562. *
  563. * Retrieves tmConfigChanged in g_psop->soh.
  564. *
  565. * @returns
  566. *
  567. * tmConfigChanged
  568. *****************************************************************************/
  569. DWORD EXTERNAL
  570. Excl_GetConfigChangedTime()
  571. {
  572. DWORD dwRc;
  573. AssertF(g_hmtxGlobal);
  574. WaitForSingleObject(g_hmtxGlobal, INFINITE);
  575. AssertF(g_psop);
  576. dwRc = g_psop->soh.tmConfigChanged;
  577. ReleaseMutex(g_hmtxGlobal);
  578. return dwRc;
  579. }
  580. /*****************************************************************************
  581. *
  582. * @doc INTERNAL
  583. *
  584. * @func void | Excl_SetConfigChangedTime |
  585. *
  586. * Sets tmConfigChanged in g_psop->soh.
  587. *
  588. * @returns
  589. *
  590. * void
  591. *****************************************************************************/
  592. void EXTERNAL
  593. Excl_SetConfigChangedTime(DWORD tm)
  594. {
  595. AssertF(g_hmtxGlobal);
  596. WaitForSingleObject(g_hmtxGlobal, INFINITE);
  597. AssertF(g_psop);
  598. g_psop->soh.tmConfigChanged = tm;
  599. ReleaseMutex(g_hmtxGlobal);
  600. return;
  601. }
  602. #if 0
  603. /*
  604. * This is the code I wrote when I tired to fix WI321711.
  605. * It may be used in the future when we want to communicate between DInput7
  606. * DInput8. -qzheng 3/9/2001
  607. */
  608. /*****************************************************************************
  609. *
  610. * @doc INTERNAL
  611. *
  612. * @func void | Excl_SetFlag |
  613. *
  614. * Sets dwFlags in g_psop->soh.
  615. *
  616. * @returns
  617. *
  618. * void
  619. *****************************************************************************/
  620. void EXTERNAL
  621. Excl_SetFlag(DWORD flag)
  622. {
  623. AssertF(g_hmtxGlobal);
  624. WaitForSingleObject(g_hmtxGlobal, INFINITE);
  625. AssertF(g_psop);
  626. g_psop->soh.dwFlags = flag;
  627. ReleaseMutex(g_hmtxGlobal);
  628. return;
  629. }
  630. /*****************************************************************************
  631. *
  632. * @doc INTERNAL
  633. *
  634. * @func BOOL | Excl_TestFlag |
  635. *
  636. * Test whether a flag is set.
  637. * The flags are as dwFlags in g_psop->soh.
  638. *
  639. * @returns
  640. *
  641. * TRUE: the flag is set
  642. * FALSE: otherwise
  643. *
  644. *****************************************************************************/
  645. BOOL EXTERNAL
  646. Excl_TestFlag(DWORD flag)
  647. {
  648. BOOL fRc;
  649. AssertF(g_hmtxGlobal);
  650. WaitForSingleObject(g_hmtxGlobal, INFINITE);
  651. AssertF(g_psop);
  652. if( g_psop->soh.dwFlags & flag ) {
  653. fRc = TRUE;
  654. }
  655. ReleaseMutex(g_hmtxGlobal);
  656. return fRc;
  657. }
  658. /*****************************************************************************
  659. *
  660. * @doc INTERNAL
  661. *
  662. * @func void | Excl_ClearFlag |
  663. *
  664. * Clear a flag.
  665. * The flags are as dwFlags in g_psop->soh.
  666. *
  667. * @returns
  668. *
  669. * void
  670. *****************************************************************************/
  671. void EXTERNAL
  672. Excl_ClearFlag(DWORD flag)
  673. {
  674. AssertF(g_hmtxGlobal);
  675. WaitForSingleObject(g_hmtxGlobal, INFINITE);
  676. AssertF(g_psop);
  677. if( g_psop->soh.dwFlags &= ~flag;
  678. ReleaseMutex(g_hmtxGlobal);
  679. return;
  680. }
  681. /*****************************************************************************
  682. *
  683. * @doc INTERNAL
  684. *
  685. * @func BOOL | Excl_TestAndClearFlag |
  686. *
  687. * Test whether a flag is set, if set, then clear it.
  688. * The flags are as dwFlags in g_psop->soh.
  689. *
  690. * @returns
  691. *
  692. * TRUE: the flag is set
  693. * FALSE: otherwise
  694. *
  695. *****************************************************************************/
  696. BOOL EXTERNAL
  697. Excl_TestAndClearFlag(DWORD flag)
  698. {
  699. BOOL fRc;
  700. AssertF(g_hmtxGlobal);
  701. WaitForSingleObject(g_hmtxGlobal, INFINITE);
  702. AssertF(g_psop);
  703. if( g_psop->soh.dwFlags & flag ) {
  704. g_psop->soh.dwFlags &= ~flag;
  705. fRc = TRUE;
  706. }
  707. ReleaseMutex(g_hmtxGlobal);
  708. return fRc;
  709. }
  710. #endif
  711. #endif