Implemented interprocess DDE message posting.
[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     case WM_WINE_SETWINDOWPOS:
516         push_data( data, (WINDOWPOS *)lparam, sizeof(WINDOWPOS) );
517         return 0;
518
519     /* these contain an HFONT */
520     case WM_SETFONT:
521     case WM_GETFONT:
522     /* these contain an HDC */
523     case WM_PAINT:
524     case WM_ERASEBKGND:
525     case WM_ICONERASEBKGND:
526     case WM_NCPAINT:
527     case WM_CTLCOLORMSGBOX:
528     case WM_CTLCOLOREDIT:
529     case WM_CTLCOLORLISTBOX:
530     case WM_CTLCOLORBTN:
531     case WM_CTLCOLORDLG:
532     case WM_CTLCOLORSCROLLBAR:
533     case WM_CTLCOLORSTATIC:
534     case WM_PRINT:
535     case WM_PRINTCLIENT:
536     /* these contain an HGLOBAL */
537     case WM_PAINTCLIPBOARD:
538     case WM_SIZECLIPBOARD:
539     /* these contain pointers */
540     case WM_DROPOBJECT:
541     case WM_QUERYDROPOBJECT:
542     case WM_DRAGLOOP:
543     case WM_DRAGSELECT:
544     case WM_DRAGMOVE:
545     case WM_DEVICECHANGE:
546         FIXME( "msg %x (%s) not supported yet\n", message, SPY_GetMsgName(message, hwnd) );
547         data->count = -1;
548         return 0;
549     }
550     return 0;
551 }
552
553
554 /***********************************************************************
555  *              unpack_message
556  *
557  * Unpack a message received from another process.
558  */
559 static BOOL unpack_message( HWND hwnd, UINT message, WPARAM *wparam, LPARAM *lparam,
560                             void **buffer, size_t size )
561 {
562     size_t minsize = 0;
563
564     switch(message)
565     {
566     case WM_NCCREATE:
567     case WM_CREATE:
568     {
569         CREATESTRUCTW *cs = *buffer;
570         WCHAR *str = (WCHAR *)(cs + 1);
571         if (size < sizeof(*cs)) return FALSE;
572         size -= sizeof(*cs);
573         if (HIWORD(cs->lpszName))
574         {
575             if (!check_string( str, size )) return FALSE;
576             cs->lpszName = str;
577             size -= (strlenW(str) + 1) * sizeof(WCHAR);
578             str += strlenW(str) + 1;
579         }
580         if (HIWORD(cs->lpszClass))
581         {
582             if (!check_string( str, size )) return FALSE;
583             cs->lpszClass = str;
584         }
585         break;
586     }
587     case WM_GETTEXT:
588     case WM_ASKCBFORMATNAME:
589         if (!get_buffer_space( buffer, (*wparam * sizeof(WCHAR)) )) return FALSE;
590         break;
591     case WM_SETTEXT:
592     case WM_WININICHANGE:
593     case WM_DEVMODECHANGE:
594     case CB_DIR:
595     case CB_FINDSTRING:
596     case CB_FINDSTRINGEXACT:
597     case CB_SELECTSTRING:
598     case LB_DIR:
599     case LB_ADDFILE:
600     case LB_FINDSTRING:
601     case LB_FINDSTRINGEXACT:
602     case LB_SELECTSTRING:
603     case EM_REPLACESEL:
604         if (!check_string( *buffer, size )) return FALSE;
605         break;
606     case WM_GETMINMAXINFO:
607         minsize = sizeof(MINMAXINFO);
608         break;
609     case WM_DRAWITEM:
610         minsize = sizeof(DRAWITEMSTRUCT);
611         break;
612     case WM_MEASUREITEM:
613         minsize = sizeof(MEASUREITEMSTRUCT);
614         break;
615     case WM_DELETEITEM:
616         minsize = sizeof(DELETEITEMSTRUCT);
617         break;
618     case WM_COMPAREITEM:
619         minsize = sizeof(COMPAREITEMSTRUCT);
620         break;
621     case WM_WINDOWPOSCHANGING:
622     case WM_WINDOWPOSCHANGED:
623     case WM_WINE_SETWINDOWPOS:
624         minsize = sizeof(WINDOWPOS);
625         break;
626     case WM_COPYDATA:
627     {
628         COPYDATASTRUCT *cp = *buffer;
629         if (size < sizeof(*cp)) return FALSE;
630         if (cp->lpData)
631         {
632             minsize = sizeof(*cp) + cp->cbData;
633             cp->lpData = cp + 1;
634         }
635         break;
636     }
637     case WM_NOTIFY:
638         /* WM_NOTIFY cannot be sent across processes (MSDN) */
639         return FALSE;
640     case WM_HELP:
641         minsize = sizeof(HELPINFO);
642         break;
643     case WM_STYLECHANGING:
644     case WM_STYLECHANGED:
645         minsize = sizeof(STYLESTRUCT);
646         break;
647     case WM_NCCALCSIZE:
648         if (!*wparam) minsize = sizeof(RECT);
649         else
650         {
651             NCCALCSIZE_PARAMS *nc = *buffer;
652             if (size < sizeof(*nc) + sizeof(*nc->lppos)) return FALSE;
653             nc->lppos = (WINDOWPOS *)(nc + 1);
654         }
655         break;
656     case WM_GETDLGCODE:
657         if (!*lparam) return TRUE;
658         minsize = sizeof(MSG);
659         break;
660     case SBM_SETSCROLLINFO:
661         minsize = sizeof(SCROLLINFO);
662         break;
663     case SBM_GETSCROLLINFO:
664         if (!get_buffer_space( buffer, sizeof(SCROLLINFO ))) return FALSE;
665         break;
666     case EM_GETSEL:
667     case SBM_GETRANGE:
668     case CB_GETEDITSEL:
669         if (*wparam || *lparam)
670         {
671             if (!get_buffer_space( buffer, 2*sizeof(DWORD) )) return FALSE;
672             if (*wparam) *wparam = (WPARAM)*buffer;
673             if (*lparam) *lparam = (LPARAM)((DWORD *)*buffer + 1);
674         }
675         return TRUE;
676     case EM_GETRECT:
677     case LB_GETITEMRECT:
678     case CB_GETDROPPEDCONTROLRECT:
679         if (!get_buffer_space( buffer, sizeof(RECT) )) return FALSE;
680         break;
681     case EM_SETRECT:
682     case EM_SETRECTNP:
683         minsize = sizeof(RECT);
684         break;
685     case EM_GETLINE:
686     {
687         WORD len;
688         if (size < sizeof(WORD)) return FALSE;
689         len = *(WORD *)*buffer;
690         if (!get_buffer_space( buffer, (len + 1) * sizeof(WCHAR) )) return FALSE;
691         *lparam = (LPARAM)*buffer + sizeof(WORD);  /* don't erase WORD at start of buffer */
692         return TRUE;
693     }
694     case EM_SETTABSTOPS:
695     case LB_SETTABSTOPS:
696         if (!*wparam) return TRUE;
697         minsize = *wparam * sizeof(UINT);
698         break;
699     case CB_ADDSTRING:
700     case CB_INSERTSTRING:
701     case LB_ADDSTRING:
702     case LB_INSERTSTRING:
703         if (!*buffer) return TRUE;
704         if (!check_string( *buffer, size )) return FALSE;
705         break;
706     case CB_GETLBTEXT:
707     {
708         size = sizeof(ULONG_PTR);
709         if (combobox_has_strings( hwnd ))
710             size = (SendMessageW( hwnd, CB_GETLBTEXTLEN, *wparam, 0 ) + 1) * sizeof(WCHAR);
711         if (!get_buffer_space( buffer, size )) return FALSE;
712         break;
713     }
714     case LB_GETTEXT:
715     {
716         size = sizeof(ULONG_PTR);
717         if (listbox_has_strings( hwnd ))
718             size = (SendMessageW( hwnd, LB_GETTEXTLEN, *wparam, 0 ) + 1) * sizeof(WCHAR);
719         if (!get_buffer_space( buffer, size )) return FALSE;
720         break;
721     }
722     case LB_GETSELITEMS:
723         if (!get_buffer_space( buffer, *wparam * sizeof(UINT) )) return FALSE;
724         break;
725     case WM_NEXTMENU:
726         minsize = sizeof(MDINEXTMENU);
727         if (!get_buffer_space( buffer, sizeof(MDINEXTMENU) )) return FALSE;
728         break;
729     case WM_SIZING:
730     case WM_MOVING:
731         minsize = sizeof(RECT);
732         if (!get_buffer_space( buffer, sizeof(RECT) )) return FALSE;
733         break;
734     case WM_MDICREATE:
735     {
736         MDICREATESTRUCTW *cs = *buffer;
737         WCHAR *str = (WCHAR *)(cs + 1);
738         if (size < sizeof(*cs)) return FALSE;
739         size -= sizeof(*cs);
740         if (HIWORD(cs->szTitle))
741         {
742             if (!check_string( str, size )) return FALSE;
743             cs->szTitle = str;
744             size -= (strlenW(str) + 1) * sizeof(WCHAR);
745             str += strlenW(str) + 1;
746         }
747         if (HIWORD(cs->szClass))
748         {
749             if (!check_string( str, size )) return FALSE;
750             cs->szClass = str;
751         }
752         break;
753     }
754     case WM_MDIGETACTIVE:
755         if (!*lparam) return TRUE;
756         if (!get_buffer_space( buffer, sizeof(BOOL) )) return FALSE;
757         break;
758     /* these contain an HFONT */
759     case WM_SETFONT:
760     case WM_GETFONT:
761     /* these contain an HDC */
762     case WM_PAINT:
763     case WM_ERASEBKGND:
764     case WM_ICONERASEBKGND:
765     case WM_NCPAINT:
766     case WM_CTLCOLORMSGBOX:
767     case WM_CTLCOLOREDIT:
768     case WM_CTLCOLORLISTBOX:
769     case WM_CTLCOLORBTN:
770     case WM_CTLCOLORDLG:
771     case WM_CTLCOLORSCROLLBAR:
772     case WM_CTLCOLORSTATIC:
773     case WM_PRINT:
774     case WM_PRINTCLIENT:
775     /* these contain an HGLOBAL */
776     case WM_PAINTCLIPBOARD:
777     case WM_SIZECLIPBOARD:
778     /* these contain pointers */
779     case WM_DROPOBJECT:
780     case WM_QUERYDROPOBJECT:
781     case WM_DRAGLOOP:
782     case WM_DRAGSELECT:
783     case WM_DRAGMOVE:
784     case WM_DEVICECHANGE:
785         FIXME( "msg %x (%s) not supported yet\n", message, SPY_GetMsgName(message, hwnd) );
786         return FALSE;
787
788     default:
789         return TRUE; /* message doesn't need any unpacking */
790     }
791
792     /* default exit for most messages: check minsize and store buffer in lparam */
793     if (size < minsize) return FALSE;
794     *lparam = (LPARAM)*buffer;
795     return TRUE;
796 }
797
798
799 /***********************************************************************
800  *              pack_reply
801  *
802  * Pack a reply to a message for sending to another process.
803  */
804 static void pack_reply( HWND hwnd, UINT message, WPARAM wparam, LPARAM lparam,
805                         LRESULT res, struct packed_message *data )
806 {
807     data->count = 0;
808     switch(message)
809     {
810     case WM_NCCREATE:
811     case WM_CREATE:
812         push_data( data, (CREATESTRUCTW *)lparam, sizeof(CREATESTRUCTW) );
813         break;
814     case WM_GETTEXT:
815     case CB_GETLBTEXT:
816     case LB_GETTEXT:
817         push_data( data, (WCHAR *)lparam, (res + 1) * sizeof(WCHAR) );
818         break;
819     case WM_GETMINMAXINFO:
820         push_data( data, (MINMAXINFO *)lparam, sizeof(MINMAXINFO) );
821         break;
822     case WM_MEASUREITEM:
823         push_data( data, (MEASUREITEMSTRUCT *)lparam, sizeof(MEASUREITEMSTRUCT) );
824         break;
825     case WM_WINDOWPOSCHANGING:
826     case WM_WINDOWPOSCHANGED:
827         push_data( data, (WINDOWPOS *)lparam, sizeof(WINDOWPOS) );
828         break;
829     case WM_GETDLGCODE:
830         if (lparam) push_data( data, (MSG *)lparam, sizeof(MSG) );
831         break;
832     case SBM_GETSCROLLINFO:
833         push_data( data, (SCROLLINFO *)lparam, sizeof(SCROLLINFO) );
834         break;
835     case EM_GETRECT:
836     case LB_GETITEMRECT:
837     case CB_GETDROPPEDCONTROLRECT:
838     case WM_SIZING:
839     case WM_MOVING:
840         push_data( data, (RECT *)lparam, sizeof(RECT) );
841         break;
842     case EM_GETLINE:
843     {
844         WORD *ptr = (WORD *)lparam;
845         push_data( data, ptr, ptr[-1] * sizeof(WCHAR) );
846         break;
847     }
848     case LB_GETSELITEMS:
849         push_data( data, (UINT *)lparam, wparam * sizeof(UINT) );
850         break;
851     case WM_MDIGETACTIVE:
852         if (lparam) push_data( data, (BOOL *)lparam, sizeof(BOOL) );
853         break;
854     case WM_NCCALCSIZE:
855         if (!wparam)
856             push_data( data, (RECT *)lparam, sizeof(RECT) );
857         else
858         {
859             NCCALCSIZE_PARAMS *nc = (NCCALCSIZE_PARAMS *)lparam;
860             push_data( data, nc, sizeof(*nc) );
861             push_data( data, nc->lppos, sizeof(*nc->lppos) );
862         }
863         break;
864     case EM_GETSEL:
865     case SBM_GETRANGE:
866     case CB_GETEDITSEL:
867         if (wparam) push_data( data, (DWORD *)wparam, sizeof(DWORD) );
868         if (lparam) push_data( data, (DWORD *)lparam, sizeof(DWORD) );
869         break;
870     case WM_NEXTMENU:
871         push_data( data, (MDINEXTMENU *)lparam, sizeof(MDINEXTMENU) );
872         break;
873     case WM_MDICREATE:
874         push_data( data, (MDICREATESTRUCTW *)lparam, sizeof(MDICREATESTRUCTW) );
875         break;
876     case WM_ASKCBFORMATNAME:
877         push_data( data, (WCHAR *)lparam, (strlenW((WCHAR *)lparam) + 1) * sizeof(WCHAR) );
878         break;
879     }
880 }
881
882
883 /***********************************************************************
884  *              unpack_reply
885  *
886  * Unpack a message reply received from another process.
887  */
888 static void unpack_reply( HWND hwnd, UINT message, WPARAM wparam, LPARAM lparam,
889                           void *buffer, size_t size )
890 {
891     switch(message)
892     {
893     case WM_NCCREATE:
894     case WM_CREATE:
895     {
896         CREATESTRUCTW *cs = (CREATESTRUCTW *)lparam;
897         LPCWSTR name = cs->lpszName, class = cs->lpszClass;
898         memcpy( cs, buffer, min( sizeof(*cs), size ));
899         cs->lpszName = name;  /* restore the original pointers */
900         cs->lpszClass = class;
901         break;
902     }
903     case WM_GETTEXT:
904     case WM_ASKCBFORMATNAME:
905         memcpy( (WCHAR *)lparam, buffer, min( wparam*sizeof(WCHAR), size ));
906         break;
907     case WM_GETMINMAXINFO:
908         memcpy( (MINMAXINFO *)lparam, buffer, min( sizeof(MINMAXINFO), size ));
909         break;
910     case WM_MEASUREITEM:
911         memcpy( (MEASUREITEMSTRUCT *)lparam, buffer, min( sizeof(MEASUREITEMSTRUCT), size ));
912         break;
913     case WM_WINDOWPOSCHANGING:
914     case WM_WINDOWPOSCHANGED:
915         memcpy( (WINDOWPOS *)lparam, buffer, min( sizeof(WINDOWPOS), size ));
916         break;
917     case WM_GETDLGCODE:
918         if (lparam) memcpy( (MSG *)lparam, buffer, min( sizeof(MSG), size ));
919         break;
920     case SBM_GETSCROLLINFO:
921         memcpy( (SCROLLINFO *)lparam, buffer, min( sizeof(SCROLLINFO), size ));
922         break;
923     case EM_GETRECT:
924     case CB_GETDROPPEDCONTROLRECT:
925     case LB_GETITEMRECT:
926     case WM_SIZING:
927     case WM_MOVING:
928         memcpy( (RECT *)lparam, buffer, min( sizeof(RECT), size ));
929         break;
930     case EM_GETLINE:
931         size = min( size, (size_t)*(WORD *)lparam );
932         memcpy( (WCHAR *)lparam, buffer, size );
933         break;
934     case LB_GETSELITEMS:
935         memcpy( (UINT *)lparam, buffer, min( wparam*sizeof(UINT), size ));
936         break;
937     case LB_GETTEXT:
938     case CB_GETLBTEXT:
939         memcpy( (WCHAR *)lparam, buffer, size );
940         break;
941     case WM_NEXTMENU:
942         memcpy( (MDINEXTMENU *)lparam, buffer, min( sizeof(MDINEXTMENU), size ));
943         break;
944     case WM_MDIGETACTIVE:
945         if (lparam) memcpy( (BOOL *)lparam, buffer, min( sizeof(BOOL), size ));
946         break;
947     case WM_NCCALCSIZE:
948         if (!wparam)
949             memcpy( (RECT *)lparam, buffer, min( sizeof(RECT), size ));
950         else
951         {
952             NCCALCSIZE_PARAMS *nc = (NCCALCSIZE_PARAMS *)lparam;
953             WINDOWPOS *wp = nc->lppos;
954             memcpy( nc, buffer, min( sizeof(*nc), size ));
955             if (size > sizeof(*nc))
956             {
957                 size -= sizeof(*nc);
958                 memcpy( wp, (NCCALCSIZE_PARAMS*)buffer + 1, min( sizeof(*wp), size ));
959             }
960             nc->lppos = wp;  /* restore the original pointer */
961         }
962         break;
963     case EM_GETSEL:
964     case SBM_GETRANGE:
965     case CB_GETEDITSEL:
966         if (wparam)
967         {
968             memcpy( (DWORD *)wparam, buffer, min( sizeof(DWORD), size ));
969             if (size <= sizeof(DWORD)) break;
970             size -= sizeof(DWORD);
971             buffer = (DWORD *)buffer + 1;
972         }
973         if (lparam) memcpy( (DWORD *)lparam, buffer, min( sizeof(DWORD), size ));
974         break;
975     case WM_MDICREATE:
976     {
977         MDICREATESTRUCTW *cs = (MDICREATESTRUCTW *)lparam;
978         LPCWSTR title = cs->szTitle, class = cs->szClass;
979         memcpy( cs, buffer, min( sizeof(*cs), size ));
980         cs->szTitle = title;  /* restore the original pointers */
981         cs->szClass = class;
982         break;
983     }
984     default:
985         ERR( "should not happen: unexpected message %x\n", message );
986         break;
987     }
988 }
989
990
991 /***********************************************************************
992  *           reply_message
993  *
994  * Send a reply to a sent message.
995  */
996 static void reply_message( struct received_message_info *info, LRESULT result, BOOL remove )
997 {
998     struct packed_message data;
999     int i, replied = info->flags & ISMEX_REPLIED;
1000
1001     if (info->flags & ISMEX_NOTIFY) return;  /* notify messages don't get replies */
1002     if (!remove && replied) return;  /* replied already */
1003
1004     data.count = 0;
1005     info->flags |= ISMEX_REPLIED;
1006
1007     if (info->type == MSG_OTHER_PROCESS && !replied)
1008     {
1009         pack_reply( info->msg.hwnd, info->msg.message, info->msg.wParam,
1010                     info->msg.lParam, result, &data );
1011     }
1012
1013     SERVER_START_REQ( reply_message )
1014     {
1015         req->result = result;
1016         req->remove = remove;
1017         for (i = 0; i < data.count; i++) wine_server_add_data( req, data.data[i], data.size[i] );
1018         wine_server_call( req );
1019     }
1020     SERVER_END_REQ;
1021 }
1022
1023
1024 /***********************************************************************
1025  *           handle_internal_message
1026  *
1027  * Handle an internal Wine message instead of calling the window proc.
1028  */
1029 static LRESULT handle_internal_message( HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam )
1030 {
1031     if (hwnd == GetDesktopWindow()) return 0;
1032     switch(msg)
1033     {
1034     case WM_WINE_DESTROYWINDOW:
1035         return WIN_DestroyWindow( hwnd );
1036     case WM_WINE_SETWINDOWPOS:
1037         return USER_Driver.pSetWindowPos( (WINDOWPOS *)lparam );
1038     case WM_WINE_SHOWWINDOW:
1039         return ShowWindow( hwnd, wparam );
1040     case WM_WINE_SETPARENT:
1041         return (LRESULT)SetParent( hwnd, (HWND)wparam );
1042     case WM_WINE_SETWINDOWLONG:
1043         return (LRESULT)SetWindowLongW( hwnd, wparam, lparam );
1044     case WM_WINE_ENABLEWINDOW:
1045         return EnableWindow( hwnd, wparam );
1046     default:
1047         FIXME( "unknown internal message %x\n", msg );
1048         return 0;
1049     }
1050 }
1051
1052 /* since the WM_DDE_ACK response to a WM_DDE_EXECUTE message should contain the handle
1053  * to the memory handle, we keep track (in the server side) of all pairs of handle
1054  * used (the client passes its value and the content of the memory handle), and
1055  * the server stored both values (the client, and the local one, created after the
1056  * content). When a ACK message is generated, the list of pair is searched for a 
1057  * matching pair, so that the client memory handle can be returned.
1058  */
1059 struct DDE_pair {
1060     HGLOBAL     client_hMem;
1061     HGLOBAL     server_hMem;
1062 };
1063
1064 static      struct DDE_pair*    dde_pairs;
1065 static      int                 dde_num_alloc;
1066 static      int                 dde_num_used;
1067 static      CRITICAL_SECTION    dde_crst = CRITICAL_SECTION_INIT("Raw_DDE_CritSect");
1068
1069 static BOOL dde_add_pair(HGLOBAL chm, HGLOBAL shm)
1070 {
1071     int  i;
1072 #define GROWBY  4
1073
1074     EnterCriticalSection(&dde_crst);
1075
1076     /* now remember the pair of hMem on both sides */
1077     if (dde_num_used == dde_num_alloc)
1078     {
1079         struct DDE_pair* tmp = HeapReAlloc( GetProcessHeap(), 0, dde_pairs,
1080                                             (dde_num_alloc + GROWBY) * sizeof(struct DDE_pair));
1081         if (!tmp)
1082         {
1083             LeaveCriticalSection(&dde_crst);
1084             return FALSE;
1085         }
1086         dde_pairs = tmp;
1087         /* zero out newly allocated part */
1088         memset(&dde_pairs[dde_num_alloc], 0, GROWBY * sizeof(struct DDE_pair));
1089         dde_num_alloc += GROWBY;
1090     }
1091 #undef GROWBY
1092     for (i = 0; i < dde_num_alloc; i++)
1093     {
1094         if (dde_pairs[i].server_hMem == 0)
1095         {
1096             dde_pairs[i].client_hMem = chm;
1097             dde_pairs[i].server_hMem = shm;
1098             dde_num_used++;
1099             break;
1100         }
1101     }
1102     LeaveCriticalSection(&dde_crst);
1103     return TRUE;
1104 }
1105
1106 static HGLOBAL dde_get_pair(HGLOBAL shm)
1107 {
1108     int  i;
1109     HGLOBAL     ret = 0;
1110
1111     EnterCriticalSection(&dde_crst);
1112     for (i = 0; i < dde_num_alloc; i++)
1113     {
1114         if (dde_pairs[i].server_hMem == shm)
1115         {
1116             /* free this pair */
1117             dde_pairs[i].server_hMem = 0;
1118             dde_num_used--;
1119             ret = dde_pairs[i].client_hMem;
1120             break;
1121         }
1122     }
1123     LeaveCriticalSection(&dde_crst);
1124     return ret;
1125 }
1126
1127 /***********************************************************************
1128  *              post_dde_message
1129  *
1130  * Post a DDE messag
1131  */
1132 static BOOL post_dde_message( DWORD dest_tid, struct packed_message *data, const struct send_message_info *info )
1133 {
1134     void*       ptr = NULL;
1135     int         size = 0;
1136     UINT        uiLo, uiHi;
1137     LPARAM      lp = 0;
1138     HGLOBAL     hunlock = 0;
1139     int         i;
1140     DWORD       res;
1141
1142     if (!UnpackDDElParam( info->msg, info->lparam, &uiLo, &uiHi ))
1143         return FALSE;
1144
1145     lp = info->lparam;
1146     switch (info->msg)
1147     {
1148         /* DDE messages which don't require packing are:
1149          * WM_DDE_INITIATE
1150          * WM_DDE_TERMINATE
1151          * WM_DDE_REQUEST
1152          * WM_DDE_UNADVISE
1153          */
1154     case WM_DDE_ACK:
1155         if (HIWORD(uiHi))
1156         {
1157             /* uiHi should contain a hMem from WM_DDE_EXECUTE */
1158             HGLOBAL h = dde_get_pair( uiHi );
1159             if (h)
1160             {
1161                 /* send back the value of h on the other side */
1162                 push_data( data, &h, sizeof(HGLOBAL) );
1163                 lp = uiLo;
1164                 TRACE( "send dde-ack %x %08x => %08lx\n", uiLo, uiHi, (DWORD)h );
1165             }
1166         }
1167         else
1168         {
1169             /* uiHi should contain either an atom or 0 */
1170             TRACE( "send dde-ack %x atom=%x\n", uiLo, uiHi );
1171             lp = MAKELONG( uiLo, uiHi );
1172         }
1173         break;
1174     case WM_DDE_ADVISE:
1175     case WM_DDE_DATA:
1176     case WM_DDE_POKE:
1177         size = 0;
1178         if (uiLo)
1179         {
1180             size = GlobalSize( (HGLOBAL)uiLo ) ;
1181             if ((info->msg == WM_DDE_ADVISE && size < sizeof(DDEADVISE)) ||
1182                 (info->msg == WM_DDE_DATA   && size < sizeof(DDEDATA))   ||
1183                 (info->msg == WM_DDE_POKE   && size < sizeof(DDEPOKE))
1184                 )
1185             return FALSE;
1186         }
1187         else if (info->msg != WM_DDE_DATA) return FALSE;
1188         
1189         lp = uiHi;
1190         if (uiLo)
1191         {
1192             if ((ptr = GlobalLock( (HGLOBAL)uiLo) ))
1193             {
1194                 push_data( data, ptr, size );
1195                 hunlock = (HGLOBAL)uiLo;
1196             }
1197         }
1198         TRACE( "send ddepack %u %x\n", size, uiHi );
1199         break;
1200     case WM_DDE_EXECUTE:
1201         if (info->lparam)
1202         {
1203             if ((ptr = GlobalLock( (HGLOBAL)info->lparam) ))
1204             {
1205                 push_data(data, ptr, GlobalSize( (HGLOBAL)info->lparam ));
1206                 /* so that the other side can send it back on ACK */
1207                 lp = info->lparam;
1208                 hunlock = (HGLOBAL)info->lparam;
1209             }
1210         }
1211         break;
1212     }
1213     SERVER_START_REQ( send_message )
1214     {
1215         req->id      = (void *)dest_tid;
1216         req->type    = info->type;
1217         req->win     = info->hwnd;
1218         req->msg     = info->msg;
1219         req->wparam  = info->wparam;
1220         req->lparam  = lp;
1221         req->time    = GetCurrentTime();
1222         req->timeout = -1;
1223         for (i = 0; i < data->count; i++) 
1224             wine_server_add_data( req, data->data[i], data->size[i] );
1225         if ((res = wine_server_call( req )))
1226         {
1227             if (res == STATUS_INVALID_PARAMETER)
1228                 /* FIXME: find a STATUS_ value for this one */
1229                 SetLastError( ERROR_INVALID_THREAD_ID );
1230             else
1231                 SetLastError( RtlNtStatusToDosError(res) );
1232         }   
1233         else 
1234             FreeDDElParam(info->msg, info->lparam);
1235     }
1236     SERVER_END_REQ;
1237     if (hunlock) GlobalUnlock(hunlock);
1238
1239     return !res;
1240 }
1241
1242 /***********************************************************************
1243  *              unpack_dde_message
1244  *
1245  * Unpack a posted DDE message received from another process.
1246  */
1247 static BOOL unpack_dde_message( HWND hwnd, UINT message, WPARAM *wparam, LPARAM *lparam,
1248                                 void **buffer, size_t size )
1249 {
1250     UINT        uiLo, uiHi;
1251     HGLOBAL     hMem = 0;
1252     void*       ptr;
1253
1254     switch (message)
1255     {
1256     case WM_DDE_ACK:
1257         if (size)
1258         {
1259             /* hMem is being passed */
1260             if (size != sizeof(HGLOBAL)) return FALSE;
1261             if (!buffer || !*buffer) return FALSE;
1262             uiLo = *lparam;
1263             memcpy( &hMem, *buffer, size );
1264             uiHi = hMem;
1265             TRACE("recv dde-ack %u mem=%x[%lx]\n", uiLo, uiHi, GlobalSize( uiHi ));
1266         }
1267         else
1268         {
1269             uiLo = LOWORD( *lparam );
1270             uiHi = HIWORD( *lparam );
1271             TRACE("recv dde-ack %x atom=%x\n", uiLo, uiHi);
1272         }
1273         *lparam = PackDDElParam( WM_DDE_ACK, uiLo, uiHi );
1274         break;
1275     case WM_DDE_ADVISE:
1276     case WM_DDE_DATA:
1277     case WM_DDE_POKE:
1278         if ((!buffer || !*buffer) && message != WM_DDE_DATA) return FALSE;
1279         uiHi = *lparam;
1280         TRACE( "recv ddepack %u %x\n", size, uiHi );
1281         if (size)
1282         {
1283             hMem = GlobalAlloc( GMEM_MOVEABLE|GMEM_DDESHARE, size );
1284             if (hMem && (ptr = GlobalLock( hMem )))
1285             {
1286                 memcpy( ptr, *buffer, size );
1287                 GlobalUnlock( hMem );
1288             }
1289             else return FALSE;
1290         }
1291         uiLo = hMem;
1292
1293         *lparam = PackDDElParam( message, uiLo, uiHi );
1294         break;
1295     case WM_DDE_EXECUTE:
1296         if (size)
1297         {
1298             if (!buffer || !*buffer) return FALSE;
1299             hMem = GlobalAlloc( GMEM_MOVEABLE|GMEM_DDESHARE, size );
1300             if (hMem && (ptr = GlobalLock( hMem )))
1301             {
1302                 memcpy( ptr, *buffer, size );
1303                 GlobalUnlock( hMem );
1304                 TRACE( "exec: pairing c=%08lx s=%08lx\n", *lparam, (DWORD)hMem );
1305                 if (!dde_add_pair( *lparam, hMem )) 
1306                 {
1307                     GlobalFree( hMem );
1308                     return FALSE;
1309                 }
1310             }
1311         } else return FALSE;
1312         *lparam = hMem;
1313         break;
1314     }
1315     return TRUE;
1316 }
1317
1318 /***********************************************************************
1319  *           call_window_proc
1320  *
1321  * Call a window procedure and the corresponding hooks.
1322  */
1323 static LRESULT call_window_proc( HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam, BOOL unicode )
1324 {
1325     LRESULT result;
1326     WNDPROC winproc;
1327
1328     if (msg & 0x80000000) return handle_internal_message( hwnd, msg, wparam, lparam );
1329
1330     /* first the WH_CALLWNDPROC hook */
1331     if (HOOK_IsHooked( WH_CALLWNDPROC ))
1332     {
1333         CWPSTRUCT cwp;
1334         cwp.lParam  = lparam;
1335         cwp.wParam  = wparam;
1336         cwp.message = msg;
1337         cwp.hwnd    = WIN_GetFullHandle( hwnd );
1338         if (unicode) HOOK_CallHooksW( WH_CALLWNDPROC, HC_ACTION, 1, (LPARAM)&cwp );
1339         else HOOK_CallHooksA( WH_CALLWNDPROC, HC_ACTION, 1, (LPARAM)&cwp );
1340         lparam = cwp.lParam;
1341         wparam = cwp.wParam;
1342         msg    = cwp.message;
1343         hwnd   = cwp.hwnd;
1344     }
1345
1346     /* now call the window procedure */
1347     if (unicode)
1348     {
1349         if (!(winproc = (WNDPROC)GetWindowLongW( hwnd, GWL_WNDPROC ))) return 0;
1350         result = CallWindowProcW( winproc, hwnd, msg, wparam, lparam );
1351     }
1352     else
1353     {
1354         if (!(winproc = (WNDPROC)GetWindowLongA( hwnd, GWL_WNDPROC ))) return 0;
1355         result = CallWindowProcA( winproc, hwnd, msg, wparam, lparam );
1356     }
1357
1358     /* and finally the WH_CALLWNDPROCRET hook */
1359     if (HOOK_IsHooked( WH_CALLWNDPROCRET ))
1360     {
1361         CWPRETSTRUCT cwp;
1362         cwp.lResult = result;
1363         cwp.lParam  = lparam;
1364         cwp.wParam  = wparam;
1365         cwp.message = msg;
1366         cwp.hwnd    = WIN_GetFullHandle( hwnd );
1367         if (unicode) HOOK_CallHooksW( WH_CALLWNDPROCRET, HC_ACTION, 1, (LPARAM)&cwp );
1368         else HOOK_CallHooksA( WH_CALLWNDPROCRET, HC_ACTION, 1, (LPARAM)&cwp );
1369     }
1370     return result;
1371 }
1372
1373
1374 /***********************************************************************
1375  *           MSG_peek_message
1376  *
1377  * Peek for a message matching the given parameters. Return FALSE if none available.
1378  * All pending sent messages are processed before returning.
1379  */
1380 BOOL MSG_peek_message( MSG *msg, HWND hwnd, UINT first, UINT last, int flags )
1381 {
1382     LRESULT result;
1383     ULONG_PTR extra_info = 0;
1384     MESSAGEQUEUE *queue = QUEUE_Current();
1385     struct received_message_info info, *old_info;
1386
1387     if (!first && !last) last = ~0;
1388
1389     for (;;)
1390     {
1391         NTSTATUS res;
1392         void *buffer = NULL;
1393         size_t size = 0, buffer_size = 0;
1394
1395         do  /* loop while buffer is too small */
1396         {
1397             if (buffer_size && !(buffer = HeapAlloc( GetProcessHeap(), 0, buffer_size )))
1398                 return FALSE;
1399             SERVER_START_REQ( get_message )
1400             {
1401                 req->flags     = flags;
1402                 req->get_win   = hwnd;
1403                 req->get_first = first;
1404                 req->get_last  = last;
1405                 if (buffer_size) wine_server_set_reply( req, buffer, buffer_size );
1406                 if (!(res = wine_server_call( req )))
1407                 {
1408                     size = wine_server_reply_size( reply );
1409                     info.type        = reply->type;
1410                     info.msg.hwnd    = reply->win;
1411                     info.msg.message = reply->msg;
1412                     info.msg.wParam  = reply->wparam;
1413                     info.msg.lParam  = reply->lparam;
1414                     info.msg.time    = reply->time;
1415                     info.msg.pt.x    = reply->x;
1416                     info.msg.pt.y    = reply->y;
1417                     extra_info       = reply->info;
1418                 }
1419                 else
1420                 {
1421                     if (buffer) HeapFree( GetProcessHeap(), 0, buffer );
1422                     buffer_size = reply->total;
1423                 }
1424             }
1425             SERVER_END_REQ;
1426         } while (res == STATUS_BUFFER_OVERFLOW);
1427
1428         if (res) return FALSE;
1429
1430         TRACE( "got type %d msg %x hwnd %x wp %x lp %lx\n",
1431                info.type, info.msg.message, info.msg.hwnd, info.msg.wParam, info.msg.lParam );
1432
1433         switch(info.type)
1434         {
1435         case MSG_ASCII:
1436         case MSG_UNICODE:
1437             info.flags = ISMEX_SEND;
1438             break;
1439         case MSG_NOTIFY:
1440             info.flags = ISMEX_NOTIFY;
1441             break;
1442         case MSG_CALLBACK:
1443             info.flags = ISMEX_CALLBACK;
1444             break;
1445         case MSG_OTHER_PROCESS:
1446             info.flags = ISMEX_SEND;
1447             if (!unpack_message( info.msg.hwnd, info.msg.message, &info.msg.wParam,
1448                                  &info.msg.lParam, &buffer, size ))
1449             {
1450                 ERR( "invalid packed message %x (%s) hwnd %x wp %x lp %lx size %d\n",
1451                      info.msg.message, SPY_GetMsgName(info.msg.message, info.msg.hwnd), info.msg.hwnd,
1452                      info.msg.wParam, info.msg.lParam, size );
1453                 /* ignore it */
1454                 reply_message( &info, 0, TRUE );
1455                 goto next;
1456             }
1457             break;
1458         case MSG_HARDWARE_RAW:
1459             if (!MSG_process_raw_hardware_message( &info.msg, extra_info,
1460                                                    hwnd, first, last, flags & GET_MSG_REMOVE ))
1461                 goto next;
1462             /* fall through */
1463         case MSG_HARDWARE_COOKED:
1464             if (!MSG_process_cooked_hardware_message( &info.msg, extra_info,
1465                                                       flags & GET_MSG_REMOVE ))
1466             {
1467                 flags |= GET_MSG_REMOVE_LAST;
1468                 goto next;
1469             }
1470             queue->GetMessagePosVal = MAKELONG( info.msg.pt.x, info.msg.pt.y );
1471             /* fall through */
1472         case MSG_POSTED:
1473             queue->GetMessageExtraInfoVal = extra_info;
1474             if (info.msg.message >= WM_DDE_FIRST && info.msg.message <= WM_DDE_LAST)
1475             {
1476                 if (!unpack_dde_message( info.msg.hwnd, info.msg.message, &info.msg.wParam,
1477                                          &info.msg.lParam, &buffer, size ))
1478                 {
1479                     ERR( "invalid packed dde-message %x (%s) hwnd %x wp %x lp %lx size %d\n",
1480                          info.msg.message, SPY_GetMsgName(info.msg.message, info.msg.hwnd), 
1481                          info.msg.hwnd, info.msg.wParam, info.msg.lParam, size );
1482                     /* ignore it */
1483                     continue;
1484                 }
1485             }
1486             *msg = info.msg;
1487             if (buffer) HeapFree( GetProcessHeap(), 0, buffer );
1488             return TRUE;
1489         }
1490
1491         /* if we get here, we have a sent message; call the window procedure */
1492         old_info = queue->receive_info;
1493         queue->receive_info = &info;
1494         result = call_window_proc( info.msg.hwnd, info.msg.message, info.msg.wParam,
1495                                    info.msg.lParam, (info.type != MSG_ASCII) );
1496         reply_message( &info, result, TRUE );
1497         queue->receive_info = old_info;
1498     next:
1499         if (buffer) HeapFree( GetProcessHeap(), 0, buffer );
1500     }
1501 }
1502
1503
1504 /***********************************************************************
1505  *           wait_message_reply
1506  *
1507  * Wait until a sent message gets replied to.
1508  */
1509 static void wait_message_reply( UINT flags )
1510 {
1511     MESSAGEQUEUE *queue;
1512
1513     if (!(queue = QUEUE_Current())) return;
1514
1515     for (;;)
1516     {
1517         unsigned int wake_bits = 0, changed_bits = 0;
1518         DWORD dwlc, res;
1519
1520         SERVER_START_REQ( set_queue_mask )
1521         {
1522             req->wake_mask    = (flags & SMTO_BLOCK) ? 0 : QS_SENDMESSAGE;
1523             req->changed_mask = QS_SMRESULT | req->wake_mask;
1524             req->skip_wait    = 1;
1525             if (!wine_server_call( req ))
1526             {
1527                 wake_bits    = reply->wake_bits;
1528                 changed_bits = reply->changed_bits;
1529             }
1530         }
1531         SERVER_END_REQ;
1532
1533         if (changed_bits & QS_SMRESULT) return;  /* got a result */
1534         if (wake_bits & QS_SENDMESSAGE)
1535         {
1536             /* Process the sent message immediately */
1537             MSG msg;
1538             MSG_peek_message( &msg, 0, 0, 0, GET_MSG_REMOVE | GET_MSG_SENT_ONLY );
1539             continue;
1540         }
1541
1542         /* now wait for it */
1543
1544         ReleaseThunkLock( &dwlc );
1545
1546         if (USER_Driver.pMsgWaitForMultipleObjectsEx)
1547             res = USER_Driver.pMsgWaitForMultipleObjectsEx( 1, &queue->server_queue,
1548                                                             INFINITE, 0, 0 );
1549         else
1550             res = WaitForSingleObject( queue->server_queue, INFINITE );
1551
1552         if (dwlc) RestoreThunkLock( dwlc );
1553     }
1554 }
1555
1556 /***********************************************************************
1557  *              put_message_in_queue
1558  *
1559  * Put a sent message into the destination queue.
1560  * For inter-process message, reply_size is set to expected size of reply data.
1561  */
1562 static BOOL put_message_in_queue( DWORD dest_tid, const struct send_message_info *info,
1563                                   size_t *reply_size )
1564 {
1565     struct packed_message data;
1566     unsigned int res;
1567     int i, timeout = -1;
1568
1569     if (info->type != MSG_NOTIFY &&
1570         info->type != MSG_CALLBACK &&
1571         info->type != MSG_POSTED &&
1572         info->timeout != INFINITE)
1573         timeout = info->timeout;
1574
1575     data.count = 0;
1576     if (info->type == MSG_OTHER_PROCESS)
1577     {
1578         *reply_size = pack_message( info->hwnd, info->msg, info->wparam, info->lparam, &data );
1579         if (data.count == -1)
1580         {
1581             WARN( "cannot pack message %x\n", info->msg );
1582             return FALSE;
1583         }
1584     }
1585     else if (info->type == MSG_POSTED && info->msg >= WM_DDE_FIRST && info->msg <= WM_DDE_LAST)
1586     {
1587         return post_dde_message( dest_tid, &data, info );
1588     }
1589
1590     SERVER_START_REQ( send_message )
1591     {
1592         req->id      = (void *)dest_tid;
1593         req->type    = info->type;
1594         req->win     = info->hwnd;
1595         req->msg     = info->msg;
1596         req->wparam  = info->wparam;
1597         req->lparam  = info->lparam;
1598         req->time    = GetCurrentTime();
1599         req->timeout = timeout;
1600         for (i = 0; i < data.count; i++) wine_server_add_data( req, data.data[i], data.size[i] );
1601         if ((res = wine_server_call( req )))
1602         {
1603             if (res == STATUS_INVALID_PARAMETER)
1604                 /* FIXME: find a STATUS_ value for this one */
1605                 SetLastError( ERROR_INVALID_THREAD_ID );
1606             else
1607                 SetLastError( RtlNtStatusToDosError(res) );
1608         }
1609     }
1610     SERVER_END_REQ;
1611     return !res;
1612 }
1613
1614
1615 /***********************************************************************
1616  *              retrieve_reply
1617  *
1618  * Retrieve a message reply from the server.
1619  */
1620 static LRESULT retrieve_reply( const struct send_message_info *info,
1621                                size_t reply_size, LRESULT *result )
1622 {
1623     NTSTATUS status;
1624     void *reply_data = NULL;
1625
1626     if (reply_size)
1627     {
1628         if (!(reply_data = HeapAlloc( GetProcessHeap(), 0, reply_size )))
1629         {
1630             WARN( "no memory for reply %d bytes, will be truncated\n", reply_size );
1631             reply_size = 0;
1632         }
1633     }
1634     SERVER_START_REQ( get_message_reply )
1635     {
1636         req->cancel = 1;
1637         if (reply_size) wine_server_set_reply( req, reply_data, reply_size );
1638         if (!(status = wine_server_call( req ))) *result = reply->result;
1639         reply_size = wine_server_reply_size( reply );
1640     }
1641     SERVER_END_REQ;
1642     if (!status && reply_size)
1643         unpack_reply( info->hwnd, info->msg, info->wparam, info->lparam, reply_data, reply_size );
1644
1645     if (reply_data) HeapFree( GetProcessHeap(), 0, reply_data );
1646
1647     TRACE( "hwnd %x msg %x (%s) wp %x lp %lx got reply %lx (err=%ld)\n",
1648            info->hwnd, info->msg, SPY_GetMsgName(info->msg, info->hwnd), info->wparam,
1649            info->lparam, *result, status );
1650
1651     if (!status) return 1;
1652     if (status == STATUS_TIMEOUT) SetLastError(0);  /* timeout */
1653     else SetLastError( RtlNtStatusToDosError(status) );
1654     return 0;
1655 }
1656
1657
1658 /***********************************************************************
1659  *              send_inter_thread_message
1660  */
1661 static LRESULT send_inter_thread_message( DWORD dest_tid, const struct send_message_info *info,
1662                                           LRESULT *res_ptr )
1663 {
1664     LRESULT ret;
1665     int locks;
1666     size_t reply_size = 0;
1667
1668     TRACE( "hwnd %x msg %x (%s) wp %x lp %lx\n",
1669            info->hwnd, info->msg, SPY_GetMsgName(info->msg, info->hwnd), info->wparam, info->lparam );
1670
1671     if (!put_message_in_queue( dest_tid, info, &reply_size )) return 0;
1672
1673     /* there's no reply to wait for on notify/callback messages */
1674     if (info->type == MSG_NOTIFY || info->type == MSG_CALLBACK) return 1;
1675
1676     locks = WIN_SuspendWndsLock();
1677
1678     wait_message_reply( info->flags );
1679     ret = retrieve_reply( info, reply_size, res_ptr );
1680
1681     WIN_RestoreWndsLock( locks );
1682     return ret;
1683 }
1684
1685
1686 /***********************************************************************
1687  *              SendMessageTimeoutW  (USER32.@)
1688  */
1689 LRESULT WINAPI SendMessageTimeoutW( HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam,
1690                                     UINT flags, UINT timeout, LPDWORD res_ptr )
1691 {
1692     struct send_message_info info;
1693     DWORD dest_tid, dest_pid;
1694     LRESULT ret, result;
1695
1696     info.type    = MSG_UNICODE;
1697     info.hwnd    = hwnd;
1698     info.msg     = msg;
1699     info.wparam  = wparam;
1700     info.lparam  = lparam;
1701     info.flags   = flags;
1702     info.timeout = timeout;
1703
1704     if (is_broadcast(hwnd))
1705     {
1706         EnumWindows( broadcast_message_callback, (LPARAM)&info );
1707         if (res_ptr) *res_ptr = 1;
1708         return 1;
1709     }
1710
1711     if (!(dest_tid = GetWindowThreadProcessId( hwnd, &dest_pid ))) return 0;
1712
1713     if (USER_IsExitingThread( dest_tid )) return 0;
1714
1715     SPY_EnterMessage( SPY_SENDMESSAGE, hwnd, msg, wparam, lparam );
1716
1717     if (dest_tid == GetCurrentThreadId())
1718     {
1719         result = call_window_proc( hwnd, msg, wparam, lparam, TRUE );
1720         ret = 1;
1721     }
1722     else
1723     {
1724         if (dest_pid != GetCurrentProcessId()) info.type = MSG_OTHER_PROCESS;
1725         ret = send_inter_thread_message( dest_tid, &info, &result );
1726     }
1727
1728     SPY_ExitMessage( SPY_RESULT_OK, hwnd, msg, result, wparam, lparam );
1729     if (ret && res_ptr) *res_ptr = result;
1730     return ret;
1731 }
1732
1733
1734 /***********************************************************************
1735  *              SendMessageTimeoutA  (USER32.@)
1736  */
1737 LRESULT WINAPI SendMessageTimeoutA( HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam,
1738                                     UINT flags, UINT timeout, LPDWORD res_ptr )
1739 {
1740     struct send_message_info info;
1741     DWORD dest_tid, dest_pid;
1742     LRESULT ret, result;
1743
1744     info.type    = MSG_ASCII;
1745     info.hwnd    = hwnd;
1746     info.msg     = msg;
1747     info.wparam  = wparam;
1748     info.lparam  = lparam;
1749     info.flags   = flags;
1750     info.timeout = timeout;
1751
1752     if (is_broadcast(hwnd))
1753     {
1754         EnumWindows( broadcast_message_callback, (LPARAM)&info );
1755         if (res_ptr) *res_ptr = 1;
1756         return 1;
1757     }
1758
1759     if (!(dest_tid = GetWindowThreadProcessId( hwnd, &dest_pid ))) return 0;
1760
1761     if (USER_IsExitingThread( dest_tid )) return 0;
1762
1763     SPY_EnterMessage( SPY_SENDMESSAGE, hwnd, msg, wparam, lparam );
1764
1765     if (dest_tid == GetCurrentThreadId())
1766     {
1767         result = call_window_proc( hwnd, msg, wparam, lparam, FALSE );
1768         ret = 1;
1769     }
1770     else if (dest_pid == GetCurrentProcessId())
1771     {
1772         ret = send_inter_thread_message( dest_tid, &info, &result );
1773     }
1774     else
1775     {
1776         /* inter-process message: need to map to Unicode */
1777         info.type = MSG_OTHER_PROCESS;
1778         if (is_unicode_message( info.msg ))
1779         {
1780             if (WINPROC_MapMsg32ATo32W( info.hwnd, info.msg, &info.wparam, &info.lparam ) == -1)
1781                 return 0;
1782             ret = send_inter_thread_message( dest_tid, &info, &result );
1783             result = WINPROC_UnmapMsg32ATo32W( info.hwnd, info.msg, info.wparam,
1784                                                info.lparam, result );
1785         }
1786         else ret = send_inter_thread_message( dest_tid, &info, &result );
1787     }
1788     SPY_ExitMessage( SPY_RESULT_OK, hwnd, msg, result, wparam, lparam );
1789     if (ret && res_ptr) *res_ptr = result;
1790     return ret;
1791 }
1792
1793
1794 /***********************************************************************
1795  *              SendMessageW  (USER32.@)
1796  */
1797 LRESULT WINAPI SendMessageW( HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam )
1798 {
1799     LRESULT res = 0;
1800     SendMessageTimeoutW( hwnd, msg, wparam, lparam, SMTO_NORMAL, INFINITE, &res );
1801     return res;
1802 }
1803
1804
1805 /***********************************************************************
1806  *              SendMessageA  (USER32.@)
1807  */
1808 LRESULT WINAPI SendMessageA( HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam )
1809 {
1810     LRESULT res = 0;
1811     SendMessageTimeoutA( hwnd, msg, wparam, lparam, SMTO_NORMAL, INFINITE, &res );
1812     return res;
1813 }
1814
1815
1816 /***********************************************************************
1817  *              SendNotifyMessageA  (USER32.@)
1818  */
1819 BOOL WINAPI SendNotifyMessageA( HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam )
1820 {
1821     return SendNotifyMessageW( hwnd, msg, map_wparam_AtoW( msg, wparam ), lparam );
1822 }
1823
1824
1825 /***********************************************************************
1826  *              SendNotifyMessageW  (USER32.@)
1827  */
1828 BOOL WINAPI SendNotifyMessageW( HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam )
1829 {
1830     struct send_message_info info;
1831     DWORD dest_tid;
1832     LRESULT result;
1833
1834     if (is_pointer_message(msg))
1835     {
1836         SetLastError(ERROR_INVALID_PARAMETER);
1837         return FALSE;
1838     }
1839
1840     info.type    = MSG_NOTIFY;
1841     info.hwnd    = hwnd;
1842     info.msg     = msg;
1843     info.wparam  = wparam;
1844     info.lparam  = lparam;
1845
1846     if (is_broadcast(hwnd))
1847     {
1848         EnumWindows( broadcast_message_callback, (LPARAM)&info );
1849         return TRUE;
1850     }
1851
1852     if (!(dest_tid = GetWindowThreadProcessId( hwnd, NULL ))) return FALSE;
1853
1854     if (USER_IsExitingThread( dest_tid )) return TRUE;
1855
1856     if (dest_tid == GetCurrentThreadId())
1857     {
1858         call_window_proc( hwnd, msg, wparam, lparam, TRUE );
1859         return TRUE;
1860     }
1861     return send_inter_thread_message( dest_tid, &info, &result );
1862 }
1863
1864
1865 /***********************************************************************
1866  *              SendMessageCallbackA  (USER32.@)
1867  */
1868 BOOL WINAPI SendMessageCallbackA( HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam,
1869                                   SENDASYNCPROC callback, ULONG_PTR data )
1870 {
1871     return SendMessageCallbackW( hwnd, msg, map_wparam_AtoW( msg, wparam ),
1872                                  lparam, callback, data );
1873 }
1874
1875
1876 /***********************************************************************
1877  *              SendMessageCallbackW  (USER32.@)
1878  */
1879 BOOL WINAPI SendMessageCallbackW( HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam,
1880                                   SENDASYNCPROC callback, ULONG_PTR data )
1881 {
1882     struct send_message_info info;
1883     LRESULT result;
1884     DWORD dest_tid;
1885
1886     if (is_pointer_message(msg))
1887     {
1888         SetLastError(ERROR_INVALID_PARAMETER);
1889         return FALSE;
1890     }
1891
1892     info.type     = MSG_CALLBACK;
1893     info.hwnd     = hwnd;
1894     info.msg      = msg;
1895     info.wparam   = wparam;
1896     info.lparam   = lparam;
1897     info.callback = callback;
1898     info.data     = data;
1899
1900     if (is_broadcast(hwnd))
1901     {
1902         EnumWindows( broadcast_message_callback, (LPARAM)&info );
1903         return TRUE;
1904     }
1905
1906     if (!(dest_tid = GetWindowThreadProcessId( hwnd, NULL ))) return FALSE;
1907
1908     if (USER_IsExitingThread( dest_tid )) return TRUE;
1909
1910     if (dest_tid == GetCurrentThreadId())
1911     {
1912         result = call_window_proc( hwnd, msg, wparam, lparam, TRUE );
1913         callback( hwnd, msg, data, result );
1914         return TRUE;
1915     }
1916     FIXME( "callback will not be called\n" );
1917     return send_inter_thread_message( dest_tid, &info, &result );
1918 }
1919
1920
1921 /***********************************************************************
1922  *              ReplyMessage  (USER32.@)
1923  */
1924 BOOL WINAPI ReplyMessage( LRESULT result )
1925 {
1926     MESSAGEQUEUE *queue = QUEUE_Current();
1927     struct received_message_info *info = queue->receive_info;
1928
1929     if (!info) return FALSE;
1930     reply_message( info, result, FALSE );
1931     return TRUE;
1932 }
1933
1934
1935 /***********************************************************************
1936  *              InSendMessage  (USER32.@)
1937  */
1938 BOOL WINAPI InSendMessage(void)
1939 {
1940     return (InSendMessageEx(NULL) & (ISMEX_SEND|ISMEX_REPLIED)) == ISMEX_SEND;
1941 }
1942
1943
1944 /***********************************************************************
1945  *              InSendMessageEx  (USER32.@)
1946  */
1947 DWORD WINAPI InSendMessageEx( LPVOID reserved )
1948 {
1949     MESSAGEQUEUE *queue = QUEUE_Current();
1950     struct received_message_info *info = queue->receive_info;
1951
1952     if (info) return info->flags;
1953     return ISMEX_NOSEND;
1954 }
1955
1956
1957 /***********************************************************************
1958  *              PostMessageA  (USER32.@)
1959  */
1960 BOOL WINAPI PostMessageA( HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam )
1961 {
1962     return PostMessageW( hwnd, msg, map_wparam_AtoW( msg, wparam ), lparam );
1963 }
1964
1965
1966 /***********************************************************************
1967  *              PostMessageW  (USER32.@)
1968  */
1969 BOOL WINAPI PostMessageW( HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam )
1970 {
1971     struct send_message_info info;
1972     DWORD dest_tid;
1973
1974     if (is_pointer_message( msg ))
1975     {
1976         SetLastError( ERROR_INVALID_PARAMETER );
1977         return FALSE;
1978     }
1979
1980     info.type   = MSG_POSTED;
1981     info.hwnd   = hwnd;
1982     info.msg    = msg;
1983     info.wparam = wparam;
1984     info.lparam = lparam;
1985
1986     if (is_broadcast(hwnd))
1987     {
1988         EnumWindows( broadcast_message_callback, (LPARAM)&info );
1989         return TRUE;
1990     }
1991     if (!(dest_tid = GetWindowThreadProcessId( hwnd, NULL ))) return FALSE;
1992
1993     if (USER_IsExitingThread( dest_tid )) return TRUE;
1994
1995     return put_message_in_queue( dest_tid, &info, NULL );
1996 }
1997
1998
1999 /**********************************************************************
2000  *              PostThreadMessageA  (USER32.@)
2001  */
2002 BOOL WINAPI PostThreadMessageA( DWORD thread, UINT msg, WPARAM wparam, LPARAM lparam )
2003 {
2004     return PostThreadMessageW( thread, msg, map_wparam_AtoW( msg, wparam ), lparam );
2005 }
2006
2007
2008 /**********************************************************************
2009  *              PostThreadMessageW  (USER32.@)
2010  */
2011 BOOL WINAPI PostThreadMessageW( DWORD thread, UINT msg, WPARAM wparam, LPARAM lparam )
2012 {
2013     struct send_message_info info;
2014
2015     if (is_pointer_message( msg ))
2016     {
2017         SetLastError( ERROR_INVALID_PARAMETER );
2018         return FALSE;
2019     }
2020     if (USER_IsExitingThread( thread )) return TRUE;
2021
2022     info.type   = MSG_POSTED;
2023     info.hwnd   = 0;
2024     info.msg    = msg;
2025     info.wparam = wparam;
2026     info.lparam = lparam;
2027     return put_message_in_queue( thread, &info, NULL );
2028 }
2029
2030
2031 /***********************************************************************
2032  *              PostQuitMessage  (USER32.@)
2033  */
2034 void WINAPI PostQuitMessage( INT exitCode )
2035 {
2036     PostThreadMessageW( GetCurrentThreadId(), WM_QUIT, exitCode, 0 );
2037 }
2038
2039
2040 /***********************************************************************
2041  *              PeekMessageW  (USER32.@)
2042  */
2043 BOOL WINAPI PeekMessageW( MSG *msg_out, HWND hwnd, UINT first, UINT last, UINT flags )
2044 {
2045     MESSAGEQUEUE *queue;
2046     MSG msg;
2047     int locks;
2048
2049     /* check for graphics events */
2050     if (USER_Driver.pMsgWaitForMultipleObjectsEx)
2051         USER_Driver.pMsgWaitForMultipleObjectsEx( 0, NULL, 0, 0, 0 );
2052
2053     hwnd = WIN_GetFullHandle( hwnd );
2054     locks = WIN_SuspendWndsLock();
2055
2056     if (!MSG_peek_message( &msg, hwnd, first, last,
2057                            (flags & PM_REMOVE) ? GET_MSG_REMOVE : 0 ))
2058     {
2059         /* FIXME: should be done before checking for hw events */
2060         MSG_JournalPlayBackMsg();
2061
2062         if (!(flags & PM_NOYIELD))
2063         {
2064             DWORD count;
2065             ReleaseThunkLock(&count);
2066             if (count) RestoreThunkLock(count);
2067         }
2068         WIN_RestoreWndsLock( locks );
2069         return FALSE;
2070     }
2071
2072     WIN_RestoreWndsLock( locks );
2073
2074     /* need to fill the window handle for WM_PAINT message */
2075     if (msg.message == WM_PAINT)
2076     {
2077         if (IsIconic( msg.hwnd ) && GetClassLongA( msg.hwnd, GCL_HICON ))
2078         {
2079             msg.message = WM_PAINTICON;
2080             msg.wParam = 1;
2081         }
2082         /* clear internal paint flag */
2083         RedrawWindow( msg.hwnd, NULL, 0, RDW_NOINTERNALPAINT | RDW_NOCHILDREN );
2084     }
2085
2086     if ((queue = QUEUE_Current()))
2087     {
2088         queue->GetMessageTimeVal = msg.time;
2089         msg.pt.x = LOWORD( queue->GetMessagePosVal );
2090         msg.pt.y = HIWORD( queue->GetMessagePosVal );
2091     }
2092
2093     HOOK_CallHooksW( WH_GETMESSAGE, HC_ACTION, flags & PM_REMOVE, (LPARAM)&msg );
2094
2095     /* copy back our internal safe copy of message data to msg_out.
2096      * msg_out is a variable from the *program*, so it can't be used
2097      * internally as it can get "corrupted" by our use of SendMessage()
2098      * (back to the program) inside the message handling itself. */
2099     *msg_out = msg;
2100     return TRUE;
2101 }
2102
2103
2104 /***********************************************************************
2105  *              PeekMessageA  (USER32.@)
2106  */
2107 BOOL WINAPI PeekMessageA( MSG *msg, HWND hwnd, UINT first, UINT last, UINT flags )
2108 {
2109     BOOL ret = PeekMessageW( msg, hwnd, first, last, flags );
2110     if (ret) msg->wParam = map_wparam_WtoA( msg->message, msg->wParam );
2111     return ret;
2112 }
2113
2114
2115 /***********************************************************************
2116  *              GetMessageW  (USER32.@)
2117  */
2118 BOOL WINAPI GetMessageW( MSG *msg, HWND hwnd, UINT first, UINT last )
2119 {
2120     MESSAGEQUEUE *queue = QUEUE_Current();
2121     int mask, locks;
2122
2123     mask = QS_POSTMESSAGE | QS_SENDMESSAGE;  /* Always selected */
2124     if (first || last)
2125     {
2126         if ((first <= WM_KEYLAST) && (last >= WM_KEYFIRST)) mask |= QS_KEY;
2127         if ( ((first <= WM_MOUSELAST) && (last >= WM_MOUSEFIRST)) ||
2128              ((first <= WM_NCMOUSELAST) && (last >= WM_NCMOUSEFIRST)) ) mask |= QS_MOUSE;
2129         if ((first <= WM_TIMER) && (last >= WM_TIMER)) mask |= QS_TIMER;
2130         if ((first <= WM_SYSTIMER) && (last >= WM_SYSTIMER)) mask |= QS_TIMER;
2131         if ((first <= WM_PAINT) && (last >= WM_PAINT)) mask |= QS_PAINT;
2132     }
2133     else mask |= QS_MOUSE | QS_KEY | QS_TIMER | QS_PAINT;
2134
2135     locks = WIN_SuspendWndsLock();
2136
2137     while (!PeekMessageW( msg, hwnd, first, last, PM_REMOVE ))
2138     {
2139         /* wait until one of the bits is set */
2140         unsigned int wake_bits = 0, changed_bits = 0;
2141         DWORD dwlc;
2142
2143         SERVER_START_REQ( set_queue_mask )
2144         {
2145             req->wake_mask    = QS_SENDMESSAGE;
2146             req->changed_mask = mask;
2147             req->skip_wait    = 1;
2148             if (!wine_server_call( req ))
2149             {
2150                 wake_bits    = reply->wake_bits;
2151                 changed_bits = reply->changed_bits;
2152             }
2153         }
2154         SERVER_END_REQ;
2155
2156         if (changed_bits & mask) continue;
2157         if (wake_bits & QS_SENDMESSAGE) continue;
2158
2159         TRACE( "(%04x) mask=%08x, bits=%08x, changed=%08x, waiting\n",
2160                queue->self, mask, wake_bits, changed_bits );
2161
2162         ReleaseThunkLock( &dwlc );
2163         if (USER_Driver.pMsgWaitForMultipleObjectsEx)
2164             USER_Driver.pMsgWaitForMultipleObjectsEx( 1, &queue->server_queue, INFINITE, 0, 0 );
2165         else
2166             WaitForSingleObject( queue->server_queue, INFINITE );
2167         if (dwlc) RestoreThunkLock( dwlc );
2168     }
2169
2170     WIN_RestoreWndsLock( locks );
2171
2172     return (msg->message != WM_QUIT);
2173 }
2174
2175
2176 /***********************************************************************
2177  *              GetMessageA  (USER32.@)
2178  */
2179 BOOL WINAPI GetMessageA( MSG *msg, HWND hwnd, UINT first, UINT last )
2180 {
2181     GetMessageW( msg, hwnd, first, last );
2182     msg->wParam = map_wparam_WtoA( msg->message, msg->wParam );
2183     return (msg->message != WM_QUIT);
2184 }
2185
2186
2187 /***********************************************************************
2188  *              SetMessageQueue (USER32.@)
2189  */
2190 BOOL WINAPI SetMessageQueue( INT size )
2191 {
2192     /* now obsolete the message queue will be expanded dynamically as necessary */
2193     return TRUE;
2194 }