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.

439 lines
13 KiB

  1. /*****************************************************************************
  2. *
  3. * DIEm.h
  4. *
  5. * Copyright (c) 1996-1997 Microsoft Corporation. All Rights Reserved.
  6. *
  7. * Abstract:
  8. *
  9. * DirectInput internal header file for emulation.
  10. *
  11. *****************************************************************************/
  12. /*****************************************************************************
  13. *
  14. * @doc INTERNAL
  15. *
  16. * @struct CEd |
  17. *
  18. * Emulation descriptor. One of these is created for each
  19. * device. It is never destroyed, so the variable must
  20. * be a global variable or memory allocated inside a
  21. * container that will eventually be destroyed.
  22. *
  23. * ISSUE-2001/03/29-timgill Need a better destructor function
  24. *
  25. * @field LPVOID const | pState |
  26. *
  27. * State buffer that everybody parties into.
  28. *
  29. * It too is never destroyed, so once again it should be
  30. * a global variable or live inside something else that
  31. * will be destroyed.
  32. *
  33. * @field LPDWORD const | pDevType |
  34. *
  35. * Array of device type descriptors, indexed by data format
  36. * offset. Used to determine whether a particular piece of
  37. * data belongs to an axis, button, or POV.
  38. *
  39. * @field EMULATIONPROC | Acquire |
  40. *
  41. * Callback function for acquisition and loss thereof.
  42. * It is called once when the first client acquires,
  43. * and again when the last app unacquires. It is not
  44. * informed of nested acquisition.
  45. *
  46. * @field LONG | cAcquire |
  47. *
  48. * Number of times the device emulation has been acquired (minus one).
  49. *
  50. * @field DWORD | cbData |
  51. *
  52. * Size of the device data type. In other words, size of
  53. * <p pState> in bytes.
  54. *
  55. *****************************************************************************/
  56. typedef STDMETHOD(EMULATIONPROC)(struct CEm *, BOOL fAcquire);
  57. typedef struct CEd {
  58. LPVOID const pState;
  59. LPDWORD const pDevType;
  60. EMULATIONPROC Acquire;
  61. LONG cAcquire;
  62. DWORD cbData;
  63. ULONG cRef;
  64. } CEd, ED, *PED;
  65. /*****************************************************************************
  66. *
  67. * @doc INTERNAL
  68. *
  69. * @struct CEm |
  70. *
  71. * Emulation state information.
  72. *
  73. * @field VXDINSTANCE | vi |
  74. *
  75. * Information shared with parent device.
  76. *
  77. * @field PEM | pemNext |
  78. *
  79. * Next item in linked list of all active device instances.
  80. *
  81. * @field LPDWORD | rgdwDf |
  82. *
  83. * Array of items (one for each byte in the device
  84. * data format). This maps each device data format byte
  85. * into an application device data offset, or -1 if the
  86. * application doesn't care about the corresponding object.
  87. *
  88. * @field ULONG_PTR | dwExtra |
  89. *
  90. * Extra information passed in the <t VXDDEVICEFORMAT>
  91. * when the device was created. This is used by each
  92. * particular device to encode additional instance infomation.
  93. *
  94. * @field PED | ped |
  95. *
  96. * The device that owns this instance. Multiple instances
  97. * of the same device share the same <e CEm.ped>.
  98. *
  99. * @field LONG | cRef |
  100. *
  101. * Reference count.
  102. *
  103. *
  104. * @field LONG | cAcquire |
  105. *
  106. * Number of times the device instance has been acquired (minus one).
  107. *
  108. *
  109. * @field BOOL | fWorkerThread |
  110. *
  111. * This is used by low-level hooks and HID devices, which
  112. * require a worker thread to collect the data.
  113. * This is not cheap, so
  114. * instead, we spin up the thread on the first acquire, and
  115. * on the unacquire, we keep the thread around so that the next
  116. * acquire is fast. When the last object is released, we finally
  117. * kill the thread.
  118. *
  119. *****************************************************************************/
  120. typedef struct CEm {
  121. VXDINSTANCE vi; /* This must be first */
  122. struct CEm *pemNext;
  123. LPDWORD rgdwDf;
  124. ULONG_PTR dwExtra;
  125. PED ped;
  126. LONG cAcquire;
  127. LONG cRef;
  128. #ifdef WORKER_THREAD
  129. BOOL fWorkerThread;
  130. #endif
  131. #ifdef DEBUG
  132. DWORD dwSignature;
  133. #endif
  134. BOOL fHidden;
  135. } CEm, EM, *PEM;
  136. #define CEM_SIGNATURE 0x4D4D4545 /* "EEMM" */
  137. /*****************************************************************************
  138. *
  139. * @doc INTERNAL
  140. *
  141. * @func PEM | pemFromPvi |
  142. *
  143. * Given an interior pointer to a <t VXDINSTANCE>, retrieve
  144. * a pointer to the parent <t CEm>.
  145. *
  146. * @parm PVXDINSTANCE | pvi |
  147. *
  148. * The pointer to convert.
  149. *
  150. *****************************************************************************/
  151. PEM INLINE
  152. pemFromPvi(PVXDINSTANCE pvi)
  153. {
  154. return pvSubPvCb(pvi, FIELD_OFFSET(CEm, vi));
  155. }
  156. /*****************************************************************************
  157. *
  158. * NT low-level hook support
  159. *
  160. * Low-level hooks live on a separate thread which we spin
  161. * up when first requested and take down when the last
  162. * DirectInput device that used a thread has been destroyed.
  163. *
  164. * If we wanted, we could destroy the thread when the
  165. * device is unacquired (rather than when the device is
  166. * destroyed), but we cache the thread instead, because
  167. * a device that once has been acquired will probably be
  168. * acquired again.
  169. *
  170. * To prevent race conditions from crashing us, we addref
  171. * our DLL when the thread exists and have the thread
  172. * perform a FreeLibrary as its final act.
  173. *
  174. * Note that this helper thread is also used by the HID data
  175. * collector.
  176. *
  177. *****************************************************************************/
  178. #ifdef USE_SLOW_LL_HOOKS
  179. /*****************************************************************************
  180. *
  181. * @doc INTERNAL
  182. *
  183. * @struct LLHOOKSTATE |
  184. *
  185. * Low-level hook information about a single hook.
  186. *
  187. * @field int | cHook |
  188. *
  189. * Number of times the hook has been requested. If zero,
  190. * then there should be no hook. All modifications to
  191. * this field must be interlocked to avoid race conditions
  192. * when two threads try to hook or unhook simultaneously.
  193. *
  194. * @field int | cExcl |
  195. *
  196. * Number of times the hook has been requested in an exclusive
  197. * mode. This value should always be less than or equal to the
  198. * cHook value. All modifications to this field must be
  199. * interlocked to avoid race conditions when two threads try to
  200. * hook or unhook simultaneously.
  201. *
  202. * @field HHOOK | hhk |
  203. *
  204. * The actual hook, if it is installed. Only the hook thread
  205. * touches this field, so it does not need to be protected.
  206. *
  207. * @field BOOLEAN | fExcluded |
  208. *
  209. * Flag to indicate whether or not exclusivity has been applied.
  210. * Only the hook thread touches this field, so it does not need to
  211. * be protected.
  212. *
  213. *****************************************************************************/
  214. typedef struct LLHOOKSTATE {
  215. int cHook;
  216. int cExcl;
  217. HHOOK hhk;
  218. BOOLEAN fExcluded;
  219. } LLHOOKSTATE, *PLLHOOKSTATE;
  220. LRESULT CALLBACK CEm_LL_KbdHook(int nCode, WPARAM wp, LPARAM lp);
  221. LRESULT CALLBACK CEm_LL_MseHook(int nCode, WPARAM wp, LPARAM lp);
  222. #endif /* USE_SLOW_LL_HOOKS */
  223. #ifdef WORKER_THREAD
  224. /*****************************************************************************
  225. *
  226. * @doc INTERNAL
  227. *
  228. * @struct LLTHREADSTATE |
  229. *
  230. * Low-level hook state for a thread. Note that this is
  231. * a dynamically
  232. * allocated structure instead of a static. This avoids various
  233. * race conditions where, for example, somebody terminates the
  234. * worker thread and somebody else starts it up before the
  235. * worker thread is completely gone.
  236. *
  237. * A pointer to the hThread is passed as the pointer to an array
  238. * of two handles in calls to WaitForMultipleObject so hEvent must
  239. * follow it directly.
  240. *
  241. * @field DWORD | idThread |
  242. *
  243. * The ID of the worker thread.
  244. *
  245. * @field LONG | cRef |
  246. *
  247. * Thread reference count. The thread kills itself when this
  248. * drops to zero.
  249. *
  250. * @field LLHOOKSTATE | rglhs[2] |
  251. *
  252. * Hook states, indexed by LLTS_* values.
  253. *
  254. * These are used only if low-level hooks are enabled.
  255. *
  256. * @field HANDLE | hThread |
  257. *
  258. * The handle (from the create) of the worker thread.
  259. *
  260. * This is used only if HID support is enabled.
  261. *
  262. * @field HANDLE | hEvent |
  263. *
  264. * The handle to the event used to synchronize with the worker thread.
  265. *
  266. * This is used only if HID support is enabled.
  267. *
  268. * @field GPA | gpaHid |
  269. *
  270. * Pointer array of HID devices which are acquired.
  271. *
  272. * This is used only if HID support is enabled.
  273. *
  274. * @field PEM | pemCheck |
  275. *
  276. * Pointer to Emulation state information.
  277. *
  278. * This is used only if HID support is enabled.
  279. *
  280. *****************************************************************************/
  281. #define LLTS_KBD 0
  282. #define LLTS_MSE 1
  283. #define LLTS_MAX 2
  284. typedef struct LLTHREADSTATE {
  285. DWORD idThread;
  286. LONG cRef;
  287. #ifdef USE_SLOW_LL_HOOKS
  288. LLHOOKSTATE rglhs[LLTS_MAX];
  289. #endif
  290. HANDLE hThread; /* MUST be followed by hEvent, see above */
  291. HANDLE hEvent; /* MUST follow hThread, see above */
  292. GPA gpaHid;
  293. PEM pemCheck;
  294. } LLTHREADSTATE, *PLLTHREADSTATE;
  295. /*****************************************************************************
  296. *
  297. * @doc INTERNAL
  298. *
  299. * @topic Communicating with the worker thread |
  300. *
  301. * Communication with the worker thread is performed via
  302. * <c WM_NULL> messages. Extra care must be taken to make
  303. * sure that someone isn't randomly sending messages to us.
  304. *
  305. * We use the <c WM_NULL> message because there are race
  306. * windows where we might post a message to a thread after
  307. * it is gone. During this window, the thread ID might get
  308. * recycled, and we end up posting the message to some random
  309. * thread that isn't ours. By using the <c WM_NULL> message,
  310. * we are safe in knowing that the target thread won't barf
  311. * on the unexpected message.
  312. *
  313. * The <t WPARAM> of the <c WM_NULL> is the magic value
  314. * <c WT_WPARAM>.
  315. *
  316. * The <t LPARAM> of the <c WM_NULL> is either a pointer
  317. * to the <t CEm> that needs to be refreshed or is
  318. * zero if we merely want to check our bearings.
  319. *
  320. *****************************************************************************/
  321. #define WT_WPARAM 0
  322. #define PostWorkerMessage(thid, lp) \
  323. PostThreadMessage(thid, WM_NULL, WT_WPARAM, (LPARAM)(lp)) \
  324. #define NudgeWorkerThread(thid) \
  325. PostThreadMessage(thid, WM_NULL, WT_WPARAM, (LPARAM)NULL)
  326. HRESULT EXTERNAL NudgeWorkerThreadPem( PLLTHREADSTATE plts, PEM pem );
  327. HRESULT EXTERNAL NotifyWorkerThreadPem(DWORD idThread, PEM pem);
  328. STDMETHODIMP CEm_GetWorkerThread(PEM pem, PLLTHREADSTATE *pplts);
  329. /*****************************************************************************
  330. *
  331. * @doc INTERNAL
  332. *
  333. * @global PLLTHREADSTATE | g_plts |
  334. *
  335. * The thread state of the currently-active thread.
  336. *
  337. * This variable needs to be externally accessible
  338. * because you can't pass instance data to a windows
  339. * hook function. (Whose idea was that?)
  340. *
  341. *****************************************************************************/
  342. extern PLLTHREADSTATE g_plts;
  343. void EXTERNAL CEm_Mouse_OnMouseChange(void);
  344. #endif /* WORKER_THREAD */
  345. /*
  346. * Private helper functions in diem.c
  347. */
  348. #define FDUFL_NORMAL 0x0000 /* Nothing unusual */
  349. #define FDUFL_UNPLUGGED VIFL_UNPLUGGED /* Device disconnected */
  350. void EXTERNAL CEm_ForceDeviceUnacquire(PED ped, UINT fdufl);
  351. void EXTERNAL CEm_AddState(PED ped, LPVOID pvData, DWORD tm);
  352. DWORD EXTERNAL CEm_AddEvent(PED ped, DWORD dwData, DWORD dwOfs, DWORD tm);
  353. BOOL EXTERNAL CEm_ContinueEvent(PED ped, DWORD dwData, DWORD dwOfs, DWORD tm, DWORD dwSeq);
  354. STDMETHODIMP CEm_LL_Acquire(PEM this, BOOL fAcquire, ULONG fl, UINT ilts);
  355. HRESULT EXTERNAL
  356. CEm_CreateInstance(PVXDDEVICEFORMAT pdevf, PVXDINSTANCE *ppviOut, PED ped);
  357. void EXTERNAL CEm_FreeInstance(PEM this);
  358. /*****************************************************************************
  359. *
  360. * @doc INTERNAL
  361. *
  362. * @func void | CEm_AddRef |
  363. *
  364. * Bump the reference count because we're doing something with it.
  365. *
  366. * @parm PEM | this |
  367. *
  368. * The victim.
  369. *
  370. *****************************************************************************/
  371. void INLINE
  372. CEm_AddRef(PEM this)
  373. {
  374. AssertF(this->dwSignature == CEM_SIGNATURE);
  375. InterlockedIncrement(&this->cRef);
  376. }
  377. /*****************************************************************************
  378. *
  379. * @doc INTERNAL
  380. *
  381. * @func void | CEm_Release |
  382. *
  383. * Drop the reference count and blow it away if it's gone.
  384. *
  385. * @parm PEM | this |
  386. *
  387. * The victim.
  388. *
  389. *****************************************************************************/
  390. void INLINE
  391. CEm_Release(PEM this)
  392. {
  393. AssertF(this->dwSignature == CEM_SIGNATURE);
  394. if (InterlockedDecrement(&this->cRef) == 0) {
  395. CEm_FreeInstance(this);
  396. }
  397. }