Added a typedef for __int64 which is a builtin Visual C++ type
[wine/multimedia.git] / windows / message.c
blob5da24fdde6e356bd3e804821dffbe692285f5bd3
1 /*
2 * Message queues related functions
4 * Copyright 1993, 1994 Alexandre Julliard
5 */
7 #include "ts_xlib.h"
9 #include <stdlib.h>
10 #include <string.h>
11 #include <ctype.h>
12 #include <sys/time.h>
13 #include <sys/types.h>
15 #include "message.h"
16 #include "win.h"
17 #include "gdi.h"
18 #include "sysmetrics.h"
19 #include "heap.h"
20 #include "hook.h"
21 #include "input.h"
22 #include "spy.h"
23 #include "winpos.h"
24 #include "dde.h"
25 #include "queue.h"
26 #include "winproc.h"
27 #include "task.h"
28 #include "process.h"
29 #include "thread.h"
30 #include "options.h"
31 #include "struct32.h"
32 #include "debug.h"
34 #define WM_NCMOUSEFIRST WM_NCMOUSEMOVE
35 #define WM_NCMOUSELAST WM_NCMBUTTONDBLCLK
37 typedef enum { SYSQ_MSG_ABANDON, SYSQ_MSG_SKIP,
38 SYSQ_MSG_ACCEPT, SYSQ_MSG_CONTINUE } SYSQ_STATUS;
40 extern MESSAGEQUEUE *pCursorQueue; /* queue.c */
41 extern MESSAGEQUEUE *pActiveQueue;
43 DWORD MSG_WineStartTicks; /* Ticks at Wine startup */
45 static UINT32 doubleClickSpeed = 452;
46 static INT32 debugSMRL = 0; /* intertask SendMessage() recursion level */
48 /***********************************************************************
49 * MSG_CheckFilter
51 BOOL32 MSG_CheckFilter(WORD uMsg, DWORD filter)
53 if( filter )
54 return (uMsg >= LOWORD(filter) && uMsg <= HIWORD(filter));
55 return TRUE;
58 /***********************************************************************
59 * MSG_SendParentNotify
61 * Send a WM_PARENTNOTIFY to all ancestors of the given window, unless
62 * the window has the WS_EX_NOPARENTNOTIFY style.
64 static void MSG_SendParentNotify(WND* wndPtr, WORD event, WORD idChild, LPARAM lValue)
66 #define lppt ((LPPOINT16)&lValue)
68 /* pt has to be in the client coordinates of the parent window */
70 MapWindowPoints16( 0, wndPtr->hwndSelf, lppt, 1 );
71 while (wndPtr)
73 if (!(wndPtr->dwStyle & WS_CHILD) || (wndPtr->dwExStyle & WS_EX_NOPARENTNOTIFY)) break;
74 lppt->x += wndPtr->rectClient.left;
75 lppt->y += wndPtr->rectClient.top;
76 wndPtr = wndPtr->parent;
77 SendMessage32A( wndPtr->hwndSelf, WM_PARENTNOTIFY,
78 MAKEWPARAM( event, idChild ), lValue );
80 #undef lppt
84 /***********************************************************************
85 * MSG_TranslateMouseMsg
87 * Translate an mouse hardware event into a real mouse message.
88 * Return value indicates whether the translated message must be passed
89 * to the user, left in the queue, or skipped entirely (in this case
90 * HIWORD contains hit test code).
92 static DWORD MSG_TranslateMouseMsg( HWND16 hTopWnd, DWORD filter,
93 MSG16 *msg, BOOL32 remove, WND* pWndScope )
95 static DWORD dblclk_time_limit = 0;
96 static UINT16 clk_message = 0;
97 static HWND16 clk_hwnd = 0;
98 static POINT16 clk_pos = { 0, 0 };
100 WND *pWnd;
101 HWND16 hWnd;
102 INT16 ht, hittest, sendSC = 0;
103 UINT16 message = msg->message;
104 POINT16 screen_pt, pt;
105 HANDLE16 hQ = GetFastQueue();
106 MESSAGEQUEUE *queue = (MESSAGEQUEUE *)GlobalLock16(hQ);
107 BOOL32 eatMsg = FALSE;
108 BOOL32 mouseClick = ((message == WM_LBUTTONDOWN) ||
109 (message == WM_RBUTTONDOWN) ||
110 (message == WM_MBUTTONDOWN))?1:0;
111 SYSQ_STATUS ret = 0;
113 /* Find the window */
115 ht = hittest = HTCLIENT;
116 hWnd = GetCapture16();
117 if( !hWnd )
119 ht = hittest = WINPOS_WindowFromPoint( pWndScope, msg->pt, &pWnd );
120 if( !pWnd ) pWnd = WIN_GetDesktop();
121 hWnd = pWnd->hwndSelf;
122 sendSC = 1;
124 else
126 pWnd = WIN_FindWndPtr(hWnd);
127 ht = EVENT_GetCaptureInfo();
130 /* stop if not the right queue */
132 if (pWnd->hmemTaskQ != hQ)
134 /* Not for the current task */
135 if (queue) QUEUE_ClearWakeBit( queue, QS_MOUSE );
136 /* Wake up the other task */
137 queue = (MESSAGEQUEUE *)GlobalLock16( pWnd->hmemTaskQ );
138 if (queue) QUEUE_SetWakeBit( queue, QS_MOUSE );
139 return SYSQ_MSG_ABANDON;
142 /* check if hWnd is within hWndScope */
144 if( hTopWnd && hWnd != hTopWnd )
145 if( !IsChild16(hTopWnd, hWnd) ) return SYSQ_MSG_CONTINUE;
147 if( mouseClick )
149 /* translate double clicks -
150 * note that ...MOUSEMOVEs can slip in between
151 * ...BUTTONDOWN and ...BUTTONDBLCLK messages */
153 if( pWnd->class->style & CS_DBLCLKS || ht != HTCLIENT )
155 if ((message == clk_message) && (hWnd == clk_hwnd) &&
156 (msg->time - dblclk_time_limit < doubleClickSpeed) &&
157 (abs(msg->pt.x - clk_pos.x) < SYSMETRICS_CXDOUBLECLK/2) &&
158 (abs(msg->pt.y - clk_pos.y) < SYSMETRICS_CYDOUBLECLK/2))
160 message += (WM_LBUTTONDBLCLK - WM_LBUTTONDOWN);
161 mouseClick++; /* == 2 */
165 screen_pt = pt = msg->pt;
167 if (hittest != HTCLIENT)
169 message += ((INT16)WM_NCMOUSEMOVE - WM_MOUSEMOVE);
170 msg->wParam = hittest;
172 else ScreenToClient16( hWnd, &pt );
174 /* check message filter */
176 if (!MSG_CheckFilter(message, filter)) return SYSQ_MSG_CONTINUE;
178 pCursorQueue = queue;
180 /* call WH_MOUSE */
182 if (HOOK_IsHooked( WH_MOUSE ))
184 MOUSEHOOKSTRUCT16 *hook = SEGPTR_NEW(MOUSEHOOKSTRUCT16);
185 if( hook )
187 hook->pt = screen_pt;
188 hook->hwnd = hWnd;
189 hook->wHitTestCode = hittest;
190 hook->dwExtraInfo = 0;
191 ret = HOOK_CallHooks16( WH_MOUSE, remove ? HC_ACTION : HC_NOREMOVE,
192 message, (LPARAM)SEGPTR_GET(hook) );
193 SEGPTR_FREE(hook);
195 if( ret ) return MAKELONG((INT16)SYSQ_MSG_SKIP, hittest);
198 if ((hittest == HTERROR) || (hittest == HTNOWHERE))
199 eatMsg = sendSC = 1;
200 else if( remove && mouseClick )
202 HWND32 hwndTop = WIN_GetTopParent( hWnd );
204 if( mouseClick == 1 )
206 /* set conditions */
207 dblclk_time_limit = msg->time;
208 clk_message = msg->message;
209 clk_hwnd = hWnd;
210 clk_pos = screen_pt;
211 } else
212 /* got double click - zero them out */
213 dblclk_time_limit = clk_hwnd = 0;
215 if( sendSC )
217 /* Send the WM_PARENTNOTIFY,
218 * note that even for double/nonclient clicks
219 * notification message is still WM_L/M/RBUTTONDOWN.
222 MSG_SendParentNotify( pWnd, msg->message, 0, MAKELPARAM(screen_pt.x, screen_pt.y) );
224 /* Activate the window if needed */
226 if (hWnd != GetActiveWindow16() && hWnd != GetDesktopWindow16())
228 LONG ret = SendMessage16( hWnd, WM_MOUSEACTIVATE, hwndTop,
229 MAKELONG( hittest, message ) );
231 if ((ret == MA_ACTIVATEANDEAT) || (ret == MA_NOACTIVATEANDEAT))
232 eatMsg = TRUE;
234 if (((ret == MA_ACTIVATE) || (ret == MA_ACTIVATEANDEAT))
235 && hwndTop != GetActiveWindow16() )
236 if (!WINPOS_SetActiveWindow( hwndTop, TRUE , TRUE ))
237 eatMsg = TRUE;
240 } else sendSC = (remove && sendSC);
242 /* Send the WM_SETCURSOR message */
244 if (sendSC)
245 SendMessage16( hWnd, WM_SETCURSOR, (WPARAM16)hWnd,
246 MAKELONG( hittest, message ));
247 if (eatMsg) return MAKELONG( (UINT16)SYSQ_MSG_SKIP, hittest);
249 msg->hwnd = hWnd;
250 msg->message = message;
251 msg->lParam = MAKELONG( pt.x, pt.y );
252 return SYSQ_MSG_ACCEPT;
256 /***********************************************************************
257 * MSG_TranslateKbdMsg
259 * Translate an keyboard hardware event into a real message.
261 static DWORD MSG_TranslateKbdMsg( HWND16 hTopWnd, DWORD filter,
262 MSG16 *msg, BOOL32 remove )
264 WORD message = msg->message;
265 HWND16 hWnd = GetFocus16();
266 WND *pWnd;
268 /* Should check Ctrl-Esc and PrintScreen here */
270 if (!hWnd)
272 /* Send the message to the active window instead, */
273 /* translating messages to their WM_SYS equivalent */
275 hWnd = GetActiveWindow16();
277 if( message < WM_SYSKEYDOWN )
278 message += WM_SYSKEYDOWN - WM_KEYDOWN;
280 pWnd = WIN_FindWndPtr( hWnd );
281 if (pWnd && (pWnd->hmemTaskQ != GetFastQueue()))
283 /* Not for the current task */
284 MESSAGEQUEUE *queue = (MESSAGEQUEUE *)GlobalLock16( GetFastQueue() );
285 if (queue) QUEUE_ClearWakeBit( queue, QS_KEY );
286 /* Wake up the other task */
287 queue = (MESSAGEQUEUE *)GlobalLock16( pWnd->hmemTaskQ );
288 if (queue) QUEUE_SetWakeBit( queue, QS_KEY );
289 return SYSQ_MSG_ABANDON;
292 if (hTopWnd && hWnd != hTopWnd)
293 if (!IsChild16(hTopWnd, hWnd)) return SYSQ_MSG_CONTINUE;
294 if (!MSG_CheckFilter(message, filter)) return SYSQ_MSG_CONTINUE;
296 msg->hwnd = hWnd;
297 msg->message = message;
299 return (HOOK_CallHooks16( WH_KEYBOARD, remove ? HC_ACTION : HC_NOREMOVE,
300 msg->wParam, msg->lParam )
301 ? SYSQ_MSG_SKIP : SYSQ_MSG_ACCEPT);
305 /***********************************************************************
306 * MSG_JournalRecordMsg
308 * Build an EVENTMSG structure and call JOURNALRECORD hook
310 static void MSG_JournalRecordMsg( MSG16 *msg )
312 EVENTMSG16 *event = SEGPTR_NEW(EVENTMSG16);
313 if (!event) return;
314 event->message = msg->message;
315 event->time = msg->time;
316 if ((msg->message >= WM_KEYFIRST) && (msg->message <= WM_KEYLAST))
318 event->paramL = (msg->wParam & 0xFF) | (HIWORD(msg->lParam) << 8);
319 event->paramH = msg->lParam & 0x7FFF;
320 if (HIWORD(msg->lParam) & 0x0100)
321 event->paramH |= 0x8000; /* special_key - bit */
322 HOOK_CallHooks16( WH_JOURNALRECORD, HC_ACTION, 0,
323 (LPARAM)SEGPTR_GET(event) );
325 else if ((msg->message >= WM_MOUSEFIRST) && (msg->message <= WM_MOUSELAST))
327 event->paramL = LOWORD(msg->lParam); /* X pos */
328 event->paramH = HIWORD(msg->lParam); /* Y pos */
329 ClientToScreen16( msg->hwnd, (LPPOINT16)&event->paramL );
330 HOOK_CallHooks16( WH_JOURNALRECORD, HC_ACTION, 0,
331 (LPARAM)SEGPTR_GET(event) );
333 else if ((msg->message >= WM_NCMOUSEFIRST) &&
334 (msg->message <= WM_NCMOUSELAST))
336 event->paramL = LOWORD(msg->lParam); /* X pos */
337 event->paramH = HIWORD(msg->lParam); /* Y pos */
338 event->message += WM_MOUSEMOVE-WM_NCMOUSEMOVE;/* give no info about NC area */
339 HOOK_CallHooks16( WH_JOURNALRECORD, HC_ACTION, 0,
340 (LPARAM)SEGPTR_GET(event) );
342 SEGPTR_FREE(event);
345 /***********************************************************************
346 * MSG_JournalPlayBackMsg
348 * Get an EVENTMSG struct via call JOURNALPLAYBACK hook function
350 static int MSG_JournalPlayBackMsg(void)
352 EVENTMSG16 *tmpMsg;
353 long wtime,lParam;
354 WORD keyDown,i,wParam,result=0;
356 if ( HOOK_IsHooked( WH_JOURNALPLAYBACK ) )
358 tmpMsg = SEGPTR_NEW(EVENTMSG16);
359 wtime=HOOK_CallHooks16( WH_JOURNALPLAYBACK, HC_GETNEXT, 0,
360 (LPARAM)SEGPTR_GET(tmpMsg));
361 /* TRACE(msg,"Playback wait time =%ld\n",wtime); */
362 if (wtime<=0)
364 wtime=0;
365 if ((tmpMsg->message>= WM_KEYFIRST) && (tmpMsg->message <= WM_KEYLAST))
367 wParam=tmpMsg->paramL & 0xFF;
368 lParam=MAKELONG(tmpMsg->paramH&0x7ffff,tmpMsg->paramL>>8);
369 if (tmpMsg->message == WM_KEYDOWN || tmpMsg->message == WM_SYSKEYDOWN)
371 for (keyDown=i=0; i<256 && !keyDown; i++)
372 if (InputKeyStateTable[i] & 0x80)
373 keyDown++;
374 if (!keyDown)
375 lParam |= 0x40000000;
376 AsyncKeyStateTable[wParam]=InputKeyStateTable[wParam] |= 0x80;
378 else /* WM_KEYUP, WM_SYSKEYUP */
380 lParam |= 0xC0000000;
381 AsyncKeyStateTable[wParam]=InputKeyStateTable[wParam] &= ~0x80;
383 if (InputKeyStateTable[VK_MENU] & 0x80)
384 lParam |= 0x20000000;
385 if (tmpMsg->paramH & 0x8000) /*special_key bit*/
386 lParam |= 0x01000000;
387 hardware_event( tmpMsg->message, wParam, lParam,0, 0, tmpMsg->time, 0 );
389 else
391 if ((tmpMsg->message>= WM_MOUSEFIRST) && (tmpMsg->message <= WM_MOUSELAST))
393 switch (tmpMsg->message)
395 case WM_LBUTTONDOWN:
396 MouseButtonsStates[0]=AsyncMouseButtonsStates[0]=TRUE;break;
397 case WM_LBUTTONUP:
398 MouseButtonsStates[0]=AsyncMouseButtonsStates[0]=FALSE;break;
399 case WM_MBUTTONDOWN:
400 MouseButtonsStates[1]=AsyncMouseButtonsStates[1]=TRUE;break;
401 case WM_MBUTTONUP:
402 MouseButtonsStates[1]=AsyncMouseButtonsStates[1]=FALSE;break;
403 case WM_RBUTTONDOWN:
404 MouseButtonsStates[2]=AsyncMouseButtonsStates[2]=TRUE;break;
405 case WM_RBUTTONUP:
406 MouseButtonsStates[2]=AsyncMouseButtonsStates[2]=FALSE;break;
408 AsyncKeyStateTable[VK_LBUTTON]= InputKeyStateTable[VK_LBUTTON] = MouseButtonsStates[0] ? 0x80 : 0;
409 AsyncKeyStateTable[VK_MBUTTON]= InputKeyStateTable[VK_MBUTTON] = MouseButtonsStates[1] ? 0x80 : 0;
410 AsyncKeyStateTable[VK_RBUTTON]= InputKeyStateTable[VK_RBUTTON] = MouseButtonsStates[2] ? 0x80 : 0;
411 SetCursorPos32(tmpMsg->paramL,tmpMsg->paramH);
412 lParam=MAKELONG(tmpMsg->paramL,tmpMsg->paramH);
413 wParam=0;
414 if (MouseButtonsStates[0]) wParam |= MK_LBUTTON;
415 if (MouseButtonsStates[1]) wParam |= MK_MBUTTON;
416 if (MouseButtonsStates[2]) wParam |= MK_RBUTTON;
417 hardware_event( tmpMsg->message, wParam, lParam,
418 tmpMsg->paramL, tmpMsg->paramH, tmpMsg->time, 0 );
421 HOOK_CallHooks16( WH_JOURNALPLAYBACK, HC_SKIP, 0,
422 (LPARAM)SEGPTR_GET(tmpMsg));
424 else
426 if( tmpMsg->message == WM_QUEUESYNC )
427 if (HOOK_IsHooked( WH_CBT ))
428 HOOK_CallHooks16( WH_CBT, HCBT_QS, 0, 0L);
430 result= QS_MOUSE | QS_KEY; /* ? */
432 SEGPTR_FREE(tmpMsg);
434 return result;
437 /***********************************************************************
438 * MSG_PeekHardwareMsg
440 * Peek for a hardware message matching the hwnd and message filters.
442 static BOOL32 MSG_PeekHardwareMsg( MSG16 *msg, HWND16 hwnd, DWORD filter,
443 BOOL32 remove )
445 DWORD status = SYSQ_MSG_ACCEPT;
446 MESSAGEQUEUE *sysMsgQueue = QUEUE_GetSysQueue();
447 int i, kbd_msg, pos = sysMsgQueue->nextMessage;
449 /* FIXME: there has to be a better way to do this */
450 joySendMessages();
452 /* If the queue is empty, attempt to fill it */
453 if (!sysMsgQueue->msgCount && THREAD_IsWin16( THREAD_Current() )
454 && EVENT_Pending())
455 EVENT_WaitNetEvent( FALSE, FALSE );
457 for (i = kbd_msg = 0; i < sysMsgQueue->msgCount; i++, pos++)
459 if (pos >= sysMsgQueue->queueSize) pos = 0;
460 *msg = sysMsgQueue->messages[pos].msg;
462 /* Translate message */
464 if ((msg->message >= WM_MOUSEFIRST) && (msg->message <= WM_MOUSELAST))
466 HWND32 hWndScope = (HWND32)sysMsgQueue->messages[pos].extraInfo;
468 status = MSG_TranslateMouseMsg(hwnd, filter, msg, remove,
469 (Options.managed && IsWindow32(hWndScope) )
470 ? WIN_FindWndPtr(hWndScope) : WIN_GetDesktop() );
471 kbd_msg = 0;
473 else if ((msg->message >= WM_KEYFIRST) && (msg->message <= WM_KEYLAST))
475 status = MSG_TranslateKbdMsg(hwnd, filter, msg, remove);
476 kbd_msg = 1;
478 else /* Non-standard hardware event */
480 HARDWAREHOOKSTRUCT16 *hook;
481 if ((hook = SEGPTR_NEW(HARDWAREHOOKSTRUCT16)))
483 BOOL32 ret;
484 hook->hWnd = msg->hwnd;
485 hook->wMessage = msg->message;
486 hook->wParam = msg->wParam;
487 hook->lParam = msg->lParam;
488 ret = HOOK_CallHooks16( WH_HARDWARE,
489 remove ? HC_ACTION : HC_NOREMOVE,
490 0, (LPARAM)SEGPTR_GET(hook) );
491 SEGPTR_FREE(hook);
492 if (ret)
494 QUEUE_RemoveMsg( sysMsgQueue, pos );
495 continue;
497 status = SYSQ_MSG_ACCEPT;
501 switch (LOWORD(status))
503 case SYSQ_MSG_ACCEPT:
504 break;
506 case SYSQ_MSG_SKIP:
507 if (HOOK_IsHooked( WH_CBT ))
509 if( kbd_msg )
510 HOOK_CallHooks16( WH_CBT, HCBT_KEYSKIPPED,
511 msg->wParam, msg->lParam );
512 else
514 MOUSEHOOKSTRUCT16 *hook = SEGPTR_NEW(MOUSEHOOKSTRUCT16);
515 if (hook)
517 hook->pt = msg->pt;
518 hook->hwnd = msg->hwnd;
519 hook->wHitTestCode = HIWORD(status);
520 hook->dwExtraInfo = 0;
521 HOOK_CallHooks16( WH_CBT, HCBT_CLICKSKIPPED ,msg->message,
522 (LPARAM)SEGPTR_GET(hook) );
523 SEGPTR_FREE(hook);
528 if (remove)
529 QUEUE_RemoveMsg( sysMsgQueue, pos );
530 /* continue */
532 case SYSQ_MSG_CONTINUE:
533 continue;
535 case SYSQ_MSG_ABANDON:
536 return FALSE;
539 if (remove)
541 if (HOOK_IsHooked( WH_JOURNALRECORD )) MSG_JournalRecordMsg( msg );
542 QUEUE_RemoveMsg( sysMsgQueue, pos );
544 return TRUE;
546 return FALSE;
550 /**********************************************************************
551 * SetDoubleClickTime16 (USER.20)
553 void WINAPI SetDoubleClickTime16( UINT16 interval )
555 SetDoubleClickTime32( interval );
559 /**********************************************************************
560 * SetDoubleClickTime32 (USER32.480)
562 BOOL32 WINAPI SetDoubleClickTime32( UINT32 interval )
564 doubleClickSpeed = interval ? interval : 500;
565 return TRUE;
569 /**********************************************************************
570 * GetDoubleClickTime16 (USER.21)
572 UINT16 WINAPI GetDoubleClickTime16(void)
574 return doubleClickSpeed;
578 /**********************************************************************
579 * GetDoubleClickTime32 (USER32.239)
581 UINT32 WINAPI GetDoubleClickTime32(void)
583 return doubleClickSpeed;
587 /***********************************************************************
588 * MSG_SendMessage
590 * Implementation of an inter-task SendMessage.
592 static LRESULT MSG_SendMessage( HQUEUE16 hDestQueue, HWND16 hwnd, UINT16 msg,
593 WPARAM32 wParam, LPARAM lParam, WORD flags )
595 INT32 prevSMRL = debugSMRL;
596 QSMCTRL qCtrl = { 0, 1};
597 MESSAGEQUEUE *queue, *destQ;
599 if (!(queue = (MESSAGEQUEUE*)GlobalLock16( GetFastQueue() ))) return 0;
600 if (!(destQ = (MESSAGEQUEUE*)GlobalLock16( hDestQueue ))) return 0;
602 if (IsTaskLocked() || !IsWindow32(hwnd)) return 0;
604 debugSMRL+=4;
605 TRACE(sendmsg,"%*sSM: %s [%04x] (%04x -> %04x)\n",
606 prevSMRL, "", SPY_GetMsgName(msg), msg, queue->self, hDestQueue );
608 if( !(queue->wakeBits & QS_SMPARAMSFREE) )
610 TRACE(sendmsg,"\tIntertask SendMessage: sleeping since unreplied SendMessage pending\n");
611 QUEUE_WaitBits( QS_SMPARAMSFREE );
614 /* resume sending */
616 queue->hWnd = hwnd;
617 queue->msg = msg;
618 queue->wParam = LOWORD(wParam);
619 queue->wParamHigh = HIWORD(wParam);
620 queue->lParam = lParam;
621 queue->hPrevSendingTask = destQ->hSendingTask;
622 destQ->hSendingTask = GetFastQueue();
624 QUEUE_ClearWakeBit( queue, QS_SMPARAMSFREE );
625 queue->flags = (queue->flags & ~(QUEUE_SM_WIN32|QUEUE_SM_UNICODE)) | flags;
627 TRACE(sendmsg,"%*ssm: smResultInit = %08x\n", prevSMRL, "", (unsigned)&qCtrl);
629 queue->smResultInit = &qCtrl;
631 QUEUE_SetWakeBit( destQ, QS_SENDMESSAGE );
633 /* perform task switch and wait for the result */
635 while( qCtrl.bPending )
637 if (!(queue->wakeBits & QS_SMRESULT))
639 if (THREAD_IsWin16( THREAD_Current() )) DirectedYield( destQ->hTask );
640 QUEUE_WaitBits( QS_SMRESULT );
641 TRACE(sendmsg,"\tsm: have result!\n");
643 /* got something */
645 TRACE(sendmsg,"%*ssm: smResult = %08x\n", prevSMRL, "", (unsigned)queue->smResult );
647 if (queue->smResult) { /* FIXME, smResult should always be set */
648 queue->smResult->lResult = queue->SendMessageReturn;
649 queue->smResult->bPending = FALSE;
651 QUEUE_ClearWakeBit( queue, QS_SMRESULT );
653 if( queue->smResult != &qCtrl )
654 ERR(sendmsg, "%*ssm: weird scenes inside the goldmine!\n", prevSMRL, "");
656 queue->smResultInit = NULL;
658 TRACE(sendmsg,"%*sSM: [%04x] returning %08lx\n", prevSMRL, "", msg, qCtrl.lResult);
659 debugSMRL-=4;
661 return qCtrl.lResult;
665 /***********************************************************************
666 * ReplyMessage16 (USER.115)
668 void WINAPI ReplyMessage16( LRESULT result )
670 MESSAGEQUEUE *senderQ;
671 MESSAGEQUEUE *queue;
673 if (!(queue = (MESSAGEQUEUE*)GlobalLock16( GetFastQueue() ))) return;
675 TRACE(msg,"ReplyMessage, queue %04x\n", queue->self);
677 while( (senderQ = (MESSAGEQUEUE*)GlobalLock16( queue->InSendMessageHandle)))
679 TRACE(msg,"\trpm: replying to %04x (%04x -> %04x)\n",
680 queue->msg, queue->self, senderQ->self);
682 if( queue->wakeBits & QS_SENDMESSAGE )
684 QUEUE_ReceiveMessage( queue );
685 continue; /* ReceiveMessage() already called us */
688 if(!(senderQ->wakeBits & QS_SMRESULT) ) break;
689 if (THREAD_IsWin16(THREAD_Current())) OldYield();
691 if( !senderQ ) { TRACE(msg,"\trpm: done\n"); return; }
693 senderQ->SendMessageReturn = result;
694 TRACE(msg,"\trpm: smResult = %08x, result = %08lx\n",
695 (unsigned)queue->smResultCurrent, result );
697 senderQ->smResult = queue->smResultCurrent;
698 queue->InSendMessageHandle = 0;
700 QUEUE_SetWakeBit( senderQ, QS_SMRESULT );
701 if (THREAD_IsWin16(THREAD_Current())) DirectedYield( senderQ->hTask );
705 /***********************************************************************
706 * MSG_PeekMessage
708 static BOOL32 MSG_PeekMessage( LPMSG16 msg, HWND16 hwnd, WORD first, WORD last,
709 WORD flags, BOOL32 peek )
711 int pos, mask;
712 MESSAGEQUEUE *msgQueue;
713 HQUEUE16 hQueue;
715 #ifdef CONFIG_IPC
716 DDE_TestDDE(hwnd); /* do we have dde handling in the window ?*/
717 DDE_GetRemoteMessage();
718 #endif /* CONFIG_IPC */
720 mask = QS_POSTMESSAGE | QS_SENDMESSAGE; /* Always selected */
721 if (first || last)
723 if ((first <= WM_KEYLAST) && (last >= WM_KEYFIRST)) mask |= QS_KEY;
724 if ( ((first <= WM_MOUSELAST) && (last >= WM_MOUSEFIRST)) ||
725 ((first <= WM_NCMOUSELAST) && (last >= WM_NCMOUSEFIRST)) ) mask |= QS_MOUSE;
726 if ((first <= WM_TIMER) && (last >= WM_TIMER)) mask |= QS_TIMER;
727 if ((first <= WM_SYSTIMER) && (last >= WM_SYSTIMER)) mask |= QS_TIMER;
728 if ((first <= WM_PAINT) && (last >= WM_PAINT)) mask |= QS_PAINT;
730 else mask |= QS_MOUSE | QS_KEY | QS_TIMER | QS_PAINT;
732 if (IsTaskLocked()) flags |= PM_NOYIELD;
734 /* Never yield on Win32 threads */
735 if (!THREAD_IsWin16(THREAD_Current())) flags |= PM_NOYIELD;
737 while(1)
739 hQueue = GetFastQueue();
740 msgQueue = (MESSAGEQUEUE *)GlobalLock16( hQueue );
741 if (!msgQueue) return FALSE;
742 msgQueue->changeBits = 0;
744 /* First handle a message put by SendMessage() */
746 while (msgQueue->wakeBits & QS_SENDMESSAGE)
747 QUEUE_ReceiveMessage( msgQueue );
749 /* Now handle a WM_QUIT message */
751 if (msgQueue->wPostQMsg &&
752 (!first || WM_QUIT >= first) &&
753 (!last || WM_QUIT <= last) )
755 msg->hwnd = hwnd;
756 msg->message = WM_QUIT;
757 msg->wParam = msgQueue->wExitCode;
758 msg->lParam = 0;
759 if (flags & PM_REMOVE) msgQueue->wPostQMsg = 0;
760 break;
763 /* Now find a normal message */
765 if (((msgQueue->wakeBits & mask) & QS_POSTMESSAGE) &&
766 ((pos = QUEUE_FindMsg( msgQueue, hwnd, first, last )) != -1))
768 QMSG *qmsg = &msgQueue->messages[pos];
769 *msg = qmsg->msg;
770 msgQueue->GetMessageTimeVal = msg->time;
771 msgQueue->GetMessagePosVal = *(DWORD *)&msg->pt;
772 msgQueue->GetMessageExtraInfoVal = qmsg->extraInfo;
774 if (flags & PM_REMOVE) QUEUE_RemoveMsg( msgQueue, pos );
775 break;
778 msgQueue->changeBits |= MSG_JournalPlayBackMsg();
780 /* Now find a hardware event */
782 if (((msgQueue->wakeBits & mask) & (QS_MOUSE | QS_KEY)) &&
783 MSG_PeekHardwareMsg( msg, hwnd, MAKELONG(first,last), flags & PM_REMOVE ))
785 /* Got one */
786 msgQueue->GetMessageTimeVal = msg->time;
787 msgQueue->GetMessagePosVal = *(DWORD *)&msg->pt;
788 msgQueue->GetMessageExtraInfoVal = 0; /* Always 0 for now */
789 break;
792 /* Check again for SendMessage */
794 while (msgQueue->wakeBits & QS_SENDMESSAGE)
795 QUEUE_ReceiveMessage( msgQueue );
797 /* Now find a WM_PAINT message */
799 if ((msgQueue->wakeBits & mask) & QS_PAINT)
801 WND* wndPtr;
802 msg->hwnd = WIN_FindWinToRepaint( hwnd , hQueue );
803 msg->message = WM_PAINT;
804 msg->wParam = 0;
805 msg->lParam = 0;
807 if ((wndPtr = WIN_FindWndPtr(msg->hwnd)))
809 if( wndPtr->dwStyle & WS_MINIMIZE &&
810 wndPtr->class->hIcon )
812 msg->message = WM_PAINTICON;
813 msg->wParam = 1;
816 if( !hwnd || msg->hwnd == hwnd || IsChild16(hwnd,msg->hwnd) )
818 if( wndPtr->flags & WIN_INTERNAL_PAINT && !wndPtr->hrgnUpdate)
820 wndPtr->flags &= ~WIN_INTERNAL_PAINT;
821 QUEUE_DecPaintCount( hQueue );
823 break;
828 /* Check for timer messages, but yield first */
830 if (!(flags & PM_NOYIELD))
832 UserYield();
833 while (msgQueue->wakeBits & QS_SENDMESSAGE)
834 QUEUE_ReceiveMessage( msgQueue );
836 if ((msgQueue->wakeBits & mask) & QS_TIMER)
838 if (TIMER_GetTimerMsg(msg, hwnd, hQueue, flags & PM_REMOVE)) break;
841 if (peek)
843 if (!(flags & PM_NOYIELD)) UserYield();
844 return FALSE;
846 msgQueue->wakeMask = mask;
847 QUEUE_WaitBits( mask );
850 /* We got a message */
851 if (flags & PM_REMOVE)
853 WORD message = msg->message;
855 if (message == WM_KEYDOWN || message == WM_SYSKEYDOWN)
857 BYTE *p = &QueueKeyStateTable[msg->wParam & 0xff];
859 if (!(*p & 0x80))
860 *p ^= 0x01;
861 *p |= 0x80;
863 else if (message == WM_KEYUP || message == WM_SYSKEYUP)
864 QueueKeyStateTable[msg->wParam & 0xff] &= ~0x80;
866 if (peek) return TRUE;
867 else return (msg->message != WM_QUIT);
871 /***********************************************************************
872 * MSG_InternalGetMessage
874 * GetMessage() function for internal use. Behave like GetMessage(),
875 * but also call message filters and optionally send WM_ENTERIDLE messages.
876 * 'hwnd' must be the handle of the dialog or menu window.
877 * 'code' is the message filter value (MSGF_??? codes).
879 BOOL32 MSG_InternalGetMessage( MSG16 *msg, HWND32 hwnd, HWND32 hwndOwner,
880 WPARAM32 code, WORD flags, BOOL32 sendIdle )
882 for (;;)
884 if (sendIdle)
886 if (!MSG_PeekMessage( msg, 0, 0, 0, flags, TRUE ))
888 /* No message present -> send ENTERIDLE and wait */
889 if (IsWindow32(hwndOwner))
890 SendMessage16( hwndOwner, WM_ENTERIDLE,
891 code, (LPARAM)hwnd );
892 MSG_PeekMessage( msg, 0, 0, 0, flags, FALSE );
895 else /* Always wait for a message */
896 MSG_PeekMessage( msg, 0, 0, 0, flags, FALSE );
898 /* Call message filters */
900 if (HOOK_IsHooked( WH_SYSMSGFILTER ) || HOOK_IsHooked( WH_MSGFILTER ))
902 MSG16 *pmsg = SEGPTR_NEW(MSG16);
903 if (pmsg)
905 BOOL32 ret;
906 *pmsg = *msg;
907 ret = ((BOOL16)HOOK_CallHooks16( WH_SYSMSGFILTER, code, 0,
908 (LPARAM)SEGPTR_GET(pmsg) ) ||
909 (BOOL16)HOOK_CallHooks16( WH_MSGFILTER, code, 0,
910 (LPARAM)SEGPTR_GET(pmsg) ));
911 SEGPTR_FREE(pmsg);
912 if (ret)
914 /* Message filtered -> remove it from the queue */
915 /* if it's still there. */
916 if (!(flags & PM_REMOVE))
917 MSG_PeekMessage( msg, 0, 0, 0, PM_REMOVE, TRUE );
918 continue;
923 return (msg->message != WM_QUIT);
928 /***********************************************************************
929 * PeekMessage16 (USER.109)
931 BOOL16 WINAPI PeekMessage16( LPMSG16 msg, HWND16 hwnd, UINT16 first,
932 UINT16 last, UINT16 flags )
934 return MSG_PeekMessage( msg, hwnd, first, last, flags, TRUE );
937 /***********************************************************************
938 * PeekMessageA
940 BOOL32 WINAPI PeekMessage32A( LPMSG32 lpmsg, HWND32 hwnd,
941 UINT32 min,UINT32 max,UINT32 wRemoveMsg)
943 MSG16 msg;
944 BOOL32 ret;
945 ret=PeekMessage16(&msg,hwnd,min,max,wRemoveMsg);
946 /* FIXME: should translate the message to Win32 */
947 STRUCT32_MSG16to32(&msg,lpmsg);
948 return ret;
951 /***********************************************************************
952 * PeekMessageW Check queue for messages
954 * Checks for a message in the thread's queue, filtered as for
955 * GetMessage(). Returns immediately whether a message is available
956 * or not.
958 * Whether a retrieved message is removed from the queue is set by the
959 * _wRemoveMsg_ flags, which should be one of the following values:
961 * PM_NOREMOVE Do not remove the message from the queue.
963 * PM_REMOVE Remove the message from the queue.
965 * In addition, PM_NOYIELD may be combined into _wRemoveMsg_ to
966 * request that the system not yield control during PeekMessage();
967 * however applications may not rely on scheduling behavior.
969 * RETURNS
971 * Nonzero if a message is available and is retrieved, zero otherwise.
973 * CONFORMANCE
975 * ECMA-234, Win32
978 BOOL32 WINAPI PeekMessage32W(
979 LPMSG32 lpmsg, /* buffer to receive message */
980 HWND32 hwnd, /* restrict to messages for hwnd */
981 UINT32 min, /* minimum message to receive */
982 UINT32 max, /* maximum message to receive */
983 UINT32 wRemoveMsg /* removal flags */
985 /* FIXME: Should perform Unicode translation on specific messages */
986 return PeekMessage32A(lpmsg,hwnd,min,max,wRemoveMsg);
989 /***********************************************************************
990 * GetMessage16 (USER.108)
992 BOOL16 WINAPI GetMessage16( SEGPTR msg, HWND16 hwnd, UINT16 first, UINT16 last)
994 MSG16 *lpmsg = (MSG16 *)PTR_SEG_TO_LIN(msg);
995 MSG_PeekMessage( lpmsg,
996 hwnd, first, last, PM_REMOVE, FALSE );
998 TRACE(msg,"message %04x, hwnd %04x, filter(%04x - %04x)\n", lpmsg->message,
999 hwnd, first, last );
1000 HOOK_CallHooks16( WH_GETMESSAGE, HC_ACTION, 0, (LPARAM)msg );
1001 return (lpmsg->message != WM_QUIT);
1004 /***********************************************************************
1005 * GetMessage32A (USER32.270)
1007 BOOL32 WINAPI GetMessage32A(MSG32* lpmsg,HWND32 hwnd,UINT32 min,UINT32 max)
1009 BOOL32 ret;
1010 MSG16 *msg = SEGPTR_NEW(MSG16);
1011 if (!msg) return 0;
1012 ret=GetMessage16(SEGPTR_GET(msg),(HWND16)hwnd,min,max);
1013 /* FIXME */
1014 STRUCT32_MSG16to32(msg,lpmsg);
1015 SEGPTR_FREE(msg);
1016 return ret;
1019 /***********************************************************************
1020 * GetMessage32W (USER32.274) Retrieve next message
1022 * GetMessage retrieves the next event from the calling thread's
1023 * queue and deposits it in *lpmsg.
1025 * If _hwnd_ is not NULL, only messages for window _hwnd_ and its
1026 * children as specified by IsChild() are retrieved. If _hwnd_ is NULL
1027 * all application messages are retrieved.
1029 * _min_ and _max_ specify the range of messages of interest. If
1030 * min==max==0, no filtering is performed. Useful examples are
1031 * WM_KEYFIRST and WM_KEYLAST to retrieve keyboard input, and
1032 * WM_MOUSEFIRST and WM_MOUSELAST to retrieve mouse input.
1034 * WM_PAINT messages are not removed from the queue; they remain until
1035 * processed. Other messages are removed from the queue.
1037 * RETURNS
1039 * -1 on error, 0 if message is WM_QUIT, nonzero otherwise.
1041 * CONFORMANCE
1043 * ECMA-234, Win32
1046 BOOL32 WINAPI GetMessage32W(
1047 MSG32* lpmsg, /* buffer to receive message */
1048 HWND32 hwnd, /* restrict to messages for hwnd */
1049 UINT32 min, /* minimum message to receive */
1050 UINT32 max /* maximum message to receive */
1052 BOOL32 ret;
1053 MSG16 *msg = SEGPTR_NEW(MSG16);
1054 if (!msg) return 0;
1055 ret=GetMessage16(SEGPTR_GET(msg),(HWND16)hwnd,min,max);
1056 /* FIXME */
1057 STRUCT32_MSG16to32(msg,lpmsg);
1058 SEGPTR_FREE(msg);
1059 return ret;
1063 /***********************************************************************
1064 * PostMessage16 (USER.110)
1066 BOOL16 WINAPI PostMessage16( HWND16 hwnd, UINT16 message, WPARAM16 wParam,
1067 LPARAM lParam )
1069 MSG16 msg;
1070 WND *wndPtr;
1072 msg.hwnd = hwnd;
1073 msg.message = message;
1074 msg.wParam = wParam;
1075 msg.lParam = lParam;
1076 msg.time = GetTickCount();
1077 msg.pt.x = 0;
1078 msg.pt.y = 0;
1080 #ifdef CONFIG_IPC
1081 if (DDE_PostMessage(&msg))
1082 return TRUE;
1083 #endif /* CONFIG_IPC */
1085 if (hwnd == HWND_BROADCAST)
1087 TRACE(msg,"HWND_BROADCAST !\n");
1088 for (wndPtr = WIN_GetDesktop()->child; wndPtr; wndPtr = wndPtr->next)
1090 if (wndPtr->dwStyle & WS_POPUP || wndPtr->dwStyle & WS_CAPTION)
1092 TRACE(msg,"BROADCAST Message to hWnd=%04x m=%04X w=%04X l=%08lX !\n",
1093 wndPtr->hwndSelf, message, wParam, lParam);
1094 PostMessage16( wndPtr->hwndSelf, message, wParam, lParam );
1097 TRACE(msg,"End of HWND_BROADCAST !\n");
1098 return TRUE;
1101 wndPtr = WIN_FindWndPtr( hwnd );
1102 if (!wndPtr || !wndPtr->hmemTaskQ) return FALSE;
1104 return QUEUE_AddMsg( wndPtr->hmemTaskQ, &msg, 0 );
1108 /***********************************************************************
1109 * PostMessage32A (USER32.419)
1111 BOOL32 WINAPI PostMessage32A( HWND32 hwnd, UINT32 message, WPARAM32 wParam,
1112 LPARAM lParam )
1114 /* FIXME */
1115 if (message&0xffff0000)
1116 FIXME(msg,"message is truncated from %d to %d\n", message, message&0xffff);
1117 if (wParam&0xffff0000)
1118 FIXME(msg,"wParam is truncated from %d to %d\n", wParam, wParam&0xffff);
1119 return PostMessage16( hwnd, message, wParam, lParam );
1123 /***********************************************************************
1124 * PostMessage32W (USER32.420)
1126 BOOL32 WINAPI PostMessage32W( HWND32 hwnd, UINT32 message, WPARAM32 wParam,
1127 LPARAM lParam )
1129 /* FIXME */
1130 if (message&0xffff0000)
1131 FIXME(msg,"message is truncated from %d to %d\n", message, message&0xffff);
1132 if (wParam&0xffff0000)
1133 FIXME(msg,"wParam is truncated from %d to %d\n", wParam, wParam&0xffff);
1134 return PostMessage16( hwnd, message, wParam, lParam );
1138 /***********************************************************************
1139 * PostAppMessage16 (USER.116)
1141 BOOL16 WINAPI PostAppMessage16( HTASK16 hTask, UINT16 message, WPARAM16 wParam,
1142 LPARAM lParam )
1144 MSG16 msg;
1146 if (GetTaskQueue(hTask) == 0) return FALSE;
1147 msg.hwnd = 0;
1148 msg.message = message;
1149 msg.wParam = wParam;
1150 msg.lParam = lParam;
1151 msg.time = GetTickCount();
1152 msg.pt.x = 0;
1153 msg.pt.y = 0;
1155 return QUEUE_AddMsg( GetTaskQueue(hTask), &msg, 0 );
1159 /***********************************************************************
1160 * SendMessage16 (USER.111)
1162 LRESULT WINAPI SendMessage16( HWND16 hwnd, UINT16 msg, WPARAM16 wParam,
1163 LPARAM lParam)
1165 WND * wndPtr;
1166 WND **list, **ppWnd;
1167 LRESULT ret;
1169 #ifdef CONFIG_IPC
1170 MSG16 DDE_msg = { hwnd, msg, wParam, lParam };
1171 if (DDE_SendMessage(&DDE_msg)) return TRUE;
1172 #endif /* CONFIG_IPC */
1174 if (hwnd == HWND_BROADCAST)
1176 if (!(list = WIN_BuildWinArray( WIN_GetDesktop(), 0, NULL )))
1177 return TRUE;
1178 TRACE(msg,"HWND_BROADCAST !\n");
1179 for (ppWnd = list; *ppWnd; ppWnd++)
1181 wndPtr = *ppWnd;
1182 if (!IsWindow32(wndPtr->hwndSelf)) continue;
1183 if (wndPtr->dwStyle & WS_POPUP || wndPtr->dwStyle & WS_CAPTION)
1185 TRACE(msg,"BROADCAST Message to hWnd=%04x m=%04X w=%04lX l=%08lX !\n",
1186 wndPtr->hwndSelf, msg, (DWORD)wParam, lParam);
1187 SendMessage16( wndPtr->hwndSelf, msg, wParam, lParam );
1190 HeapFree( SystemHeap, 0, list );
1191 TRACE(msg,"End of HWND_BROADCAST !\n");
1192 return TRUE;
1195 if (HOOK_IsHooked( WH_CALLWNDPROC ))
1197 LPCWPSTRUCT16 pmsg;
1199 if ((pmsg = SEGPTR_NEW(CWPSTRUCT16)))
1201 pmsg->hwnd = hwnd;
1202 pmsg->message= msg;
1203 pmsg->wParam = wParam;
1204 pmsg->lParam = lParam;
1205 HOOK_CallHooks16( WH_CALLWNDPROC, HC_ACTION, 1,
1206 (LPARAM)SEGPTR_GET(pmsg) );
1207 hwnd = pmsg->hwnd;
1208 msg = pmsg->message;
1209 wParam = pmsg->wParam;
1210 lParam = pmsg->lParam;
1211 SEGPTR_FREE( pmsg );
1215 if (!(wndPtr = WIN_FindWndPtr( hwnd )))
1217 WARN(msg, "invalid hwnd %04x\n", hwnd );
1218 return 0;
1220 if (QUEUE_IsExitingQueue(wndPtr->hmemTaskQ))
1221 return 0; /* Don't send anything if the task is dying */
1223 SPY_EnterMessage( SPY_SENDMESSAGE16, hwnd, msg, wParam, lParam );
1225 if (wndPtr->hmemTaskQ != GetFastQueue())
1226 ret = MSG_SendMessage( wndPtr->hmemTaskQ, hwnd, msg,
1227 wParam, lParam, 0 );
1228 else
1229 ret = CallWindowProc16( (WNDPROC16)wndPtr->winproc,
1230 hwnd, msg, wParam, lParam );
1232 SPY_ExitMessage( SPY_RESULT_OK16, hwnd, msg, ret );
1233 return ret;
1236 /************************************************************************
1237 * MSG_CallWndProcHook32
1239 static void MSG_CallWndProcHook32( LPMSG32 pmsg, BOOL32 bUnicode )
1241 CWPSTRUCT32 cwp;
1243 cwp.lParam = pmsg->lParam;
1244 cwp.wParam = pmsg->wParam;
1245 cwp.message = pmsg->message;
1246 cwp.hwnd = pmsg->hwnd;
1248 if (bUnicode) HOOK_CallHooks32W(WH_CALLWNDPROC, HC_ACTION, 1, (LPARAM)&cwp);
1249 else HOOK_CallHooks32A( WH_CALLWNDPROC, HC_ACTION, 1, (LPARAM)&cwp );
1251 pmsg->lParam = cwp.lParam;
1252 pmsg->wParam = cwp.wParam;
1253 pmsg->message = cwp.message;
1254 pmsg->hwnd = cwp.hwnd;
1257 /**********************************************************************
1258 * PostThreadMessage32A (USER32.422)
1260 * BUGS
1262 * Thread-local message queues are not supported.
1265 BOOL32 WINAPI PostThreadMessage32A(DWORD idThread , UINT32 message,
1266 WPARAM32 wParam, LPARAM lParam )
1268 THDB *thdb = THREAD_ID_TO_THDB(idThread);
1269 if (!thdb || !thdb->process) return FALSE;
1271 FIXME(sendmsg, "(...): Should use thread-local message queue!\n");
1272 return PostAppMessage16(thdb->process->task, message, wParam, lParam);
1275 /**********************************************************************
1276 * PostThreadMessage32W (USER32.423)
1278 * BUGS
1280 * Thread-local message queues are not supported.
1283 BOOL32 WINAPI PostThreadMessage32W(DWORD idThread , UINT32 message,
1284 WPARAM32 wParam, LPARAM lParam )
1286 THDB *thdb = THREAD_ID_TO_THDB(idThread);
1287 if (!thdb || !thdb->process) return FALSE;
1289 FIXME(sendmsg, "(...): Should use thread-local message queue!\n");
1290 return PostAppMessage16(thdb->process->task, message, wParam, lParam);
1293 /***********************************************************************
1294 * SendMessage32A (USER32.454)
1296 LRESULT WINAPI SendMessage32A( HWND32 hwnd, UINT32 msg, WPARAM32 wParam,
1297 LPARAM lParam )
1299 WND * wndPtr;
1300 WND **list, **ppWnd;
1301 LRESULT ret;
1303 if (hwnd == HWND_BROADCAST || hwnd == HWND_TOPMOST)
1305 if (!(list = WIN_BuildWinArray( WIN_GetDesktop(), 0, NULL )))
1306 return TRUE;
1307 for (ppWnd = list; *ppWnd; ppWnd++)
1309 wndPtr = *ppWnd;
1310 if (!IsWindow32(wndPtr->hwndSelf)) continue;
1311 if (wndPtr->dwStyle & WS_POPUP || wndPtr->dwStyle & WS_CAPTION)
1312 SendMessage32A( wndPtr->hwndSelf, msg, wParam, lParam );
1314 HeapFree( SystemHeap, 0, list );
1315 return TRUE;
1318 if (HOOK_IsHooked( WH_CALLWNDPROC ))
1319 MSG_CallWndProcHook32( (LPMSG32)&hwnd, FALSE);
1321 if (!(wndPtr = WIN_FindWndPtr( hwnd )))
1323 WARN(msg, "invalid hwnd %08x\n", hwnd );
1324 return 0;
1327 if (QUEUE_IsExitingQueue(wndPtr->hmemTaskQ))
1328 return 0; /* Don't send anything if the task is dying */
1330 SPY_EnterMessage( SPY_SENDMESSAGE32, hwnd, msg, wParam, lParam );
1332 if (wndPtr->hmemTaskQ != GetFastQueue())
1333 ret = MSG_SendMessage( wndPtr->hmemTaskQ, hwnd, msg, wParam, lParam,
1334 QUEUE_SM_WIN32 );
1335 else
1336 ret = CallWindowProc32A( (WNDPROC32)wndPtr->winproc,
1337 hwnd, msg, wParam, lParam );
1339 SPY_ExitMessage( SPY_RESULT_OK32, hwnd, msg, ret );
1340 return ret;
1344 /***********************************************************************
1345 * SendMessage32W (USER32.459) Send Window Message
1347 * Sends a message to the window procedure of the specified window.
1348 * SendMessage() will not return until the called window procedure
1349 * either returns or calls ReplyMessage().
1351 * Use PostMessage() to send message and return immediately. A window
1352 * procedure may use InSendMessage() to detect
1353 * SendMessage()-originated messages.
1355 * Applications which communicate via HWND_BROADCAST may use
1356 * RegisterWindowMessage() to obtain a unique message to avoid conflicts
1357 * with other applications.
1359 * CONFORMANCE
1361 * ECMA-234, Win32
1363 LRESULT WINAPI SendMessage32W(
1364 HWND32 hwnd, /* Window to send message to. If HWND_BROADCAST,
1365 the message will be sent to all top-level windows. */
1367 UINT32 msg, /* message */
1368 WPARAM32 wParam, /* message parameter */
1369 LPARAM lParam /* additional message parameter */
1371 WND * wndPtr;
1372 WND **list, **ppWnd;
1373 LRESULT ret;
1375 if (hwnd == HWND_BROADCAST || hwnd == HWND_TOPMOST)
1377 if (!(list = WIN_BuildWinArray( WIN_GetDesktop(), 0, NULL )))
1378 return TRUE;
1379 for (ppWnd = list; *ppWnd; ppWnd++)
1381 wndPtr = *ppWnd;
1382 if (!IsWindow32(wndPtr->hwndSelf)) continue;
1383 if (wndPtr->dwStyle & WS_POPUP || wndPtr->dwStyle & WS_CAPTION)
1384 SendMessage32W( wndPtr->hwndSelf, msg, wParam, lParam );
1386 HeapFree( SystemHeap, 0, list );
1387 return TRUE;
1390 if (HOOK_IsHooked( WH_CALLWNDPROC ))
1391 MSG_CallWndProcHook32( (LPMSG32)&hwnd, TRUE);
1393 if (!(wndPtr = WIN_FindWndPtr( hwnd )))
1395 WARN(msg, "invalid hwnd %08x\n", hwnd );
1396 return 0;
1398 if (QUEUE_IsExitingQueue(wndPtr->hmemTaskQ))
1399 return 0; /* Don't send anything if the task is dying */
1401 SPY_EnterMessage( SPY_SENDMESSAGE32, hwnd, msg, wParam, lParam );
1403 if (wndPtr->hmemTaskQ != GetFastQueue())
1404 ret = MSG_SendMessage( wndPtr->hmemTaskQ, hwnd, msg, wParam, lParam,
1405 QUEUE_SM_WIN32 | QUEUE_SM_UNICODE );
1406 else
1407 ret = CallWindowProc32W( (WNDPROC32)wndPtr->winproc,
1408 hwnd, msg, wParam, lParam );
1410 SPY_ExitMessage( SPY_RESULT_OK32, hwnd, msg, ret );
1411 return ret;
1415 /***********************************************************************
1416 * SendMessageTimeout16 (not a WINAPI)
1418 LRESULT WINAPI SendMessageTimeout16( HWND16 hwnd, UINT16 msg, WPARAM16 wParam,
1419 LPARAM lParam, UINT16 flags,
1420 UINT16 timeout, LPWORD resultp)
1422 FIXME(sendmsg, "(...): semistub\n");
1423 return SendMessage16 (hwnd, msg, wParam, lParam);
1427 /***********************************************************************
1428 * SendMessageTimeout32A (USER32.457)
1430 LRESULT WINAPI SendMessageTimeout32A( HWND32 hwnd, UINT32 msg, WPARAM32 wParam,
1431 LPARAM lParam, UINT32 flags,
1432 UINT32 timeout, LPDWORD resultp)
1434 FIXME(sendmsg, "(...): semistub\n");
1435 return SendMessage32A (hwnd, msg, wParam, lParam);
1439 /***********************************************************************
1440 * SendMessageTimeout32W (USER32.458)
1442 LRESULT WINAPI SendMessageTimeout32W( HWND32 hwnd, UINT32 msg, WPARAM32 wParam,
1443 LPARAM lParam, UINT32 flags,
1444 UINT32 timeout, LPDWORD resultp)
1446 FIXME(sendmsg, "(...): semistub\n");
1447 return SendMessage32W (hwnd, msg, wParam, lParam);
1451 /***********************************************************************
1452 * WaitMessage (USER.112) (USER32.578) Suspend thread pending messages
1454 * WaitMessage() suspends a thread until events appear in the thread's
1455 * queue.
1457 * BUGS
1459 * Is supposed to return BOOL under Win32.
1461 * Thread-local message queues are not supported.
1463 * CONFORMANCE
1465 * ECMA-234, Win32
1468 void WINAPI WaitMessage( void )
1470 QUEUE_WaitBits( QS_ALLINPUT );
1473 /***********************************************************************
1474 * MsgWaitForMultipleObjects (USER32.400)
1476 DWORD WINAPI MsgWaitForMultipleObjects( DWORD nCount, HANDLE32 *pHandles,
1477 BOOL32 fWaitAll, DWORD dwMilliseconds,
1478 DWORD dwWakeMask )
1480 DWORD retv;
1482 TDB *currTask = (TDB *)GlobalLock16( GetCurrentTask() );
1483 HQUEUE16 hQueue = currTask? currTask->hQueue : 0;
1484 MESSAGEQUEUE *msgQueue = (MESSAGEQUEUE *)GlobalLock16( hQueue );
1485 if (!msgQueue) return 0xFFFFFFFF;
1487 msgQueue->changeBits = 0;
1488 msgQueue->wakeMask = dwWakeMask;
1490 retv = SYNC_DoWait( nCount, pHandles, fWaitAll, dwMilliseconds, FALSE, TRUE );
1492 return retv;
1497 struct accent_char
1499 BYTE ac_accent;
1500 BYTE ac_char;
1501 BYTE ac_result;
1504 static const struct accent_char accent_chars[] =
1506 /* A good idea should be to read /usr/X11/lib/X11/locale/iso8859-x/Compose */
1507 {'`', 'A', '\300'}, {'`', 'a', '\340'},
1508 {'\'', 'A', '\301'}, {'\'', 'a', '\341'},
1509 {'^', 'A', '\302'}, {'^', 'a', '\342'},
1510 {'~', 'A', '\303'}, {'~', 'a', '\343'},
1511 {'"', 'A', '\304'}, {'"', 'a', '\344'},
1512 {'O', 'A', '\305'}, {'o', 'a', '\345'},
1513 {'0', 'A', '\305'}, {'0', 'a', '\345'},
1514 {'A', 'A', '\305'}, {'a', 'a', '\345'},
1515 {'A', 'E', '\306'}, {'a', 'e', '\346'},
1516 {',', 'C', '\307'}, {',', 'c', '\347'},
1517 {'`', 'E', '\310'}, {'`', 'e', '\350'},
1518 {'\'', 'E', '\311'}, {'\'', 'e', '\351'},
1519 {'^', 'E', '\312'}, {'^', 'e', '\352'},
1520 {'"', 'E', '\313'}, {'"', 'e', '\353'},
1521 {'`', 'I', '\314'}, {'`', 'i', '\354'},
1522 {'\'', 'I', '\315'}, {'\'', 'i', '\355'},
1523 {'^', 'I', '\316'}, {'^', 'i', '\356'},
1524 {'"', 'I', '\317'}, {'"', 'i', '\357'},
1525 {'-', 'D', '\320'}, {'-', 'd', '\360'},
1526 {'~', 'N', '\321'}, {'~', 'n', '\361'},
1527 {'`', 'O', '\322'}, {'`', 'o', '\362'},
1528 {'\'', 'O', '\323'}, {'\'', 'o', '\363'},
1529 {'^', 'O', '\324'}, {'^', 'o', '\364'},
1530 {'~', 'O', '\325'}, {'~', 'o', '\365'},
1531 {'"', 'O', '\326'}, {'"', 'o', '\366'},
1532 {'/', 'O', '\330'}, {'/', 'o', '\370'},
1533 {'`', 'U', '\331'}, {'`', 'u', '\371'},
1534 {'\'', 'U', '\332'}, {'\'', 'u', '\372'},
1535 {'^', 'U', '\333'}, {'^', 'u', '\373'},
1536 {'"', 'U', '\334'}, {'"', 'u', '\374'},
1537 {'\'', 'Y', '\335'}, {'\'', 'y', '\375'},
1538 {'T', 'H', '\336'}, {'t', 'h', '\376'},
1539 {'s', 's', '\337'}, {'"', 'y', '\377'},
1540 {'s', 'z', '\337'}, {'i', 'j', '\377'},
1541 /* iso-8859-2 uses this */
1542 {'<', 'L', '\245'}, {'<', 'l', '\265'}, /* caron */
1543 {'<', 'S', '\251'}, {'<', 's', '\271'},
1544 {'<', 'T', '\253'}, {'<', 't', '\273'},
1545 {'<', 'Z', '\256'}, {'<', 'z', '\276'},
1546 {'<', 'C', '\310'}, {'<', 'c', '\350'},
1547 {'<', 'E', '\314'}, {'<', 'e', '\354'},
1548 {'<', 'D', '\317'}, {'<', 'd', '\357'},
1549 {'<', 'N', '\322'}, {'<', 'n', '\362'},
1550 {'<', 'R', '\330'}, {'<', 'r', '\370'},
1551 {';', 'A', '\241'}, {';', 'a', '\261'}, /* ogonek */
1552 {';', 'E', '\312'}, {';', 'e', '\332'},
1553 {'\'', 'Z', '\254'}, {'\'', 'z', '\274'}, /* acute */
1554 {'\'', 'R', '\300'}, {'\'', 'r', '\340'},
1555 {'\'', 'L', '\305'}, {'\'', 'l', '\345'},
1556 {'\'', 'C', '\306'}, {'\'', 'c', '\346'},
1557 {'\'', 'N', '\321'}, {'\'', 'n', '\361'},
1558 /* collision whith S, from iso-8859-9 !!! */
1559 {',', 'S', '\252'}, {',', 's', '\272'}, /* cedilla */
1560 {',', 'T', '\336'}, {',', 't', '\376'},
1561 {'.', 'Z', '\257'}, {'.', 'z', '\277'}, /* dot above */
1562 {'/', 'L', '\243'}, {'/', 'l', '\263'}, /* slash */
1563 {'/', 'D', '\320'}, {'/', 'd', '\360'},
1564 {'(', 'A', '\303'}, {'(', 'a', '\343'}, /* breve */
1565 {'\275', 'O', '\325'}, {'\275', 'o', '\365'}, /* double acute */
1566 {'\275', 'U', '\334'}, {'\275', 'u', '\374'},
1567 {'0', 'U', '\332'}, {'0', 'u', '\372'}, /* ring above */
1568 /* iso-8859-3 uses this */
1569 {'/', 'H', '\241'}, {'/', 'h', '\261'}, /* slash */
1570 {'>', 'H', '\246'}, {'>', 'h', '\266'}, /* circumflex */
1571 {'>', 'J', '\254'}, {'>', 'j', '\274'},
1572 {'>', 'C', '\306'}, {'>', 'c', '\346'},
1573 {'>', 'G', '\330'}, {'>', 'g', '\370'},
1574 {'>', 'S', '\336'}, {'>', 's', '\376'},
1575 /* collision whith G( from iso-8859-9 !!! */
1576 {'(', 'G', '\253'}, {'(', 'g', '\273'}, /* breve */
1577 {'(', 'U', '\335'}, {'(', 'u', '\375'},
1578 /* collision whith I. from iso-8859-3 !!! */
1579 {'.', 'I', '\251'}, {'.', 'i', '\271'}, /* dot above */
1580 {'.', 'C', '\305'}, {'.', 'c', '\345'},
1581 {'.', 'G', '\325'}, {'.', 'g', '\365'},
1582 /* iso-8859-4 uses this */
1583 {',', 'R', '\243'}, {',', 'r', '\263'}, /* cedilla */
1584 {',', 'L', '\246'}, {',', 'l', '\266'},
1585 {',', 'G', '\253'}, {',', 'g', '\273'},
1586 {',', 'N', '\321'}, {',', 'n', '\361'},
1587 {',', 'K', '\323'}, {',', 'k', '\363'},
1588 {'~', 'I', '\245'}, {'~', 'i', '\265'}, /* tilde */
1589 {'-', 'E', '\252'}, {'-', 'e', '\272'}, /* macron */
1590 {'-', 'A', '\300'}, {'-', 'a', '\340'},
1591 {'-', 'I', '\317'}, {'-', 'i', '\357'},
1592 {'-', 'O', '\322'}, {'-', 'o', '\362'},
1593 {'-', 'U', '\336'}, {'-', 'u', '\376'},
1594 {'/', 'T', '\254'}, {'/', 't', '\274'}, /* slash */
1595 {'.', 'E', '\314'}, {'.', 'e', '\344'}, /* dot above */
1596 {';', 'I', '\307'}, {';', 'i', '\347'}, /* ogonek */
1597 {';', 'U', '\331'}, {';', 'u', '\371'},
1598 /* iso-8859-9 uses this */
1599 /* iso-8859-9 has really bad choosen G( S, and I. as they collide
1600 * whith the same letters on other iso-8859-x (that is they are on
1601 * different places :-( ), if you use turkish uncomment these and
1602 * comment out the lines in iso-8859-2 and iso-8859-3 sections
1603 * FIXME: should be dynamic according to chosen language
1604 * if/when Wine has turkish support.
1606 /* collision whith G( from iso-8859-3 !!! */
1607 /* {'(', 'G', '\320'}, {'(', 'g', '\360'}, */ /* breve */
1608 /* collision whith S, from iso-8859-2 !!! */
1609 /* {',', 'S', '\336'}, {',', 's', '\376'}, */ /* cedilla */
1610 /* collision whith I. from iso-8859-3 !!! */
1611 /* {'.', 'I', '\335'}, {'.', 'i', '\375'}, */ /* dot above */
1615 /***********************************************************************
1616 * MSG_DoTranslateMessage
1618 * Implementation of TranslateMessage.
1620 * TranslateMessage translates virtual-key messages into character-messages,
1621 * as follows :
1622 * WM_KEYDOWN/WM_KEYUP combinations produce a WM_CHAR or WM_DEADCHAR message.
1623 * ditto replacing WM_* with WM_SYS*
1624 * This produces WM_CHAR messages only for keys mapped to ASCII characters
1625 * by the keyboard driver.
1627 static BOOL32 MSG_DoTranslateMessage( UINT32 message, HWND32 hwnd,
1628 WPARAM32 wParam, LPARAM lParam )
1630 static int dead_char;
1631 BYTE wp[2];
1633 if (message != WM_MOUSEMOVE && message != WM_TIMER)
1634 TRACE(msg, "(%s, %04X, %08lX)\n",
1635 SPY_GetMsgName(message), wParam, lParam );
1636 if(message >= WM_KEYFIRST && message <= WM_KEYLAST)
1637 TRACE(key, "(%s, %04X, %08lX)\n",
1638 SPY_GetMsgName(message), wParam, lParam );
1640 if ((message != WM_KEYDOWN) && (message != WM_SYSKEYDOWN)) return FALSE;
1642 TRACE(key, "Translating key %04X, scancode %04X\n",
1643 wParam, HIWORD(lParam) );
1645 /* FIXME : should handle ToAscii yielding 2 */
1646 switch (ToAscii32(wParam, HIWORD(lParam),
1647 QueueKeyStateTable,(LPWORD)wp, 0))
1649 case 1 :
1650 message = (message == WM_KEYDOWN) ? WM_CHAR : WM_SYSCHAR;
1651 /* Should dead chars handling go in ToAscii ? */
1652 if (dead_char)
1654 int i;
1656 if (wp[0] == ' ') wp[0] = dead_char;
1657 if (dead_char == 0xa2) dead_char = '(';
1658 else if (dead_char == 0xa8) dead_char = '"';
1659 else if (dead_char == 0xb2) dead_char = ';';
1660 else if (dead_char == 0xb4) dead_char = '\'';
1661 else if (dead_char == 0xb7) dead_char = '<';
1662 else if (dead_char == 0xb8) dead_char = ',';
1663 else if (dead_char == 0xff) dead_char = '.';
1664 for (i = 0; i < sizeof(accent_chars)/sizeof(accent_chars[0]); i++)
1665 if ((accent_chars[i].ac_accent == dead_char) &&
1666 (accent_chars[i].ac_char == wp[0]))
1668 wp[0] = accent_chars[i].ac_result;
1669 break;
1671 dead_char = 0;
1673 TRACE(key, "1 -> PostMessage(%s)\n", SPY_GetMsgName(message));
1674 PostMessage16( hwnd, message, wp[0], lParam );
1675 return TRUE;
1677 case -1 :
1678 message = (message == WM_KEYDOWN) ? WM_DEADCHAR : WM_SYSDEADCHAR;
1679 dead_char = wp[0];
1680 TRACE(key, "-1 -> PostMessage(%s)\n",
1681 SPY_GetMsgName(message));
1682 PostMessage16( hwnd, message, wp[0], lParam );
1683 return TRUE;
1685 return FALSE;
1689 /***********************************************************************
1690 * TranslateMessage16 (USER.113)
1692 BOOL16 WINAPI TranslateMessage16( const MSG16 *msg )
1694 return MSG_DoTranslateMessage( msg->message, msg->hwnd,
1695 msg->wParam, msg->lParam );
1699 /***********************************************************************
1700 * TranslateMessage32 (USER32.556)
1702 BOOL32 WINAPI TranslateMessage32( const MSG32 *msg )
1704 return MSG_DoTranslateMessage( msg->message, msg->hwnd,
1705 msg->wParam, msg->lParam );
1709 /***********************************************************************
1710 * DispatchMessage16 (USER.114)
1712 LONG WINAPI DispatchMessage16( const MSG16* msg )
1714 WND * wndPtr;
1715 LONG retval;
1716 int painting;
1718 /* Process timer messages */
1719 if ((msg->message == WM_TIMER) || (msg->message == WM_SYSTIMER))
1721 if (msg->lParam)
1723 return CallWindowProc16( (WNDPROC16)msg->lParam, msg->hwnd,
1724 msg->message, msg->wParam, GetTickCount() );
1728 if (!msg->hwnd) return 0;
1729 if (!(wndPtr = WIN_FindWndPtr( msg->hwnd ))) return 0;
1730 if (!wndPtr->winproc) return 0;
1731 painting = (msg->message == WM_PAINT);
1732 if (painting) wndPtr->flags |= WIN_NEEDS_BEGINPAINT;
1734 SPY_EnterMessage( SPY_DISPATCHMESSAGE16, msg->hwnd, msg->message,
1735 msg->wParam, msg->lParam );
1736 retval = CallWindowProc16( (WNDPROC16)wndPtr->winproc,
1737 msg->hwnd, msg->message,
1738 msg->wParam, msg->lParam );
1739 SPY_ExitMessage( SPY_RESULT_OK16, msg->hwnd, msg->message, retval );
1741 if (painting && (wndPtr = WIN_FindWndPtr( msg->hwnd )) &&
1742 (wndPtr->flags & WIN_NEEDS_BEGINPAINT) && wndPtr->hrgnUpdate)
1744 ERR(msg, "BeginPaint not called on WM_PAINT for hwnd %04x!\n",
1745 msg->hwnd);
1746 wndPtr->flags &= ~WIN_NEEDS_BEGINPAINT;
1747 /* Validate the update region to avoid infinite WM_PAINT loop */
1748 ValidateRect32( msg->hwnd, NULL );
1750 return retval;
1754 /***********************************************************************
1755 * DispatchMessage32A (USER32.141)
1757 LONG WINAPI DispatchMessage32A( const MSG32* msg )
1759 WND * wndPtr;
1760 LONG retval;
1761 int painting;
1763 /* Process timer messages */
1764 if ((msg->message == WM_TIMER) || (msg->message == WM_SYSTIMER))
1766 if (msg->lParam)
1768 /* HOOK_CallHooks32A( WH_CALLWNDPROC, HC_ACTION, 0, FIXME ); */
1769 return CallWindowProc32A( (WNDPROC32)msg->lParam, msg->hwnd,
1770 msg->message, msg->wParam, GetTickCount() );
1774 if (!msg->hwnd) return 0;
1775 if (!(wndPtr = WIN_FindWndPtr( msg->hwnd ))) return 0;
1776 if (!wndPtr->winproc) return 0;
1777 painting = (msg->message == WM_PAINT);
1778 if (painting) wndPtr->flags |= WIN_NEEDS_BEGINPAINT;
1779 /* HOOK_CallHooks32A( WH_CALLWNDPROC, HC_ACTION, 0, FIXME ); */
1781 SPY_EnterMessage( SPY_DISPATCHMESSAGE32, msg->hwnd, msg->message,
1782 msg->wParam, msg->lParam );
1783 retval = CallWindowProc32A( (WNDPROC32)wndPtr->winproc,
1784 msg->hwnd, msg->message,
1785 msg->wParam, msg->lParam );
1786 SPY_ExitMessage( SPY_RESULT_OK32, msg->hwnd, msg->message, retval );
1788 if (painting && (wndPtr = WIN_FindWndPtr( msg->hwnd )) &&
1789 (wndPtr->flags & WIN_NEEDS_BEGINPAINT) && wndPtr->hrgnUpdate)
1791 ERR(msg, "BeginPaint not called on WM_PAINT for hwnd %04x!\n",
1792 msg->hwnd);
1793 wndPtr->flags &= ~WIN_NEEDS_BEGINPAINT;
1794 /* Validate the update region to avoid infinite WM_PAINT loop */
1795 ValidateRect32( msg->hwnd, NULL );
1797 return retval;
1801 /***********************************************************************
1802 * DispatchMessage32W (USER32.142) Process Message
1804 * Process the message specified in the structure *_msg_.
1806 * If the lpMsg parameter points to a WM_TIMER message and the
1807 * parameter of the WM_TIMER message is not NULL, the lParam parameter
1808 * points to the function that is called instead of the window
1809 * procedure.
1811 * The message must be valid.
1813 * RETURNS
1815 * DispatchMessage() returns the result of the window procedure invoked.
1817 * CONFORMANCE
1819 * ECMA-234, Win32
1822 LONG WINAPI DispatchMessage32W( const MSG32* msg )
1824 WND * wndPtr;
1825 LONG retval;
1826 int painting;
1828 /* Process timer messages */
1829 if ((msg->message == WM_TIMER) || (msg->message == WM_SYSTIMER))
1831 if (msg->lParam)
1833 /* HOOK_CallHooks32W( WH_CALLWNDPROC, HC_ACTION, 0, FIXME ); */
1834 return CallWindowProc32W( (WNDPROC32)msg->lParam, msg->hwnd,
1835 msg->message, msg->wParam, GetTickCount() );
1839 if (!msg->hwnd) return 0;
1840 if (!(wndPtr = WIN_FindWndPtr( msg->hwnd ))) return 0;
1841 if (!wndPtr->winproc) return 0;
1842 painting = (msg->message == WM_PAINT);
1843 if (painting) wndPtr->flags |= WIN_NEEDS_BEGINPAINT;
1844 /* HOOK_CallHooks32W( WH_CALLWNDPROC, HC_ACTION, 0, FIXME ); */
1846 SPY_EnterMessage( SPY_DISPATCHMESSAGE32, msg->hwnd, msg->message,
1847 msg->wParam, msg->lParam );
1848 retval = CallWindowProc32W( (WNDPROC32)wndPtr->winproc,
1849 msg->hwnd, msg->message,
1850 msg->wParam, msg->lParam );
1851 SPY_ExitMessage( SPY_RESULT_OK32, msg->hwnd, msg->message, retval );
1853 if (painting && (wndPtr = WIN_FindWndPtr( msg->hwnd )) &&
1854 (wndPtr->flags & WIN_NEEDS_BEGINPAINT) && wndPtr->hrgnUpdate)
1856 ERR(msg, "BeginPaint not called on WM_PAINT for hwnd %04x!\n",
1857 msg->hwnd);
1858 wndPtr->flags &= ~WIN_NEEDS_BEGINPAINT;
1859 /* Validate the update region to avoid infinite WM_PAINT loop */
1860 ValidateRect32( msg->hwnd, NULL );
1862 return retval;
1866 /***********************************************************************
1867 * RegisterWindowMessage16 (USER.118)
1869 WORD WINAPI RegisterWindowMessage16( SEGPTR str )
1871 TRACE(msg, "%08lx\n", (DWORD)str );
1872 return GlobalAddAtom16( str );
1876 /***********************************************************************
1877 * RegisterWindowMessage32A (USER32.437)
1879 WORD WINAPI RegisterWindowMessage32A( LPCSTR str )
1881 TRACE(msg, "%s\n", str );
1882 return GlobalAddAtom32A( str );
1886 /***********************************************************************
1887 * RegisterWindowMessage32W (USER32.438)
1889 WORD WINAPI RegisterWindowMessage32W( LPCWSTR str )
1891 TRACE(msg, "%p\n", str );
1892 return GlobalAddAtom32W( str );
1896 /***********************************************************************
1897 * GetTickCount (USER.13) (KERNEL32.299) System Time
1898 * Returns the number of milliseconds, modulo 2^32, since the start
1899 * of the current session.
1901 * CONFORMANCE
1903 * ECMA-234, Win32
1905 DWORD WINAPI GetTickCount(void)
1907 struct timeval t;
1908 gettimeofday( &t, NULL );
1909 /* make extremely compatible: granularity is 25 msec */
1910 return ((t.tv_sec * 1000) + (t.tv_usec / 25000) * 25) - MSG_WineStartTicks;
1914 /***********************************************************************
1915 * GetCurrentTime16 (USER.15)
1917 * (effectively identical to GetTickCount)
1919 DWORD WINAPI GetCurrentTime16(void)
1921 return GetTickCount();
1925 /***********************************************************************
1926 * InSendMessage16 (USER.192)
1928 BOOL16 WINAPI InSendMessage16(void)
1930 return InSendMessage32();
1934 /***********************************************************************
1935 * InSendMessage32 (USER32.320)
1937 BOOL32 WINAPI InSendMessage32(void)
1939 MESSAGEQUEUE *queue;
1941 if (!(queue = (MESSAGEQUEUE *)GlobalLock16( GetFastQueue() )))
1942 return 0;
1943 return (BOOL32)queue->InSendMessageHandle;
1946 /***********************************************************************
1947 * BroadcastSystemMessage (USER32.12)
1949 LONG WINAPI BroadcastSystemMessage(
1950 DWORD dwFlags,LPDWORD recipients,UINT32 uMessage,WPARAM32 wParam,
1951 LPARAM lParam
1953 FIXME(sendmsg,"(%08lx,%08lx,%08x,%08x,%08lx): stub!\n",
1954 dwFlags,*recipients,uMessage,wParam,lParam
1956 return 0;
1959 /***********************************************************************
1960 * SendNotifyMessageA (USER32.460)
1961 * FIXME
1962 * The message sended with PostMessage has to be put in the queue
1963 * with a higher priority as the other "Posted" messages.
1964 * QUEUE_AddMsg has to be modifyed.
1966 BOOL32 WINAPI SendNotifyMessage32A(HWND32 hwnd,UINT32 msg,WPARAM32 wParam,LPARAM lParam)
1967 { BOOL32 ret = TRUE;
1968 FIXME(msg,"(%04x,%08x,%08x,%08lx) not complete\n",
1969 hwnd, msg, wParam, lParam);
1971 if ( GetCurrentThreadId() == GetWindowThreadProcessId ( hwnd, NULL))
1972 { ret=SendMessage32A ( hwnd, msg, wParam, lParam );
1974 else
1975 { PostMessage32A ( hwnd, msg, wParam, lParam );
1977 return ret;
1980 /***********************************************************************
1981 * SendNotifyMessageW (USER32.461)
1982 * FIXME
1983 * The message sended with PostMessage has to be put in the queue
1984 * with a higher priority as the other "Posted" messages.
1985 * QUEUE_AddMsg has to be modifyed.
1987 BOOL32 WINAPI SendNotifyMessage32W(HWND32 hwnd,UINT32 msg,WPARAM32 wParam,LPARAM lParam)
1988 { BOOL32 ret = TRUE;
1989 FIXME(msg,"(%04x,%08x,%08x,%08lx) not complete\n",
1990 hwnd, msg, wParam, lParam);
1992 if ( GetCurrentThreadId() == GetWindowThreadProcessId ( hwnd, NULL))
1993 { ret=SendMessage32W ( hwnd, msg, wParam, lParam );
1995 else
1996 { PostMessage32W ( hwnd, msg, wParam, lParam );
1998 return ret;
2001 /***********************************************************************
2002 * SendMessageCallBack32A
2003 * FIXME: It's like PostMessage. The callback gets called when the message
2004 * is processed. We have to modify the message processing for a exact
2005 * implementation...
2007 BOOL32 WINAPI SendMessageCallBack32A(
2008 HWND32 hWnd,UINT32 Msg,WPARAM32 wParam,LPARAM lParam,
2009 FARPROC32 lpResultCallBack,DWORD dwData)
2011 FIXME(msg,"(0x%04x,0x%04x,0x%08x,0x%08lx,%p,0x%08lx),stub!\n",
2012 hWnd,Msg,wParam,lParam,lpResultCallBack,dwData);
2013 if ( hWnd == HWND_BROADCAST)
2014 { PostMessage32A( hWnd, Msg, wParam, lParam);
2015 FIXME(msg,"Broadcast: Callback will not be called!\n");
2016 return TRUE;
2018 (lpResultCallBack)( hWnd, Msg, dwData, SendMessage32A ( hWnd, Msg, wParam, lParam ));
2019 return TRUE;