source: trunk/src/user32/HOOK.CPP@ 2912

Last change on this file since 2912 was 2804, checked in by sandervl, 26 years ago

Added new logging feature

File size: 19.8 KB
Line 
1/* $Id: HOOK.CPP,v 1.11 2000-02-16 14:34:02 sandervl Exp $ */
2
3/*
4 * Windows hook functions
5 *
6 * Copyright 1999 Sander van Leeuwen (OS/2 Port)
7 *
8 * Port of Wine code (windows\hook.c; dated 990920)
9 * All 16 bits code removed
10 *
11 * Copyright 1994, 1995 Alexandre Julliard
12 * 1996 Andrew Lewycky
13 *
14 * Based on investigations by Alex Korobka
15 *
16 *
17 * Project Odin Software License can be found in LICENSE.TXT
18 */
19
20/*
21 * Warning!
22 * A HHOOK is a 32-bit handle for compatibility with Windows 3.0 where it was
23 * a pointer to the next function. Now it is in fact composed of a USER heap
24 * handle in the low 16 bits and of a HOOK_MAGIC value in the high 16 bits.
25 */
26
27#include <os2win.h>
28#include "hook.h"
29#include "queue.h"
30#include "task.h"
31#include "winproc.h"
32#include "debugtools.h"
33#include <misc.h>
34#include <heapstring.h>
35#include <vmutex.h>
36#include <wprocess.h>
37
38#define DBG_LOCALLOG DBG_hook
39#include "dbglocal.h"
40
41DEFAULT_DEBUG_CHANNEL(hook)
42
43#include "pshpack1.h"
44
45 /* Hook data (pointed to by a HHOOK) */
46typedef struct
47{
48 HANDLE next; /* 00 Next hook in chain */
49 HOOKPROC proc; /* 04 Hook procedure (original) */
50 INT id; /* 08 Hook id (WH_xxx) */
51 DWORD ownerThread; /* 0C Owner thread (0 for system hook) */
52 HMODULE ownerModule; /* 10 Owner module */
53 DWORD flags; /* 14 flags */
54 DWORD magic; /* 18 magic dword */
55} HOOKDATA;
56
57#include "poppack.h"
58
59#define HOOK_MAGIC1 ((int)'H' | (int)'K' << 8) /* 'HK' */
60#define HOOK_MAGIC ((HOOK_MAGIC1<<16)|HOOK_MAGIC1) // 'HKHK'
61
62#define CHECK_MAGIC(a) ((a != 0) && (((HOOKDATA *)a)->magic == HOOK_MAGIC))
63
64//Global DLL Data
65#pragma data_seg(_GLOBALDATA)
66static HANDLE HOOK_systemHooks[WH_NB_HOOKS] = { 0 };
67static VMutex systemHookMutex(TRUE);
68#pragma data_seg()
69static HANDLE HOOK_threadHooks[WH_NB_HOOKS] = { 0 };
70static VMutex threadHookMutex;
71
72typedef VOID (*HOOK_MapFunc)(INT, INT, WPARAM *, LPARAM *);
73typedef VOID (*HOOK_UnMapFunc)(INT, INT, WPARAM, LPARAM, WPARAM,
74 LPARAM);
75
76/***********************************************************************
77 * HOOK_Map32ATo32W
78 */
79static void HOOK_Map32ATo32W(INT id, INT code, WPARAM *pwParam,
80 LPARAM *plParam)
81{
82 if (id == WH_CBT && code == HCBT_CREATEWND)
83 {
84 LPCBT_CREATEWNDA lpcbtcwA = (LPCBT_CREATEWNDA)*plParam;
85 LPCBT_CREATEWNDW lpcbtcwW = (LPCBT_CREATEWNDW)HeapAlloc(GetProcessHeap(), 0,
86 sizeof(*lpcbtcwW) );
87 lpcbtcwW->lpcs = (CREATESTRUCTW*)HeapAlloc( GetProcessHeap(), 0, sizeof(*lpcbtcwW->lpcs) );
88
89 lpcbtcwW->hwndInsertAfter = lpcbtcwA->hwndInsertAfter;
90 *lpcbtcwW->lpcs = *(LPCREATESTRUCTW)lpcbtcwA->lpcs;
91
92 if (HIWORD(lpcbtcwA->lpcs->lpszName))
93 {
94 lpcbtcwW->lpcs->lpszName = HEAP_strdupAtoW( GetProcessHeap(), 0,
95 lpcbtcwA->lpcs->lpszName );
96 }
97 else
98 lpcbtcwW->lpcs->lpszName = (LPWSTR)lpcbtcwA->lpcs->lpszName;
99
100 if (HIWORD(lpcbtcwA->lpcs->lpszClass))
101 {
102 lpcbtcwW->lpcs->lpszClass = HEAP_strdupAtoW( GetProcessHeap(), 0,
103 lpcbtcwA->lpcs->lpszClass );
104 }
105 else
106 lpcbtcwW->lpcs->lpszClass = (LPCWSTR)lpcbtcwA->lpcs->lpszClass;
107 *plParam = (LPARAM)lpcbtcwW;
108 }
109 return;
110}
111
112
113/***********************************************************************
114 * HOOK_UnMap32ATo32W
115 */
116static void HOOK_UnMap32ATo32W(INT id, INT code, WPARAM wParamOrig,
117 LPARAM lParamOrig, WPARAM wParam,
118 LPARAM lParam)
119{
120 if (id == WH_CBT && code == HCBT_CREATEWND)
121 {
122 LPCBT_CREATEWNDW lpcbtcwW = (LPCBT_CREATEWNDW)lParam;
123 if (HIWORD(lpcbtcwW->lpcs->lpszName))
124 HeapFree( GetProcessHeap(), 0, (LPWSTR)lpcbtcwW->lpcs->lpszName );
125 if (HIWORD(lpcbtcwW->lpcs->lpszClass))
126 HeapFree( GetProcessHeap(), 0, (LPWSTR)lpcbtcwW->lpcs->lpszClass );
127 HeapFree( GetProcessHeap(), 0, lpcbtcwW->lpcs );
128 HeapFree( GetProcessHeap(), 0, lpcbtcwW );
129 }
130 return;
131}
132
133
134/***********************************************************************
135 * HOOK_Map32WTo32A
136 */
137static void HOOK_Map32WTo32A(INT id, INT code, WPARAM *pwParam,
138 LPARAM *plParam)
139{
140 if (id == WH_CBT && code == HCBT_CREATEWND)
141 {
142 LPCBT_CREATEWNDW lpcbtcwW = (LPCBT_CREATEWNDW)*plParam;
143 LPCBT_CREATEWNDA lpcbtcwA = (LPCBT_CREATEWNDA)HeapAlloc(GetProcessHeap(), 0,
144 sizeof(*lpcbtcwA) );
145 lpcbtcwA->lpcs = (CREATESTRUCTA*)HeapAlloc( GetProcessHeap(), 0, sizeof(*lpcbtcwA->lpcs) );
146
147 lpcbtcwA->hwndInsertAfter = lpcbtcwW->hwndInsertAfter;
148 *lpcbtcwA->lpcs = *(LPCREATESTRUCTA)lpcbtcwW->lpcs;
149
150 if (HIWORD(lpcbtcwW->lpcs->lpszName))
151 lpcbtcwA->lpcs->lpszName = HEAP_strdupWtoA( GetProcessHeap(), 0,
152 lpcbtcwW->lpcs->lpszName );
153 else
154 lpcbtcwA->lpcs->lpszName = (LPSTR)lpcbtcwW->lpcs->lpszName;
155
156 if (HIWORD(lpcbtcwW->lpcs->lpszClass))
157 lpcbtcwA->lpcs->lpszClass = HEAP_strdupWtoA( GetProcessHeap(), 0,
158 lpcbtcwW->lpcs->lpszClass );
159 else
160 lpcbtcwA->lpcs->lpszClass = (LPSTR)lpcbtcwW->lpcs->lpszClass;
161 *plParam = (LPARAM)lpcbtcwA;
162 }
163 return;
164}
165
166
167/***********************************************************************
168 * HOOK_UnMap32WTo32A
169 */
170static void HOOK_UnMap32WTo32A(INT id, INT code, WPARAM wParamOrig,
171 LPARAM lParamOrig, WPARAM wParam,
172 LPARAM lParam)
173{
174 if (id == WH_CBT && code == HCBT_CREATEWND)
175 {
176 LPCBT_CREATEWNDA lpcbtcwA = (LPCBT_CREATEWNDA)lParam;
177 if (HIWORD(lpcbtcwA->lpcs->lpszName))
178 HeapFree( GetProcessHeap(), 0, (LPSTR)lpcbtcwA->lpcs->lpszName );
179 if (HIWORD(lpcbtcwA->lpcs->lpszClass))
180 HeapFree( GetProcessHeap(), 0, (LPSTR)lpcbtcwA->lpcs->lpszClass );
181 HeapFree( GetProcessHeap(), 0, lpcbtcwA->lpcs );
182 HeapFree( GetProcessHeap(), 0, lpcbtcwA );
183 }
184 return;
185}
186
187
188/***********************************************************************
189 * Map Function Tables
190 */
191static const HOOK_MapFunc HOOK_MapFuncs[3][3] =
192{
193 { NULL, NULL, NULL },
194 { NULL, NULL, HOOK_Map32ATo32W },
195 { NULL, HOOK_Map32WTo32A, NULL }
196};
197
198static const HOOK_UnMapFunc HOOK_UnMapFuncs[3][3] =
199{
200 { NULL, NULL, NULL },
201 { NULL, NULL, HOOK_UnMap32ATo32W },
202 { NULL, HOOK_UnMap32WTo32A, NULL }
203};
204
205
206/***********************************************************************
207 * Internal Functions
208 */
209
210/***********************************************************************
211 * HOOK_GetNextHook
212 *
213 * Get the next hook of a given hook.
214 */
215static HANDLE HOOK_GetNextHook( HANDLE hook )
216{
217 HOOKDATA *data = (HOOKDATA *)hook;
218
219 if (!data || !hook) return 0;
220 if (data->next) return data->next;
221 if (!data->ownerThread) return 0; /* Already system hook */
222
223 /* Now start enumerating the system hooks */
224 return HOOK_systemHooks[data->id - WH_MINHOOK];
225}
226
227
228/***********************************************************************
229 * HOOK_GetHook
230 *
231 * Get the first hook for a given type.
232 */
233static HANDLE HOOK_GetHook( INT id, DWORD threadId )
234{
235 MESSAGEQUEUE *queue;
236 HANDLE hook = 0;
237 THDB *thdb;
238
239 thdb = GetTHDBFromThreadId(threadId);
240 if(thdb) {
241 hook = thdb->hooks[id - WH_MINHOOK];
242 }
243 if (!hook) hook = HOOK_systemHooks[id - WH_MINHOOK];
244
245 return hook;
246}
247
248
249/***********************************************************************
250 * HOOK_SetHook
251 *
252 * Install a given hook.
253 */
254static HHOOK HOOK_SetHook( INT id, LPVOID proc, INT type,
255 HMODULE hModule, DWORD dwThreadId )
256{
257 HOOKDATA *data;
258 THDB *thdb;
259
260 if ((id < WH_MINHOOK) || (id > WH_MAXHOOK) || !proc )
261 {
262 SetLastError(ERROR_INVALID_PARAMETER);
263 return 0;
264 }
265
266 dprintf(("Setting hook %d: %08x %04x %08lx\n",
267 id, (UINT)proc, hModule, dwThreadId ));
268
269#ifndef __WIN32OS2__
270 /* Create task queue if none present */
271 GetFastQueue16();
272
273 if (id == WH_JOURNALPLAYBACK) EnableHardwareInput16(FALSE);
274#endif
275
276
277 if (dwThreadId) /* Task-specific hook */
278 {
279 if ((id == WH_JOURNALRECORD) || (id == WH_JOURNALPLAYBACK) ||
280 (id == WH_SYSMSGFILTER)) {
281 SetLastError(ERROR_INVALID_PARAMETER);
282 return 0; /* System-only hooks */
283 }
284 }
285
286 /* Create the hook structure */
287
288 data = (HOOKDATA *) HeapAlloc(GetProcessHeap(), 0, sizeof(HOOKDATA));
289 data->proc = (HOOKPROC)proc;
290 data->id = id;
291 data->ownerThread = dwThreadId;
292 data->ownerModule = hModule;
293 data->flags = type;
294 data->magic = HOOK_MAGIC;
295
296 /* Insert it in the correct linked list */
297 if(dwThreadId)
298 {
299 thdb = GetTHDBFromThreadId(dwThreadId);
300 if(!thdb) {
301 dprintf(("HOOK_SetHook: can't find thread database for thread %x", dwThreadId));
302 return 0;
303 }
304 threadHookMutex.enter();
305 data->next = thdb->hooks[id - WH_MINHOOK];
306 thdb->hooks[id - WH_MINHOOK] = (DWORD)data;
307 threadHookMutex.leave();
308 }
309 else
310 {
311 systemHookMutex.enter();
312 data->next = HOOK_systemHooks[id - WH_MINHOOK];
313 HOOK_systemHooks[id - WH_MINHOOK] = (HANDLE)data;
314 systemHookMutex.leave();
315 }
316
317 return (HHOOK)data;
318}
319
320
321/***********************************************************************
322 * HOOK_RemoveHook
323 *
324 * Remove a hook from the list.
325 */
326static BOOL HOOK_RemoveHook( HOOKDATA *data )
327{
328 HOOKDATA **prevHook;
329 THDB *thdb;
330 VMutex *hookMutex;
331
332 dprintf(("Removing hook %08x\n", data));
333
334 if (data->flags & HOOK_INUSE)
335 {
336 /* Mark it for deletion later on */
337 dprintf(("Hook still running, deletion delayed\n" ));
338 data->flags |= HOOK_DELAYED_DELETE;
339 return TRUE;
340 }
341
342#ifndef __WIN32OS2__
343 if (data->id == WH_JOURNALPLAYBACK) EnableHardwareInput16(TRUE);
344#endif
345
346 /* Remove it from the linked list */
347
348 if (data->ownerThread)
349 {
350 thdb = GetTHDBFromThreadId(data->ownerThread);
351 if(!thdb) {
352 dprintf(("HOOK_RemoveHook: can't find thread database for thread %x", data->ownerThread));
353 return FALSE;
354 }
355 hookMutex = &threadHookMutex;
356 hookMutex->enter();
357 prevHook = (HOOKDATA **)&thdb->hooks[data->id - WH_MINHOOK];
358 }
359 else {
360 hookMutex = &systemHookMutex;
361 hookMutex->enter();
362 prevHook = (HOOKDATA **)&HOOK_systemHooks[data->id - WH_MINHOOK];
363 }
364 while (*prevHook && *prevHook != data)
365 prevHook = (HOOKDATA **)&(*prevHook)->next;
366
367 if (!prevHook) {
368 hookMutex->leave();
369 return FALSE;
370 }
371 *prevHook = (HOOKDATA *)data->next;
372 hookMutex->leave();
373
374 HeapFree(GetProcessHeap(), 0, (LPVOID)data );
375 return TRUE;
376}
377
378
379/***********************************************************************
380 * HOOK_FindValidHook
381 */
382static HANDLE HOOK_FindValidHook( HANDLE hook )
383{
384 HOOKDATA *data;
385
386 for (;;)
387 {
388 if (!(data = (HOOKDATA *)hook)) return 0;
389 if (data->proc) return hook;
390 hook = data->next;
391 }
392}
393
394
395/***********************************************************************
396 * HOOK_CallHook
397 *
398 * Call a hook procedure.
399 */
400static LRESULT HOOK_CallHook( HANDLE hook, INT fromtype, INT code,
401 WPARAM wParam, LPARAM lParam )
402{
403 MESSAGEQUEUE *queue;
404 HANDLE prevHook;
405 HOOKDATA *data = (HOOKDATA *)hook;
406 LRESULT ret;
407
408 WPARAM wParamOrig = wParam;
409 LPARAM lParamOrig = lParam;
410 HOOK_MapFunc MapFunc;
411 HOOK_UnMapFunc UnMapFunc;
412
413 MapFunc = HOOK_MapFuncs[fromtype][data->flags & HOOK_MAPTYPE];
414 UnMapFunc = HOOK_UnMapFuncs[fromtype][data->flags & HOOK_MAPTYPE];
415
416 if (MapFunc)
417 MapFunc( data->id, code, &wParam, &lParam );
418
419 /* Now call it */
420
421 data->flags |= HOOK_INUSE;
422
423 dprintf2(("Calling hook %04x: %d %08x %08lx\n", hook, code, wParam, lParam ));
424
425 ret = data->proc(code, wParam, lParam);
426
427 data->flags &= ~HOOK_INUSE;
428
429 if (UnMapFunc)
430 UnMapFunc( data->id, code, wParamOrig, lParamOrig, wParam, lParam );
431
432 if(data->flags & HOOK_DELAYED_DELETE) HOOK_RemoveHook( data );
433
434 return ret;
435}
436
437/***********************************************************************
438 * Exported Functions & APIs
439 */
440
441/***********************************************************************
442 * HOOK_IsHooked
443 *
444 * Replacement for calling HOOK_GetHook from other modules.
445 */
446BOOL HOOK_IsHooked( INT id )
447{
448 /* Hmmm. Use GetThreadQueue(0) instead of GetFastQueue() here to
449 avoid queue being created if someone wants to merely check ... */
450
451 return HOOK_GetHook( id, GetCurrentThreadId() ) != 0;
452}
453
454/***********************************************************************
455 * HOOK_CallHooks32A
456 *
457 * Call a hook chain.
458 */
459LRESULT HOOK_CallHooksA( INT id, INT code, WPARAM wParam,
460 LPARAM lParam )
461{
462 HANDLE hook;
463
464 if (!(hook = HOOK_GetHook( id, GetCurrentThreadId() ))) return 0;
465 if (!(hook = HOOK_FindValidHook(hook))) return 0;
466 return HOOK_CallHook( hook, HOOK_WIN32A, code, wParam, lParam );
467}
468
469/***********************************************************************
470 * HOOK_CallHooks32W
471 *
472 * Call a hook chain.
473 */
474LRESULT HOOK_CallHooksW( INT id, INT code, WPARAM wParam,
475 LPARAM lParam )
476{
477 HANDLE hook;
478
479 if (!(hook = HOOK_GetHook( id, GetCurrentThreadId() ))) return 0;
480 if (!(hook = HOOK_FindValidHook(hook))) return 0;
481 return HOOK_CallHook( hook, HOOK_WIN32W, code, wParam,
482 lParam );
483}
484
485
486#if 0
487/***********************************************************************
488 * HOOK_ResetQueueHooks
489 */
490void HOOK_ResetQueueHooks( HQUEUE hQueue )
491{
492 MESSAGEQUEUE *queue;
493
494 if ((queue = (MESSAGEQUEUE *)QUEUE_Lock( hQueue )) != NULL)
495 {
496 HOOKDATA* data;
497 HHOOK hook;
498 int id;
499 for( id = WH_MINHOOK; id <= WH_MAXHOOK; id++ )
500 {
501 hook = queue->hooks[id - WH_MINHOOK];
502 while( hook )
503 {
504 if( (data = (HOOKDATA *)hook) )
505 {
506 data->ownerQueue = hQueue;
507 hook = data->next;
508 } else break;
509 }
510 }
511
512 QUEUE_Unlock( queue );
513 }
514}
515#endif
516
517/***********************************************************************
518 * HOOK_FreeModuleHooks
519 */
520void HOOK_FreeModuleHooks( HMODULE hModule )
521{
522 /* remove all system hooks registered by this module */
523
524 HOOKDATA* hptr;
525 HHOOK hook, next;
526 int id;
527
528 for( id = WH_MINHOOK; id <= WH_MAXHOOK; id++ )
529 {
530 hook = HOOK_systemHooks[id - WH_MINHOOK];
531 while( hook )
532 {
533 hptr = (HOOKDATA *)hook;
534 if (hptr)
535 {
536 next = hptr->next;
537 if( hptr->ownerModule == hModule )
538 {
539 hptr->flags &= HOOK_MAPTYPE;
540 HOOK_RemoveHook(hptr);
541 }
542 hook = next;
543 }
544 else hook = 0;
545 }
546 }
547}
548
549/***********************************************************************
550 * HOOK_FreeQueueHooks
551 */
552void HOOK_FreeQueueHooks( DWORD threadId )
553{
554 /* remove all hooks registered by this queue */
555
556 HOOKDATA* hptr = NULL;
557 HHOOK hook, next;
558 int id;
559
560 for( id = WH_MINHOOK; id <= WH_MAXHOOK; id++ )
561 {
562 hook = HOOK_GetHook( id, threadId );
563 while( hook )
564 {
565 next = HOOK_GetNextHook(hook);
566
567 hptr = (HOOKDATA *)hook;
568 if( hptr && hptr->ownerThread == threadId )
569 {
570 hptr->flags &= HOOK_MAPTYPE;
571 HOOK_RemoveHook(hptr);
572 }
573 hook = next;
574 }
575 }
576}
577
578
579/***********************************************************************
580 * SetWindowsHook32A (USER32.525)
581 */
582HHOOK WINAPI SetWindowsHookA( INT id, HOOKPROC proc )
583{
584 return SetWindowsHookExA( id, proc, 0, GetCurrentThreadId() );
585}
586
587/***********************************************************************
588 * SetWindowsHook32W (USER32.528)
589 */
590HHOOK WINAPI SetWindowsHookW( INT id, HOOKPROC proc )
591{
592 return SetWindowsHookExW( id, proc, 0, GetCurrentThreadId() );
593}
594
595/***********************************************************************
596 * SetWindowsHookEx32A (USER32.526)
597 */
598HHOOK WINAPI SetWindowsHookExA( INT id, HOOKPROC proc, HINSTANCE hInst,
599 DWORD dwThreadId )
600{
601 return HOOK_SetHook( id, proc, HOOK_WIN32A, hInst, dwThreadId );
602}
603
604/***********************************************************************
605 * SetWindowsHookEx32W (USER32.527)
606 */
607HHOOK WINAPI SetWindowsHookExW( INT id, HOOKPROC proc, HINSTANCE hInst,
608 DWORD dwThreadId )
609{
610 return HOOK_SetHook( id, proc, HOOK_WIN32W, hInst, dwThreadId );
611}
612
613/***********************************************************************
614 * UnhookWindowsHook32 (USER32.557)
615 */
616BOOL WINAPI UnhookWindowsHook( INT id, HOOKPROC proc )
617{
618 HANDLE hook = HOOK_GetHook( id, GetCurrentThreadId() );
619
620 dprintf(("UnhookWindowsHook: %d %08lx\n", id, (DWORD)proc ));
621
622 while (hook)
623 {
624 HOOKDATA *data = (HOOKDATA *)hook;
625 if (data->proc == proc) break;
626 hook = HOOK_GetNextHook( hook );
627 }
628 if (!hook) return FALSE;
629 return HOOK_RemoveHook( (HOOKDATA *)hook );
630}
631
632
633/***********************************************************************
634 * UnhookWindowHookEx32 (USER32.558)
635 */
636BOOL WINAPI UnhookWindowsHookEx( HHOOK hhook )
637{
638 if (CHECK_MAGIC(hhook) == FALSE)
639 return FALSE;
640
641 return HOOK_RemoveHook( (HOOKDATA *)hhook );
642}
643
644/***********************************************************************
645 * CallNextHookEx32 (USER32.17)
646 *
647 * There aren't ANSI and UNICODE versions of this.
648 */
649LRESULT WINAPI CallNextHookEx( HHOOK hhook, INT code, WPARAM wParam,
650 LPARAM lParam )
651{
652 HANDLE next;
653 INT fromtype; /* figure out Ansi/Unicode */
654 HOOKDATA *oldhook;
655
656 if (CHECK_MAGIC(hhook) == FALSE)
657 return FALSE;
658
659 if (!(next = HOOK_GetNextHook( hhook ))) return 0;
660
661 oldhook = (HOOKDATA *)hhook ;
662 fromtype = oldhook->flags & HOOK_MAPTYPE;
663
664 return HOOK_CallHook( next, fromtype, code, wParam, lParam );
665}
666
667
668/***********************************************************************
669 * CallMsgFilter32A (USER32.15)
670 */
671/*
672 * FIXME: There are ANSI and UNICODE versions of this, plus an unspecified
673 * version, plus USER (the 16bit one) has a CallMsgFilter32 function.
674 */
675BOOL WINAPI CallMsgFilterA( LPMSG msg, INT code )
676{
677#if 0 //CB: not a Win32 API and unimplemented
678 if (GetSysModalWindow()) return FALSE; /* ??? */
679#endif
680 if (HOOK_CallHooksA( WH_SYSMSGFILTER, code, 0, (LPARAM)msg ))
681 return TRUE;
682 return HOOK_CallHooksA( WH_MSGFILTER, code, 0, (LPARAM)msg );
683}
684
685
686/***********************************************************************
687 * CallMsgFilter32W (USER32.16)
688 */
689BOOL WINAPI CallMsgFilterW( LPMSG msg, INT code )
690{
691#if 0 //CB: not a Win32 API and unimplemented
692 if (GetSysModalWindow()) return FALSE; /* ??? */
693#endif
694 if (HOOK_CallHooksW( WH_SYSMSGFILTER, code, 0, (LPARAM)msg ))
695 return TRUE;
696 return HOOK_CallHooksW( WH_MSGFILTER, code, 0, (LPARAM)msg );
697}
698
Note: See TracBrowser for help on using the repository browser.