- Don't string copy from uninitialised stack memory. In fact don't
[wine] / dlls / user / message.c
1 /*
2  * Window messaging support
3  *
4  * Copyright 2001 Alexandre Julliard
5  */
6
7 #include "winbase.h"
8 #include "wingdi.h"
9 #include "winuser.h"
10 #include "winerror.h"
11 #include "winnls.h"
12 #include "dde.h"
13 #include "wine/unicode.h"
14 #include "wine/server.h"
15 #include "queue.h"
16 #include "input.h"
17 #include "message.h"
18 #include "hook.h"
19 #include "spy.h"
20 #include "user.h"
21 #include "win.h"
22 #include "debugtools.h"
23
24 DEFAULT_DEBUG_CHANNEL(msg);
25
26 #define WM_NCMOUSEFIRST WM_NCMOUSEMOVE
27 #define WM_NCMOUSELAST  WM_NCMBUTTONDBLCLK
28
29 #define MAX_PACK_COUNT 4
30
31 /* description of the data fields that need to be packed along with a sent message */
32 struct packed_message
33 {
34     int         count;
35     const void *data[MAX_PACK_COUNT];
36     size_t      size[MAX_PACK_COUNT];
37 };
38
39 /* info about the message currently being received by the current thread */
40 struct received_message_info
41 {
42     enum message_type type;
43     MSG               msg;
44     UINT              flags;  /* InSendMessageEx return flags */
45 };
46
47 /* structure to group all parameters for sent messages of the various kinds */
48 struct send_message_info
49 {
50     enum message_type type;
51     HWND              hwnd;
52     UINT              msg;
53     WPARAM            wparam;
54     LPARAM            lparam;
55     UINT              flags;      /* flags for SendMessageTimeout */
56     UINT              timeout;    /* timeout for SendMessageTimeout */
57     SENDASYNCPROC     callback;   /* callback function for SendMessageCallback */
58     ULONG_PTR         data;       /* callback data */
59 };
60
61
62 /* flag for messages that contain pointers */
63 /* 32 messages per entry, messages 0..31 map to bits 0..31 */
64
65 #define SET(msg) (1 << ((msg) & 31))
66
67 static const unsigned int message_pointer_flags[] =
68 {
69     /* 0x00 - 0x1f */
70     SET(WM_CREATE) | SET(WM_SETTEXT) | SET(WM_GETTEXT) |
71     SET(WM_WININICHANGE) | SET(WM_DEVMODECHANGE),
72     /* 0x20 - 0x3f */
73     SET(WM_GETMINMAXINFO) | SET(WM_DRAWITEM) | SET(WM_MEASUREITEM) | SET(WM_DELETEITEM) |
74     SET(WM_COMPAREITEM),
75     /* 0x40 - 0x5f */
76     SET(WM_WINDOWPOSCHANGING) | SET(WM_WINDOWPOSCHANGED) | SET(WM_COPYDATA) |
77     SET(WM_NOTIFY) | SET(WM_HELP),
78     /* 0x60 - 0x7f */
79     SET(WM_STYLECHANGING) | SET(WM_STYLECHANGED),
80     /* 0x80 - 0x9f */
81     SET(WM_NCCREATE) | SET(WM_NCCALCSIZE) | SET(WM_GETDLGCODE),
82     /* 0xa0 - 0xbf */
83     SET(EM_GETSEL) | SET(EM_GETRECT) | SET(EM_SETRECT) | SET(EM_SETRECTNP),
84     /* 0xc0 - 0xdf */
85     SET(EM_REPLACESEL) | SET(EM_GETLINE) | SET(EM_SETTABSTOPS),
86     /* 0xe0 - 0xff */
87     SET(SBM_GETRANGE) | SET(SBM_SETSCROLLINFO) | SET(SBM_GETSCROLLINFO),
88     /* 0x100 - 0x11f */
89     0,
90     /* 0x120 - 0x13f */
91     0,
92     /* 0x140 - 0x15f */
93     SET(CB_GETEDITSEL) | SET(CB_ADDSTRING) | SET(CB_DIR) | SET(CB_GETLBTEXT) |
94     SET(CB_INSERTSTRING) | SET(CB_FINDSTRING) | SET(CB_SELECTSTRING) |
95     SET(CB_GETDROPPEDCONTROLRECT) | SET(CB_FINDSTRINGEXACT),
96     /* 0x160 - 0x17f */
97     0,
98     /* 0x180 - 0x19f */
99     SET(LB_ADDSTRING) | SET(LB_INSERTSTRING) | SET(LB_GETTEXT) | SET(LB_SELECTSTRING) |
100     SET(LB_DIR) | SET(LB_FINDSTRING) |
101     SET(LB_GETSELITEMS) | SET(LB_SETTABSTOPS) | SET(LB_ADDFILE) | SET(LB_GETITEMRECT),
102     /* 0x1a0 - 0x1bf */
103     SET(LB_FINDSTRINGEXACT),
104     /* 0x1c0 - 0x1df */
105     0,
106     /* 0x1e0 - 0x1ff */
107     0,
108     /* 0x200 - 0x21f */
109     SET(WM_NEXTMENU) | SET(WM_SIZING) | SET(WM_MOVING) | SET(WM_DEVICECHANGE),
110     /* 0x220 - 0x23f */
111     SET(WM_MDICREATE) | SET(WM_MDIGETACTIVE) | SET(WM_DROPOBJECT) |
112     SET(WM_QUERYDROPOBJECT) | SET(WM_DRAGLOOP) | SET(WM_DRAGSELECT) | SET(WM_DRAGMOVE),
113     /* 0x240 - 0x25f */
114     0,
115     /* 0x260 - 0x27f */
116     0,
117     /* 0x280 - 0x29f */
118     0,
119     /* 0x2a0 - 0x2bf */
120     0,
121     /* 0x2c0 - 0x2df */
122     0,
123     /* 0x2e0 - 0x2ff */
124     0,
125     /* 0x300 - 0x31f */
126     SET(WM_ASKCBFORMATNAME)
127 };
128
129 /* flags for messages that contain Unicode strings */
130 static const unsigned int message_unicode_flags[] =
131 {
132     /* 0x00 - 0x1f */
133     SET(WM_CREATE) | SET(WM_SETTEXT) | SET(WM_GETTEXT) | SET(WM_GETTEXTLENGTH) |
134     SET(WM_WININICHANGE) | SET(WM_DEVMODECHANGE),
135     /* 0x20 - 0x3f */
136     SET(WM_CHARTOITEM),
137     /* 0x40 - 0x5f */
138     0,
139     /* 0x60 - 0x7f */
140     0,
141     /* 0x80 - 0x9f */
142     SET(WM_NCCREATE),
143     /* 0xa0 - 0xbf */
144     0,
145     /* 0xc0 - 0xdf */
146     SET(EM_REPLACESEL) | SET(EM_GETLINE) | SET(EM_SETPASSWORDCHAR),
147     /* 0xe0 - 0xff */
148     0,
149     /* 0x100 - 0x11f */
150     SET(WM_CHAR) | SET(WM_DEADCHAR) | SET(WM_SYSCHAR) | SET(WM_SYSDEADCHAR),
151     /* 0x120 - 0x13f */
152     SET(WM_MENUCHAR),
153     /* 0x140 - 0x15f */
154     SET(CB_ADDSTRING) | SET(CB_DIR) | SET(CB_GETLBTEXT) | SET(CB_GETLBTEXTLEN) |
155     SET(CB_INSERTSTRING) | SET(CB_FINDSTRING) | SET(CB_SELECTSTRING) | SET(CB_FINDSTRINGEXACT),
156     /* 0x160 - 0x17f */
157     0,
158     /* 0x180 - 0x19f */
159     SET(LB_ADDSTRING) | SET(LB_INSERTSTRING) | SET(LB_GETTEXT) | SET(LB_GETTEXTLEN) |
160     SET(LB_SELECTSTRING) | SET(LB_DIR) | SET(LB_FINDSTRING) | SET(LB_ADDFILE),
161     /* 0x1a0 - 0x1bf */
162     SET(LB_FINDSTRINGEXACT),
163     /* 0x1c0 - 0x1df */
164     0,
165     /* 0x1e0 - 0x1ff */
166     0,
167     /* 0x200 - 0x21f */
168     0,
169     /* 0x220 - 0x23f */
170     SET(WM_MDICREATE),
171     /* 0x240 - 0x25f */
172     0,
173     /* 0x260 - 0x27f */
174     0,
175     /* 0x280 - 0x29f */
176     0,
177     /* 0x2a0 - 0x2bf */
178     0,
179     /* 0x2c0 - 0x2df */
180     0,
181     /* 0x2e0 - 0x2ff */
182     0,
183     /* 0x300 - 0x31f */
184     SET(WM_PAINTCLIPBOARD) | SET(WM_SIZECLIPBOARD) | SET(WM_ASKCBFORMATNAME)
185 };
186
187 /* check whether a given message type includes pointers */
188 inline static int is_pointer_message( UINT message )
189 {
190     if (message >= 8*sizeof(message_pointer_flags)) return FALSE;
191     return (message_pointer_flags[message / 32] & SET(message)) != 0;
192 }
193
194 /* check whether a given message type contains Unicode (or ASCII) chars */
195 inline static int is_unicode_message( UINT message )
196 {
197     if (message >= 8*sizeof(message_unicode_flags)) return FALSE;
198     return (message_unicode_flags[message / 32] & SET(message)) != 0;
199 }
200
201 #undef SET
202
203 /* add a data field to a packed message */
204 inline static void push_data( struct packed_message *data, const void *ptr, size_t size )
205 {
206     data->data[data->count] = ptr;
207     data->size[data->count] = size;
208     data->count++;
209 }
210
211 /* add a string to a packed message */
212 inline static void push_string( struct packed_message *data, LPCWSTR str )
213 {
214     push_data( data, str, (strlenW(str) + 1) * sizeof(WCHAR) );
215 }
216
217 /* retrieve a pointer to data from a packed message and increment the buffer pointer */
218 inline static void *get_data( void **buffer, size_t size )
219 {
220     void *ret = *buffer;
221     *buffer = (char *)*buffer + size;
222     return ret;
223 }
224
225 /* make sure that the buffer contains a valid null-terminated Unicode string */
226 inline static BOOL check_string( LPCWSTR str, size_t size )
227 {
228     for (size /= sizeof(WCHAR); size; size--, str++)
229         if (!*str) return TRUE;
230     return FALSE;
231 }
232
233 /* make sure that there is space for 'size' bytes in buffer, growing it if needed */
234 inline static void *get_buffer_space( void **buffer, size_t size )
235 {
236     void *ret;
237     if (!(ret = HeapReAlloc( GetProcessHeap(), 0, *buffer, size )))
238         HeapFree( GetProcessHeap(), 0, *buffer );
239     *buffer = ret;
240     return ret;
241 }
242
243 /* retrieve a string pointer from packed data */
244 inline static LPWSTR get_string( void **buffer )
245 {
246     return get_data( buffer, (strlenW( (LPWSTR)*buffer ) + 1) * sizeof(WCHAR) );
247 }
248
249 /* check whether a combobox expects strings or ids in CB_ADDSTRING/CB_INSERTSTRING */
250 inline static BOOL combobox_has_strings( HWND hwnd )
251 {
252     DWORD style = GetWindowLongA( hwnd, GWL_STYLE );
253     return (!(style & (CBS_OWNERDRAWFIXED | CBS_OWNERDRAWVARIABLE)) || (style & CBS_HASSTRINGS));
254 }
255
256 /* check whether a listbox expects strings or ids in LB_ADDSTRING/LB_INSERTSTRING */
257 inline static BOOL listbox_has_strings( HWND hwnd )
258 {
259     DWORD style = GetWindowLongA( hwnd, GWL_STYLE );
260     return (!(style & (LBS_OWNERDRAWFIXED | LBS_OWNERDRAWVARIABLE)) || (style & LBS_HASSTRINGS));
261 }
262
263 /* check if hwnd is a broadcast magic handle */
264 inline static BOOL is_broadcast( HWND hwnd )
265 {
266     return (hwnd == HWND_BROADCAST || hwnd == HWND_TOPMOST);
267 }
268
269
270 /***********************************************************************
271  *              broadcast_message_callback
272  *
273  * Helper callback for broadcasting messages.
274  */
275 static BOOL CALLBACK broadcast_message_callback( HWND hwnd, LPARAM lparam )
276 {
277     struct send_message_info *info = (struct send_message_info *)lparam;
278     if (!(GetWindowLongW( hwnd, GWL_STYLE ) & (WS_POPUP|WS_CAPTION))) return TRUE;
279     switch(info->type)
280     {
281     case MSG_UNICODE:
282         SendMessageTimeoutW( hwnd, info->msg, info->wparam, info->lparam,
283                              info->flags, info->timeout, NULL );
284         break;
285     case MSG_ASCII:
286         SendMessageTimeoutA( hwnd, info->msg, info->wparam, info->lparam,
287                              info->flags, info->timeout, NULL );
288         break;
289     case MSG_NOTIFY:
290         SendNotifyMessageW( hwnd, info->msg, info->wparam, info->lparam );
291         break;
292     case MSG_CALLBACK:
293         SendMessageCallbackW( hwnd, info->msg, info->wparam, info->lparam,
294                               info->callback, info->data );
295         break;
296     case MSG_POSTED:
297         PostMessageW( hwnd, info->msg, info->wparam, info->lparam );
298         break;
299     default:
300         ERR( "bad type %d\n", info->type );
301         break;
302     }
303     return TRUE;
304 }
305
306
307 /***********************************************************************
308  *              map_wparam_AtoW
309  *
310  * Convert the wparam of an ASCII message to Unicode.
311  */
312 static WPARAM map_wparam_AtoW( UINT message, WPARAM wparam )
313 {
314     if (message == WM_CHARTOITEM ||
315         message == EM_SETPASSWORDCHAR ||
316         message == WM_CHAR ||
317         message == WM_DEADCHAR ||
318         message == WM_SYSCHAR ||
319         message == WM_SYSDEADCHAR ||
320         message == WM_MENUCHAR)
321     {
322         char ch = LOWORD(wparam);
323         WCHAR wch;
324         MultiByteToWideChar(CP_ACP, 0, &ch, 1, &wch, 1);
325         wparam = MAKEWPARAM( wch, HIWORD(wparam) );
326     }
327     return wparam;
328 }
329
330
331 /***********************************************************************
332  *              map_wparam_WtoA
333  *
334  * Convert the wparam of a Unicode message to ASCII.
335  */
336 static WPARAM map_wparam_WtoA( UINT message, WPARAM wparam )
337 {
338     if (message == WM_CHARTOITEM ||
339         message == EM_SETPASSWORDCHAR ||
340         message == WM_CHAR ||
341         message == WM_DEADCHAR ||
342         message == WM_SYSCHAR ||
343         message == WM_SYSDEADCHAR ||
344         message == WM_MENUCHAR)
345     {
346         WCHAR wch = LOWORD(wparam);
347         char ch;
348         WideCharToMultiByte( CP_ACP, 0, &wch, 1, &ch, 1, NULL, NULL );
349         wparam = MAKEWPARAM( (unsigned char)ch, HIWORD(wparam) );
350     }
351     return wparam;
352 }
353
354
355 /***********************************************************************
356  *              pack_message
357  *
358  * Pack a message for sending to another process.
359  * Return the size of the data we expect in the message reply.
360  * Set data->count to -1 if there is an error.
361  */
362 static size_t pack_message( HWND hwnd, UINT message, WPARAM wparam, LPARAM lparam,
363                             struct packed_message *data )
364 {
365     data->count = 0;
366     switch(message)
367     {
368     case WM_NCCREATE:
369     case WM_CREATE:
370     {
371         CREATESTRUCTW *cs = (CREATESTRUCTW *)lparam;
372         push_data( data, cs, sizeof(*cs) );
373         if (HIWORD(cs->lpszName)) push_string( data, cs->lpszName );
374         if (HIWORD(cs->lpszClass)) push_string( data, cs->lpszClass );
375         return sizeof(*cs);
376     }
377     case WM_GETTEXT:
378     case WM_ASKCBFORMATNAME:
379         return wparam * sizeof(WCHAR);
380     case WM_SETTEXT:
381     case WM_WININICHANGE:
382     case WM_DEVMODECHANGE:
383     case CB_DIR:
384     case CB_FINDSTRING:
385     case CB_FINDSTRINGEXACT:
386     case CB_SELECTSTRING:
387     case LB_DIR:
388     case LB_ADDFILE:
389     case LB_FINDSTRING:
390     case LB_FINDSTRINGEXACT:
391     case LB_SELECTSTRING:
392     case EM_REPLACESEL:
393         push_string( data, (LPWSTR)lparam );
394         return 0;
395     case WM_GETMINMAXINFO:
396         push_data( data, (MINMAXINFO *)lparam, sizeof(MINMAXINFO) );
397         return sizeof(MINMAXINFO);
398     case WM_DRAWITEM:
399         push_data( data, (DRAWITEMSTRUCT *)lparam, sizeof(DRAWITEMSTRUCT) );
400         return 0;
401     case WM_MEASUREITEM:
402         push_data( data, (MEASUREITEMSTRUCT *)lparam, sizeof(MEASUREITEMSTRUCT) );
403         return sizeof(MEASUREITEMSTRUCT);
404     case WM_DELETEITEM:
405         push_data( data, (DELETEITEMSTRUCT *)lparam, sizeof(DELETEITEMSTRUCT) );
406         return 0;
407     case WM_COMPAREITEM:
408         push_data( data, (COMPAREITEMSTRUCT *)lparam, sizeof(COMPAREITEMSTRUCT) );
409         return 0;
410     case WM_WINDOWPOSCHANGING:
411     case WM_WINDOWPOSCHANGED:
412         push_data( data, (WINDOWPOS *)lparam, sizeof(WINDOWPOS) );
413         return sizeof(WINDOWPOS);
414     case WM_COPYDATA:
415     {
416         COPYDATASTRUCT *cp = (COPYDATASTRUCT *)lparam;
417         push_data( data, cp, sizeof(*cp) );
418         if (cp->lpData) push_data( data, cp->lpData, cp->cbData );
419         return 0;
420     }
421     case WM_NOTIFY:
422         /* WM_NOTIFY cannot be sent across processes (MSDN) */
423         data->count = -1;
424         return 0;
425     case WM_HELP:
426         push_data( data, (HELPINFO *)lparam, sizeof(HELPINFO) );
427         return 0;
428     case WM_STYLECHANGING:
429     case WM_STYLECHANGED:
430         push_data( data, (STYLESTRUCT *)lparam, sizeof(STYLESTRUCT) );
431         return 0;
432     case WM_NCCALCSIZE:
433         if (!wparam)
434         {
435             push_data( data, (RECT *)lparam, sizeof(RECT) );
436             return sizeof(RECT);
437         }
438         else
439         {
440             NCCALCSIZE_PARAMS *nc = (NCCALCSIZE_PARAMS *)lparam;
441             push_data( data, nc, sizeof(*nc) );
442             push_data( data, nc->lppos, sizeof(*nc->lppos) );
443             return sizeof(*nc) + sizeof(*nc->lppos);
444         }
445     case WM_GETDLGCODE:
446         if (lparam) push_data( data, (MSG *)lparam, sizeof(MSG) );
447         return sizeof(MSG);
448     case SBM_SETSCROLLINFO:
449         push_data( data, (SCROLLINFO *)lparam, sizeof(SCROLLINFO) );
450         return 0;
451     case SBM_GETSCROLLINFO:
452         push_data( data, (SCROLLINFO *)lparam, sizeof(SCROLLINFO) );
453         return sizeof(SCROLLINFO);
454     case EM_GETSEL:
455     case SBM_GETRANGE:
456     case CB_GETEDITSEL:
457     {
458         size_t size = 0;
459         if (wparam) size += sizeof(DWORD);
460         if (lparam) size += sizeof(DWORD);
461         return size;
462     }
463     case EM_GETRECT:
464     case LB_GETITEMRECT:
465     case CB_GETDROPPEDCONTROLRECT:
466         return sizeof(RECT);
467     case EM_SETRECT:
468     case EM_SETRECTNP:
469         push_data( data, (RECT *)lparam, sizeof(RECT) );
470         return 0;
471     case EM_GETLINE:
472     {
473         WORD *pw = (WORD *)lparam;
474         push_data( data, pw, sizeof(*pw) );
475         return *pw * sizeof(WCHAR);
476     }
477     case EM_SETTABSTOPS:
478     case LB_SETTABSTOPS:
479         if (wparam) push_data( data, (UINT *)lparam, sizeof(UINT) * wparam );
480         return 0;
481     case CB_ADDSTRING:
482     case CB_INSERTSTRING:
483         if (combobox_has_strings( hwnd )) push_string( data, (LPWSTR)lparam );
484         return 0;
485     case CB_GETLBTEXT:
486         if (!combobox_has_strings( hwnd )) return sizeof(ULONG_PTR);
487         return (SendMessageW( hwnd, CB_GETLBTEXTLEN, wparam, 0 ) + 1) * sizeof(WCHAR);
488     case LB_ADDSTRING:
489     case LB_INSERTSTRING:
490         if (listbox_has_strings( hwnd )) push_string( data, (LPWSTR)lparam );
491         return 0;
492     case LB_GETTEXT:
493         if (!listbox_has_strings( hwnd )) return sizeof(ULONG_PTR);
494         return (SendMessageW( hwnd, LB_GETTEXTLEN, wparam, 0 ) + 1) * sizeof(WCHAR);
495     case LB_GETSELITEMS:
496         return wparam * sizeof(UINT);
497     case WM_NEXTMENU:
498         push_data( data, (MDINEXTMENU *)lparam, sizeof(MDINEXTMENU) );
499         return sizeof(MDINEXTMENU);
500     case WM_SIZING:
501     case WM_MOVING:
502         push_data( data, (RECT *)lparam, sizeof(RECT) );
503         return sizeof(RECT);
504     case WM_MDICREATE:
505     {
506         MDICREATESTRUCTW *cs = (MDICREATESTRUCTW *)lparam;
507         push_data( data, cs, sizeof(*cs) );
508         if (HIWORD(cs->szTitle)) push_string( data, cs->szTitle );
509         if (HIWORD(cs->szClass)) push_string( data, cs->szClass );
510         return sizeof(*cs);
511     }
512     case WM_MDIGETACTIVE:
513         if (lparam) return sizeof(BOOL);
514         return 0;
515
516     case WM_WINE_SETWINDOWPOS:
517         push_data( data, (WINDOWPOS *)lparam, sizeof(WINDOWPOS) );
518         return 0;
519
520     /* these contain an HFONT */
521     case WM_SETFONT:
522     case WM_GETFONT:
523     /* these contain an HDC */
524     case WM_PAINT:
525     case WM_ERASEBKGND:
526     case WM_ICONERASEBKGND:
527     case WM_NCPAINT:
528     case WM_CTLCOLORMSGBOX:
529     case WM_CTLCOLOREDIT:
530     case WM_CTLCOLORLISTBOX:
531     case WM_CTLCOLORBTN:
532     case WM_CTLCOLORDLG:
533     case WM_CTLCOLORSCROLLBAR:
534     case WM_CTLCOLORSTATIC:
535     case WM_PRINT:
536     case WM_PRINTCLIENT:
537     /* these contain an HGLOBAL */
538     case WM_PAINTCLIPBOARD:
539     case WM_SIZECLIPBOARD:
540     case WM_DDE_INITIATE:
541     case WM_DDE_ADVISE:
542     case WM_DDE_UNADVISE:
543     case WM_DDE_DATA:
544     case WM_DDE_REQUEST:
545     case WM_DDE_POKE:
546     case WM_DDE_EXECUTE:
547     /* these contain pointers */
548     case WM_DROPOBJECT:
549     case WM_QUERYDROPOBJECT:
550     case WM_DRAGLOOP:
551     case WM_DRAGSELECT:
552     case WM_DRAGMOVE:
553     case WM_DEVICECHANGE:
554         FIXME( "msg %x (%s) not supported yet\n", message, SPY_GetMsgName(message, hwnd) );
555         data->count = -1;
556         return 0;
557     }
558     return 0;
559 }
560
561
562 /***********************************************************************
563  *              unpack_message
564  *
565  * Unpack a message received from another process.
566  */
567 static BOOL unpack_message( HWND hwnd, UINT message, WPARAM *wparam, LPARAM *lparam,
568                             void **buffer, size_t size )
569 {
570     size_t minsize = 0;
571
572     switch(message)
573     {
574     case WM_NCCREATE:
575     case WM_CREATE:
576     {
577         CREATESTRUCTW *cs = *buffer;
578         WCHAR *str = (WCHAR *)(cs + 1);
579         if (size < sizeof(*cs)) return FALSE;
580         size -= sizeof(*cs);
581         if (HIWORD(cs->lpszName))
582         {
583             if (!check_string( str, size )) return FALSE;
584             cs->lpszName = str;
585             size -= (strlenW(str) + 1) * sizeof(WCHAR);
586             str += strlenW(str) + 1;
587         }
588         if (HIWORD(cs->lpszClass))
589         {
590             if (!check_string( str, size )) return FALSE;
591             cs->lpszClass = str;
592         }
593         break;
594     }
595     case WM_GETTEXT:
596     case WM_ASKCBFORMATNAME:
597         if (!get_buffer_space( buffer, (*wparam * sizeof(WCHAR)) )) return FALSE;
598         break;
599     case WM_SETTEXT:
600     case WM_WININICHANGE:
601     case WM_DEVMODECHANGE:
602     case CB_DIR:
603     case CB_FINDSTRING:
604     case CB_FINDSTRINGEXACT:
605     case CB_SELECTSTRING:
606     case LB_DIR:
607     case LB_ADDFILE:
608     case LB_FINDSTRING:
609     case LB_FINDSTRINGEXACT:
610     case LB_SELECTSTRING:
611     case EM_REPLACESEL:
612         if (!check_string( *buffer, size )) return FALSE;
613         break;
614     case WM_GETMINMAXINFO:
615         minsize = sizeof(MINMAXINFO);
616         break;
617     case WM_DRAWITEM:
618         minsize = sizeof(DRAWITEMSTRUCT);
619         break;
620     case WM_MEASUREITEM:
621         minsize = sizeof(MEASUREITEMSTRUCT);
622         break;
623     case WM_DELETEITEM:
624         minsize = sizeof(DELETEITEMSTRUCT);
625         break;
626     case WM_COMPAREITEM:
627         minsize = sizeof(COMPAREITEMSTRUCT);
628         break;
629     case WM_WINDOWPOSCHANGING:
630     case WM_WINDOWPOSCHANGED:
631     case WM_WINE_SETWINDOWPOS:
632         minsize = sizeof(WINDOWPOS);
633         break;
634     case WM_COPYDATA:
635     {
636         COPYDATASTRUCT *cp = *buffer;
637         if (size < sizeof(*cp)) return FALSE;
638         if (cp->lpData)
639         {
640             minsize = sizeof(*cp) + cp->cbData;
641             cp->lpData = cp + 1;
642         }
643         break;
644     }
645     case WM_NOTIFY:
646         /* WM_NOTIFY cannot be sent across processes (MSDN) */
647         return FALSE;
648     case WM_HELP:
649         minsize = sizeof(HELPINFO);
650         break;
651     case WM_STYLECHANGING:
652     case WM_STYLECHANGED:
653         minsize = sizeof(STYLESTRUCT);
654         break;
655     case WM_NCCALCSIZE:
656         if (!*wparam) minsize = sizeof(RECT);
657         else
658         {
659             NCCALCSIZE_PARAMS *nc = *buffer;
660             if (size < sizeof(*nc) + sizeof(*nc->lppos)) return FALSE;
661             nc->lppos = (WINDOWPOS *)(nc + 1);
662         }
663         break;
664     case WM_GETDLGCODE:
665         if (!*lparam) return TRUE;
666         minsize = sizeof(MSG);
667         break;
668     case SBM_SETSCROLLINFO:
669         minsize = sizeof(SCROLLINFO);
670         break;
671     case SBM_GETSCROLLINFO:
672         if (!get_buffer_space( buffer, sizeof(SCROLLINFO ))) return FALSE;
673         break;
674     case EM_GETSEL:
675     case SBM_GETRANGE:
676     case CB_GETEDITSEL:
677         if (*wparam || *lparam)
678         {
679             if (!get_buffer_space( buffer, 2*sizeof(DWORD) )) return FALSE;
680             if (*wparam) *wparam = (WPARAM)*buffer;
681             if (*lparam) *lparam = (LPARAM)((DWORD *)*buffer + 1);
682         }
683         return TRUE;
684     case EM_GETRECT:
685     case LB_GETITEMRECT:
686     case CB_GETDROPPEDCONTROLRECT:
687         if (!get_buffer_space( buffer, sizeof(RECT) )) return FALSE;
688         break;
689     case EM_SETRECT:
690     case EM_SETRECTNP:
691         minsize = sizeof(RECT);
692         break;
693     case EM_GETLINE:
694     {
695         WORD len;
696         if (size < sizeof(WORD)) return FALSE;
697         len = *(WORD *)*buffer;
698         if (!get_buffer_space( buffer, (len + 1) * sizeof(WCHAR) )) return FALSE;
699         *lparam = (LPARAM)*buffer + sizeof(WORD);  /* don't erase WORD at start of buffer */
700         return TRUE;
701     }
702     case EM_SETTABSTOPS:
703     case LB_SETTABSTOPS:
704         if (!*wparam) return TRUE;
705         minsize = *wparam * sizeof(UINT);
706         break;
707     case CB_ADDSTRING:
708     case CB_INSERTSTRING:
709     case LB_ADDSTRING:
710     case LB_INSERTSTRING:
711         if (!*buffer) return TRUE;
712         if (!check_string( *buffer, size )) return FALSE;
713         break;
714     case CB_GETLBTEXT:
715     {
716         size = sizeof(ULONG_PTR);
717         if (combobox_has_strings( hwnd ))
718             size = (SendMessageW( hwnd, CB_GETLBTEXTLEN, *wparam, 0 ) + 1) * sizeof(WCHAR);
719         if (!get_buffer_space( buffer, size )) return FALSE;
720         break;
721     }
722     case LB_GETTEXT:
723     {
724         size = sizeof(ULONG_PTR);
725         if (listbox_has_strings( hwnd ))
726             size = (SendMessageW( hwnd, LB_GETTEXTLEN, *wparam, 0 ) + 1) * sizeof(WCHAR);
727         if (!get_buffer_space( buffer, size )) return FALSE;
728         break;
729     }
730     case LB_GETSELITEMS:
731         if (!get_buffer_space( buffer, *wparam * sizeof(UINT) )) return FALSE;
732         break;
733     case WM_NEXTMENU:
734         minsize = sizeof(MDINEXTMENU);
735         if (!get_buffer_space( buffer, sizeof(MDINEXTMENU) )) return FALSE;
736         break;
737     case WM_SIZING:
738     case WM_MOVING:
739         minsize = sizeof(RECT);
740         if (!get_buffer_space( buffer, sizeof(RECT) )) return FALSE;
741         break;
742     case WM_MDICREATE:
743     {
744         MDICREATESTRUCTW *cs = *buffer;
745         WCHAR *str = (WCHAR *)(cs + 1);
746         if (size < sizeof(*cs)) return FALSE;
747         size -= sizeof(*cs);
748         if (HIWORD(cs->szTitle))
749         {
750             if (!check_string( str, size )) return FALSE;
751             cs->szTitle = str;
752             size -= (strlenW(str) + 1) * sizeof(WCHAR);
753             str += strlenW(str) + 1;
754         }
755         if (HIWORD(cs->szClass))
756         {
757             if (!check_string( str, size )) return FALSE;
758             cs->szClass = str;
759         }
760         break;
761     }
762     case WM_MDIGETACTIVE:
763         if (!*lparam) return TRUE;
764         if (!get_buffer_space( buffer, sizeof(BOOL) )) return FALSE;
765         break;
766
767     /* these contain an HFONT */
768     case WM_SETFONT:
769     case WM_GETFONT:
770     /* these contain an HDC */
771     case WM_PAINT:
772     case WM_ERASEBKGND:
773     case WM_ICONERASEBKGND:
774     case WM_NCPAINT:
775     case WM_CTLCOLORMSGBOX:
776     case WM_CTLCOLOREDIT:
777     case WM_CTLCOLORLISTBOX:
778     case WM_CTLCOLORBTN:
779     case WM_CTLCOLORDLG:
780     case WM_CTLCOLORSCROLLBAR:
781     case WM_CTLCOLORSTATIC:
782     case WM_PRINT:
783     case WM_PRINTCLIENT:
784     /* these contain an HGLOBAL */
785     case WM_PAINTCLIPBOARD:
786     case WM_SIZECLIPBOARD:
787     case WM_DDE_INITIATE:
788     case WM_DDE_ADVISE:
789     case WM_DDE_UNADVISE:
790     case WM_DDE_DATA:
791     case WM_DDE_REQUEST:
792     case WM_DDE_POKE:
793     case WM_DDE_EXECUTE:
794     /* these contain pointers */
795     case WM_DROPOBJECT:
796     case WM_QUERYDROPOBJECT:
797     case WM_DRAGLOOP:
798     case WM_DRAGSELECT:
799     case WM_DRAGMOVE:
800     case WM_DEVICECHANGE:
801         FIXME( "msg %x (%s) not supported yet\n", message, SPY_GetMsgName(message, hwnd) );
802         return FALSE;
803
804     default:
805         return TRUE; /* message doesn't need any unpacking */
806     }
807
808     /* default exit for most messages: check minsize and store buffer in lparam */
809     if (size < minsize) return FALSE;
810     *lparam = (LPARAM)*buffer;
811     return TRUE;
812 }
813
814
815 /***********************************************************************
816  *              pack_reply
817  *
818  * Pack a reply to a message for sending to another process.
819  */
820 static void pack_reply( HWND hwnd, UINT message, WPARAM wparam, LPARAM lparam,
821                         LRESULT res, struct packed_message *data )
822 {
823     data->count = 0;
824     switch(message)
825     {
826     case WM_NCCREATE:
827     case WM_CREATE:
828         push_data( data, (CREATESTRUCTW *)lparam, sizeof(CREATESTRUCTW) );
829         break;
830     case WM_GETTEXT:
831     case CB_GETLBTEXT:
832     case LB_GETTEXT:
833         push_data( data, (WCHAR *)lparam, (res + 1) * sizeof(WCHAR) );
834         break;
835     case WM_GETMINMAXINFO:
836         push_data( data, (MINMAXINFO *)lparam, sizeof(MINMAXINFO) );
837         break;
838     case WM_MEASUREITEM:
839         push_data( data, (MEASUREITEMSTRUCT *)lparam, sizeof(MEASUREITEMSTRUCT) );
840         break;
841     case WM_WINDOWPOSCHANGING:
842     case WM_WINDOWPOSCHANGED:
843         push_data( data, (WINDOWPOS *)lparam, sizeof(WINDOWPOS) );
844         break;
845     case WM_GETDLGCODE:
846         if (lparam) push_data( data, (MSG *)lparam, sizeof(MSG) );
847         break;
848     case SBM_GETSCROLLINFO:
849         push_data( data, (SCROLLINFO *)lparam, sizeof(SCROLLINFO) );
850         break;
851     case EM_GETRECT:
852     case LB_GETITEMRECT:
853     case CB_GETDROPPEDCONTROLRECT:
854     case WM_SIZING:
855     case WM_MOVING:
856         push_data( data, (RECT *)lparam, sizeof(RECT) );
857         break;
858     case EM_GETLINE:
859     {
860         WORD *ptr = (WORD *)lparam;
861         push_data( data, ptr, ptr[-1] * sizeof(WCHAR) );
862         break;
863     }
864     case LB_GETSELITEMS:
865         push_data( data, (UINT *)lparam, wparam * sizeof(UINT) );
866         break;
867     case WM_MDIGETACTIVE:
868         if (lparam) push_data( data, (BOOL *)lparam, sizeof(BOOL) );
869         break;
870     case WM_NCCALCSIZE:
871         if (!wparam)
872             push_data( data, (RECT *)lparam, sizeof(RECT) );
873         else
874         {
875             NCCALCSIZE_PARAMS *nc = (NCCALCSIZE_PARAMS *)lparam;
876             push_data( data, nc, sizeof(*nc) );
877             push_data( data, nc->lppos, sizeof(*nc->lppos) );
878         }
879         break;
880     case EM_GETSEL:
881     case SBM_GETRANGE:
882     case CB_GETEDITSEL:
883         if (wparam) push_data( data, (DWORD *)wparam, sizeof(DWORD) );
884         if (lparam) push_data( data, (DWORD *)lparam, sizeof(DWORD) );
885         break;
886     case WM_NEXTMENU:
887         push_data( data, (MDINEXTMENU *)lparam, sizeof(MDINEXTMENU) );
888         break;
889     case WM_MDICREATE:
890         push_data( data, (MDICREATESTRUCTW *)lparam, sizeof(MDICREATESTRUCTW) );
891         break;
892     case WM_ASKCBFORMATNAME:
893         push_data( data, (WCHAR *)lparam, (strlenW((WCHAR *)lparam) + 1) * sizeof(WCHAR) );
894         break;
895     }
896 }
897
898
899 /***********************************************************************
900  *              unpack_reply
901  *
902  * Unpack a message reply received from another process.
903  */
904 static void unpack_reply( HWND hwnd, UINT message, WPARAM wparam, LPARAM lparam,
905                           void *buffer, size_t size )
906 {
907     switch(message)
908     {
909     case WM_NCCREATE:
910     case WM_CREATE:
911     {
912         CREATESTRUCTW *cs = (CREATESTRUCTW *)lparam;
913         LPCWSTR name = cs->lpszName, class = cs->lpszClass;
914         memcpy( cs, buffer, min( sizeof(*cs), size ));
915         cs->lpszName = name;  /* restore the original pointers */
916         cs->lpszClass = class;
917         break;
918     }
919     case WM_GETTEXT:
920     case WM_ASKCBFORMATNAME:
921         memcpy( (WCHAR *)lparam, buffer, min( wparam*sizeof(WCHAR), size ));
922         break;
923     case WM_GETMINMAXINFO:
924         memcpy( (MINMAXINFO *)lparam, buffer, min( sizeof(MINMAXINFO), size ));
925         break;
926     case WM_MEASUREITEM:
927         memcpy( (MEASUREITEMSTRUCT *)lparam, buffer, min( sizeof(MEASUREITEMSTRUCT), size ));
928         break;
929     case WM_WINDOWPOSCHANGING:
930     case WM_WINDOWPOSCHANGED:
931         memcpy( (WINDOWPOS *)lparam, buffer, min( sizeof(WINDOWPOS), size ));
932         break;
933     case WM_GETDLGCODE:
934         if (lparam) memcpy( (MSG *)lparam, buffer, min( sizeof(MSG), size ));
935         break;
936     case SBM_GETSCROLLINFO:
937         memcpy( (SCROLLINFO *)lparam, buffer, min( sizeof(SCROLLINFO), size ));
938         break;
939     case EM_GETRECT:
940     case CB_GETDROPPEDCONTROLRECT:
941     case LB_GETITEMRECT:
942     case WM_SIZING:
943     case WM_MOVING:
944         memcpy( (RECT *)lparam, buffer, min( sizeof(RECT), size ));
945         break;
946     case EM_GETLINE:
947         size = min( size, *(WORD *)lparam );
948         memcpy( (WCHAR *)lparam, buffer, size );
949         break;
950     case LB_GETSELITEMS:
951         memcpy( (UINT *)lparam, buffer, min( wparam*sizeof(UINT), size ));
952         break;
953     case LB_GETTEXT:
954     case CB_GETLBTEXT:
955         memcpy( (WCHAR *)lparam, buffer, size );
956         break;
957     case WM_NEXTMENU:
958         memcpy( (MDINEXTMENU *)lparam, buffer, min( sizeof(MDINEXTMENU), size ));
959         break;
960     case WM_MDIGETACTIVE:
961         if (lparam) memcpy( (BOOL *)lparam, buffer, min( sizeof(BOOL), size ));
962         break;
963     case WM_NCCALCSIZE:
964         if (!wparam)
965             memcpy( (RECT *)lparam, buffer, min( sizeof(RECT), size ));
966         else
967         {
968             NCCALCSIZE_PARAMS *nc = (NCCALCSIZE_PARAMS *)lparam;
969             WINDOWPOS *wp = nc->lppos;
970             memcpy( nc, buffer, min( sizeof(*nc), size ));
971             if (size > sizeof(*nc))
972             {
973                 size -= sizeof(*nc);
974                 memcpy( wp, (NCCALCSIZE_PARAMS*)buffer + 1, min( sizeof(*wp), size ));
975             }
976             nc->lppos = wp;  /* restore the original pointer */
977         }
978         break;
979     case EM_GETSEL:
980     case SBM_GETRANGE:
981     case CB_GETEDITSEL:
982         if (wparam)
983         {
984             memcpy( (DWORD *)wparam, buffer, min( sizeof(DWORD), size ));
985             if (size <= sizeof(DWORD)) break;
986             size -= sizeof(DWORD);
987             buffer = (DWORD *)buffer + 1;
988         }
989         if (lparam) memcpy( (DWORD *)lparam, buffer, min( sizeof(DWORD), size ));
990         break;
991     case WM_MDICREATE:
992     {
993         MDICREATESTRUCTW *cs = (MDICREATESTRUCTW *)lparam;
994         LPCWSTR title = cs->szTitle, class = cs->szClass;
995         memcpy( cs, buffer, min( sizeof(*cs), size ));
996         cs->szTitle = title;  /* restore the original pointers */
997         cs->szClass = class;
998         break;
999     }
1000     default:
1001         ERR( "should not happen: unexpected message %x\n", message );
1002         break;
1003     }
1004 }
1005
1006
1007 /***********************************************************************
1008  *           reply_message
1009  *
1010  * Send a reply to a sent message.
1011  */
1012 static void reply_message( struct received_message_info *info, LRESULT result, BOOL remove )
1013 {
1014     struct packed_message data;
1015     int i, replied = info->flags & ISMEX_REPLIED;
1016
1017     if (info->flags & ISMEX_NOTIFY) return;  /* notify messages don't get replies */
1018     if (!remove && replied) return;  /* replied already */
1019
1020     data.count = 0;
1021     info->flags |= ISMEX_REPLIED;
1022
1023     if (info->type == MSG_OTHER_PROCESS && !replied)
1024     {
1025         pack_reply( info->msg.hwnd, info->msg.message, info->msg.wParam,
1026                     info->msg.lParam, result, &data );
1027     }
1028
1029     SERVER_START_REQ( reply_message )
1030     {
1031         req->result = result;
1032         req->remove = remove;
1033         for (i = 0; i < data.count; i++) wine_server_add_data( req, data.data[i], data.size[i] );
1034         wine_server_call( req );
1035     }
1036     SERVER_END_REQ;
1037 }
1038
1039
1040 /***********************************************************************
1041  *           handle_internal_message
1042  *
1043  * Handle an internal Wine message instead of calling the window proc.
1044  */
1045 static LRESULT handle_internal_message( HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam )
1046 {
1047     if (hwnd == GetDesktopWindow()) return 0;
1048     switch(msg)
1049     {
1050     case WM_WINE_DESTROYWINDOW:
1051         return WIN_DestroyWindow( hwnd );
1052     case WM_WINE_SETWINDOWPOS:
1053         return USER_Driver.pSetWindowPos( (WINDOWPOS *)lparam );
1054     case WM_WINE_SHOWWINDOW:
1055         return ShowWindow( hwnd, wparam );
1056     case WM_WINE_SETPARENT:
1057         return (LRESULT)SetParent( hwnd, (HWND)wparam );
1058     case WM_WINE_SETWINDOWLONG:
1059         return (LRESULT)SetWindowLongW( hwnd, wparam, lparam );
1060     case WM_WINE_ENABLEWINDOW:
1061         return EnableWindow( hwnd, wparam );
1062     default:
1063         FIXME( "unknown internal message %x\n", msg );
1064         return 0;
1065     }
1066 }
1067
1068
1069 /***********************************************************************
1070  *           call_window_proc
1071  *
1072  * Call a window procedure and the corresponding hooks.
1073  */
1074 static LRESULT call_window_proc( HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam, BOOL unicode )
1075 {
1076     LRESULT result;
1077     WNDPROC winproc;
1078
1079     if (msg & 0x80000000) return handle_internal_message( hwnd, msg, wparam, lparam );
1080
1081     /* first the WH_CALLWNDPROC hook */
1082     if (HOOK_IsHooked( WH_CALLWNDPROC ))
1083     {
1084         CWPSTRUCT cwp;
1085         cwp.lParam  = lparam;
1086         cwp.wParam  = wparam;
1087         cwp.message = msg;
1088         cwp.hwnd    = WIN_GetFullHandle( hwnd );
1089         if (unicode) HOOK_CallHooksW( WH_CALLWNDPROC, HC_ACTION, 1, (LPARAM)&cwp );
1090         else HOOK_CallHooksA( WH_CALLWNDPROC, HC_ACTION, 1, (LPARAM)&cwp );
1091         lparam = cwp.lParam;
1092         wparam = cwp.wParam;
1093         msg    = cwp.message;
1094         hwnd   = cwp.hwnd;
1095     }
1096
1097     /* now call the window procedure */
1098     if (unicode)
1099     {
1100         if (!(winproc = (WNDPROC)GetWindowLongW( hwnd, GWL_WNDPROC ))) return 0;
1101         result = CallWindowProcW( winproc, hwnd, msg, wparam, lparam );
1102     }
1103     else
1104     {
1105         if (!(winproc = (WNDPROC)GetWindowLongA( hwnd, GWL_WNDPROC ))) return 0;
1106         result = CallWindowProcA( winproc, hwnd, msg, wparam, lparam );
1107     }
1108
1109     /* and finally the WH_CALLWNDPROCRET hook */
1110     if (HOOK_IsHooked( WH_CALLWNDPROCRET ))
1111     {
1112         CWPRETSTRUCT cwp;
1113         cwp.lResult = result;
1114         cwp.lParam  = lparam;
1115         cwp.wParam  = wparam;
1116         cwp.message = msg;
1117         cwp.hwnd    = WIN_GetFullHandle( hwnd );
1118         if (unicode) HOOK_CallHooksW( WH_CALLWNDPROCRET, HC_ACTION, 1, (LPARAM)&cwp );
1119         else HOOK_CallHooksA( WH_CALLWNDPROCRET, HC_ACTION, 1, (LPARAM)&cwp );
1120     }
1121     return result;
1122 }
1123
1124
1125 /***********************************************************************
1126  *           MSG_peek_message
1127  *
1128  * Peek for a message matching the given parameters. Return FALSE if none available.
1129  * All pending sent messages are processed before returning.
1130  */
1131 BOOL MSG_peek_message( MSG *msg, HWND hwnd, UINT first, UINT last, int flags )
1132 {
1133     LRESULT result;
1134     ULONG_PTR extra_info = 0;
1135     MESSAGEQUEUE *queue = QUEUE_Current();
1136     struct received_message_info info, *old_info;
1137
1138     if (!first && !last) last = ~0;
1139
1140     for (;;)
1141     {
1142         NTSTATUS res;
1143         void *buffer = NULL;
1144         size_t size = 0, buffer_size = 0;
1145
1146         do  /* loop while buffer is too small */
1147         {
1148             if (buffer_size && !(buffer = HeapAlloc( GetProcessHeap(), 0, buffer_size )))
1149                 return FALSE;
1150             SERVER_START_REQ( get_message )
1151             {
1152                 req->flags     = flags;
1153                 req->get_win   = hwnd;
1154                 req->get_first = first;
1155                 req->get_last  = last;
1156                 if (buffer_size) wine_server_set_reply( req, buffer, buffer_size );
1157                 if (!(res = wine_server_call( req )))
1158                 {
1159                     size = wine_server_reply_size( reply );
1160                     info.type        = reply->type;
1161                     info.msg.hwnd    = reply->win;
1162                     info.msg.message = reply->msg;
1163                     info.msg.wParam  = reply->wparam;
1164                     info.msg.lParam  = reply->lparam;
1165                     info.msg.time    = reply->time;
1166                     info.msg.pt.x    = reply->x;
1167                     info.msg.pt.y    = reply->y;
1168                     extra_info       = reply->info;
1169                 }
1170                 else
1171                 {
1172                     if (buffer) HeapFree( GetProcessHeap(), 0, buffer );
1173                     buffer_size = reply->total;
1174                 }
1175             }
1176             SERVER_END_REQ;
1177         } while (res == STATUS_BUFFER_OVERFLOW);
1178
1179         if (res) return FALSE;
1180
1181         TRACE( "got type %d msg %x hwnd %x wp %x lp %lx\n",
1182                info.type, info.msg.message, info.msg.hwnd, info.msg.wParam, info.msg.lParam );
1183
1184         switch(info.type)
1185         {
1186         case MSG_ASCII:
1187         case MSG_UNICODE:
1188             info.flags = ISMEX_SEND;
1189             break;
1190         case MSG_NOTIFY:
1191             info.flags = ISMEX_NOTIFY;
1192             break;
1193         case MSG_CALLBACK:
1194             info.flags = ISMEX_CALLBACK;
1195             break;
1196         case MSG_OTHER_PROCESS:
1197             info.flags = ISMEX_SEND;
1198             if (!unpack_message( info.msg.hwnd, info.msg.message, &info.msg.wParam,
1199                                  &info.msg.lParam, &buffer, size ))
1200             {
1201                 ERR( "invalid packed message %x (%s) hwnd %x wp %x lp %lx size %d\n",
1202                      info.msg.message, SPY_GetMsgName(info.msg.message, info.msg.hwnd), info.msg.hwnd,
1203                      info.msg.wParam, info.msg.lParam, size );
1204                 /* ignore it */
1205                 reply_message( &info, 0, TRUE );
1206                 goto next;
1207             }
1208             break;
1209         case MSG_HARDWARE_RAW:
1210             if (!MSG_process_raw_hardware_message( &info.msg, extra_info,
1211                                                    hwnd, first, last, flags & GET_MSG_REMOVE ))
1212                 goto next;
1213             /* fall through */
1214         case MSG_HARDWARE_COOKED:
1215             if (!MSG_process_cooked_hardware_message( &info.msg, extra_info,
1216                                                       flags & GET_MSG_REMOVE ))
1217             {
1218                 flags |= GET_MSG_REMOVE_LAST;
1219                 goto next;
1220             }
1221             queue->GetMessagePosVal = MAKELONG( info.msg.pt.x, info.msg.pt.y );
1222             /* fall through */
1223         case MSG_POSTED:
1224             queue->GetMessageExtraInfoVal = extra_info;
1225             *msg = info.msg;
1226             if (buffer) HeapFree( GetProcessHeap(), 0, buffer );
1227             return TRUE;
1228         }
1229
1230         /* if we get here, we have a sent message; call the window procedure */
1231         old_info = queue->receive_info;
1232         queue->receive_info = &info;
1233         result = call_window_proc( info.msg.hwnd, info.msg.message, info.msg.wParam,
1234                                    info.msg.lParam, (info.type != MSG_ASCII) );
1235         reply_message( &info, result, TRUE );
1236         queue->receive_info = old_info;
1237     next:
1238         if (buffer) HeapFree( GetProcessHeap(), 0, buffer );
1239     }
1240 }
1241
1242
1243 /***********************************************************************
1244  *           wait_message_reply
1245  *
1246  * Wait until a sent message gets replied to.
1247  */
1248 static void wait_message_reply( UINT flags )
1249 {
1250     MESSAGEQUEUE *queue;
1251
1252     if (!(queue = QUEUE_Current())) return;
1253
1254     for (;;)
1255     {
1256         unsigned int wake_bits = 0, changed_bits = 0;
1257         DWORD dwlc, res;
1258
1259         SERVER_START_REQ( set_queue_mask )
1260         {
1261             req->wake_mask    = (flags & SMTO_BLOCK) ? 0 : QS_SENDMESSAGE;
1262             req->changed_mask = QS_SMRESULT | req->wake_mask;
1263             req->skip_wait    = 1;
1264             if (!wine_server_call( req ))
1265             {
1266                 wake_bits    = reply->wake_bits;
1267                 changed_bits = reply->changed_bits;
1268             }
1269         }
1270         SERVER_END_REQ;
1271
1272         if (changed_bits & QS_SMRESULT) return;  /* got a result */
1273         if (wake_bits & QS_SENDMESSAGE)
1274         {
1275             /* Process the sent message immediately */
1276             MSG msg;
1277             MSG_peek_message( &msg, 0, 0, 0, GET_MSG_REMOVE | GET_MSG_SENT_ONLY );
1278             continue;
1279         }
1280
1281         /* now wait for it */
1282
1283         ReleaseThunkLock( &dwlc );
1284
1285         if (USER_Driver.pMsgWaitForMultipleObjectsEx)
1286             res = USER_Driver.pMsgWaitForMultipleObjectsEx( 1, &queue->server_queue,
1287                                                             INFINITE, 0, 0 );
1288         else
1289             res = WaitForSingleObject( queue->server_queue, INFINITE );
1290
1291         if (dwlc) RestoreThunkLock( dwlc );
1292     }
1293 }
1294
1295 /***********************************************************************
1296  *              put_message_in_queue
1297  *
1298  * Put a sent message into the destination queue.
1299  * For inter-process message, reply_size is set to expected size of reply data.
1300  */
1301 static BOOL put_message_in_queue( DWORD dest_tid, const struct send_message_info *info,
1302                                   size_t *reply_size )
1303 {
1304     struct packed_message data;
1305     unsigned int res;
1306     int i, timeout = -1;
1307
1308     if (info->type != MSG_NOTIFY &&
1309         info->type != MSG_CALLBACK &&
1310         info->type != MSG_POSTED &&
1311         info->timeout != INFINITE)
1312         timeout = info->timeout;
1313
1314     data.count = 0;
1315     if (info->type == MSG_OTHER_PROCESS)
1316     {
1317         *reply_size = pack_message( info->hwnd, info->msg, info->wparam, info->lparam, &data );
1318         if (data.count == -1)
1319         {
1320             WARN( "cannot pack message %x\n", info->msg );
1321             return FALSE;
1322         }
1323     }
1324
1325     SERVER_START_REQ( send_message )
1326     {
1327         req->id      = (void *)dest_tid;
1328         req->type    = info->type;
1329         req->win     = info->hwnd;
1330         req->msg     = info->msg;
1331         req->wparam  = info->wparam;
1332         req->lparam  = info->lparam;
1333         req->time    = GetCurrentTime();
1334         req->timeout = timeout;
1335         for (i = 0; i < data.count; i++) wine_server_add_data( req, data.data[i], data.size[i] );
1336         if ((res = wine_server_call( req )))
1337         {
1338             if (res == STATUS_INVALID_PARAMETER)
1339                 /* FIXME: find a STATUS_ value for this one */
1340                 SetLastError( ERROR_INVALID_THREAD_ID );
1341             else
1342                 SetLastError( RtlNtStatusToDosError(res) );
1343         }
1344     }
1345     SERVER_END_REQ;
1346     return !res;
1347 }
1348
1349
1350 /***********************************************************************
1351  *              retrieve_reply
1352  *
1353  * Retrieve a message reply from the server.
1354  */
1355 static LRESULT retrieve_reply( const struct send_message_info *info,
1356                                size_t reply_size, LRESULT *result )
1357 {
1358     NTSTATUS status;
1359     void *reply_data = NULL;
1360
1361     if (reply_size)
1362     {
1363         if (!(reply_data = HeapAlloc( GetProcessHeap(), 0, reply_size )))
1364         {
1365             WARN( "no memory for reply %d bytes, will be truncated\n", reply_size );
1366             reply_size = 0;
1367         }
1368     }
1369     SERVER_START_REQ( get_message_reply )
1370     {
1371         req->cancel = 1;
1372         if (reply_size) wine_server_set_reply( req, reply_data, reply_size );
1373         if (!(status = wine_server_call( req ))) *result = reply->result;
1374         reply_size = wine_server_reply_size( reply );
1375     }
1376     SERVER_END_REQ;
1377     if (!status && reply_size)
1378         unpack_reply( info->hwnd, info->msg, info->wparam, info->lparam, reply_data, reply_size );
1379
1380     if (reply_data) HeapFree( GetProcessHeap(), 0, reply_data );
1381
1382     TRACE( "hwnd %x msg %x (%s) wp %x lp %lx got reply %lx (err=%ld)\n",
1383            info->hwnd, info->msg, SPY_GetMsgName(info->msg, info->hwnd), info->wparam,
1384            info->lparam, *result, status );
1385
1386     if (!status) return 1;
1387     if (status == STATUS_TIMEOUT) SetLastError(0);  /* timeout */
1388     else SetLastError( RtlNtStatusToDosError(status) );
1389     return 0;
1390 }
1391
1392
1393 /***********************************************************************
1394  *              send_inter_thread_message
1395  */
1396 static LRESULT send_inter_thread_message( DWORD dest_tid, const struct send_message_info *info,
1397                                           LRESULT *res_ptr )
1398 {
1399     LRESULT ret;
1400     int locks;
1401     size_t reply_size = 0;
1402
1403     TRACE( "hwnd %x msg %x (%s) wp %x lp %lx\n",
1404            info->hwnd, info->msg, SPY_GetMsgName(info->msg, info->hwnd), info->wparam, info->lparam );
1405
1406     if (!put_message_in_queue( dest_tid, info, &reply_size )) return 0;
1407
1408     /* there's no reply to wait for on notify/callback messages */
1409     if (info->type == MSG_NOTIFY || info->type == MSG_CALLBACK) return 1;
1410
1411     locks = WIN_SuspendWndsLock();
1412
1413     wait_message_reply( info->flags );
1414     ret = retrieve_reply( info, reply_size, res_ptr );
1415
1416     WIN_RestoreWndsLock( locks );
1417     return ret;
1418 }
1419
1420
1421 /***********************************************************************
1422  *              SendMessageTimeoutW  (USER32.@)
1423  */
1424 LRESULT WINAPI SendMessageTimeoutW( HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam,
1425                                     UINT flags, UINT timeout, LPDWORD res_ptr )
1426 {
1427     struct send_message_info info;
1428     DWORD dest_tid, dest_pid;
1429     LRESULT ret, result;
1430
1431     info.type    = MSG_UNICODE;
1432     info.hwnd    = hwnd;
1433     info.msg     = msg;
1434     info.wparam  = wparam;
1435     info.lparam  = lparam;
1436     info.flags   = flags;
1437     info.timeout = timeout;
1438
1439     if (is_broadcast(hwnd))
1440     {
1441         EnumWindows( broadcast_message_callback, (LPARAM)&info );
1442         if (res_ptr) *res_ptr = 1;
1443         return 1;
1444     }
1445
1446     if (!(dest_tid = GetWindowThreadProcessId( hwnd, &dest_pid ))) return 0;
1447
1448     if (USER_IsExitingThread( dest_tid )) return 0;
1449
1450     SPY_EnterMessage( SPY_SENDMESSAGE, hwnd, msg, wparam, lparam );
1451
1452     if (dest_tid == GetCurrentThreadId())
1453     {
1454         result = call_window_proc( hwnd, msg, wparam, lparam, TRUE );
1455         ret = 1;
1456     }
1457     else
1458     {
1459         if (dest_pid != GetCurrentProcessId()) info.type = MSG_OTHER_PROCESS;
1460         ret = send_inter_thread_message( dest_tid, &info, &result );
1461     }
1462
1463     SPY_ExitMessage( SPY_RESULT_OK, hwnd, msg, result, wparam, lparam );
1464     if (ret && res_ptr) *res_ptr = result;
1465     return ret;
1466 }
1467
1468
1469 /***********************************************************************
1470  *              SendMessageTimeoutA  (USER32.@)
1471  */
1472 LRESULT WINAPI SendMessageTimeoutA( HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam,
1473                                     UINT flags, UINT timeout, LPDWORD res_ptr )
1474 {
1475     struct send_message_info info;
1476     DWORD dest_tid, dest_pid;
1477     LRESULT ret, result;
1478
1479     info.type    = MSG_ASCII;
1480     info.hwnd    = hwnd;
1481     info.msg     = msg;
1482     info.wparam  = wparam;
1483     info.lparam  = lparam;
1484     info.flags   = flags;
1485     info.timeout = timeout;
1486
1487     if (is_broadcast(hwnd))
1488     {
1489         EnumWindows( broadcast_message_callback, (LPARAM)&info );
1490         if (res_ptr) *res_ptr = 1;
1491         return 1;
1492     }
1493
1494     if (!(dest_tid = GetWindowThreadProcessId( hwnd, &dest_pid ))) return 0;
1495
1496     if (USER_IsExitingThread( dest_tid )) return 0;
1497
1498     SPY_EnterMessage( SPY_SENDMESSAGE, hwnd, msg, wparam, lparam );
1499
1500     if (dest_tid == GetCurrentThreadId())
1501     {
1502         result = call_window_proc( hwnd, msg, wparam, lparam, FALSE );
1503         ret = 1;
1504     }
1505     else if (dest_pid == GetCurrentProcessId())
1506     {
1507         ret = send_inter_thread_message( dest_tid, &info, &result );
1508     }
1509     else
1510     {
1511         /* inter-process message: need to map to Unicode */
1512         info.type = MSG_OTHER_PROCESS;
1513         if (is_unicode_message( info.msg ))
1514         {
1515             if (WINPROC_MapMsg32ATo32W( info.hwnd, info.msg, &info.wparam, &info.lparam ) == -1)
1516                 return 0;
1517             ret = send_inter_thread_message( dest_tid, &info, &result );
1518             result = WINPROC_UnmapMsg32ATo32W( info.hwnd, info.msg, info.wparam,
1519                                                info.lparam, result );
1520         }
1521         else ret = send_inter_thread_message( dest_tid, &info, &result );
1522     }
1523     SPY_ExitMessage( SPY_RESULT_OK, hwnd, msg, result, wparam, lparam );
1524     if (ret && res_ptr) *res_ptr = result;
1525     return ret;
1526 }
1527
1528
1529 /***********************************************************************
1530  *              SendMessageW  (USER32.@)
1531  */
1532 LRESULT WINAPI SendMessageW( HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam )
1533 {
1534     LRESULT res = 0;
1535     SendMessageTimeoutW( hwnd, msg, wparam, lparam, SMTO_NORMAL, INFINITE, &res );
1536     return res;
1537 }
1538
1539
1540 /***********************************************************************
1541  *              SendMessageA  (USER32.@)
1542  */
1543 LRESULT WINAPI SendMessageA( HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam )
1544 {
1545     LRESULT res = 0;
1546     SendMessageTimeoutA( hwnd, msg, wparam, lparam, SMTO_NORMAL, INFINITE, &res );
1547     return res;
1548 }
1549
1550
1551 /***********************************************************************
1552  *              SendNotifyMessageA  (USER32.@)
1553  */
1554 BOOL WINAPI SendNotifyMessageA( HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam )
1555 {
1556     return SendNotifyMessageW( hwnd, msg, map_wparam_AtoW( msg, wparam ), lparam );
1557 }
1558
1559
1560 /***********************************************************************
1561  *              SendNotifyMessageW  (USER32.@)
1562  */
1563 BOOL WINAPI SendNotifyMessageW( HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam )
1564 {
1565     struct send_message_info info;
1566     DWORD dest_tid;
1567     LRESULT result;
1568
1569     if (is_pointer_message(msg))
1570     {
1571         SetLastError(ERROR_INVALID_PARAMETER);
1572         return FALSE;
1573     }
1574
1575     info.type    = MSG_NOTIFY;
1576     info.hwnd    = hwnd;
1577     info.msg     = msg;
1578     info.wparam  = wparam;
1579     info.lparam  = lparam;
1580
1581     if (is_broadcast(hwnd))
1582     {
1583         EnumWindows( broadcast_message_callback, (LPARAM)&info );
1584         return TRUE;
1585     }
1586
1587     if (!(dest_tid = GetWindowThreadProcessId( hwnd, NULL ))) return FALSE;
1588
1589     if (USER_IsExitingThread( dest_tid )) return TRUE;
1590
1591     if (dest_tid == GetCurrentThreadId())
1592     {
1593         call_window_proc( hwnd, msg, wparam, lparam, TRUE );
1594         return TRUE;
1595     }
1596     return send_inter_thread_message( dest_tid, &info, &result );
1597 }
1598
1599
1600 /***********************************************************************
1601  *              SendMessageCallbackA  (USER32.@)
1602  */
1603 BOOL WINAPI SendMessageCallbackA( HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam,
1604                                   SENDASYNCPROC callback, ULONG_PTR data )
1605 {
1606     return SendMessageCallbackW( hwnd, msg, map_wparam_AtoW( msg, wparam ),
1607                                  lparam, callback, data );
1608 }
1609
1610
1611 /***********************************************************************
1612  *              SendMessageCallbackW  (USER32.@)
1613  */
1614 BOOL WINAPI SendMessageCallbackW( HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam,
1615                                   SENDASYNCPROC callback, ULONG_PTR data )
1616 {
1617     struct send_message_info info;
1618     LRESULT result;
1619     DWORD dest_tid;
1620
1621     if (is_pointer_message(msg))
1622     {
1623         SetLastError(ERROR_INVALID_PARAMETER);
1624         return FALSE;
1625     }
1626
1627     info.type     = MSG_CALLBACK;
1628     info.hwnd     = hwnd;
1629     info.msg      = msg;
1630     info.wparam   = wparam;
1631     info.lparam   = lparam;
1632     info.callback = callback;
1633     info.data     = data;
1634
1635     if (is_broadcast(hwnd))
1636     {
1637         EnumWindows( broadcast_message_callback, (LPARAM)&info );
1638         return TRUE;
1639     }
1640
1641     if (!(dest_tid = GetWindowThreadProcessId( hwnd, NULL ))) return FALSE;
1642
1643     if (USER_IsExitingThread( dest_tid )) return TRUE;
1644
1645     if (dest_tid == GetCurrentThreadId())
1646     {
1647         result = call_window_proc( hwnd, msg, wparam, lparam, TRUE );
1648         callback( hwnd, msg, data, result );
1649         return TRUE;
1650     }
1651     FIXME( "callback will not be called\n" );
1652     return send_inter_thread_message( dest_tid, &info, &result );
1653 }
1654
1655
1656 /***********************************************************************
1657  *              ReplyMessage  (USER32.@)
1658  */
1659 BOOL WINAPI ReplyMessage( LRESULT result )
1660 {
1661     MESSAGEQUEUE *queue = QUEUE_Current();
1662     struct received_message_info *info = queue->receive_info;
1663
1664     if (!info) return FALSE;
1665     reply_message( info, result, FALSE );
1666     return TRUE;
1667 }
1668
1669
1670 /***********************************************************************
1671  *              InSendMessage  (USER32.@)
1672  */
1673 BOOL WINAPI InSendMessage(void)
1674 {
1675     return (InSendMessageEx(NULL) & (ISMEX_SEND|ISMEX_REPLIED)) == ISMEX_SEND;
1676 }
1677
1678
1679 /***********************************************************************
1680  *              InSendMessageEx  (USER32.@)
1681  */
1682 DWORD WINAPI InSendMessageEx( LPVOID reserved )
1683 {
1684     MESSAGEQUEUE *queue = QUEUE_Current();
1685     struct received_message_info *info = queue->receive_info;
1686
1687     if (info) return info->flags;
1688     return ISMEX_NOSEND;
1689 }
1690
1691
1692 /***********************************************************************
1693  *              PostMessageA  (USER32.@)
1694  */
1695 BOOL WINAPI PostMessageA( HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam )
1696 {
1697     return PostMessageW( hwnd, msg, map_wparam_AtoW( msg, wparam ), lparam );
1698 }
1699
1700
1701 /***********************************************************************
1702  *              PostMessageW  (USER32.@)
1703  */
1704 BOOL WINAPI PostMessageW( HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam )
1705 {
1706     struct send_message_info info;
1707     DWORD dest_tid;
1708
1709     if (is_pointer_message( msg ))
1710     {
1711         SetLastError( ERROR_INVALID_PARAMETER );
1712         return FALSE;
1713     }
1714
1715     info.type   = MSG_POSTED;
1716     info.hwnd   = hwnd;
1717     info.msg    = msg;
1718     info.wparam = wparam;
1719     info.lparam = lparam;
1720
1721     if (is_broadcast(hwnd))
1722     {
1723         EnumWindows( broadcast_message_callback, (LPARAM)&info );
1724         return TRUE;
1725     }
1726     if (!(dest_tid = GetWindowThreadProcessId( hwnd, NULL ))) return FALSE;
1727
1728     if (USER_IsExitingThread( dest_tid )) return TRUE;
1729
1730     return put_message_in_queue( dest_tid, &info, NULL );
1731 }
1732
1733
1734 /**********************************************************************
1735  *              PostThreadMessageA  (USER32.@)
1736  */
1737 BOOL WINAPI PostThreadMessageA( DWORD thread, UINT msg, WPARAM wparam, LPARAM lparam )
1738 {
1739     return PostThreadMessageW( thread, msg, map_wparam_AtoW( msg, wparam ), lparam );
1740 }
1741
1742
1743 /**********************************************************************
1744  *              PostThreadMessageW  (USER32.@)
1745  */
1746 BOOL WINAPI PostThreadMessageW( DWORD thread, UINT msg, WPARAM wparam, LPARAM lparam )
1747 {
1748     struct send_message_info info;
1749
1750     if (is_pointer_message( msg ))
1751     {
1752         SetLastError( ERROR_INVALID_PARAMETER );
1753         return FALSE;
1754     }
1755     if (USER_IsExitingThread( thread )) return TRUE;
1756
1757     info.type   = MSG_POSTED;
1758     info.hwnd   = 0;
1759     info.msg    = msg;
1760     info.wparam = wparam;
1761     info.lparam = lparam;
1762     return put_message_in_queue( thread, &info, NULL );
1763 }
1764
1765
1766 /***********************************************************************
1767  *              PostQuitMessage  (USER32.@)
1768  */
1769 void WINAPI PostQuitMessage( INT exitCode )
1770 {
1771     PostThreadMessageW( GetCurrentThreadId(), WM_QUIT, exitCode, 0 );
1772 }
1773
1774
1775 /***********************************************************************
1776  *              PeekMessageW  (USER32.@)
1777  */
1778 BOOL WINAPI PeekMessageW( MSG *msg_out, HWND hwnd, UINT first, UINT last, UINT flags )
1779 {
1780     MESSAGEQUEUE *queue;
1781     MSG msg;
1782     int locks;
1783
1784     /* check for graphics events */
1785     if (USER_Driver.pMsgWaitForMultipleObjectsEx)
1786         USER_Driver.pMsgWaitForMultipleObjectsEx( 0, NULL, 0, 0, 0 );
1787
1788     hwnd = WIN_GetFullHandle( hwnd );
1789     locks = WIN_SuspendWndsLock();
1790
1791     if (!MSG_peek_message( &msg, hwnd, first, last,
1792                            (flags & PM_REMOVE) ? GET_MSG_REMOVE : 0 ))
1793     {
1794         /* FIXME: should be done before checking for hw events */
1795         MSG_JournalPlayBackMsg();
1796
1797         if (!(flags & PM_NOYIELD))
1798         {
1799             DWORD count;
1800             ReleaseThunkLock(&count);
1801             if (count) RestoreThunkLock(count);
1802         }
1803         WIN_RestoreWndsLock( locks );
1804         return FALSE;
1805     }
1806
1807     WIN_RestoreWndsLock( locks );
1808
1809     /* need to fill the window handle for WM_PAINT message */
1810     if (msg.message == WM_PAINT)
1811     {
1812         if (IsIconic( msg.hwnd ) && GetClassLongA( msg.hwnd, GCL_HICON ))
1813         {
1814             msg.message = WM_PAINTICON;
1815             msg.wParam = 1;
1816         }
1817         /* clear internal paint flag */
1818         RedrawWindow( msg.hwnd, NULL, 0, RDW_NOINTERNALPAINT | RDW_NOCHILDREN );
1819     }
1820
1821     if ((queue = QUEUE_Current()))
1822     {
1823         queue->GetMessageTimeVal = msg.time;
1824         msg.pt.x = LOWORD( queue->GetMessagePosVal );
1825         msg.pt.y = HIWORD( queue->GetMessagePosVal );
1826     }
1827
1828     HOOK_CallHooksW( WH_GETMESSAGE, HC_ACTION, flags & PM_REMOVE, (LPARAM)&msg );
1829
1830     /* copy back our internal safe copy of message data to msg_out.
1831      * msg_out is a variable from the *program*, so it can't be used
1832      * internally as it can get "corrupted" by our use of SendMessage()
1833      * (back to the program) inside the message handling itself. */
1834     *msg_out = msg;
1835     return TRUE;
1836 }
1837
1838
1839 /***********************************************************************
1840  *              PeekMessageA  (USER32.@)
1841  */
1842 BOOL WINAPI PeekMessageA( MSG *msg, HWND hwnd, UINT first, UINT last, UINT flags )
1843 {
1844     BOOL ret = PeekMessageW( msg, hwnd, first, last, flags );
1845     if (ret) msg->wParam = map_wparam_WtoA( msg->message, msg->wParam );
1846     return ret;
1847 }
1848
1849
1850 /***********************************************************************
1851  *              GetMessageW  (USER32.@)
1852  */
1853 BOOL WINAPI GetMessageW( MSG *msg, HWND hwnd, UINT first, UINT last )
1854 {
1855     MESSAGEQUEUE *queue = QUEUE_Current();
1856     int mask, locks;
1857
1858     mask = QS_POSTMESSAGE | QS_SENDMESSAGE;  /* Always selected */
1859     if (first || last)
1860     {
1861         if ((first <= WM_KEYLAST) && (last >= WM_KEYFIRST)) mask |= QS_KEY;
1862         if ( ((first <= WM_MOUSELAST) && (last >= WM_MOUSEFIRST)) ||
1863              ((first <= WM_NCMOUSELAST) && (last >= WM_NCMOUSEFIRST)) ) mask |= QS_MOUSE;
1864         if ((first <= WM_TIMER) && (last >= WM_TIMER)) mask |= QS_TIMER;
1865         if ((first <= WM_SYSTIMER) && (last >= WM_SYSTIMER)) mask |= QS_TIMER;
1866         if ((first <= WM_PAINT) && (last >= WM_PAINT)) mask |= QS_PAINT;
1867     }
1868     else mask |= QS_MOUSE | QS_KEY | QS_TIMER | QS_PAINT;
1869
1870     locks = WIN_SuspendWndsLock();
1871
1872     while (!PeekMessageW( msg, hwnd, first, last, PM_REMOVE ))
1873     {
1874         /* wait until one of the bits is set */
1875         unsigned int wake_bits = 0, changed_bits = 0;
1876         DWORD dwlc;
1877
1878         SERVER_START_REQ( set_queue_mask )
1879         {
1880             req->wake_mask    = QS_SENDMESSAGE;
1881             req->changed_mask = mask;
1882             req->skip_wait    = 1;
1883             if (!wine_server_call( req ))
1884             {
1885                 wake_bits    = reply->wake_bits;
1886                 changed_bits = reply->changed_bits;
1887             }
1888         }
1889         SERVER_END_REQ;
1890
1891         if (changed_bits & mask) continue;
1892         if (wake_bits & QS_SENDMESSAGE) continue;
1893
1894         TRACE( "(%04x) mask=%08x, bits=%08x, changed=%08x, waiting\n",
1895                queue->self, mask, wake_bits, changed_bits );
1896
1897         ReleaseThunkLock( &dwlc );
1898         if (USER_Driver.pMsgWaitForMultipleObjectsEx)
1899             USER_Driver.pMsgWaitForMultipleObjectsEx( 1, &queue->server_queue, INFINITE, 0, 0 );
1900         else
1901             WaitForSingleObject( queue->server_queue, INFINITE );
1902         if (dwlc) RestoreThunkLock( dwlc );
1903     }
1904
1905     WIN_RestoreWndsLock( locks );
1906
1907     return (msg->message != WM_QUIT);
1908 }
1909
1910
1911 /***********************************************************************
1912  *              GetMessageA  (USER32.@)
1913  */
1914 BOOL WINAPI GetMessageA( MSG *msg, HWND hwnd, UINT first, UINT last )
1915 {
1916     GetMessageW( msg, hwnd, first, last );
1917     msg->wParam = map_wparam_WtoA( msg->message, msg->wParam );
1918     return (msg->message != WM_QUIT);
1919 }
1920
1921
1922 /***********************************************************************
1923  *              SetMessageQueue (USER32.@)
1924  */
1925 BOOL WINAPI SetMessageQueue( INT size )
1926 {
1927     /* now obsolete the message queue will be expanded dynamically as necessary */
1928     return TRUE;
1929 }