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.

642 lines
22 KiB

  1. /*++
  2. *
  3. * WOW v1.0
  4. *
  5. * Copyright (c) 1991, Microsoft Corporation
  6. *
  7. * WUHOOK.C
  8. * WOW32 16-bit User API support
  9. *
  10. * History:
  11. * Created 07-Mar-1991 by Jeff Parsons (jeffpar)
  12. --*/
  13. #include "precomp.h"
  14. #pragma hdrstop
  15. MODNAME(wuhook.c);
  16. /*++
  17. FARPROC SetWindowsHook(<nFilterType>, <lpFilterFunc>)
  18. int <nFilterType>;
  19. FARPROC <lpFilterFunc>;
  20. The %SetWindowsHook% function installs a filter function in a chain. A
  21. filter function processes events before they are sent to an application's
  22. message loop in the WinMain function. A chain is a linked list of filter
  23. functions of the same type.
  24. <nFilterType>
  25. Specifies the system hook to be installed. It can be any one of the
  26. following values:
  27. WH_CALLWNDPROC Installs a window-function filter.
  28. WH_GETMESSAGE Installs a message filter.
  29. WH_JOURNALPLAYBACK Installs a journaling playback filter.
  30. WH_JOURNALRECORD Installs a journaling record filter.
  31. WH_KEYBOARD Installs a keyboard filter.
  32. WH_MSGFILTER Installs a message filter.
  33. WH_SYSMSGFILTER Installs a system-wide message filter.
  34. <lpFilterFunc>
  35. Is the procedure-instance address of the filter function to be
  36. installed. See the following Comments section for details.
  37. The return value points to the procedure-instance address of the previously
  38. installed filter (if any). It is NULL if there is no previous filter. The
  39. application or library that calls the %SetWindowsHook% function should save
  40. this return value in the library's data segment. The fourth argument of the
  41. %DefHookProc% function points to the location in memory where the library
  42. saves this return value.
  43. The return value is -1 if the function fails.
  44. The WH_CALLWNDPROC hook will affect system performance. It is supplied for
  45. debugging purposes only.
  46. The system hooks are a shared resource. Installing a hook affects all
  47. applications. Most hook functions must be in libraries. The only exception
  48. is WH_MSGFILTER, which is task-specific. System hooks should be restricted
  49. to special-purpose applications or as a development aid during debugging of
  50. an application. Libraries that no longer need the hook should remove the
  51. filter function.
  52. To install a filter function, the %SetWindowsHook% function must receive a
  53. procedure-instance address of the function, and the function must be
  54. exported in the library's module-definition file. Libraries can pass the
  55. procedure address directly. Tasks must use %MakeProcInstance% to get a
  56. procedure-instance address. Dynamic-link libraries must use %GetProcAddress%
  57. to get a procedure-instance address.
  58. The following section describes how to support the individual hook
  59. functions.
  60. WH_CALLWNDPROC:
  61. Windows calls the WH_CALLWNDPROC filter function whenever the %SendMessage%
  62. function is called. Windows does not call the filter function when the
  63. %PostMessage% function is called.
  64. The filter function must use the Pascal calling convention and must be
  65. declared %FAR%. The filter function must have the following form:
  66. Filter Function:
  67. DWORD FAR PASCAL <FilterFunc>(<nCode>, <wParam>, <lParam>)
  68. int <nCode>;
  69. WORD <wParam>;
  70. DWORD <lParam>;
  71. <FilterFunc> is a placeholder for the application- or library-supplied
  72. function name. The actual name must be exported by including it in an
  73. %EXPORTS% statement in the library's module-definition file.
  74. <nCode>
  75. Specifies whether the filter function should process the message or call
  76. the DefHookProc function. If the nCode parameter is less than zero, the
  77. filter function should pass the message to DefHookProc without further
  78. processing. <wParam> Specifies whether the message is sent by the
  79. current task. It is nonzero if the message is sent; otherwise, it is
  80. NULL.
  81. <lParam>
  82. Points to a structure that contains details about the message
  83. intercepted by the filter. The following shows the order, type, and
  84. description of each field of the structure:
  85. %lParam%
  86. %WORD% Contains the low-order word of the <lParam> parameter of the
  87. message received by the filter.
  88. %wParam%
  89. %WORD% Contains the <wParam> parameter of the message received by the
  90. filter.
  91. %wMsg%
  92. %WORD% Contains the message received by the filter.
  93. %hwnd%
  94. %WORD% Contains the window handle of the window that is to receive the
  95. message.
  96. The WH_CALLWNDPROC filter function can examine or modify the message as
  97. desired. Once it returns control to Windows, the message, with any
  98. modifications, is passed on to the window function. The filter function does
  99. not require a return value.
  100. WH_GETMESSAGE:
  101. Windows calls the WH_GETMESSAGE filter function whenever the %GetMessage%
  102. function is called. Windows calls the filter function immediately after
  103. %GetMessage% has retrieved a message from an application queue. The filter
  104. function must use the Pascal calling convention and must be declared %FAR%.
  105. The filter function must have the following form:
  106. Filter Function:
  107. DWORD FAR PASCAL <FilterFunc>(<nCode>, <wParam>, <lParam>)
  108. int <nCode>;
  109. WORD <wParam>;
  110. DWORD <lParam>;
  111. <FilterFunc> is a placeholder for the library-supplied function name. The
  112. actual name must be exported by including it in an %EXPORTS% statement in
  113. the library's module-definition file.
  114. <nCode>
  115. Specifies whether the filter function should process the message or call
  116. the DefHookProc function. If the <nCode> parameter is less than zero, the
  117. filter function should pass the message to DefHookProc without further
  118. processing.
  119. <wParam>
  120. Specifies a NULL value.
  121. <lParam>
  122. Points to a message structure.
  123. The WH_GETMESSAGE filter function can examine or modify the message as
  124. desired. Once it returns control to Windows, the %GetMessage% function
  125. returns the message, with any modifications, to the application that
  126. originally called it. The filter function does not require a return value.
  127. WH_JOURNALPLAYBACK:
  128. Windows calls the WH_JOURNALPLAYBACK filter function whenever a request for
  129. an event message is made. The function is intended to be used to supply a
  130. previously recorded event message.
  131. The filter function must use the Pascal calling convention and must be
  132. declared %FAR%. The filter function must have the following form:
  133. DWORD FAR PASCAL <FilterFunc>(<nCode>, <wParam>, <lParam>)
  134. int <nCode>;
  135. WORD <wParam>;
  136. DWORD <lParam>;
  137. <FilterFunc> is a placeholder for the library-supplied function name. The
  138. actual name must be exported by including it in an %EXPORTS% statement in
  139. the library's module-definition file.
  140. <nCode>
  141. Specifies whether the filter function should process the message or call
  142. the DefHookProc function. If the nCode parameter is less then zero, the
  143. filter function should pass the message to DefHookProc without further
  144. processing.
  145. <wParam>
  146. Specifies a NULL value.
  147. <lParam>
  148. Points to the message being processed by the filter function.
  149. The WH_JOURNALPLAYBACK function should copy an event message to the <lParam>
  150. parameter. The message must have been previously recorded by using the
  151. WH_JOURNALRECORD filter. It should not modify the message. The return value
  152. should be the amount of time (in clock ticks) Windows should wait before
  153. processing the message. This time can be computed by calculating the
  154. difference between the %time% fields in the current and previous event
  155. messages. If the function returns zero, the message is processed
  156. immediately. Once it returns control to Windows, the message continues to be
  157. processed. If the <nCode> parameter is HC_SKIP, the filter function should
  158. prepare to return the next recorded event message on its next call.
  159. While the WH_JOURNALPLAYBACK function is in effect, Windows ignores all
  160. mouse and keyboard input.
  161. WH_JOURNALRECORD:
  162. Windows calls the WH_JOURNALRECORD filter function whenever it processes a
  163. message from the event queue. The filter can be used to record the event for
  164. later playback.
  165. The filter function must use the Pascal calling convention and must be
  166. declared %FAR%. The filter function must have the following form:
  167. DWORD FAR PASCAL <FilterFunc>(<nCode>, <wParam>,<lParam>)
  168. int <nCode>;
  169. WORD <wParam>;
  170. DWORD <lParam>;
  171. <FilterFunc> is a placeholder for the library-supplied function name. The
  172. actual name must be exported by including it in an %EXPORTS% statement in
  173. the library's module-definition file.
  174. <nCode>
  175. Specifies whether the filter function should process the message or call
  176. the DefHookProc function. If the nCode parameter is less than zero, the
  177. filter function should pass the message to DefHookProc without further
  178. processing.
  179. <wParam>
  180. Specifies a NULL value.
  181. <lParam>
  182. Points to a message structure.
  183. The WH_JOURNALRECORD function should save a copy of the event message for
  184. later playback. It should not modify the message. Once it returns control to
  185. Windows, the message continues to be processed. The filter function does not
  186. require a return value.
  187. WH_KEYBOARD:
  188. Windows calls the WH_KEYBOARD filter function whenever the application calls
  189. the %GetMessage% or %PeekMessage% function and there is a keyboard event
  190. (WM_KEYUP or WM_KEYDOWN) to process.
  191. The filter function must use the Pascal calling convention and must be
  192. declared %FAR%. The filter function must have the following form:
  193. DWORD FAR PASCAL <FilterFunc>(<nCode>, <wParam>, <lParam>)
  194. int <nCode>;
  195. WORD <wParam>; DWORD <lParam>;
  196. <FilterFunc> is a placeholder for the library-supplied function name. The
  197. actual name must be exported by including it in an %EXPORTS% statement in
  198. the library's module-definition file.
  199. <nCode>
  200. Specifies whether the filter function should process the message or call
  201. the DefHookProc function. If this value is HC_NOREMOVE, the application
  202. is using the PeekMessage function with the PM_NOREMOVE option and the
  203. message will not be removed from the system queue. If this value is less
  204. than zero, the filter function should pass the message to DefHookProc
  205. without further processing.
  206. <wParam>
  207. Specifies the virtual-key code of the given key.
  208. <lParam>
  209. Specifies the repeat count, scan code, key-transition code, previous key
  210. state, and context code, as shown in the following list. Bit 1 is the
  211. low-order bit:
  212. 0-15
  213. (low-order word) Repeat count (the number of times the keystroke is
  214. repeated as a result of the user holding down the key).
  215. 16-23
  216. (low byte of high-order word) Scan code (OEM-dependent value).
  217. 24
  218. Extended key (1 if it is an extended key).
  219. 25-26
  220. Not used.
  221. 27-28
  222. (Context code (1 if the ^ALT^ key was held down while the key was
  223. pressed, 0 otherwise) Used internally by Windows.
  224. 30
  225. Previous key state (1 if the key was held down before the message was
  226. sent, 0 if the key was up).
  227. 31
  228. Transition state (1 if the key is being released, 0 if the key is being
  229. pressed).
  230. The return value specifies what should happen to the message. It is zero if
  231. the message should be processed by Windows; it is 1 if the message should be
  232. discarded.
  233. WH_MSGFILTER:
  234. Windows calls the WH_MSGFILTER filter function whenever a dialog box,
  235. message box, or menu has retrieved a message, and before it has processed
  236. that message. The filter allows an application to process or modify the
  237. messages.
  238. This is the only task-specific filter. A task may install this filter.
  239. The WH_MSGFILTER filter function must use the Pascal calling convention and
  240. must be declared %FAR%. The filter function must have the following form:
  241. DWORD FAR PASCAL <FilterFunc>(<nCode>, <wParam>, <lParam>)
  242. int <nCode>;
  243. WORD <wParam>;
  244. DWORD <lParam>;
  245. <FilterFunc> is a placeholder for the library- or application-supplied
  246. function name. The actual name must be exported by including it in an
  247. %EXPORTS% statement in the application's module-definition file.
  248. <nCode>
  249. Specifies the type of message being processed. It must be one of the
  250. following values:
  251. MSGF_MENU
  252. Processing keyboard and mouse messages in a menu.
  253. MSGF_MENU
  254. Processing keyboard and mouse messages in a menu.
  255. If the <nCode> parameter is less than zero, the filter function must
  256. pass the message to %DefHookProc% without further processing and return
  257. the value returned by %DefHookProc%.
  258. <wParam>
  259. Specifies a NULL value.
  260. <lParam>
  261. Points to the message structure.
  262. The return value specifies the outcome of the function. It is nonzero if the
  263. hook function processes the message. Otherwise, it is zero.
  264. WH_SYSMSGFILTER:
  265. Windows calls the WH_SYSMSGFILTER filter function whenever a dialog box,
  266. message box, or menu has retrieved a message and before it has processed
  267. that message. The filter allows an application to process or modify messages
  268. for any application in the system.
  269. The filter function must use the Pascal calling convention and must be
  270. declared %FAR%. The filter function must have the following form:
  271. DWORD FAR PASCAL <FilterFunc>(<nCode>, <wParam>, <lParam>)
  272. int <nCode>;
  273. WORD <wParam>;
  274. DWORD <lParam>;
  275. <FilterFunc> is a placeholder for the library-supplied function name. The
  276. actual name must be exported by including it in an %EXPORTS% statement in
  277. the library's module-definition file.
  278. <nCode>
  279. Specifies the type of message being processed. It must be one of the
  280. following values:
  281. MSGF_MENU
  282. Processing keyboard and mouse messages in menu.
  283. MSGF_MESSAGEBOX
  284. Processing messages inside the %MessageBox% function.
  285. If the <nCode> parameter is less than zero, the filter function must
  286. pass the message to %DefHookProc% without further processing and return
  287. the value returned by %DefHookProc%.
  288. <wParam>
  289. Specifies a NULL value.
  290. <lParam>
  291. Points to the message structure.
  292. The return value specifies the outcome of the function. It is nonzero if the
  293. hook function processes the message. Otherwise, it is zero.
  294. --*/
  295. ULONG FASTCALL WU32SetWindowsHookInternal(PVDMFRAME pFrame)
  296. {
  297. ULONG ul;
  298. register PSETWINDOWSHOOKINTERNAL16 parg16;
  299. HOOKSTATEDATA HkData;
  300. HAND16 hMod16;
  301. INT iHook;
  302. DWORD Proc16;
  303. DWORD ThreadId;
  304. PTD ptd = CURRENTPTD();
  305. GETARGPTR(pFrame, sizeof(SETWINDOWSHOOKINTERNAL16), parg16);
  306. hMod16 = FETCHWORD(parg16->f1);
  307. iHook = INT32(parg16->f2);
  308. Proc16 = DWORD32(parg16->f3);
  309. //
  310. // HACKHACK - Work around MS Mail 3.0's journal record hook.
  311. // This hook is used only to keep track of the input
  312. // activity in the system. When the hook is called,
  313. // Mail simply stores the current time. Later, on
  314. // expiration of a timer, Mail determines whether or
  315. // not to start background database compression, using
  316. // the amount of time since input was received as a
  317. // determining factor. If the hook hasn't been called
  318. // in a while, Mail is more likely to start slow
  319. // compression or switch to fast compression.
  320. //
  321. // The problem is that WH_JOURNALRECORD causes all
  322. // threads in the system to share one input queue,
  323. // thereby meaning that any app that stops processing
  324. // input hangs the entire UI.
  325. //
  326. // For now, just disable the hook.
  327. //
  328. if (WH_JOURNALRECORD == iHook &&
  329. (ptd->dwWOWCompatFlags & WOWCF_FAKEJOURNALRECORDHOOK)) {
  330. return 0;
  331. }
  332. /*
  333. ** Micrografx Draw installs a hook, then when minimized, it unhooks the
  334. ** hook by re-hooking the return value from the original hook call.
  335. ** This works in Win 3.1 because the hook return value is a proc address.
  336. ** We can detect this by looking at the HIWORD of the proc address. If
  337. ** it is NULL, we assume they are passing us a hook handle instead of
  338. ** a proc address. If this is the case, then what they really want is
  339. ** unhooking. -BobDay
  340. */
  341. if ( HIWORD(Proc16) == HOOK_ID ) {
  342. ul = GETBOOL16(UnhookWindowsHookEx(W32FreeHHookOfIndex(GETHHOOKINDEX(Proc16))));
  343. FREEARGPTR(parg16);
  344. return( ul );
  345. }
  346. if (!(ul = (ULONG)W32IsDuplicateHook(iHook, Proc16, ptd->htask16))) {
  347. if (W32GetThunkHookProc(iHook, Proc16, &HkData)) {
  348. // We pass threadid=0, for all hooks except WH_MSGFILTER.
  349. // because it is the only task-specific filter in WIN30.
  350. //
  351. // The understanding between USER and WOW is this:
  352. // When a WOW thread sets a hook, with thread ID = 0,
  353. // USER does the following:
  354. // If Journal Hooks are being set, USER will set the
  355. // WOW hook 'globally', ie. system wide.
  356. //
  357. // For all the other hooks, USER sets the hook for all
  358. // 'WOW' threads i.e., the hook is global for the WOW
  359. // process.
  360. //
  361. // If the threadiD != 0, then no special processing is done.
  362. // the hook is set only for that particular thread.
  363. //
  364. if (iHook == (INT)WH_MSGFILTER)
  365. ThreadId = (DWORD)THREADID32(HkData.TaskId);
  366. else
  367. ThreadId = 0;
  368. ul = (ULONG)SetWindowsHookEx(iHook, (HOOKPROC)HkData.Proc32,
  369. (HINSTANCE)HkData.hMod, ThreadId);
  370. HkData.hHook = (HANDLE)ul;
  371. HkData.hMod16 = hMod16;
  372. // Excel looks at the hiword; so instead of passing back just an
  373. // index we make the hiword a hook identifier.
  374. if (ul == (ULONG)NULL)
  375. HkData.InUse = FALSE;
  376. else
  377. ul = MAKEHHOOK(HkData.iIndex);
  378. W32SetHookStateData(&HkData);
  379. }
  380. else
  381. ul = (ULONG)NULL;
  382. }
  383. FREEARGPTR(parg16);
  384. RETURN(ul);
  385. }
  386. /*++
  387. BOOL UnhookWindowsHook(<nHook>, <lpfnHook>)
  388. The %UnhookWindowsHook% function removes the Windows hook function pointed
  389. to by the <lpfnHook> parameter from a chain of hook functions. A Windows
  390. hook function processes events before they are sent to an application's
  391. message loop in the WinMain function.
  392. <nHook>
  393. int Specifies the type of hook function removed. It may be one of the
  394. following values:
  395. WH_CALLWNDPROC
  396. Installs a window-function filter.
  397. WH_GETMESSAGE
  398. Installs a message filter.
  399. WH_JOURNALPLAYBACK
  400. Installs a journaling playback filter.
  401. WH_JOURNALRECORD
  402. Installs a journaling record filter.
  403. WH_KEYBOARD
  404. Install a keyboard filter.
  405. WH_MSGFILTER
  406. Installs a message filter.
  407. The return value specifies the outcome of the function. It is TRUE if the
  408. hook function is successfully removed. Otherwise, it is FALSE.
  409. --*/
  410. ULONG FASTCALL WU32UnhookWindowsHook(PVDMFRAME pFrame)
  411. {
  412. ULONG ul;
  413. register PUNHOOKWINDOWSHOOK16 parg16;
  414. INT iHook;
  415. DWORD Proc16;
  416. GETARGPTR(pFrame, sizeof(UNHOOKWINDOWSHOOK16), parg16);
  417. iHook = INT32(parg16->f1);
  418. Proc16 = DWORD32(parg16->f2);
  419. ul = GETBOOL16(UnhookWindowsHookEx(W32FreeHHook(iHook, Proc16)));
  420. FREEARGPTR(parg16);
  421. RETURN(ul);
  422. }
  423. /*++
  424. CallNextHookEx - similar to DefHookProc
  425. --*/
  426. ULONG FASTCALL WU32CallNextHookEx(PVDMFRAME pFrame)
  427. {
  428. ULONG ul = 0;
  429. register PCALLNEXTHOOKEX16 parg16;
  430. HOOKSTATEDATA HkData;
  431. ULONG hHook16;
  432. INT nCode;
  433. LONG wParam;
  434. LONG lParam;
  435. DWORD iHookCode;
  436. GETARGPTR(pFrame, sizeof(CALLNEXTHOOKEX16), parg16);
  437. hHook16 = DWORD32(parg16->f1);
  438. nCode = INT32(parg16->f2);
  439. wParam = WORD32(parg16->f3);
  440. lParam = DWORD32(parg16->f4);
  441. if (ISVALIDHHOOK(hHook16)) {
  442. iHookCode = GETHHOOKINDEX(hHook16);
  443. HkData.iIndex = (INT)iHookCode;
  444. if ( W32GetHookStateData( &HkData ) ) {
  445. ul = (ULONG)WU32StdDefHookProc(nCode, wParam, lParam, iHookCode);
  446. }
  447. }
  448. FREEARGPTR(parg16);
  449. RETURN(ul);
  450. }
  451. /*++
  452. SetWindowsHookEx - similar to SetWindowsHook.
  453. --*/
  454. ULONG FASTCALL WU32SetWindowsHookEx(PVDMFRAME pFrame)
  455. {
  456. ULONG ul;
  457. register PSETWINDOWSHOOKEX16 parg16;
  458. HOOKSTATEDATA HkData;
  459. INT iHook;
  460. DWORD Proc16;
  461. GETARGPTR(pFrame, sizeof(SETWINDOWSHOOKEX16), parg16);
  462. iHook = INT32(parg16->f1);
  463. Proc16 = DWORD32(parg16->f2);
  464. if (W32GetThunkHookProc(iHook, Proc16, &HkData)) {
  465. ul = (ULONG)SetWindowsHookEx(iHook, (HOOKPROC)HkData.Proc32,
  466. (HINSTANCE)HkData.hMod, (DWORD)THREADID32(parg16->f4));
  467. HkData.hHook = (HANDLE)ul;
  468. if (ul == (ULONG)NULL) {
  469. HkData.InUse = FALSE;
  470. } else {
  471. ul = MAKEHHOOK(HkData.iIndex);
  472. HkData.hMod16 = GetExePtr16(parg16->f3);
  473. }
  474. W32SetHookStateData(&HkData);
  475. }
  476. else
  477. ul = (ULONG)NULL;
  478. FREEARGPTR(parg16);
  479. RETURN(ul);
  480. }
  481. /*++
  482. UnhookWindowsHookEx - similar to unhookwindowshook
  483. --*/
  484. ULONG FASTCALL WU32UnhookWindowsHookEx(PVDMFRAME pFrame)
  485. {
  486. ULONG ul;
  487. register PUNHOOKWINDOWSHOOKEX16 parg16;
  488. GETARGPTR(pFrame, sizeof(UNHOOKWINDOWSHOOKEX16), parg16);
  489. ul = GETBOOL16(UnhookWindowsHookEx(W32FreeHHookOfIndex(GETHHOOKINDEX(INT32(parg16->f1)))));
  490. FREEARGPTR(parg16);
  491. RETURN(ul);
  492. }