GetWindowLong -> GetWindowLongPtr.
[wine] / dlls / user / message.c
1 /*
2  * Window messaging support
3  *
4  * Copyright 2001 Alexandre Julliard
5  *
6  * This library is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU Lesser General Public
8  * License as published by the Free Software Foundation; either
9  * version 2.1 of the License, or (at your option) any later version.
10  *
11  * This library is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14  * Lesser General Public License for more details.
15  *
16  * You should have received a copy of the GNU Lesser General Public
17  * License along with this library; if not, write to the Free Software
18  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
19  */
20
21 #include "config.h"
22 #include "wine/port.h"
23
24 #include <assert.h>
25 #include <stdarg.h>
26
27 #include "ntstatus.h"
28 #include "windef.h"
29 #include "winbase.h"
30 #include "wingdi.h"
31 #include "winuser.h"
32 #include "winerror.h"
33 #include "winnls.h"
34 #include "dde.h"
35 #include "wine/unicode.h"
36 #include "wine/server.h"
37 #include "message.h"
38 #include "user.h"
39 #include "win.h"
40 #include "winproc.h"
41 #include "wine/debug.h"
42
43 WINE_DEFAULT_DEBUG_CHANNEL(msg);
44 WINE_DECLARE_DEBUG_CHANNEL(relay);
45
46 #define WM_NCMOUSEFIRST WM_NCMOUSEMOVE
47 #define WM_NCMOUSELAST  WM_NCMBUTTONDBLCLK
48
49 #define MAX_PACK_COUNT 4
50
51 /* description of the data fields that need to be packed along with a sent message */
52 struct packed_message
53 {
54     int         count;
55     const void *data[MAX_PACK_COUNT];
56     size_t      size[MAX_PACK_COUNT];
57 };
58
59 /* info about the message currently being received by the current thread */
60 struct received_message_info
61 {
62     enum message_type type;
63     MSG               msg;
64     UINT              flags;  /* InSendMessageEx return flags */
65 };
66
67 /* structure to group all parameters for sent messages of the various kinds */
68 struct send_message_info
69 {
70     enum message_type type;
71     HWND              hwnd;
72     UINT              msg;
73     WPARAM            wparam;
74     LPARAM            lparam;
75     UINT              flags;      /* flags for SendMessageTimeout */
76     UINT              timeout;    /* timeout for SendMessageTimeout */
77     SENDASYNCPROC     callback;   /* callback function for SendMessageCallback */
78     ULONG_PTR         data;       /* callback data */
79 };
80
81
82 /* flag for messages that contain pointers */
83 /* 32 messages per entry, messages 0..31 map to bits 0..31 */
84
85 #define SET(msg) (1 << ((msg) & 31))
86
87 static const unsigned int message_pointer_flags[] =
88 {
89     /* 0x00 - 0x1f */
90     SET(WM_CREATE) | SET(WM_SETTEXT) | SET(WM_GETTEXT) |
91     SET(WM_WININICHANGE) | SET(WM_DEVMODECHANGE),
92     /* 0x20 - 0x3f */
93     SET(WM_GETMINMAXINFO) | SET(WM_DRAWITEM) | SET(WM_MEASUREITEM) | SET(WM_DELETEITEM) |
94     SET(WM_COMPAREITEM),
95     /* 0x40 - 0x5f */
96     SET(WM_WINDOWPOSCHANGING) | SET(WM_WINDOWPOSCHANGED) | SET(WM_COPYDATA) |
97     SET(WM_NOTIFY) | SET(WM_HELP),
98     /* 0x60 - 0x7f */
99     SET(WM_STYLECHANGING) | SET(WM_STYLECHANGED),
100     /* 0x80 - 0x9f */
101     SET(WM_NCCREATE) | SET(WM_NCCALCSIZE) | SET(WM_GETDLGCODE),
102     /* 0xa0 - 0xbf */
103     SET(EM_GETSEL) | SET(EM_GETRECT) | SET(EM_SETRECT) | SET(EM_SETRECTNP),
104     /* 0xc0 - 0xdf */
105     SET(EM_REPLACESEL) | SET(EM_GETLINE) | SET(EM_SETTABSTOPS),
106     /* 0xe0 - 0xff */
107     SET(SBM_GETRANGE) | SET(SBM_SETSCROLLINFO) | SET(SBM_GETSCROLLINFO),
108     /* 0x100 - 0x11f */
109     0,
110     /* 0x120 - 0x13f */
111     0,
112     /* 0x140 - 0x15f */
113     SET(CB_GETEDITSEL) | SET(CB_ADDSTRING) | SET(CB_DIR) | SET(CB_GETLBTEXT) |
114     SET(CB_INSERTSTRING) | SET(CB_FINDSTRING) | SET(CB_SELECTSTRING) |
115     SET(CB_GETDROPPEDCONTROLRECT) | SET(CB_FINDSTRINGEXACT),
116     /* 0x160 - 0x17f */
117     0,
118     /* 0x180 - 0x19f */
119     SET(LB_ADDSTRING) | SET(LB_INSERTSTRING) | SET(LB_GETTEXT) | SET(LB_SELECTSTRING) |
120     SET(LB_DIR) | SET(LB_FINDSTRING) |
121     SET(LB_GETSELITEMS) | SET(LB_SETTABSTOPS) | SET(LB_ADDFILE) | SET(LB_GETITEMRECT),
122     /* 0x1a0 - 0x1bf */
123     SET(LB_FINDSTRINGEXACT),
124     /* 0x1c0 - 0x1df */
125     0,
126     /* 0x1e0 - 0x1ff */
127     0,
128     /* 0x200 - 0x21f */
129     SET(WM_NEXTMENU) | SET(WM_SIZING) | SET(WM_MOVING) | SET(WM_DEVICECHANGE),
130     /* 0x220 - 0x23f */
131     SET(WM_MDICREATE) | SET(WM_MDIGETACTIVE) | SET(WM_DROPOBJECT) |
132     SET(WM_QUERYDROPOBJECT) | SET(WM_DRAGLOOP) | SET(WM_DRAGSELECT) | SET(WM_DRAGMOVE),
133     /* 0x240 - 0x25f */
134     0,
135     /* 0x260 - 0x27f */
136     0,
137     /* 0x280 - 0x29f */
138     0,
139     /* 0x2a0 - 0x2bf */
140     0,
141     /* 0x2c0 - 0x2df */
142     0,
143     /* 0x2e0 - 0x2ff */
144     0,
145     /* 0x300 - 0x31f */
146     SET(WM_ASKCBFORMATNAME)
147 };
148
149 /* flags for messages that contain Unicode strings */
150 static const unsigned int message_unicode_flags[] =
151 {
152     /* 0x00 - 0x1f */
153     SET(WM_CREATE) | SET(WM_SETTEXT) | SET(WM_GETTEXT) | SET(WM_GETTEXTLENGTH) |
154     SET(WM_WININICHANGE) | SET(WM_DEVMODECHANGE),
155     /* 0x20 - 0x3f */
156     SET(WM_CHARTOITEM),
157     /* 0x40 - 0x5f */
158     0,
159     /* 0x60 - 0x7f */
160     0,
161     /* 0x80 - 0x9f */
162     SET(WM_NCCREATE),
163     /* 0xa0 - 0xbf */
164     0,
165     /* 0xc0 - 0xdf */
166     SET(EM_REPLACESEL) | SET(EM_GETLINE) | SET(EM_SETPASSWORDCHAR),
167     /* 0xe0 - 0xff */
168     0,
169     /* 0x100 - 0x11f */
170     SET(WM_CHAR) | SET(WM_DEADCHAR) | SET(WM_SYSCHAR) | SET(WM_SYSDEADCHAR),
171     /* 0x120 - 0x13f */
172     SET(WM_MENUCHAR),
173     /* 0x140 - 0x15f */
174     SET(CB_ADDSTRING) | SET(CB_DIR) | SET(CB_GETLBTEXT) | SET(CB_GETLBTEXTLEN) |
175     SET(CB_INSERTSTRING) | SET(CB_FINDSTRING) | SET(CB_SELECTSTRING) | SET(CB_FINDSTRINGEXACT),
176     /* 0x160 - 0x17f */
177     0,
178     /* 0x180 - 0x19f */
179     SET(LB_ADDSTRING) | SET(LB_INSERTSTRING) | SET(LB_GETTEXT) | SET(LB_GETTEXTLEN) |
180     SET(LB_SELECTSTRING) | SET(LB_DIR) | SET(LB_FINDSTRING) | SET(LB_ADDFILE),
181     /* 0x1a0 - 0x1bf */
182     SET(LB_FINDSTRINGEXACT),
183     /* 0x1c0 - 0x1df */
184     0,
185     /* 0x1e0 - 0x1ff */
186     0,
187     /* 0x200 - 0x21f */
188     0,
189     /* 0x220 - 0x23f */
190     SET(WM_MDICREATE),
191     /* 0x240 - 0x25f */
192     0,
193     /* 0x260 - 0x27f */
194     0,
195     /* 0x280 - 0x29f */
196     SET(WM_IME_CHAR),
197     /* 0x2a0 - 0x2bf */
198     0,
199     /* 0x2c0 - 0x2df */
200     0,
201     /* 0x2e0 - 0x2ff */
202     0,
203     /* 0x300 - 0x31f */
204     SET(WM_PAINTCLIPBOARD) | SET(WM_SIZECLIPBOARD) | SET(WM_ASKCBFORMATNAME)
205 };
206
207 /* check whether a given message type includes pointers */
208 inline static int is_pointer_message( UINT message )
209 {
210     if (message >= 8*sizeof(message_pointer_flags)) return FALSE;
211     return (message_pointer_flags[message / 32] & SET(message)) != 0;
212 }
213
214 /* check whether a given message type contains Unicode (or ASCII) chars */
215 inline static int is_unicode_message( UINT message )
216 {
217     if (message >= 8*sizeof(message_unicode_flags)) return FALSE;
218     return (message_unicode_flags[message / 32] & SET(message)) != 0;
219 }
220
221 #undef SET
222
223 /* add a data field to a packed message */
224 inline static void push_data( struct packed_message *data, const void *ptr, size_t size )
225 {
226     data->data[data->count] = ptr;
227     data->size[data->count] = size;
228     data->count++;
229 }
230
231 /* add a string to a packed message */
232 inline static void push_string( struct packed_message *data, LPCWSTR str )
233 {
234     push_data( data, str, (strlenW(str) + 1) * sizeof(WCHAR) );
235 }
236
237 /* retrieve a pointer to data from a packed message and increment the buffer pointer */
238 inline static void *get_data( void **buffer, size_t size )
239 {
240     void *ret = *buffer;
241     *buffer = (char *)*buffer + size;
242     return ret;
243 }
244
245 /* make sure that the buffer contains a valid null-terminated Unicode string */
246 inline static BOOL check_string( LPCWSTR str, size_t size )
247 {
248     for (size /= sizeof(WCHAR); size; size--, str++)
249         if (!*str) return TRUE;
250     return FALSE;
251 }
252
253 /* make sure that there is space for 'size' bytes in buffer, growing it if needed */
254 inline static void *get_buffer_space( void **buffer, size_t size )
255 {
256     void *ret;
257
258     if (*buffer)
259     {
260         if (!(ret = HeapReAlloc( GetProcessHeap(), 0, *buffer, size )))
261             HeapFree( GetProcessHeap(), 0, *buffer );
262     }
263     else ret = HeapAlloc( GetProcessHeap(), 0, size );
264
265     *buffer = ret;
266     return ret;
267 }
268
269 /* retrieve a string pointer from packed data */
270 inline static LPWSTR get_string( void **buffer )
271 {
272     return get_data( buffer, (strlenW( (LPWSTR)*buffer ) + 1) * sizeof(WCHAR) );
273 }
274
275 /* check whether a combobox expects strings or ids in CB_ADDSTRING/CB_INSERTSTRING */
276 inline static BOOL combobox_has_strings( HWND hwnd )
277 {
278     DWORD style = GetWindowLongA( hwnd, GWL_STYLE );
279     return (!(style & (CBS_OWNERDRAWFIXED | CBS_OWNERDRAWVARIABLE)) || (style & CBS_HASSTRINGS));
280 }
281
282 /* check whether a listbox expects strings or ids in LB_ADDSTRING/LB_INSERTSTRING */
283 inline static BOOL listbox_has_strings( HWND hwnd )
284 {
285     DWORD style = GetWindowLongA( hwnd, GWL_STYLE );
286     return (!(style & (LBS_OWNERDRAWFIXED | LBS_OWNERDRAWVARIABLE)) || (style & LBS_HASSTRINGS));
287 }
288
289
290 /***********************************************************************
291  *              broadcast_message_callback
292  *
293  * Helper callback for broadcasting messages.
294  */
295 static BOOL CALLBACK broadcast_message_callback( HWND hwnd, LPARAM lparam )
296 {
297     struct send_message_info *info = (struct send_message_info *)lparam;
298     if (!(GetWindowLongW( hwnd, GWL_STYLE ) & (WS_POPUP|WS_CAPTION))) return TRUE;
299     switch(info->type)
300     {
301     case MSG_UNICODE:
302         SendMessageTimeoutW( hwnd, info->msg, info->wparam, info->lparam,
303                              info->flags, info->timeout, NULL );
304         break;
305     case MSG_ASCII:
306         SendMessageTimeoutA( hwnd, info->msg, info->wparam, info->lparam,
307                              info->flags, info->timeout, NULL );
308         break;
309     case MSG_NOTIFY:
310         SendNotifyMessageW( hwnd, info->msg, info->wparam, info->lparam );
311         break;
312     case MSG_CALLBACK:
313         SendMessageCallbackW( hwnd, info->msg, info->wparam, info->lparam,
314                               info->callback, info->data );
315         break;
316     case MSG_POSTED:
317         PostMessageW( hwnd, info->msg, info->wparam, info->lparam );
318         break;
319     default:
320         ERR( "bad type %d\n", info->type );
321         break;
322     }
323     return TRUE;
324 }
325
326
327 /***********************************************************************
328  *              map_wparam_AtoW
329  *
330  * Convert the wparam of an ASCII message to Unicode.
331  */
332 static WPARAM map_wparam_AtoW( UINT message, WPARAM wparam )
333 {
334     switch(message)
335     {
336     case WM_CHARTOITEM:
337     case EM_SETPASSWORDCHAR:
338     case WM_CHAR:
339     case WM_DEADCHAR:
340     case WM_SYSCHAR:
341     case WM_SYSDEADCHAR:
342     case WM_MENUCHAR:
343         {
344             char ch = LOWORD(wparam);
345             WCHAR wch;
346             MultiByteToWideChar(CP_ACP, 0, &ch, 1, &wch, 1);
347             wparam = MAKEWPARAM( wch, HIWORD(wparam) );
348         }
349         break;
350     case WM_IME_CHAR:
351         {
352             char ch[2];
353             WCHAR wch;
354             ch[0] = (wparam >> 8);
355             ch[1] = (wparam & 0xff);
356             if (ch[0]) MultiByteToWideChar(CP_ACP, 0, ch, 2, &wch, 1);
357             else MultiByteToWideChar(CP_ACP, 0, &ch[1], 1, &wch, 1);
358             wparam = MAKEWPARAM( wch, HIWORD(wparam) );
359         }
360         break;
361     }
362     return wparam;
363 }
364
365
366 /***********************************************************************
367  *              map_wparam_WtoA
368  *
369  * Convert the wparam of a Unicode message to ASCII.
370  */
371 static WPARAM map_wparam_WtoA( UINT message, WPARAM wparam )
372 {
373     switch(message)
374     {
375     case WM_CHARTOITEM:
376     case EM_SETPASSWORDCHAR:
377     case WM_CHAR:
378     case WM_DEADCHAR:
379     case WM_SYSCHAR:
380     case WM_SYSDEADCHAR:
381     case WM_MENUCHAR:
382         {
383             WCHAR wch = LOWORD(wparam);
384             BYTE ch;
385             WideCharToMultiByte( CP_ACP, 0, &wch, 1, &ch, 1, NULL, NULL );
386             wparam = MAKEWPARAM( ch, HIWORD(wparam) );
387         }
388         break;
389     case WM_IME_CHAR:
390         {
391             WCHAR wch = LOWORD(wparam);
392             BYTE ch[2];
393
394             if (WideCharToMultiByte( CP_ACP, 0, &wch, 1, ch, 2, NULL, NULL ) == 2)
395                 wparam = MAKEWPARAM( (ch[0] << 8) | ch[1], HIWORD(wparam) );
396             else
397                 wparam = MAKEWPARAM( ch[0], HIWORD(wparam) );
398         }
399         break;
400     }
401     return wparam;
402 }
403
404
405 /***********************************************************************
406  *              pack_message
407  *
408  * Pack a message for sending to another process.
409  * Return the size of the data we expect in the message reply.
410  * Set data->count to -1 if there is an error.
411  */
412 static size_t pack_message( HWND hwnd, UINT message, WPARAM wparam, LPARAM lparam,
413                             struct packed_message *data )
414 {
415     data->count = 0;
416     switch(message)
417     {
418     case WM_NCCREATE:
419     case WM_CREATE:
420     {
421         CREATESTRUCTW *cs = (CREATESTRUCTW *)lparam;
422         push_data( data, cs, sizeof(*cs) );
423         if (HIWORD(cs->lpszName)) push_string( data, cs->lpszName );
424         if (HIWORD(cs->lpszClass)) push_string( data, cs->lpszClass );
425         return sizeof(*cs);
426     }
427     case WM_GETTEXT:
428     case WM_ASKCBFORMATNAME:
429         return wparam * sizeof(WCHAR);
430     case WM_WININICHANGE:
431         if (lparam) push_string(data, (LPWSTR)lparam );
432         return 0;
433     case WM_SETTEXT:
434     case WM_DEVMODECHANGE:
435     case CB_DIR:
436     case LB_DIR:
437     case LB_ADDFILE:
438     case EM_REPLACESEL:
439         push_string( data, (LPWSTR)lparam );
440         return 0;
441     case WM_GETMINMAXINFO:
442         push_data( data, (MINMAXINFO *)lparam, sizeof(MINMAXINFO) );
443         return sizeof(MINMAXINFO);
444     case WM_DRAWITEM:
445         push_data( data, (DRAWITEMSTRUCT *)lparam, sizeof(DRAWITEMSTRUCT) );
446         return 0;
447     case WM_MEASUREITEM:
448         push_data( data, (MEASUREITEMSTRUCT *)lparam, sizeof(MEASUREITEMSTRUCT) );
449         return sizeof(MEASUREITEMSTRUCT);
450     case WM_DELETEITEM:
451         push_data( data, (DELETEITEMSTRUCT *)lparam, sizeof(DELETEITEMSTRUCT) );
452         return 0;
453     case WM_COMPAREITEM:
454         push_data( data, (COMPAREITEMSTRUCT *)lparam, sizeof(COMPAREITEMSTRUCT) );
455         return 0;
456     case WM_WINDOWPOSCHANGING:
457     case WM_WINDOWPOSCHANGED:
458         push_data( data, (WINDOWPOS *)lparam, sizeof(WINDOWPOS) );
459         return sizeof(WINDOWPOS);
460     case WM_COPYDATA:
461     {
462         COPYDATASTRUCT *cp = (COPYDATASTRUCT *)lparam;
463         push_data( data, cp, sizeof(*cp) );
464         if (cp->lpData) push_data( data, cp->lpData, cp->cbData );
465         return 0;
466     }
467     case WM_NOTIFY:
468         /* WM_NOTIFY cannot be sent across processes (MSDN) */
469         data->count = -1;
470         return 0;
471     case WM_HELP:
472         push_data( data, (HELPINFO *)lparam, sizeof(HELPINFO) );
473         return 0;
474     case WM_STYLECHANGING:
475     case WM_STYLECHANGED:
476         push_data( data, (STYLESTRUCT *)lparam, sizeof(STYLESTRUCT) );
477         return 0;
478     case WM_NCCALCSIZE:
479         if (!wparam)
480         {
481             push_data( data, (RECT *)lparam, sizeof(RECT) );
482             return sizeof(RECT);
483         }
484         else
485         {
486             NCCALCSIZE_PARAMS *nc = (NCCALCSIZE_PARAMS *)lparam;
487             push_data( data, nc, sizeof(*nc) );
488             push_data( data, nc->lppos, sizeof(*nc->lppos) );
489             return sizeof(*nc) + sizeof(*nc->lppos);
490         }
491     case WM_GETDLGCODE:
492         if (lparam) push_data( data, (MSG *)lparam, sizeof(MSG) );
493         return sizeof(MSG);
494     case SBM_SETSCROLLINFO:
495         push_data( data, (SCROLLINFO *)lparam, sizeof(SCROLLINFO) );
496         return 0;
497     case SBM_GETSCROLLINFO:
498         push_data( data, (SCROLLINFO *)lparam, sizeof(SCROLLINFO) );
499         return sizeof(SCROLLINFO);
500     case EM_GETSEL:
501     case SBM_GETRANGE:
502     case CB_GETEDITSEL:
503     {
504         size_t size = 0;
505         if (wparam) size += sizeof(DWORD);
506         if (lparam) size += sizeof(DWORD);
507         return size;
508     }
509     case EM_GETRECT:
510     case LB_GETITEMRECT:
511     case CB_GETDROPPEDCONTROLRECT:
512         return sizeof(RECT);
513     case EM_SETRECT:
514     case EM_SETRECTNP:
515         push_data( data, (RECT *)lparam, sizeof(RECT) );
516         return 0;
517     case EM_GETLINE:
518     {
519         WORD *pw = (WORD *)lparam;
520         push_data( data, pw, sizeof(*pw) );
521         return *pw * sizeof(WCHAR);
522     }
523     case EM_SETTABSTOPS:
524     case LB_SETTABSTOPS:
525         if (wparam) push_data( data, (UINT *)lparam, sizeof(UINT) * wparam );
526         return 0;
527     case CB_ADDSTRING:
528     case CB_INSERTSTRING:
529     case CB_FINDSTRING:
530     case CB_FINDSTRINGEXACT:
531     case CB_SELECTSTRING:
532         if (combobox_has_strings( hwnd )) push_string( data, (LPWSTR)lparam );
533         return 0;
534     case CB_GETLBTEXT:
535         if (!combobox_has_strings( hwnd )) return sizeof(ULONG_PTR);
536         return (SendMessageW( hwnd, CB_GETLBTEXTLEN, wparam, 0 ) + 1) * sizeof(WCHAR);
537     case LB_ADDSTRING:
538     case LB_INSERTSTRING:
539     case LB_FINDSTRING:
540     case LB_FINDSTRINGEXACT:
541     case LB_SELECTSTRING:
542         if (listbox_has_strings( hwnd )) push_string( data, (LPWSTR)lparam );
543         return 0;
544     case LB_GETTEXT:
545         if (!listbox_has_strings( hwnd )) return sizeof(ULONG_PTR);
546         return (SendMessageW( hwnd, LB_GETTEXTLEN, wparam, 0 ) + 1) * sizeof(WCHAR);
547     case LB_GETSELITEMS:
548         return wparam * sizeof(UINT);
549     case WM_NEXTMENU:
550         push_data( data, (MDINEXTMENU *)lparam, sizeof(MDINEXTMENU) );
551         return sizeof(MDINEXTMENU);
552     case WM_SIZING:
553     case WM_MOVING:
554         push_data( data, (RECT *)lparam, sizeof(RECT) );
555         return sizeof(RECT);
556     case WM_MDICREATE:
557     {
558         MDICREATESTRUCTW *cs = (MDICREATESTRUCTW *)lparam;
559         push_data( data, cs, sizeof(*cs) );
560         if (HIWORD(cs->szTitle)) push_string( data, cs->szTitle );
561         if (HIWORD(cs->szClass)) push_string( data, cs->szClass );
562         return sizeof(*cs);
563     }
564     case WM_MDIGETACTIVE:
565         if (lparam) return sizeof(BOOL);
566         return 0;
567     case WM_WINE_SETWINDOWPOS:
568         push_data( data, (WINDOWPOS *)lparam, sizeof(WINDOWPOS) );
569         return 0;
570     case WM_WINE_KEYBOARD_LL_HOOK:
571         push_data( data, (KBDLLHOOKSTRUCT *)lparam, sizeof(KBDLLHOOKSTRUCT) );
572         return 0;
573     case WM_WINE_MOUSE_LL_HOOK:
574         push_data( data, (MSLLHOOKSTRUCT *)lparam, sizeof(MSLLHOOKSTRUCT) );
575         return 0;
576
577     /* these contain an HFONT */
578     case WM_SETFONT:
579     case WM_GETFONT:
580     /* these contain an HDC */
581     case WM_PAINT:
582     case WM_ERASEBKGND:
583     case WM_ICONERASEBKGND:
584     case WM_NCPAINT:
585     case WM_CTLCOLORMSGBOX:
586     case WM_CTLCOLOREDIT:
587     case WM_CTLCOLORLISTBOX:
588     case WM_CTLCOLORBTN:
589     case WM_CTLCOLORDLG:
590     case WM_CTLCOLORSCROLLBAR:
591     case WM_CTLCOLORSTATIC:
592     case WM_PRINT:
593     case WM_PRINTCLIENT:
594     /* these contain an HGLOBAL */
595     case WM_PAINTCLIPBOARD:
596     case WM_SIZECLIPBOARD:
597     /* these contain HICON */
598     case WM_GETICON:
599     case WM_SETICON:
600     case WM_QUERYDRAGICON:
601     case WM_QUERYPARKICON:
602     /* these contain pointers */
603     case WM_DROPOBJECT:
604     case WM_QUERYDROPOBJECT:
605     case WM_DRAGLOOP:
606     case WM_DRAGSELECT:
607     case WM_DRAGMOVE:
608     case WM_DEVICECHANGE:
609         FIXME( "msg %x (%s) not supported yet\n", message, SPY_GetMsgName(message, hwnd) );
610         data->count = -1;
611         return 0;
612     }
613     return 0;
614 }
615
616
617 /***********************************************************************
618  *              unpack_message
619  *
620  * Unpack a message received from another process.
621  */
622 static BOOL unpack_message( HWND hwnd, UINT message, WPARAM *wparam, LPARAM *lparam,
623                             void **buffer, size_t size )
624 {
625     size_t minsize = 0;
626
627     switch(message)
628     {
629     case WM_NCCREATE:
630     case WM_CREATE:
631     {
632         CREATESTRUCTW *cs = *buffer;
633         WCHAR *str = (WCHAR *)(cs + 1);
634         if (size < sizeof(*cs)) return FALSE;
635         size -= sizeof(*cs);
636         if (HIWORD(cs->lpszName))
637         {
638             if (!check_string( str, size )) return FALSE;
639             cs->lpszName = str;
640             size -= (strlenW(str) + 1) * sizeof(WCHAR);
641             str += strlenW(str) + 1;
642         }
643         if (HIWORD(cs->lpszClass))
644         {
645             if (!check_string( str, size )) return FALSE;
646             cs->lpszClass = str;
647         }
648         break;
649     }
650     case WM_GETTEXT:
651     case WM_ASKCBFORMATNAME:
652         if (!get_buffer_space( buffer, (*wparam * sizeof(WCHAR)) )) return FALSE;
653         break;
654     case WM_WININICHANGE:
655         if (!*lparam) return TRUE;
656         /* fall through */
657     case WM_SETTEXT:
658     case WM_DEVMODECHANGE:
659     case CB_DIR:
660     case LB_DIR:
661     case LB_ADDFILE:
662     case EM_REPLACESEL:
663         if (!check_string( *buffer, size )) return FALSE;
664         break;
665     case WM_GETMINMAXINFO:
666         minsize = sizeof(MINMAXINFO);
667         break;
668     case WM_DRAWITEM:
669         minsize = sizeof(DRAWITEMSTRUCT);
670         break;
671     case WM_MEASUREITEM:
672         minsize = sizeof(MEASUREITEMSTRUCT);
673         break;
674     case WM_DELETEITEM:
675         minsize = sizeof(DELETEITEMSTRUCT);
676         break;
677     case WM_COMPAREITEM:
678         minsize = sizeof(COMPAREITEMSTRUCT);
679         break;
680     case WM_WINDOWPOSCHANGING:
681     case WM_WINDOWPOSCHANGED:
682     case WM_WINE_SETWINDOWPOS:
683         minsize = sizeof(WINDOWPOS);
684         break;
685     case WM_COPYDATA:
686     {
687         COPYDATASTRUCT *cp = *buffer;
688         if (size < sizeof(*cp)) return FALSE;
689         if (cp->lpData)
690         {
691             minsize = sizeof(*cp) + cp->cbData;
692             cp->lpData = cp + 1;
693         }
694         break;
695     }
696     case WM_NOTIFY:
697         /* WM_NOTIFY cannot be sent across processes (MSDN) */
698         return FALSE;
699     case WM_HELP:
700         minsize = sizeof(HELPINFO);
701         break;
702     case WM_STYLECHANGING:
703     case WM_STYLECHANGED:
704         minsize = sizeof(STYLESTRUCT);
705         break;
706     case WM_NCCALCSIZE:
707         if (!*wparam) minsize = sizeof(RECT);
708         else
709         {
710             NCCALCSIZE_PARAMS *nc = *buffer;
711             if (size < sizeof(*nc) + sizeof(*nc->lppos)) return FALSE;
712             nc->lppos = (WINDOWPOS *)(nc + 1);
713         }
714         break;
715     case WM_GETDLGCODE:
716         if (!*lparam) return TRUE;
717         minsize = sizeof(MSG);
718         break;
719     case SBM_SETSCROLLINFO:
720         minsize = sizeof(SCROLLINFO);
721         break;
722     case SBM_GETSCROLLINFO:
723         if (!get_buffer_space( buffer, sizeof(SCROLLINFO ))) return FALSE;
724         break;
725     case EM_GETSEL:
726     case SBM_GETRANGE:
727     case CB_GETEDITSEL:
728         if (*wparam || *lparam)
729         {
730             if (!get_buffer_space( buffer, 2*sizeof(DWORD) )) return FALSE;
731             if (*wparam) *wparam = (WPARAM)*buffer;
732             if (*lparam) *lparam = (LPARAM)((DWORD *)*buffer + 1);
733         }
734         return TRUE;
735     case EM_GETRECT:
736     case LB_GETITEMRECT:
737     case CB_GETDROPPEDCONTROLRECT:
738         if (!get_buffer_space( buffer, sizeof(RECT) )) return FALSE;
739         break;
740     case EM_SETRECT:
741     case EM_SETRECTNP:
742         minsize = sizeof(RECT);
743         break;
744     case EM_GETLINE:
745     {
746         WORD len;
747         if (size < sizeof(WORD)) return FALSE;
748         len = *(WORD *)*buffer;
749         if (!get_buffer_space( buffer, (len + 1) * sizeof(WCHAR) )) return FALSE;
750         *lparam = (LPARAM)*buffer + sizeof(WORD);  /* don't erase WORD at start of buffer */
751         return TRUE;
752     }
753     case EM_SETTABSTOPS:
754     case LB_SETTABSTOPS:
755         if (!*wparam) return TRUE;
756         minsize = *wparam * sizeof(UINT);
757         break;
758     case CB_ADDSTRING:
759     case CB_INSERTSTRING:
760     case CB_FINDSTRING:
761     case CB_FINDSTRINGEXACT:
762     case CB_SELECTSTRING:
763     case LB_ADDSTRING:
764     case LB_INSERTSTRING:
765     case LB_FINDSTRING:
766     case LB_FINDSTRINGEXACT:
767     case LB_SELECTSTRING:
768         if (!*buffer) return TRUE;
769         if (!check_string( *buffer, size )) return FALSE;
770         break;
771     case CB_GETLBTEXT:
772     {
773         size = sizeof(ULONG_PTR);
774         if (combobox_has_strings( hwnd ))
775             size = (SendMessageW( hwnd, CB_GETLBTEXTLEN, *wparam, 0 ) + 1) * sizeof(WCHAR);
776         if (!get_buffer_space( buffer, size )) return FALSE;
777         break;
778     }
779     case LB_GETTEXT:
780     {
781         size = sizeof(ULONG_PTR);
782         if (listbox_has_strings( hwnd ))
783             size = (SendMessageW( hwnd, LB_GETTEXTLEN, *wparam, 0 ) + 1) * sizeof(WCHAR);
784         if (!get_buffer_space( buffer, size )) return FALSE;
785         break;
786     }
787     case LB_GETSELITEMS:
788         if (!get_buffer_space( buffer, *wparam * sizeof(UINT) )) return FALSE;
789         break;
790     case WM_NEXTMENU:
791         minsize = sizeof(MDINEXTMENU);
792         if (!get_buffer_space( buffer, sizeof(MDINEXTMENU) )) return FALSE;
793         break;
794     case WM_SIZING:
795     case WM_MOVING:
796         minsize = sizeof(RECT);
797         if (!get_buffer_space( buffer, sizeof(RECT) )) return FALSE;
798         break;
799     case WM_MDICREATE:
800     {
801         MDICREATESTRUCTW *cs = *buffer;
802         WCHAR *str = (WCHAR *)(cs + 1);
803         if (size < sizeof(*cs)) return FALSE;
804         size -= sizeof(*cs);
805         if (HIWORD(cs->szTitle))
806         {
807             if (!check_string( str, size )) return FALSE;
808             cs->szTitle = str;
809             size -= (strlenW(str) + 1) * sizeof(WCHAR);
810             str += strlenW(str) + 1;
811         }
812         if (HIWORD(cs->szClass))
813         {
814             if (!check_string( str, size )) return FALSE;
815             cs->szClass = str;
816         }
817         break;
818     }
819     case WM_MDIGETACTIVE:
820         if (!*lparam) return TRUE;
821         if (!get_buffer_space( buffer, sizeof(BOOL) )) return FALSE;
822         break;
823     case WM_WINE_KEYBOARD_LL_HOOK:
824         minsize = sizeof(KBDLLHOOKSTRUCT);
825         break;
826     case WM_WINE_MOUSE_LL_HOOK:
827         minsize = sizeof(MSLLHOOKSTRUCT);
828         break;
829
830     /* these contain an HFONT */
831     case WM_SETFONT:
832     case WM_GETFONT:
833     /* these contain an HDC */
834     case WM_PAINT:
835     case WM_ERASEBKGND:
836     case WM_ICONERASEBKGND:
837     case WM_NCPAINT:
838     case WM_CTLCOLORMSGBOX:
839     case WM_CTLCOLOREDIT:
840     case WM_CTLCOLORLISTBOX:
841     case WM_CTLCOLORBTN:
842     case WM_CTLCOLORDLG:
843     case WM_CTLCOLORSCROLLBAR:
844     case WM_CTLCOLORSTATIC:
845     case WM_PRINT:
846     case WM_PRINTCLIENT:
847     /* these contain an HGLOBAL */
848     case WM_PAINTCLIPBOARD:
849     case WM_SIZECLIPBOARD:
850     /* these contain HICON */
851     case WM_GETICON:
852     case WM_SETICON:
853     case WM_QUERYDRAGICON:
854     case WM_QUERYPARKICON:
855     /* these contain pointers */
856     case WM_DROPOBJECT:
857     case WM_QUERYDROPOBJECT:
858     case WM_DRAGLOOP:
859     case WM_DRAGSELECT:
860     case WM_DRAGMOVE:
861     case WM_DEVICECHANGE:
862         FIXME( "msg %x (%s) not supported yet\n", message, SPY_GetMsgName(message, hwnd) );
863         return FALSE;
864
865     default:
866         return TRUE; /* message doesn't need any unpacking */
867     }
868
869     /* default exit for most messages: check minsize and store buffer in lparam */
870     if (size < minsize) return FALSE;
871     *lparam = (LPARAM)*buffer;
872     return TRUE;
873 }
874
875
876 /***********************************************************************
877  *              pack_reply
878  *
879  * Pack a reply to a message for sending to another process.
880  */
881 static void pack_reply( HWND hwnd, UINT message, WPARAM wparam, LPARAM lparam,
882                         LRESULT res, struct packed_message *data )
883 {
884     data->count = 0;
885     switch(message)
886     {
887     case WM_NCCREATE:
888     case WM_CREATE:
889         push_data( data, (CREATESTRUCTW *)lparam, sizeof(CREATESTRUCTW) );
890         break;
891     case WM_GETTEXT:
892     case CB_GETLBTEXT:
893     case LB_GETTEXT:
894         push_data( data, (WCHAR *)lparam, (res + 1) * sizeof(WCHAR) );
895         break;
896     case WM_GETMINMAXINFO:
897         push_data( data, (MINMAXINFO *)lparam, sizeof(MINMAXINFO) );
898         break;
899     case WM_MEASUREITEM:
900         push_data( data, (MEASUREITEMSTRUCT *)lparam, sizeof(MEASUREITEMSTRUCT) );
901         break;
902     case WM_WINDOWPOSCHANGING:
903     case WM_WINDOWPOSCHANGED:
904         push_data( data, (WINDOWPOS *)lparam, sizeof(WINDOWPOS) );
905         break;
906     case WM_GETDLGCODE:
907         if (lparam) push_data( data, (MSG *)lparam, sizeof(MSG) );
908         break;
909     case SBM_GETSCROLLINFO:
910         push_data( data, (SCROLLINFO *)lparam, sizeof(SCROLLINFO) );
911         break;
912     case EM_GETRECT:
913     case LB_GETITEMRECT:
914     case CB_GETDROPPEDCONTROLRECT:
915     case WM_SIZING:
916     case WM_MOVING:
917         push_data( data, (RECT *)lparam, sizeof(RECT) );
918         break;
919     case EM_GETLINE:
920     {
921         WORD *ptr = (WORD *)lparam;
922         push_data( data, ptr, ptr[-1] * sizeof(WCHAR) );
923         break;
924     }
925     case LB_GETSELITEMS:
926         push_data( data, (UINT *)lparam, wparam * sizeof(UINT) );
927         break;
928     case WM_MDIGETACTIVE:
929         if (lparam) push_data( data, (BOOL *)lparam, sizeof(BOOL) );
930         break;
931     case WM_NCCALCSIZE:
932         if (!wparam)
933             push_data( data, (RECT *)lparam, sizeof(RECT) );
934         else
935         {
936             NCCALCSIZE_PARAMS *nc = (NCCALCSIZE_PARAMS *)lparam;
937             push_data( data, nc, sizeof(*nc) );
938             push_data( data, nc->lppos, sizeof(*nc->lppos) );
939         }
940         break;
941     case EM_GETSEL:
942     case SBM_GETRANGE:
943     case CB_GETEDITSEL:
944         if (wparam) push_data( data, (DWORD *)wparam, sizeof(DWORD) );
945         if (lparam) push_data( data, (DWORD *)lparam, sizeof(DWORD) );
946         break;
947     case WM_NEXTMENU:
948         push_data( data, (MDINEXTMENU *)lparam, sizeof(MDINEXTMENU) );
949         break;
950     case WM_MDICREATE:
951         push_data( data, (MDICREATESTRUCTW *)lparam, sizeof(MDICREATESTRUCTW) );
952         break;
953     case WM_ASKCBFORMATNAME:
954         push_data( data, (WCHAR *)lparam, (strlenW((WCHAR *)lparam) + 1) * sizeof(WCHAR) );
955         break;
956     }
957 }
958
959
960 /***********************************************************************
961  *              unpack_reply
962  *
963  * Unpack a message reply received from another process.
964  */
965 static void unpack_reply( HWND hwnd, UINT message, WPARAM wparam, LPARAM lparam,
966                           void *buffer, size_t size )
967 {
968     switch(message)
969     {
970     case WM_NCCREATE:
971     case WM_CREATE:
972     {
973         CREATESTRUCTW *cs = (CREATESTRUCTW *)lparam;
974         LPCWSTR name = cs->lpszName, class = cs->lpszClass;
975         memcpy( cs, buffer, min( sizeof(*cs), size ));
976         cs->lpszName = name;  /* restore the original pointers */
977         cs->lpszClass = class;
978         break;
979     }
980     case WM_GETTEXT:
981     case WM_ASKCBFORMATNAME:
982         memcpy( (WCHAR *)lparam, buffer, min( wparam*sizeof(WCHAR), size ));
983         break;
984     case WM_GETMINMAXINFO:
985         memcpy( (MINMAXINFO *)lparam, buffer, min( sizeof(MINMAXINFO), size ));
986         break;
987     case WM_MEASUREITEM:
988         memcpy( (MEASUREITEMSTRUCT *)lparam, buffer, min( sizeof(MEASUREITEMSTRUCT), size ));
989         break;
990     case WM_WINDOWPOSCHANGING:
991     case WM_WINDOWPOSCHANGED:
992         memcpy( (WINDOWPOS *)lparam, buffer, min( sizeof(WINDOWPOS), size ));
993         break;
994     case WM_GETDLGCODE:
995         if (lparam) memcpy( (MSG *)lparam, buffer, min( sizeof(MSG), size ));
996         break;
997     case SBM_GETSCROLLINFO:
998         memcpy( (SCROLLINFO *)lparam, buffer, min( sizeof(SCROLLINFO), size ));
999         break;
1000     case EM_GETRECT:
1001     case CB_GETDROPPEDCONTROLRECT:
1002     case LB_GETITEMRECT:
1003     case WM_SIZING:
1004     case WM_MOVING:
1005         memcpy( (RECT *)lparam, buffer, min( sizeof(RECT), size ));
1006         break;
1007     case EM_GETLINE:
1008         size = min( size, (size_t)*(WORD *)lparam );
1009         memcpy( (WCHAR *)lparam, buffer, size );
1010         break;
1011     case LB_GETSELITEMS:
1012         memcpy( (UINT *)lparam, buffer, min( wparam*sizeof(UINT), size ));
1013         break;
1014     case LB_GETTEXT:
1015     case CB_GETLBTEXT:
1016         memcpy( (WCHAR *)lparam, buffer, size );
1017         break;
1018     case WM_NEXTMENU:
1019         memcpy( (MDINEXTMENU *)lparam, buffer, min( sizeof(MDINEXTMENU), size ));
1020         break;
1021     case WM_MDIGETACTIVE:
1022         if (lparam) memcpy( (BOOL *)lparam, buffer, min( sizeof(BOOL), size ));
1023         break;
1024     case WM_NCCALCSIZE:
1025         if (!wparam)
1026             memcpy( (RECT *)lparam, buffer, min( sizeof(RECT), size ));
1027         else
1028         {
1029             NCCALCSIZE_PARAMS *nc = (NCCALCSIZE_PARAMS *)lparam;
1030             WINDOWPOS *wp = nc->lppos;
1031             memcpy( nc, buffer, min( sizeof(*nc), size ));
1032             if (size > sizeof(*nc))
1033             {
1034                 size -= sizeof(*nc);
1035                 memcpy( wp, (NCCALCSIZE_PARAMS*)buffer + 1, min( sizeof(*wp), size ));
1036             }
1037             nc->lppos = wp;  /* restore the original pointer */
1038         }
1039         break;
1040     case EM_GETSEL:
1041     case SBM_GETRANGE:
1042     case CB_GETEDITSEL:
1043         if (wparam)
1044         {
1045             memcpy( (DWORD *)wparam, buffer, min( sizeof(DWORD), size ));
1046             if (size <= sizeof(DWORD)) break;
1047             size -= sizeof(DWORD);
1048             buffer = (DWORD *)buffer + 1;
1049         }
1050         if (lparam) memcpy( (DWORD *)lparam, buffer, min( sizeof(DWORD), size ));
1051         break;
1052     case WM_MDICREATE:
1053     {
1054         MDICREATESTRUCTW *cs = (MDICREATESTRUCTW *)lparam;
1055         LPCWSTR title = cs->szTitle, class = cs->szClass;
1056         memcpy( cs, buffer, min( sizeof(*cs), size ));
1057         cs->szTitle = title;  /* restore the original pointers */
1058         cs->szClass = class;
1059         break;
1060     }
1061     default:
1062         ERR( "should not happen: unexpected message %x\n", message );
1063         break;
1064     }
1065 }
1066
1067
1068 /***********************************************************************
1069  *           reply_message
1070  *
1071  * Send a reply to a sent message.
1072  */
1073 static void reply_message( struct received_message_info *info, LRESULT result, BOOL remove )
1074 {
1075     struct packed_message data;
1076     int i, replied = info->flags & ISMEX_REPLIED;
1077
1078     if (info->flags & ISMEX_NOTIFY) return;  /* notify messages don't get replies */
1079     if (!remove && replied) return;  /* replied already */
1080
1081     data.count = 0;
1082     info->flags |= ISMEX_REPLIED;
1083
1084     if (info->type == MSG_OTHER_PROCESS && !replied)
1085     {
1086         pack_reply( info->msg.hwnd, info->msg.message, info->msg.wParam,
1087                     info->msg.lParam, result, &data );
1088     }
1089
1090     SERVER_START_REQ( reply_message )
1091     {
1092         req->type   = info->type;
1093         req->result = result;
1094         req->remove = remove;
1095         for (i = 0; i < data.count; i++) wine_server_add_data( req, data.data[i], data.size[i] );
1096         wine_server_call( req );
1097     }
1098     SERVER_END_REQ;
1099 }
1100
1101
1102 /***********************************************************************
1103  *           handle_internal_message
1104  *
1105  * Handle an internal Wine message instead of calling the window proc.
1106  */
1107 static LRESULT handle_internal_message( HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam )
1108 {
1109     if (hwnd == GetDesktopWindow()) return 0;
1110     switch(msg)
1111     {
1112     case WM_WINE_DESTROYWINDOW:
1113         return WIN_DestroyWindow( hwnd );
1114     case WM_WINE_SETWINDOWPOS:
1115         return USER_Driver.pSetWindowPos( (WINDOWPOS *)lparam );
1116     case WM_WINE_SHOWWINDOW:
1117         return ShowWindow( hwnd, wparam );
1118     case WM_WINE_SETPARENT:
1119         return (LRESULT)SetParent( hwnd, (HWND)wparam );
1120     case WM_WINE_SETWINDOWLONG:
1121         return (LRESULT)SetWindowLongW( hwnd, wparam, lparam );
1122     case WM_WINE_ENABLEWINDOW:
1123         return EnableWindow( hwnd, wparam );
1124     case WM_WINE_SETACTIVEWINDOW:
1125         return (LRESULT)SetActiveWindow( (HWND)wparam );
1126     case WM_WINE_KEYBOARD_LL_HOOK:
1127         return HOOK_CallHooks( WH_KEYBOARD_LL, HC_ACTION, wparam, lparam, TRUE );
1128     case WM_WINE_MOUSE_LL_HOOK:
1129         return HOOK_CallHooks( WH_MOUSE_LL, HC_ACTION, wparam, lparam, TRUE );
1130     default:
1131         FIXME( "unknown internal message %x\n", msg );
1132         return 0;
1133     }
1134 }
1135
1136 /* since the WM_DDE_ACK response to a WM_DDE_EXECUTE message should contain the handle
1137  * to the memory handle, we keep track (in the server side) of all pairs of handle
1138  * used (the client passes its value and the content of the memory handle), and
1139  * the server stored both values (the client, and the local one, created after the
1140  * content). When a ACK message is generated, the list of pair is searched for a
1141  * matching pair, so that the client memory handle can be returned.
1142  */
1143 struct DDE_pair {
1144     HGLOBAL     client_hMem;
1145     HGLOBAL     server_hMem;
1146 };
1147
1148 static      struct DDE_pair*    dde_pairs;
1149 static      int                 dde_num_alloc;
1150 static      int                 dde_num_used;
1151
1152 static CRITICAL_SECTION dde_crst;
1153 static CRITICAL_SECTION_DEBUG critsect_debug =
1154 {
1155     0, 0, &dde_crst,
1156     { &critsect_debug.ProcessLocksList, &critsect_debug.ProcessLocksList },
1157       0, 0, { 0, (DWORD)(__FILE__ ": dde_crst") }
1158 };
1159 static CRITICAL_SECTION dde_crst = { &critsect_debug, -1, 0, 0, 0, 0 };
1160
1161 static BOOL dde_add_pair(HGLOBAL chm, HGLOBAL shm)
1162 {
1163     int  i;
1164 #define GROWBY  4
1165
1166     EnterCriticalSection(&dde_crst);
1167
1168     /* now remember the pair of hMem on both sides */
1169     if (dde_num_used == dde_num_alloc)
1170     {
1171         struct DDE_pair* tmp;
1172         if (dde_pairs)
1173             tmp  = HeapReAlloc( GetProcessHeap(), 0, dde_pairs,
1174                                             (dde_num_alloc + GROWBY) * sizeof(struct DDE_pair));
1175         else
1176             tmp  = HeapAlloc( GetProcessHeap(), 0, 
1177                                             (dde_num_alloc + GROWBY) * sizeof(struct DDE_pair));
1178
1179         if (!tmp)
1180         {
1181             LeaveCriticalSection(&dde_crst);
1182             return FALSE;
1183         }
1184         dde_pairs = tmp;
1185         /* zero out newly allocated part */
1186         memset(&dde_pairs[dde_num_alloc], 0, GROWBY * sizeof(struct DDE_pair));
1187         dde_num_alloc += GROWBY;
1188     }
1189 #undef GROWBY
1190     for (i = 0; i < dde_num_alloc; i++)
1191     {
1192         if (dde_pairs[i].server_hMem == 0)
1193         {
1194             dde_pairs[i].client_hMem = chm;
1195             dde_pairs[i].server_hMem = shm;
1196             dde_num_used++;
1197             break;
1198         }
1199     }
1200     LeaveCriticalSection(&dde_crst);
1201     return TRUE;
1202 }
1203
1204 static HGLOBAL dde_get_pair(HGLOBAL shm)
1205 {
1206     int  i;
1207     HGLOBAL     ret = 0;
1208
1209     EnterCriticalSection(&dde_crst);
1210     for (i = 0; i < dde_num_alloc; i++)
1211     {
1212         if (dde_pairs[i].server_hMem == shm)
1213         {
1214             /* free this pair */
1215             dde_pairs[i].server_hMem = 0;
1216             dde_num_used--;
1217             ret = dde_pairs[i].client_hMem;
1218             break;
1219         }
1220     }
1221     LeaveCriticalSection(&dde_crst);
1222     return ret;
1223 }
1224
1225 /***********************************************************************
1226  *              post_dde_message
1227  *
1228  * Post a DDE message
1229  */
1230 static BOOL post_dde_message( DWORD dest_tid, struct packed_message *data, const struct send_message_info *info )
1231 {
1232     void*       ptr = NULL;
1233     int         size = 0;
1234     UINT        uiLo, uiHi;
1235     LPARAM      lp = 0;
1236     HGLOBAL     hunlock = 0;
1237     int         i;
1238     DWORD       res;
1239
1240     if (!UnpackDDElParam( info->msg, info->lparam, &uiLo, &uiHi ))
1241         return FALSE;
1242
1243     lp = info->lparam;
1244     switch (info->msg)
1245     {
1246         /* DDE messages which don't require packing are:
1247          * WM_DDE_INITIATE
1248          * WM_DDE_TERMINATE
1249          * WM_DDE_REQUEST
1250          * WM_DDE_UNADVISE
1251          */
1252     case WM_DDE_ACK:
1253         if (HIWORD(uiHi))
1254         {
1255             /* uiHi should contain a hMem from WM_DDE_EXECUTE */
1256             HGLOBAL h = dde_get_pair( (HANDLE)uiHi );
1257             if (h)
1258             {
1259                 /* send back the value of h on the other side */
1260                 push_data( data, &h, sizeof(HGLOBAL) );
1261                 lp = uiLo;
1262                 TRACE( "send dde-ack %x %08x => %08lx\n", uiLo, uiHi, (DWORD)h );
1263             }
1264         }
1265         else
1266         {
1267             /* uiHi should contain either an atom or 0 */
1268             TRACE( "send dde-ack %x atom=%x\n", uiLo, uiHi );
1269             lp = MAKELONG( uiLo, uiHi );
1270         }
1271         break;
1272     case WM_DDE_ADVISE:
1273     case WM_DDE_DATA:
1274     case WM_DDE_POKE:
1275         size = 0;
1276         if (uiLo)
1277         {
1278             size = GlobalSize( (HGLOBAL)uiLo ) ;
1279             if ((info->msg == WM_DDE_ADVISE && size < sizeof(DDEADVISE)) ||
1280                 (info->msg == WM_DDE_DATA   && size < sizeof(DDEDATA))   ||
1281                 (info->msg == WM_DDE_POKE   && size < sizeof(DDEPOKE))
1282                 )
1283             return FALSE;
1284         }
1285         else if (info->msg != WM_DDE_DATA) return FALSE;
1286
1287         lp = uiHi;
1288         if (uiLo)
1289         {
1290             if ((ptr = GlobalLock( (HGLOBAL)uiLo) ))
1291             {
1292                 DDEDATA *dde_data = (DDEDATA *)ptr;
1293                 TRACE("unused %d, fResponse %d, fRelease %d, fDeferUpd %d, fAckReq %d, cfFormat %d\n",
1294                        dde_data->unused, dde_data->fResponse, dde_data->fRelease,
1295                        dde_data->reserved, dde_data->fAckReq, dde_data->cfFormat);
1296                 push_data( data, ptr, size );
1297                 hunlock = (HGLOBAL)uiLo;
1298             }
1299         }
1300         TRACE( "send ddepack %u %x\n", size, uiHi );
1301         break;
1302     case WM_DDE_EXECUTE:
1303         if (info->lparam)
1304         {
1305             if ((ptr = GlobalLock( (HGLOBAL)info->lparam) ))
1306             {
1307                 push_data(data, ptr, GlobalSize( (HGLOBAL)info->lparam ));
1308                 /* so that the other side can send it back on ACK */
1309                 lp = info->lparam;
1310                 hunlock = (HGLOBAL)info->lparam;
1311             }
1312         }
1313         break;
1314     }
1315     SERVER_START_REQ( send_message )
1316     {
1317         req->id      = dest_tid;
1318         req->type    = info->type;
1319         req->flags   = 0;
1320         req->win     = info->hwnd;
1321         req->msg     = info->msg;
1322         req->wparam  = info->wparam;
1323         req->lparam  = lp;
1324         req->time    = GetCurrentTime();
1325         req->timeout = -1;
1326         for (i = 0; i < data->count; i++)
1327             wine_server_add_data( req, data->data[i], data->size[i] );
1328         if ((res = wine_server_call( req )))
1329         {
1330             if (res == STATUS_INVALID_PARAMETER)
1331                 /* FIXME: find a STATUS_ value for this one */
1332                 SetLastError( ERROR_INVALID_THREAD_ID );
1333             else
1334                 SetLastError( RtlNtStatusToDosError(res) );
1335         }
1336         else
1337             FreeDDElParam(info->msg, info->lparam);
1338     }
1339     SERVER_END_REQ;
1340     if (hunlock) GlobalUnlock(hunlock);
1341
1342     return !res;
1343 }
1344
1345 /***********************************************************************
1346  *              unpack_dde_message
1347  *
1348  * Unpack a posted DDE message received from another process.
1349  */
1350 static BOOL unpack_dde_message( HWND hwnd, UINT message, WPARAM *wparam, LPARAM *lparam,
1351                                 void **buffer, size_t size )
1352 {
1353     UINT        uiLo, uiHi;
1354     HGLOBAL     hMem = 0;
1355     void*       ptr;
1356
1357     switch (message)
1358     {
1359     case WM_DDE_ACK:
1360         if (size)
1361         {
1362             /* hMem is being passed */
1363             if (size != sizeof(HGLOBAL)) return FALSE;
1364             if (!buffer || !*buffer) return FALSE;
1365             uiLo = *lparam;
1366             memcpy( &hMem, *buffer, size );
1367             uiHi = (UINT)hMem;
1368             TRACE("recv dde-ack %x mem=%x[%lx]\n", uiLo, uiHi, GlobalSize( hMem ));
1369         }
1370         else
1371         {
1372             uiLo = LOWORD( *lparam );
1373             uiHi = HIWORD( *lparam );
1374             TRACE("recv dde-ack %x atom=%x\n", uiLo, uiHi);
1375         }
1376         *lparam = PackDDElParam( WM_DDE_ACK, uiLo, uiHi );
1377         break;
1378     case WM_DDE_ADVISE:
1379     case WM_DDE_DATA:
1380     case WM_DDE_POKE:
1381         if ((!buffer || !*buffer) && message != WM_DDE_DATA) return FALSE;
1382         uiHi = *lparam;
1383         TRACE( "recv ddepack %u %x\n", size, uiHi );
1384         if (size)
1385         {
1386             hMem = GlobalAlloc( GMEM_MOVEABLE|GMEM_DDESHARE, size );
1387             if (hMem && (ptr = GlobalLock( hMem )))
1388             {
1389                 memcpy( ptr, *buffer, size );
1390                 GlobalUnlock( hMem );
1391             }
1392             else return FALSE;
1393         }
1394         uiLo = (UINT)hMem;
1395
1396         *lparam = PackDDElParam( message, uiLo, uiHi );
1397         break;
1398     case WM_DDE_EXECUTE:
1399         if (size)
1400         {
1401             if (!buffer || !*buffer) return FALSE;
1402             hMem = GlobalAlloc( GMEM_MOVEABLE|GMEM_DDESHARE, size );
1403             if (hMem && (ptr = GlobalLock( hMem )))
1404             {
1405                 memcpy( ptr, *buffer, size );
1406                 GlobalUnlock( hMem );
1407                 TRACE( "exec: pairing c=%08lx s=%08lx\n", *lparam, (DWORD)hMem );
1408                 if (!dde_add_pair( (HGLOBAL)*lparam, hMem ))
1409                 {
1410                     GlobalFree( hMem );
1411                     return FALSE;
1412                 }
1413             }
1414         } else return FALSE;
1415         *lparam = (LPARAM)hMem;
1416         break;
1417     }
1418     return TRUE;
1419 }
1420
1421 /***********************************************************************
1422  *           call_window_proc
1423  *
1424  * Call a window procedure and the corresponding hooks.
1425  */
1426 static LRESULT call_window_proc( HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam,
1427                                  BOOL unicode, BOOL same_thread )
1428 {
1429     LRESULT result = 0;
1430     WNDPROC winproc;
1431     CWPSTRUCT cwp;
1432     CWPRETSTRUCT cwpret;
1433     MESSAGEQUEUE *queue = QUEUE_Current();
1434
1435     if (queue->recursion_count > MAX_SENDMSG_RECURSION) return 0;
1436     queue->recursion_count++;
1437
1438     if (msg & 0x80000000)
1439     {
1440         result = handle_internal_message( hwnd, msg, wparam, lparam );
1441         goto done;
1442     }
1443
1444     /* first the WH_CALLWNDPROC hook */
1445     hwnd = WIN_GetFullHandle( hwnd );
1446     cwp.lParam  = lparam;
1447     cwp.wParam  = wparam;
1448     cwp.message = msg;
1449     cwp.hwnd    = hwnd;
1450     HOOK_CallHooks( WH_CALLWNDPROC, HC_ACTION, same_thread, (LPARAM)&cwp, unicode );
1451
1452     /* now call the window procedure */
1453     if (unicode)
1454     {
1455         if (!(winproc = (WNDPROC)GetWindowLongPtrW( hwnd, GWLP_WNDPROC ))) goto done;
1456         result = CallWindowProcW( winproc, hwnd, msg, wparam, lparam );
1457     }
1458     else
1459     {
1460         if (!(winproc = (WNDPROC)GetWindowLongPtrA( hwnd, GWLP_WNDPROC ))) goto done;
1461         result = CallWindowProcA( winproc, hwnd, msg, wparam, lparam );
1462     }
1463
1464     /* and finally the WH_CALLWNDPROCRET hook */
1465     cwpret.lResult = result;
1466     cwpret.lParam  = lparam;
1467     cwpret.wParam  = wparam;
1468     cwpret.message = msg;
1469     cwpret.hwnd    = hwnd;
1470     HOOK_CallHooks( WH_CALLWNDPROCRET, HC_ACTION, same_thread, (LPARAM)&cwpret, unicode );
1471  done:
1472     queue->recursion_count--;
1473     return result;
1474 }
1475
1476
1477 /***********************************************************************
1478  *           process_hardware_message
1479  *
1480  * Process a hardware message; return TRUE if message should be passed on to the app
1481  */
1482 static BOOL process_hardware_message( MSG *msg, ULONG_PTR extra_info, HWND hwnd,
1483                                       UINT first, UINT last, BOOL remove )
1484 {
1485     BOOL ret;
1486
1487     if (!MSG_process_raw_hardware_message( msg, extra_info, hwnd, first, last, remove ))
1488         return FALSE;
1489
1490     ret = MSG_process_cooked_hardware_message( msg, extra_info, remove );
1491
1492     /* tell the server we have passed it to the app
1493      * (even though we may end up dropping it later on)
1494      */
1495     SERVER_START_REQ( reply_message )
1496     {
1497         req->type   = MSG_HARDWARE;
1498         req->result = 0;
1499         req->remove = remove || !ret;
1500         wine_server_call( req );
1501     }
1502     SERVER_END_REQ;
1503     return ret;
1504 }
1505
1506
1507 /***********************************************************************
1508  *           call_sendmsg_callback
1509  *
1510  * Call the callback function of SendMessageCallback.
1511  */
1512 static inline void call_sendmsg_callback( SENDASYNCPROC callback, HWND hwnd, UINT msg,
1513                                           ULONG_PTR data, LRESULT result )
1514 {
1515     if (TRACE_ON(relay))
1516         DPRINTF( "%04lx:Call message callback %p (hwnd=%p,msg=%s,data=%08lx,result=%08lx)\n",
1517                  GetCurrentThreadId(), callback, hwnd, SPY_GetMsgName( msg, hwnd ),
1518                  data, result );
1519     callback( hwnd, msg, data, result );
1520     if (TRACE_ON(relay))
1521         DPRINTF( "%04lx:Ret  message callback %p (hwnd=%p,msg=%s,data=%08lx,result=%08lx)\n",
1522                  GetCurrentThreadId(), callback, hwnd, SPY_GetMsgName( msg, hwnd ),
1523                  data, result );
1524 }
1525
1526
1527 /***********************************************************************
1528  *           MSG_peek_message
1529  *
1530  * Peek for a message matching the given parameters. Return FALSE if none available.
1531  * All pending sent messages are processed before returning.
1532  */
1533 BOOL MSG_peek_message( MSG *msg, HWND hwnd, UINT first, UINT last, int flags )
1534 {
1535     LRESULT result;
1536     ULONG_PTR extra_info = 0;
1537     MESSAGEQUEUE *queue = QUEUE_Current();
1538     struct received_message_info info, *old_info;
1539
1540     if (!first && !last) last = ~0;
1541
1542     for (;;)
1543     {
1544         NTSTATUS res;
1545         void *buffer = NULL;
1546         size_t size = 0, buffer_size = 0;
1547
1548         do  /* loop while buffer is too small */
1549         {
1550             if (buffer_size && !(buffer = HeapAlloc( GetProcessHeap(), 0, buffer_size )))
1551                 return FALSE;
1552             SERVER_START_REQ( get_message )
1553             {
1554                 req->flags     = flags;
1555                 req->get_win   = hwnd;
1556                 req->get_first = first;
1557                 req->get_last  = last;
1558                 if (buffer_size) wine_server_set_reply( req, buffer, buffer_size );
1559                 if (!(res = wine_server_call( req )))
1560                 {
1561                     size = wine_server_reply_size( reply );
1562                     info.type        = reply->type;
1563                     info.msg.hwnd    = reply->win;
1564                     info.msg.message = reply->msg;
1565                     info.msg.wParam  = reply->wparam;
1566                     info.msg.lParam  = reply->lparam;
1567                     info.msg.time    = reply->time;
1568                     info.msg.pt.x    = reply->x;
1569                     info.msg.pt.y    = reply->y;
1570                     extra_info       = reply->info;
1571                 }
1572                 else
1573                 {
1574                     if (buffer) HeapFree( GetProcessHeap(), 0, buffer );
1575                     buffer_size = reply->total;
1576                 }
1577             }
1578             SERVER_END_REQ;
1579         } while (res == STATUS_BUFFER_OVERFLOW);
1580
1581         if (res) return FALSE;
1582
1583         TRACE( "got type %d msg %x (%s) hwnd %p wp %x lp %lx\n",
1584                info.type, info.msg.message, SPY_GetMsgName(info.msg.message, info.msg.hwnd),
1585                info.msg.hwnd, info.msg.wParam, info.msg.lParam );
1586
1587         switch(info.type)
1588         {
1589         case MSG_ASCII:
1590         case MSG_UNICODE:
1591             info.flags = ISMEX_SEND;
1592             break;
1593         case MSG_NOTIFY:
1594             info.flags = ISMEX_NOTIFY;
1595             break;
1596         case MSG_CALLBACK:
1597             info.flags = ISMEX_CALLBACK;
1598             break;
1599         case MSG_CALLBACK_RESULT:
1600             call_sendmsg_callback( (SENDASYNCPROC)info.msg.wParam, info.msg.hwnd,
1601                                    info.msg.message, extra_info, info.msg.lParam );
1602             goto next;
1603         case MSG_OTHER_PROCESS:
1604             info.flags = ISMEX_SEND;
1605             if (!unpack_message( info.msg.hwnd, info.msg.message, &info.msg.wParam,
1606                                  &info.msg.lParam, &buffer, size ))
1607             {
1608                 ERR( "invalid packed message %x (%s) hwnd %p wp %x lp %lx size %d\n",
1609                      info.msg.message, SPY_GetMsgName(info.msg.message, info.msg.hwnd), info.msg.hwnd,
1610                      info.msg.wParam, info.msg.lParam, size );
1611                 /* ignore it */
1612                 reply_message( &info, 0, TRUE );
1613                 goto next;
1614             }
1615             break;
1616         case MSG_HARDWARE:
1617             if (!process_hardware_message( &info.msg, extra_info,
1618                                            hwnd, first, last, flags & GET_MSG_REMOVE ))
1619             {
1620                 TRACE("dropping msg %x\n", info.msg.message );
1621                 goto next;  /* ignore it */
1622             }
1623             queue->GetMessagePosVal = MAKELONG( info.msg.pt.x, info.msg.pt.y );
1624             /* fall through */
1625         case MSG_POSTED:
1626             queue->GetMessageExtraInfoVal = extra_info;
1627             if (info.msg.message >= WM_DDE_FIRST && info.msg.message <= WM_DDE_LAST)
1628             {
1629                 if (!unpack_dde_message( info.msg.hwnd, info.msg.message, &info.msg.wParam,
1630                                          &info.msg.lParam, &buffer, size ))
1631                 {
1632                     ERR( "invalid packed dde-message %x (%s) hwnd %p wp %x lp %lx size %d\n",
1633                          info.msg.message, SPY_GetMsgName(info.msg.message, info.msg.hwnd),
1634                          info.msg.hwnd, info.msg.wParam, info.msg.lParam, size );
1635                     goto next;  /* ignore it */
1636                 }
1637             }
1638             *msg = info.msg;
1639             if (buffer) HeapFree( GetProcessHeap(), 0, buffer );
1640             return TRUE;
1641         }
1642
1643         /* if we get here, we have a sent message; call the window procedure */
1644         old_info = queue->receive_info;
1645         queue->receive_info = &info;
1646         result = call_window_proc( info.msg.hwnd, info.msg.message, info.msg.wParam,
1647                                    info.msg.lParam, (info.type != MSG_ASCII), FALSE );
1648         reply_message( &info, result, TRUE );
1649         queue->receive_info = old_info;
1650     next:
1651         if (buffer) HeapFree( GetProcessHeap(), 0, buffer );
1652     }
1653 }
1654
1655
1656 /***********************************************************************
1657  *           wait_message_reply
1658  *
1659  * Wait until a sent message gets replied to.
1660  */
1661 static void wait_message_reply( UINT flags )
1662 {
1663     MESSAGEQUEUE *queue;
1664
1665     if (!(queue = QUEUE_Current())) return;
1666
1667     for (;;)
1668     {
1669         unsigned int wake_bits = 0, changed_bits = 0;
1670         DWORD dwlc, res;
1671
1672         SERVER_START_REQ( set_queue_mask )
1673         {
1674             req->wake_mask    = QS_SMRESULT | ((flags & SMTO_BLOCK) ? 0 : QS_SENDMESSAGE);
1675             req->changed_mask = req->wake_mask;
1676             req->skip_wait    = 1;
1677             if (!wine_server_call( req ))
1678             {
1679                 wake_bits    = reply->wake_bits;
1680                 changed_bits = reply->changed_bits;
1681             }
1682         }
1683         SERVER_END_REQ;
1684
1685         if (wake_bits & QS_SMRESULT) return;  /* got a result */
1686         if (wake_bits & QS_SENDMESSAGE)
1687         {
1688             /* Process the sent message immediately */
1689             MSG msg;
1690             MSG_peek_message( &msg, 0, 0, 0, GET_MSG_REMOVE | GET_MSG_SENT_ONLY );
1691             continue;
1692         }
1693
1694         /* now wait for it */
1695
1696         ReleaseThunkLock( &dwlc );
1697
1698         if (USER_Driver.pMsgWaitForMultipleObjectsEx)
1699             res = USER_Driver.pMsgWaitForMultipleObjectsEx( 1, &queue->server_queue,
1700                                                             INFINITE, 0, 0 );
1701         else
1702             res = WaitForSingleObject( queue->server_queue, INFINITE );
1703
1704         if (dwlc) RestoreThunkLock( dwlc );
1705     }
1706 }
1707
1708 /***********************************************************************
1709  *              put_message_in_queue
1710  *
1711  * Put a sent message into the destination queue.
1712  * For inter-process message, reply_size is set to expected size of reply data.
1713  */
1714 static BOOL put_message_in_queue( DWORD dest_tid, const struct send_message_info *info,
1715                                   size_t *reply_size )
1716 {
1717     struct packed_message data;
1718     unsigned int res;
1719     int i, timeout = -1;
1720
1721     if (info->type != MSG_NOTIFY &&
1722         info->type != MSG_CALLBACK &&
1723         info->type != MSG_POSTED &&
1724         info->timeout != INFINITE)
1725         timeout = info->timeout;
1726
1727     data.count = 0;
1728     if (info->type == MSG_OTHER_PROCESS)
1729     {
1730         *reply_size = pack_message( info->hwnd, info->msg, info->wparam, info->lparam, &data );
1731         if (data.count == -1)
1732         {
1733             WARN( "cannot pack message %x\n", info->msg );
1734             return FALSE;
1735         }
1736     }
1737     else if (info->type == MSG_POSTED && info->msg >= WM_DDE_FIRST && info->msg <= WM_DDE_LAST)
1738     {
1739         return post_dde_message( dest_tid, &data, info );
1740     }
1741
1742     SERVER_START_REQ( send_message )
1743     {
1744         req->id      = dest_tid;
1745         req->type    = info->type;
1746         req->flags   = 0;
1747         req->win     = info->hwnd;
1748         req->msg     = info->msg;
1749         req->wparam  = info->wparam;
1750         req->lparam  = info->lparam;
1751         req->time    = GetCurrentTime();
1752         req->timeout = timeout;
1753
1754         if (info->type == MSG_CALLBACK)
1755         {
1756             req->callback = info->callback;
1757             req->info     = info->data;
1758         }
1759
1760         if (info->flags & SMTO_ABORTIFHUNG) req->flags |= SEND_MSG_ABORT_IF_HUNG;
1761         for (i = 0; i < data.count; i++) wine_server_add_data( req, data.data[i], data.size[i] );
1762         if ((res = wine_server_call( req )))
1763         {
1764             if (res == STATUS_INVALID_PARAMETER)
1765                 /* FIXME: find a STATUS_ value for this one */
1766                 SetLastError( ERROR_INVALID_THREAD_ID );
1767             else
1768                 SetLastError( RtlNtStatusToDosError(res) );
1769         }
1770     }
1771     SERVER_END_REQ;
1772     return !res;
1773 }
1774
1775
1776 /***********************************************************************
1777  *              retrieve_reply
1778  *
1779  * Retrieve a message reply from the server.
1780  */
1781 static LRESULT retrieve_reply( const struct send_message_info *info,
1782                                size_t reply_size, LRESULT *result )
1783 {
1784     NTSTATUS status;
1785     void *reply_data = NULL;
1786
1787     if (reply_size)
1788     {
1789         if (!(reply_data = HeapAlloc( GetProcessHeap(), 0, reply_size )))
1790         {
1791             WARN( "no memory for reply %d bytes, will be truncated\n", reply_size );
1792             reply_size = 0;
1793         }
1794     }
1795     SERVER_START_REQ( get_message_reply )
1796     {
1797         req->cancel = 1;
1798         if (reply_size) wine_server_set_reply( req, reply_data, reply_size );
1799         if (!(status = wine_server_call( req ))) *result = reply->result;
1800         reply_size = wine_server_reply_size( reply );
1801     }
1802     SERVER_END_REQ;
1803     if (!status && reply_size)
1804         unpack_reply( info->hwnd, info->msg, info->wparam, info->lparam, reply_data, reply_size );
1805
1806     if (reply_data) HeapFree( GetProcessHeap(), 0, reply_data );
1807
1808     TRACE( "hwnd %p msg %x (%s) wp %x lp %lx got reply %lx (err=%ld)\n",
1809            info->hwnd, info->msg, SPY_GetMsgName(info->msg, info->hwnd), info->wparam,
1810            info->lparam, *result, status );
1811
1812     /* MSDN states that last error is 0 on timeout, but at least NT4 returns ERROR_TIMEOUT */
1813     if (status) SetLastError( RtlNtStatusToDosError(status) );
1814     return !status;
1815 }
1816
1817
1818 /***********************************************************************
1819  *              send_inter_thread_message
1820  */
1821 static LRESULT send_inter_thread_message( DWORD dest_tid, const struct send_message_info *info,
1822                                           LRESULT *res_ptr )
1823 {
1824     LRESULT ret;
1825     int locks;
1826     size_t reply_size = 0;
1827
1828     TRACE( "hwnd %p msg %x (%s) wp %x lp %lx\n",
1829            info->hwnd, info->msg, SPY_GetMsgName(info->msg, info->hwnd), info->wparam, info->lparam );
1830
1831     if (!put_message_in_queue( dest_tid, info, &reply_size )) return 0;
1832
1833     /* there's no reply to wait for on notify/callback messages */
1834     if (info->type == MSG_NOTIFY || info->type == MSG_CALLBACK) return 1;
1835
1836     locks = WIN_SuspendWndsLock();
1837
1838     wait_message_reply( info->flags );
1839     ret = retrieve_reply( info, reply_size, res_ptr );
1840
1841     WIN_RestoreWndsLock( locks );
1842     return ret;
1843 }
1844
1845
1846 /***********************************************************************
1847  *              MSG_SendInternalMessageTimeout
1848  *
1849  * Same as SendMessageTimeoutW but sends the message to a specific thread
1850  * without requiring a window handle. Only works for internal Wine messages.
1851  */
1852 LRESULT MSG_SendInternalMessageTimeout( DWORD dest_pid, DWORD dest_tid,
1853                                         UINT msg, WPARAM wparam, LPARAM lparam,
1854                                         UINT flags, UINT timeout, PDWORD_PTR res_ptr )
1855 {
1856     struct send_message_info info;
1857     LRESULT ret, result;
1858
1859     assert( msg & 0x80000000 );  /* must be an internal Wine message */
1860
1861     info.type    = MSG_UNICODE;
1862     info.hwnd    = 0;
1863     info.msg     = msg;
1864     info.wparam  = wparam;
1865     info.lparam  = lparam;
1866     info.flags   = flags;
1867     info.timeout = timeout;
1868
1869     if (USER_IsExitingThread( dest_tid )) return 0;
1870
1871     if (dest_tid == GetCurrentThreadId())
1872     {
1873         result = handle_internal_message( 0, msg, wparam, lparam );
1874         ret = 1;
1875     }
1876     else
1877     {
1878         if (dest_pid != GetCurrentProcessId()) info.type = MSG_OTHER_PROCESS;
1879         ret = send_inter_thread_message( dest_tid, &info, &result );
1880     }
1881     if (ret && res_ptr) *res_ptr = result;
1882     return ret;
1883 }
1884
1885
1886 /***********************************************************************
1887  *              SendMessageTimeoutW  (USER32.@)
1888  */
1889 LRESULT WINAPI SendMessageTimeoutW( HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam,
1890                                     UINT flags, UINT timeout, PDWORD_PTR res_ptr )
1891 {
1892     struct send_message_info info;
1893     DWORD dest_tid, dest_pid;
1894     LRESULT ret, result;
1895
1896     info.type    = MSG_UNICODE;
1897     info.hwnd    = hwnd;
1898     info.msg     = msg;
1899     info.wparam  = wparam;
1900     info.lparam  = lparam;
1901     info.flags   = flags;
1902     info.timeout = timeout;
1903
1904     if (is_broadcast(hwnd))
1905     {
1906         EnumWindows( broadcast_message_callback, (LPARAM)&info );
1907         if (res_ptr) *res_ptr = 1;
1908         return 1;
1909     }
1910
1911     if (!(dest_tid = GetWindowThreadProcessId( hwnd, &dest_pid ))) return 0;
1912
1913     if (USER_IsExitingThread( dest_tid )) return 0;
1914
1915     SPY_EnterMessage( SPY_SENDMESSAGE, hwnd, msg, wparam, lparam );
1916
1917     if (dest_tid == GetCurrentThreadId())
1918     {
1919         result = call_window_proc( hwnd, msg, wparam, lparam, TRUE, TRUE );
1920         ret = 1;
1921     }
1922     else
1923     {
1924         if (dest_pid != GetCurrentProcessId()) info.type = MSG_OTHER_PROCESS;
1925         ret = send_inter_thread_message( dest_tid, &info, &result );
1926     }
1927
1928     SPY_ExitMessage( SPY_RESULT_OK, hwnd, msg, result, wparam, lparam );
1929     if (ret && res_ptr) *res_ptr = result;
1930     return ret;
1931 }
1932
1933
1934 /***********************************************************************
1935  *              SendMessageTimeoutA  (USER32.@)
1936  */
1937 LRESULT WINAPI SendMessageTimeoutA( HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam,
1938                                     UINT flags, UINT timeout, PDWORD_PTR res_ptr )
1939 {
1940     struct send_message_info info;
1941     DWORD dest_tid, dest_pid;
1942     LRESULT ret, result;
1943
1944     info.type    = MSG_ASCII;
1945     info.hwnd    = hwnd;
1946     info.msg     = msg;
1947     info.wparam  = wparam;
1948     info.lparam  = lparam;
1949     info.flags   = flags;
1950     info.timeout = timeout;
1951
1952     if (is_broadcast(hwnd))
1953     {
1954         EnumWindows( broadcast_message_callback, (LPARAM)&info );
1955         if (res_ptr) *res_ptr = 1;
1956         return 1;
1957     }
1958
1959     if (!(dest_tid = GetWindowThreadProcessId( hwnd, &dest_pid ))) return 0;
1960
1961     if (USER_IsExitingThread( dest_tid )) return 0;
1962
1963     SPY_EnterMessage( SPY_SENDMESSAGE, hwnd, msg, wparam, lparam );
1964
1965     if (dest_tid == GetCurrentThreadId())
1966     {
1967         result = call_window_proc( hwnd, msg, wparam, lparam, FALSE, TRUE );
1968         ret = 1;
1969     }
1970     else if (dest_pid == GetCurrentProcessId())
1971     {
1972         ret = send_inter_thread_message( dest_tid, &info, &result );
1973     }
1974     else
1975     {
1976         /* inter-process message: need to map to Unicode */
1977         info.type = MSG_OTHER_PROCESS;
1978         if (is_unicode_message( info.msg ))
1979         {
1980             if (WINPROC_MapMsg32ATo32W( info.hwnd, info.msg, &info.wparam, &info.lparam ) == -1)
1981                 return 0;
1982             ret = send_inter_thread_message( dest_tid, &info, &result );
1983             result = WINPROC_UnmapMsg32ATo32W( info.hwnd, info.msg, info.wparam,
1984                                                info.lparam, result );
1985         }
1986         else ret = send_inter_thread_message( dest_tid, &info, &result );
1987     }
1988     SPY_ExitMessage( SPY_RESULT_OK, hwnd, msg, result, wparam, lparam );
1989     if (ret && res_ptr) *res_ptr = result;
1990     return ret;
1991 }
1992
1993
1994 /***********************************************************************
1995  *              SendMessageW  (USER32.@)
1996  */
1997 LRESULT WINAPI SendMessageW( HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam )
1998 {
1999     LRESULT res = 0;
2000     SendMessageTimeoutW( hwnd, msg, wparam, lparam, SMTO_NORMAL, INFINITE, &res );
2001     return res;
2002 }
2003
2004
2005 /***********************************************************************
2006  *              SendMessageA  (USER32.@)
2007  */
2008 LRESULT WINAPI SendMessageA( HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam )
2009 {
2010     LRESULT res = 0;
2011     SendMessageTimeoutA( hwnd, msg, wparam, lparam, SMTO_NORMAL, INFINITE, &res );
2012     return res;
2013 }
2014
2015
2016 /***********************************************************************
2017  *              SendNotifyMessageA  (USER32.@)
2018  */
2019 BOOL WINAPI SendNotifyMessageA( HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam )
2020 {
2021     return SendNotifyMessageW( hwnd, msg, map_wparam_AtoW( msg, wparam ), lparam );
2022 }
2023
2024
2025 /***********************************************************************
2026  *              SendNotifyMessageW  (USER32.@)
2027  */
2028 BOOL WINAPI SendNotifyMessageW( HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam )
2029 {
2030     struct send_message_info info;
2031     DWORD dest_tid;
2032     LRESULT result;
2033
2034     if (is_pointer_message(msg))
2035     {
2036         SetLastError(ERROR_INVALID_PARAMETER);
2037         return FALSE;
2038     }
2039
2040     info.type    = MSG_NOTIFY;
2041     info.hwnd    = hwnd;
2042     info.msg     = msg;
2043     info.wparam  = wparam;
2044     info.lparam  = lparam;
2045     info.flags   = 0;
2046
2047     if (is_broadcast(hwnd))
2048     {
2049         EnumWindows( broadcast_message_callback, (LPARAM)&info );
2050         return TRUE;
2051     }
2052
2053     if (!(dest_tid = GetWindowThreadProcessId( hwnd, NULL ))) return FALSE;
2054
2055     if (USER_IsExitingThread( dest_tid )) return TRUE;
2056
2057     if (dest_tid == GetCurrentThreadId())
2058     {
2059         call_window_proc( hwnd, msg, wparam, lparam, TRUE, TRUE );
2060         return TRUE;
2061     }
2062     return send_inter_thread_message( dest_tid, &info, &result );
2063 }
2064
2065
2066 /***********************************************************************
2067  *              SendMessageCallbackA  (USER32.@)
2068  */
2069 BOOL WINAPI SendMessageCallbackA( HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam,
2070                                   SENDASYNCPROC callback, ULONG_PTR data )
2071 {
2072     return SendMessageCallbackW( hwnd, msg, map_wparam_AtoW( msg, wparam ),
2073                                  lparam, callback, data );
2074 }
2075
2076
2077 /***********************************************************************
2078  *              SendMessageCallbackW  (USER32.@)
2079  */
2080 BOOL WINAPI SendMessageCallbackW( HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam,
2081                                   SENDASYNCPROC callback, ULONG_PTR data )
2082 {
2083     struct send_message_info info;
2084     LRESULT result;
2085     DWORD dest_tid;
2086
2087     if (is_pointer_message(msg))
2088     {
2089         SetLastError(ERROR_INVALID_PARAMETER);
2090         return FALSE;
2091     }
2092
2093     info.type     = MSG_CALLBACK;
2094     info.hwnd     = hwnd;
2095     info.msg      = msg;
2096     info.wparam   = wparam;
2097     info.lparam   = lparam;
2098     info.callback = callback;
2099     info.data     = data;
2100     info.flags    = 0;
2101
2102     if (is_broadcast(hwnd))
2103     {
2104         EnumWindows( broadcast_message_callback, (LPARAM)&info );
2105         return TRUE;
2106     }
2107
2108     if (!(dest_tid = GetWindowThreadProcessId( hwnd, NULL ))) return FALSE;
2109
2110     if (USER_IsExitingThread( dest_tid )) return TRUE;
2111
2112     if (dest_tid == GetCurrentThreadId())
2113     {
2114         result = call_window_proc( hwnd, msg, wparam, lparam, TRUE, TRUE );
2115         call_sendmsg_callback( callback, hwnd, msg, data, result );
2116         return TRUE;
2117     }
2118     FIXME( "callback will not be called\n" );
2119     return send_inter_thread_message( dest_tid, &info, &result );
2120 }
2121
2122
2123 /***********************************************************************
2124  *              ReplyMessage  (USER32.@)
2125  */
2126 BOOL WINAPI ReplyMessage( LRESULT result )
2127 {
2128     MESSAGEQUEUE *queue = QUEUE_Current();
2129     struct received_message_info *info = queue->receive_info;
2130
2131     if (!info) return FALSE;
2132     reply_message( info, result, FALSE );
2133     return TRUE;
2134 }
2135
2136
2137 /***********************************************************************
2138  *              InSendMessage  (USER32.@)
2139  */
2140 BOOL WINAPI InSendMessage(void)
2141 {
2142     return (InSendMessageEx(NULL) & (ISMEX_SEND|ISMEX_REPLIED)) == ISMEX_SEND;
2143 }
2144
2145
2146 /***********************************************************************
2147  *              InSendMessageEx  (USER32.@)
2148  */
2149 DWORD WINAPI InSendMessageEx( LPVOID reserved )
2150 {
2151     MESSAGEQUEUE *queue = QUEUE_Current();
2152     struct received_message_info *info = queue->receive_info;
2153
2154     if (info) return info->flags;
2155     return ISMEX_NOSEND;
2156 }
2157
2158
2159 /***********************************************************************
2160  *              PostMessageA  (USER32.@)
2161  */
2162 BOOL WINAPI PostMessageA( HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam )
2163 {
2164     return PostMessageW( hwnd, msg, map_wparam_AtoW( msg, wparam ), lparam );
2165 }
2166
2167
2168 /***********************************************************************
2169  *              PostMessageW  (USER32.@)
2170  */
2171 BOOL WINAPI PostMessageW( HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam )
2172 {
2173     struct send_message_info info;
2174     DWORD dest_tid;
2175
2176     if (is_pointer_message( msg ))
2177     {
2178         SetLastError( ERROR_INVALID_PARAMETER );
2179         return FALSE;
2180     }
2181
2182     TRACE( "hwnd %p msg %x (%s) wp %x lp %lx\n",
2183            hwnd, msg, SPY_GetMsgName(msg, hwnd), wparam, lparam );
2184
2185     info.type   = MSG_POSTED;
2186     info.hwnd   = hwnd;
2187     info.msg    = msg;
2188     info.wparam = wparam;
2189     info.lparam = lparam;
2190     info.flags  = 0;
2191
2192     if (is_broadcast(hwnd))
2193     {
2194         EnumWindows( broadcast_message_callback, (LPARAM)&info );
2195         return TRUE;
2196     }
2197
2198     if (!hwnd) return PostThreadMessageW( GetCurrentThreadId(), msg, wparam, lparam );
2199
2200     if (!(dest_tid = GetWindowThreadProcessId( hwnd, NULL ))) return FALSE;
2201
2202     if (USER_IsExitingThread( dest_tid )) return TRUE;
2203
2204     return put_message_in_queue( dest_tid, &info, NULL );
2205 }
2206
2207
2208 /**********************************************************************
2209  *              PostThreadMessageA  (USER32.@)
2210  */
2211 BOOL WINAPI PostThreadMessageA( DWORD thread, UINT msg, WPARAM wparam, LPARAM lparam )
2212 {
2213     return PostThreadMessageW( thread, msg, map_wparam_AtoW( msg, wparam ), lparam );
2214 }
2215
2216
2217 /**********************************************************************
2218  *              PostThreadMessageW  (USER32.@)
2219  */
2220 BOOL WINAPI PostThreadMessageW( DWORD thread, UINT msg, WPARAM wparam, LPARAM lparam )
2221 {
2222     struct send_message_info info;
2223
2224     if (is_pointer_message( msg ))
2225     {
2226         SetLastError( ERROR_INVALID_PARAMETER );
2227         return FALSE;
2228     }
2229     if (USER_IsExitingThread( thread )) return TRUE;
2230
2231     info.type   = MSG_POSTED;
2232     info.hwnd   = 0;
2233     info.msg    = msg;
2234     info.wparam = wparam;
2235     info.lparam = lparam;
2236     info.flags  = 0;
2237     return put_message_in_queue( thread, &info, NULL );
2238 }
2239
2240
2241 /***********************************************************************
2242  *              PostQuitMessage  (USER32.@)
2243  */
2244 void WINAPI PostQuitMessage( INT exitCode )
2245 {
2246     PostThreadMessageW( GetCurrentThreadId(), WM_QUIT, exitCode, 0 );
2247 }
2248
2249
2250 /***********************************************************************
2251  *              PeekMessageW  (USER32.@)
2252  */
2253 BOOL WINAPI PeekMessageW( MSG *msg_out, HWND hwnd, UINT first, UINT last, UINT flags )
2254 {
2255     MESSAGEQUEUE *queue;
2256     MSG msg;
2257     int locks;
2258
2259     /* check for graphics events */
2260     if (USER_Driver.pMsgWaitForMultipleObjectsEx)
2261         USER_Driver.pMsgWaitForMultipleObjectsEx( 0, NULL, 0, 0, 0 );
2262
2263     hwnd = WIN_GetFullHandle( hwnd );
2264     locks = WIN_SuspendWndsLock();
2265
2266     if (!MSG_peek_message( &msg, hwnd, first, last,
2267                            (flags & PM_REMOVE) ? GET_MSG_REMOVE : 0 ))
2268     {
2269         if (!(flags & PM_NOYIELD))
2270         {
2271             DWORD count;
2272             ReleaseThunkLock(&count);
2273             if (count) RestoreThunkLock(count);
2274         }
2275         WIN_RestoreWndsLock( locks );
2276         return FALSE;
2277     }
2278
2279     WIN_RestoreWndsLock( locks );
2280
2281     /* need to fill the window handle for WM_PAINT message */
2282     if (msg.message == WM_PAINT)
2283     {
2284         if (IsIconic( msg.hwnd ) && GetClassLongW( msg.hwnd, GCL_HICON ))
2285         {
2286             msg.message = WM_PAINTICON;
2287             msg.wParam = 1;
2288         }
2289         /* clear internal paint flag */
2290         RedrawWindow( msg.hwnd, NULL, 0, RDW_NOINTERNALPAINT | RDW_NOCHILDREN );
2291     }
2292
2293     if ((queue = QUEUE_Current()))
2294     {
2295         queue->GetMessageTimeVal = msg.time;
2296         msg.pt.x = LOWORD( queue->GetMessagePosVal );
2297         msg.pt.y = HIWORD( queue->GetMessagePosVal );
2298     }
2299
2300     HOOK_CallHooks( WH_GETMESSAGE, HC_ACTION, flags & PM_REMOVE, (LPARAM)&msg, TRUE );
2301
2302     /* copy back our internal safe copy of message data to msg_out.
2303      * msg_out is a variable from the *program*, so it can't be used
2304      * internally as it can get "corrupted" by our use of SendMessage()
2305      * (back to the program) inside the message handling itself. */
2306     *msg_out = msg;
2307     return TRUE;
2308 }
2309
2310
2311 /***********************************************************************
2312  *              PeekMessageA  (USER32.@)
2313  */
2314 BOOL WINAPI PeekMessageA( MSG *msg, HWND hwnd, UINT first, UINT last, UINT flags )
2315 {
2316     BOOL ret = PeekMessageW( msg, hwnd, first, last, flags );
2317     if (ret) msg->wParam = map_wparam_WtoA( msg->message, msg->wParam );
2318     return ret;
2319 }
2320
2321
2322 /***********************************************************************
2323  *              GetMessageW  (USER32.@)
2324  */
2325 BOOL WINAPI GetMessageW( MSG *msg, HWND hwnd, UINT first, UINT last )
2326 {
2327     MESSAGEQUEUE *queue = QUEUE_Current();
2328     int mask, locks;
2329
2330     mask = QS_POSTMESSAGE | QS_SENDMESSAGE;  /* Always selected */
2331     if (first || last)
2332     {
2333         if ((first <= WM_KEYLAST) && (last >= WM_KEYFIRST)) mask |= QS_KEY;
2334         if ( ((first <= WM_MOUSELAST) && (last >= WM_MOUSEFIRST)) ||
2335              ((first <= WM_NCMOUSELAST) && (last >= WM_NCMOUSEFIRST)) ) mask |= QS_MOUSE;
2336         if ((first <= WM_TIMER) && (last >= WM_TIMER)) mask |= QS_TIMER;
2337         if ((first <= WM_SYSTIMER) && (last >= WM_SYSTIMER)) mask |= QS_TIMER;
2338         if ((first <= WM_PAINT) && (last >= WM_PAINT)) mask |= QS_PAINT;
2339     }
2340     else mask |= QS_MOUSE | QS_KEY | QS_TIMER | QS_PAINT;
2341
2342     locks = WIN_SuspendWndsLock();
2343
2344     while (!PeekMessageW( msg, hwnd, first, last, PM_REMOVE ))
2345     {
2346         /* wait until one of the bits is set */
2347         unsigned int wake_bits = 0, changed_bits = 0;
2348         DWORD dwlc;
2349
2350         SERVER_START_REQ( set_queue_mask )
2351         {
2352             req->wake_mask    = QS_SENDMESSAGE;
2353             req->changed_mask = mask;
2354             req->skip_wait    = 1;
2355             if (!wine_server_call( req ))
2356             {
2357                 wake_bits    = reply->wake_bits;
2358                 changed_bits = reply->changed_bits;
2359             }
2360         }
2361         SERVER_END_REQ;
2362
2363         if (changed_bits & mask) continue;
2364         if (wake_bits & QS_SENDMESSAGE) continue;
2365
2366         TRACE( "(%04x) mask=%08x, bits=%08x, changed=%08x, waiting\n",
2367                queue->self, mask, wake_bits, changed_bits );
2368
2369         ReleaseThunkLock( &dwlc );
2370         if (USER_Driver.pMsgWaitForMultipleObjectsEx)
2371             USER_Driver.pMsgWaitForMultipleObjectsEx( 1, &queue->server_queue, INFINITE, 0, 0 );
2372         else
2373             WaitForSingleObject( queue->server_queue, INFINITE );
2374         if (dwlc) RestoreThunkLock( dwlc );
2375     }
2376
2377     WIN_RestoreWndsLock( locks );
2378
2379     return (msg->message != WM_QUIT);
2380 }
2381
2382
2383 /***********************************************************************
2384  *              GetMessageA  (USER32.@)
2385  */
2386 BOOL WINAPI GetMessageA( MSG *msg, HWND hwnd, UINT first, UINT last )
2387 {
2388     GetMessageW( msg, hwnd, first, last );
2389     msg->wParam = map_wparam_WtoA( msg->message, msg->wParam );
2390     return (msg->message != WM_QUIT);
2391 }
2392
2393
2394 /***********************************************************************
2395  *              IsDialogMessage  (USER32.@)
2396  *              IsDialogMessageA (USER32.@)
2397  */
2398 BOOL WINAPI IsDialogMessageA( HWND hwndDlg, LPMSG pmsg )
2399 {
2400     MSG msg = *pmsg;
2401     msg.wParam = map_wparam_AtoW( msg.message, msg.wParam );
2402     return IsDialogMessageW( hwndDlg, &msg );
2403 }
2404
2405
2406 /***********************************************************************
2407  *              SetMessageQueue (USER32.@)
2408  */
2409 BOOL WINAPI SetMessageQueue( INT size )
2410 {
2411     /* now obsolete the message queue will be expanded dynamically as necessary */
2412     return TRUE;
2413 }
2414
2415
2416 /***********************************************************************
2417  *              MessageBeep (USER32.@)
2418  */
2419 BOOL WINAPI MessageBeep( UINT i )
2420 {
2421     BOOL active = TRUE;
2422     SystemParametersInfoA( SPI_GETBEEP, 0, &active, FALSE );
2423     if (active) USER_Driver.pBeep();
2424     return TRUE;
2425 }
2426
2427
2428 /**********************************************************************
2429  *              AttachThreadInput (USER32.@)
2430  *
2431  * Attaches the input processing mechanism of one thread to that of
2432  * another thread.
2433  */
2434 BOOL WINAPI AttachThreadInput( DWORD from, DWORD to, BOOL attach )
2435 {
2436     BOOL ret;
2437
2438     SERVER_START_REQ( attach_thread_input )
2439     {
2440         req->tid_from = from;
2441         req->tid_to   = to;
2442         req->attach   = attach;
2443         ret = !wine_server_call_err( req );
2444     }
2445     SERVER_END_REQ;
2446     return ret;
2447 }
2448
2449
2450 /**********************************************************************
2451  *              GetGUIThreadInfo  (USER32.@)
2452  */
2453 BOOL WINAPI GetGUIThreadInfo( DWORD id, GUITHREADINFO *info )
2454 {
2455     BOOL ret;
2456
2457     SERVER_START_REQ( get_thread_input )
2458     {
2459         req->tid = id;
2460         if ((ret = !wine_server_call_err( req )))
2461         {
2462             info->flags          = 0;
2463             info->hwndActive     = reply->active;
2464             info->hwndFocus      = reply->focus;
2465             info->hwndCapture    = reply->capture;
2466             info->hwndMenuOwner  = reply->menu_owner;
2467             info->hwndMoveSize   = reply->move_size;
2468             info->hwndCaret      = reply->caret;
2469             info->rcCaret.left   = reply->rect.left;
2470             info->rcCaret.top    = reply->rect.top;
2471             info->rcCaret.right  = reply->rect.right;
2472             info->rcCaret.bottom = reply->rect.bottom;
2473             if (reply->menu_owner) info->flags |= GUI_INMENUMODE;
2474             if (reply->move_size) info->flags |= GUI_INMOVESIZE;
2475             if (reply->caret) info->flags |= GUI_CARETBLINKING;
2476         }
2477     }
2478     SERVER_END_REQ;
2479     return ret;
2480 }
2481
2482
2483 /**********************************************************************
2484  *              GetKeyState (USER32.@)
2485  *
2486  * An application calls the GetKeyState function in response to a
2487  * keyboard-input message.  This function retrieves the state of the key
2488  * at the time the input message was generated.
2489  */
2490 SHORT WINAPI GetKeyState(INT vkey)
2491 {
2492     SHORT retval = 0;
2493
2494     SERVER_START_REQ( get_key_state )
2495     {
2496         req->tid = GetCurrentThreadId();
2497         req->key = vkey;
2498         if (!wine_server_call( req )) retval = (signed char)reply->state;
2499     }
2500     SERVER_END_REQ;
2501     TRACE("key (0x%x) -> %x\n", vkey, retval);
2502     return retval;
2503 }
2504
2505
2506 /**********************************************************************
2507  *              GetKeyboardState (USER32.@)
2508  */
2509 BOOL WINAPI GetKeyboardState( LPBYTE state )
2510 {
2511     BOOL ret;
2512
2513     TRACE("(%p)\n", state);
2514
2515     memset( state, 0, 256 );
2516     SERVER_START_REQ( get_key_state )
2517     {
2518         req->tid = GetCurrentThreadId();
2519         req->key = -1;
2520         wine_server_set_reply( req, state, 256 );
2521         ret = !wine_server_call_err( req );
2522     }
2523     SERVER_END_REQ;
2524     return ret;
2525 }
2526
2527
2528 /**********************************************************************
2529  *              SetKeyboardState (USER32.@)
2530  */
2531 BOOL WINAPI SetKeyboardState( LPBYTE state )
2532 {
2533     BOOL ret;
2534
2535     TRACE("(%p)\n", state);
2536
2537     SERVER_START_REQ( set_key_state )
2538     {
2539         req->tid = GetCurrentThreadId();
2540         wine_server_add_data( req, state, 256 );
2541         ret = !wine_server_call_err( req );
2542     }
2543     SERVER_END_REQ;
2544     return ret;
2545 }
2546
2547 /******************************************************************
2548  *              IsHungAppWindow (USER32.@)
2549  *
2550  */
2551 BOOL WINAPI IsHungAppWindow( HWND hWnd )
2552 {
2553     DWORD dwResult; 
2554     return !SendMessageTimeoutA(hWnd, WM_NULL, 0, 0, SMTO_ABORTIFHUNG, 5000, &dwResult);        
2555 }