Release 980614
[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 "message.h"
14 #include "win.h"
15 #include "gdi.h"
16 #include "sysmetrics.h"
17 #include "heap.h"
18 #include "hook.h"
19 #include "keyboard.h"
20 #include "spy.h"
21 #include "winpos.h"
22 #include "atom.h"
23 #include "dde.h"
24 #include "queue.h"
25 #include "winproc.h"
26 #include "process.h"
27 #include "thread.h"
28 #include "options.h"
29 #include "debug.h"
30
31 #define WM_NCMOUSEFIRST         WM_NCMOUSEMOVE
32 #define WM_NCMOUSELAST          WM_NCMBUTTONDBLCLK
33
34 typedef enum { SYSQ_MSG_ABANDON, SYSQ_MSG_SKIP, 
35                SYSQ_MSG_ACCEPT, SYSQ_MSG_CONTINUE } SYSQ_STATUS;
36
37 extern MESSAGEQUEUE *pCursorQueue;                       /* queue.c */
38 extern MESSAGEQUEUE *pActiveQueue;
39
40 DWORD MSG_WineStartTicks; /* Ticks at Wine startup */
41
42 static UINT32 doubleClickSpeed = 452;
43 static INT32 debugSMRL = 0;       /* intertask SendMessage() recursion level */
44
45 /***********************************************************************
46  *           MSG_CheckFilter
47  */
48 BOOL32 MSG_CheckFilter(WORD uMsg, DWORD filter)
49 {
50    if( filter )
51        return (uMsg >= LOWORD(filter) && uMsg <= HIWORD(filter));
52    return TRUE;
53 }
54
55 /***********************************************************************
56  *           MSG_SendParentNotify
57  *
58  * Send a WM_PARENTNOTIFY to all ancestors of the given window, unless
59  * the window has the WS_EX_NOPARENTNOTIFY style.
60  */
61 static void MSG_SendParentNotify(WND* wndPtr, WORD event, WORD idChild, LPARAM lValue)
62 {
63 #define lppt ((LPPOINT16)&lValue)
64
65     /* pt has to be in the client coordinates of the parent window */
66
67     MapWindowPoints16( 0, wndPtr->hwndSelf, lppt, 1 );
68     while (wndPtr)
69     {
70         if (!(wndPtr->dwStyle & WS_CHILD) || (wndPtr->dwExStyle & WS_EX_NOPARENTNOTIFY)) break;
71         lppt->x += wndPtr->rectClient.left;
72         lppt->y += wndPtr->rectClient.top;
73         wndPtr = wndPtr->parent;
74         SendMessage32A( wndPtr->hwndSelf, WM_PARENTNOTIFY,
75                         MAKEWPARAM( event, idChild ), lValue );
76     }
77 #undef lppt
78 }
79
80
81 /***********************************************************************
82  *           MSG_TranslateMouseMsg
83  *
84  * Translate an mouse hardware event into a real mouse message.
85  * Return value indicates whether the translated message must be passed
86  * to the user, left in the queue, or skipped entirely (in this case
87  * HIWORD contains hit test code).
88  */
89 static DWORD MSG_TranslateMouseMsg( HWND16 hTopWnd, DWORD filter, 
90                                     MSG16 *msg, BOOL32 remove, WND* pWndScope )
91 {
92     static DWORD   dblclk_time_limit = 0;
93     static UINT16     clk_message = 0;
94     static HWND16     clk_hwnd = 0;
95     static POINT16    clk_pos = { 0, 0 };
96
97     WND *pWnd;
98     HWND16 hWnd;
99     INT16 ht, hittest, sendSC = 0;
100     UINT16 message = msg->message;
101     POINT16 screen_pt, pt;
102     HANDLE16 hQ = GetTaskQueue(0);
103     MESSAGEQUEUE *queue = (MESSAGEQUEUE *)GlobalLock16(hQ);
104     BOOL32 eatMsg = FALSE;
105     BOOL32 mouseClick = ((message == WM_LBUTTONDOWN) ||
106                          (message == WM_RBUTTONDOWN) ||
107                          (message == WM_MBUTTONDOWN))?1:0;
108     SYSQ_STATUS ret = 0;
109
110       /* Find the window */
111
112     ht = hittest = HTCLIENT;
113     hWnd = GetCapture16();
114     if( !hWnd )
115     {
116         ht = hittest = WINPOS_WindowFromPoint( pWndScope, msg->pt, &pWnd );
117         if( !pWnd ) pWnd = WIN_GetDesktop();
118         hWnd = pWnd->hwndSelf;
119         sendSC = 1;
120     } 
121     else 
122     {
123         pWnd = WIN_FindWndPtr(hWnd);
124         ht = EVENT_GetCaptureInfo();
125     }
126
127         /* stop if not the right queue */
128
129     if (pWnd->hmemTaskQ != hQ)
130     {
131         /* Not for the current task */
132         if (queue) QUEUE_ClearWakeBit( queue, QS_MOUSE );
133         /* Wake up the other task */
134         queue = (MESSAGEQUEUE *)GlobalLock16( pWnd->hmemTaskQ );
135         if (queue) QUEUE_SetWakeBit( queue, QS_MOUSE );
136         return SYSQ_MSG_ABANDON;
137     }
138
139         /* check if hWnd is within hWndScope */
140
141     if( hTopWnd && hWnd != hTopWnd )
142         if( !IsChild16(hTopWnd, hWnd) ) return SYSQ_MSG_CONTINUE;
143
144     if( mouseClick )
145     {
146         /* translate double clicks -
147          * note that ...MOUSEMOVEs can slip in between
148          * ...BUTTONDOWN and ...BUTTONDBLCLK messages */
149
150         if( pWnd->class->style & CS_DBLCLKS || ht != HTCLIENT )
151         {
152            if ((message == clk_message) && (hWnd == clk_hwnd) &&
153                (msg->time - dblclk_time_limit < doubleClickSpeed) &&
154                (abs(msg->pt.x - clk_pos.x) < SYSMETRICS_CXDOUBLECLK/2) &&
155                (abs(msg->pt.y - clk_pos.y) < SYSMETRICS_CYDOUBLECLK/2))
156            {
157               message += (WM_LBUTTONDBLCLK - WM_LBUTTONDOWN);
158               mouseClick++;   /* == 2 */
159            }
160         }
161     }
162     screen_pt = pt = msg->pt;
163
164     if (hittest != HTCLIENT)
165     {
166         message += ((INT16)WM_NCMOUSEMOVE - WM_MOUSEMOVE);
167         msg->wParam = hittest;
168     }
169     else ScreenToClient16( hWnd, &pt );
170
171         /* check message filter */
172
173     if (!MSG_CheckFilter(message, filter)) return SYSQ_MSG_CONTINUE;
174
175     pCursorQueue = queue;
176
177         /* call WH_MOUSE */
178
179     if (HOOK_IsHooked( WH_MOUSE ))
180     { 
181         MOUSEHOOKSTRUCT16 *hook = SEGPTR_NEW(MOUSEHOOKSTRUCT16);
182         if( hook )
183         {
184             hook->pt           = screen_pt;
185             hook->hwnd         = hWnd;
186             hook->wHitTestCode = hittest;
187             hook->dwExtraInfo  = 0;
188             ret = HOOK_CallHooks16( WH_MOUSE, remove ? HC_ACTION : HC_NOREMOVE,
189                                     message, (LPARAM)SEGPTR_GET(hook) );
190             SEGPTR_FREE(hook);
191         }
192         if( ret ) return MAKELONG((INT16)SYSQ_MSG_SKIP, hittest);
193     }
194
195     if ((hittest == HTERROR) || (hittest == HTNOWHERE)) 
196         eatMsg = sendSC = 1;
197     else if( remove && mouseClick )
198     {
199         HWND32 hwndTop = WIN_GetTopParent( hWnd );
200
201         if( mouseClick == 1 )
202         {
203             /* set conditions */
204             dblclk_time_limit = msg->time;
205                clk_message = msg->message;
206                clk_hwnd = hWnd;
207                clk_pos = screen_pt;
208         } else 
209             /* got double click - zero them out */
210             dblclk_time_limit = clk_hwnd = 0;
211
212         if( sendSC )
213         {
214             /* Send the WM_PARENTNOTIFY,
215              * note that even for double/nonclient clicks
216              * notification message is still WM_L/M/RBUTTONDOWN.
217              */
218
219             MSG_SendParentNotify( pWnd, msg->message, 0, MAKELPARAM(screen_pt.x, screen_pt.y) );
220
221             /* Activate the window if needed */
222
223             if (hWnd != GetActiveWindow16() && hWnd != GetDesktopWindow16())
224             {
225                 LONG ret = SendMessage16( hWnd, WM_MOUSEACTIVATE, hwndTop,
226                                           MAKELONG( hittest, message ) );
227
228                 if ((ret == MA_ACTIVATEANDEAT) || (ret == MA_NOACTIVATEANDEAT))
229                          eatMsg = TRUE;
230
231                 if (((ret == MA_ACTIVATE) || (ret == MA_ACTIVATEANDEAT)) 
232                       && hwndTop != GetActiveWindow16() )
233                       if (!WINPOS_SetActiveWindow( hwndTop, TRUE , TRUE ))
234                          eatMsg = TRUE;
235             }
236         }
237     } else sendSC = (remove && sendSC);
238
239      /* Send the WM_SETCURSOR message */
240
241     if (sendSC)
242         SendMessage16( hWnd, WM_SETCURSOR, (WPARAM16)hWnd,
243                        MAKELONG( hittest, message ));
244     if (eatMsg) return MAKELONG( (UINT16)SYSQ_MSG_SKIP, hittest);
245
246     msg->hwnd    = hWnd;
247     msg->message = message;
248     msg->lParam  = MAKELONG( pt.x, pt.y );
249     return SYSQ_MSG_ACCEPT;
250 }
251
252
253 /***********************************************************************
254  *           MSG_TranslateKbdMsg
255  *
256  * Translate an keyboard hardware event into a real message.
257  */
258 static DWORD MSG_TranslateKbdMsg( HWND16 hTopWnd, DWORD filter,
259                                   MSG16 *msg, BOOL32 remove )
260 {
261     WORD message = msg->message;
262     HWND16 hWnd = GetFocus16();
263     WND *pWnd;
264
265       /* Should check Ctrl-Esc and PrintScreen here */
266
267     if (!hWnd)
268     {
269           /* Send the message to the active window instead,  */
270           /* translating messages to their WM_SYS equivalent */
271
272         hWnd = GetActiveWindow16();
273
274         if( message < WM_SYSKEYDOWN )
275             message += WM_SYSKEYDOWN - WM_KEYDOWN;
276     }
277     pWnd = WIN_FindWndPtr( hWnd );
278     if (pWnd && (pWnd->hmemTaskQ != GetTaskQueue(0)))
279     {
280         /* Not for the current task */
281         MESSAGEQUEUE *queue = (MESSAGEQUEUE *)GlobalLock16( GetTaskQueue(0) );
282         if (queue) QUEUE_ClearWakeBit( queue, QS_KEY );
283         /* Wake up the other task */
284         queue = (MESSAGEQUEUE *)GlobalLock16( pWnd->hmemTaskQ );
285         if (queue) QUEUE_SetWakeBit( queue, QS_KEY );
286         return SYSQ_MSG_ABANDON;
287     }
288
289     if (hTopWnd && hWnd != hTopWnd)
290         if (!IsChild16(hTopWnd, hWnd)) return SYSQ_MSG_CONTINUE;
291     if (!MSG_CheckFilter(message, filter)) return SYSQ_MSG_CONTINUE;
292
293     msg->hwnd = hWnd;
294     msg->message = message;
295
296     return (HOOK_CallHooks16( WH_KEYBOARD, remove ? HC_ACTION : HC_NOREMOVE,
297                               msg->wParam, msg->lParam )
298             ? SYSQ_MSG_SKIP : SYSQ_MSG_ACCEPT);
299 }
300
301
302 /***********************************************************************
303  *           MSG_JournalRecordMsg
304  *
305  * Build an EVENTMSG structure and call JOURNALRECORD hook
306  */
307 static void MSG_JournalRecordMsg( MSG16 *msg )
308 {
309     EVENTMSG16 *event = SEGPTR_NEW(EVENTMSG16);
310     if (!event) return;
311     event->message = msg->message;
312     event->time = msg->time;
313     if ((msg->message >= WM_KEYFIRST) && (msg->message <= WM_KEYLAST))
314     {
315         event->paramL = (msg->wParam & 0xFF) | (HIWORD(msg->lParam) << 8);
316         event->paramH = msg->lParam & 0x7FFF;  
317         if (HIWORD(msg->lParam) & 0x0100)
318             event->paramH |= 0x8000;               /* special_key - bit */
319         HOOK_CallHooks16( WH_JOURNALRECORD, HC_ACTION, 0,
320                           (LPARAM)SEGPTR_GET(event) );
321     }
322     else if ((msg->message >= WM_MOUSEFIRST) && (msg->message <= WM_MOUSELAST))
323     {
324         event->paramL = LOWORD(msg->lParam);       /* X pos */
325         event->paramH = HIWORD(msg->lParam);       /* Y pos */ 
326         ClientToScreen16( msg->hwnd, (LPPOINT16)&event->paramL );
327         HOOK_CallHooks16( WH_JOURNALRECORD, HC_ACTION, 0,
328                           (LPARAM)SEGPTR_GET(event) );
329     }
330     else if ((msg->message >= WM_NCMOUSEFIRST) &&
331              (msg->message <= WM_NCMOUSELAST))
332     {
333         event->paramL = LOWORD(msg->lParam);       /* X pos */
334         event->paramH = HIWORD(msg->lParam);       /* Y pos */ 
335         event->message += WM_MOUSEMOVE-WM_NCMOUSEMOVE;/* give no info about NC area */
336         HOOK_CallHooks16( WH_JOURNALRECORD, HC_ACTION, 0,
337                           (LPARAM)SEGPTR_GET(event) );
338     }
339     SEGPTR_FREE(event);
340 }
341
342 /***********************************************************************
343  *          MSG_JournalPlayBackMsg
344  *
345  * Get an EVENTMSG struct via call JOURNALPLAYBACK hook function 
346  */
347 static int MSG_JournalPlayBackMsg(void)
348 {
349  EVENTMSG16 *tmpMsg;
350  long wtime,lParam;
351  WORD keyDown,i,wParam,result=0;
352
353  if ( HOOK_IsHooked( WH_JOURNALPLAYBACK ) )
354  {
355   tmpMsg = SEGPTR_NEW(EVENTMSG16);
356   wtime=HOOK_CallHooks16( WH_JOURNALPLAYBACK, HC_GETNEXT, 0,
357                           (LPARAM)SEGPTR_GET(tmpMsg));
358   /*  TRACE(msg,"Playback wait time =%ld\n",wtime); */
359   if (wtime<=0)
360   {
361    wtime=0;
362    if ((tmpMsg->message>= WM_KEYFIRST) && (tmpMsg->message <= WM_KEYLAST))
363    {
364      wParam=tmpMsg->paramL & 0xFF;
365      lParam=MAKELONG(tmpMsg->paramH&0x7ffff,tmpMsg->paramL>>8);
366      if (tmpMsg->message == WM_KEYDOWN || tmpMsg->message == WM_SYSKEYDOWN)
367      {
368        for (keyDown=i=0; i<256 && !keyDown; i++)
369           if (InputKeyStateTable[i] & 0x80)
370             keyDown++;
371        if (!keyDown)
372          lParam |= 0x40000000;       
373        AsyncKeyStateTable[wParam]=InputKeyStateTable[wParam] |= 0x80;
374      }  
375      else                                       /* WM_KEYUP, WM_SYSKEYUP */
376      {
377        lParam |= 0xC0000000;      
378        AsyncKeyStateTable[wParam]=InputKeyStateTable[wParam] &= ~0x80;
379      }
380      if (InputKeyStateTable[VK_MENU] & 0x80)
381        lParam |= 0x20000000;     
382      if (tmpMsg->paramH & 0x8000)              /*special_key bit*/
383        lParam |= 0x01000000;
384      hardware_event( tmpMsg->message, wParam, lParam,0, 0, tmpMsg->time, 0 );     
385    }
386    else
387    {
388     if ((tmpMsg->message>= WM_MOUSEFIRST) && (tmpMsg->message <= WM_MOUSELAST))
389     {
390      switch (tmpMsg->message)
391      {
392       case WM_LBUTTONDOWN:
393           MouseButtonsStates[0]=AsyncMouseButtonsStates[0]=TRUE;break;
394       case WM_LBUTTONUP:
395           MouseButtonsStates[0]=AsyncMouseButtonsStates[0]=FALSE;break;
396       case WM_MBUTTONDOWN:
397           MouseButtonsStates[1]=AsyncMouseButtonsStates[1]=TRUE;break;
398       case WM_MBUTTONUP:
399           MouseButtonsStates[1]=AsyncMouseButtonsStates[1]=FALSE;break;
400       case WM_RBUTTONDOWN:
401           MouseButtonsStates[2]=AsyncMouseButtonsStates[2]=TRUE;break;
402       case WM_RBUTTONUP:
403           MouseButtonsStates[2]=AsyncMouseButtonsStates[2]=FALSE;break;      
404      }
405      AsyncKeyStateTable[VK_LBUTTON]= InputKeyStateTable[VK_LBUTTON] = MouseButtonsStates[0] ? 0x80 : 0;
406      AsyncKeyStateTable[VK_MBUTTON]= InputKeyStateTable[VK_MBUTTON] = MouseButtonsStates[1] ? 0x80 : 0;
407      AsyncKeyStateTable[VK_RBUTTON]= InputKeyStateTable[VK_RBUTTON] = MouseButtonsStates[2] ? 0x80 : 0;
408      SetCursorPos32(tmpMsg->paramL,tmpMsg->paramH);
409      lParam=MAKELONG(tmpMsg->paramL,tmpMsg->paramH);
410      wParam=0;             
411      if (MouseButtonsStates[0]) wParam |= MK_LBUTTON;
412      if (MouseButtonsStates[1]) wParam |= MK_MBUTTON;
413      if (MouseButtonsStates[2]) wParam |= MK_RBUTTON;
414      hardware_event( tmpMsg->message, wParam, lParam,  
415                      tmpMsg->paramL, tmpMsg->paramH, tmpMsg->time, 0 );
416     }
417    }
418    HOOK_CallHooks16( WH_JOURNALPLAYBACK, HC_SKIP, 0,
419                      (LPARAM)SEGPTR_GET(tmpMsg));
420   }
421   else
422   {
423     if( tmpMsg->message == WM_QUEUESYNC )
424         if (HOOK_IsHooked( WH_CBT ))
425             HOOK_CallHooks16( WH_CBT, HCBT_QS, 0, 0L);
426
427     result= QS_MOUSE | QS_KEY; /* ? */
428   }
429   SEGPTR_FREE(tmpMsg);
430  }
431  return result;
432
433
434 /***********************************************************************
435  *           MSG_PeekHardwareMsg
436  *
437  * Peek for a hardware message matching the hwnd and message filters.
438  */
439 static BOOL32 MSG_PeekHardwareMsg( MSG16 *msg, HWND16 hwnd, DWORD filter,
440                                    BOOL32 remove )
441 {
442     DWORD status = SYSQ_MSG_ACCEPT;
443     MESSAGEQUEUE *sysMsgQueue = QUEUE_GetSysQueue();
444     int i, kbd_msg, pos = sysMsgQueue->nextMessage;
445
446     /* FIXME: there has to be a better way to do this */
447     joySendMessages();
448
449     /* If the queue is empty, attempt to fill it */
450     if (!sysMsgQueue->msgCount && TSXPending(display))
451         EVENT_WaitNetEvent( FALSE, FALSE );
452
453     for (i = kbd_msg = 0; i < sysMsgQueue->msgCount; i++, pos++)
454     {
455         if (pos >= sysMsgQueue->queueSize) pos = 0;
456         *msg = sysMsgQueue->messages[pos].msg;
457
458           /* Translate message */
459
460         if ((msg->message >= WM_MOUSEFIRST) && (msg->message <= WM_MOUSELAST))
461         {
462             HWND32 hWndScope = (HWND32)sysMsgQueue->messages[pos].extraInfo;
463
464             status = MSG_TranslateMouseMsg(hwnd, filter, msg, remove, 
465                                           (Options.managed && IsWindow32(hWndScope) ) 
466                                            ? WIN_FindWndPtr(hWndScope) : WIN_GetDesktop() );
467             kbd_msg = 0;
468         }
469         else if ((msg->message >= WM_KEYFIRST) && (msg->message <= WM_KEYLAST))
470         {
471             status = MSG_TranslateKbdMsg(hwnd, filter, msg, remove);
472             kbd_msg = 1;
473         }
474         else /* Non-standard hardware event */
475         {
476             HARDWAREHOOKSTRUCT16 *hook;
477             if ((hook = SEGPTR_NEW(HARDWAREHOOKSTRUCT16)))
478             {
479                 BOOL32 ret;
480                 hook->hWnd     = msg->hwnd;
481                 hook->wMessage = msg->message;
482                 hook->wParam   = msg->wParam;
483                 hook->lParam   = msg->lParam;
484                 ret = HOOK_CallHooks16( WH_HARDWARE,
485                                         remove ? HC_ACTION : HC_NOREMOVE,
486                                         0, (LPARAM)SEGPTR_GET(hook) );
487                 SEGPTR_FREE(hook);
488                 if (ret) 
489                 {
490                     QUEUE_RemoveMsg( sysMsgQueue, pos );
491                     continue;
492                 }
493                 status = SYSQ_MSG_ACCEPT; 
494             }
495         }
496
497         switch (LOWORD(status))
498         {
499            case SYSQ_MSG_ACCEPT:
500                 break;
501
502            case SYSQ_MSG_SKIP:
503                 if (HOOK_IsHooked( WH_CBT ))
504                    if( kbd_msg )
505                        HOOK_CallHooks16( WH_CBT, HCBT_KEYSKIPPED, 
506                                                  msg->wParam, msg->lParam );
507                    else
508                    {
509                        MOUSEHOOKSTRUCT16 *hook = SEGPTR_NEW(MOUSEHOOKSTRUCT16);
510                        if (hook)
511                        {
512                            hook->pt           = msg->pt;
513                            hook->hwnd         = msg->hwnd;
514                            hook->wHitTestCode = HIWORD(status);
515                            hook->dwExtraInfo  = 0;
516                            HOOK_CallHooks16( WH_CBT, HCBT_CLICKSKIPPED ,msg->message,
517                                           (LPARAM)SEGPTR_GET(hook) );
518                            SEGPTR_FREE(hook);
519                        }
520                    }
521
522                 if (remove)
523                     QUEUE_RemoveMsg( sysMsgQueue, pos );
524                 /* continue */
525
526            case SYSQ_MSG_CONTINUE:
527                 continue;
528
529            case SYSQ_MSG_ABANDON: 
530                 return FALSE;
531         }
532
533         if (remove)
534         {
535             if (HOOK_IsHooked( WH_JOURNALRECORD )) MSG_JournalRecordMsg( msg );
536             QUEUE_RemoveMsg( sysMsgQueue, pos );
537         }
538         return TRUE;
539     }
540     return FALSE;
541 }
542
543
544 /**********************************************************************
545  *           SetDoubleClickTime16   (USER.20)
546  */
547 void WINAPI SetDoubleClickTime16( UINT16 interval )
548 {
549     SetDoubleClickTime32( interval );
550 }               
551
552
553 /**********************************************************************
554  *           SetDoubleClickTime32   (USER32.480)
555  */
556 BOOL32 WINAPI SetDoubleClickTime32( UINT32 interval )
557 {
558     doubleClickSpeed = interval ? interval : 500;
559     return TRUE;
560 }               
561
562
563 /**********************************************************************
564  *           GetDoubleClickTime16   (USER.21)
565  */
566 UINT16 WINAPI GetDoubleClickTime16(void)
567 {
568     return doubleClickSpeed;
569 }               
570
571
572 /**********************************************************************
573  *           GetDoubleClickTime32   (USER32.239)
574  */
575 UINT32 WINAPI GetDoubleClickTime32(void)
576 {
577     return doubleClickSpeed;
578 }               
579
580
581 /***********************************************************************
582  *           MSG_SendMessage
583  *
584  * Implementation of an inter-task SendMessage.
585  */
586 static LRESULT MSG_SendMessage( HQUEUE16 hDestQueue, HWND16 hwnd, UINT16 msg,
587                                 WPARAM32 wParam, LPARAM lParam, WORD flags )
588 {
589     INT32         prevSMRL = debugSMRL;
590     QSMCTRL       qCtrl = { 0, 1};
591     MESSAGEQUEUE *queue, *destQ;
592
593     if (!(queue = (MESSAGEQUEUE*)GlobalLock16( GetTaskQueue(0) ))) return 0;
594     if (!(destQ = (MESSAGEQUEUE*)GlobalLock16( hDestQueue ))) return 0;
595
596     if (IsTaskLocked() || !IsWindow32(hwnd)) return 0;
597
598     debugSMRL+=4;
599     TRACE(sendmsg,"%*sSM: %s [%04x] (%04x -> %04x)\n", 
600                     prevSMRL, "", SPY_GetMsgName(msg), msg, queue->self, hDestQueue );
601
602     if( !(queue->wakeBits & QS_SMPARAMSFREE) )
603     {
604       TRACE(sendmsg,"\tIntertask SendMessage: sleeping since unreplied SendMessage pending\n");
605       queue->changeBits &= ~QS_SMPARAMSFREE;
606       QUEUE_WaitBits( QS_SMPARAMSFREE );
607     }
608
609     /* resume sending */ 
610
611     queue->hWnd       = hwnd;
612     queue->msg        = msg;
613     queue->wParam     = LOWORD(wParam);
614     queue->wParamHigh = HIWORD(wParam);
615     queue->lParam     = lParam;
616     queue->hPrevSendingTask = destQ->hSendingTask;
617     destQ->hSendingTask = GetTaskQueue(0);
618
619     queue->wakeBits &= ~QS_SMPARAMSFREE;
620     queue->flags = (queue->flags & ~(QUEUE_SM_WIN32|QUEUE_SM_UNICODE)) | flags;
621
622     TRACE(sendmsg,"%*ssm: smResultInit = %08x\n", prevSMRL, "", (unsigned)&qCtrl);
623
624     queue->smResultInit = &qCtrl;
625
626     QUEUE_SetWakeBit( destQ, QS_SENDMESSAGE );
627
628     /* perform task switch and wait for the result */
629
630     while( qCtrl.bPending )
631     {
632       if (!(queue->wakeBits & QS_SMRESULT))
633       {
634         queue->changeBits &= ~QS_SMRESULT;
635         DirectedYield( destQ->hTask );
636         QUEUE_WaitBits( QS_SMRESULT );
637         TRACE(sendmsg,"\tsm: have result!\n");
638       }
639       /* got something */
640
641       TRACE(sendmsg,"%*ssm: smResult = %08x\n", prevSMRL, "", (unsigned)queue->smResult );
642
643       if (queue->smResult) { /* FIXME, smResult should always be set */
644         queue->smResult->lResult = queue->SendMessageReturn;
645         queue->smResult->bPending = FALSE;
646       }
647       queue->wakeBits &= ~QS_SMRESULT;
648
649       if( queue->smResult != &qCtrl )
650           ERR(sendmsg, "%*ssm: weird scenes inside the goldmine!\n", prevSMRL, "");
651     }
652     queue->smResultInit = NULL;
653     
654     TRACE(sendmsg,"%*sSM: [%04x] returning %08lx\n", prevSMRL, "", msg, qCtrl.lResult);
655     debugSMRL-=4;
656
657     return qCtrl.lResult;
658 }
659
660
661 /***********************************************************************
662  *           ReplyMessage16   (USER.115)
663  */
664 void WINAPI ReplyMessage16( LRESULT result )
665 {
666     MESSAGEQUEUE *senderQ;
667     MESSAGEQUEUE *queue;
668
669     if (!(queue = (MESSAGEQUEUE*)GlobalLock16( GetTaskQueue(0) ))) return;
670
671     TRACE(msg,"ReplyMessage, queue %04x\n", queue->self);
672
673     while( (senderQ = (MESSAGEQUEUE*)GlobalLock16( queue->InSendMessageHandle)))
674     {
675       TRACE(msg,"\trpm: replying to %04x (%04x -> %04x)\n",
676                           queue->msg, queue->self, senderQ->self);
677
678       if( queue->wakeBits & QS_SENDMESSAGE )
679       {
680         QUEUE_ReceiveMessage( queue );
681         continue; /* ReceiveMessage() already called us */
682       }
683
684       if(!(senderQ->wakeBits & QS_SMRESULT) ) break;
685       OldYield();
686     } 
687     if( !senderQ ) { TRACE(msg,"\trpm: done\n"); return; }
688
689     senderQ->SendMessageReturn = result;
690     TRACE(msg,"\trpm: smResult = %08x, result = %08lx\n", 
691                         (unsigned)queue->smResultCurrent, result );
692
693     senderQ->smResult = queue->smResultCurrent;
694     queue->InSendMessageHandle = 0;
695
696     QUEUE_SetWakeBit( senderQ, QS_SMRESULT );
697     DirectedYield( queue->hSendingTask );
698 }
699
700
701 /***********************************************************************
702  *           MSG_PeekMessage
703  */
704 static BOOL32 MSG_PeekMessage( LPMSG16 msg, HWND16 hwnd, WORD first, WORD last,
705                                WORD flags, BOOL32 peek )
706 {
707     int pos, mask;
708     MESSAGEQUEUE *msgQueue;
709     HQUEUE16 hQueue;
710
711 #ifdef CONFIG_IPC
712     DDE_TestDDE(hwnd);  /* do we have dde handling in the window ?*/
713     DDE_GetRemoteMessage();
714 #endif  /* CONFIG_IPC */
715
716     mask = QS_POSTMESSAGE | QS_SENDMESSAGE;  /* Always selected */
717     if (first || last)
718     {
719         if ((first <= WM_KEYLAST) && (last >= WM_KEYFIRST)) mask |= QS_KEY;
720         if ( ((first <= WM_MOUSELAST) && (last >= WM_MOUSEFIRST)) ||
721              ((first <= WM_NCMOUSELAST) && (last >= WM_NCMOUSEFIRST)) ) mask |= QS_MOUSE;
722         if ((first <= WM_TIMER) && (last >= WM_TIMER)) mask |= QS_TIMER;
723         if ((first <= WM_SYSTIMER) && (last >= WM_SYSTIMER)) mask |= QS_TIMER;
724         if ((first <= WM_PAINT) && (last >= WM_PAINT)) mask |= QS_PAINT;
725     }
726     else mask |= QS_MOUSE | QS_KEY | QS_TIMER | QS_PAINT;
727
728     if (IsTaskLocked()) flags |= PM_NOYIELD;
729
730     while(1)
731     {    
732         hQueue   = GetTaskQueue(0);
733         msgQueue = (MESSAGEQUEUE *)GlobalLock16( hQueue );
734         if (!msgQueue) return FALSE;
735         msgQueue->changeBits = 0;
736
737         /* First handle a message put by SendMessage() */
738
739         while (msgQueue->wakeBits & QS_SENDMESSAGE)
740             QUEUE_ReceiveMessage( msgQueue );
741
742         /* Now handle a WM_QUIT message */
743
744         if (msgQueue->wPostQMsg &&
745            (!first || WM_QUIT >= first) && 
746            (!last || WM_QUIT <= last) )
747         {
748             msg->hwnd    = hwnd;
749             msg->message = WM_QUIT;
750             msg->wParam  = msgQueue->wExitCode;
751             msg->lParam  = 0;
752             if (flags & PM_REMOVE) msgQueue->wPostQMsg = 0;
753             break;
754         }
755     
756         /* Now find a normal message */
757
758         if (((msgQueue->wakeBits & mask) & QS_POSTMESSAGE) &&
759             ((pos = QUEUE_FindMsg( msgQueue, hwnd, first, last )) != -1))
760         {
761             QMSG *qmsg = &msgQueue->messages[pos];
762             *msg = qmsg->msg;
763             msgQueue->GetMessageTimeVal      = msg->time;
764             msgQueue->GetMessagePosVal       = *(DWORD *)&msg->pt;
765             msgQueue->GetMessageExtraInfoVal = qmsg->extraInfo;
766
767             if (flags & PM_REMOVE) QUEUE_RemoveMsg( msgQueue, pos );
768             break;
769         }
770
771         msgQueue->changeBits |= MSG_JournalPlayBackMsg();
772
773         /* Now find a hardware event */
774
775         if (((msgQueue->wakeBits & mask) & (QS_MOUSE | QS_KEY)) &&
776             MSG_PeekHardwareMsg( msg, hwnd, MAKELONG(first,last), flags & PM_REMOVE ))
777         {
778             /* Got one */
779             msgQueue->GetMessageTimeVal      = msg->time;
780             msgQueue->GetMessagePosVal       = *(DWORD *)&msg->pt;
781             msgQueue->GetMessageExtraInfoVal = 0;  /* Always 0 for now */
782             break;
783         }
784
785         /* Check again for SendMessage */
786
787         while (msgQueue->wakeBits & QS_SENDMESSAGE)
788             QUEUE_ReceiveMessage( msgQueue );
789
790         /* Now find a WM_PAINT message */
791
792         if ((msgQueue->wakeBits & mask) & QS_PAINT)
793         {
794             WND* wndPtr;
795             msg->hwnd = WIN_FindWinToRepaint( hwnd , hQueue );
796             msg->message = WM_PAINT;
797             msg->wParam = 0;
798             msg->lParam = 0;
799
800             if ((wndPtr = WIN_FindWndPtr(msg->hwnd)))
801             {
802                 if( wndPtr->dwStyle & WS_MINIMIZE &&
803                     wndPtr->class->hIcon )
804                 {
805                     msg->message = WM_PAINTICON;
806                     msg->wParam = 1;
807                 }
808
809                 if( !hwnd || msg->hwnd == hwnd || IsChild16(hwnd,msg->hwnd) )
810                 {
811                     if( wndPtr->flags & WIN_INTERNAL_PAINT && !wndPtr->hrgnUpdate)
812                     {
813                         wndPtr->flags &= ~WIN_INTERNAL_PAINT;
814                         QUEUE_DecPaintCount( hQueue );
815                     }
816                     break;
817                 }
818             }
819         }
820
821         /* Check for timer messages, but yield first */
822
823         if (!(flags & PM_NOYIELD))
824         {
825             UserYield();
826             while (msgQueue->wakeBits & QS_SENDMESSAGE)
827                 QUEUE_ReceiveMessage( msgQueue );
828         }
829         if ((msgQueue->wakeBits & mask) & QS_TIMER)
830         {
831             if (TIMER_GetTimerMsg(msg, hwnd, hQueue, flags & PM_REMOVE)) break;
832         }
833
834         if (peek)
835         {
836             if (!(flags & PM_NOYIELD)) UserYield();
837             return FALSE;
838         }
839         msgQueue->wakeMask = mask;
840         QUEUE_WaitBits( mask );
841     }
842
843       /* We got a message */
844     if (flags & PM_REMOVE)
845     {
846         WORD message = msg->message;
847
848         if (message == WM_KEYDOWN || message == WM_SYSKEYDOWN)
849         {
850             BYTE *p = &QueueKeyStateTable[msg->wParam & 0xff];
851
852             if (!(*p & 0x80))
853                 *p ^= 0x01;
854             *p |= 0x80;
855         }
856         else if (message == WM_KEYUP || message == WM_SYSKEYUP)
857             QueueKeyStateTable[msg->wParam & 0xff] &= ~0x80;
858     }
859     if (peek) return TRUE;
860     else return (msg->message != WM_QUIT);
861 }
862
863
864 /***********************************************************************
865  *           MSG_InternalGetMessage
866  *
867  * GetMessage() function for internal use. Behave like GetMessage(),
868  * but also call message filters and optionally send WM_ENTERIDLE messages.
869  * 'hwnd' must be the handle of the dialog or menu window.
870  * 'code' is the message filter value (MSGF_??? codes).
871  */
872 BOOL32 MSG_InternalGetMessage( MSG16 *msg, HWND32 hwnd, HWND32 hwndOwner,
873                                WPARAM32 code, WORD flags, BOOL32 sendIdle ) 
874 {
875     for (;;)
876     {
877         if (sendIdle)
878         {
879             if (!MSG_PeekMessage( msg, 0, 0, 0, flags, TRUE ))
880             {
881                   /* No message present -> send ENTERIDLE and wait */
882                 if (IsWindow32(hwndOwner))
883                     SendMessage16( hwndOwner, WM_ENTERIDLE,
884                                    code, (LPARAM)hwnd );
885                 MSG_PeekMessage( msg, 0, 0, 0, flags, FALSE );
886             }
887         }
888         else  /* Always wait for a message */
889             MSG_PeekMessage( msg, 0, 0, 0, flags, FALSE );
890
891         /* Call message filters */
892
893         if (HOOK_IsHooked( WH_SYSMSGFILTER ) || HOOK_IsHooked( WH_MSGFILTER ))
894         {
895             MSG16 *pmsg = SEGPTR_NEW(MSG16);
896             if (pmsg)
897             {
898                 BOOL32 ret;
899                 *pmsg = *msg;
900                 ret = ((BOOL16)HOOK_CallHooks16( WH_SYSMSGFILTER, code, 0,
901                                                  (LPARAM)SEGPTR_GET(pmsg) ) ||
902                        (BOOL16)HOOK_CallHooks16( WH_MSGFILTER, code, 0,
903                                                  (LPARAM)SEGPTR_GET(pmsg) ));
904                 SEGPTR_FREE(pmsg);
905                 if (ret)
906                 {
907                     /* Message filtered -> remove it from the queue */
908                     /* if it's still there. */
909                     if (!(flags & PM_REMOVE))
910                         MSG_PeekMessage( msg, 0, 0, 0, PM_REMOVE, TRUE );
911                     continue;
912                 }
913             }
914         }
915
916         return (msg->message != WM_QUIT);
917     }
918 }
919
920
921 /***********************************************************************
922  *           PeekMessage16   (USER.109)
923  */
924 BOOL16 WINAPI PeekMessage16( LPMSG16 msg, HWND16 hwnd, UINT16 first,
925                              UINT16 last, UINT16 flags )
926 {
927     return MSG_PeekMessage( msg, hwnd, first, last, flags, TRUE );
928 }
929
930
931 /***********************************************************************
932  *           GetMessage16   (USER.108)
933  */
934 BOOL16 WINAPI GetMessage16( SEGPTR msg, HWND16 hwnd, UINT16 first, UINT16 last)
935 {
936     MSG16 *lpmsg = (MSG16 *)PTR_SEG_TO_LIN(msg);
937     MSG_PeekMessage( lpmsg,
938                      hwnd, first, last, PM_REMOVE, FALSE );
939
940     TRACE(msg,"message %04x, hwnd %04x, filter(%04x - %04x)\n", lpmsg->message,
941                                                                  hwnd, first, last );
942     HOOK_CallHooks16( WH_GETMESSAGE, HC_ACTION, 0, (LPARAM)msg );
943     return (lpmsg->message != WM_QUIT);
944 }
945
946
947 /***********************************************************************
948  *           PostMessage16   (USER.110)
949  */
950 BOOL16 WINAPI PostMessage16( HWND16 hwnd, UINT16 message, WPARAM16 wParam,
951                              LPARAM lParam )
952 {
953     MSG16       msg;
954     WND         *wndPtr;
955
956     msg.hwnd    = hwnd;
957     msg.message = message;
958     msg.wParam  = wParam;
959     msg.lParam  = lParam;
960     msg.time    = GetTickCount();
961     msg.pt.x    = 0;
962     msg.pt.y    = 0;
963
964 #ifdef CONFIG_IPC
965     if (DDE_PostMessage(&msg))
966        return TRUE;
967 #endif  /* CONFIG_IPC */
968     
969     if (hwnd == HWND_BROADCAST)
970     {
971         TRACE(msg,"HWND_BROADCAST !\n");
972         for (wndPtr = WIN_GetDesktop()->child; wndPtr; wndPtr = wndPtr->next)
973         {
974             if (wndPtr->dwStyle & WS_POPUP || wndPtr->dwStyle & WS_CAPTION)
975             {
976                 TRACE(msg,"BROADCAST Message to hWnd=%04x m=%04X w=%04X l=%08lX !\n",
977                             wndPtr->hwndSelf, message, wParam, lParam);
978                 PostMessage16( wndPtr->hwndSelf, message, wParam, lParam );
979             }
980         }
981         TRACE(msg,"End of HWND_BROADCAST !\n");
982         return TRUE;
983     }
984
985     wndPtr = WIN_FindWndPtr( hwnd );
986     if (!wndPtr || !wndPtr->hmemTaskQ) return FALSE;
987
988     return QUEUE_AddMsg( wndPtr->hmemTaskQ, &msg, 0 );
989 }
990
991
992 /***********************************************************************
993  *           PostMessage32A   (USER32.419)
994  */
995 BOOL32 WINAPI PostMessage32A( HWND32 hwnd, UINT32 message, WPARAM32 wParam,
996                               LPARAM lParam )
997 {
998     /* FIXME */
999     return PostMessage16( hwnd, message, wParam, lParam );
1000 }
1001
1002
1003 /***********************************************************************
1004  *           PostMessage32W   (USER32.420)
1005  */
1006 BOOL32 WINAPI PostMessage32W( HWND32 hwnd, UINT32 message, WPARAM32 wParam,
1007                               LPARAM lParam )
1008 {
1009     /* FIXME */
1010     return PostMessage16( hwnd, message, wParam, lParam );
1011 }
1012
1013
1014 /***********************************************************************
1015  *           PostAppMessage16   (USER.116)
1016  */
1017 BOOL16 WINAPI PostAppMessage16( HTASK16 hTask, UINT16 message, WPARAM16 wParam,
1018                                 LPARAM lParam )
1019 {
1020     MSG16 msg;
1021
1022     if (GetTaskQueue(hTask) == 0) return FALSE;
1023     msg.hwnd    = 0;
1024     msg.message = message;
1025     msg.wParam  = wParam;
1026     msg.lParam  = lParam;
1027     msg.time    = GetTickCount();
1028     msg.pt.x    = 0;
1029     msg.pt.y    = 0;
1030
1031     return QUEUE_AddMsg( GetTaskQueue(hTask), &msg, 0 );
1032 }
1033
1034
1035 /***********************************************************************
1036  *           SendMessage16   (USER.111)
1037  */
1038 LRESULT WINAPI SendMessage16( HWND16 hwnd, UINT16 msg, WPARAM16 wParam,
1039                               LPARAM lParam)
1040 {
1041     WND * wndPtr;
1042     WND **list, **ppWnd;
1043     LRESULT ret;
1044
1045 #ifdef CONFIG_IPC
1046     MSG16 DDE_msg = { hwnd, msg, wParam, lParam };
1047     if (DDE_SendMessage(&DDE_msg)) return TRUE;
1048 #endif  /* CONFIG_IPC */
1049
1050     if (hwnd == HWND_BROADCAST)
1051     {
1052         if (!(list = WIN_BuildWinArray( WIN_GetDesktop(), 0, NULL )))
1053             return TRUE;
1054         TRACE(msg,"HWND_BROADCAST !\n");
1055         for (ppWnd = list; *ppWnd; ppWnd++)
1056         {
1057             wndPtr = *ppWnd;
1058             if (!IsWindow32(wndPtr->hwndSelf)) continue;
1059             if (wndPtr->dwStyle & WS_POPUP || wndPtr->dwStyle & WS_CAPTION)
1060             {
1061                 TRACE(msg,"BROADCAST Message to hWnd=%04x m=%04X w=%04lX l=%08lX !\n",
1062                             wndPtr->hwndSelf, msg, (DWORD)wParam, lParam);
1063                 SendMessage16( wndPtr->hwndSelf, msg, wParam, lParam );
1064             }
1065         }
1066         HeapFree( SystemHeap, 0, list );
1067         TRACE(msg,"End of HWND_BROADCAST !\n");
1068         return TRUE;
1069     }
1070
1071     if (HOOK_IsHooked( WH_CALLWNDPROC ))
1072     {
1073         LPCWPSTRUCT16 pmsg;
1074
1075         if ((pmsg = SEGPTR_NEW(CWPSTRUCT16)))
1076         {
1077             pmsg->hwnd   = hwnd;
1078             pmsg->message= msg;
1079             pmsg->wParam = wParam;
1080             pmsg->lParam = lParam;
1081             HOOK_CallHooks16( WH_CALLWNDPROC, HC_ACTION, 1,
1082                               (LPARAM)SEGPTR_GET(pmsg) );
1083             hwnd   = pmsg->hwnd;
1084             msg    = pmsg->message;
1085             wParam = pmsg->wParam;
1086             lParam = pmsg->lParam;
1087             SEGPTR_FREE( pmsg );
1088         }
1089     }
1090
1091     if (!(wndPtr = WIN_FindWndPtr( hwnd )))
1092     {
1093         WARN(msg, "invalid hwnd %04x\n", hwnd );
1094         return 0;
1095     }
1096     if (QUEUE_IsExitingQueue(wndPtr->hmemTaskQ))
1097         return 0;  /* Don't send anything if the task is dying */
1098
1099     SPY_EnterMessage( SPY_SENDMESSAGE16, hwnd, msg, wParam, lParam );
1100
1101     if (wndPtr->hmemTaskQ != GetTaskQueue(0))
1102         ret = MSG_SendMessage( wndPtr->hmemTaskQ, hwnd, msg,
1103                                wParam, lParam, 0 );
1104     else
1105         ret = CallWindowProc16( (WNDPROC16)wndPtr->winproc,
1106                                 hwnd, msg, wParam, lParam );
1107
1108     SPY_ExitMessage( SPY_RESULT_OK16, hwnd, msg, ret );
1109     return ret;
1110 }
1111
1112 /************************************************************************
1113  *           MSG_CallWndProcHook32
1114  */
1115 static void  MSG_CallWndProcHook32( LPMSG32 pmsg, BOOL32 bUnicode )
1116 {
1117    CWPSTRUCT32 cwp;
1118
1119    cwp.lParam = pmsg->lParam;
1120    cwp.wParam = pmsg->wParam;
1121    cwp.message = pmsg->message;
1122    cwp.hwnd = pmsg->hwnd;
1123
1124    if (bUnicode) HOOK_CallHooks32W(WH_CALLWNDPROC, HC_ACTION, 1, (LPARAM)&cwp);
1125    else HOOK_CallHooks32A( WH_CALLWNDPROC, HC_ACTION, 1, (LPARAM)&cwp );
1126
1127    pmsg->lParam = cwp.lParam;
1128    pmsg->wParam = cwp.wParam;
1129    pmsg->message = cwp.message;
1130    pmsg->hwnd = cwp.hwnd;
1131 }
1132
1133 /**********************************************************************
1134  *           PostThreadMessage32A    (USER32.422)
1135  */
1136 BOOL32 WINAPI PostThreadMessage32A(DWORD idThread , UINT32 message,
1137                                    WPARAM32 wParam, LPARAM lParam )
1138 {
1139    THDB *thdb = THREAD_ID_TO_THDB(idThread);
1140    if (!thdb || !thdb->process) return FALSE;
1141
1142    FIXME(sendmsg, "(...): Should use thread-local message queue!\n");
1143    return PostAppMessage16(thdb->process->task, message, wParam, lParam);
1144 }
1145
1146 /***********************************************************************
1147  *           SendMessage32A   (USER32.454)
1148  */
1149 LRESULT WINAPI SendMessage32A( HWND32 hwnd, UINT32 msg, WPARAM32 wParam,
1150                                LPARAM lParam )
1151 {
1152     WND * wndPtr;
1153     WND **list, **ppWnd;
1154     LRESULT ret;
1155
1156     if (hwnd == HWND_BROADCAST || hwnd == HWND_TOPMOST)
1157     {
1158         if (!(list = WIN_BuildWinArray( WIN_GetDesktop(), 0, NULL )))
1159             return TRUE;
1160         for (ppWnd = list; *ppWnd; ppWnd++)
1161         {
1162             wndPtr = *ppWnd;
1163             if (!IsWindow32(wndPtr->hwndSelf)) continue;
1164             if (wndPtr->dwStyle & WS_POPUP || wndPtr->dwStyle & WS_CAPTION)
1165                 SendMessage32A( wndPtr->hwndSelf, msg, wParam, lParam );
1166         }
1167         HeapFree( SystemHeap, 0, list );
1168         return TRUE;
1169     }
1170
1171     if (HOOK_IsHooked( WH_CALLWNDPROC ))
1172         MSG_CallWndProcHook32( (LPMSG32)&hwnd, FALSE);
1173
1174     if (!(wndPtr = WIN_FindWndPtr( hwnd )))
1175     {
1176         WARN(msg, "invalid hwnd %08x\n", hwnd );
1177         return 0;
1178     }
1179
1180     if (QUEUE_IsExitingQueue(wndPtr->hmemTaskQ))
1181         return 0;  /* Don't send anything if the task is dying */
1182
1183     SPY_EnterMessage( SPY_SENDMESSAGE32, hwnd, msg, wParam, lParam );
1184
1185     if (wndPtr->hmemTaskQ != GetTaskQueue(0))
1186         ret = MSG_SendMessage( wndPtr->hmemTaskQ, hwnd, msg, wParam, lParam,
1187                                QUEUE_SM_WIN32 );
1188     else
1189         ret = CallWindowProc32A( (WNDPROC32)wndPtr->winproc,
1190                                  hwnd, msg, wParam, lParam );
1191
1192     SPY_ExitMessage( SPY_RESULT_OK32, hwnd, msg, ret );
1193     return ret;
1194 }
1195
1196
1197 /***********************************************************************
1198  *           SendMessage32W   (USER32.459)
1199  */
1200 LRESULT WINAPI SendMessage32W( HWND32 hwnd, UINT32 msg, WPARAM32 wParam,
1201                                LPARAM lParam )
1202 {
1203     WND * wndPtr;
1204     WND **list, **ppWnd;
1205     LRESULT ret;
1206
1207     if (hwnd == HWND_BROADCAST || hwnd == HWND_TOPMOST)
1208     {
1209         if (!(list = WIN_BuildWinArray( WIN_GetDesktop(), 0, NULL )))
1210             return TRUE;
1211         for (ppWnd = list; *ppWnd; ppWnd++)
1212         {
1213             wndPtr = *ppWnd;
1214             if (!IsWindow32(wndPtr->hwndSelf)) continue;
1215             if (wndPtr->dwStyle & WS_POPUP || wndPtr->dwStyle & WS_CAPTION)
1216                 SendMessage32W( wndPtr->hwndSelf, msg, wParam, lParam );
1217         }
1218         HeapFree( SystemHeap, 0, list );
1219         return TRUE;
1220     }
1221
1222     if (HOOK_IsHooked( WH_CALLWNDPROC ))
1223         MSG_CallWndProcHook32( (LPMSG32)&hwnd, TRUE);
1224
1225     if (!(wndPtr = WIN_FindWndPtr( hwnd )))
1226     {
1227         WARN(msg, "invalid hwnd %08x\n", hwnd );
1228         return 0;
1229     }
1230     if (QUEUE_IsExitingQueue(wndPtr->hmemTaskQ))
1231         return 0;  /* Don't send anything if the task is dying */
1232
1233     SPY_EnterMessage( SPY_SENDMESSAGE32, hwnd, msg, wParam, lParam );
1234
1235     if (wndPtr->hmemTaskQ != GetTaskQueue(0))
1236         ret = MSG_SendMessage( wndPtr->hmemTaskQ, hwnd, msg, wParam, lParam,
1237                                 QUEUE_SM_WIN32 | QUEUE_SM_UNICODE );
1238     else
1239         ret = CallWindowProc32W( (WNDPROC32)wndPtr->winproc,
1240                                  hwnd, msg, wParam, lParam );
1241
1242     SPY_ExitMessage( SPY_RESULT_OK32, hwnd, msg, ret );
1243     return ret;
1244 }
1245
1246
1247 /***********************************************************************
1248  *           SendMessageTimeout16    (not a WINAPI)
1249  */
1250 LRESULT WINAPI SendMessageTimeout16( HWND16 hwnd, UINT16 msg, WPARAM16 wParam,
1251                                      LPARAM lParam, UINT16 flags,
1252                                      UINT16 timeout, LPWORD resultp)
1253 {
1254   FIXME(sendmsg, "(...): semistub\n");
1255   return SendMessage16 (hwnd, msg, wParam, lParam);
1256 }
1257
1258
1259 /***********************************************************************
1260  *           SendMessageTimeout32A   (USER32.457)
1261  */
1262 LRESULT WINAPI SendMessageTimeout32A( HWND32 hwnd, UINT32 msg, WPARAM32 wParam,
1263                                       LPARAM lParam, UINT32 flags,
1264                                       UINT32 timeout, LPDWORD resultp)
1265 {
1266   FIXME(sendmsg, "(...): semistub\n");
1267   return SendMessage32A (hwnd, msg, wParam, lParam);
1268 }
1269
1270
1271 /***********************************************************************
1272  *           SendMessageTimeout32W   (USER32.458)
1273  */
1274 LRESULT WINAPI SendMessageTimeout32W( HWND32 hwnd, UINT32 msg, WPARAM32 wParam,
1275                                       LPARAM lParam, UINT32 flags,
1276                                       UINT32 timeout, LPDWORD resultp)
1277 {
1278   FIXME(sendmsg, "(...): semistub\n");
1279   return SendMessage32W (hwnd, msg, wParam, lParam);
1280 }
1281
1282
1283 /***********************************************************************
1284  *           WaitMessage    (USER.112) (USER32.578)
1285  */
1286 void WINAPI WaitMessage( void )
1287 {
1288     QUEUE_WaitBits( QS_ALLINPUT );
1289 }
1290
1291
1292 struct accent_char
1293 {
1294     BYTE ac_accent;
1295     BYTE ac_char;
1296     BYTE ac_result;
1297 };
1298
1299 static const struct accent_char accent_chars[] =
1300 {
1301 /* A good idea should be to read /usr/X11/lib/X11/locale/iso8859-x/Compose */
1302     {'`', 'A', '\300'},  {'`', 'a', '\340'},
1303     {'\'', 'A', '\301'}, {'\'', 'a', '\341'},
1304     {'^', 'A', '\302'},  {'^', 'a', '\342'},
1305     {'~', 'A', '\303'},  {'~', 'a', '\343'},
1306     {'"', 'A', '\304'},  {'"', 'a', '\344'},
1307     {'O', 'A', '\305'},  {'o', 'a', '\345'},
1308     {'0', 'A', '\305'},  {'0', 'a', '\345'},
1309     {'A', 'A', '\305'},  {'a', 'a', '\345'},
1310     {'A', 'E', '\306'},  {'a', 'e', '\346'},
1311     {',', 'C', '\307'},  {',', 'c', '\347'},
1312     {'`', 'E', '\310'},  {'`', 'e', '\350'},
1313     {'\'', 'E', '\311'}, {'\'', 'e', '\351'},
1314     {'^', 'E', '\312'},  {'^', 'e', '\352'},
1315     {'"', 'E', '\313'},  {'"', 'e', '\353'},
1316     {'`', 'I', '\314'},  {'`', 'i', '\354'},
1317     {'\'', 'I', '\315'}, {'\'', 'i', '\355'},
1318     {'^', 'I', '\316'},  {'^', 'i', '\356'},
1319     {'"', 'I', '\317'},  {'"', 'i', '\357'},
1320     {'-', 'D', '\320'},  {'-', 'd', '\360'},
1321     {'~', 'N', '\321'},  {'~', 'n', '\361'},
1322     {'`', 'O', '\322'},  {'`', 'o', '\362'},
1323     {'\'', 'O', '\323'}, {'\'', 'o', '\363'},
1324     {'^', 'O', '\324'},  {'^', 'o', '\364'},
1325     {'~', 'O', '\325'},  {'~', 'o', '\365'},
1326     {'"', 'O', '\326'},  {'"', 'o', '\366'},
1327     {'/', 'O', '\330'},  {'/', 'o', '\370'},
1328     {'`', 'U', '\331'},  {'`', 'u', '\371'},
1329     {'\'', 'U', '\332'}, {'\'', 'u', '\372'},
1330     {'^', 'U', '\333'},  {'^', 'u', '\373'},
1331     {'"', 'U', '\334'},  {'"', 'u', '\374'},
1332     {'\'', 'Y', '\335'}, {'\'', 'y', '\375'},
1333     {'T', 'H', '\336'},  {'t', 'h', '\376'},
1334     {'s', 's', '\337'},  {'"', 'y', '\377'},
1335     {'s', 'z', '\337'},  {'i', 'j', '\377'},
1336         /* iso-8859-2 uses this */
1337     {'<', 'L', '\245'},  {'<', 'l', '\265'},    /* caron */
1338     {'<', 'S', '\251'},  {'<', 's', '\271'},
1339     {'<', 'T', '\253'},  {'<', 't', '\273'},
1340     {'<', 'Z', '\256'},  {'<', 'z', '\276'},
1341     {'<', 'C', '\310'},  {'<', 'c', '\350'},
1342     {'<', 'E', '\314'},  {'<', 'e', '\354'},
1343     {'<', 'D', '\317'},  {'<', 'd', '\357'},
1344     {'<', 'N', '\322'},  {'<', 'n', '\362'},
1345     {'<', 'R', '\330'},  {'<', 'r', '\370'},
1346     {';', 'A', '\241'},  {';', 'a', '\261'},    /* ogonek */
1347     {';', 'E', '\312'},  {';', 'e', '\332'},
1348     {'\'', 'Z', '\254'}, {'\'', 'z', '\274'},   /* acute */
1349     {'\'', 'R', '\300'}, {'\'', 'r', '\340'},
1350     {'\'', 'L', '\305'}, {'\'', 'l', '\345'},
1351     {'\'', 'C', '\306'}, {'\'', 'c', '\346'},
1352     {'\'', 'N', '\321'}, {'\'', 'n', '\361'},
1353 /*  collision whith S, from iso-8859-9 !!! */
1354     {',', 'S', '\252'},  {',', 's', '\272'},    /* cedilla */
1355     {',', 'T', '\336'},  {',', 't', '\376'},
1356     {'.', 'Z', '\257'},  {'.', 'z', '\277'},    /* dot above */
1357     {'/', 'L', '\243'},  {'/', 'l', '\263'},    /* slash */
1358     {'/', 'D', '\320'},  {'/', 'd', '\360'},
1359     {'(', 'A', '\303'},  {'(', 'a', '\343'},    /* breve */
1360     {'\275', 'O', '\325'}, {'\275', 'o', '\365'},       /* double acute */
1361     {'\275', 'U', '\334'}, {'\275', 'u', '\374'},
1362     {'0', 'U', '\332'},  {'0', 'u', '\372'},    /* ring above */
1363         /* iso-8859-3 uses this */
1364     {'/', 'H', '\241'},  {'/', 'h', '\261'},    /* slash */
1365     {'>', 'H', '\246'},  {'>', 'h', '\266'},    /* circumflex */
1366     {'>', 'J', '\254'},  {'>', 'j', '\274'},
1367     {'>', 'C', '\306'},  {'>', 'c', '\346'},
1368     {'>', 'G', '\330'},  {'>', 'g', '\370'},
1369     {'>', 'S', '\336'},  {'>', 's', '\376'},
1370 /*  collision whith G( from iso-8859-9 !!!   */
1371     {'(', 'G', '\253'},  {'(', 'g', '\273'},    /* breve */
1372     {'(', 'U', '\335'},  {'(', 'u', '\375'},
1373 /*  collision whith I. from iso-8859-3 !!!   */
1374     {'.', 'I', '\251'},  {'.', 'i', '\271'},    /* dot above */
1375     {'.', 'C', '\305'},  {'.', 'c', '\345'},
1376     {'.', 'G', '\325'},  {'.', 'g', '\365'},
1377         /* iso-8859-4 uses this */
1378     {',', 'R', '\243'},  {',', 'r', '\263'},    /* cedilla */
1379     {',', 'L', '\246'},  {',', 'l', '\266'},
1380     {',', 'G', '\253'},  {',', 'g', '\273'},
1381     {',', 'N', '\321'},  {',', 'n', '\361'},
1382     {',', 'K', '\323'},  {',', 'k', '\363'},
1383     {'~', 'I', '\245'},  {'~', 'i', '\265'},    /* tilde */
1384     {'-', 'E', '\252'},  {'-', 'e', '\272'},    /* macron */
1385     {'-', 'A', '\300'},  {'-', 'a', '\340'},
1386     {'-', 'I', '\317'},  {'-', 'i', '\357'},
1387     {'-', 'O', '\322'},  {'-', 'o', '\362'},
1388     {'-', 'U', '\336'},  {'-', 'u', '\376'},
1389     {'/', 'T', '\254'},  {'/', 't', '\274'},    /* slash */
1390     {'.', 'E', '\314'},  {'.', 'e', '\344'},    /* dot above */
1391     {';', 'I', '\307'},  {';', 'i', '\347'},    /* ogonek */
1392     {';', 'U', '\331'},  {';', 'u', '\371'},
1393         /* iso-8859-9 uses this */
1394         /* iso-8859-9 has really bad choosen G( S, and I. as they collide
1395          * whith the same letters on other iso-8859-x (that is they are on
1396          * different places :-( ), if you use turkish uncomment these and
1397          * comment out the lines in iso-8859-2 and iso-8859-3 sections
1398          * FIXME: should be dynamic according to chosen language
1399          *        if/when Wine has turkish support.  
1400          */ 
1401 /*  collision whith G( from iso-8859-3 !!!   */
1402 /*  {'(', 'G', '\320'},  {'(', 'g', '\360'}, */ /* breve */
1403 /*  collision whith S, from iso-8859-2 !!! */
1404 /*  {',', 'S', '\336'},  {',', 's', '\376'}, */ /* cedilla */
1405 /*  collision whith I. from iso-8859-3 !!!   */
1406 /*  {'.', 'I', '\335'},  {'.', 'i', '\375'}, */ /* dot above */
1407 };
1408
1409
1410 /***********************************************************************
1411  *           MSG_DoTranslateMessage
1412  *
1413  * Implementation of TranslateMessage.
1414  *
1415  * TranslateMessage translates virtual-key messages into character-messages,
1416  * as follows :
1417  * WM_KEYDOWN/WM_KEYUP combinations produce a WM_CHAR or WM_DEADCHAR message.
1418  * ditto replacing WM_* with WM_SYS*
1419  * This produces WM_CHAR messages only for keys mapped to ASCII characters
1420  * by the keyboard driver.
1421  */
1422 static BOOL32 MSG_DoTranslateMessage( UINT32 message, HWND32 hwnd,
1423                                       WPARAM32 wParam, LPARAM lParam )
1424 {
1425     static int dead_char;
1426     BYTE wp[2];
1427     
1428     if (message != WM_MOUSEMOVE && message != WM_TIMER)
1429         TRACE(msg, "(%s, %04X, %08lX)\n",
1430                      SPY_GetMsgName(message), wParam, lParam );
1431     if(message >= WM_KEYFIRST && message <= WM_KEYLAST)
1432         TRACE(key, "(%s, %04X, %08lX)\n",
1433                      SPY_GetMsgName(message), wParam, lParam );
1434
1435     if ((message != WM_KEYDOWN) && (message != WM_SYSKEYDOWN)) return FALSE;
1436
1437     TRACE(key, "Translating key %04X, scancode %04X\n",
1438                  wParam, HIWORD(lParam) );
1439
1440     /* FIXME : should handle ToAscii yielding 2 */
1441     switch (ToAscii32(wParam, HIWORD(lParam),
1442                       QueueKeyStateTable,(LPWORD)wp, 0)) 
1443     {
1444     case 1 :
1445         message = (message == WM_KEYDOWN) ? WM_CHAR : WM_SYSCHAR;
1446         /* Should dead chars handling go in ToAscii ? */
1447         if (dead_char)
1448         {
1449             int i;
1450
1451             if (wp[0] == ' ') wp[0] =  dead_char;
1452             if (dead_char == 0xa2) dead_char = '(';
1453             else if (dead_char == 0xa8) dead_char = '"';
1454             else if (dead_char == 0xb2) dead_char = ';';
1455             else if (dead_char == 0xb4) dead_char = '\'';
1456             else if (dead_char == 0xb7) dead_char = '<';
1457             else if (dead_char == 0xb8) dead_char = ',';
1458             else if (dead_char == 0xff) dead_char = '.';
1459             for (i = 0; i < sizeof(accent_chars)/sizeof(accent_chars[0]); i++)
1460                 if ((accent_chars[i].ac_accent == dead_char) &&
1461                     (accent_chars[i].ac_char == wp[0]))
1462                 {
1463                     wp[0] = accent_chars[i].ac_result;
1464                     break;
1465                 }
1466             dead_char = 0;
1467         }
1468         TRACE(key, "1 -> PostMessage(%s)\n", SPY_GetMsgName(message));
1469         PostMessage16( hwnd, message, wp[0], lParam );
1470         return TRUE;
1471
1472     case -1 :
1473         message = (message == WM_KEYDOWN) ? WM_DEADCHAR : WM_SYSDEADCHAR;
1474         dead_char = wp[0];
1475         TRACE(key, "-1 -> PostMessage(%s)\n",
1476                      SPY_GetMsgName(message));
1477         PostMessage16( hwnd, message, wp[0], lParam );
1478         return TRUE;
1479     }
1480     return FALSE;
1481 }
1482
1483
1484 /***********************************************************************
1485  *           TranslateMessage16   (USER.113)
1486  */
1487 BOOL16 WINAPI TranslateMessage16( const MSG16 *msg )
1488 {
1489     return MSG_DoTranslateMessage( msg->message, msg->hwnd,
1490                                    msg->wParam, msg->lParam );
1491 }
1492
1493
1494 /***********************************************************************
1495  *           TranslateMessage32   (USER32.556)
1496  */
1497 BOOL32 WINAPI TranslateMessage32( const MSG32 *msg )
1498 {
1499     return MSG_DoTranslateMessage( msg->message, msg->hwnd,
1500                                    msg->wParam, msg->lParam );
1501 }
1502
1503
1504 /***********************************************************************
1505  *           DispatchMessage16   (USER.114)
1506  */
1507 LONG WINAPI DispatchMessage16( const MSG16* msg )
1508 {
1509     WND * wndPtr;
1510     LONG retval;
1511     int painting;
1512     
1513       /* Process timer messages */
1514     if ((msg->message == WM_TIMER) || (msg->message == WM_SYSTIMER))
1515     {
1516         if (msg->lParam)
1517         {
1518             return CallWindowProc16( (WNDPROC16)msg->lParam, msg->hwnd,
1519                                    msg->message, msg->wParam, GetTickCount() );
1520         }
1521     }
1522
1523     if (!msg->hwnd) return 0;
1524     if (!(wndPtr = WIN_FindWndPtr( msg->hwnd ))) return 0;
1525     if (!wndPtr->winproc) return 0;
1526     painting = (msg->message == WM_PAINT);
1527     if (painting) wndPtr->flags |= WIN_NEEDS_BEGINPAINT;
1528
1529     SPY_EnterMessage( SPY_DISPATCHMESSAGE16, msg->hwnd, msg->message,
1530                       msg->wParam, msg->lParam );
1531     retval = CallWindowProc16( (WNDPROC16)wndPtr->winproc,
1532                                msg->hwnd, msg->message,
1533                                msg->wParam, msg->lParam );
1534     SPY_ExitMessage( SPY_RESULT_OK16, msg->hwnd, msg->message, retval );
1535
1536     if (painting && (wndPtr = WIN_FindWndPtr( msg->hwnd )) &&
1537         (wndPtr->flags & WIN_NEEDS_BEGINPAINT) && wndPtr->hrgnUpdate)
1538     {
1539         ERR(msg, "BeginPaint not called on WM_PAINT for hwnd %04x!\n", 
1540             msg->hwnd);
1541         wndPtr->flags &= ~WIN_NEEDS_BEGINPAINT;
1542         /* Validate the update region to avoid infinite WM_PAINT loop */
1543         ValidateRect32( msg->hwnd, NULL );
1544     }
1545     return retval;
1546 }
1547
1548
1549 /***********************************************************************
1550  *           DispatchMessage32A   (USER32.141)
1551  */
1552 LONG WINAPI DispatchMessage32A( const MSG32* msg )
1553 {
1554     WND * wndPtr;
1555     LONG retval;
1556     int painting;
1557     
1558       /* Process timer messages */
1559     if ((msg->message == WM_TIMER) || (msg->message == WM_SYSTIMER))
1560     {
1561         if (msg->lParam)
1562         {
1563 /*            HOOK_CallHooks32A( WH_CALLWNDPROC, HC_ACTION, 0, FIXME ); */
1564             return CallWindowProc32A( (WNDPROC32)msg->lParam, msg->hwnd,
1565                                    msg->message, msg->wParam, GetTickCount() );
1566         }
1567     }
1568
1569     if (!msg->hwnd) return 0;
1570     if (!(wndPtr = WIN_FindWndPtr( msg->hwnd ))) return 0;
1571     if (!wndPtr->winproc) return 0;
1572     painting = (msg->message == WM_PAINT);
1573     if (painting) wndPtr->flags |= WIN_NEEDS_BEGINPAINT;
1574 /*    HOOK_CallHooks32A( WH_CALLWNDPROC, HC_ACTION, 0, FIXME ); */
1575
1576     SPY_EnterMessage( SPY_DISPATCHMESSAGE32, msg->hwnd, msg->message,
1577                       msg->wParam, msg->lParam );
1578     retval = CallWindowProc32A( (WNDPROC32)wndPtr->winproc,
1579                                 msg->hwnd, msg->message,
1580                                 msg->wParam, msg->lParam );
1581     SPY_ExitMessage( SPY_RESULT_OK32, msg->hwnd, msg->message, retval );
1582
1583     if (painting && (wndPtr = WIN_FindWndPtr( msg->hwnd )) &&
1584         (wndPtr->flags & WIN_NEEDS_BEGINPAINT) && wndPtr->hrgnUpdate)
1585     {
1586         ERR(msg, "BeginPaint not called on WM_PAINT for hwnd %04x!\n", 
1587             msg->hwnd);
1588         wndPtr->flags &= ~WIN_NEEDS_BEGINPAINT;
1589         /* Validate the update region to avoid infinite WM_PAINT loop */
1590         ValidateRect32( msg->hwnd, NULL );
1591     }
1592     return retval;
1593 }
1594
1595
1596 /***********************************************************************
1597  *           DispatchMessage32W   (USER32.142)
1598  */
1599 LONG WINAPI DispatchMessage32W( const MSG32* msg )
1600 {
1601     WND * wndPtr;
1602     LONG retval;
1603     int painting;
1604     
1605       /* Process timer messages */
1606     if ((msg->message == WM_TIMER) || (msg->message == WM_SYSTIMER))
1607     {
1608         if (msg->lParam)
1609         {
1610 /*            HOOK_CallHooks32W( WH_CALLWNDPROC, HC_ACTION, 0, FIXME ); */
1611             return CallWindowProc32W( (WNDPROC32)msg->lParam, msg->hwnd,
1612                                    msg->message, msg->wParam, GetTickCount() );
1613         }
1614     }
1615
1616     if (!msg->hwnd) return 0;
1617     if (!(wndPtr = WIN_FindWndPtr( msg->hwnd ))) return 0;
1618     if (!wndPtr->winproc) return 0;
1619     painting = (msg->message == WM_PAINT);
1620     if (painting) wndPtr->flags |= WIN_NEEDS_BEGINPAINT;
1621 /*    HOOK_CallHooks32W( WH_CALLWNDPROC, HC_ACTION, 0, FIXME ); */
1622
1623     SPY_EnterMessage( SPY_DISPATCHMESSAGE32, msg->hwnd, msg->message,
1624                       msg->wParam, msg->lParam );
1625     retval = CallWindowProc32W( (WNDPROC32)wndPtr->winproc,
1626                                 msg->hwnd, msg->message,
1627                                 msg->wParam, msg->lParam );
1628     SPY_ExitMessage( SPY_RESULT_OK32, msg->hwnd, msg->message, retval );
1629
1630     if (painting && (wndPtr = WIN_FindWndPtr( msg->hwnd )) &&
1631         (wndPtr->flags & WIN_NEEDS_BEGINPAINT) && wndPtr->hrgnUpdate)
1632     {
1633         ERR(msg, "BeginPaint not called on WM_PAINT for hwnd %04x!\n", 
1634             msg->hwnd);
1635         wndPtr->flags &= ~WIN_NEEDS_BEGINPAINT;
1636         /* Validate the update region to avoid infinite WM_PAINT loop */
1637         ValidateRect32( msg->hwnd, NULL );
1638     }
1639     return retval;
1640 }
1641
1642
1643 /***********************************************************************
1644  *           RegisterWindowMessage16   (USER.118)
1645  */
1646 WORD WINAPI RegisterWindowMessage16( SEGPTR str )
1647 {
1648     TRACE(msg, "%08lx\n", (DWORD)str );
1649     return GlobalAddAtom16( str );
1650 }
1651
1652
1653 /***********************************************************************
1654  *           RegisterWindowMessage32A   (USER32.437)
1655  */
1656 WORD WINAPI RegisterWindowMessage32A( LPCSTR str )
1657 {
1658     TRACE(msg, "%s\n", str );
1659     return GlobalAddAtom32A( str );
1660 }
1661
1662
1663 /***********************************************************************
1664  *           RegisterWindowMessage32W   (USER32.438)
1665  */
1666 WORD WINAPI RegisterWindowMessage32W( LPCWSTR str )
1667 {
1668     TRACE(msg, "%p\n", str );
1669     return GlobalAddAtom32W( str );
1670 }
1671
1672
1673 /***********************************************************************
1674  *           GetTickCount   (USER.13) (KERNEL32.299)
1675  */
1676 DWORD WINAPI GetTickCount(void)
1677 {
1678     struct timeval t;
1679     gettimeofday( &t, NULL );
1680     return ((t.tv_sec * 1000) + (t.tv_usec / 1000)) - MSG_WineStartTicks;
1681 }
1682
1683
1684 /***********************************************************************
1685  *           GetCurrentTime16    (USER.15)
1686  *
1687  * (effectively identical to GetTickCount)
1688  */
1689 DWORD WINAPI GetCurrentTime16(void)
1690 {
1691     return GetTickCount();
1692 }
1693
1694
1695 /***********************************************************************
1696  *           InSendMessage16    (USER.192)
1697  */
1698 BOOL16 WINAPI InSendMessage16(void)
1699 {
1700     return InSendMessage32();
1701 }
1702
1703
1704 /***********************************************************************
1705  *           InSendMessage32    (USER32.320)
1706  */
1707 BOOL32 WINAPI InSendMessage32(void)
1708 {
1709     MESSAGEQUEUE *queue;
1710
1711     if (!(queue = (MESSAGEQUEUE *)GlobalLock16( GetTaskQueue(0) )))
1712         return 0;
1713     return (BOOL32)queue->InSendMessageHandle;
1714 }
1715
1716 /***********************************************************************
1717  *           BroadcastSystemMessage    (USER32.12)
1718  */
1719 LONG WINAPI BroadcastSystemMessage(
1720         DWORD dwFlags,LPDWORD recipients,UINT32 uMessage,WPARAM32 wParam,
1721         LPARAM lParam
1722 ) {
1723         FIXME(sendmsg,"(%08lx,%08lx,%08x,%08x,%08lx): stub!\n",
1724               dwFlags,*recipients,uMessage,wParam,lParam
1725         );
1726         return 0;
1727 }
1728
1729 /***********************************************************************
1730  *           SendNotifyMessageA    (USER32.460)
1731  */
1732 LONG WINAPI SendNotifyMessage32A(HWND32 hwnd,UINT32 msg,WPARAM32 wParam,LPARAM lParam)
1733 {
1734         FIXME(msg,"(%04x,%08lx,%08lx,%08lx): stub!\n",
1735               hwnd,(long)msg,(long)wParam,lParam
1736         );
1737         return 0;
1738 }
1739
1740 BOOL32 WINAPI SendMessageCallBack32A(
1741         HWND32 hWnd,UINT32 Msg,WPARAM32 wParam,LPARAM lParam,
1742         /*SENDASYNCPROC*/FARPROC32 lpResultCallBack,DWORD dwData
1743 ) {
1744         FIXME(msg,"(0x%04x,0x%04x,0x%08lx,0x%08lx,%p,0x%08lx),stub!\n",
1745                 hWnd,Msg,wParam,lParam,lpResultCallBack,dwData
1746         );
1747         return FALSE;
1748 }