- Remove cooked hardware messages when they are dropped (reported by
[wine] / windows / message.c
1 /*
2  * Message queues related functions
3  *
4  * Copyright 1993, 1994 Alexandre Julliard
5  */
6
7 #include <stdlib.h>
8 #include <string.h>
9 #include <ctype.h>
10 #include <sys/time.h>
11 #include <sys/types.h>
12
13 #include "wine/winbase16.h"
14 #include "wine/winuser16.h"
15 #include "message.h"
16 #include "winerror.h"
17 #include "server.h"
18 #include "win.h"
19 #include "heap.h"
20 #include "hook.h"
21 #include "input.h"
22 #include "spy.h"
23 #include "winpos.h"
24 #include "dde.h"
25 #include "queue.h"
26 #include "winproc.h"
27 #include "user.h"
28 #include "thread.h"
29 #include "task.h"
30 #include "controls.h"
31 #include "debugtools.h"
32
33 DEFAULT_DEBUG_CHANNEL(msg);
34 DECLARE_DEBUG_CHANNEL(key);
35
36 #define WM_NCMOUSEFIRST         WM_NCMOUSEMOVE
37 #define WM_NCMOUSELAST          WM_NCMBUTTONDBLCLK
38
39 #define QMSG_WIN16    1
40 #define QMSG_WIN32A   2
41 #define QMSG_WIN32W   3
42
43 static UINT doubleClickSpeed = 452;
44
45 static BOOL MSG_ConvertMsg( MSG *msg, int srcType, int dstType );
46
47
48
49 /* flag for messages that contain pointers */
50 /* 16 messages per entry, messages 0..15 map to bits 0..15 */
51
52 #define SET(msg) (1 << ((msg) & 15))
53
54 static const unsigned short message_pointer_flags[] =
55 {
56     /* 0x00 - 0x0f */
57     SET(WM_CREATE) | SET(WM_GETTEXT) | SET(WM_SETTEXT),
58     /* 0x10 - 0x1f */
59     SET(WM_WININICHANGE),
60     /* 0x20 - 0x2f */
61     SET(WM_GETMINMAXINFO) | SET(WM_DRAWITEM) | SET(WM_MEASUREITEM) | SET(WM_DELETEITEM),
62     /* 0x30 - 0x3f */
63     SET(WM_COMPAREITEM),
64     /* 0x40 - 0x4f */
65     SET(WM_WINDOWPOSCHANGING) | SET(WM_WINDOWPOSCHANGED) | SET(WM_COPYDATA) | SET(WM_NOTIFY),
66     /* 0x50 - 0x5f */
67     SET(WM_HELP),
68     /* 0x60 - 0x6f */
69     0,
70     /* 0x70 - 0x7f */
71     SET(WM_STYLECHANGING) | SET(WM_STYLECHANGED),
72     /* 0x80 - 0x8f */
73     SET(WM_NCCREATE) | SET(WM_NCCALCSIZE) | SET(WM_GETDLGCODE),
74     /* 0x90 - 0x9f */
75     0,
76     /* 0xa0 - 0xaf */
77     0,
78     /* 0xb0 - 0xbf */
79     SET(EM_GETSEL) | SET(EM_GETRECT) | SET(EM_SETRECT) | SET(EM_SETRECTNP),
80     /* 0xc0 - 0xcf */
81     SET(EM_REPLACESEL) | SET(EM_GETLINE) | SET(EM_SETTABSTOPS),
82     /* 0xd0 - 0xdf */
83     0,
84     /* 0xe0 - 0xef */
85     0,
86     /* 0xf0 - 0xff */
87     0,
88     /* 0x100 - 0x10f */
89     0,
90     /* 0x110 - 0x11f */
91     0,
92     /* 0x120 - 0x12f */
93     0,
94     /* 0x130 - 0x13f */
95     0,
96     /* 0x140 - 0x14f */
97     SET(CB_ADDSTRING) | SET(CB_DIR) | SET(CB_GETLBTEXT) | SET(CB_INSERTSTRING) |
98     SET(CB_FINDSTRING) | SET(CB_SELECTSTRING),
99     /* 0x150 - 0x15f */
100     SET(CB_GETDROPPEDCONTROLRECT) | SET(CB_FINDSTRINGEXACT),
101     /* 0x160 - 0x16f */
102     0,
103     /* 0x170 - 0x17f */
104     0,
105     /* 0x180 - 0x18f */
106     SET(LB_ADDSTRING) | SET(LB_INSERTSTRING) | SET(LB_GETTEXT) | SET(LB_SELECTSTRING) |
107     SET(LB_DIR) | SET(LB_FINDSTRING),
108     /* 0x190 - 0x19f */
109     SET(LB_GETSELITEMS) | SET(LB_SETTABSTOPS) | SET(LB_ADDFILE) | SET(LB_GETITEMRECT),
110     /* 0x1a0 - 0x1af */
111     SET(LB_FINDSTRINGEXACT),
112     /* 0x1b0 - 0x1bf */
113     0,
114     /* 0x1c0 - 0x1cf */
115     0,
116     /* 0x1d0 - 0x1df */
117     0,
118     /* 0x1e0 - 0x1ef */
119     0,
120     /* 0x1f0 - 0x1ff */
121     0,
122     /* 0x200 - 0x20f */
123     0,
124     /* 0x210 - 0x21f */
125     0,
126     /* 0x220 - 0x22f */
127     SET(WM_MDICREATE) | SET(WM_MDIGETACTIVE) | SET(WM_DROPOBJECT) |
128     SET(WM_QUERYDROPOBJECT) | SET(WM_DRAGSELECT) | SET(WM_DRAGMOVE)
129 };
130
131 #undef SET
132
133 /***********************************************************************
134  *           is_pointer_message
135  */
136 inline static int is_pointer_message( UINT message )
137 {
138     if (message >= 8*sizeof(message_pointer_flags)) return FALSE;
139     return (message_pointer_flags[message / 16] & (1 << (message & 15))) != 0;
140 }
141
142
143 /***********************************************************************
144  *           is_keyboard_message
145  */
146 inline static BOOL is_keyboard_message( UINT message )
147 {
148     return (message >= WM_KEYFIRST && message <= WM_KEYLAST);
149 }
150
151
152 /***********************************************************************
153  *           is_mouse_message
154  */
155 inline static BOOL is_mouse_message( UINT message )
156 {
157     return ((message >= WM_NCMOUSEFIRST && message <= WM_NCMOUSELAST) ||
158             (message >= WM_MOUSEFIRST && message <= WM_MOUSELAST));
159 }
160
161
162 /***********************************************************************
163  *           check_message_filter
164  */
165 inline static BOOL check_message_filter( const MSG *msg, HWND hwnd, UINT first, UINT last )
166 {
167     if (hwnd)
168     {
169         if (msg->hwnd != hwnd && !IsChild( hwnd, msg->hwnd )) return FALSE;
170     }
171     if (first || last)
172     {
173        return (msg->message >= first && msg->message <= last);
174     }
175     return TRUE;
176 }
177
178
179 /***********************************************************************
180  *              map_wparam_AtoW
181  *
182  * Convert the wparam of an ASCII message to Unicode.
183  */
184 static WPARAM map_wparam_AtoW( UINT message, WPARAM wparam )
185 {
186     if (message == WM_CHARTOITEM ||
187         message == EM_SETPASSWORDCHAR ||
188         message == WM_CHAR ||
189         message == WM_DEADCHAR ||
190         message == WM_SYSCHAR ||
191         message == WM_SYSDEADCHAR ||
192         message == WM_MENUCHAR)
193     {
194         char ch = LOWORD(wparam);
195         WCHAR wch;
196         MultiByteToWideChar(CP_ACP, 0, &ch, 1, &wch, 1);
197         wparam = MAKEWPARAM( wch, HIWORD(wparam) );
198     }
199     return wparam;
200 }
201
202
203 /***********************************************************************
204  *              map_wparam_WtoA
205  *
206  * Convert the wparam of a Unicode message to ASCII.
207  */
208 static WPARAM map_wparam_WtoA( UINT message, WPARAM wparam )
209 {
210     if (message == WM_CHARTOITEM ||
211         message == EM_SETPASSWORDCHAR ||
212         message == WM_CHAR ||
213         message == WM_DEADCHAR ||
214         message == WM_SYSCHAR ||
215         message == WM_SYSDEADCHAR ||
216         message == WM_MENUCHAR)
217     {
218         WCHAR wch = LOWORD(wparam);
219         char ch;
220         WideCharToMultiByte( CP_ACP, 0, &wch, 1, &ch, 1, NULL, NULL );
221         wparam = MAKEWPARAM( ch, HIWORD(wparam) );
222     }
223     return wparam;
224 }
225
226
227 /***********************************************************************
228  *           queue_hardware_message
229  *
230  * store a hardware message in the thread queue
231  */
232 static void queue_hardware_message( MSG *msg, ULONG_PTR extra_info, enum message_kind kind )
233 {
234     SERVER_START_REQ( send_message )
235     {
236         req->kind   = kind;
237         req->id     = (void *)GetWindowThreadProcessId( msg->hwnd, NULL );
238         req->type   = 0;
239         req->win    = msg->hwnd;
240         req->msg    = msg->message;
241         req->wparam = msg->wParam;
242         req->lparam = msg->lParam;
243         req->x      = msg->pt.x;
244         req->y      = msg->pt.y;
245         req->time   = msg->time;
246         req->info   = extra_info;
247         SERVER_CALL();
248     }
249     SERVER_END_REQ;
250 }
251
252
253 /***********************************************************************
254  *           MSG_SendParentNotify
255  *
256  * Send a WM_PARENTNOTIFY to all ancestors of the given window, unless
257  * the window has the WS_EX_NOPARENTNOTIFY style.
258  */
259 static void MSG_SendParentNotify( HWND hwnd, WORD event, WORD idChild, POINT pt )
260 {
261     WND *tmpWnd = WIN_FindWndPtr(hwnd);
262
263     /* pt has to be in the client coordinates of the parent window */
264     MapWindowPoints( 0, tmpWnd->hwndSelf, &pt, 1 );
265     while (tmpWnd)
266     {
267         if (!(tmpWnd->dwStyle & WS_CHILD) || (tmpWnd->dwExStyle & WS_EX_NOPARENTNOTIFY))
268         {
269             WIN_ReleaseWndPtr(tmpWnd);
270             break;
271         }
272         pt.x += tmpWnd->rectClient.left;
273         pt.y += tmpWnd->rectClient.top;
274         WIN_UpdateWndPtr(&tmpWnd,tmpWnd->parent);
275         SendMessageA( tmpWnd->hwndSelf, WM_PARENTNOTIFY,
276                       MAKEWPARAM( event, idChild ), MAKELPARAM( pt.x, pt.y ) );
277     }
278 }
279
280
281 /***********************************************************************
282  *          MSG_JournalPlayBackMsg
283  *
284  * Get an EVENTMSG struct via call JOURNALPLAYBACK hook function 
285  */
286 static void MSG_JournalPlayBackMsg(void)
287 {
288     EVENTMSG tmpMsg;
289     MSG msg;
290     LRESULT wtime;
291     int keyDown,i;
292
293     if (!HOOK_IsHooked( WH_JOURNALPLAYBACK )) return;
294
295     wtime=HOOK_CallHooksA( WH_JOURNALPLAYBACK, HC_GETNEXT, 0, (LPARAM)&tmpMsg );
296     /*  TRACE(msg,"Playback wait time =%ld\n",wtime); */
297     if (wtime<=0)
298     {
299         wtime=0;
300         msg.message = tmpMsg.message;
301         msg.hwnd    = tmpMsg.hwnd;
302         msg.time    = tmpMsg.time;
303         if ((tmpMsg.message >= WM_KEYFIRST) && (tmpMsg.message <= WM_KEYLAST))
304         {
305             msg.wParam  = tmpMsg.paramL & 0xFF;
306             msg.lParam  = MAKELONG(tmpMsg.paramH&0x7ffff,tmpMsg.paramL>>8);
307             if (tmpMsg.message == WM_KEYDOWN || tmpMsg.message == WM_SYSKEYDOWN)
308             {
309                 for (keyDown=i=0; i<256 && !keyDown; i++)
310                     if (InputKeyStateTable[i] & 0x80)
311                         keyDown++;
312                 if (!keyDown)
313                     msg.lParam |= 0x40000000;
314                 AsyncKeyStateTable[msg.wParam]=InputKeyStateTable[msg.wParam] |= 0x80;
315             }
316             else                                       /* WM_KEYUP, WM_SYSKEYUP */
317             {
318                 msg.lParam |= 0xC0000000;
319                 AsyncKeyStateTable[msg.wParam]=InputKeyStateTable[msg.wParam] &= ~0x80;
320             }
321             if (InputKeyStateTable[VK_MENU] & 0x80)
322                 msg.lParam |= 0x20000000;
323             if (tmpMsg.paramH & 0x8000)              /*special_key bit*/
324                 msg.lParam |= 0x01000000;
325
326             msg.pt.x = msg.pt.y = 0;
327             queue_hardware_message( &msg, 0, RAW_HW_MESSAGE );
328         }
329         else if ((tmpMsg.message>= WM_MOUSEFIRST) && (tmpMsg.message <= WM_MOUSELAST))
330         {
331             switch (tmpMsg.message)
332             {
333             case WM_LBUTTONDOWN:
334                 MouseButtonsStates[0]=AsyncMouseButtonsStates[0]=TRUE;break;
335             case WM_LBUTTONUP:
336                 MouseButtonsStates[0]=AsyncMouseButtonsStates[0]=FALSE;break;
337             case WM_MBUTTONDOWN:
338                 MouseButtonsStates[1]=AsyncMouseButtonsStates[1]=TRUE;break;
339             case WM_MBUTTONUP:
340                 MouseButtonsStates[1]=AsyncMouseButtonsStates[1]=FALSE;break;
341             case WM_RBUTTONDOWN:
342                 MouseButtonsStates[2]=AsyncMouseButtonsStates[2]=TRUE;break;
343             case WM_RBUTTONUP:
344                 MouseButtonsStates[2]=AsyncMouseButtonsStates[2]=FALSE;break;
345             }
346             AsyncKeyStateTable[VK_LBUTTON]= InputKeyStateTable[VK_LBUTTON] = MouseButtonsStates[0] ? 0x80 : 0;
347             AsyncKeyStateTable[VK_MBUTTON]= InputKeyStateTable[VK_MBUTTON] = MouseButtonsStates[1] ? 0x80 : 0;
348             AsyncKeyStateTable[VK_RBUTTON]= InputKeyStateTable[VK_RBUTTON] = MouseButtonsStates[2] ? 0x80 : 0;
349             SetCursorPos(tmpMsg.paramL,tmpMsg.paramH);
350             msg.lParam=MAKELONG(tmpMsg.paramL,tmpMsg.paramH);
351             msg.wParam=0;
352             if (MouseButtonsStates[0]) msg.wParam |= MK_LBUTTON;
353             if (MouseButtonsStates[1]) msg.wParam |= MK_MBUTTON;
354             if (MouseButtonsStates[2]) msg.wParam |= MK_RBUTTON;
355
356             msg.pt.x = tmpMsg.paramL;
357             msg.pt.y = tmpMsg.paramH;
358             queue_hardware_message( &msg, 0, RAW_HW_MESSAGE );
359         }
360         HOOK_CallHooksA( WH_JOURNALPLAYBACK, HC_SKIP, 0, (LPARAM)&tmpMsg);
361     }
362     else
363     {
364         if( tmpMsg.message == WM_QUEUESYNC )
365             if (HOOK_IsHooked( WH_CBT ))
366                 HOOK_CallHooksA( WH_CBT, HCBT_QS, 0, 0L);
367     }
368 }
369
370
371 /***********************************************************************
372  *          process_raw_keyboard_message
373  *
374  * returns TRUE if the contents of 'msg' should be passed to the application
375  */
376 static BOOL process_raw_keyboard_message( MSG *msg, ULONG_PTR extra_info )
377 {
378     if (!(msg->hwnd = GetFocus()))
379     {
380         /* Send the message to the active window instead,  */
381         /* translating messages to their WM_SYS equivalent */
382         msg->hwnd = GetActiveWindow();
383         if (msg->message < WM_SYSKEYDOWN) msg->message += WM_SYSKEYDOWN - WM_KEYDOWN;
384     }
385
386     if (HOOK_IsHooked( WH_JOURNALRECORD ))
387     {
388         EVENTMSG event;
389
390         event.message = msg->message;
391         event.hwnd    = msg->hwnd;
392         event.time    = msg->time;
393         event.paramL  = (msg->wParam & 0xFF) | (HIWORD(msg->lParam) << 8);
394         event.paramH  = msg->lParam & 0x7FFF;
395         if (HIWORD(msg->lParam) & 0x0100) event.paramH |= 0x8000; /* special_key - bit */
396         HOOK_CallHooksA( WH_JOURNALRECORD, HC_ACTION, 0, (LPARAM)&event );
397     }
398
399     return (msg->hwnd != 0);
400 }
401
402
403 /***********************************************************************
404  *          process_cooked_keyboard_message
405  *
406  * returns TRUE if the contents of 'msg' should be passed to the application
407  */
408 static BOOL process_cooked_keyboard_message( MSG *msg, BOOL remove )
409 {
410     if (remove)
411     {
412         /* Handle F1 key by sending out WM_HELP message */
413         if ((msg->message == WM_KEYUP) &&
414             (msg->wParam == VK_F1) &&
415             (msg->hwnd != GetDesktopWindow()) &&
416             !MENU_IsMenuActive())
417         {
418             HELPINFO hi;
419             hi.cbSize = sizeof(HELPINFO);
420             hi.iContextType = HELPINFO_WINDOW;
421             hi.iCtrlId = GetWindowLongA( msg->hwnd, GWL_ID );
422             hi.hItemHandle = msg->hwnd;
423             hi.dwContextId = GetWindowContextHelpId( msg->hwnd );
424             hi.MousePos = msg->pt;
425             SendMessageA(msg->hwnd, WM_HELP, 0, (LPARAM)&hi);
426         }
427     }
428
429     if (HOOK_CallHooksA( WH_KEYBOARD, remove ? HC_ACTION : HC_NOREMOVE,
430                          LOWORD(msg->wParam), msg->lParam ))
431     {
432         /* skip this message */
433         HOOK_CallHooksA( WH_CBT, HCBT_KEYSKIPPED, LOWORD(msg->wParam), msg->lParam );
434         return FALSE;
435     }
436     return TRUE;
437 }
438
439
440 /***********************************************************************
441  *          process_raw_mouse_message
442  *
443  * returns TRUE if the contents of 'msg' should be passed to the application
444  */
445 static BOOL process_raw_mouse_message( MSG *msg, ULONG_PTR extra_info )
446 {
447     static MSG clk_msg;
448
449     POINT pt;
450     INT ht, hittest;
451
452     /* find the window to dispatch this mouse message to */
453
454     hittest = HTCLIENT;
455     if (!(msg->hwnd = PERQDATA_GetCaptureWnd( &ht )))
456     {
457         /* If no capture HWND, find window which contains the mouse position.
458          * Also find the position of the cursor hot spot (hittest) */
459         HWND hWndScope = (HWND)extra_info;
460
461         if (!IsWindow(hWndScope)) hWndScope = 0;
462         if (!(msg->hwnd = WINPOS_WindowFromPoint( hWndScope, msg->pt, &hittest )))
463             msg->hwnd = GetDesktopWindow();
464         ht = hittest;
465     }
466
467     if (HOOK_IsHooked( WH_JOURNALRECORD ))
468     {
469         EVENTMSG event;
470         event.message = msg->message;
471         event.time    = msg->time;
472         event.hwnd    = msg->hwnd;
473         event.paramL  = msg->pt.x;
474         event.paramH  = msg->pt.y;
475         HOOK_CallHooksA( WH_JOURNALRECORD, HC_ACTION, 0, (LPARAM)&event );
476     }
477
478     /* translate double clicks */
479
480     if ((msg->message == WM_LBUTTONDOWN) ||
481         (msg->message == WM_RBUTTONDOWN) ||
482         (msg->message == WM_MBUTTONDOWN))
483     {
484         BOOL update = TRUE;
485         /* translate double clicks -
486          * note that ...MOUSEMOVEs can slip in between
487          * ...BUTTONDOWN and ...BUTTONDBLCLK messages */
488
489         if (GetClassLongA( msg->hwnd, GCL_STYLE ) & CS_DBLCLKS || ht != HTCLIENT )
490         {
491            if ((msg->message == clk_msg.message) &&
492                (msg->hwnd == clk_msg.hwnd) &&
493                (msg->time - clk_msg.time < doubleClickSpeed) &&
494                (abs(msg->pt.x - clk_msg.pt.x) < GetSystemMetrics(SM_CXDOUBLECLK)/2) &&
495                (abs(msg->pt.y - clk_msg.pt.y) < GetSystemMetrics(SM_CYDOUBLECLK)/2))
496            {
497                msg->message += (WM_LBUTTONDBLCLK - WM_LBUTTONDOWN);
498                clk_msg.message = 0;
499                update = FALSE;
500            }
501         }
502         /* update static double click conditions */
503         if (update) clk_msg = *msg;
504     }
505
506     pt = msg->pt;
507     if (hittest != HTCLIENT)
508     {
509         msg->message += WM_NCMOUSEMOVE - WM_MOUSEMOVE;
510         msg->wParam = hittest;
511     }
512     else ScreenToClient( msg->hwnd, &pt );
513     msg->lParam = MAKELONG( pt.x, pt.y );
514     return TRUE;
515 }
516
517
518 /***********************************************************************
519  *          process_cooked_mouse_message
520  *
521  * returns TRUE if the contents of 'msg' should be passed to the application
522  */
523 static BOOL process_cooked_mouse_message( MSG *msg, BOOL remove )
524 {
525     INT hittest = HTCLIENT;
526     UINT raw_message = msg->message;
527     BOOL eatMsg;
528
529     if (msg->message >= WM_NCMOUSEFIRST && msg->message <= WM_NCMOUSELAST)
530     {
531         raw_message += WM_MOUSEFIRST - WM_NCMOUSEFIRST;
532         hittest = msg->wParam;
533     }
534     if (raw_message == WM_LBUTTONDBLCLK ||
535         raw_message == WM_RBUTTONDBLCLK ||
536         raw_message == WM_MBUTTONDBLCLK)
537     {
538         raw_message += WM_LBUTTONDOWN - WM_LBUTTONDBLCLK;
539     }
540
541     if (HOOK_IsHooked( WH_MOUSE ))
542     {
543         MOUSEHOOKSTRUCT hook;
544         hook.pt           = msg->pt;
545         hook.hwnd         = msg->hwnd;
546         hook.wHitTestCode = hittest;
547         hook.dwExtraInfo  = 0;
548         if (HOOK_CallHooksA( WH_MOUSE, remove ? HC_ACTION : HC_NOREMOVE,
549                              msg->message, (LPARAM)&hook ))
550         {
551             hook.pt           = msg->pt;
552             hook.hwnd         = msg->hwnd;
553             hook.wHitTestCode = hittest;
554             hook.dwExtraInfo  = 0;
555             HOOK_CallHooksA( WH_CBT, HCBT_CLICKSKIPPED, msg->message, (LPARAM)&hook );
556             return FALSE;
557         }
558     }
559
560     if ((hittest == HTERROR) || (hittest == HTNOWHERE))
561     {
562         SendMessageA( msg->hwnd, WM_SETCURSOR, msg->hwnd, MAKELONG( hittest, raw_message ));
563         return FALSE;
564     }
565
566     if (!remove || GetCapture()) return TRUE;
567
568     eatMsg = FALSE;
569
570     if ((raw_message == WM_LBUTTONDOWN) ||
571         (raw_message == WM_RBUTTONDOWN) ||
572         (raw_message == WM_MBUTTONDOWN))
573     {
574         HWND hwndTop = WIN_GetTopParent( msg->hwnd );
575
576         /* Send the WM_PARENTNOTIFY,
577          * note that even for double/nonclient clicks
578          * notification message is still WM_L/M/RBUTTONDOWN.
579          */
580         MSG_SendParentNotify( msg->hwnd, raw_message, 0, msg->pt );
581
582         /* Activate the window if needed */
583
584         if (msg->hwnd != GetActiveWindow() && hwndTop != GetDesktopWindow())
585         {
586             LONG ret = SendMessageA( msg->hwnd, WM_MOUSEACTIVATE, hwndTop,
587                                      MAKELONG( hittest, raw_message ) );
588
589             switch(ret)
590             {
591             case MA_NOACTIVATEANDEAT:
592                 eatMsg = TRUE;
593                 /* fall through */
594             case MA_NOACTIVATE:
595                 break;
596             case MA_ACTIVATEANDEAT:
597                 eatMsg = TRUE;
598                 /* fall through */
599             case MA_ACTIVATE:
600                 if (hwndTop != GetForegroundWindow() )
601                 {
602                     if (!WINPOS_SetActiveWindow( hwndTop, TRUE , TRUE ))
603                         eatMsg = TRUE;
604                 }
605                 break;
606             default:
607                 WARN( "unknown WM_MOUSEACTIVATE code %ld\n", ret );
608                 break;
609             }
610         }
611     }
612
613     /* send the WM_SETCURSOR message */
614
615     /* Windows sends the normal mouse message as the message parameter
616        in the WM_SETCURSOR message even if it's non-client mouse message */
617     SendMessageA( msg->hwnd, WM_SETCURSOR, msg->hwnd, MAKELONG( hittest, raw_message ));
618
619     return !eatMsg;
620 }
621
622
623 /***********************************************************************
624  *          process_hardware_message
625  *
626  * returns TRUE if the contents of 'msg' should be passed to the application
627  */
628 static BOOL process_raw_hardware_message( MSG *msg, ULONG_PTR extra_info, HWND hwnd_filter,
629                                           UINT first, UINT last, BOOL remove )
630 {
631     if (is_keyboard_message( msg->message ))
632     {
633         if (!process_raw_keyboard_message( msg, extra_info )) return FALSE;
634     }
635     else if (is_mouse_message( msg->message ))
636     {
637         if (!process_raw_mouse_message( msg, extra_info )) return FALSE;
638     }
639     else
640     {
641         ERR( "unknown message type %x\n", msg->message );
642         return FALSE;
643     }
644
645     /* check destination thread and filters */
646     if (!check_message_filter( msg, hwnd_filter, first, last ) ||
647         GetWindowThreadProcessId( msg->hwnd, NULL ) != GetCurrentThreadId())
648     {
649         /* queue it for later, or for another thread */
650         queue_hardware_message( msg, extra_info, COOKED_HW_MESSAGE );
651         return FALSE;
652     }
653
654     /* save the message in the cooked queue if we didn't want to remove it */
655     if (!remove) queue_hardware_message( msg, extra_info, COOKED_HW_MESSAGE );
656     return TRUE;
657 }
658
659
660 /***********************************************************************
661  *          process_cooked_hardware_message
662  *
663  * returns TRUE if the contents of 'msg' should be passed to the application
664  */
665 static BOOL process_cooked_hardware_message( MSG *msg, BOOL remove )
666 {
667     if (is_keyboard_message( msg->message ))
668         return process_cooked_keyboard_message( msg, remove );
669
670     if (is_mouse_message( msg->message ))
671         return process_cooked_mouse_message( msg, remove );
672
673     ERR( "unknown message type %x\n", msg->message );
674     return FALSE;
675 }
676
677
678 /***********************************************************************
679  *           handle_sent_message
680  *
681  * Handle the reception of a sent message by calling the corresponding window proc
682  */
683 static void handle_sent_message( MSG *msg, int type, ULONG_PTR extra_info )
684 {
685     LRESULT result = 0;
686     MESSAGEQUEUE *queue = QUEUE_Lock( GetFastQueue16() );
687     ULONG_PTR old_extra_info = queue->GetMessageExtraInfoVal; /* save ExtraInfo */
688     WND *wndPtr = WIN_FindWndPtr( msg->hwnd );
689
690     TRACE( "got hwnd %x msg %x (%s) wp %x lp %lx\n",
691            msg->hwnd, msg->message, SPY_GetMsgName(msg->message),
692            msg->wParam, msg->lParam );
693
694     queue->GetMessageExtraInfoVal = extra_info;
695
696     /* call the right version of CallWindowProcXX */
697     switch(type)
698     {
699     case QMSG_WIN16:
700         result = CallWindowProc16( (WNDPROC16)wndPtr->winproc,
701                                    (HWND16) msg->hwnd,
702                                    (UINT16) msg->message,
703                                    LOWORD(msg->wParam),
704                                    msg->lParam );
705         break;
706     case QMSG_WIN32A:
707         result = CallWindowProcA( wndPtr->winproc, msg->hwnd, msg->message,
708                                   msg->wParam, msg->lParam );
709         break;
710     case QMSG_WIN32W:
711         result = CallWindowProcW( wndPtr->winproc, msg->hwnd, msg->message,
712                                   msg->wParam, msg->lParam );
713         break;
714     }
715
716     queue->GetMessageExtraInfoVal = old_extra_info;  /* Restore extra info */
717     WIN_ReleaseWndPtr(wndPtr);
718     QUEUE_Unlock( queue );
719
720     SERVER_START_REQ( reply_message )
721     {
722         req->result = result;
723         req->remove = 1;
724         SERVER_CALL();
725     }
726     SERVER_END_REQ;
727 }
728
729
730 /***********************************************************************
731  *           process_sent_messages
732  *
733  * Process all pending sent messages
734  */
735 static void process_sent_messages(void)
736 {
737     MSG msg;
738     int type;
739     unsigned int res;
740     ULONG_PTR extra_info;
741
742     for (;;)
743     {
744         SERVER_START_REQ( get_message )
745         {
746             req->flags = GET_MSG_REMOVE | GET_MSG_SENT_ONLY;
747             req->get_win   = 0;
748             req->get_first = 0;
749             req->get_last  = ~0;
750             if (!(res = SERVER_CALL()))
751             {
752                 type        = req->type;
753                 msg.hwnd    = req->win;
754                 msg.message = req->msg;
755                 msg.wParam  = req->wparam;
756                 msg.lParam  = req->lparam;
757                 msg.time    = req->time;
758                 msg.pt.x    = req->x;
759                 msg.pt.y    = req->y;
760                 extra_info  = req->info;
761             }
762         }
763         SERVER_END_REQ;
764
765         if (res) break;
766         handle_sent_message( &msg, type, extra_info );
767     }
768 }
769
770
771
772 /***********************************************************************
773  *           peek_message
774  *
775  * Peek for a message matching the given parameters. Return FALSE if none available.
776  */
777 static BOOL peek_message( HWND hwnd, UINT first, UINT last, int flags, int type,
778                           MSG *msg, ULONG_PTR *extra_info )
779 {
780     BOOL ret = FALSE;
781     enum message_kind kind;
782     int msg_type;
783
784     if (!first && !last) last = ~0;
785
786     for (;;)
787     {
788         SERVER_START_REQ( get_message )
789         {
790             req->flags     = flags;
791             req->get_win   = hwnd;
792             req->get_first = first;
793             req->get_last  = last;
794             if ((ret = !SERVER_CALL()))
795             {
796                 kind         = req->kind;
797                 msg_type     = req->type;
798                 msg->hwnd    = req->win;
799                 msg->message = req->msg;
800                 msg->wParam  = req->wparam;
801                 msg->lParam  = req->lparam;
802                 msg->time    = req->time;
803                 msg->pt.x    = req->x;
804                 msg->pt.y    = req->y;
805                 *extra_info  = req->info;
806             }
807         }
808         SERVER_END_REQ;
809
810         if (!ret) return FALSE;
811
812         switch(kind)
813         {
814         case SEND_MESSAGE:
815             handle_sent_message( msg, msg_type, *extra_info );
816             continue;
817         case POST_MESSAGE:
818             /* try to convert message to requested type */
819             if (!MSG_ConvertMsg( msg, msg_type, type ))
820             {
821                 ERR( "Message %s of wrong type contains pointer parameters. Skipped!\n",
822                      SPY_GetMsgName(msg->message));
823                 /* remove it */
824                 flags |= GET_MSG_REMOVE_LAST;
825                 continue;
826             }
827             break;
828         case RAW_HW_MESSAGE:
829             if (!process_raw_hardware_message( msg, *extra_info,
830                                                hwnd, first, last, flags & GET_MSG_REMOVE ))
831                 continue;
832             /* fall through */
833         case COOKED_HW_MESSAGE:
834             if (!process_cooked_hardware_message( msg, flags & GET_MSG_REMOVE ))
835             {
836                 flags |= GET_MSG_REMOVE_LAST;
837                 continue;
838             }
839             break;
840         }
841
842         /* now we got something */
843         TRACE( "got hwnd %x msg %x (%s) wp %x lp %lx\n",
844                msg->hwnd, msg->message, SPY_GetMsgName(msg->message),
845                msg->wParam, msg->lParam );
846         return TRUE;
847     }
848 }
849
850
851 /***********************************************************************
852  *           wait_queue_bits
853  *
854  * See "Windows Internals", p.447
855  *
856  * return values:
857  *    0 if exit with timeout
858  *    1 otherwise
859  */
860 static int wait_queue_bits( WORD bits, DWORD timeout )
861 {
862     MESSAGEQUEUE *queue;
863     HQUEUE16 hQueue;
864
865     TRACE_(msg)("q %04x waiting for %04x\n", GetFastQueue16(), bits);
866
867     hQueue = GetFastQueue16();
868     if (!(queue = QUEUE_Lock( hQueue ))) return 0;
869
870     for (;;)
871     {
872         unsigned int wake_bits = 0, changed_bits = 0;
873         DWORD dwlc;
874
875         SERVER_START_REQ( set_queue_mask )
876         {
877             req->wake_mask    = QS_SENDMESSAGE;
878             req->changed_mask = bits | QS_SENDMESSAGE;
879             req->skip_wait    = 1;
880             if (!SERVER_CALL())
881             {
882                 wake_bits    = req->wake_bits;
883                 changed_bits = req->changed_bits;
884             }
885         }
886         SERVER_END_REQ;
887
888         if (changed_bits & bits)
889         {
890             /* One of the bits is set; we can return */
891             QUEUE_Unlock( queue );
892             return 1;
893         }
894         if (wake_bits & QS_SENDMESSAGE)
895         {
896             /* Process the sent message immediately */
897             process_sent_messages();
898             continue;  /* nested sm crux */
899         }
900
901         TRACE_(msg)("(%04x) mask=%08x, bits=%08x, changed=%08x, waiting\n",
902                     queue->self, bits, wake_bits, changed_bits );
903
904         ReleaseThunkLock( &dwlc );
905         if (dwlc) TRACE_(msg)("had win16 lock\n");
906
907         if (USER_Driver.pMsgWaitForMultipleObjectsEx)
908             USER_Driver.pMsgWaitForMultipleObjectsEx( 1, &queue->server_queue, timeout, 0, 0 );
909         else
910             WaitForSingleObject( queue->server_queue, timeout );
911         if (dwlc) RestoreThunkLock( dwlc );
912     }
913 }
914
915
916 /**********************************************************************
917  *              SetDoubleClickTime (USER.20)
918  */
919 void WINAPI SetDoubleClickTime16( UINT16 interval )
920 {
921     SetDoubleClickTime( interval );
922 }               
923
924
925 /**********************************************************************
926  *              SetDoubleClickTime (USER32.@)
927  */
928 BOOL WINAPI SetDoubleClickTime( UINT interval )
929 {
930     doubleClickSpeed = interval ? interval : 500;
931     return TRUE;
932 }               
933
934
935 /**********************************************************************
936  *              GetDoubleClickTime (USER.21)
937  */
938 UINT16 WINAPI GetDoubleClickTime16(void)
939 {
940     return doubleClickSpeed;
941 }               
942
943
944 /**********************************************************************
945  *              GetDoubleClickTime (USER32.@)
946  */
947 UINT WINAPI GetDoubleClickTime(void)
948 {
949     return doubleClickSpeed;
950 }               
951
952
953 /***********************************************************************
954  *           MSG_SendMessageInterThread
955  *
956  * Implementation of an inter-task SendMessage.
957  * Return values:
958  *    0 if error or timeout
959  *    1 if successful
960  */
961 static LRESULT MSG_SendMessageInterThread( DWORD dest_tid, HWND hwnd, UINT msg,
962                                            WPARAM wParam, LPARAM lParam,
963                                            DWORD timeout, WORD type,
964                                            LRESULT *pRes)
965 {
966     BOOL ret;
967     int iWndsLocks;
968     LRESULT result = 0;
969
970     TRACE( "hwnd %x msg %x (%s) wp %x lp %lx\n", hwnd, msg, SPY_GetMsgName(msg), wParam, lParam );
971
972     SERVER_START_REQ( send_message )
973     {
974         req->kind   = SEND_MESSAGE;
975         req->id     = (void *)dest_tid;
976         req->type   = type;
977         req->win    = hwnd;
978         req->msg    = msg;
979         req->wparam = wParam;
980         req->lparam = lParam;
981         req->x      = 0;
982         req->y      = 0;
983         req->time   = GetCurrentTime();
984         req->info   = 0;
985         ret = !SERVER_CALL_ERR();
986     }
987     SERVER_END_REQ;
988     if (!ret) return 0;
989
990     iWndsLocks = WIN_SuspendWndsLock();
991
992     /* wait for the result */
993     wait_queue_bits( QS_SMRESULT, timeout );
994
995     SERVER_START_REQ( get_message_reply )
996     {
997         req->cancel = 1;
998         if ((ret = !SERVER_CALL_ERR())) result = req->result;
999     }
1000     SERVER_END_REQ;
1001
1002     TRACE( "hwnd %x msg %x (%s) wp %x lp %lx got reply %lx (err=%ld)\n",
1003            hwnd, msg, SPY_GetMsgName(msg), wParam, lParam, result, GetLastError() );
1004
1005     if (!ret && (GetLastError() == ERROR_IO_PENDING))
1006     {
1007         if (timeout == INFINITE) ERR("no timeout but no result\n");
1008         SetLastError(0);  /* timeout */
1009     }
1010
1011     if (pRes) *pRes = result;
1012
1013     WIN_RestoreWndsLock(iWndsLocks);
1014     return ret;
1015 }
1016
1017
1018 /***********************************************************************
1019  *              ReplyMessage (USER.115)
1020  */
1021 void WINAPI ReplyMessage16( LRESULT result )
1022 {
1023     ReplyMessage( result );
1024 }
1025
1026 /***********************************************************************
1027  *              ReplyMessage (USER32.@)
1028  */
1029 BOOL WINAPI ReplyMessage( LRESULT result )
1030 {
1031     BOOL ret;
1032     SERVER_START_REQ( reply_message )
1033     {
1034         req->result = result;
1035         req->remove = 0;
1036         ret = !SERVER_CALL_ERR();
1037     }
1038     SERVER_END_REQ;
1039     return ret;
1040 }
1041
1042 /***********************************************************************
1043  *           MSG_ConvertMsg
1044  */
1045 static BOOL MSG_ConvertMsg( MSG *msg, int srcType, int dstType )
1046 {
1047     if (srcType == QMSG_WIN32A || dstType == QMSG_WIN32A)
1048     {
1049         /* posted messages are always either Win16 or Unicode Win32,
1050          * QMSG_WIN32A is only for sent messages */
1051         ERR( "invalid type %d/%d\n", srcType, dstType );
1052         return FALSE;
1053     }
1054
1055     if (!srcType || srcType == dstType) return TRUE;
1056
1057     if (srcType == QMSG_WIN16)
1058     {
1059         if (dstType == QMSG_WIN32W)
1060         {
1061             switch ( WINPROC_MapMsg16To32W( msg->hwnd, msg->message, msg->wParam,
1062                                             &msg->message, &msg->wParam, &msg->lParam ) )
1063             {
1064             case 0:
1065                 return TRUE;
1066             case 1:
1067                 /* Pointer messages were mapped --> need to free allocated memory and fail */
1068                 WINPROC_UnmapMsg16To32W( msg->hwnd, msg->message, msg->wParam, msg->lParam, 0 );
1069             default:
1070                 return FALSE;
1071             }
1072         }
1073     }
1074     else if (srcType == QMSG_WIN32W)
1075     {
1076         if (dstType == QMSG_WIN16)
1077         {
1078             UINT16 msg16;
1079             MSGPARAM16 mp16;
1080
1081             mp16.lParam = msg->lParam;
1082             switch ( WINPROC_MapMsg32WTo16( msg->hwnd, msg->message, msg->wParam,
1083                                             &msg16, &mp16.wParam, &mp16.lParam ) )
1084             {
1085             case 0:
1086                 msg->message = msg16;
1087                 msg->wParam  = mp16.wParam;
1088                 msg->lParam  = mp16.lParam;
1089                 return TRUE;
1090             case 1:
1091                 /* Pointer messages were mapped --> need to free allocated memory and fail */
1092                 WINPROC_UnmapMsg32WTo16( msg->hwnd, msg->message, msg->wParam, msg->lParam, &mp16 );
1093             default:
1094                 return FALSE;
1095             }
1096         }
1097     }
1098
1099     FIXME( "Invalid message type(s): %d / %d\n", srcType, dstType );
1100     return FALSE;
1101 }
1102
1103
1104 /***********************************************************************
1105  *           MSG_PeekMessage
1106  */
1107 static BOOL MSG_PeekMessage( int type, LPMSG msg_out, HWND hwnd, 
1108                              DWORD first, DWORD last, WORD flags, BOOL peek )
1109 {
1110     int mask, msg_flags = 0;
1111     MESSAGEQUEUE *msgQueue;
1112     int iWndsLocks;
1113     MSG msg;
1114     ULONG_PTR extra_info;
1115
1116     mask = QS_POSTMESSAGE | QS_SENDMESSAGE;  /* Always selected */
1117     if (first || last)
1118     {
1119         if ((first <= WM_KEYLAST) && (last >= WM_KEYFIRST)) mask |= QS_KEY;
1120         if ( ((first <= WM_MOUSELAST) && (last >= WM_MOUSEFIRST)) ||
1121              ((first <= WM_NCMOUSELAST) && (last >= WM_NCMOUSEFIRST)) ) mask |= QS_MOUSE;
1122         if ((first <= WM_TIMER) && (last >= WM_TIMER)) mask |= QS_TIMER;
1123         if ((first <= WM_SYSTIMER) && (last >= WM_SYSTIMER)) mask |= QS_TIMER;
1124         if ((first <= WM_PAINT) && (last >= WM_PAINT)) mask |= QS_PAINT;
1125     }
1126     else mask |= QS_MOUSE | QS_KEY | QS_TIMER | QS_PAINT;
1127
1128     if (IsTaskLocked16()) flags |= PM_NOYIELD;
1129
1130     iWndsLocks = WIN_SuspendWndsLock();
1131
1132     /* check for graphics events */
1133     if (USER_Driver.pMsgWaitForMultipleObjectsEx)
1134         USER_Driver.pMsgWaitForMultipleObjectsEx( 0, NULL, 0, 0, 0 );
1135
1136     if (flags & PM_REMOVE) msg_flags |= GET_MSG_REMOVE;
1137
1138     while(1)
1139     {
1140         if (peek_message( hwnd, first, last, msg_flags, type, &msg, &extra_info ))
1141         {
1142             /* need to fill the window handle for WM_PAINT message */
1143             if (msg.message == WM_PAINT)
1144             {
1145                 if ((msg.hwnd = WIN_FindWinToRepaint( hwnd )))
1146                 {
1147                     if (IsIconic( msg.hwnd ) && GetClassLongA( msg.hwnd, GCL_HICON ))
1148                     {
1149                         msg.message = WM_PAINTICON;
1150                         msg.wParam = 1;
1151                     }
1152                     if( !hwnd || msg.hwnd == hwnd || IsChild(hwnd,msg.hwnd) )
1153                     {
1154                         /* clear internal paint flag */
1155                         RedrawWindow( msg.hwnd, NULL, 0,
1156                                       RDW_NOINTERNALPAINT | RDW_NOCHILDREN );
1157                         break;
1158                     }
1159                 }
1160             }
1161             else break;
1162         }
1163
1164         /* FIXME: should be done before checking for hw events */
1165         MSG_JournalPlayBackMsg();
1166
1167         if (peek)
1168         {
1169 #if 0  /* FIXME */
1170             if (!(flags & PM_NOYIELD)) UserYield16();
1171 #endif
1172             WIN_RestoreWndsLock(iWndsLocks);
1173             return FALSE;
1174         }
1175
1176         wait_queue_bits( mask, INFINITE );
1177     }
1178
1179     WIN_RestoreWndsLock(iWndsLocks);
1180
1181     if ((msgQueue = QUEUE_Lock( GetFastQueue16() )))
1182     {
1183         msgQueue->GetMessageTimeVal      = msg.time;
1184         msgQueue->GetMessagePosVal       = MAKELONG( msg.pt.x, msg.pt.y );
1185         msgQueue->GetMessageExtraInfoVal = extra_info;
1186         QUEUE_Unlock( msgQueue );
1187     }
1188
1189       /* We got a message */
1190     if (flags & PM_REMOVE)
1191     {
1192         if (msg.message == WM_KEYDOWN || msg.message == WM_SYSKEYDOWN)
1193         {
1194             BYTE *p = &QueueKeyStateTable[msg.wParam & 0xff];
1195
1196             if (!(*p & 0x80))
1197                 *p ^= 0x01;
1198             *p |= 0x80;
1199         }
1200         else if (msg.message == WM_KEYUP || msg.message == WM_SYSKEYUP)
1201             QueueKeyStateTable[msg.wParam & 0xff] &= ~0x80;
1202     }
1203
1204     /* copy back our internal safe copy of message data to msg_out.
1205      * msg_out is a variable from the *program*, so it can't be used
1206      * internally as it can get "corrupted" by our use of SendMessage()
1207      * (back to the program) inside the message handling itself. */
1208     *msg_out = msg;
1209     if (peek)
1210         return TRUE;
1211
1212     else
1213         return (msg.message != WM_QUIT);
1214 }
1215
1216 /***********************************************************************
1217  *           MSG_InternalGetMessage
1218  *
1219  * GetMessage() function for internal use. Behave like GetMessage(),
1220  * but also call message filters and optionally send WM_ENTERIDLE messages.
1221  * 'hwnd' must be the handle of the dialog or menu window.
1222  * 'code' is the message filter value (MSGF_??? codes).
1223  */
1224 BOOL MSG_InternalGetMessage( MSG *msg, HWND hwnd, HWND hwndOwner, UINT first, UINT last,
1225                              WPARAM code, WORD flags, BOOL sendIdle, BOOL* idleSent ) 
1226 {
1227     for (;;)
1228     {
1229         if (sendIdle)
1230         {
1231             if (!MSG_PeekMessage( QMSG_WIN32W, msg, 0, first, last, flags, TRUE ))
1232             {
1233                   /* No message present -> send ENTERIDLE and wait */
1234                 if (IsWindow(hwndOwner))
1235                 {
1236                     SendMessageA( hwndOwner, WM_ENTERIDLE,
1237                                    code, (LPARAM)hwnd );
1238
1239                     if (idleSent!=NULL)
1240                       *idleSent=TRUE;
1241                 }
1242                 MSG_PeekMessage( QMSG_WIN32W, msg, 0, first, last, flags, FALSE );
1243             }
1244         }
1245         else  /* Always wait for a message */
1246             MSG_PeekMessage( QMSG_WIN32W, msg, 0, first, last, flags, FALSE );
1247
1248         /* Call message filters */
1249
1250         if (HOOK_IsHooked( WH_SYSMSGFILTER ) || HOOK_IsHooked( WH_MSGFILTER ))
1251         {
1252             MSG tmp_msg = *msg;
1253
1254             if (HOOK_CallHooksW( WH_SYSMSGFILTER, code, 0, (LPARAM)&tmp_msg ) ||
1255                 HOOK_CallHooksW( WH_MSGFILTER, code, 0, (LPARAM)&tmp_msg ))
1256             {
1257                 /* Message filtered -> remove it from the queue if it's still there. */
1258                 if (!(flags & PM_REMOVE))
1259                     MSG_PeekMessage( QMSG_WIN32W, msg, 0, first, last, PM_REMOVE, TRUE );
1260                 continue;
1261             }
1262         }
1263         /* need to return an ASCII message (FIXME) */
1264         msg->wParam = map_wparam_WtoA( msg->message, msg->wParam );
1265         return (msg->message != WM_QUIT);
1266     }
1267 }
1268
1269
1270 /***********************************************************************
1271  *              PeekMessage32 (USER.819)
1272  */
1273 BOOL16 WINAPI PeekMessage32_16( SEGPTR msg16_32, HWND16 hwnd,
1274                                 UINT16 first, UINT16 last, UINT16 flags, 
1275                                 BOOL16 wHaveParamHigh )
1276 {
1277     BOOL ret;
1278     MSG32_16 *lpmsg16_32 = MapSL(msg16_32);
1279     MSG msg;
1280
1281     ret = MSG_PeekMessage( QMSG_WIN16, &msg, hwnd, first, last, flags, TRUE );
1282
1283     lpmsg16_32->msg.hwnd    = msg.hwnd;
1284     lpmsg16_32->msg.message = msg.message;
1285     lpmsg16_32->msg.wParam  = LOWORD(msg.wParam);
1286     lpmsg16_32->msg.lParam  = msg.lParam;
1287     lpmsg16_32->msg.time    = msg.time;
1288     lpmsg16_32->msg.pt.x    = (INT16)msg.pt.x;
1289     lpmsg16_32->msg.pt.y    = (INT16)msg.pt.y;
1290
1291     if ( wHaveParamHigh )
1292         lpmsg16_32->wParamHigh = HIWORD(msg.wParam);
1293
1294     HOOK_CallHooks16( WH_GETMESSAGE, HC_ACTION, flags & PM_REMOVE, (LPARAM)msg16_32 );
1295     return ret;
1296 }
1297
1298 /***********************************************************************
1299  *              PeekMessage (USER.109)
1300  */
1301 BOOL16 WINAPI PeekMessage16( SEGPTR msg, HWND16 hwnd,
1302                              UINT16 first, UINT16 last, UINT16 flags )
1303 {
1304     return PeekMessage32_16( msg, hwnd, first, last, flags, FALSE );
1305 }
1306
1307 /***********************************************************************
1308  *              PeekMessageA (USER32.@)
1309  */
1310 BOOL WINAPI PeekMessageA( LPMSG lpmsg, HWND hwnd, UINT min, UINT max, UINT flags )
1311 {
1312     BOOL ret = PeekMessageW( lpmsg, hwnd, min, max, flags );
1313     if (ret) lpmsg->wParam = map_wparam_WtoA( lpmsg->message, lpmsg->wParam );
1314     return ret;
1315 }
1316
1317 /***********************************************************************
1318  *              PeekMessageW (USER32.@) Check queue for messages
1319  *
1320  * Checks for a message in the thread's queue, filtered as for
1321  * GetMessage(). Returns immediately whether a message is available
1322  * or not.
1323  *
1324  * Whether a retrieved message is removed from the queue is set by the
1325  * _wRemoveMsg_ flags, which should be one of the following values:
1326  *
1327  *    PM_NOREMOVE    Do not remove the message from the queue. 
1328  *
1329  *    PM_REMOVE      Remove the message from the queue.
1330  *
1331  * In addition, PM_NOYIELD may be combined into _wRemoveMsg_ to
1332  * request that the system not yield control during PeekMessage();
1333  * however applications may not rely on scheduling behavior.
1334  * 
1335  * RETURNS
1336  *
1337  *  Nonzero if a message is available and is retrieved, zero otherwise.
1338  *
1339  * CONFORMANCE
1340  *
1341  * ECMA-234, Win32
1342  *
1343  */
1344 BOOL WINAPI PeekMessageW( 
1345   LPMSG lpmsg,    /* [out] buffer to receive message */
1346   HWND hwnd,      /* [in] restrict to messages for hwnd */
1347   UINT min,       /* [in] minimum message to receive */
1348   UINT max,       /* [in] maximum message to receive */
1349   UINT wRemoveMsg /* [in] removal flags */ 
1350
1351 {
1352     BOOL ret = MSG_PeekMessage( QMSG_WIN32W, lpmsg, hwnd, min, max, wRemoveMsg, TRUE );
1353     if (ret) HOOK_CallHooksW( WH_GETMESSAGE, HC_ACTION,
1354                               wRemoveMsg & PM_REMOVE, (LPARAM)lpmsg );
1355     return ret;
1356 }
1357
1358
1359 /***********************************************************************
1360  *              GetMessage32 (USER.820)
1361  */
1362 BOOL16 WINAPI GetMessage32_16( SEGPTR msg16_32, HWND16 hWnd, UINT16 first,
1363                                UINT16 last, BOOL16 wHaveParamHigh )
1364 {
1365     MSG32_16 *lpmsg16_32 = MapSL(msg16_32);
1366     MSG msg;
1367
1368     MSG_PeekMessage( QMSG_WIN16, &msg, hWnd, first, last, PM_REMOVE, FALSE );
1369
1370     lpmsg16_32->msg.hwnd    = msg.hwnd;
1371     lpmsg16_32->msg.message = msg.message;
1372     lpmsg16_32->msg.wParam  = LOWORD(msg.wParam);
1373     lpmsg16_32->msg.lParam  = msg.lParam;
1374     lpmsg16_32->msg.time    = msg.time;
1375     lpmsg16_32->msg.pt.x    = (INT16)msg.pt.x;
1376     lpmsg16_32->msg.pt.y    = (INT16)msg.pt.y;
1377
1378     if ( wHaveParamHigh )
1379         lpmsg16_32->wParamHigh = HIWORD(msg.wParam);
1380
1381     TRACE( "message %04x, hwnd %04x, filter(%04x - %04x)\n",
1382            lpmsg16_32->msg.message, hWnd, first, last );
1383
1384     HOOK_CallHooks16( WH_GETMESSAGE, HC_ACTION, PM_REMOVE, (LPARAM)msg16_32 );
1385     return lpmsg16_32->msg.message != WM_QUIT;
1386 }
1387
1388 /***********************************************************************
1389  *              GetMessage (USER.108)
1390  */
1391 BOOL16 WINAPI GetMessage16( SEGPTR msg, HWND16 hwnd, UINT16 first, UINT16 last)
1392 {
1393     return GetMessage32_16( msg, hwnd, first, last, FALSE );
1394 }
1395
1396 /***********************************************************************
1397  *              GetMessageA (USER32.@)
1398  */
1399 BOOL WINAPI GetMessageA( MSG *lpmsg, HWND hwnd, UINT min, UINT max )
1400 {
1401     GetMessageW( lpmsg, hwnd, min, max );
1402     lpmsg->wParam = map_wparam_WtoA( lpmsg->message, lpmsg->wParam );
1403     return lpmsg->message != WM_QUIT;
1404 }
1405
1406 /***********************************************************************
1407  *              GetMessageW (USER32.@) Retrieve next message
1408  *
1409  * GetMessage retrieves the next event from the calling thread's
1410  * queue and deposits it in *lpmsg.
1411  *
1412  * If _hwnd_ is not NULL, only messages for window _hwnd_ and its
1413  * children as specified by IsChild() are retrieved. If _hwnd_ is NULL
1414  * all application messages are retrieved.
1415  *
1416  * _min_ and _max_ specify the range of messages of interest. If
1417  * min==max==0, no filtering is performed. Useful examples are
1418  * WM_KEYFIRST and WM_KEYLAST to retrieve keyboard input, and
1419  * WM_MOUSEFIRST and WM_MOUSELAST to retrieve mouse input.
1420  *
1421  * WM_PAINT messages are not removed from the queue; they remain until
1422  * processed. Other messages are removed from the queue.
1423  *
1424  * RETURNS
1425  *
1426  * -1 on error, 0 if message is WM_QUIT, nonzero otherwise.
1427  *
1428  * CONFORMANCE
1429  *
1430  * ECMA-234, Win32
1431  * 
1432  */
1433 BOOL WINAPI GetMessageW(
1434   MSG* lpmsg, /* [out] buffer to receive message */
1435   HWND hwnd,  /* [in] restrict to messages for hwnd */
1436   UINT min,   /* [in] minimum message to receive */
1437   UINT max    /* [in] maximum message to receive */
1438
1439 {
1440     MSG_PeekMessage( QMSG_WIN32W, lpmsg, hwnd, min, max, PM_REMOVE, FALSE );
1441     
1442     TRACE( "message %04x, hwnd %04x, filter(%04x - %04x)\n", 
1443            lpmsg->message, hwnd, min, max );
1444     
1445     HOOK_CallHooksW( WH_GETMESSAGE, HC_ACTION, PM_REMOVE, (LPARAM)lpmsg );
1446     return lpmsg->message != WM_QUIT;
1447 }
1448
1449 /***********************************************************************
1450  *           MSG_PostToQueue
1451  */
1452 static BOOL MSG_PostToQueue( DWORD tid, int type, HWND hwnd,
1453                              UINT message, WPARAM wParam, LPARAM lParam )
1454 {
1455     unsigned int res;
1456
1457     TRACE( "posting %x %x (%s) %x %lx\n", hwnd, message, SPY_GetMsgName(message), wParam, lParam );
1458
1459     SERVER_START_REQ( send_message )
1460     {
1461         req->kind   = POST_MESSAGE;
1462         req->id     = (void *)tid;
1463         req->type   = type;
1464         req->win    = hwnd;
1465         req->msg    = message;
1466         req->wparam = wParam;
1467         req->lparam = lParam;
1468         req->x      = 0;
1469         req->y      = 0;
1470         req->time   = GetCurrentTime();
1471         req->info   = 0;
1472         res = SERVER_CALL();
1473     }
1474     SERVER_END_REQ;
1475
1476     if (res)
1477     {
1478         if (res == STATUS_INVALID_PARAMETER)
1479             SetLastError( ERROR_INVALID_THREAD_ID );
1480         else
1481             SetLastError( RtlNtStatusToDosError(res) );
1482     }
1483     return !res;
1484 }
1485
1486
1487 /***********************************************************************
1488  *           MSG_PostMessage
1489  */
1490 static BOOL MSG_PostMessage( int type, HWND hwnd, UINT message, 
1491                              WPARAM wParam, LPARAM lParam )
1492 {
1493     WND *wndPtr;
1494
1495     if (hwnd == HWND_BROADCAST)
1496     {
1497         WND *pDesktop = WIN_GetDesktop();
1498         TRACE("HWND_BROADCAST !\n");
1499         
1500         for (wndPtr=WIN_LockWndPtr(pDesktop->child); wndPtr; WIN_UpdateWndPtr(&wndPtr,wndPtr->next))
1501         {
1502             if (wndPtr->dwStyle & WS_POPUP || wndPtr->dwStyle & WS_CAPTION)
1503             {
1504                 TRACE("BROADCAST Message to hWnd=%04x m=%04X w=%04X l=%08lX !\n",
1505                       wndPtr->hwndSelf, message, wParam, lParam);
1506                 MSG_PostToQueue( GetWindowThreadProcessId( wndPtr->hwndSelf, NULL ), type,
1507                                  wndPtr->hwndSelf, message, wParam, lParam );
1508             }
1509         }
1510         WIN_ReleaseDesktop();
1511         TRACE("End of HWND_BROADCAST !\n");
1512         return TRUE;
1513     }
1514
1515     return MSG_PostToQueue( GetWindowThreadProcessId( hwnd, NULL ),
1516                             type, hwnd, message, wParam, lParam );
1517 }
1518
1519
1520 /***********************************************************************
1521  *              PostMessage (USER.110)
1522  */
1523 BOOL16 WINAPI PostMessage16( HWND16 hwnd, UINT16 message, WPARAM16 wParam,
1524                              LPARAM lParam )
1525 {
1526     return (BOOL16) MSG_PostMessage( QMSG_WIN16, hwnd, message, wParam, lParam );
1527 }
1528
1529 /***********************************************************************
1530  *              PostMessageA (USER32.@)
1531  */
1532 BOOL WINAPI PostMessageA( HWND hwnd, UINT message, WPARAM wParam,
1533                           LPARAM lParam )
1534 {
1535     return PostMessageW( hwnd, message, map_wparam_AtoW( message, wParam ), lParam );
1536 }
1537
1538 /***********************************************************************
1539  *              PostMessageW (USER32.@)
1540  */
1541 BOOL WINAPI PostMessageW( HWND hwnd, UINT message, WPARAM wParam,
1542                           LPARAM lParam )
1543 {
1544     /* See thread on wine-devel around 6.2.2001. Basically posted messages
1545      * that are known to contain pointers are dropped by the Windows 32bit
1546      * PostMessage() with return FALSE; and invalid parameter last error.
1547      * (tested against NT4 by Gerard Patel)
1548      */
1549     if (is_pointer_message(message))
1550     {
1551         SetLastError(ERROR_INVALID_PARAMETER);
1552         return FALSE;
1553     }
1554     return MSG_PostMessage( QMSG_WIN32W, hwnd, message, wParam, lParam );
1555 }
1556
1557 /***********************************************************************
1558  *              PostAppMessage (USER.116)
1559  *              PostAppMessage16 (USER32.@)
1560  */
1561 BOOL16 WINAPI PostAppMessage16( HTASK16 hTask, UINT16 message, 
1562                                 WPARAM16 wParam, LPARAM lParam )
1563 {
1564     TDB *pTask = TASK_GetPtr( hTask );
1565     if (!pTask) return FALSE;
1566     return MSG_PostToQueue( (DWORD)pTask->teb->tid, QMSG_WIN16, 0, message, wParam, lParam );
1567 }
1568
1569 /**********************************************************************
1570  *              PostThreadMessageA (USER32.@)
1571  */
1572 BOOL WINAPI PostThreadMessageA( DWORD idThread, UINT message,
1573                                 WPARAM wParam, LPARAM lParam )
1574 {
1575     return PostThreadMessageW( idThread, message, map_wparam_AtoW( message, wParam ), lParam );
1576 }
1577
1578 /**********************************************************************
1579  *              PostThreadMessageW (USER32.@)
1580  */
1581 BOOL WINAPI PostThreadMessageW( DWORD idThread, UINT message,
1582                                  WPARAM wParam, LPARAM lParam )
1583 {
1584     if (is_pointer_message( message ))
1585     {
1586         SetLastError( ERROR_INVALID_PARAMETER );
1587         return FALSE;
1588     }
1589     return MSG_PostToQueue( idThread, QMSG_WIN32W, 0, message, wParam, lParam );
1590 }
1591
1592
1593 /************************************************************************
1594  *           MSG_CallWndProcHook32
1595  */
1596 static void  MSG_CallWndProcHook( LPMSG pmsg, BOOL bUnicode )
1597 {
1598    CWPSTRUCT cwp;
1599
1600    cwp.lParam = pmsg->lParam;
1601    cwp.wParam = pmsg->wParam;
1602    cwp.message = pmsg->message;
1603    cwp.hwnd = pmsg->hwnd;
1604
1605    if (bUnicode) HOOK_CallHooksW(WH_CALLWNDPROC, HC_ACTION, 1, (LPARAM)&cwp);
1606    else HOOK_CallHooksA( WH_CALLWNDPROC, HC_ACTION, 1, (LPARAM)&cwp );
1607
1608    pmsg->lParam = cwp.lParam;
1609    pmsg->wParam = cwp.wParam;
1610    pmsg->message = cwp.message;
1611    pmsg->hwnd = cwp.hwnd;
1612 }
1613
1614
1615 /***********************************************************************
1616  *           MSG_SendMessage
1617  *
1618  * return values: 0 if timeout occurs
1619  *                1 otherwise
1620  */
1621 static LRESULT MSG_SendMessage( HWND hwnd, UINT msg, WPARAM wParam,
1622                                 LPARAM lParam, DWORD timeout, WORD type,
1623                          LRESULT *pRes)
1624 {
1625     WND * wndPtr = 0;
1626     WND **list, **ppWnd;
1627     LRESULT ret = 1;
1628     DWORD dest_tid;
1629     WNDPROC winproc;
1630
1631     if (pRes) *pRes = 0;
1632
1633     if (hwnd == HWND_BROADCAST|| hwnd == HWND_TOPMOST)
1634     {
1635         if (pRes) *pRes = 1;
1636         
1637         if (!(list = WIN_BuildWinArray( WIN_GetDesktop(), 0, NULL )))
1638         {
1639             WIN_ReleaseDesktop();
1640             return 1;
1641         }
1642         WIN_ReleaseDesktop();
1643
1644         TRACE("HWND_BROADCAST !\n");
1645         for (ppWnd = list; *ppWnd; ppWnd++)
1646         {
1647             WIN_UpdateWndPtr(&wndPtr,*ppWnd);
1648             if (!IsWindow(wndPtr->hwndSelf)) continue;
1649             if (wndPtr->dwStyle & WS_POPUP || wndPtr->dwStyle & WS_CAPTION)
1650             {
1651                 TRACE("BROADCAST Message to hWnd=%04x m=%04X w=%04lX l=%08lX !\n",
1652                       wndPtr->hwndSelf, msg, (DWORD)wParam, lParam);
1653                 MSG_SendMessage( wndPtr->hwndSelf, msg, wParam, lParam,
1654                                timeout, type, pRes);
1655             }
1656         }
1657         WIN_ReleaseWndPtr(wndPtr);
1658         WIN_ReleaseWinArray(list);
1659         TRACE("End of HWND_BROADCAST !\n");
1660         return 1;
1661     }
1662
1663     if (HOOK_IsHooked( WH_CALLWNDPROC ))
1664     {
1665         switch(type)
1666         {
1667         case QMSG_WIN16:
1668             {
1669                 LPCWPSTRUCT16 pmsg;
1670
1671                 if ((pmsg = SEGPTR_NEW(CWPSTRUCT16)))
1672                 {
1673                     pmsg->hwnd   = hwnd & 0xffff;
1674                     pmsg->message= msg & 0xffff;
1675                     pmsg->wParam = wParam & 0xffff;
1676                     pmsg->lParam = lParam;
1677                     HOOK_CallHooks16( WH_CALLWNDPROC, HC_ACTION, 1,
1678                                       (LPARAM)SEGPTR_GET(pmsg) );
1679                     hwnd   = pmsg->hwnd;
1680                     msg    = pmsg->message;
1681                     wParam = pmsg->wParam;
1682                     lParam = pmsg->lParam;
1683                     SEGPTR_FREE( pmsg );
1684                 }
1685             }
1686             break;
1687         case QMSG_WIN32A:
1688             MSG_CallWndProcHook( (LPMSG)&hwnd, FALSE);
1689             break;
1690         case QMSG_WIN32W:
1691             MSG_CallWndProcHook( (LPMSG)&hwnd, TRUE);
1692             break;
1693         }
1694     }
1695
1696     if (!(wndPtr = WIN_FindWndPtr( hwnd )))
1697     {
1698         WARN("invalid hwnd %04x\n", hwnd );
1699         return 0;
1700     }
1701     if (QUEUE_IsExitingQueue(wndPtr->hmemTaskQ))
1702     {
1703         WIN_ReleaseWndPtr( wndPtr );
1704         return 0;  /* Don't send anything if the task is dying */
1705     }
1706     winproc = (WNDPROC)wndPtr->winproc;
1707     WIN_ReleaseWndPtr( wndPtr );
1708
1709     if (type != QMSG_WIN16)
1710         SPY_EnterMessage( SPY_SENDMESSAGE, hwnd, msg, wParam, lParam );
1711     else
1712         SPY_EnterMessage( SPY_SENDMESSAGE16, hwnd, msg, wParam, lParam );
1713
1714     dest_tid = GetWindowThreadProcessId( hwnd, NULL );
1715     if (dest_tid && dest_tid != GetCurrentThreadId())
1716     {
1717         ret = MSG_SendMessageInterThread( dest_tid, hwnd, msg,
1718                                           wParam, lParam, timeout, type, pRes );
1719     }
1720     else
1721     {
1722         LRESULT res = 0;
1723
1724         /* Call the right CallWindowProc flavor */
1725         switch(type)
1726         {
1727         case QMSG_WIN16:
1728             res = CallWindowProc16( (WNDPROC16)winproc, hwnd, msg, wParam, lParam );
1729             break;
1730         case QMSG_WIN32A:
1731             res = CallWindowProcA( winproc, hwnd, msg, wParam, lParam );
1732             break;
1733         case QMSG_WIN32W:
1734             res = CallWindowProcW( winproc, hwnd, msg, wParam, lParam );
1735             break;
1736         }
1737         if (pRes) *pRes = res;
1738     }
1739
1740     if (type != QMSG_WIN16)
1741         SPY_ExitMessage( SPY_RESULT_OK, hwnd, msg, pRes?*pRes:0, wParam, lParam );
1742     else
1743         SPY_ExitMessage( SPY_RESULT_OK16, hwnd, msg, pRes?*pRes:0, wParam, lParam );
1744
1745     return ret;
1746 }
1747
1748
1749 /***********************************************************************
1750  *              SendMessage (USER.111)
1751  */
1752 LRESULT WINAPI SendMessage16( HWND16 hwnd, UINT16 msg, WPARAM16 wParam,
1753                               LPARAM lParam)
1754 {
1755     LRESULT res;
1756     MSG_SendMessage(hwnd, msg, wParam, lParam, INFINITE, QMSG_WIN16, &res);
1757     return res;
1758 }
1759
1760
1761 /***********************************************************************
1762  *              SendMessageA (USER32.@)
1763  */
1764 LRESULT WINAPI SendMessageA( HWND hwnd, UINT msg, WPARAM wParam,
1765                                LPARAM lParam )
1766         {
1767     LRESULT res;
1768
1769     MSG_SendMessage(hwnd, msg, wParam, lParam, INFINITE, QMSG_WIN32A, &res);
1770
1771     return res;
1772 }
1773
1774
1775 /***********************************************************************
1776  *              SendMessageW (USER32.@) Send Window Message
1777  *
1778  *  Sends a message to the window procedure of the specified window.
1779  *  SendMessage() will not return until the called window procedure
1780  *  either returns or calls ReplyMessage().
1781  *
1782  *  Use PostMessage() to send message and return immediately. A window
1783  *  procedure may use InSendMessage() to detect
1784  *  SendMessage()-originated messages.
1785  *
1786  *  Applications which communicate via HWND_BROADCAST may use
1787  *  RegisterWindowMessage() to obtain a unique message to avoid conflicts
1788  *  with other applications.
1789  *
1790  * CONFORMANCE
1791  * 
1792  *  ECMA-234, Win32 
1793  */
1794 LRESULT WINAPI SendMessageW( 
1795   HWND hwnd,     /* [in] Window to send message to. If HWND_BROADCAST, 
1796                          the message will be sent to all top-level windows. */
1797
1798   UINT msg,      /* [in] message */
1799   WPARAM wParam, /* [in] message parameter */
1800   LPARAM lParam  /* [in] additional message parameter */
1801 ) {
1802     LRESULT res;
1803
1804     MSG_SendMessage(hwnd, msg, wParam, lParam, INFINITE, QMSG_WIN32W, &res);
1805
1806     return res;
1807 }
1808
1809
1810 /***********************************************************************
1811  *              SendMessageTimeout (not a WINAPI)
1812  */
1813 LRESULT WINAPI SendMessageTimeout16( HWND16 hwnd, UINT16 msg, WPARAM16 wParam,
1814                                      LPARAM lParam, UINT16 flags,
1815                                      UINT16 timeout, LPWORD resultp)
1816 {
1817     LRESULT ret;
1818     LRESULT msgRet;
1819     
1820     /* FIXME: need support for SMTO_BLOCK */
1821     
1822     ret = MSG_SendMessage(hwnd, msg, wParam, lParam, timeout, QMSG_WIN16, &msgRet);
1823     if (resultp) *resultp = (WORD) msgRet;
1824     return ret;
1825 }
1826
1827
1828 /***********************************************************************
1829  *              SendMessageTimeoutA (USER32.@)
1830  */
1831 LRESULT WINAPI SendMessageTimeoutA( HWND hwnd, UINT msg, WPARAM wParam,
1832                                       LPARAM lParam, UINT flags,
1833                                       UINT timeout, LPDWORD resultp)
1834 {
1835     LRESULT ret;
1836     LRESULT msgRet;
1837
1838     /* FIXME: need support for SMTO_BLOCK */
1839     
1840     ret = MSG_SendMessage(hwnd, msg, wParam, lParam, timeout, QMSG_WIN32A, &msgRet);
1841
1842     if (resultp) *resultp = (DWORD) msgRet;
1843     return ret;
1844 }
1845
1846
1847 /***********************************************************************
1848  *              SendMessageTimeoutW (USER32.@)
1849  */
1850 LRESULT WINAPI SendMessageTimeoutW( HWND hwnd, UINT msg, WPARAM wParam,
1851                                       LPARAM lParam, UINT flags,
1852                                       UINT timeout, LPDWORD resultp)
1853 {
1854     LRESULT ret;
1855     LRESULT msgRet;
1856     
1857     /* FIXME: need support for SMTO_BLOCK */
1858
1859     ret = MSG_SendMessage(hwnd, msg, wParam, lParam, timeout, QMSG_WIN32W, &msgRet);
1860     
1861     if (resultp) *resultp = (DWORD) msgRet;
1862     return ret;
1863 }
1864
1865
1866 /***********************************************************************
1867  *              WaitMessage (USER.112) (USER32.@) Suspend thread pending messages
1868  *
1869  * WaitMessage() suspends a thread until events appear in the thread's
1870  * queue.
1871  */
1872 BOOL WINAPI WaitMessage(void)
1873 {
1874     return (MsgWaitForMultipleObjectsEx( 0, NULL, INFINITE, QS_ALLINPUT, 0 ) != WAIT_FAILED);
1875 }
1876
1877
1878 /***********************************************************************
1879  *              MsgWaitForMultipleObjectsEx   (USER32.@)
1880  */
1881 DWORD WINAPI MsgWaitForMultipleObjectsEx( DWORD count, CONST HANDLE *pHandles,
1882                                           DWORD timeout, DWORD mask, DWORD flags )
1883 {
1884     HANDLE handles[MAXIMUM_WAIT_OBJECTS];
1885     DWORD i, ret;
1886     HQUEUE16 hQueue = GetFastQueue16();
1887     MESSAGEQUEUE *msgQueue;
1888
1889     if (count > MAXIMUM_WAIT_OBJECTS-1)
1890     {
1891         SetLastError( ERROR_INVALID_PARAMETER );
1892         return WAIT_FAILED;
1893     }
1894
1895     if (!(msgQueue = QUEUE_Lock( hQueue ))) return WAIT_FAILED;
1896
1897     /* set the queue mask */
1898     SERVER_START_REQ( set_queue_mask )
1899     {
1900         req->wake_mask    = (flags & MWMO_INPUTAVAILABLE) ? mask : 0;
1901         req->changed_mask = mask;
1902         req->skip_wait    = 0;
1903         SERVER_CALL();
1904     }
1905     SERVER_END_REQ;
1906
1907     /* Add the thread event to the handle list */
1908     for (i = 0; i < count; i++) handles[i] = pHandles[i];
1909     handles[count] = msgQueue->server_queue;
1910
1911
1912     if (USER_Driver.pMsgWaitForMultipleObjectsEx)
1913     {
1914         ret = USER_Driver.pMsgWaitForMultipleObjectsEx( count+1, handles, timeout, mask, flags );
1915         if (ret == count+1) ret = count; /* pretend the msg queue is ready */
1916     }
1917     else
1918         ret = WaitForMultipleObjectsEx( count+1, handles, flags & MWMO_WAITALL,
1919                                         timeout, flags & MWMO_ALERTABLE );
1920     QUEUE_Unlock( msgQueue );
1921     return ret;
1922 }
1923
1924
1925 /***********************************************************************
1926  *              MsgWaitForMultipleObjects (USER32.@)
1927  */
1928 DWORD WINAPI MsgWaitForMultipleObjects( DWORD count, CONST HANDLE *handles,
1929                                         BOOL wait_all, DWORD timeout, DWORD mask )
1930 {
1931     return MsgWaitForMultipleObjectsEx( count, handles, timeout, mask,
1932                                         wait_all ? MWMO_WAITALL : 0 );
1933 }
1934
1935
1936 /***********************************************************************
1937  *              MsgWaitForMultipleObjects16  (USER.640)
1938  */
1939 DWORD WINAPI MsgWaitForMultipleObjects16( DWORD count, CONST HANDLE *handles,
1940                                           BOOL wait_all, DWORD timeout, DWORD mask )
1941 {
1942     return MsgWaitForMultipleObjectsEx( count, handles, timeout, mask,
1943                                         wait_all ? MWMO_WAITALL : 0 );
1944 }
1945
1946
1947 /***********************************************************************
1948  *              WaitForInputIdle (USER32.@)
1949  */
1950 DWORD WINAPI WaitForInputIdle( HANDLE hProcess, DWORD dwTimeOut )
1951 {
1952     DWORD cur_time, ret;
1953     HANDLE idle_event = -1;
1954
1955     SERVER_START_REQ( wait_input_idle )
1956     {
1957         req->handle = hProcess;
1958         req->timeout = dwTimeOut;
1959         if (!(ret = SERVER_CALL_ERR())) idle_event = req->event;
1960     }
1961     SERVER_END_REQ;
1962     if (ret) return 0xffffffff;  /* error */
1963     if (!idle_event) return 0;  /* no event to wait on */
1964
1965     cur_time = GetTickCount();
1966
1967     TRACE("waiting for %x\n", idle_event );
1968     while ( dwTimeOut > GetTickCount() - cur_time || dwTimeOut == INFINITE )
1969     {
1970         ret = MsgWaitForMultipleObjects ( 1, &idle_event, FALSE, dwTimeOut, QS_SENDMESSAGE );
1971         if ( ret == ( WAIT_OBJECT_0 + 1 ))
1972         {
1973             process_sent_messages();
1974             continue;
1975         }
1976         if ( ret == WAIT_TIMEOUT || ret == 0xFFFFFFFF )
1977         {
1978             TRACE("timeout or error\n");
1979             return ret;
1980         }
1981         else
1982         {
1983             TRACE("finished\n");
1984             return 0;
1985         }
1986     }
1987
1988     return WAIT_TIMEOUT;
1989 }
1990
1991
1992 /***********************************************************************
1993  *              UserYield (USER.332)
1994  *              UserYield16 (USER32.@)
1995  */
1996 void WINAPI UserYield16(void)
1997 {
1998     /* Handle sent messages */
1999     process_sent_messages();
2000
2001     /* Yield */
2002     OldYield16();
2003
2004     /* Handle sent messages again */
2005     process_sent_messages();
2006 }
2007
2008
2009 struct accent_char
2010 {
2011     BYTE ac_accent;
2012     BYTE ac_char;
2013     BYTE ac_result;
2014 };
2015
2016 static const struct accent_char accent_chars[] =
2017 {
2018 /* A good idea should be to read /usr/X11/lib/X11/locale/iso8859-x/Compose */
2019     {'`', 'A', '\300'},  {'`', 'a', '\340'},
2020     {'\'', 'A', '\301'}, {'\'', 'a', '\341'},
2021     {'^', 'A', '\302'},  {'^', 'a', '\342'},
2022     {'~', 'A', '\303'},  {'~', 'a', '\343'},
2023     {'"', 'A', '\304'},  {'"', 'a', '\344'},
2024     {'O', 'A', '\305'},  {'o', 'a', '\345'},
2025     {'0', 'A', '\305'},  {'0', 'a', '\345'},
2026     {'A', 'A', '\305'},  {'a', 'a', '\345'},
2027     {'A', 'E', '\306'},  {'a', 'e', '\346'},
2028     {',', 'C', '\307'},  {',', 'c', '\347'},
2029     {'`', 'E', '\310'},  {'`', 'e', '\350'},
2030     {'\'', 'E', '\311'}, {'\'', 'e', '\351'},
2031     {'^', 'E', '\312'},  {'^', 'e', '\352'},
2032     {'"', 'E', '\313'},  {'"', 'e', '\353'},
2033     {'`', 'I', '\314'},  {'`', 'i', '\354'},
2034     {'\'', 'I', '\315'}, {'\'', 'i', '\355'},
2035     {'^', 'I', '\316'},  {'^', 'i', '\356'},
2036     {'"', 'I', '\317'},  {'"', 'i', '\357'},
2037     {'-', 'D', '\320'},  {'-', 'd', '\360'},
2038     {'~', 'N', '\321'},  {'~', 'n', '\361'},
2039     {'`', 'O', '\322'},  {'`', 'o', '\362'},
2040     {'\'', 'O', '\323'}, {'\'', 'o', '\363'},
2041     {'^', 'O', '\324'},  {'^', 'o', '\364'},
2042     {'~', 'O', '\325'},  {'~', 'o', '\365'},
2043     {'"', 'O', '\326'},  {'"', 'o', '\366'},
2044     {'/', 'O', '\330'},  {'/', 'o', '\370'},
2045     {'`', 'U', '\331'},  {'`', 'u', '\371'},
2046     {'\'', 'U', '\332'}, {'\'', 'u', '\372'},
2047     {'^', 'U', '\333'},  {'^', 'u', '\373'},
2048     {'"', 'U', '\334'},  {'"', 'u', '\374'},
2049     {'\'', 'Y', '\335'}, {'\'', 'y', '\375'},
2050     {'T', 'H', '\336'},  {'t', 'h', '\376'},
2051     {'s', 's', '\337'},  {'"', 'y', '\377'},
2052     {'s', 'z', '\337'},  {'i', 'j', '\377'},
2053         /* iso-8859-2 uses this */
2054     {'<', 'L', '\245'},  {'<', 'l', '\265'},    /* caron */
2055     {'<', 'S', '\251'},  {'<', 's', '\271'},
2056     {'<', 'T', '\253'},  {'<', 't', '\273'},
2057     {'<', 'Z', '\256'},  {'<', 'z', '\276'},
2058     {'<', 'C', '\310'},  {'<', 'c', '\350'},
2059     {'<', 'E', '\314'},  {'<', 'e', '\354'},
2060     {'<', 'D', '\317'},  {'<', 'd', '\357'},
2061     {'<', 'N', '\322'},  {'<', 'n', '\362'},
2062     {'<', 'R', '\330'},  {'<', 'r', '\370'},
2063     {';', 'A', '\241'},  {';', 'a', '\261'},    /* ogonek */
2064     {';', 'E', '\312'},  {';', 'e', '\332'},
2065     {'\'', 'Z', '\254'}, {'\'', 'z', '\274'},   /* acute */
2066     {'\'', 'R', '\300'}, {'\'', 'r', '\340'},
2067     {'\'', 'L', '\305'}, {'\'', 'l', '\345'},
2068     {'\'', 'C', '\306'}, {'\'', 'c', '\346'},
2069     {'\'', 'N', '\321'}, {'\'', 'n', '\361'},
2070 /*  collision whith S, from iso-8859-9 !!! */
2071     {',', 'S', '\252'},  {',', 's', '\272'},    /* cedilla */
2072     {',', 'T', '\336'},  {',', 't', '\376'},
2073     {'.', 'Z', '\257'},  {'.', 'z', '\277'},    /* dot above */
2074     {'/', 'L', '\243'},  {'/', 'l', '\263'},    /* slash */
2075     {'/', 'D', '\320'},  {'/', 'd', '\360'},
2076     {'(', 'A', '\303'},  {'(', 'a', '\343'},    /* breve */
2077     {'\275', 'O', '\325'}, {'\275', 'o', '\365'},       /* double acute */
2078     {'\275', 'U', '\334'}, {'\275', 'u', '\374'},
2079     {'0', 'U', '\332'},  {'0', 'u', '\372'},    /* ring above */
2080         /* iso-8859-3 uses this */
2081     {'/', 'H', '\241'},  {'/', 'h', '\261'},    /* slash */
2082     {'>', 'H', '\246'},  {'>', 'h', '\266'},    /* circumflex */
2083     {'>', 'J', '\254'},  {'>', 'j', '\274'},
2084     {'>', 'C', '\306'},  {'>', 'c', '\346'},
2085     {'>', 'G', '\330'},  {'>', 'g', '\370'},
2086     {'>', 'S', '\336'},  {'>', 's', '\376'},
2087 /*  collision whith G( from iso-8859-9 !!!   */
2088     {'(', 'G', '\253'},  {'(', 'g', '\273'},    /* breve */
2089     {'(', 'U', '\335'},  {'(', 'u', '\375'},
2090 /*  collision whith I. from iso-8859-3 !!!   */
2091     {'.', 'I', '\251'},  {'.', 'i', '\271'},    /* dot above */
2092     {'.', 'C', '\305'},  {'.', 'c', '\345'},
2093     {'.', 'G', '\325'},  {'.', 'g', '\365'},
2094         /* iso-8859-4 uses this */
2095     {',', 'R', '\243'},  {',', 'r', '\263'},    /* cedilla */
2096     {',', 'L', '\246'},  {',', 'l', '\266'},
2097     {',', 'G', '\253'},  {',', 'g', '\273'},
2098     {',', 'N', '\321'},  {',', 'n', '\361'},
2099     {',', 'K', '\323'},  {',', 'k', '\363'},
2100     {'~', 'I', '\245'},  {'~', 'i', '\265'},    /* tilde */
2101     {'-', 'E', '\252'},  {'-', 'e', '\272'},    /* macron */
2102     {'-', 'A', '\300'},  {'-', 'a', '\340'},
2103     {'-', 'I', '\317'},  {'-', 'i', '\357'},
2104     {'-', 'O', '\322'},  {'-', 'o', '\362'},
2105     {'-', 'U', '\336'},  {'-', 'u', '\376'},
2106     {'/', 'T', '\254'},  {'/', 't', '\274'},    /* slash */
2107     {'.', 'E', '\314'},  {'.', 'e', '\344'},    /* dot above */
2108     {';', 'I', '\307'},  {';', 'i', '\347'},    /* ogonek */
2109     {';', 'U', '\331'},  {';', 'u', '\371'},
2110         /* iso-8859-9 uses this */
2111         /* iso-8859-9 has really bad choosen G( S, and I. as they collide
2112          * whith the same letters on other iso-8859-x (that is they are on
2113          * different places :-( ), if you use turkish uncomment these and
2114          * comment out the lines in iso-8859-2 and iso-8859-3 sections
2115          * FIXME: should be dynamic according to chosen language
2116          *        if/when Wine has turkish support.  
2117          */ 
2118 /*  collision whith G( from iso-8859-3 !!!   */
2119 /*  {'(', 'G', '\320'},  {'(', 'g', '\360'}, */ /* breve */
2120 /*  collision whith S, from iso-8859-2 !!! */
2121 /*  {',', 'S', '\336'},  {',', 's', '\376'}, */ /* cedilla */
2122 /*  collision whith I. from iso-8859-3 !!!   */
2123 /*  {'.', 'I', '\335'},  {'.', 'i', '\375'}, */ /* dot above */
2124 };
2125
2126
2127 /***********************************************************************
2128  *           MSG_DoTranslateMessage
2129  *
2130  * Implementation of TranslateMessage.
2131  *
2132  * TranslateMessage translates virtual-key messages into character-messages,
2133  * as follows :
2134  * WM_KEYDOWN/WM_KEYUP combinations produce a WM_CHAR or WM_DEADCHAR message.
2135  * ditto replacing WM_* with WM_SYS*
2136  * This produces WM_CHAR messages only for keys mapped to ASCII characters
2137  * by the keyboard driver.
2138  */
2139 static BOOL MSG_DoTranslateMessage( UINT message, HWND hwnd,
2140                                       WPARAM wParam, LPARAM lParam )
2141 {
2142     static int dead_char;
2143     WCHAR wp[2];
2144     
2145     if (message != WM_MOUSEMOVE && message != WM_TIMER)
2146         TRACE("(%s, %04X, %08lX)\n",
2147                      SPY_GetMsgName(message), wParam, lParam );
2148     if(message >= WM_KEYFIRST && message <= WM_KEYLAST)
2149         TRACE_(key)("(%s, %04X, %08lX)\n",
2150                      SPY_GetMsgName(message), wParam, lParam );
2151
2152     if ((message != WM_KEYDOWN) && (message != WM_SYSKEYDOWN))  return FALSE;
2153
2154     TRACE_(key)("Translating key %s (%04x), scancode %02x\n",
2155                  SPY_GetVKeyName(wParam), wParam, LOBYTE(HIWORD(lParam)));
2156
2157     /* FIXME : should handle ToUnicode yielding 2 */
2158     switch (ToUnicode(wParam, HIWORD(lParam), QueueKeyStateTable, wp, 2, 0)) 
2159     {
2160     case 1:
2161         message = (message == WM_KEYDOWN) ? WM_CHAR : WM_SYSCHAR;
2162         /* Should dead chars handling go in ToAscii ? */
2163         if (dead_char)
2164         {
2165             int i;
2166
2167             if (wp[0] == ' ') wp[0] =  dead_char;
2168             if (dead_char == 0xa2) dead_char = '(';
2169             else if (dead_char == 0xa8) dead_char = '"';
2170             else if (dead_char == 0xb2) dead_char = ';';
2171             else if (dead_char == 0xb4) dead_char = '\'';
2172             else if (dead_char == 0xb7) dead_char = '<';
2173             else if (dead_char == 0xb8) dead_char = ',';
2174             else if (dead_char == 0xff) dead_char = '.';
2175             for (i = 0; i < sizeof(accent_chars)/sizeof(accent_chars[0]); i++)
2176                 if ((accent_chars[i].ac_accent == dead_char) &&
2177                     (accent_chars[i].ac_char == wp[0]))
2178                 {
2179                     wp[0] = accent_chars[i].ac_result;
2180                     break;
2181                 }
2182             dead_char = 0;
2183         }
2184         TRACE_(key)("1 -> PostMessage(%s)\n", SPY_GetMsgName(message));
2185         PostMessageW( hwnd, message, wp[0], lParam );
2186         return TRUE;
2187
2188     case -1:
2189         message = (message == WM_KEYDOWN) ? WM_DEADCHAR : WM_SYSDEADCHAR;
2190         dead_char = wp[0];
2191         TRACE_(key)("-1 -> PostMessage(%s)\n", SPY_GetMsgName(message));
2192         PostMessageW( hwnd, message, wp[0], lParam );
2193         return TRUE;
2194     }
2195     return FALSE;
2196 }
2197
2198
2199 /***********************************************************************
2200  *              TranslateMessage (USER.113)
2201  */
2202 BOOL16 WINAPI TranslateMessage16( const MSG16 *msg )
2203 {
2204     return MSG_DoTranslateMessage( msg->message, msg->hwnd,
2205                                    msg->wParam, msg->lParam );
2206 }
2207
2208
2209 /***********************************************************************
2210  *              TranslateMessage32 (USER.821)
2211  */
2212 BOOL16 WINAPI TranslateMessage32_16( const MSG32_16 *msg, BOOL16 wHaveParamHigh )
2213 {
2214     WPARAM wParam;
2215
2216     if (wHaveParamHigh)
2217         wParam = MAKELONG(msg->msg.wParam, msg->wParamHigh);
2218     else
2219         wParam = (WPARAM)msg->msg.wParam;
2220
2221     return MSG_DoTranslateMessage( msg->msg.message, msg->msg.hwnd,
2222                                    wParam, msg->msg.lParam );
2223 }
2224
2225 /***********************************************************************
2226  *              TranslateMessage (USER32.@)
2227  */
2228 BOOL WINAPI TranslateMessage( const MSG *msg )
2229 {
2230     return MSG_DoTranslateMessage( msg->message, msg->hwnd,
2231                                    msg->wParam, msg->lParam );
2232 }
2233
2234
2235 /***********************************************************************
2236  *              DispatchMessage (USER.114)
2237  */
2238 LONG WINAPI DispatchMessage16( const MSG16* msg )
2239 {
2240     WND * wndPtr;
2241     LONG retval;
2242     int painting;
2243     
2244       /* Process timer messages */
2245     if ((msg->message == WM_TIMER) || (msg->message == WM_SYSTIMER))
2246     {
2247         if (msg->lParam)
2248         {
2249             /* before calling window proc, verify whether timer is still valid;
2250                there's a slim chance that the application kills the timer
2251                between GetMessage and DispatchMessage API calls */
2252             if (!TIMER_IsTimerValid(msg->hwnd, (UINT) msg->wParam, (HWINDOWPROC) msg->lParam))
2253                 return 0; /* invalid winproc */
2254
2255             return CallWindowProc16( (WNDPROC16)msg->lParam, msg->hwnd,
2256                                    msg->message, msg->wParam, GetTickCount() );
2257         }
2258     }
2259
2260     if (!msg->hwnd) return 0;
2261     if (!(wndPtr = WIN_FindWndPtr( msg->hwnd ))) return 0;
2262     if (!wndPtr->winproc)
2263     {
2264         retval = 0;
2265         goto END;
2266     }
2267     painting = (msg->message == WM_PAINT);
2268     if (painting) wndPtr->flags |= WIN_NEEDS_BEGINPAINT;
2269
2270     SPY_EnterMessage( SPY_DISPATCHMESSAGE16, msg->hwnd, msg->message,
2271                       msg->wParam, msg->lParam );
2272     retval = CallWindowProc16( (WNDPROC16)wndPtr->winproc,
2273                                msg->hwnd, msg->message,
2274                                msg->wParam, msg->lParam );
2275     SPY_ExitMessage( SPY_RESULT_OK16, msg->hwnd, msg->message, retval, 
2276                      msg->wParam, msg->lParam );
2277
2278     WIN_ReleaseWndPtr(wndPtr);
2279     wndPtr = WIN_FindWndPtr(msg->hwnd);
2280     if (painting && wndPtr &&
2281         (wndPtr->flags & WIN_NEEDS_BEGINPAINT) && wndPtr->hrgnUpdate)
2282     {
2283         ERR("BeginPaint not called on WM_PAINT for hwnd %04x!\n", 
2284             msg->hwnd);
2285         wndPtr->flags &= ~WIN_NEEDS_BEGINPAINT;
2286         /* Validate the update region to avoid infinite WM_PAINT loop */
2287         RedrawWindow( wndPtr->hwndSelf, NULL, 0,
2288                       RDW_NOFRAME | RDW_VALIDATE | RDW_NOCHILDREN | RDW_NOINTERNALPAINT );
2289     }
2290 END:
2291     WIN_ReleaseWndPtr(wndPtr);
2292     return retval;
2293 }
2294
2295
2296 /***********************************************************************
2297  *              DispatchMessage32 (USER.822)
2298  */
2299 LONG WINAPI DispatchMessage32_16( const MSG32_16* lpmsg16_32, BOOL16 wHaveParamHigh )
2300 {
2301     if (wHaveParamHigh == FALSE)
2302         return DispatchMessage16(&(lpmsg16_32->msg));
2303     else
2304     {
2305         MSG msg;
2306
2307         msg.hwnd = lpmsg16_32->msg.hwnd;
2308         msg.message = lpmsg16_32->msg.message;
2309         msg.wParam = MAKELONG(lpmsg16_32->msg.wParam, lpmsg16_32->wParamHigh);
2310         msg.lParam = lpmsg16_32->msg.lParam;
2311         msg.time = lpmsg16_32->msg.time;
2312         msg.pt.x = (INT)lpmsg16_32->msg.pt.x;
2313         msg.pt.y = (INT)lpmsg16_32->msg.pt.y;
2314         return DispatchMessageA(&msg);
2315     }
2316 }
2317
2318 /***********************************************************************
2319  *              DispatchMessageA (USER32.@)
2320  */
2321 LONG WINAPI DispatchMessageA( const MSG* msg )
2322 {
2323     WND * wndPtr;
2324     LONG retval;
2325     int painting;
2326     
2327       /* Process timer messages */
2328     if ((msg->message == WM_TIMER) || (msg->message == WM_SYSTIMER))
2329     {
2330         if (msg->lParam)
2331         {
2332 /*            HOOK_CallHooks32A( WH_CALLWNDPROC, HC_ACTION, 0, FIXME ); */
2333
2334             /* before calling window proc, verify whether timer is still valid;
2335                there's a slim chance that the application kills the timer
2336                between GetMessage and DispatchMessage API calls */
2337             if (!TIMER_IsTimerValid(msg->hwnd, (UINT) msg->wParam, (HWINDOWPROC) msg->lParam))
2338                 return 0; /* invalid winproc */
2339
2340             return CallWindowProcA( (WNDPROC)msg->lParam, msg->hwnd,
2341                                    msg->message, msg->wParam, GetTickCount() );
2342         }
2343     }
2344
2345     if (!msg->hwnd) return 0;
2346     if (!(wndPtr = WIN_FindWndPtr( msg->hwnd ))) return 0;
2347     if (!wndPtr->winproc)
2348     {
2349         retval = 0;
2350         goto END;
2351     }
2352     painting = (msg->message == WM_PAINT);
2353     if (painting) wndPtr->flags |= WIN_NEEDS_BEGINPAINT;
2354 /*    HOOK_CallHooks32A( WH_CALLWNDPROC, HC_ACTION, 0, FIXME ); */
2355
2356     SPY_EnterMessage( SPY_DISPATCHMESSAGE, msg->hwnd, msg->message,
2357                       msg->wParam, msg->lParam );
2358     retval = CallWindowProcA( (WNDPROC)wndPtr->winproc,
2359                                 msg->hwnd, msg->message,
2360                                 msg->wParam, msg->lParam );
2361     SPY_ExitMessage( SPY_RESULT_OK, msg->hwnd, msg->message, retval,
2362                      msg->wParam, msg->lParam );
2363
2364     WIN_ReleaseWndPtr(wndPtr);
2365     wndPtr = WIN_FindWndPtr(msg->hwnd);
2366
2367     if (painting && wndPtr &&
2368         (wndPtr->flags & WIN_NEEDS_BEGINPAINT) && wndPtr->hrgnUpdate)
2369     {
2370         ERR("BeginPaint not called on WM_PAINT for hwnd %04x!\n", 
2371             msg->hwnd);
2372         wndPtr->flags &= ~WIN_NEEDS_BEGINPAINT;
2373         /* Validate the update region to avoid infinite WM_PAINT loop */
2374         RedrawWindow( wndPtr->hwndSelf, NULL, 0,
2375                       RDW_NOFRAME | RDW_VALIDATE | RDW_NOCHILDREN | RDW_NOINTERNALPAINT );
2376     }
2377 END:
2378     WIN_ReleaseWndPtr(wndPtr);
2379     return retval;
2380 }
2381
2382
2383 /***********************************************************************
2384  *              DispatchMessageW (USER32.@) Process Message
2385  *
2386  * Process the message specified in the structure *_msg_.
2387  *
2388  * If the lpMsg parameter points to a WM_TIMER message and the
2389  * parameter of the WM_TIMER message is not NULL, the lParam parameter
2390  * points to the function that is called instead of the window
2391  * procedure.
2392  *  
2393  * The message must be valid.
2394  *
2395  * RETURNS
2396  *
2397  *   DispatchMessage() returns the result of the window procedure invoked.
2398  *
2399  * CONFORMANCE
2400  *
2401  *   ECMA-234, Win32 
2402  *
2403  */
2404 LONG WINAPI DispatchMessageW( const MSG* msg )
2405 {
2406     WND * wndPtr;
2407     LONG retval;
2408     int painting;
2409     
2410       /* Process timer messages */
2411     if ((msg->message == WM_TIMER) || (msg->message == WM_SYSTIMER))
2412     {
2413         if (msg->lParam)
2414         {
2415 /*            HOOK_CallHooks32W( WH_CALLWNDPROC, HC_ACTION, 0, FIXME ); */
2416
2417             /* before calling window proc, verify whether timer is still valid;
2418                there's a slim chance that the application kills the timer
2419                between GetMessage and DispatchMessage API calls */
2420             if (!TIMER_IsTimerValid(msg->hwnd, (UINT) msg->wParam, (HWINDOWPROC) msg->lParam))
2421                 return 0; /* invalid winproc */
2422
2423             return CallWindowProcW( (WNDPROC)msg->lParam, msg->hwnd,
2424                                    msg->message, msg->wParam, GetTickCount() );
2425         }
2426     }
2427
2428     if (!msg->hwnd) return 0;
2429     if (!(wndPtr = WIN_FindWndPtr( msg->hwnd ))) return 0;
2430     if (!wndPtr->winproc)
2431     {
2432         retval = 0;
2433         goto END;
2434     }
2435     painting = (msg->message == WM_PAINT);
2436     if (painting) wndPtr->flags |= WIN_NEEDS_BEGINPAINT;
2437 /*    HOOK_CallHooks32W( WH_CALLWNDPROC, HC_ACTION, 0, FIXME ); */
2438
2439     SPY_EnterMessage( SPY_DISPATCHMESSAGE, msg->hwnd, msg->message,
2440                       msg->wParam, msg->lParam );
2441     retval = CallWindowProcW( (WNDPROC)wndPtr->winproc,
2442                                 msg->hwnd, msg->message,
2443                                 msg->wParam, msg->lParam );
2444     SPY_ExitMessage( SPY_RESULT_OK, msg->hwnd, msg->message, retval,
2445                      msg->wParam, msg->lParam );
2446
2447     WIN_ReleaseWndPtr(wndPtr);
2448     wndPtr = WIN_FindWndPtr(msg->hwnd);
2449
2450     if (painting && wndPtr &&
2451         (wndPtr->flags & WIN_NEEDS_BEGINPAINT) && wndPtr->hrgnUpdate)
2452     {
2453         ERR("BeginPaint not called on WM_PAINT for hwnd %04x!\n", 
2454             msg->hwnd);
2455         wndPtr->flags &= ~WIN_NEEDS_BEGINPAINT;
2456         /* Validate the update region to avoid infinite WM_PAINT loop */
2457         RedrawWindow( wndPtr->hwndSelf, NULL, 0,
2458                       RDW_NOFRAME | RDW_VALIDATE | RDW_NOCHILDREN | RDW_NOINTERNALPAINT );
2459     }
2460 END:
2461     WIN_ReleaseWndPtr(wndPtr);
2462     return retval;
2463 }
2464
2465
2466 /***********************************************************************
2467  *              RegisterWindowMessage (USER.118)
2468  *              RegisterWindowMessageA (USER32.@)
2469  */
2470 WORD WINAPI RegisterWindowMessageA( LPCSTR str )
2471 {
2472     TRACE("%s\n", str );
2473     return GlobalAddAtomA( str );
2474 }
2475
2476
2477 /***********************************************************************
2478  *              RegisterWindowMessageW (USER32.@)
2479  */
2480 WORD WINAPI RegisterWindowMessageW( LPCWSTR str )
2481 {
2482     TRACE("%p\n", str );
2483     return GlobalAddAtomW( str );
2484 }
2485
2486
2487 /***********************************************************************
2488  *              InSendMessage (USER.192)
2489  */
2490 BOOL16 WINAPI InSendMessage16(void)
2491 {
2492     return InSendMessage();
2493 }
2494
2495
2496 /***********************************************************************
2497  *              InSendMessage (USER32.@)
2498  */
2499 BOOL WINAPI InSendMessage(void)
2500 {
2501     return (InSendMessageEx(NULL) & (ISMEX_SEND|ISMEX_REPLIED)) == ISMEX_SEND;
2502 }
2503
2504
2505 /***********************************************************************
2506  *              InSendMessageEx  (USER32.@)
2507  */
2508 DWORD WINAPI InSendMessageEx( LPVOID reserved )
2509 {
2510     DWORD ret = 0;
2511     SERVER_START_REQ( in_send_message )
2512     {
2513         if (!SERVER_CALL_ERR()) ret = req->flags;
2514     }
2515     SERVER_END_REQ;
2516     return ret;
2517 }
2518
2519
2520 /***********************************************************************
2521  *              BroadcastSystemMessage (USER32.@)
2522  */
2523 LONG WINAPI BroadcastSystemMessage(
2524         DWORD dwFlags,LPDWORD recipients,UINT uMessage,WPARAM wParam,
2525         LPARAM lParam
2526 ) {
2527         FIXME("(%08lx,%08lx,%08x,%08x,%08lx): stub!\n",
2528               dwFlags,*recipients,uMessage,wParam,lParam
2529         );
2530         return 0;
2531 }
2532
2533 /***********************************************************************
2534  *              SendNotifyMessageA (USER32.@)
2535  */
2536 BOOL WINAPI SendNotifyMessageA(HWND hwnd,UINT msg,WPARAM wParam,LPARAM lParam)
2537 {
2538    return MSG_SendMessage(hwnd, msg, wParam, lParam, INFINITE, QMSG_WIN32A, NULL);
2539 }
2540
2541 /***********************************************************************
2542  *              SendNotifyMessageW (USER32.@)
2543  */
2544 BOOL WINAPI SendNotifyMessageW(HWND hwnd,UINT msg,WPARAM wParam,LPARAM lParam)
2545 {
2546    return MSG_SendMessage(hwnd, msg, wParam, lParam, INFINITE, QMSG_WIN32W, NULL);
2547 }
2548
2549 /***********************************************************************
2550  *              SendMessageCallbackA (USER32.@)
2551  * FIXME: It's like PostMessage. The callback gets called when the message
2552  * is processed. We have to modify the message processing for an exact
2553  * implementation...
2554  * The callback is only called when the thread that called us calls one of
2555  * Get/Peek/WaitMessage.
2556  */
2557 BOOL WINAPI SendMessageCallbackA(
2558         HWND hWnd,UINT Msg,WPARAM wParam,LPARAM lParam,
2559         FARPROC lpResultCallBack,DWORD dwData)
2560 {       
2561         FIXME("(0x%04x,0x%04x,0x%08x,0x%08lx,%p,0x%08lx),stub!\n",
2562               hWnd,Msg,wParam,lParam,lpResultCallBack,dwData);
2563         if ( hWnd == HWND_BROADCAST)
2564         {       PostMessageA( hWnd, Msg, wParam, lParam);
2565                 FIXME("Broadcast: Callback will not be called!\n");
2566                 return TRUE;
2567         }
2568         (lpResultCallBack)( hWnd, Msg, dwData, SendMessageA ( hWnd, Msg, wParam, lParam ));
2569                 return TRUE;
2570 }
2571 /***********************************************************************
2572  *              SendMessageCallbackW (USER32.@)
2573  * FIXME: see SendMessageCallbackA.
2574  */
2575 BOOL WINAPI SendMessageCallbackW(
2576         HWND hWnd,UINT Msg,WPARAM wParam,LPARAM lParam,
2577         FARPROC lpResultCallBack,DWORD dwData)
2578 {       
2579         FIXME("(0x%04x,0x%04x,0x%08x,0x%08lx,%p,0x%08lx),stub!\n",
2580               hWnd,Msg,wParam,lParam,lpResultCallBack,dwData);
2581         if ( hWnd == HWND_BROADCAST)
2582         {       PostMessageW( hWnd, Msg, wParam, lParam);
2583                 FIXME("Broadcast: Callback will not be called!\n");
2584                 return TRUE;
2585         }
2586         (lpResultCallBack)( hWnd, Msg, dwData, SendMessageA ( hWnd, Msg, wParam, lParam ));
2587                 return TRUE;
2588 }