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