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

Last change on this file since 2768 was 2768, checked in by cbratschi, 26 years ago

added v5.00 messages

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