user32: Pack the MDINEXTMENU structure in messages to allow crossing 32/64 boundaries.
[wine] / dlls / user32 / message.c
1 /*
2  * Window messaging support
3  *
4  * Copyright 2001 Alexandre Julliard
5  * Copyright 2008 Maarten Lankhorst
6  *
7  * This library is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU Lesser General Public
9  * License as published by the Free Software Foundation; either
10  * version 2.1 of the License, or (at your option) any later version.
11  *
12  * This library is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15  * Lesser General Public License for more details.
16  *
17  * You should have received a copy of the GNU Lesser General Public
18  * License along with this library; if not, write to the Free Software
19  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
20  */
21
22 #include "config.h"
23 #include "wine/port.h"
24
25 #include <assert.h>
26 #include <stdarg.h>
27
28 #include "ntstatus.h"
29 #define WIN32_NO_STATUS
30 #include "windef.h"
31 #include "winbase.h"
32 #include "wingdi.h"
33 #include "winuser.h"
34 #include "winerror.h"
35 #include "winnls.h"
36 #include "dbt.h"
37 #include "dde.h"
38 #include "imm.h"
39 #include "ddk/imm.h"
40 #include "wine/unicode.h"
41 #include "wine/server.h"
42 #include "user_private.h"
43 #include "win.h"
44 #include "controls.h"
45 #include "wine/debug.h"
46 #include "wine/exception.h"
47
48 WINE_DEFAULT_DEBUG_CHANNEL(msg);
49 WINE_DECLARE_DEBUG_CHANNEL(relay);
50 WINE_DECLARE_DEBUG_CHANNEL(key);
51
52 #define WM_NCMOUSEFIRST WM_NCMOUSEMOVE
53 #define WM_NCMOUSELAST  (WM_NCMOUSEFIRST+(WM_MOUSELAST-WM_MOUSEFIRST))
54
55 #define MAX_PACK_COUNT 4
56
57 #define SYS_TIMER_RATE  55   /* min. timer rate in ms (actually 54.925)*/
58
59 /* the various structures that can be sent in messages, in platform-independent layout */
60 struct packed_CREATESTRUCTW
61 {
62     ULONGLONG     lpCreateParams;
63     ULONGLONG     hInstance;
64     user_handle_t hMenu;
65     DWORD         __pad1;
66     user_handle_t hwndParent;
67     DWORD         __pad2;
68     INT           cy;
69     INT           cx;
70     INT           y;
71     INT           x;
72     LONG          style;
73     ULONGLONG     lpszName;
74     ULONGLONG     lpszClass;
75     DWORD         dwExStyle;
76     DWORD         __pad3;
77 };
78
79 struct packed_DRAWITEMSTRUCT
80 {
81     UINT          CtlType;
82     UINT          CtlID;
83     UINT          itemID;
84     UINT          itemAction;
85     UINT          itemState;
86     user_handle_t hwndItem;
87     DWORD         __pad1;
88     user_handle_t hDC;
89     DWORD         __pad2;
90     RECT          rcItem;
91     ULONGLONG     itemData;
92 };
93
94 struct packed_MEASUREITEMSTRUCT
95 {
96     UINT          CtlType;
97     UINT          CtlID;
98     UINT          itemID;
99     UINT          itemWidth;
100     UINT          itemHeight;
101     ULONGLONG     itemData;
102 };
103
104 struct packed_DELETEITEMSTRUCT
105 {
106     UINT          CtlType;
107     UINT          CtlID;
108     UINT          itemID;
109     user_handle_t hwndItem;
110     DWORD         __pad;
111     ULONGLONG     itemData;
112 };
113
114 struct packed_COMPAREITEMSTRUCT
115 {
116     UINT          CtlType;
117     UINT          CtlID;
118     user_handle_t hwndItem;
119     DWORD         __pad1;
120     UINT          itemID1;
121     ULONGLONG     itemData1;
122     UINT          itemID2;
123     ULONGLONG     itemData2;
124     DWORD         dwLocaleId;
125     DWORD         __pad2;
126 };
127
128 struct packed_WINDOWPOS
129 {
130     user_handle_t hwnd;
131     DWORD         __pad1;
132     user_handle_t hwndInsertAfter;
133     DWORD         __pad2;
134     INT           x;
135     INT           y;
136     INT           cx;
137     INT           cy;
138     UINT          flags;
139     DWORD         __pad3;
140 };
141
142 struct packed_COPYDATASTRUCT
143 {
144     ULONGLONG dwData;
145     DWORD     cbData;
146     ULONGLONG lpData;
147 };
148
149 struct packed_HELPINFO
150 {
151     UINT          cbSize;
152     INT           iContextType;
153     INT           iCtrlId;
154     user_handle_t hItemHandle;
155     DWORD         __pad;
156     ULONGLONG     dwContextId;
157     POINT         MousePos;
158 };
159
160 struct packed_NCCALCSIZE_PARAMS
161 {
162     RECT          rgrc[3];
163     ULONGLONG     __pad1;
164     user_handle_t hwnd;
165     DWORD         __pad2;
166     user_handle_t hwndInsertAfter;
167     DWORD         __pad3;
168     INT           x;
169     INT           y;
170     INT           cx;
171     INT           cy;
172     UINT          flags;
173     DWORD         __pad4;
174 };
175
176 struct packed_MSG
177 {
178     user_handle_t hwnd;
179     DWORD         __pad1;
180     UINT          message;
181     ULONGLONG     wParam;
182     ULONGLONG     lParam;
183     DWORD         time;
184     POINT         pt;
185     DWORD         __pad2;
186 };
187
188 struct packed_MDINEXTMENU
189 {
190     user_handle_t hmenuIn;
191     DWORD         __pad1;
192     user_handle_t hmenuNext;
193     DWORD         __pad2;
194     user_handle_t hwndNext;
195     DWORD         __pad3;
196 };
197
198 /* the structures are unpacked on top of the packed ones, so make sure they fit */
199 C_ASSERT( sizeof(struct packed_CREATESTRUCTW) >= sizeof(CREATESTRUCTW) );
200 C_ASSERT( sizeof(struct packed_DRAWITEMSTRUCT) >= sizeof(DRAWITEMSTRUCT) );
201 C_ASSERT( sizeof(struct packed_MEASUREITEMSTRUCT) >= sizeof(MEASUREITEMSTRUCT) );
202 C_ASSERT( sizeof(struct packed_DELETEITEMSTRUCT) >= sizeof(DELETEITEMSTRUCT) );
203 C_ASSERT( sizeof(struct packed_COMPAREITEMSTRUCT) >= sizeof(COMPAREITEMSTRUCT) );
204 C_ASSERT( sizeof(struct packed_WINDOWPOS) >= sizeof(WINDOWPOS) );
205 C_ASSERT( sizeof(struct packed_COPYDATASTRUCT) >= sizeof(COPYDATASTRUCT) );
206 C_ASSERT( sizeof(struct packed_HELPINFO) >= sizeof(HELPINFO) );
207 C_ASSERT( sizeof(struct packed_NCCALCSIZE_PARAMS) >= sizeof(NCCALCSIZE_PARAMS) + sizeof(WINDOWPOS) );
208 C_ASSERT( sizeof(struct packed_MSG) >= sizeof(MSG) );
209 C_ASSERT( sizeof(struct packed_MDINEXTMENU) >= sizeof(MDINEXTMENU) );
210
211 union packed_structs
212 {
213     struct packed_CREATESTRUCTW cs;
214     struct packed_DRAWITEMSTRUCT dis;
215     struct packed_MEASUREITEMSTRUCT mis;
216     struct packed_DELETEITEMSTRUCT dls;
217     struct packed_COMPAREITEMSTRUCT cis;
218     struct packed_WINDOWPOS wp;
219     struct packed_COPYDATASTRUCT cds;
220     struct packed_HELPINFO hi;
221     struct packed_NCCALCSIZE_PARAMS ncp;
222     struct packed_MSG msg;
223     struct packed_MDINEXTMENU mnm;
224 };
225
226 /* description of the data fields that need to be packed along with a sent message */
227 struct packed_message
228 {
229     union packed_structs ps;
230     int                  count;
231     const void          *data[MAX_PACK_COUNT];
232     size_t               size[MAX_PACK_COUNT];
233 };
234
235 /* info about the message currently being received by the current thread */
236 struct received_message_info
237 {
238     enum message_type type;
239     MSG               msg;
240     UINT              flags;  /* InSendMessageEx return flags */
241 };
242
243 /* structure to group all parameters for sent messages of the various kinds */
244 struct send_message_info
245 {
246     enum message_type type;
247     DWORD             dest_tid;
248     HWND              hwnd;
249     UINT              msg;
250     WPARAM            wparam;
251     LPARAM            lparam;
252     UINT              flags;      /* flags for SendMessageTimeout */
253     UINT              timeout;    /* timeout for SendMessageTimeout */
254     SENDASYNCPROC     callback;   /* callback function for SendMessageCallback */
255     ULONG_PTR         data;       /* callback data */
256     enum wm_char_mapping wm_char;
257 };
258
259
260 /* Message class descriptor */
261 static const WCHAR messageW[] = {'M','e','s','s','a','g','e',0};
262
263 const struct builtin_class_descr MESSAGE_builtin_class =
264 {
265     messageW,             /* name */
266     0,                    /* style */
267     WINPROC_MESSAGE,      /* proc */
268     0,                    /* extra */
269     IDC_ARROW,            /* cursor */
270     0                     /* brush */
271 };
272
273
274
275 /* flag for messages that contain pointers */
276 /* 32 messages per entry, messages 0..31 map to bits 0..31 */
277
278 #define SET(msg) (1 << ((msg) & 31))
279
280 static const unsigned int message_pointer_flags[] =
281 {
282     /* 0x00 - 0x1f */
283     SET(WM_CREATE) | SET(WM_SETTEXT) | SET(WM_GETTEXT) |
284     SET(WM_WININICHANGE) | SET(WM_DEVMODECHANGE),
285     /* 0x20 - 0x3f */
286     SET(WM_GETMINMAXINFO) | SET(WM_DRAWITEM) | SET(WM_MEASUREITEM) | SET(WM_DELETEITEM) |
287     SET(WM_COMPAREITEM),
288     /* 0x40 - 0x5f */
289     SET(WM_WINDOWPOSCHANGING) | SET(WM_WINDOWPOSCHANGED) | SET(WM_COPYDATA) |
290     SET(WM_NOTIFY) | SET(WM_HELP),
291     /* 0x60 - 0x7f */
292     SET(WM_STYLECHANGING) | SET(WM_STYLECHANGED),
293     /* 0x80 - 0x9f */
294     SET(WM_NCCREATE) | SET(WM_NCCALCSIZE) | SET(WM_GETDLGCODE),
295     /* 0xa0 - 0xbf */
296     SET(EM_GETSEL) | SET(EM_GETRECT) | SET(EM_SETRECT) | SET(EM_SETRECTNP),
297     /* 0xc0 - 0xdf */
298     SET(EM_REPLACESEL) | SET(EM_GETLINE) | SET(EM_SETTABSTOPS),
299     /* 0xe0 - 0xff */
300     SET(SBM_GETRANGE) | SET(SBM_SETSCROLLINFO) | SET(SBM_GETSCROLLINFO) | SET(SBM_GETSCROLLBARINFO),
301     /* 0x100 - 0x11f */
302     0,
303     /* 0x120 - 0x13f */
304     0,
305     /* 0x140 - 0x15f */
306     SET(CB_GETEDITSEL) | SET(CB_ADDSTRING) | SET(CB_DIR) | SET(CB_GETLBTEXT) |
307     SET(CB_INSERTSTRING) | SET(CB_FINDSTRING) | SET(CB_SELECTSTRING) |
308     SET(CB_GETDROPPEDCONTROLRECT) | SET(CB_FINDSTRINGEXACT),
309     /* 0x160 - 0x17f */
310     0,
311     /* 0x180 - 0x19f */
312     SET(LB_ADDSTRING) | SET(LB_INSERTSTRING) | SET(LB_GETTEXT) | SET(LB_SELECTSTRING) |
313     SET(LB_DIR) | SET(LB_FINDSTRING) |
314     SET(LB_GETSELITEMS) | SET(LB_SETTABSTOPS) | SET(LB_ADDFILE) | SET(LB_GETITEMRECT),
315     /* 0x1a0 - 0x1bf */
316     SET(LB_FINDSTRINGEXACT),
317     /* 0x1c0 - 0x1df */
318     0,
319     /* 0x1e0 - 0x1ff */
320     0,
321     /* 0x200 - 0x21f */
322     SET(WM_NEXTMENU) | SET(WM_SIZING) | SET(WM_MOVING) | SET(WM_DEVICECHANGE),
323     /* 0x220 - 0x23f */
324     SET(WM_MDICREATE) | SET(WM_MDIGETACTIVE) | SET(WM_DROPOBJECT) |
325     SET(WM_QUERYDROPOBJECT) | SET(WM_DRAGLOOP) | SET(WM_DRAGSELECT) | SET(WM_DRAGMOVE),
326     /* 0x240 - 0x25f */
327     0,
328     /* 0x260 - 0x27f */
329     0,
330     /* 0x280 - 0x29f */
331     0,
332     /* 0x2a0 - 0x2bf */
333     0,
334     /* 0x2c0 - 0x2df */
335     0,
336     /* 0x2e0 - 0x2ff */
337     0,
338     /* 0x300 - 0x31f */
339     SET(WM_ASKCBFORMATNAME)
340 };
341
342 /* flags for messages that contain Unicode strings */
343 static const unsigned int message_unicode_flags[] =
344 {
345     /* 0x00 - 0x1f */
346     SET(WM_CREATE) | SET(WM_SETTEXT) | SET(WM_GETTEXT) | SET(WM_GETTEXTLENGTH) |
347     SET(WM_WININICHANGE) | SET(WM_DEVMODECHANGE),
348     /* 0x20 - 0x3f */
349     SET(WM_CHARTOITEM),
350     /* 0x40 - 0x5f */
351     0,
352     /* 0x60 - 0x7f */
353     0,
354     /* 0x80 - 0x9f */
355     SET(WM_NCCREATE),
356     /* 0xa0 - 0xbf */
357     0,
358     /* 0xc0 - 0xdf */
359     SET(EM_REPLACESEL) | SET(EM_GETLINE) | SET(EM_SETPASSWORDCHAR),
360     /* 0xe0 - 0xff */
361     0,
362     /* 0x100 - 0x11f */
363     SET(WM_CHAR) | SET(WM_DEADCHAR) | SET(WM_SYSCHAR) | SET(WM_SYSDEADCHAR),
364     /* 0x120 - 0x13f */
365     SET(WM_MENUCHAR),
366     /* 0x140 - 0x15f */
367     SET(CB_ADDSTRING) | SET(CB_DIR) | SET(CB_GETLBTEXT) | SET(CB_GETLBTEXTLEN) |
368     SET(CB_INSERTSTRING) | SET(CB_FINDSTRING) | SET(CB_SELECTSTRING) | SET(CB_FINDSTRINGEXACT),
369     /* 0x160 - 0x17f */
370     0,
371     /* 0x180 - 0x19f */
372     SET(LB_ADDSTRING) | SET(LB_INSERTSTRING) | SET(LB_GETTEXT) | SET(LB_GETTEXTLEN) |
373     SET(LB_SELECTSTRING) | SET(LB_DIR) | SET(LB_FINDSTRING) | SET(LB_ADDFILE),
374     /* 0x1a0 - 0x1bf */
375     SET(LB_FINDSTRINGEXACT),
376     /* 0x1c0 - 0x1df */
377     0,
378     /* 0x1e0 - 0x1ff */
379     0,
380     /* 0x200 - 0x21f */
381     0,
382     /* 0x220 - 0x23f */
383     SET(WM_MDICREATE),
384     /* 0x240 - 0x25f */
385     0,
386     /* 0x260 - 0x27f */
387     0,
388     /* 0x280 - 0x29f */
389     SET(WM_IME_CHAR),
390     /* 0x2a0 - 0x2bf */
391     0,
392     /* 0x2c0 - 0x2df */
393     0,
394     /* 0x2e0 - 0x2ff */
395     0,
396     /* 0x300 - 0x31f */
397     SET(WM_PAINTCLIPBOARD) | SET(WM_SIZECLIPBOARD) | SET(WM_ASKCBFORMATNAME)
398 };
399
400 /* check whether a given message type includes pointers */
401 static inline int is_pointer_message( UINT message )
402 {
403     if (message >= 8*sizeof(message_pointer_flags)) return FALSE;
404     return (message_pointer_flags[message / 32] & SET(message)) != 0;
405 }
406
407 /* check whether a given message type contains Unicode (or ASCII) chars */
408 static inline int is_unicode_message( UINT message )
409 {
410     if (message >= 8*sizeof(message_unicode_flags)) return FALSE;
411     return (message_unicode_flags[message / 32] & SET(message)) != 0;
412 }
413
414 #undef SET
415
416 /* add a data field to a packed message */
417 static inline void push_data( struct packed_message *data, const void *ptr, size_t size )
418 {
419     data->data[data->count] = ptr;
420     data->size[data->count] = size;
421     data->count++;
422 }
423
424 /* add a string to a packed message */
425 static inline void push_string( struct packed_message *data, LPCWSTR str )
426 {
427     push_data( data, str, (strlenW(str) + 1) * sizeof(WCHAR) );
428 }
429
430 /* make sure that the buffer contains a valid null-terminated Unicode string */
431 static inline BOOL check_string( LPCWSTR str, size_t size )
432 {
433     for (size /= sizeof(WCHAR); size; size--, str++)
434         if (!*str) return TRUE;
435     return FALSE;
436 }
437
438 /* pack a pointer into a 32/64 portable format */
439 static inline ULONGLONG pack_ptr( const void *ptr )
440 {
441     return (ULONG_PTR)ptr;
442 }
443
444 /* unpack a potentially 64-bit pointer, returning 0 when truncated */
445 static inline void *unpack_ptr( ULONGLONG ptr64 )
446 {
447     if ((ULONG_PTR)ptr64 != ptr64) return 0;
448     return (void *)(ULONG_PTR)ptr64;
449 }
450
451 /* make sure that there is space for 'size' bytes in buffer, growing it if needed */
452 static inline void *get_buffer_space( void **buffer, size_t size )
453 {
454     void *ret;
455
456     if (*buffer)
457     {
458         if (!(ret = HeapReAlloc( GetProcessHeap(), 0, *buffer, size )))
459             HeapFree( GetProcessHeap(), 0, *buffer );
460     }
461     else ret = HeapAlloc( GetProcessHeap(), 0, size );
462
463     *buffer = ret;
464     return ret;
465 }
466
467 /* check whether a combobox expects strings or ids in CB_ADDSTRING/CB_INSERTSTRING */
468 static inline BOOL combobox_has_strings( HWND hwnd )
469 {
470     DWORD style = GetWindowLongA( hwnd, GWL_STYLE );
471     return (!(style & (CBS_OWNERDRAWFIXED | CBS_OWNERDRAWVARIABLE)) || (style & CBS_HASSTRINGS));
472 }
473
474 /* check whether a listbox expects strings or ids in LB_ADDSTRING/LB_INSERTSTRING */
475 static inline BOOL listbox_has_strings( HWND hwnd )
476 {
477     DWORD style = GetWindowLongA( hwnd, GWL_STYLE );
478     return (!(style & (LBS_OWNERDRAWFIXED | LBS_OWNERDRAWVARIABLE)) || (style & LBS_HASSTRINGS));
479 }
480
481 /* check whether message is in the range of keyboard messages */
482 static inline BOOL is_keyboard_message( UINT message )
483 {
484     return (message >= WM_KEYFIRST && message <= WM_KEYLAST);
485 }
486
487 /* check whether message is in the range of mouse messages */
488 static inline BOOL is_mouse_message( UINT message )
489 {
490     return ((message >= WM_NCMOUSEFIRST && message <= WM_NCMOUSELAST) ||
491             (message >= WM_MOUSEFIRST && message <= WM_MOUSELAST));
492 }
493
494 /* check whether message matches the specified hwnd filter */
495 static inline BOOL check_hwnd_filter( const MSG *msg, HWND hwnd_filter )
496 {
497     if (!hwnd_filter || hwnd_filter == GetDesktopWindow()) return TRUE;
498     return (msg->hwnd == hwnd_filter || IsChild( hwnd_filter, msg->hwnd ));
499 }
500
501 /* check for pending WM_CHAR message with DBCS trailing byte */
502 static inline BOOL get_pending_wmchar( MSG *msg, UINT first, UINT last, BOOL remove )
503 {
504     struct wm_char_mapping_data *data = get_user_thread_info()->wmchar_data;
505
506     if (!data || !data->get_msg.message) return FALSE;
507     if ((first || last) && (first > WM_CHAR || last < WM_CHAR)) return FALSE;
508     if (!msg) return FALSE;
509     *msg = data->get_msg;
510     if (remove) data->get_msg.message = 0;
511     return TRUE;
512 }
513
514
515 /***********************************************************************
516  *           MessageWndProc
517  *
518  * Window procedure for "Message" windows (HWND_MESSAGE parent).
519  */
520 LRESULT WINAPI MessageWndProc( HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam )
521 {
522     if (message == WM_NCCREATE) return TRUE;
523     return 0;  /* all other messages are ignored */
524 }
525
526
527 /***********************************************************************
528  *              broadcast_message_callback
529  *
530  * Helper callback for broadcasting messages.
531  */
532 static BOOL CALLBACK broadcast_message_callback( HWND hwnd, LPARAM lparam )
533 {
534     struct send_message_info *info = (struct send_message_info *)lparam;
535     if (!(GetWindowLongW( hwnd, GWL_STYLE ) & (WS_POPUP|WS_CAPTION))) return TRUE;
536     switch(info->type)
537     {
538     case MSG_UNICODE:
539         SendMessageTimeoutW( hwnd, info->msg, info->wparam, info->lparam,
540                              info->flags, info->timeout, NULL );
541         break;
542     case MSG_ASCII:
543         SendMessageTimeoutA( hwnd, info->msg, info->wparam, info->lparam,
544                              info->flags, info->timeout, NULL );
545         break;
546     case MSG_NOTIFY:
547         SendNotifyMessageW( hwnd, info->msg, info->wparam, info->lparam );
548         break;
549     case MSG_CALLBACK:
550         SendMessageCallbackW( hwnd, info->msg, info->wparam, info->lparam,
551                               info->callback, info->data );
552         break;
553     case MSG_POSTED:
554         PostMessageW( hwnd, info->msg, info->wparam, info->lparam );
555         break;
556     default:
557         ERR( "bad type %d\n", info->type );
558         break;
559     }
560     return TRUE;
561 }
562
563
564 /***********************************************************************
565  *              map_wparam_AtoW
566  *
567  * Convert the wparam of an ASCII message to Unicode.
568  */
569 BOOL map_wparam_AtoW( UINT message, WPARAM *wparam, enum wm_char_mapping mapping )
570 {
571     char ch[2];
572     WCHAR wch[2];
573
574     wch[0] = wch[1] = 0;
575     switch(message)
576     {
577     case WM_CHAR:
578         /* WM_CHAR is magic: a DBCS char can be sent/posted as two consecutive WM_CHAR
579          * messages, in which case the first char is stored, and the conversion
580          * to Unicode only takes place once the second char is sent/posted.
581          */
582         if (mapping != WMCHAR_MAP_NOMAPPING)
583         {
584             struct wm_char_mapping_data *data = get_user_thread_info()->wmchar_data;
585             BYTE low = LOBYTE(*wparam);
586
587             if (HIBYTE(*wparam))
588             {
589                 ch[0] = low;
590                 ch[1] = HIBYTE(*wparam);
591                 RtlMultiByteToUnicodeN( wch, sizeof(wch), NULL, ch, 2 );
592                 TRACE( "map %02x,%02x -> %04x mapping %u\n", (BYTE)ch[0], (BYTE)ch[1], wch[0], mapping );
593                 if (data) data->lead_byte[mapping] = 0;
594             }
595             else if (data && data->lead_byte[mapping])
596             {
597                 ch[0] = data->lead_byte[mapping];
598                 ch[1] = low;
599                 RtlMultiByteToUnicodeN( wch, sizeof(wch), NULL, ch, 2 );
600                 TRACE( "map stored %02x,%02x -> %04x mapping %u\n", (BYTE)ch[0], (BYTE)ch[1], wch[0], mapping );
601                 data->lead_byte[mapping] = 0;
602             }
603             else if (!IsDBCSLeadByte( low ))
604             {
605                 ch[0] = low;
606                 RtlMultiByteToUnicodeN( wch, sizeof(wch), NULL, ch, 1 );
607                 TRACE( "map %02x -> %04x\n", (BYTE)ch[0], wch[0] );
608                 if (data) data->lead_byte[mapping] = 0;
609             }
610             else  /* store it and wait for trail byte */
611             {
612                 if (!data)
613                 {
614                     if (!(data = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*data) )))
615                         return FALSE;
616                     get_user_thread_info()->wmchar_data = data;
617                 }
618                 TRACE( "storing lead byte %02x mapping %u\n", low, mapping );
619                 data->lead_byte[mapping] = low;
620                 return FALSE;
621             }
622             *wparam = MAKEWPARAM(wch[0], wch[1]);
623             break;
624         }
625         /* else fall through */
626     case WM_CHARTOITEM:
627     case EM_SETPASSWORDCHAR:
628     case WM_DEADCHAR:
629     case WM_SYSCHAR:
630     case WM_SYSDEADCHAR:
631     case WM_MENUCHAR:
632         ch[0] = LOBYTE(*wparam);
633         ch[1] = HIBYTE(*wparam);
634         RtlMultiByteToUnicodeN( wch, sizeof(wch), NULL, ch, 2 );
635         *wparam = MAKEWPARAM(wch[0], wch[1]);
636         break;
637     case WM_IME_CHAR:
638         ch[0] = HIBYTE(*wparam);
639         ch[1] = LOBYTE(*wparam);
640         if (ch[0]) RtlMultiByteToUnicodeN( wch, sizeof(wch[0]), NULL, ch, 2 );
641         else RtlMultiByteToUnicodeN( wch, sizeof(wch[0]), NULL, ch + 1, 1 );
642         *wparam = MAKEWPARAM(wch[0], HIWORD(*wparam));
643         break;
644     }
645     return TRUE;
646 }
647
648
649 /***********************************************************************
650  *              map_wparam_WtoA
651  *
652  * Convert the wparam of a Unicode message to ASCII.
653  */
654 static void map_wparam_WtoA( MSG *msg, BOOL remove )
655 {
656     BYTE ch[2];
657     WCHAR wch[2];
658     DWORD len;
659
660     switch(msg->message)
661     {
662     case WM_CHAR:
663         if (!HIWORD(msg->wParam))
664         {
665             wch[0] = LOWORD(msg->wParam);
666             ch[0] = ch[1] = 0;
667             RtlUnicodeToMultiByteN( (LPSTR)ch, 2, &len, wch, sizeof(wch[0]) );
668             if (len == 2)  /* DBCS char */
669             {
670                 struct wm_char_mapping_data *data = get_user_thread_info()->wmchar_data;
671                 if (!data)
672                 {
673                     if (!(data = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*data) ))) return;
674                     get_user_thread_info()->wmchar_data = data;
675                 }
676                 if (remove)
677                 {
678                     data->get_msg = *msg;
679                     data->get_msg.wParam = ch[1];
680                 }
681                 msg->wParam = ch[0];
682                 return;
683             }
684         }
685         /* else fall through */
686     case WM_CHARTOITEM:
687     case EM_SETPASSWORDCHAR:
688     case WM_DEADCHAR:
689     case WM_SYSCHAR:
690     case WM_SYSDEADCHAR:
691     case WM_MENUCHAR:
692         wch[0] = LOWORD(msg->wParam);
693         wch[1] = HIWORD(msg->wParam);
694         ch[0] = ch[1] = 0;
695         RtlUnicodeToMultiByteN( (LPSTR)ch, 2, NULL, wch, sizeof(wch) );
696         msg->wParam = MAKEWPARAM( ch[0] | (ch[1] << 8), 0 );
697         break;
698     case WM_IME_CHAR:
699         wch[0] = LOWORD(msg->wParam);
700         ch[0] = ch[1] = 0;
701         RtlUnicodeToMultiByteN( (LPSTR)ch, 2, &len, wch, sizeof(wch[0]) );
702         if (len == 2)
703             msg->wParam = MAKEWPARAM( (ch[0] << 8) | ch[1], HIWORD(msg->wParam) );
704         else
705             msg->wParam = MAKEWPARAM( ch[0], HIWORD(msg->wParam) );
706         break;
707     }
708 }
709
710
711 /***********************************************************************
712  *              pack_message
713  *
714  * Pack a message for sending to another process.
715  * Return the size of the data we expect in the message reply.
716  * Set data->count to -1 if there is an error.
717  */
718 static size_t pack_message( HWND hwnd, UINT message, WPARAM wparam, LPARAM lparam,
719                             struct packed_message *data )
720 {
721     data->count = 0;
722     switch(message)
723     {
724     case WM_NCCREATE:
725     case WM_CREATE:
726     {
727         CREATESTRUCTW *cs = (CREATESTRUCTW *)lparam;
728         data->ps.cs.lpCreateParams = pack_ptr( cs->lpCreateParams );
729         data->ps.cs.hInstance      = pack_ptr( cs->hInstance );
730         data->ps.cs.hMenu          = wine_server_user_handle( cs->hMenu );
731         data->ps.cs.hwndParent     = wine_server_user_handle( cs->hwndParent );
732         data->ps.cs.cy             = cs->cy;
733         data->ps.cs.cx             = cs->cx;
734         data->ps.cs.y              = cs->y;
735         data->ps.cs.x              = cs->x;
736         data->ps.cs.style          = cs->style;
737         data->ps.cs.dwExStyle      = cs->dwExStyle;
738         data->ps.cs.lpszName       = pack_ptr( cs->lpszName );
739         data->ps.cs.lpszClass      = pack_ptr( cs->lpszClass );
740         push_data( data, &data->ps.cs, sizeof(data->ps.cs) );
741         if (!IS_INTRESOURCE(cs->lpszName)) push_string( data, cs->lpszName );
742         if (!IS_INTRESOURCE(cs->lpszClass)) push_string( data, cs->lpszClass );
743         return sizeof(data->ps.cs);
744     }
745     case WM_GETTEXT:
746     case WM_ASKCBFORMATNAME:
747         return wparam * sizeof(WCHAR);
748     case WM_WININICHANGE:
749         if (lparam) push_string(data, (LPWSTR)lparam );
750         return 0;
751     case WM_SETTEXT:
752     case WM_DEVMODECHANGE:
753     case CB_DIR:
754     case LB_DIR:
755     case LB_ADDFILE:
756     case EM_REPLACESEL:
757         push_string( data, (LPWSTR)lparam );
758         return 0;
759     case WM_GETMINMAXINFO:
760         push_data( data, (MINMAXINFO *)lparam, sizeof(MINMAXINFO) );
761         return sizeof(MINMAXINFO);
762     case WM_DRAWITEM:
763     {
764         DRAWITEMSTRUCT *dis = (DRAWITEMSTRUCT *)lparam;
765         data->ps.dis.CtlType    = dis->CtlType;
766         data->ps.dis.CtlID      = dis->CtlID;
767         data->ps.dis.itemID     = dis->itemID;
768         data->ps.dis.itemAction = dis->itemAction;
769         data->ps.dis.itemState  = dis->itemState;
770         data->ps.dis.hwndItem   = wine_server_user_handle( dis->hwndItem );
771         data->ps.dis.hDC        = wine_server_user_handle( dis->hDC );  /* FIXME */
772         data->ps.dis.rcItem     = dis->rcItem;
773         data->ps.dis.itemData   = dis->itemData;
774         push_data( data, &data->ps.dis, sizeof(data->ps.dis) );
775         return 0;
776     }
777     case WM_MEASUREITEM:
778     {
779         MEASUREITEMSTRUCT *mis = (MEASUREITEMSTRUCT *)lparam;
780         data->ps.mis.CtlType    = mis->CtlType;
781         data->ps.mis.CtlID      = mis->CtlID;
782         data->ps.mis.itemID     = mis->itemID;
783         data->ps.mis.itemWidth  = mis->itemWidth;
784         data->ps.mis.itemHeight = mis->itemHeight;
785         data->ps.mis.itemData   = mis->itemData;
786         push_data( data, &data->ps.mis, sizeof(data->ps.mis) );
787         return sizeof(data->ps.mis);
788     }
789     case WM_DELETEITEM:
790     {
791         DELETEITEMSTRUCT *dls = (DELETEITEMSTRUCT *)lparam;
792         data->ps.dls.CtlType    = dls->CtlType;
793         data->ps.dls.CtlID      = dls->CtlID;
794         data->ps.dls.itemID     = dls->itemID;
795         data->ps.dls.hwndItem   = wine_server_user_handle( dls->hwndItem );
796         data->ps.dls.itemData   = dls->itemData;
797         push_data( data, &data->ps.dls, sizeof(data->ps.dls) );
798         return 0;
799     }
800     case WM_COMPAREITEM:
801     {
802         COMPAREITEMSTRUCT *cis = (COMPAREITEMSTRUCT *)lparam;
803         data->ps.cis.CtlType    = cis->CtlType;
804         data->ps.cis.CtlID      = cis->CtlID;
805         data->ps.cis.hwndItem   = wine_server_user_handle( cis->hwndItem );
806         data->ps.cis.itemID1    = cis->itemID1;
807         data->ps.cis.itemData1  = cis->itemData1;
808         data->ps.cis.itemID2    = cis->itemID2;
809         data->ps.cis.itemData2  = cis->itemData2;
810         data->ps.cis.dwLocaleId = cis->dwLocaleId;
811         push_data( data, &data->ps.cis, sizeof(data->ps.cis) );
812         return 0;
813     }
814     case WM_WINDOWPOSCHANGING:
815     case WM_WINDOWPOSCHANGED:
816     {
817         WINDOWPOS *wp = (WINDOWPOS *)lparam;
818         data->ps.wp.hwnd            = wine_server_user_handle( wp->hwnd );
819         data->ps.wp.hwndInsertAfter = wine_server_user_handle( wp->hwndInsertAfter );
820         data->ps.wp.x               = wp->x;
821         data->ps.wp.y               = wp->y;
822         data->ps.wp.cx              = wp->cx;
823         data->ps.wp.cy              = wp->cy;
824         data->ps.wp.flags           = wp->flags;
825         push_data( data, &data->ps.wp, sizeof(data->ps.wp) );
826         return sizeof(data->ps.wp);
827     }
828     case WM_COPYDATA:
829     {
830         COPYDATASTRUCT *cds = (COPYDATASTRUCT *)lparam;
831         data->ps.cds.cbData = cds->cbData;
832         data->ps.cds.dwData = cds->dwData;
833         data->ps.cds.lpData = pack_ptr( cds->lpData );
834         push_data( data, &data->ps.cds, sizeof(data->ps.cds) );
835         if (cds->lpData) push_data( data, cds->lpData, cds->cbData );
836         return 0;
837     }
838     case WM_NOTIFY:
839         /* WM_NOTIFY cannot be sent across processes (MSDN) */
840         data->count = -1;
841         return 0;
842     case WM_HELP:
843     {
844         HELPINFO *hi = (HELPINFO *)lparam;
845         data->ps.hi.iContextType = hi->iContextType;
846         data->ps.hi.iCtrlId      = hi->iCtrlId;
847         data->ps.hi.hItemHandle  = wine_server_user_handle( hi->hItemHandle );
848         data->ps.hi.dwContextId  = hi->dwContextId;
849         data->ps.hi.MousePos     = hi->MousePos;
850         push_data( data, &data->ps.hi, sizeof(data->ps.hi) );
851         return 0;
852     }
853     case WM_STYLECHANGING:
854     case WM_STYLECHANGED:
855         push_data( data, (STYLESTRUCT *)lparam, sizeof(STYLESTRUCT) );
856         return 0;
857     case WM_NCCALCSIZE:
858         if (!wparam)
859         {
860             push_data( data, (RECT *)lparam, sizeof(RECT) );
861             return sizeof(RECT);
862         }
863         else
864         {
865             NCCALCSIZE_PARAMS *ncp = (NCCALCSIZE_PARAMS *)lparam;
866             data->ps.ncp.rgrc[0]         = ncp->rgrc[0];
867             data->ps.ncp.rgrc[1]         = ncp->rgrc[1];
868             data->ps.ncp.rgrc[2]         = ncp->rgrc[2];
869             data->ps.ncp.hwnd            = wine_server_user_handle( ncp->lppos->hwnd );
870             data->ps.ncp.hwndInsertAfter = wine_server_user_handle( ncp->lppos->hwndInsertAfter );
871             data->ps.ncp.x               = ncp->lppos->x;
872             data->ps.ncp.y               = ncp->lppos->y;
873             data->ps.ncp.cx              = ncp->lppos->cx;
874             data->ps.ncp.cy              = ncp->lppos->cy;
875             data->ps.ncp.flags           = ncp->lppos->flags;
876             push_data( data, &data->ps.ncp, sizeof(data->ps.ncp) );
877             return sizeof(data->ps.ncp);
878         }
879     case WM_GETDLGCODE:
880         if (lparam)
881         {
882             MSG *msg = (MSG *)lparam;
883             data->ps.msg.hwnd    = wine_server_user_handle( msg->hwnd );
884             data->ps.msg.message = msg->message;
885             data->ps.msg.wParam  = msg->wParam;
886             data->ps.msg.lParam  = msg->lParam;
887             data->ps.msg.time    = msg->time;
888             data->ps.msg.pt      = msg->pt;
889             push_data( data, &data->ps.msg, sizeof(data->ps.msg) );
890             return sizeof(data->ps.msg);
891         }
892         return 0;
893     case SBM_SETSCROLLINFO:
894         push_data( data, (SCROLLINFO *)lparam, sizeof(SCROLLINFO) );
895         return 0;
896     case SBM_GETSCROLLINFO:
897         push_data( data, (SCROLLINFO *)lparam, sizeof(SCROLLINFO) );
898         return sizeof(SCROLLINFO);
899     case SBM_GETSCROLLBARINFO:
900     {
901         const SCROLLBARINFO *info = (const SCROLLBARINFO *)lparam;
902         size_t size = min( info->cbSize, sizeof(SCROLLBARINFO) );
903         push_data( data, info, size );
904         return size;
905     }
906     case EM_GETSEL:
907     case SBM_GETRANGE:
908     case CB_GETEDITSEL:
909     {
910         size_t size = 0;
911         if (wparam) size += sizeof(DWORD);
912         if (lparam) size += sizeof(DWORD);
913         return size;
914     }
915     case EM_GETRECT:
916     case LB_GETITEMRECT:
917     case CB_GETDROPPEDCONTROLRECT:
918         return sizeof(RECT);
919     case EM_SETRECT:
920     case EM_SETRECTNP:
921         push_data( data, (RECT *)lparam, sizeof(RECT) );
922         return 0;
923     case EM_GETLINE:
924     {
925         WORD *pw = (WORD *)lparam;
926         push_data( data, pw, sizeof(*pw) );
927         return *pw * sizeof(WCHAR);
928     }
929     case EM_SETTABSTOPS:
930     case LB_SETTABSTOPS:
931         if (wparam) push_data( data, (UINT *)lparam, sizeof(UINT) * wparam );
932         return 0;
933     case CB_ADDSTRING:
934     case CB_INSERTSTRING:
935     case CB_FINDSTRING:
936     case CB_FINDSTRINGEXACT:
937     case CB_SELECTSTRING:
938         if (combobox_has_strings( hwnd )) push_string( data, (LPWSTR)lparam );
939         return 0;
940     case CB_GETLBTEXT:
941         if (!combobox_has_strings( hwnd )) return sizeof(ULONG_PTR);
942         return (SendMessageW( hwnd, CB_GETLBTEXTLEN, wparam, 0 ) + 1) * sizeof(WCHAR);
943     case LB_ADDSTRING:
944     case LB_INSERTSTRING:
945     case LB_FINDSTRING:
946     case LB_FINDSTRINGEXACT:
947     case LB_SELECTSTRING:
948         if (listbox_has_strings( hwnd )) push_string( data, (LPWSTR)lparam );
949         return 0;
950     case LB_GETTEXT:
951         if (!listbox_has_strings( hwnd )) return sizeof(ULONG_PTR);
952         return (SendMessageW( hwnd, LB_GETTEXTLEN, wparam, 0 ) + 1) * sizeof(WCHAR);
953     case LB_GETSELITEMS:
954         return wparam * sizeof(UINT);
955     case WM_NEXTMENU:
956     {
957         MDINEXTMENU *mnm = (MDINEXTMENU *)lparam;
958         data->ps.mnm.hmenuIn   = wine_server_user_handle( mnm->hmenuIn );
959         data->ps.mnm.hmenuNext = wine_server_user_handle( mnm->hmenuNext );
960         data->ps.mnm.hwndNext  = wine_server_user_handle( mnm->hwndNext );
961         push_data( data, &data->ps.mnm, sizeof(data->ps.mnm) );
962         return sizeof(data->ps.mnm);
963     }
964     case WM_SIZING:
965     case WM_MOVING:
966         push_data( data, (RECT *)lparam, sizeof(RECT) );
967         return sizeof(RECT);
968     case WM_MDICREATE:
969     {
970         MDICREATESTRUCTW *cs = (MDICREATESTRUCTW *)lparam;
971         push_data( data, cs, sizeof(*cs) );
972         if (!IS_INTRESOURCE(cs->szTitle)) push_string( data, cs->szTitle );
973         if (!IS_INTRESOURCE(cs->szClass)) push_string( data, cs->szClass );
974         return sizeof(*cs);
975     }
976     case WM_MDIGETACTIVE:
977         if (lparam) return sizeof(BOOL);
978         return 0;
979     case WM_DEVICECHANGE:
980     {
981         DEV_BROADCAST_HDR *header = (DEV_BROADCAST_HDR *)lparam;
982         push_data( data, header, header->dbch_size );
983         return 0;
984     }
985     case WM_WINE_SETWINDOWPOS:
986         push_data( data, (WINDOWPOS *)lparam, sizeof(WINDOWPOS) );
987         return 0;
988     case WM_WINE_KEYBOARD_LL_HOOK:
989     {
990         struct hook_extra_info *h_extra = (struct hook_extra_info *)lparam;
991         push_data( data, h_extra, sizeof(*h_extra) );
992         push_data( data, (LPVOID)h_extra->lparam, sizeof(KBDLLHOOKSTRUCT) );
993         return 0;
994     }
995     case WM_WINE_MOUSE_LL_HOOK:
996     {
997         struct hook_extra_info *h_extra = (struct hook_extra_info *)lparam;
998         push_data( data, h_extra, sizeof(*h_extra) );
999         push_data( data, (LPVOID)h_extra->lparam, sizeof(MSLLHOOKSTRUCT) );
1000         return 0;
1001     }
1002     case WM_NCPAINT:
1003         if (wparam <= 1) return 0;
1004         FIXME( "WM_NCPAINT hdc packing not supported yet\n" );
1005         data->count = -1;
1006         return 0;
1007     case WM_PAINT:
1008         if (!wparam) return 0;
1009         /* fall through */
1010
1011     /* these contain an HFONT */
1012     case WM_SETFONT:
1013     case WM_GETFONT:
1014     /* these contain an HDC */
1015     case WM_ERASEBKGND:
1016     case WM_ICONERASEBKGND:
1017     case WM_CTLCOLORMSGBOX:
1018     case WM_CTLCOLOREDIT:
1019     case WM_CTLCOLORLISTBOX:
1020     case WM_CTLCOLORBTN:
1021     case WM_CTLCOLORDLG:
1022     case WM_CTLCOLORSCROLLBAR:
1023     case WM_CTLCOLORSTATIC:
1024     case WM_PRINT:
1025     case WM_PRINTCLIENT:
1026     /* these contain an HGLOBAL */
1027     case WM_PAINTCLIPBOARD:
1028     case WM_SIZECLIPBOARD:
1029     /* these contain HICON */
1030     case WM_GETICON:
1031     case WM_SETICON:
1032     case WM_QUERYDRAGICON:
1033     case WM_QUERYPARKICON:
1034     /* these contain pointers */
1035     case WM_DROPOBJECT:
1036     case WM_QUERYDROPOBJECT:
1037     case WM_DRAGLOOP:
1038     case WM_DRAGSELECT:
1039     case WM_DRAGMOVE:
1040         FIXME( "msg %x (%s) not supported yet\n", message, SPY_GetMsgName(message, hwnd) );
1041         data->count = -1;
1042         return 0;
1043     }
1044     return 0;
1045 }
1046
1047
1048 /***********************************************************************
1049  *              unpack_message
1050  *
1051  * Unpack a message received from another process.
1052  */
1053 static BOOL unpack_message( HWND hwnd, UINT message, WPARAM *wparam, LPARAM *lparam,
1054                             void **buffer, size_t size )
1055 {
1056     size_t minsize = 0;
1057     union packed_structs *ps = *buffer;
1058
1059     switch(message)
1060     {
1061     case WM_NCCREATE:
1062     case WM_CREATE:
1063     {
1064         CREATESTRUCTW cs;
1065         WCHAR *str = (WCHAR *)(&ps->cs + 1);
1066         if (size < sizeof(ps->cs)) return FALSE;
1067         size -= sizeof(ps->cs);
1068         cs.lpCreateParams = unpack_ptr( ps->cs.lpCreateParams );
1069         cs.hInstance      = unpack_ptr( ps->cs.hInstance );
1070         cs.hMenu          = wine_server_ptr_handle( ps->cs.hMenu );
1071         cs.hwndParent     = wine_server_ptr_handle( ps->cs.hwndParent );
1072         cs.cy             = ps->cs.cy;
1073         cs.cx             = ps->cs.cx;
1074         cs.y              = ps->cs.y;
1075         cs.x              = ps->cs.x;
1076         cs.style          = ps->cs.style;
1077         cs.dwExStyle      = ps->cs.dwExStyle;
1078         cs.lpszName       = unpack_ptr( ps->cs.lpszName );
1079         cs.lpszClass      = unpack_ptr( ps->cs.lpszClass );
1080         if (ps->cs.lpszName >> 16)
1081         {
1082             if (!check_string( str, size )) return FALSE;
1083             cs.lpszName = str;
1084             size -= (strlenW(str) + 1) * sizeof(WCHAR);
1085             str += strlenW(str) + 1;
1086         }
1087         if (ps->cs.lpszClass >> 16)
1088         {
1089             if (!check_string( str, size )) return FALSE;
1090             cs.lpszClass = str;
1091         }
1092         memcpy( &ps->cs, &cs, sizeof(cs) );
1093         break;
1094     }
1095     case WM_GETTEXT:
1096     case WM_ASKCBFORMATNAME:
1097         if (!get_buffer_space( buffer, (*wparam * sizeof(WCHAR)) )) return FALSE;
1098         break;
1099     case WM_WININICHANGE:
1100         if (!*lparam) return TRUE;
1101         /* fall through */
1102     case WM_SETTEXT:
1103     case WM_DEVMODECHANGE:
1104     case CB_DIR:
1105     case LB_DIR:
1106     case LB_ADDFILE:
1107     case EM_REPLACESEL:
1108         if (!check_string( *buffer, size )) return FALSE;
1109         break;
1110     case WM_GETMINMAXINFO:
1111         minsize = sizeof(MINMAXINFO);
1112         break;
1113     case WM_DRAWITEM:
1114     {
1115         DRAWITEMSTRUCT dis;
1116         if (size < sizeof(ps->dis)) return FALSE;
1117         dis.CtlType    = ps->dis.CtlType;
1118         dis.CtlID      = ps->dis.CtlID;
1119         dis.itemID     = ps->dis.itemID;
1120         dis.itemAction = ps->dis.itemAction;
1121         dis.itemState  = ps->dis.itemState;
1122         dis.hwndItem   = wine_server_ptr_handle( ps->dis.hwndItem );
1123         dis.hDC        = wine_server_ptr_handle( ps->dis.hDC );
1124         dis.rcItem     = ps->dis.rcItem;
1125         dis.itemData   = (ULONG_PTR)unpack_ptr( ps->dis.itemData );
1126         memcpy( &ps->dis, &dis, sizeof(dis) );
1127         break;
1128     }
1129     case WM_MEASUREITEM:
1130     {
1131         MEASUREITEMSTRUCT mis;
1132         if (size < sizeof(ps->mis)) return FALSE;
1133         mis.CtlType    = ps->mis.CtlType;
1134         mis.CtlID      = ps->mis.CtlID;
1135         mis.itemID     = ps->mis.itemID;
1136         mis.itemWidth  = ps->mis.itemWidth;
1137         mis.itemHeight = ps->mis.itemHeight;
1138         mis.itemData   = (ULONG_PTR)unpack_ptr( ps->mis.itemData );
1139         memcpy( &ps->mis, &mis, sizeof(mis) );
1140         break;
1141     }
1142     case WM_DELETEITEM:
1143     {
1144         DELETEITEMSTRUCT dls;
1145         if (size < sizeof(ps->dls)) return FALSE;
1146         dls.CtlType    = ps->dls.CtlType;
1147         dls.CtlID      = ps->dls.CtlID;
1148         dls.itemID     = ps->dls.itemID;
1149         dls.hwndItem   = wine_server_ptr_handle( ps->dls.hwndItem );
1150         dls.itemData   = (ULONG_PTR)unpack_ptr( ps->dls.itemData );
1151         memcpy( &ps->dls, &dls, sizeof(dls) );
1152         break;
1153     }
1154     case WM_COMPAREITEM:
1155     {
1156         COMPAREITEMSTRUCT cis;
1157         if (size < sizeof(ps->cis)) return FALSE;
1158         cis.CtlType    = ps->cis.CtlType;
1159         cis.CtlID      = ps->cis.CtlID;
1160         cis.hwndItem   = wine_server_ptr_handle( ps->cis.hwndItem );
1161         cis.itemID1    = ps->cis.itemID1;
1162         cis.itemData1  = (ULONG_PTR)unpack_ptr( ps->cis.itemData1 );
1163         cis.itemID2    = ps->cis.itemID2;
1164         cis.itemData2  = (ULONG_PTR)unpack_ptr( ps->cis.itemData2 );
1165         cis.dwLocaleId = ps->cis.dwLocaleId;
1166         memcpy( &ps->cis, &cis, sizeof(cis) );
1167         break;
1168     }
1169     case WM_WINDOWPOSCHANGING:
1170     case WM_WINDOWPOSCHANGED:
1171     case WM_WINE_SETWINDOWPOS:
1172     {
1173         WINDOWPOS wp;
1174         if (size < sizeof(ps->wp)) return FALSE;
1175         wp.hwnd            = wine_server_ptr_handle( ps->wp.hwnd );
1176         wp.hwndInsertAfter = wine_server_ptr_handle( ps->wp.hwndInsertAfter );
1177         wp.x               = ps->wp.x;
1178         wp.y               = ps->wp.y;
1179         wp.cx              = ps->wp.cx;
1180         wp.cy              = ps->wp.cy;
1181         wp.flags           = ps->wp.flags;
1182         memcpy( &ps->wp, &wp, sizeof(wp) );
1183         break;
1184     }
1185     case WM_COPYDATA:
1186     {
1187         COPYDATASTRUCT cds;
1188         if (size < sizeof(ps->cds)) return FALSE;
1189         cds.dwData = (ULONG_PTR)unpack_ptr( ps->cds.dwData );
1190         if (ps->cds.lpData)
1191         {
1192             cds.cbData = ps->cds.cbData;
1193             cds.lpData = &ps->cds + 1;
1194             minsize = sizeof(ps->cds) + cds.cbData;
1195         }
1196         else
1197         {
1198             cds.cbData = 0;
1199             cds.lpData = 0;
1200         }
1201         memcpy( &ps->cds, &cds, sizeof(cds) );
1202         break;
1203     }
1204     case WM_NOTIFY:
1205         /* WM_NOTIFY cannot be sent across processes (MSDN) */
1206         return FALSE;
1207     case WM_HELP:
1208     {
1209         HELPINFO hi;
1210         if (size < sizeof(ps->hi)) return FALSE;
1211         hi.cbSize       = sizeof(hi);
1212         hi.iContextType = ps->hi.iContextType;
1213         hi.iCtrlId      = ps->hi.iCtrlId;
1214         hi.hItemHandle  = wine_server_ptr_handle( ps->hi.hItemHandle );
1215         hi.dwContextId  = (ULONG_PTR)unpack_ptr( ps->hi.dwContextId );
1216         hi.MousePos     = ps->hi.MousePos;
1217         memcpy( &ps->hi, &hi, sizeof(hi) );
1218         break;
1219     }
1220     case WM_STYLECHANGING:
1221     case WM_STYLECHANGED:
1222         minsize = sizeof(STYLESTRUCT);
1223         break;
1224     case WM_NCCALCSIZE:
1225         if (!*wparam) minsize = sizeof(RECT);
1226         else
1227         {
1228             NCCALCSIZE_PARAMS ncp;
1229             WINDOWPOS wp;
1230             if (size < sizeof(ps->ncp)) return FALSE;
1231             ncp.rgrc[0]        = ps->ncp.rgrc[0];
1232             ncp.rgrc[1]        = ps->ncp.rgrc[1];
1233             ncp.rgrc[2]        = ps->ncp.rgrc[2];
1234             wp.hwnd            = wine_server_ptr_handle( ps->ncp.hwnd );
1235             wp.hwndInsertAfter = wine_server_ptr_handle( ps->ncp.hwndInsertAfter );
1236             wp.x               = ps->ncp.x;
1237             wp.y               = ps->ncp.y;
1238             wp.cx              = ps->ncp.cx;
1239             wp.cy              = ps->ncp.cy;
1240             wp.flags           = ps->ncp.flags;
1241             ncp.lppos = (WINDOWPOS *)((NCCALCSIZE_PARAMS *)&ps->ncp + 1);
1242             memcpy( &ps->ncp, &ncp, sizeof(ncp) );
1243             *ncp.lppos = wp;
1244         }
1245         break;
1246     case WM_GETDLGCODE:
1247         if (*lparam)
1248         {
1249             MSG msg;
1250             if (size < sizeof(ps->msg)) return FALSE;
1251             msg.hwnd    = wine_server_ptr_handle( ps->msg.hwnd );
1252             msg.message = ps->msg.message;
1253             msg.wParam  = (ULONG_PTR)unpack_ptr( ps->msg.wParam );
1254             msg.lParam  = (ULONG_PTR)unpack_ptr( ps->msg.lParam );
1255             msg.time    = ps->msg.time;
1256             msg.pt      = ps->msg.pt;
1257             memcpy( &ps->msg, &msg, sizeof(msg) );
1258             break;
1259         }
1260         return TRUE;
1261     case SBM_SETSCROLLINFO:
1262         minsize = sizeof(SCROLLINFO);
1263         break;
1264     case SBM_GETSCROLLINFO:
1265         if (!get_buffer_space( buffer, sizeof(SCROLLINFO ))) return FALSE;
1266         break;
1267     case SBM_GETSCROLLBARINFO:
1268         if (!get_buffer_space( buffer, sizeof(SCROLLBARINFO ))) return FALSE;
1269         break;
1270     case EM_GETSEL:
1271     case SBM_GETRANGE:
1272     case CB_GETEDITSEL:
1273         if (*wparam || *lparam)
1274         {
1275             if (!get_buffer_space( buffer, 2*sizeof(DWORD) )) return FALSE;
1276             if (*wparam) *wparam = (WPARAM)*buffer;
1277             if (*lparam) *lparam = (LPARAM)((DWORD *)*buffer + 1);
1278         }
1279         return TRUE;
1280     case EM_GETRECT:
1281     case LB_GETITEMRECT:
1282     case CB_GETDROPPEDCONTROLRECT:
1283         if (!get_buffer_space( buffer, sizeof(RECT) )) return FALSE;
1284         break;
1285     case EM_SETRECT:
1286     case EM_SETRECTNP:
1287         minsize = sizeof(RECT);
1288         break;
1289     case EM_GETLINE:
1290     {
1291         WORD len;
1292         if (size < sizeof(WORD)) return FALSE;
1293         len = *(WORD *)*buffer;
1294         if (!get_buffer_space( buffer, (len + 1) * sizeof(WCHAR) )) return FALSE;
1295         *lparam = (LPARAM)*buffer + sizeof(WORD);  /* don't erase WORD at start of buffer */
1296         return TRUE;
1297     }
1298     case EM_SETTABSTOPS:
1299     case LB_SETTABSTOPS:
1300         if (!*wparam) return TRUE;
1301         minsize = *wparam * sizeof(UINT);
1302         break;
1303     case CB_ADDSTRING:
1304     case CB_INSERTSTRING:
1305     case CB_FINDSTRING:
1306     case CB_FINDSTRINGEXACT:
1307     case CB_SELECTSTRING:
1308     case LB_ADDSTRING:
1309     case LB_INSERTSTRING:
1310     case LB_FINDSTRING:
1311     case LB_FINDSTRINGEXACT:
1312     case LB_SELECTSTRING:
1313         if (!*buffer) return TRUE;
1314         if (!check_string( *buffer, size )) return FALSE;
1315         break;
1316     case CB_GETLBTEXT:
1317     {
1318         size = sizeof(ULONG_PTR);
1319         if (combobox_has_strings( hwnd ))
1320             size = (SendMessageW( hwnd, CB_GETLBTEXTLEN, *wparam, 0 ) + 1) * sizeof(WCHAR);
1321         if (!get_buffer_space( buffer, size )) return FALSE;
1322         break;
1323     }
1324     case LB_GETTEXT:
1325     {
1326         size = sizeof(ULONG_PTR);
1327         if (listbox_has_strings( hwnd ))
1328             size = (SendMessageW( hwnd, LB_GETTEXTLEN, *wparam, 0 ) + 1) * sizeof(WCHAR);
1329         if (!get_buffer_space( buffer, size )) return FALSE;
1330         break;
1331     }
1332     case LB_GETSELITEMS:
1333         if (!get_buffer_space( buffer, *wparam * sizeof(UINT) )) return FALSE;
1334         break;
1335     case WM_NEXTMENU:
1336     {
1337         MDINEXTMENU mnm;
1338         if (size < sizeof(ps->mnm)) return FALSE;
1339         mnm.hmenuIn   = wine_server_ptr_handle( ps->mnm.hmenuIn );
1340         mnm.hmenuNext = wine_server_ptr_handle( ps->mnm.hmenuNext );
1341         mnm.hwndNext  = wine_server_ptr_handle( ps->mnm.hwndNext );
1342         memcpy( &ps->mnm, &mnm, sizeof(mnm) );
1343         break;
1344     }
1345     case WM_SIZING:
1346     case WM_MOVING:
1347         minsize = sizeof(RECT);
1348         if (!get_buffer_space( buffer, sizeof(RECT) )) return FALSE;
1349         break;
1350     case WM_MDICREATE:
1351     {
1352         MDICREATESTRUCTW *cs = *buffer;
1353         WCHAR *str = (WCHAR *)(cs + 1);
1354         if (size < sizeof(*cs)) return FALSE;
1355         size -= sizeof(*cs);
1356         if (!IS_INTRESOURCE(cs->szTitle))
1357         {
1358             if (!check_string( str, size )) return FALSE;
1359             cs->szTitle = str;
1360             size -= (strlenW(str) + 1) * sizeof(WCHAR);
1361             str += strlenW(str) + 1;
1362         }
1363         if (!IS_INTRESOURCE(cs->szClass))
1364         {
1365             if (!check_string( str, size )) return FALSE;
1366             cs->szClass = str;
1367         }
1368         break;
1369     }
1370     case WM_MDIGETACTIVE:
1371         if (!*lparam) return TRUE;
1372         if (!get_buffer_space( buffer, sizeof(BOOL) )) return FALSE;
1373         break;
1374     case WM_DEVICECHANGE:
1375         minsize = sizeof(DEV_BROADCAST_HDR);
1376         break;
1377     case WM_WINE_KEYBOARD_LL_HOOK:
1378     case WM_WINE_MOUSE_LL_HOOK:
1379     {
1380         struct hook_extra_info *h_extra = *buffer;
1381
1382         minsize = sizeof(struct hook_extra_info) +
1383                   (message == WM_WINE_KEYBOARD_LL_HOOK ? sizeof(KBDLLHOOKSTRUCT)
1384                                                        : sizeof(MSLLHOOKSTRUCT));
1385         if (size < minsize) return FALSE;
1386         h_extra->lparam = (LPARAM)(h_extra + 1);
1387         break;
1388     }
1389     case WM_NCPAINT:
1390         if (*wparam <= 1) return TRUE;
1391         FIXME( "WM_NCPAINT hdc unpacking not supported\n" );
1392         return FALSE;
1393     case WM_PAINT:
1394         if (!*wparam) return TRUE;
1395         /* fall through */
1396
1397     /* these contain an HFONT */
1398     case WM_SETFONT:
1399     case WM_GETFONT:
1400     /* these contain an HDC */
1401     case WM_ERASEBKGND:
1402     case WM_ICONERASEBKGND:
1403     case WM_CTLCOLORMSGBOX:
1404     case WM_CTLCOLOREDIT:
1405     case WM_CTLCOLORLISTBOX:
1406     case WM_CTLCOLORBTN:
1407     case WM_CTLCOLORDLG:
1408     case WM_CTLCOLORSCROLLBAR:
1409     case WM_CTLCOLORSTATIC:
1410     case WM_PRINT:
1411     case WM_PRINTCLIENT:
1412     /* these contain an HGLOBAL */
1413     case WM_PAINTCLIPBOARD:
1414     case WM_SIZECLIPBOARD:
1415     /* these contain HICON */
1416     case WM_GETICON:
1417     case WM_SETICON:
1418     case WM_QUERYDRAGICON:
1419     case WM_QUERYPARKICON:
1420     /* these contain pointers */
1421     case WM_DROPOBJECT:
1422     case WM_QUERYDROPOBJECT:
1423     case WM_DRAGLOOP:
1424     case WM_DRAGSELECT:
1425     case WM_DRAGMOVE:
1426         FIXME( "msg %x (%s) not supported yet\n", message, SPY_GetMsgName(message, hwnd) );
1427         return FALSE;
1428
1429     default:
1430         return TRUE; /* message doesn't need any unpacking */
1431     }
1432
1433     /* default exit for most messages: check minsize and store buffer in lparam */
1434     if (size < minsize) return FALSE;
1435     *lparam = (LPARAM)*buffer;
1436     return TRUE;
1437 }
1438
1439
1440 /***********************************************************************
1441  *              pack_reply
1442  *
1443  * Pack a reply to a message for sending to another process.
1444  */
1445 static void pack_reply( HWND hwnd, UINT message, WPARAM wparam, LPARAM lparam,
1446                         LRESULT res, struct packed_message *data )
1447 {
1448     data->count = 0;
1449     switch(message)
1450     {
1451     case WM_NCCREATE:
1452     case WM_CREATE:
1453     {
1454         CREATESTRUCTW *cs = (CREATESTRUCTW *)lparam;
1455         data->ps.cs.lpCreateParams = (ULONG_PTR)cs->lpCreateParams;
1456         data->ps.cs.hInstance      = (ULONG_PTR)cs->hInstance;
1457         data->ps.cs.hMenu          = wine_server_user_handle( cs->hMenu );
1458         data->ps.cs.hwndParent     = wine_server_user_handle( cs->hwndParent );
1459         data->ps.cs.cy             = cs->cy;
1460         data->ps.cs.cx             = cs->cx;
1461         data->ps.cs.y              = cs->y;
1462         data->ps.cs.x              = cs->x;
1463         data->ps.cs.style          = cs->style;
1464         data->ps.cs.dwExStyle      = cs->dwExStyle;
1465         data->ps.cs.lpszName       = (ULONG_PTR)cs->lpszName;
1466         data->ps.cs.lpszClass      = (ULONG_PTR)cs->lpszClass;
1467         push_data( data, &data->ps.cs, sizeof(data->ps.cs) );
1468         break;
1469     }
1470     case WM_GETTEXT:
1471     case CB_GETLBTEXT:
1472     case LB_GETTEXT:
1473         push_data( data, (WCHAR *)lparam, (res + 1) * sizeof(WCHAR) );
1474         break;
1475     case WM_GETMINMAXINFO:
1476         push_data( data, (MINMAXINFO *)lparam, sizeof(MINMAXINFO) );
1477         break;
1478     case WM_MEASUREITEM:
1479     {
1480         MEASUREITEMSTRUCT *mis = (MEASUREITEMSTRUCT *)lparam;
1481         data->ps.mis.CtlType    = mis->CtlType;
1482         data->ps.mis.CtlID      = mis->CtlID;
1483         data->ps.mis.itemID     = mis->itemID;
1484         data->ps.mis.itemWidth  = mis->itemWidth;
1485         data->ps.mis.itemHeight = mis->itemHeight;
1486         data->ps.mis.itemData   = mis->itemData;
1487         push_data( data, &data->ps.mis, sizeof(data->ps.mis) );
1488         break;
1489     }
1490     case WM_WINDOWPOSCHANGING:
1491     case WM_WINDOWPOSCHANGED:
1492     {
1493         WINDOWPOS *wp = (WINDOWPOS *)lparam;
1494         data->ps.wp.hwnd            = wine_server_user_handle( wp->hwnd );
1495         data->ps.wp.hwndInsertAfter = wine_server_user_handle( wp->hwndInsertAfter );
1496         data->ps.wp.x               = wp->x;
1497         data->ps.wp.y               = wp->y;
1498         data->ps.wp.cx              = wp->cx;
1499         data->ps.wp.cy              = wp->cy;
1500         data->ps.wp.flags           = wp->flags;
1501         push_data( data, &data->ps.wp, sizeof(data->ps.wp) );
1502         break;
1503     }
1504     case WM_GETDLGCODE:
1505         if (lparam)
1506         {
1507             MSG *msg = (MSG *)lparam;
1508             data->ps.msg.hwnd    = wine_server_user_handle( msg->hwnd );
1509             data->ps.msg.message = msg->message;
1510             data->ps.msg.wParam  = msg->wParam;
1511             data->ps.msg.lParam  = msg->lParam;
1512             data->ps.msg.time    = msg->time;
1513             data->ps.msg.pt      = msg->pt;
1514             push_data( data, &data->ps.msg, sizeof(data->ps.msg) );
1515         }
1516         break;
1517     case SBM_GETSCROLLINFO:
1518         push_data( data, (SCROLLINFO *)lparam, sizeof(SCROLLINFO) );
1519         break;
1520     case EM_GETRECT:
1521     case LB_GETITEMRECT:
1522     case CB_GETDROPPEDCONTROLRECT:
1523     case WM_SIZING:
1524     case WM_MOVING:
1525         push_data( data, (RECT *)lparam, sizeof(RECT) );
1526         break;
1527     case EM_GETLINE:
1528     {
1529         WORD *ptr = (WORD *)lparam;
1530         push_data( data, ptr, ptr[-1] * sizeof(WCHAR) );
1531         break;
1532     }
1533     case LB_GETSELITEMS:
1534         push_data( data, (UINT *)lparam, wparam * sizeof(UINT) );
1535         break;
1536     case WM_MDIGETACTIVE:
1537         if (lparam) push_data( data, (BOOL *)lparam, sizeof(BOOL) );
1538         break;
1539     case WM_NCCALCSIZE:
1540         if (!wparam)
1541             push_data( data, (RECT *)lparam, sizeof(RECT) );
1542         else
1543         {
1544             NCCALCSIZE_PARAMS *ncp = (NCCALCSIZE_PARAMS *)lparam;
1545             data->ps.ncp.rgrc[0]         = ncp->rgrc[0];
1546             data->ps.ncp.rgrc[1]         = ncp->rgrc[1];
1547             data->ps.ncp.rgrc[2]         = ncp->rgrc[2];
1548             data->ps.ncp.hwnd            = wine_server_user_handle( ncp->lppos->hwnd );
1549             data->ps.ncp.hwndInsertAfter = wine_server_user_handle( ncp->lppos->hwndInsertAfter );
1550             data->ps.ncp.x               = ncp->lppos->x;
1551             data->ps.ncp.y               = ncp->lppos->y;
1552             data->ps.ncp.cx              = ncp->lppos->cx;
1553             data->ps.ncp.cy              = ncp->lppos->cy;
1554             data->ps.ncp.flags           = ncp->lppos->flags;
1555             push_data( data, &data->ps.ncp, sizeof(data->ps.ncp) );
1556         }
1557         break;
1558     case EM_GETSEL:
1559     case SBM_GETRANGE:
1560     case CB_GETEDITSEL:
1561         if (wparam) push_data( data, (DWORD *)wparam, sizeof(DWORD) );
1562         if (lparam) push_data( data, (DWORD *)lparam, sizeof(DWORD) );
1563         break;
1564     case WM_NEXTMENU:
1565     {
1566         MDINEXTMENU *mnm = (MDINEXTMENU *)lparam;
1567         data->ps.mnm.hmenuIn   = wine_server_user_handle( mnm->hmenuIn );
1568         data->ps.mnm.hmenuNext = wine_server_user_handle( mnm->hmenuNext );
1569         data->ps.mnm.hwndNext  = wine_server_user_handle( mnm->hwndNext );
1570         push_data( data, &data->ps.mnm, sizeof(data->ps.mnm) );
1571         break;
1572     }
1573     case WM_MDICREATE:
1574         push_data( data, (MDICREATESTRUCTW *)lparam, sizeof(MDICREATESTRUCTW) );
1575         break;
1576     case WM_ASKCBFORMATNAME:
1577         push_data( data, (WCHAR *)lparam, (strlenW((WCHAR *)lparam) + 1) * sizeof(WCHAR) );
1578         break;
1579     }
1580 }
1581
1582
1583 /***********************************************************************
1584  *              unpack_reply
1585  *
1586  * Unpack a message reply received from another process.
1587  */
1588 static void unpack_reply( HWND hwnd, UINT message, WPARAM wparam, LPARAM lparam,
1589                           void *buffer, size_t size )
1590 {
1591     union packed_structs *ps = buffer;
1592
1593     switch(message)
1594     {
1595     case WM_NCCREATE:
1596     case WM_CREATE:
1597         if (size >= sizeof(ps->cs))
1598         {
1599             CREATESTRUCTW *cs = (CREATESTRUCTW *)lparam;
1600             cs->lpCreateParams = unpack_ptr( ps->cs.lpCreateParams );
1601             cs->hInstance      = unpack_ptr( ps->cs.hInstance );
1602             cs->hMenu          = wine_server_ptr_handle( ps->cs.hMenu );
1603             cs->hwndParent     = wine_server_ptr_handle( ps->cs.hwndParent );
1604             cs->cy             = ps->cs.cy;
1605             cs->cx             = ps->cs.cx;
1606             cs->y              = ps->cs.y;
1607             cs->x              = ps->cs.x;
1608             cs->style          = ps->cs.style;
1609             cs->dwExStyle      = ps->cs.dwExStyle;
1610             /* don't allow changing name and class pointers */
1611         }
1612         break;
1613     case WM_GETTEXT:
1614     case WM_ASKCBFORMATNAME:
1615         memcpy( (WCHAR *)lparam, buffer, min( wparam*sizeof(WCHAR), size ));
1616         break;
1617     case WM_GETMINMAXINFO:
1618         memcpy( (MINMAXINFO *)lparam, buffer, min( sizeof(MINMAXINFO), size ));
1619         break;
1620     case WM_MEASUREITEM:
1621         if (size >= sizeof(ps->mis))
1622         {
1623             MEASUREITEMSTRUCT *mis = (MEASUREITEMSTRUCT *)lparam;
1624             mis->CtlType    = ps->mis.CtlType;
1625             mis->CtlID      = ps->mis.CtlID;
1626             mis->itemID     = ps->mis.itemID;
1627             mis->itemWidth  = ps->mis.itemWidth;
1628             mis->itemHeight = ps->mis.itemHeight;
1629             mis->itemData   = (ULONG_PTR)unpack_ptr( ps->mis.itemData );
1630         }
1631         break;
1632     case WM_WINDOWPOSCHANGING:
1633     case WM_WINDOWPOSCHANGED:
1634         if (size >= sizeof(ps->wp))
1635         {
1636             WINDOWPOS *wp = (WINDOWPOS *)lparam;
1637             wp->hwnd            = wine_server_ptr_handle( ps->wp.hwnd );
1638             wp->hwndInsertAfter = wine_server_ptr_handle( ps->wp.hwndInsertAfter );
1639             wp->x               = ps->wp.x;
1640             wp->y               = ps->wp.y;
1641             wp->cx              = ps->wp.cx;
1642             wp->cy              = ps->wp.cy;
1643             wp->flags           = ps->wp.flags;
1644         }
1645         break;
1646     case WM_GETDLGCODE:
1647         if (lparam && size >= sizeof(ps->msg))
1648         {
1649             MSG *msg = (MSG *)lparam;
1650             msg->hwnd    = wine_server_ptr_handle( ps->msg.hwnd );
1651             msg->message = ps->msg.message;
1652             msg->wParam  = (ULONG_PTR)unpack_ptr( ps->msg.wParam );
1653             msg->lParam  = (ULONG_PTR)unpack_ptr( ps->msg.lParam );
1654             msg->time    = ps->msg.time;
1655             msg->pt      = ps->msg.pt;
1656         }
1657         break;
1658     case SBM_GETSCROLLINFO:
1659         memcpy( (SCROLLINFO *)lparam, buffer, min( sizeof(SCROLLINFO), size ));
1660         break;
1661     case SBM_GETSCROLLBARINFO:
1662         memcpy( (SCROLLBARINFO *)lparam, buffer, min( sizeof(SCROLLBARINFO), size ));
1663         break;
1664     case EM_GETRECT:
1665     case CB_GETDROPPEDCONTROLRECT:
1666     case LB_GETITEMRECT:
1667     case WM_SIZING:
1668     case WM_MOVING:
1669         memcpy( (RECT *)lparam, buffer, min( sizeof(RECT), size ));
1670         break;
1671     case EM_GETLINE:
1672         size = min( size, (size_t)*(WORD *)lparam );
1673         memcpy( (WCHAR *)lparam, buffer, size );
1674         break;
1675     case LB_GETSELITEMS:
1676         memcpy( (UINT *)lparam, buffer, min( wparam*sizeof(UINT), size ));
1677         break;
1678     case LB_GETTEXT:
1679     case CB_GETLBTEXT:
1680         memcpy( (WCHAR *)lparam, buffer, size );
1681         break;
1682     case WM_NEXTMENU:
1683         if (size >= sizeof(ps->mnm))
1684         {
1685             MDINEXTMENU *mnm = (MDINEXTMENU *)lparam;
1686             mnm->hmenuIn   = wine_server_ptr_handle( ps->mnm.hmenuIn );
1687             mnm->hmenuNext = wine_server_ptr_handle( ps->mnm.hmenuNext );
1688             mnm->hwndNext  = wine_server_ptr_handle( ps->mnm.hwndNext );
1689         }
1690         break;
1691     case WM_MDIGETACTIVE:
1692         if (lparam) memcpy( (BOOL *)lparam, buffer, min( sizeof(BOOL), size ));
1693         break;
1694     case WM_NCCALCSIZE:
1695         if (!wparam)
1696             memcpy( (RECT *)lparam, buffer, min( sizeof(RECT), size ));
1697         else if (size >= sizeof(ps->ncp))
1698         {
1699             NCCALCSIZE_PARAMS *ncp = (NCCALCSIZE_PARAMS *)lparam;
1700             ncp->rgrc[0]                = ps->ncp.rgrc[0];
1701             ncp->rgrc[1]                = ps->ncp.rgrc[1];
1702             ncp->rgrc[2]                = ps->ncp.rgrc[2];
1703             ncp->lppos->hwnd            = wine_server_ptr_handle( ps->ncp.hwnd );
1704             ncp->lppos->hwndInsertAfter = wine_server_ptr_handle( ps->ncp.hwndInsertAfter );
1705             ncp->lppos->x               = ps->ncp.x;
1706             ncp->lppos->y               = ps->ncp.y;
1707             ncp->lppos->cx              = ps->ncp.cx;
1708             ncp->lppos->cy              = ps->ncp.cy;
1709             ncp->lppos->flags           = ps->ncp.flags;
1710         }
1711         break;
1712     case EM_GETSEL:
1713     case SBM_GETRANGE:
1714     case CB_GETEDITSEL:
1715         if (wparam)
1716         {
1717             memcpy( (DWORD *)wparam, buffer, min( sizeof(DWORD), size ));
1718             if (size <= sizeof(DWORD)) break;
1719             size -= sizeof(DWORD);
1720             buffer = (DWORD *)buffer + 1;
1721         }
1722         if (lparam) memcpy( (DWORD *)lparam, buffer, min( sizeof(DWORD), size ));
1723         break;
1724     case WM_MDICREATE:
1725     {
1726         MDICREATESTRUCTW *cs = (MDICREATESTRUCTW *)lparam;
1727         LPCWSTR title = cs->szTitle, class = cs->szClass;
1728         memcpy( cs, buffer, min( sizeof(*cs), size ));
1729         cs->szTitle = title;  /* restore the original pointers */
1730         cs->szClass = class;
1731         break;
1732     }
1733     default:
1734         ERR( "should not happen: unexpected message %x\n", message );
1735         break;
1736     }
1737 }
1738
1739
1740 /***********************************************************************
1741  *           reply_message
1742  *
1743  * Send a reply to a sent message.
1744  */
1745 static void reply_message( struct received_message_info *info, LRESULT result, BOOL remove )
1746 {
1747     struct packed_message data;
1748     int i, replied = info->flags & ISMEX_REPLIED;
1749
1750     if (info->flags & ISMEX_NOTIFY) return;  /* notify messages don't get replies */
1751     if (!remove && replied) return;  /* replied already */
1752
1753     memset( &data, 0, sizeof(data) );
1754     info->flags |= ISMEX_REPLIED;
1755
1756     if (info->type == MSG_OTHER_PROCESS && !replied)
1757     {
1758         pack_reply( info->msg.hwnd, info->msg.message, info->msg.wParam,
1759                     info->msg.lParam, result, &data );
1760     }
1761
1762     SERVER_START_REQ( reply_message )
1763     {
1764         req->result = result;
1765         req->remove = remove;
1766         for (i = 0; i < data.count; i++) wine_server_add_data( req, data.data[i], data.size[i] );
1767         wine_server_call( req );
1768     }
1769     SERVER_END_REQ;
1770 }
1771
1772
1773 /***********************************************************************
1774  *           handle_internal_message
1775  *
1776  * Handle an internal Wine message instead of calling the window proc.
1777  */
1778 static LRESULT handle_internal_message( HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam )
1779 {
1780     switch(msg)
1781     {
1782     case WM_WINE_DESTROYWINDOW:
1783         return WIN_DestroyWindow( hwnd );
1784     case WM_WINE_SETWINDOWPOS:
1785         if (is_desktop_window( hwnd )) return 0;
1786         return USER_SetWindowPos( (WINDOWPOS *)lparam );
1787     case WM_WINE_SHOWWINDOW:
1788         if (is_desktop_window( hwnd )) return 0;
1789         return ShowWindow( hwnd, wparam );
1790     case WM_WINE_SETPARENT:
1791         if (is_desktop_window( hwnd )) return 0;
1792         return (LRESULT)SetParent( hwnd, (HWND)wparam );
1793     case WM_WINE_SETWINDOWLONG:
1794         return WIN_SetWindowLong( hwnd, (short)LOWORD(wparam), HIWORD(wparam), lparam, TRUE );
1795     case WM_WINE_ENABLEWINDOW:
1796         if (is_desktop_window( hwnd )) return 0;
1797         return EnableWindow( hwnd, wparam );
1798     case WM_WINE_SETACTIVEWINDOW:
1799         if (is_desktop_window( hwnd )) return 0;
1800         return (LRESULT)SetActiveWindow( (HWND)wparam );
1801     case WM_WINE_KEYBOARD_LL_HOOK:
1802     case WM_WINE_MOUSE_LL_HOOK:
1803     {
1804         struct hook_extra_info *h_extra = (struct hook_extra_info *)lparam;
1805
1806         return call_current_hook( h_extra->handle, HC_ACTION, wparam, h_extra->lparam );
1807     }
1808     default:
1809         if (msg >= WM_WINE_FIRST_DRIVER_MSG && msg <= WM_WINE_LAST_DRIVER_MSG)
1810             return USER_Driver->pWindowMessage( hwnd, msg, wparam, lparam );
1811         FIXME( "unknown internal message %x\n", msg );
1812         return 0;
1813     }
1814 }
1815
1816 /* since the WM_DDE_ACK response to a WM_DDE_EXECUTE message should contain the handle
1817  * to the memory handle, we keep track (in the server side) of all pairs of handle
1818  * used (the client passes its value and the content of the memory handle), and
1819  * the server stored both values (the client, and the local one, created after the
1820  * content). When a ACK message is generated, the list of pair is searched for a
1821  * matching pair, so that the client memory handle can be returned.
1822  */
1823 struct DDE_pair {
1824     HGLOBAL     client_hMem;
1825     HGLOBAL     server_hMem;
1826 };
1827
1828 static      struct DDE_pair*    dde_pairs;
1829 static      int                 dde_num_alloc;
1830 static      int                 dde_num_used;
1831
1832 static CRITICAL_SECTION dde_crst;
1833 static CRITICAL_SECTION_DEBUG critsect_debug =
1834 {
1835     0, 0, &dde_crst,
1836     { &critsect_debug.ProcessLocksList, &critsect_debug.ProcessLocksList },
1837       0, 0, { (DWORD_PTR)(__FILE__ ": dde_crst") }
1838 };
1839 static CRITICAL_SECTION dde_crst = { &critsect_debug, -1, 0, 0, 0, 0 };
1840
1841 static BOOL dde_add_pair(HGLOBAL chm, HGLOBAL shm)
1842 {
1843     int  i;
1844 #define GROWBY  4
1845
1846     EnterCriticalSection(&dde_crst);
1847
1848     /* now remember the pair of hMem on both sides */
1849     if (dde_num_used == dde_num_alloc)
1850     {
1851         struct DDE_pair* tmp;
1852         if (dde_pairs)
1853             tmp  = HeapReAlloc( GetProcessHeap(), 0, dde_pairs,
1854                                             (dde_num_alloc + GROWBY) * sizeof(struct DDE_pair));
1855         else
1856             tmp  = HeapAlloc( GetProcessHeap(), 0, 
1857                                             (dde_num_alloc + GROWBY) * sizeof(struct DDE_pair));
1858
1859         if (!tmp)
1860         {
1861             LeaveCriticalSection(&dde_crst);
1862             return FALSE;
1863         }
1864         dde_pairs = tmp;
1865         /* zero out newly allocated part */
1866         memset(&dde_pairs[dde_num_alloc], 0, GROWBY * sizeof(struct DDE_pair));
1867         dde_num_alloc += GROWBY;
1868     }
1869 #undef GROWBY
1870     for (i = 0; i < dde_num_alloc; i++)
1871     {
1872         if (dde_pairs[i].server_hMem == 0)
1873         {
1874             dde_pairs[i].client_hMem = chm;
1875             dde_pairs[i].server_hMem = shm;
1876             dde_num_used++;
1877             break;
1878         }
1879     }
1880     LeaveCriticalSection(&dde_crst);
1881     return TRUE;
1882 }
1883
1884 static HGLOBAL dde_get_pair(HGLOBAL shm)
1885 {
1886     int  i;
1887     HGLOBAL     ret = 0;
1888
1889     EnterCriticalSection(&dde_crst);
1890     for (i = 0; i < dde_num_alloc; i++)
1891     {
1892         if (dde_pairs[i].server_hMem == shm)
1893         {
1894             /* free this pair */
1895             dde_pairs[i].server_hMem = 0;
1896             dde_num_used--;
1897             ret = dde_pairs[i].client_hMem;
1898             break;
1899         }
1900     }
1901     LeaveCriticalSection(&dde_crst);
1902     return ret;
1903 }
1904
1905 /***********************************************************************
1906  *              post_dde_message
1907  *
1908  * Post a DDE message
1909  */
1910 static BOOL post_dde_message( struct packed_message *data, const struct send_message_info *info )
1911 {
1912     void*       ptr = NULL;
1913     int         size = 0;
1914     UINT_PTR    uiLo, uiHi;
1915     LPARAM      lp = 0;
1916     HGLOBAL     hunlock = 0;
1917     int         i;
1918     DWORD       res;
1919
1920     if (!UnpackDDElParam( info->msg, info->lparam, &uiLo, &uiHi ))
1921         return FALSE;
1922
1923     lp = info->lparam;
1924     switch (info->msg)
1925     {
1926         /* DDE messages which don't require packing are:
1927          * WM_DDE_INITIATE
1928          * WM_DDE_TERMINATE
1929          * WM_DDE_REQUEST
1930          * WM_DDE_UNADVISE
1931          */
1932     case WM_DDE_ACK:
1933         if (HIWORD(uiHi))
1934         {
1935             /* uiHi should contain a hMem from WM_DDE_EXECUTE */
1936             HGLOBAL h = dde_get_pair( (HANDLE)uiHi );
1937             if (h)
1938             {
1939                 /* send back the value of h on the other side */
1940                 push_data( data, &h, sizeof(HGLOBAL) );
1941                 lp = uiLo;
1942                 TRACE( "send dde-ack %lx %08lx => %p\n", uiLo, uiHi, h );
1943             }
1944         }
1945         else
1946         {
1947             /* uiHi should contain either an atom or 0 */
1948             TRACE( "send dde-ack %lx atom=%lx\n", uiLo, uiHi );
1949             lp = MAKELONG( uiLo, uiHi );
1950         }
1951         break;
1952     case WM_DDE_ADVISE:
1953     case WM_DDE_DATA:
1954     case WM_DDE_POKE:
1955         size = 0;
1956         if (uiLo)
1957         {
1958             size = GlobalSize( (HGLOBAL)uiLo ) ;
1959             if ((info->msg == WM_DDE_ADVISE && size < sizeof(DDEADVISE)) ||
1960                 (info->msg == WM_DDE_DATA   && size < FIELD_OFFSET(DDEDATA, Value)) ||
1961                 (info->msg == WM_DDE_POKE   && size < FIELD_OFFSET(DDEPOKE, Value))
1962                 )
1963             return FALSE;
1964         }
1965         else if (info->msg != WM_DDE_DATA) return FALSE;
1966
1967         lp = uiHi;
1968         if (uiLo)
1969         {
1970             if ((ptr = GlobalLock( (HGLOBAL)uiLo) ))
1971             {
1972                 DDEDATA *dde_data = ptr;
1973                 TRACE("unused %d, fResponse %d, fRelease %d, fDeferUpd %d, fAckReq %d, cfFormat %d\n",
1974                        dde_data->unused, dde_data->fResponse, dde_data->fRelease,
1975                        dde_data->reserved, dde_data->fAckReq, dde_data->cfFormat);
1976                 push_data( data, ptr, size );
1977                 hunlock = (HGLOBAL)uiLo;
1978             }
1979         }
1980         TRACE( "send ddepack %u %lx\n", size, uiHi );
1981         break;
1982     case WM_DDE_EXECUTE:
1983         if (info->lparam)
1984         {
1985             if ((ptr = GlobalLock( (HGLOBAL)info->lparam) ))
1986             {
1987                 push_data(data, ptr, GlobalSize( (HGLOBAL)info->lparam ));
1988                 /* so that the other side can send it back on ACK */
1989                 lp = info->lparam;
1990                 hunlock = (HGLOBAL)info->lparam;
1991             }
1992         }
1993         break;
1994     }
1995     SERVER_START_REQ( send_message )
1996     {
1997         req->id      = info->dest_tid;
1998         req->type    = info->type;
1999         req->flags   = 0;
2000         req->win     = wine_server_user_handle( info->hwnd );
2001         req->msg     = info->msg;
2002         req->wparam  = info->wparam;
2003         req->lparam  = lp;
2004         req->timeout = TIMEOUT_INFINITE;
2005         for (i = 0; i < data->count; i++)
2006             wine_server_add_data( req, data->data[i], data->size[i] );
2007         if ((res = wine_server_call( req )))
2008         {
2009             if (res == STATUS_INVALID_PARAMETER)
2010                 /* FIXME: find a STATUS_ value for this one */
2011                 SetLastError( ERROR_INVALID_THREAD_ID );
2012             else
2013                 SetLastError( RtlNtStatusToDosError(res) );
2014         }
2015         else
2016             FreeDDElParam(info->msg, info->lparam);
2017     }
2018     SERVER_END_REQ;
2019     if (hunlock) GlobalUnlock(hunlock);
2020
2021     return !res;
2022 }
2023
2024 /***********************************************************************
2025  *              unpack_dde_message
2026  *
2027  * Unpack a posted DDE message received from another process.
2028  */
2029 static BOOL unpack_dde_message( HWND hwnd, UINT message, WPARAM *wparam, LPARAM *lparam,
2030                                 void **buffer, size_t size )
2031 {
2032     UINT_PTR    uiLo, uiHi;
2033     HGLOBAL     hMem = 0;
2034     void*       ptr;
2035
2036     switch (message)
2037     {
2038     case WM_DDE_ACK:
2039         if (size)
2040         {
2041             /* hMem is being passed */
2042             if (size != sizeof(HGLOBAL)) return FALSE;
2043             if (!buffer || !*buffer) return FALSE;
2044             uiLo = *lparam;
2045             memcpy( &hMem, *buffer, size );
2046             uiHi = (UINT_PTR)hMem;
2047             TRACE("recv dde-ack %lx mem=%lx[%lx]\n", uiLo, uiHi, GlobalSize( hMem ));
2048         }
2049         else
2050         {
2051             uiLo = LOWORD( *lparam );
2052             uiHi = HIWORD( *lparam );
2053             TRACE("recv dde-ack %lx atom=%lx\n", uiLo, uiHi);
2054         }
2055         *lparam = PackDDElParam( WM_DDE_ACK, uiLo, uiHi );
2056         break;
2057     case WM_DDE_ADVISE:
2058     case WM_DDE_DATA:
2059     case WM_DDE_POKE:
2060         if ((!buffer || !*buffer) && message != WM_DDE_DATA) return FALSE;
2061         uiHi = *lparam;
2062         if (size)
2063         {
2064             if (!(hMem = GlobalAlloc( GMEM_MOVEABLE|GMEM_DDESHARE, size )))
2065                 return FALSE;
2066             if ((ptr = GlobalLock( hMem )))
2067             {
2068                 memcpy( ptr, *buffer, size );
2069                 GlobalUnlock( hMem );
2070             }
2071             else
2072             {
2073                 GlobalFree( hMem );
2074                 return FALSE;
2075             }
2076         }
2077         uiLo = (UINT_PTR)hMem;
2078
2079         *lparam = PackDDElParam( message, uiLo, uiHi );
2080         break;
2081     case WM_DDE_EXECUTE:
2082         if (size)
2083         {
2084             if (!buffer || !*buffer) return FALSE;
2085             if (!(hMem = GlobalAlloc( GMEM_MOVEABLE|GMEM_DDESHARE, size ))) return FALSE;
2086             if ((ptr = GlobalLock( hMem )))
2087             {
2088                 memcpy( ptr, *buffer, size );
2089                 GlobalUnlock( hMem );
2090                 TRACE( "exec: pairing c=%08lx s=%p\n", *lparam, hMem );
2091                 if (!dde_add_pair( (HGLOBAL)*lparam, hMem ))
2092                 {
2093                     GlobalFree( hMem );
2094                     return FALSE;
2095                 }
2096             }
2097             else
2098             {
2099                 GlobalFree( hMem );
2100                 return FALSE;
2101             }
2102         } else return FALSE;
2103         *lparam = (LPARAM)hMem;
2104         break;
2105     }
2106     return TRUE;
2107 }
2108
2109 /***********************************************************************
2110  *           call_window_proc
2111  *
2112  * Call a window procedure and the corresponding hooks.
2113  */
2114 static LRESULT call_window_proc( HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam,
2115                                  BOOL unicode, BOOL same_thread, enum wm_char_mapping mapping )
2116 {
2117     LRESULT result = 0;
2118     CWPSTRUCT cwp;
2119     CWPRETSTRUCT cwpret;
2120
2121     if (msg & 0x80000000)
2122     {
2123         result = handle_internal_message( hwnd, msg, wparam, lparam );
2124         goto done;
2125     }
2126
2127     /* first the WH_CALLWNDPROC hook */
2128     hwnd = WIN_GetFullHandle( hwnd );
2129     cwp.lParam  = lparam;
2130     cwp.wParam  = wparam;
2131     cwp.message = msg;
2132     cwp.hwnd    = hwnd;
2133     HOOK_CallHooks( WH_CALLWNDPROC, HC_ACTION, same_thread, (LPARAM)&cwp, unicode );
2134
2135     /* now call the window procedure */
2136     if (!WINPROC_call_window( hwnd, msg, wparam, lparam, &result, unicode, mapping )) goto done;
2137
2138     /* and finally the WH_CALLWNDPROCRET hook */
2139     cwpret.lResult = result;
2140     cwpret.lParam  = lparam;
2141     cwpret.wParam  = wparam;
2142     cwpret.message = msg;
2143     cwpret.hwnd    = hwnd;
2144     HOOK_CallHooks( WH_CALLWNDPROCRET, HC_ACTION, same_thread, (LPARAM)&cwpret, unicode );
2145  done:
2146     return result;
2147 }
2148
2149
2150 /***********************************************************************
2151  *           send_parent_notify
2152  *
2153  * Send a WM_PARENTNOTIFY to all ancestors of the given window, unless
2154  * the window has the WS_EX_NOPARENTNOTIFY style.
2155  */
2156 static void send_parent_notify( HWND hwnd, WORD event, WORD idChild, POINT pt )
2157 {
2158     /* pt has to be in the client coordinates of the parent window */
2159     MapWindowPoints( 0, hwnd, &pt, 1 );
2160     for (;;)
2161     {
2162         HWND parent;
2163
2164         if (!(GetWindowLongW( hwnd, GWL_STYLE ) & WS_CHILD)) break;
2165         if (GetWindowLongW( hwnd, GWL_EXSTYLE ) & WS_EX_NOPARENTNOTIFY) break;
2166         if (!(parent = GetParent(hwnd))) break;
2167         if (parent == GetDesktopWindow()) break;
2168         MapWindowPoints( hwnd, parent, &pt, 1 );
2169         hwnd = parent;
2170         SendMessageW( hwnd, WM_PARENTNOTIFY,
2171                       MAKEWPARAM( event, idChild ), MAKELPARAM( pt.x, pt.y ) );
2172     }
2173 }
2174
2175
2176 /***********************************************************************
2177  *          accept_hardware_message
2178  *
2179  * Tell the server we have passed the message to the app
2180  * (even though we may end up dropping it later on)
2181  */
2182 static void accept_hardware_message( UINT hw_id, BOOL remove, HWND new_hwnd )
2183 {
2184     SERVER_START_REQ( accept_hardware_message )
2185     {
2186         req->hw_id   = hw_id;
2187         req->remove  = remove;
2188         req->new_win = wine_server_user_handle( new_hwnd );
2189         if (wine_server_call( req ))
2190             FIXME("Failed to reply to MSG_HARDWARE message. Message may not be removed from queue.\n");
2191     }
2192     SERVER_END_REQ;
2193 }
2194
2195
2196 /***********************************************************************
2197  *          process_keyboard_message
2198  *
2199  * returns TRUE if the contents of 'msg' should be passed to the application
2200  */
2201 static BOOL process_keyboard_message( MSG *msg, UINT hw_id, HWND hwnd_filter,
2202                                       UINT first, UINT last, BOOL remove )
2203 {
2204     EVENTMSG event;
2205
2206     if (msg->message == WM_KEYDOWN || msg->message == WM_SYSKEYDOWN ||
2207         msg->message == WM_KEYUP || msg->message == WM_SYSKEYUP)
2208         switch (msg->wParam)
2209         {
2210             case VK_LSHIFT: case VK_RSHIFT:
2211                 msg->wParam = VK_SHIFT;
2212                 break;
2213             case VK_LCONTROL: case VK_RCONTROL:
2214                 msg->wParam = VK_CONTROL;
2215                 break;
2216             case VK_LMENU: case VK_RMENU:
2217                 msg->wParam = VK_MENU;
2218                 break;
2219         }
2220
2221     /* FIXME: is this really the right place for this hook? */
2222     event.message = msg->message;
2223     event.hwnd    = msg->hwnd;
2224     event.time    = msg->time;
2225     event.paramL  = (msg->wParam & 0xFF) | (HIWORD(msg->lParam) << 8);
2226     event.paramH  = msg->lParam & 0x7FFF;
2227     if (HIWORD(msg->lParam) & 0x0100) event.paramH |= 0x8000; /* special_key - bit */
2228     HOOK_CallHooks( WH_JOURNALRECORD, HC_ACTION, 0, (LPARAM)&event, TRUE );
2229
2230     /* check message filters */
2231     if (msg->message < first || msg->message > last) return FALSE;
2232     if (!check_hwnd_filter( msg, hwnd_filter )) return FALSE;
2233
2234     if (remove)
2235     {
2236         if((msg->message == WM_KEYDOWN) &&
2237            (msg->hwnd != GetDesktopWindow()))
2238         {
2239             /* Handle F1 key by sending out WM_HELP message */
2240             if (msg->wParam == VK_F1)
2241             {
2242                 PostMessageW( msg->hwnd, WM_KEYF1, 0, 0 );
2243             }
2244             else if(msg->wParam >= VK_BROWSER_BACK &&
2245                     msg->wParam <= VK_LAUNCH_APP2)
2246             {
2247                 /* FIXME: Process keystate */
2248                 SendMessageW(msg->hwnd, WM_APPCOMMAND, (WPARAM)msg->hwnd, MAKELPARAM(0, (FAPPCOMMAND_KEY | (msg->wParam - VK_BROWSER_BACK + 1))));
2249             }
2250         }
2251         else if (msg->message == WM_KEYUP)
2252         {
2253             /* Handle VK_APPS key by posting a WM_CONTEXTMENU message */
2254             if (msg->wParam == VK_APPS && !MENU_IsMenuActive())
2255                 PostMessageW(msg->hwnd, WM_CONTEXTMENU, (WPARAM)msg->hwnd, -1);
2256         }
2257     }
2258
2259     if (HOOK_CallHooks( WH_KEYBOARD, remove ? HC_ACTION : HC_NOREMOVE,
2260                         LOWORD(msg->wParam), msg->lParam, TRUE ))
2261     {
2262         /* skip this message */
2263         HOOK_CallHooks( WH_CBT, HCBT_KEYSKIPPED, LOWORD(msg->wParam), msg->lParam, TRUE );
2264         accept_hardware_message( hw_id, TRUE, 0 );
2265         return FALSE;
2266     }
2267     accept_hardware_message( hw_id, remove, 0 );
2268
2269     if ( msg->message == WM_KEYDOWN || msg->message == WM_KEYUP )
2270         if ( ImmProcessKey(msg->hwnd, GetKeyboardLayout(0), msg->wParam, msg->lParam, 0) )
2271             msg->wParam = VK_PROCESSKEY;
2272
2273     return TRUE;
2274 }
2275
2276
2277 /***********************************************************************
2278  *          process_mouse_message
2279  *
2280  * returns TRUE if the contents of 'msg' should be passed to the application
2281  */
2282 static BOOL process_mouse_message( MSG *msg, UINT hw_id, ULONG_PTR extra_info, HWND hwnd_filter,
2283                                    UINT first, UINT last, BOOL remove )
2284 {
2285     static MSG clk_msg;
2286
2287     POINT pt;
2288     UINT message;
2289     INT hittest;
2290     EVENTMSG event;
2291     GUITHREADINFO info;
2292     MOUSEHOOKSTRUCT hook;
2293     BOOL eatMsg;
2294
2295     /* find the window to dispatch this mouse message to */
2296
2297     GetGUIThreadInfo( GetCurrentThreadId(), &info );
2298     if (info.hwndCapture)
2299     {
2300         hittest = HTCLIENT;
2301         msg->hwnd = info.hwndCapture;
2302     }
2303     else
2304     {
2305         msg->hwnd = WINPOS_WindowFromPoint( msg->hwnd, msg->pt, &hittest );
2306     }
2307
2308     if (!msg->hwnd || !WIN_IsCurrentThread( msg->hwnd ))
2309     {
2310         accept_hardware_message( hw_id, TRUE, msg->hwnd );
2311         return FALSE;
2312     }
2313
2314     /* FIXME: is this really the right place for this hook? */
2315     event.message = msg->message;
2316     event.time    = msg->time;
2317     event.hwnd    = msg->hwnd;
2318     event.paramL  = msg->pt.x;
2319     event.paramH  = msg->pt.y;
2320     HOOK_CallHooks( WH_JOURNALRECORD, HC_ACTION, 0, (LPARAM)&event, TRUE );
2321
2322     if (!check_hwnd_filter( msg, hwnd_filter )) return FALSE;
2323
2324     pt = msg->pt;
2325     message = msg->message;
2326     /* Note: windows has no concept of a non-client wheel message */
2327     if (message != WM_MOUSEWHEEL)
2328     {
2329         if (hittest != HTCLIENT)
2330         {
2331             message += WM_NCMOUSEMOVE - WM_MOUSEMOVE;
2332             msg->wParam = hittest;
2333         }
2334         else
2335         {
2336             /* coordinates don't get translated while tracking a menu */
2337             /* FIXME: should differentiate popups and top-level menus */
2338             if (!(info.flags & GUI_INMENUMODE))
2339                 ScreenToClient( msg->hwnd, &pt );
2340         }
2341     }
2342     msg->lParam = MAKELONG( pt.x, pt.y );
2343
2344     /* translate double clicks */
2345
2346     if ((msg->message == WM_LBUTTONDOWN) ||
2347         (msg->message == WM_RBUTTONDOWN) ||
2348         (msg->message == WM_MBUTTONDOWN) ||
2349         (msg->message == WM_XBUTTONDOWN))
2350     {
2351         BOOL update = remove;
2352
2353         /* translate double clicks -
2354          * note that ...MOUSEMOVEs can slip in between
2355          * ...BUTTONDOWN and ...BUTTONDBLCLK messages */
2356
2357         if ((info.flags & (GUI_INMENUMODE|GUI_INMOVESIZE)) ||
2358             hittest != HTCLIENT ||
2359             (GetClassLongA( msg->hwnd, GCL_STYLE ) & CS_DBLCLKS))
2360         {
2361            if ((msg->message == clk_msg.message) &&
2362                (msg->hwnd == clk_msg.hwnd) &&
2363                (msg->wParam == clk_msg.wParam) &&
2364                (msg->time - clk_msg.time < GetDoubleClickTime()) &&
2365                (abs(msg->pt.x - clk_msg.pt.x) < GetSystemMetrics(SM_CXDOUBLECLK)/2) &&
2366                (abs(msg->pt.y - clk_msg.pt.y) < GetSystemMetrics(SM_CYDOUBLECLK)/2))
2367            {
2368                message += (WM_LBUTTONDBLCLK - WM_LBUTTONDOWN);
2369                if (update)
2370                {
2371                    clk_msg.message = 0;  /* clear the double click conditions */
2372                    update = FALSE;
2373                }
2374            }
2375         }
2376         if (message < first || message > last) return FALSE;
2377         /* update static double click conditions */
2378         if (update) clk_msg = *msg;
2379     }
2380     else
2381     {
2382         if (message < first || message > last) return FALSE;
2383     }
2384
2385     /* message is accepted now (but may still get dropped) */
2386
2387     hook.pt           = msg->pt;
2388     hook.hwnd         = msg->hwnd;
2389     hook.wHitTestCode = hittest;
2390     hook.dwExtraInfo  = extra_info;
2391     if (HOOK_CallHooks( WH_MOUSE, remove ? HC_ACTION : HC_NOREMOVE,
2392                         message, (LPARAM)&hook, TRUE ))
2393     {
2394         hook.pt           = msg->pt;
2395         hook.hwnd         = msg->hwnd;
2396         hook.wHitTestCode = hittest;
2397         hook.dwExtraInfo  = extra_info;
2398         HOOK_CallHooks( WH_CBT, HCBT_CLICKSKIPPED, message, (LPARAM)&hook, TRUE );
2399         accept_hardware_message( hw_id, TRUE, 0 );
2400         return FALSE;
2401     }
2402
2403     if ((hittest == HTERROR) || (hittest == HTNOWHERE))
2404     {
2405         SendMessageW( msg->hwnd, WM_SETCURSOR, (WPARAM)msg->hwnd,
2406                       MAKELONG( hittest, msg->message ));
2407         accept_hardware_message( hw_id, TRUE, 0 );
2408         return FALSE;
2409     }
2410
2411     accept_hardware_message( hw_id, remove, 0 );
2412
2413     if (!remove || info.hwndCapture)
2414     {
2415         msg->message = message;
2416         return TRUE;
2417     }
2418
2419     eatMsg = FALSE;
2420
2421     if ((msg->message == WM_LBUTTONDOWN) ||
2422         (msg->message == WM_RBUTTONDOWN) ||
2423         (msg->message == WM_MBUTTONDOWN) ||
2424         (msg->message == WM_XBUTTONDOWN))
2425     {
2426         /* Send the WM_PARENTNOTIFY,
2427          * note that even for double/nonclient clicks
2428          * notification message is still WM_L/M/RBUTTONDOWN.
2429          */
2430         send_parent_notify( msg->hwnd, msg->message, 0, msg->pt );
2431
2432         /* Activate the window if needed */
2433
2434         if (msg->hwnd != info.hwndActive)
2435         {
2436             HWND hwndTop = msg->hwnd;
2437             while (hwndTop)
2438             {
2439                 if ((GetWindowLongW( hwndTop, GWL_STYLE ) & (WS_POPUP|WS_CHILD)) != WS_CHILD) break;
2440                 hwndTop = GetParent( hwndTop );
2441             }
2442
2443             if (hwndTop && hwndTop != GetDesktopWindow())
2444             {
2445                 LONG ret = SendMessageW( msg->hwnd, WM_MOUSEACTIVATE, (WPARAM)hwndTop,
2446                                          MAKELONG( hittest, msg->message ) );
2447                 switch(ret)
2448                 {
2449                 case MA_NOACTIVATEANDEAT:
2450                     eatMsg = TRUE;
2451                     /* fall through */
2452                 case MA_NOACTIVATE:
2453                     break;
2454                 case MA_ACTIVATEANDEAT:
2455                     eatMsg = TRUE;
2456                     /* fall through */
2457                 case MA_ACTIVATE:
2458                 case 0:
2459                     if (!FOCUS_MouseActivate( hwndTop )) eatMsg = TRUE;
2460                     break;
2461                 default:
2462                     WARN( "unknown WM_MOUSEACTIVATE code %d\n", ret );
2463                     break;
2464                 }
2465             }
2466         }
2467     }
2468
2469     /* send the WM_SETCURSOR message */
2470
2471     /* Windows sends the normal mouse message as the message parameter
2472        in the WM_SETCURSOR message even if it's non-client mouse message */
2473     SendMessageW( msg->hwnd, WM_SETCURSOR, (WPARAM)msg->hwnd, MAKELONG( hittest, msg->message ));
2474
2475     msg->message = message;
2476     return !eatMsg;
2477 }
2478
2479
2480 /***********************************************************************
2481  *           process_hardware_message
2482  *
2483  * Process a hardware message; return TRUE if message should be passed on to the app
2484  */
2485 static BOOL process_hardware_message( MSG *msg, UINT hw_id, ULONG_PTR extra_info, HWND hwnd_filter,
2486                                       UINT first, UINT last, BOOL remove )
2487 {
2488     if (is_keyboard_message( msg->message ))
2489         return process_keyboard_message( msg, hw_id, hwnd_filter, first, last, remove );
2490
2491     if (is_mouse_message( msg->message ))
2492         return process_mouse_message( msg, hw_id, extra_info, hwnd_filter, first, last, remove );
2493
2494     ERR( "unknown message type %x\n", msg->message );
2495     return FALSE;
2496 }
2497
2498
2499 /***********************************************************************
2500  *           call_sendmsg_callback
2501  *
2502  * Call the callback function of SendMessageCallback.
2503  */
2504 static inline void call_sendmsg_callback( SENDASYNCPROC callback, HWND hwnd, UINT msg,
2505                                           ULONG_PTR data, LRESULT result )
2506 {
2507     if (!callback) return;
2508
2509     if (TRACE_ON(relay))
2510         DPRINTF( "%04x:Call message callback %p (hwnd=%p,msg=%s,data=%08lx,result=%08lx)\n",
2511                  GetCurrentThreadId(), callback, hwnd, SPY_GetMsgName( msg, hwnd ),
2512                  data, result );
2513     callback( hwnd, msg, data, result );
2514     if (TRACE_ON(relay))
2515         DPRINTF( "%04x:Ret  message callback %p (hwnd=%p,msg=%s,data=%08lx,result=%08lx)\n",
2516                  GetCurrentThreadId(), callback, hwnd, SPY_GetMsgName( msg, hwnd ),
2517                  data, result );
2518 }
2519
2520
2521 /***********************************************************************
2522  *           peek_message
2523  *
2524  * Peek for a message matching the given parameters. Return FALSE if none available.
2525  * All pending sent messages are processed before returning.
2526  */
2527 static BOOL peek_message( MSG *msg, HWND hwnd, UINT first, UINT last, UINT flags, UINT changed_mask )
2528 {
2529     LRESULT result;
2530     struct user_thread_info *thread_info = get_user_thread_info();
2531     struct received_message_info info, *old_info;
2532     unsigned int hw_id = 0;  /* id of previous hardware message */
2533     void *buffer;
2534     size_t buffer_size = 256;
2535
2536     if (!(buffer = HeapAlloc( GetProcessHeap(), 0, buffer_size ))) return FALSE;
2537
2538     if (!first && !last) last = ~0;
2539     if (hwnd == HWND_BROADCAST) hwnd = HWND_TOPMOST;
2540
2541     for (;;)
2542     {
2543         NTSTATUS res;
2544         size_t size = 0;
2545         const message_data_t *msg_data = buffer;
2546
2547         SERVER_START_REQ( get_message )
2548         {
2549             req->flags     = flags;
2550             req->get_win   = wine_server_user_handle( hwnd );
2551             req->get_first = first;
2552             req->get_last  = last;
2553             req->hw_id     = hw_id;
2554             req->wake_mask = changed_mask & (QS_SENDMESSAGE | QS_SMRESULT);
2555             req->changed_mask = changed_mask;
2556             wine_server_set_reply( req, buffer, buffer_size );
2557             if (!(res = wine_server_call( req )))
2558             {
2559                 size = wine_server_reply_size( reply );
2560                 info.type        = reply->type;
2561                 info.msg.hwnd    = wine_server_ptr_handle( reply->win );
2562                 info.msg.message = reply->msg;
2563                 info.msg.wParam  = reply->wparam;
2564                 info.msg.lParam  = reply->lparam;
2565                 info.msg.time    = reply->time;
2566                 info.msg.pt.x    = 0;
2567                 info.msg.pt.y    = 0;
2568                 hw_id            = 0;
2569                 thread_info->active_hooks = reply->active_hooks;
2570             }
2571             else buffer_size = reply->total;
2572         }
2573         SERVER_END_REQ;
2574
2575         if (res)
2576         {
2577             HeapFree( GetProcessHeap(), 0, buffer );
2578             if (res != STATUS_BUFFER_OVERFLOW) return FALSE;
2579             if (!(buffer = HeapAlloc( GetProcessHeap(), 0, buffer_size ))) return FALSE;
2580             continue;
2581         }
2582
2583         TRACE( "got type %d msg %x (%s) hwnd %p wp %lx lp %lx\n",
2584                info.type, info.msg.message,
2585                (info.type == MSG_WINEVENT) ? "MSG_WINEVENT" : SPY_GetMsgName(info.msg.message, info.msg.hwnd),
2586                info.msg.hwnd, info.msg.wParam, info.msg.lParam );
2587
2588         switch(info.type)
2589         {
2590         case MSG_ASCII:
2591         case MSG_UNICODE:
2592             info.flags = ISMEX_SEND;
2593             break;
2594         case MSG_NOTIFY:
2595             info.flags = ISMEX_NOTIFY;
2596             break;
2597         case MSG_CALLBACK:
2598             info.flags = ISMEX_CALLBACK;
2599             break;
2600         case MSG_CALLBACK_RESULT:
2601             if (size >= sizeof(msg_data->callback))
2602                 call_sendmsg_callback( wine_server_get_ptr(msg_data->callback.callback),
2603                                        info.msg.hwnd, info.msg.message,
2604                                        msg_data->callback.data, msg_data->callback.result );
2605             continue;
2606         case MSG_WINEVENT:
2607             if (size >= sizeof(msg_data->winevent))
2608             {
2609                 WINEVENTPROC hook_proc;
2610
2611                 hook_proc = wine_server_get_ptr( msg_data->winevent.hook_proc );
2612                 size -= sizeof(msg_data->winevent);
2613                 if (size)
2614                 {
2615                     WCHAR module[MAX_PATH];
2616
2617                     size = min( size, (MAX_PATH - 1) * sizeof(WCHAR) );
2618                     memcpy( module, &msg_data->winevent + 1, size );
2619                     module[size / sizeof(WCHAR)] = 0;
2620                     if (!(hook_proc = get_hook_proc( hook_proc, module )))
2621                     {
2622                         ERR( "invalid winevent hook module name %s\n", debugstr_w(module) );
2623                         continue;
2624                     }
2625                 }
2626
2627                 if (TRACE_ON(relay))
2628                     DPRINTF( "%04x:Call winevent proc %p (hook=%04x,event=%x,hwnd=%p,object_id=%lx,child_id=%lx,tid=%04x,time=%x)\n",
2629                              GetCurrentThreadId(), hook_proc,
2630                              msg_data->winevent.hook, info.msg.message, info.msg.hwnd, info.msg.wParam,
2631                              info.msg.lParam, msg_data->winevent.tid, info.msg.time);
2632
2633                 hook_proc( wine_server_ptr_handle( msg_data->winevent.hook ), info.msg.message,
2634                            info.msg.hwnd, info.msg.wParam, info.msg.lParam,
2635                            msg_data->winevent.tid, info.msg.time );
2636
2637                 if (TRACE_ON(relay))
2638                     DPRINTF( "%04x:Ret  winevent proc %p (hook=%04x,event=%x,hwnd=%p,object_id=%lx,child_id=%lx,tid=%04x,time=%x)\n",
2639                              GetCurrentThreadId(), hook_proc,
2640                              msg_data->winevent.hook, info.msg.message, info.msg.hwnd, info.msg.wParam,
2641                              info.msg.lParam, msg_data->winevent.tid, info.msg.time);
2642             }
2643             continue;
2644         case MSG_OTHER_PROCESS:
2645             info.flags = ISMEX_SEND;
2646             if (!unpack_message( info.msg.hwnd, info.msg.message, &info.msg.wParam,
2647                                  &info.msg.lParam, &buffer, size ))
2648             {
2649                 /* ignore it */
2650                 reply_message( &info, 0, TRUE );
2651                 continue;
2652             }
2653             break;
2654         case MSG_HARDWARE:
2655             if (size >= sizeof(msg_data->hardware))
2656             {
2657                 info.msg.pt.x = msg_data->hardware.x;
2658                 info.msg.pt.y = msg_data->hardware.y;
2659                 hw_id         = msg_data->hardware.hw_id;
2660                 if (!process_hardware_message( &info.msg, hw_id, msg_data->hardware.info,
2661                                                hwnd, first, last, flags & PM_REMOVE ))
2662                 {
2663                     TRACE("dropping msg %x\n", info.msg.message );
2664                     continue;  /* ignore it */
2665                 }
2666                 *msg = info.msg;
2667                 thread_info->GetMessagePosVal = MAKELONG( info.msg.pt.x, info.msg.pt.y );
2668                 thread_info->GetMessageTimeVal = info.msg.time;
2669                 thread_info->GetMessageExtraInfoVal = msg_data->hardware.info;
2670                 HeapFree( GetProcessHeap(), 0, buffer );
2671                 HOOK_CallHooks( WH_GETMESSAGE, HC_ACTION, flags & PM_REMOVE, (LPARAM)msg, TRUE );
2672                 return TRUE;
2673             }
2674             continue;
2675         case MSG_POSTED:
2676             if (info.msg.message & 0x80000000)  /* internal message */
2677             {
2678                 if (flags & PM_REMOVE)
2679                 {
2680                     handle_internal_message( info.msg.hwnd, info.msg.message,
2681                                              info.msg.wParam, info.msg.lParam );
2682                     /* if this is a nested call return right away */
2683                     if (first == info.msg.message && last == info.msg.message) return FALSE;
2684                 }
2685                 else
2686                     peek_message( msg, info.msg.hwnd, info.msg.message,
2687                                   info.msg.message, flags | PM_REMOVE, changed_mask );
2688                 continue;
2689             }
2690             if (info.msg.message >= WM_DDE_FIRST && info.msg.message <= WM_DDE_LAST)
2691             {
2692                 if (!unpack_dde_message( info.msg.hwnd, info.msg.message, &info.msg.wParam,
2693                                          &info.msg.lParam, &buffer, size ))
2694                     continue;  /* ignore it */
2695             }
2696             *msg = info.msg;
2697             msg->pt.x = (short)LOWORD( thread_info->GetMessagePosVal );
2698             msg->pt.y = (short)HIWORD( thread_info->GetMessagePosVal );
2699             thread_info->GetMessageTimeVal = info.msg.time;
2700             thread_info->GetMessageExtraInfoVal = 0;
2701             HeapFree( GetProcessHeap(), 0, buffer );
2702             HOOK_CallHooks( WH_GETMESSAGE, HC_ACTION, flags & PM_REMOVE, (LPARAM)msg, TRUE );
2703             return TRUE;
2704         }
2705
2706         /* if we get here, we have a sent message; call the window procedure */
2707         old_info = thread_info->receive_info;
2708         thread_info->receive_info = &info;
2709         result = call_window_proc( info.msg.hwnd, info.msg.message, info.msg.wParam,
2710                                    info.msg.lParam, (info.type != MSG_ASCII), FALSE,
2711                                    WMCHAR_MAP_RECVMESSAGE );
2712         reply_message( &info, result, TRUE );
2713         thread_info->receive_info = old_info;
2714
2715         /* if some PM_QS* flags were specified, only handle sent messages from now on */
2716         if (HIWORD(flags) && !changed_mask) flags = PM_QS_SENDMESSAGE | LOWORD(flags);
2717     }
2718 }
2719
2720
2721 /***********************************************************************
2722  *           process_sent_messages
2723  *
2724  * Process all pending sent messages.
2725  */
2726 static inline void process_sent_messages(void)
2727 {
2728     MSG msg;
2729     peek_message( &msg, 0, 0, 0, PM_REMOVE | PM_QS_SENDMESSAGE, 0 );
2730 }
2731
2732
2733 /***********************************************************************
2734  *           get_server_queue_handle
2735  *
2736  * Get a handle to the server message queue for the current thread.
2737  */
2738 static HANDLE get_server_queue_handle(void)
2739 {
2740     struct user_thread_info *thread_info = get_user_thread_info();
2741     HANDLE ret;
2742
2743     if (!(ret = thread_info->server_queue))
2744     {
2745         SERVER_START_REQ( get_msg_queue )
2746         {
2747             wine_server_call( req );
2748             ret = wine_server_ptr_handle( reply->handle );
2749         }
2750         SERVER_END_REQ;
2751         thread_info->server_queue = ret;
2752         if (!ret) ERR( "Cannot get server thread queue\n" );
2753     }
2754     return ret;
2755 }
2756
2757
2758 /***********************************************************************
2759  *           wait_message_reply
2760  *
2761  * Wait until a sent message gets replied to.
2762  */
2763 static void wait_message_reply( UINT flags )
2764 {
2765     HANDLE server_queue = get_server_queue_handle();
2766
2767     for (;;)
2768     {
2769         unsigned int wake_bits = 0;
2770
2771         SERVER_START_REQ( set_queue_mask )
2772         {
2773             req->wake_mask    = QS_SMRESULT | ((flags & SMTO_BLOCK) ? 0 : QS_SENDMESSAGE);
2774             req->changed_mask = req->wake_mask;
2775             req->skip_wait    = 1;
2776             if (!wine_server_call( req ))
2777                 wake_bits = reply->wake_bits;
2778         }
2779         SERVER_END_REQ;
2780
2781         if (wake_bits & QS_SMRESULT) return;  /* got a result */
2782         if (wake_bits & QS_SENDMESSAGE)
2783         {
2784             /* Process the sent message immediately */
2785             process_sent_messages();
2786             continue;
2787         }
2788
2789         wow_handlers.wait_message( 1, &server_queue, INFINITE, QS_SENDMESSAGE, 0 );
2790     }
2791 }
2792
2793 /***********************************************************************
2794  *              put_message_in_queue
2795  *
2796  * Put a sent message into the destination queue.
2797  * For inter-process message, reply_size is set to expected size of reply data.
2798  */
2799 static BOOL put_message_in_queue( const struct send_message_info *info, size_t *reply_size )
2800 {
2801     struct packed_message data;
2802     message_data_t msg_data;
2803     unsigned int res;
2804     int i;
2805     timeout_t timeout = TIMEOUT_INFINITE;
2806
2807     /* Check for INFINITE timeout for compatibility with Win9x,
2808      * although Windows >= NT does not do so
2809      */
2810     if (info->type != MSG_NOTIFY &&
2811         info->type != MSG_CALLBACK &&
2812         info->type != MSG_POSTED &&
2813         info->timeout &&
2814         info->timeout != INFINITE)
2815     {
2816         /* timeout is signed despite the prototype */
2817         timeout = (timeout_t)max( 0, (int)info->timeout ) * -10000;
2818     }
2819
2820     memset( &data, 0, sizeof(data) );
2821     if (info->type == MSG_OTHER_PROCESS)
2822     {
2823         *reply_size = pack_message( info->hwnd, info->msg, info->wparam, info->lparam, &data );
2824         if (data.count == -1)
2825         {
2826             WARN( "cannot pack message %x\n", info->msg );
2827             return FALSE;
2828         }
2829     }
2830     else if (info->type == MSG_CALLBACK)
2831     {
2832         msg_data.callback.callback = wine_server_client_ptr( info->callback );
2833         msg_data.callback.data     = info->data;
2834         msg_data.callback.result   = 0;
2835         data.data[0] = &msg_data;
2836         data.size[0] = sizeof(msg_data.callback);
2837         data.count = 1;
2838     }
2839     else if (info->type == MSG_POSTED && info->msg >= WM_DDE_FIRST && info->msg <= WM_DDE_LAST)
2840     {
2841         return post_dde_message( &data, info );
2842     }
2843
2844     SERVER_START_REQ( send_message )
2845     {
2846         req->id      = info->dest_tid;
2847         req->type    = info->type;
2848         req->flags   = 0;
2849         req->win     = wine_server_user_handle( info->hwnd );
2850         req->msg     = info->msg;
2851         req->wparam  = info->wparam;
2852         req->lparam  = info->lparam;
2853         req->timeout = timeout;
2854
2855         if (info->flags & SMTO_ABORTIFHUNG) req->flags |= SEND_MSG_ABORT_IF_HUNG;
2856         for (i = 0; i < data.count; i++) wine_server_add_data( req, data.data[i], data.size[i] );
2857         if ((res = wine_server_call( req )))
2858         {
2859             if (res == STATUS_INVALID_PARAMETER)
2860                 /* FIXME: find a STATUS_ value for this one */
2861                 SetLastError( ERROR_INVALID_THREAD_ID );
2862             else
2863                 SetLastError( RtlNtStatusToDosError(res) );
2864         }
2865     }
2866     SERVER_END_REQ;
2867     return !res;
2868 }
2869
2870
2871 /***********************************************************************
2872  *              retrieve_reply
2873  *
2874  * Retrieve a message reply from the server.
2875  */
2876 static LRESULT retrieve_reply( const struct send_message_info *info,
2877                                size_t reply_size, LRESULT *result )
2878 {
2879     NTSTATUS status;
2880     void *reply_data = NULL;
2881
2882     if (reply_size)
2883     {
2884         if (!(reply_data = HeapAlloc( GetProcessHeap(), 0, reply_size )))
2885         {
2886             WARN( "no memory for reply, will be truncated\n" );
2887             reply_size = 0;
2888         }
2889     }
2890     SERVER_START_REQ( get_message_reply )
2891     {
2892         req->cancel = 1;
2893         if (reply_size) wine_server_set_reply( req, reply_data, reply_size );
2894         if (!(status = wine_server_call( req ))) *result = reply->result;
2895         reply_size = wine_server_reply_size( reply );
2896     }
2897     SERVER_END_REQ;
2898     if (!status && reply_size)
2899         unpack_reply( info->hwnd, info->msg, info->wparam, info->lparam, reply_data, reply_size );
2900
2901     HeapFree( GetProcessHeap(), 0, reply_data );
2902
2903     TRACE( "hwnd %p msg %x (%s) wp %lx lp %lx got reply %lx (err=%d)\n",
2904            info->hwnd, info->msg, SPY_GetMsgName(info->msg, info->hwnd), info->wparam,
2905            info->lparam, *result, status );
2906
2907     /* MSDN states that last error is 0 on timeout, but at least NT4 returns ERROR_TIMEOUT */
2908     if (status) SetLastError( RtlNtStatusToDosError(status) );
2909     return !status;
2910 }
2911
2912
2913 /***********************************************************************
2914  *              send_inter_thread_message
2915  */
2916 static LRESULT send_inter_thread_message( const struct send_message_info *info, LRESULT *res_ptr )
2917 {
2918     size_t reply_size = 0;
2919
2920     TRACE( "hwnd %p msg %x (%s) wp %lx lp %lx\n",
2921            info->hwnd, info->msg, SPY_GetMsgName(info->msg, info->hwnd), info->wparam, info->lparam );
2922
2923     USER_CheckNotLock();
2924
2925     if (!put_message_in_queue( info, &reply_size )) return 0;
2926
2927     /* there's no reply to wait for on notify/callback messages */
2928     if (info->type == MSG_NOTIFY || info->type == MSG_CALLBACK) return 1;
2929
2930     wait_message_reply( info->flags );
2931     return retrieve_reply( info, reply_size, res_ptr );
2932 }
2933
2934
2935 /***********************************************************************
2936  *              send_inter_thread_callback
2937  */
2938 static LRESULT send_inter_thread_callback( HWND hwnd, UINT msg, WPARAM wp, LPARAM lp,
2939                                            LRESULT *result, void *arg )
2940 {
2941     struct send_message_info *info = arg;
2942     info->hwnd   = hwnd;
2943     info->msg    = msg;
2944     info->wparam = wp;
2945     info->lparam = lp;
2946     return send_inter_thread_message( info, result );
2947 }
2948
2949
2950 /***********************************************************************
2951  *              send_message
2952  *
2953  * Backend implementation of the various SendMessage functions.
2954  */
2955 static BOOL send_message( struct send_message_info *info, DWORD_PTR *res_ptr, BOOL unicode )
2956 {
2957     DWORD dest_pid;
2958     BOOL ret;
2959     LRESULT result;
2960
2961     if (is_broadcast(info->hwnd))
2962     {
2963         EnumWindows( broadcast_message_callback, (LPARAM)info );
2964         if (res_ptr) *res_ptr = 1;
2965         return TRUE;
2966     }
2967
2968     if (!(info->dest_tid = GetWindowThreadProcessId( info->hwnd, &dest_pid ))) return FALSE;
2969
2970     if (USER_IsExitingThread( info->dest_tid )) return FALSE;
2971
2972     SPY_EnterMessage( SPY_SENDMESSAGE, info->hwnd, info->msg, info->wparam, info->lparam );
2973
2974     if (info->dest_tid == GetCurrentThreadId())
2975     {
2976         result = call_window_proc( info->hwnd, info->msg, info->wparam, info->lparam,
2977                                    unicode, TRUE, info->wm_char );
2978         if (info->type == MSG_CALLBACK)
2979             call_sendmsg_callback( info->callback, info->hwnd, info->msg, info->data, result );
2980         ret = TRUE;
2981     }
2982     else
2983     {
2984         if (dest_pid != GetCurrentProcessId() && (info->type == MSG_ASCII || info->type == MSG_UNICODE))
2985             info->type = MSG_OTHER_PROCESS;
2986
2987         /* MSG_ASCII can be sent unconverted except for WM_CHAR; everything else needs to be Unicode */
2988         if (!unicode && is_unicode_message( info->msg ) &&
2989             (info->type != MSG_ASCII || info->msg == WM_CHAR))
2990             ret = WINPROC_CallProcAtoW( send_inter_thread_callback, info->hwnd, info->msg,
2991                                         info->wparam, info->lparam, &result, info, info->wm_char );
2992         else
2993             ret = send_inter_thread_message( info, &result );
2994     }
2995
2996     SPY_ExitMessage( SPY_RESULT_OK, info->hwnd, info->msg, result, info->wparam, info->lparam );
2997     if (ret && res_ptr) *res_ptr = result;
2998     return ret;
2999 }
3000
3001
3002 /***********************************************************************
3003  *              MSG_SendInternalMessageTimeout
3004  *
3005  * Same as SendMessageTimeoutW but sends the message to a specific thread
3006  * without requiring a window handle. Only works for internal Wine messages.
3007  */
3008 LRESULT MSG_SendInternalMessageTimeout( DWORD dest_pid, DWORD dest_tid,
3009                                         UINT msg, WPARAM wparam, LPARAM lparam,
3010                                         UINT flags, UINT timeout, PDWORD_PTR res_ptr )
3011 {
3012     struct send_message_info info;
3013     LRESULT ret, result;
3014
3015     assert( msg & 0x80000000 );  /* must be an internal Wine message */
3016
3017     info.type     = MSG_UNICODE;
3018     info.dest_tid = dest_tid;
3019     info.hwnd     = 0;
3020     info.msg      = msg;
3021     info.wparam   = wparam;
3022     info.lparam   = lparam;
3023     info.flags    = flags;
3024     info.timeout  = timeout;
3025
3026     if (USER_IsExitingThread( dest_tid )) return 0;
3027
3028     if (dest_tid == GetCurrentThreadId())
3029     {
3030         result = handle_internal_message( 0, msg, wparam, lparam );
3031         ret = 1;
3032     }
3033     else
3034     {
3035         if (dest_pid != GetCurrentProcessId()) info.type = MSG_OTHER_PROCESS;
3036         ret = send_inter_thread_message( &info, &result );
3037     }
3038     if (ret && res_ptr) *res_ptr = result;
3039     return ret;
3040 }
3041
3042
3043 /***********************************************************************
3044  *              SendMessageTimeoutW  (USER32.@)
3045  */
3046 LRESULT WINAPI SendMessageTimeoutW( HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam,
3047                                     UINT flags, UINT timeout, PDWORD_PTR res_ptr )
3048 {
3049     struct send_message_info info;
3050
3051     info.type    = MSG_UNICODE;
3052     info.hwnd    = hwnd;
3053     info.msg     = msg;
3054     info.wparam  = wparam;
3055     info.lparam  = lparam;
3056     info.flags   = flags;
3057     info.timeout = timeout;
3058
3059     return send_message( &info, res_ptr, TRUE );
3060 }
3061
3062 /***********************************************************************
3063  *              SendMessageTimeoutA  (USER32.@)
3064  */
3065 LRESULT WINAPI SendMessageTimeoutA( HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam,
3066                                     UINT flags, UINT timeout, PDWORD_PTR res_ptr )
3067 {
3068     struct send_message_info info;
3069
3070     info.type    = MSG_ASCII;
3071     info.hwnd    = hwnd;
3072     info.msg     = msg;
3073     info.wparam  = wparam;
3074     info.lparam  = lparam;
3075     info.flags   = flags;
3076     info.timeout = timeout;
3077     info.wm_char  = WMCHAR_MAP_SENDMESSAGETIMEOUT;
3078
3079     return send_message( &info, res_ptr, FALSE );
3080 }
3081
3082
3083 /***********************************************************************
3084  *              SendMessageW  (USER32.@)
3085  */
3086 LRESULT WINAPI SendMessageW( HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam )
3087 {
3088     DWORD_PTR res = 0;
3089     struct send_message_info info;
3090
3091     info.type    = MSG_UNICODE;
3092     info.hwnd    = hwnd;
3093     info.msg     = msg;
3094     info.wparam  = wparam;
3095     info.lparam  = lparam;
3096     info.flags   = SMTO_NORMAL;
3097     info.timeout = 0;
3098
3099     send_message( &info, &res, TRUE );
3100     return res;
3101 }
3102
3103
3104 /***********************************************************************
3105  *              SendMessageA  (USER32.@)
3106  */
3107 LRESULT WINAPI SendMessageA( HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam )
3108 {
3109     DWORD_PTR res = 0;
3110     struct send_message_info info;
3111
3112     info.type    = MSG_ASCII;
3113     info.hwnd    = hwnd;
3114     info.msg     = msg;
3115     info.wparam  = wparam;
3116     info.lparam  = lparam;
3117     info.flags   = SMTO_NORMAL;
3118     info.timeout = 0;
3119     info.wm_char  = WMCHAR_MAP_SENDMESSAGE;
3120
3121     send_message( &info, &res, FALSE );
3122     return res;
3123 }
3124
3125
3126 /***********************************************************************
3127  *              SendNotifyMessageA  (USER32.@)
3128  */
3129 BOOL WINAPI SendNotifyMessageA( HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam )
3130 {
3131     struct send_message_info info;
3132
3133     if (is_pointer_message(msg))
3134     {
3135         SetLastError( ERROR_MESSAGE_SYNC_ONLY );
3136         return FALSE;
3137     }
3138
3139     info.type    = MSG_NOTIFY;
3140     info.hwnd    = hwnd;
3141     info.msg     = msg;
3142     info.wparam  = wparam;
3143     info.lparam  = lparam;
3144     info.flags   = 0;
3145     info.wm_char = WMCHAR_MAP_SENDMESSAGETIMEOUT;
3146
3147     return send_message( &info, NULL, FALSE );
3148 }
3149
3150
3151 /***********************************************************************
3152  *              SendNotifyMessageW  (USER32.@)
3153  */
3154 BOOL WINAPI SendNotifyMessageW( HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam )
3155 {
3156     struct send_message_info info;
3157
3158     if (is_pointer_message(msg))
3159     {
3160         SetLastError( ERROR_MESSAGE_SYNC_ONLY );
3161         return FALSE;
3162     }
3163
3164     info.type    = MSG_NOTIFY;
3165     info.hwnd    = hwnd;
3166     info.msg     = msg;
3167     info.wparam  = wparam;
3168     info.lparam  = lparam;
3169     info.flags   = 0;
3170
3171     return send_message( &info, NULL, TRUE );
3172 }
3173
3174
3175 /***********************************************************************
3176  *              SendMessageCallbackA  (USER32.@)
3177  */
3178 BOOL WINAPI SendMessageCallbackA( HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam,
3179                                   SENDASYNCPROC callback, ULONG_PTR data )
3180 {
3181     struct send_message_info info;
3182
3183     if (is_pointer_message(msg))
3184     {
3185         SetLastError( ERROR_MESSAGE_SYNC_ONLY );
3186         return FALSE;
3187     }
3188
3189     info.type     = MSG_CALLBACK;
3190     info.hwnd     = hwnd;
3191     info.msg      = msg;
3192     info.wparam   = wparam;
3193     info.lparam   = lparam;
3194     info.callback = callback;
3195     info.data     = data;
3196     info.flags    = 0;
3197     info.wm_char  = WMCHAR_MAP_SENDMESSAGETIMEOUT;
3198
3199     return send_message( &info, NULL, FALSE );
3200 }
3201
3202
3203 /***********************************************************************
3204  *              SendMessageCallbackW  (USER32.@)
3205  */
3206 BOOL WINAPI SendMessageCallbackW( HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam,
3207                                   SENDASYNCPROC callback, ULONG_PTR data )
3208 {
3209     struct send_message_info info;
3210
3211     if (is_pointer_message(msg))
3212     {
3213         SetLastError( ERROR_MESSAGE_SYNC_ONLY );
3214         return FALSE;
3215     }
3216
3217     info.type     = MSG_CALLBACK;
3218     info.hwnd     = hwnd;
3219     info.msg      = msg;
3220     info.wparam   = wparam;
3221     info.lparam   = lparam;
3222     info.callback = callback;
3223     info.data     = data;
3224     info.flags    = 0;
3225
3226     return send_message( &info, NULL, TRUE );
3227 }
3228
3229
3230 /***********************************************************************
3231  *              ReplyMessage  (USER32.@)
3232  */
3233 BOOL WINAPI ReplyMessage( LRESULT result )
3234 {
3235     struct received_message_info *info = get_user_thread_info()->receive_info;
3236
3237     if (!info) return FALSE;
3238     reply_message( info, result, FALSE );
3239     return TRUE;
3240 }
3241
3242
3243 /***********************************************************************
3244  *              InSendMessage  (USER32.@)
3245  */
3246 BOOL WINAPI InSendMessage(void)
3247 {
3248     return (InSendMessageEx(NULL) & (ISMEX_SEND|ISMEX_REPLIED)) == ISMEX_SEND;
3249 }
3250
3251
3252 /***********************************************************************
3253  *              InSendMessageEx  (USER32.@)
3254  */
3255 DWORD WINAPI InSendMessageEx( LPVOID reserved )
3256 {
3257     struct received_message_info *info = get_user_thread_info()->receive_info;
3258
3259     if (info) return info->flags;
3260     return ISMEX_NOSEND;
3261 }
3262
3263
3264 /***********************************************************************
3265  *              PostMessageA  (USER32.@)
3266  */
3267 BOOL WINAPI PostMessageA( HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam )
3268 {
3269     if (!map_wparam_AtoW( msg, &wparam, WMCHAR_MAP_POSTMESSAGE )) return TRUE;
3270     return PostMessageW( hwnd, msg, wparam, lparam );
3271 }
3272
3273
3274 /***********************************************************************
3275  *              PostMessageW  (USER32.@)
3276  */
3277 BOOL WINAPI PostMessageW( HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam )
3278 {
3279     struct send_message_info info;
3280
3281     if (is_pointer_message( msg ))
3282     {
3283         SetLastError( ERROR_MESSAGE_SYNC_ONLY );
3284         return FALSE;
3285     }
3286
3287     TRACE( "hwnd %p msg %x (%s) wp %lx lp %lx\n",
3288            hwnd, msg, SPY_GetMsgName(msg, hwnd), wparam, lparam );
3289
3290     info.type   = MSG_POSTED;
3291     info.hwnd   = hwnd;
3292     info.msg    = msg;
3293     info.wparam = wparam;
3294     info.lparam = lparam;
3295     info.flags  = 0;
3296
3297     if (is_broadcast(hwnd))
3298     {
3299         EnumWindows( broadcast_message_callback, (LPARAM)&info );
3300         return TRUE;
3301     }
3302
3303     if (!hwnd) return PostThreadMessageW( GetCurrentThreadId(), msg, wparam, lparam );
3304
3305     if (!(info.dest_tid = GetWindowThreadProcessId( hwnd, NULL ))) return FALSE;
3306
3307     if (USER_IsExitingThread( info.dest_tid )) return TRUE;
3308
3309     return put_message_in_queue( &info, NULL );
3310 }
3311
3312
3313 /**********************************************************************
3314  *              PostThreadMessageA  (USER32.@)
3315  */
3316 BOOL WINAPI PostThreadMessageA( DWORD thread, UINT msg, WPARAM wparam, LPARAM lparam )
3317 {
3318     if (!map_wparam_AtoW( msg, &wparam, WMCHAR_MAP_POSTMESSAGE )) return TRUE;
3319     return PostThreadMessageW( thread, msg, wparam, lparam );
3320 }
3321
3322
3323 /**********************************************************************
3324  *              PostThreadMessageW  (USER32.@)
3325  */
3326 BOOL WINAPI PostThreadMessageW( DWORD thread, UINT msg, WPARAM wparam, LPARAM lparam )
3327 {
3328     struct send_message_info info;
3329
3330     if (is_pointer_message( msg ))
3331     {
3332         SetLastError( ERROR_MESSAGE_SYNC_ONLY );
3333         return FALSE;
3334     }
3335     if (USER_IsExitingThread( thread )) return TRUE;
3336
3337     info.type     = MSG_POSTED;
3338     info.dest_tid = thread;
3339     info.hwnd     = 0;
3340     info.msg      = msg;
3341     info.wparam   = wparam;
3342     info.lparam   = lparam;
3343     info.flags    = 0;
3344     return put_message_in_queue( &info, NULL );
3345 }
3346
3347
3348 /***********************************************************************
3349  *              PostQuitMessage  (USER32.@)
3350  *
3351  * Posts a quit message to the current thread's message queue.
3352  *
3353  * PARAMS
3354  *  exit_code [I] Exit code to return from message loop.
3355  *
3356  * RETURNS
3357  *  Nothing.
3358  *
3359  * NOTES
3360  *  This function is not the same as calling:
3361  *|PostThreadMessage(GetCurrentThreadId(), WM_QUIT, exit_code, 0);
3362  *  It instead sets a flag in the message queue that signals it to generate
3363  *  a WM_QUIT message when there are no other pending sent or posted messages
3364  *  in the queue.
3365  */
3366 void WINAPI PostQuitMessage( INT exit_code )
3367 {
3368     SERVER_START_REQ( post_quit_message )
3369     {
3370         req->exit_code = exit_code;
3371         wine_server_call( req );
3372     }
3373     SERVER_END_REQ;
3374 }
3375
3376
3377 /***********************************************************************
3378  *              PeekMessageW  (USER32.@)
3379  */
3380 BOOL WINAPI PeekMessageW( MSG *msg_out, HWND hwnd, UINT first, UINT last, UINT flags )
3381 {
3382     MSG msg;
3383
3384     USER_CheckNotLock();
3385
3386     /* check for graphics events */
3387     USER_Driver->pMsgWaitForMultipleObjectsEx( 0, NULL, 0, QS_ALLINPUT, 0 );
3388
3389     if (!peek_message( &msg, hwnd, first, last, flags, 0 ))
3390     {
3391         if (!(flags & PM_NOYIELD)) wow_handlers.wait_message( 0, NULL, 0, 0, 0 );
3392         return FALSE;
3393     }
3394
3395     /* copy back our internal safe copy of message data to msg_out.
3396      * msg_out is a variable from the *program*, so it can't be used
3397      * internally as it can get "corrupted" by our use of SendMessage()
3398      * (back to the program) inside the message handling itself. */
3399     if (!msg_out)
3400     {
3401         SetLastError( ERROR_NOACCESS );
3402         return FALSE;
3403     }
3404     *msg_out = msg;
3405     return TRUE;
3406 }
3407
3408
3409 /***********************************************************************
3410  *              PeekMessageA  (USER32.@)
3411  */
3412 BOOL WINAPI PeekMessageA( MSG *msg, HWND hwnd, UINT first, UINT last, UINT flags )
3413 {
3414     if (get_pending_wmchar( msg, first, last, (flags & PM_REMOVE) )) return TRUE;
3415     if (!PeekMessageW( msg, hwnd, first, last, flags )) return FALSE;
3416     map_wparam_WtoA( msg, (flags & PM_REMOVE) );
3417     return TRUE;
3418 }
3419
3420
3421 /***********************************************************************
3422  *              GetMessageW  (USER32.@)
3423  */
3424 BOOL WINAPI GetMessageW( MSG *msg, HWND hwnd, UINT first, UINT last )
3425 {
3426     HANDLE server_queue = get_server_queue_handle();
3427     unsigned int mask = QS_POSTMESSAGE | QS_SENDMESSAGE;  /* Always selected */
3428
3429     USER_CheckNotLock();
3430
3431     /* check for graphics events */
3432     USER_Driver->pMsgWaitForMultipleObjectsEx( 0, NULL, 0, QS_ALLINPUT, 0 );
3433
3434     if (first || last)
3435     {
3436         if ((first <= WM_KEYLAST) && (last >= WM_KEYFIRST)) mask |= QS_KEY;
3437         if ( ((first <= WM_MOUSELAST) && (last >= WM_MOUSEFIRST)) ||
3438              ((first <= WM_NCMOUSELAST) && (last >= WM_NCMOUSEFIRST)) ) mask |= QS_MOUSE;
3439         if ((first <= WM_TIMER) && (last >= WM_TIMER)) mask |= QS_TIMER;
3440         if ((first <= WM_SYSTIMER) && (last >= WM_SYSTIMER)) mask |= QS_TIMER;
3441         if ((first <= WM_PAINT) && (last >= WM_PAINT)) mask |= QS_PAINT;
3442     }
3443     else mask = QS_ALLINPUT;
3444
3445     while (!peek_message( msg, hwnd, first, last, PM_REMOVE | (mask << 16), mask ))
3446     {
3447         wow_handlers.wait_message( 1, &server_queue, INFINITE, mask, 0 );
3448     }
3449
3450     return (msg->message != WM_QUIT);
3451 }
3452
3453
3454 /***********************************************************************
3455  *              GetMessageA  (USER32.@)
3456  */
3457 BOOL WINAPI GetMessageA( MSG *msg, HWND hwnd, UINT first, UINT last )
3458 {
3459     if (get_pending_wmchar( msg, first, last, TRUE )) return TRUE;
3460     GetMessageW( msg, hwnd, first, last );
3461     map_wparam_WtoA( msg, TRUE );
3462     return (msg->message != WM_QUIT);
3463 }
3464
3465
3466 /***********************************************************************
3467  *              IsDialogMessageA (USER32.@)
3468  *              IsDialogMessage  (USER32.@)
3469  */
3470 BOOL WINAPI IsDialogMessageA( HWND hwndDlg, LPMSG pmsg )
3471 {
3472     MSG msg = *pmsg;
3473     map_wparam_AtoW( msg.message, &msg.wParam, WMCHAR_MAP_NOMAPPING );
3474     return IsDialogMessageW( hwndDlg, &msg );
3475 }
3476
3477
3478 /***********************************************************************
3479  *              TranslateMessage (USER32.@)
3480  *
3481  * Implementation of TranslateMessage.
3482  *
3483  * TranslateMessage translates virtual-key messages into character-messages,
3484  * as follows :
3485  * WM_KEYDOWN/WM_KEYUP combinations produce a WM_CHAR or WM_DEADCHAR message.
3486  * ditto replacing WM_* with WM_SYS*
3487  * This produces WM_CHAR messages only for keys mapped to ASCII characters
3488  * by the keyboard driver.
3489  *
3490  * If the message is WM_KEYDOWN, WM_KEYUP, WM_SYSKEYDOWN, or WM_SYSKEYUP, the
3491  * return value is nonzero, regardless of the translation.
3492  *
3493  */
3494 BOOL WINAPI TranslateMessage( const MSG *msg )
3495 {
3496     UINT message;
3497     WCHAR wp[2];
3498     BYTE state[256];
3499
3500     if (msg->message < WM_KEYFIRST || msg->message > WM_KEYLAST) return FALSE;
3501     if (msg->message != WM_KEYDOWN && msg->message != WM_SYSKEYDOWN) return TRUE;
3502
3503     TRACE_(key)("Translating key %s (%04lX), scancode %04x\n",
3504                 SPY_GetVKeyName(msg->wParam), msg->wParam, HIWORD(msg->lParam));
3505
3506     switch (msg->wParam)
3507     {
3508     case VK_PACKET:
3509         message = (msg->message == WM_KEYDOWN) ? WM_CHAR : WM_SYSCHAR;
3510         TRACE_(key)("PostMessageW(%p,%s,%04x,%08x)\n",
3511                     msg->hwnd, SPY_GetMsgName(message, msg->hwnd), HIWORD(msg->lParam), LOWORD(msg->lParam));
3512         PostMessageW( msg->hwnd, message, HIWORD(msg->lParam), LOWORD(msg->lParam));
3513         return TRUE;
3514
3515     case VK_PROCESSKEY:
3516         return ImmTranslateMessage(msg->hwnd, msg->message, msg->wParam, msg->lParam);
3517     }
3518
3519     GetKeyboardState( state );
3520     /* FIXME : should handle ToUnicode yielding 2 */
3521     switch (ToUnicode(msg->wParam, HIWORD(msg->lParam), state, wp, 2, 0))
3522     {
3523     case 1:
3524         message = (msg->message == WM_KEYDOWN) ? WM_CHAR : WM_SYSCHAR;
3525         TRACE_(key)("1 -> PostMessageW(%p,%s,%04x,%08lx)\n",
3526             msg->hwnd, SPY_GetMsgName(message, msg->hwnd), wp[0], msg->lParam);
3527         PostMessageW( msg->hwnd, message, wp[0], msg->lParam );
3528         break;
3529
3530     case -1:
3531         message = (msg->message == WM_KEYDOWN) ? WM_DEADCHAR : WM_SYSDEADCHAR;
3532         TRACE_(key)("-1 -> PostMessageW(%p,%s,%04x,%08lx)\n",
3533             msg->hwnd, SPY_GetMsgName(message, msg->hwnd), wp[0], msg->lParam);
3534         PostMessageW( msg->hwnd, message, wp[0], msg->lParam );
3535         break;
3536     }
3537     return TRUE;
3538 }
3539
3540
3541 /***********************************************************************
3542  *              DispatchMessageA (USER32.@)
3543  *
3544  * See DispatchMessageW.
3545  */
3546 LRESULT WINAPI DECLSPEC_HOTPATCH DispatchMessageA( const MSG* msg )
3547 {
3548     LRESULT retval;
3549
3550       /* Process timer messages */
3551     if ((msg->message == WM_TIMER) || (msg->message == WM_SYSTIMER))
3552     {
3553         if (msg->lParam)
3554         {
3555             __TRY
3556             {
3557                 retval = CallWindowProcA( (WNDPROC)msg->lParam, msg->hwnd,
3558                                           msg->message, msg->wParam, GetTickCount() );
3559             }
3560             __EXCEPT_PAGE_FAULT
3561             {
3562                 retval = 0;
3563             }
3564             __ENDTRY
3565             return retval;
3566         }
3567     }
3568     if (!msg->hwnd) return 0;
3569
3570     SPY_EnterMessage( SPY_DISPATCHMESSAGE, msg->hwnd, msg->message,
3571                       msg->wParam, msg->lParam );
3572
3573     if (!WINPROC_call_window( msg->hwnd, msg->message, msg->wParam, msg->lParam,
3574                               &retval, FALSE, WMCHAR_MAP_DISPATCHMESSAGE ))
3575     {
3576         if (!IsWindow( msg->hwnd )) SetLastError( ERROR_INVALID_WINDOW_HANDLE );
3577         else SetLastError( ERROR_MESSAGE_SYNC_ONLY );
3578         retval = 0;
3579     }
3580
3581     SPY_ExitMessage( SPY_RESULT_OK, msg->hwnd, msg->message, retval,
3582                      msg->wParam, msg->lParam );
3583
3584     if (msg->message == WM_PAINT)
3585     {
3586         /* send a WM_NCPAINT and WM_ERASEBKGND if the non-client area is still invalid */
3587         HRGN hrgn = CreateRectRgn( 0, 0, 0, 0 );
3588         GetUpdateRgn( msg->hwnd, hrgn, TRUE );
3589         DeleteObject( hrgn );
3590     }
3591     return retval;
3592 }
3593
3594
3595 /***********************************************************************
3596  *              DispatchMessageW (USER32.@) Process a message
3597  *
3598  * Process the message specified in the structure *_msg_.
3599  *
3600  * If the lpMsg parameter points to a WM_TIMER message and the
3601  * parameter of the WM_TIMER message is not NULL, the lParam parameter
3602  * points to the function that is called instead of the window
3603  * procedure. The function stored in lParam (timer callback) is protected
3604  * from causing page-faults.
3605  *
3606  * The message must be valid.
3607  *
3608  * RETURNS
3609  *
3610  *   DispatchMessage() returns the result of the window procedure invoked.
3611  *
3612  * CONFORMANCE
3613  *
3614  *   ECMA-234, Win32
3615  *
3616  */
3617 LRESULT WINAPI DECLSPEC_HOTPATCH DispatchMessageW( const MSG* msg )
3618 {
3619     LRESULT retval;
3620
3621       /* Process timer messages */
3622     if ((msg->message == WM_TIMER) || (msg->message == WM_SYSTIMER))
3623     {
3624         if (msg->lParam)
3625         {
3626             __TRY
3627             {
3628                 retval = CallWindowProcW( (WNDPROC)msg->lParam, msg->hwnd,
3629                                           msg->message, msg->wParam, GetTickCount() );
3630             }
3631             __EXCEPT_PAGE_FAULT
3632             {
3633                 retval = 0;
3634             }
3635             __ENDTRY
3636             return retval;
3637         }
3638     }
3639     if (!msg->hwnd) return 0;
3640
3641     SPY_EnterMessage( SPY_DISPATCHMESSAGE, msg->hwnd, msg->message,
3642                       msg->wParam, msg->lParam );
3643
3644     if (!WINPROC_call_window( msg->hwnd, msg->message, msg->wParam, msg->lParam,
3645                               &retval, TRUE, WMCHAR_MAP_DISPATCHMESSAGE ))
3646     {
3647         if (!IsWindow( msg->hwnd )) SetLastError( ERROR_INVALID_WINDOW_HANDLE );
3648         else SetLastError( ERROR_MESSAGE_SYNC_ONLY );
3649         retval = 0;
3650     }
3651
3652     SPY_ExitMessage( SPY_RESULT_OK, msg->hwnd, msg->message, retval,
3653                      msg->wParam, msg->lParam );
3654
3655     if (msg->message == WM_PAINT)
3656     {
3657         /* send a WM_NCPAINT and WM_ERASEBKGND if the non-client area is still invalid */
3658         HRGN hrgn = CreateRectRgn( 0, 0, 0, 0 );
3659         GetUpdateRgn( msg->hwnd, hrgn, TRUE );
3660         DeleteObject( hrgn );
3661     }
3662     return retval;
3663 }
3664
3665
3666 /***********************************************************************
3667  *              GetMessagePos (USER.119)
3668  *              GetMessagePos (USER32.@)
3669  *
3670  * The GetMessagePos() function returns a long value representing a
3671  * cursor position, in screen coordinates, when the last message
3672  * retrieved by the GetMessage() function occurs. The x-coordinate is
3673  * in the low-order word of the return value, the y-coordinate is in
3674  * the high-order word. The application can use the MAKEPOINT()
3675  * macro to obtain a POINT structure from the return value.
3676  *
3677  * For the current cursor position, use GetCursorPos().
3678  *
3679  * RETURNS
3680  *
3681  * Cursor position of last message on success, zero on failure.
3682  *
3683  * CONFORMANCE
3684  *
3685  * ECMA-234, Win32
3686  *
3687  */
3688 DWORD WINAPI GetMessagePos(void)
3689 {
3690     return get_user_thread_info()->GetMessagePosVal;
3691 }
3692
3693
3694 /***********************************************************************
3695  *              GetMessageTime (USER.120)
3696  *              GetMessageTime (USER32.@)
3697  *
3698  * GetMessageTime() returns the message time for the last message
3699  * retrieved by the function. The time is measured in milliseconds with
3700  * the same offset as GetTickCount().
3701  *
3702  * Since the tick count wraps, this is only useful for moderately short
3703  * relative time comparisons.
3704  *
3705  * RETURNS
3706  *
3707  * Time of last message on success, zero on failure.
3708  */
3709 LONG WINAPI GetMessageTime(void)
3710 {
3711     return get_user_thread_info()->GetMessageTimeVal;
3712 }
3713
3714
3715 /***********************************************************************
3716  *              GetMessageExtraInfo (USER.288)
3717  *              GetMessageExtraInfo (USER32.@)
3718  */
3719 LPARAM WINAPI GetMessageExtraInfo(void)
3720 {
3721     return get_user_thread_info()->GetMessageExtraInfoVal;
3722 }
3723
3724
3725 /***********************************************************************
3726  *              SetMessageExtraInfo (USER32.@)
3727  */
3728 LPARAM WINAPI SetMessageExtraInfo(LPARAM lParam)
3729 {
3730     struct user_thread_info *thread_info = get_user_thread_info();
3731     LONG old_value = thread_info->GetMessageExtraInfoVal;
3732     thread_info->GetMessageExtraInfoVal = lParam;
3733     return old_value;
3734 }
3735
3736
3737 /***********************************************************************
3738  *              WaitMessage (USER.112) Suspend thread pending messages
3739  *              WaitMessage (USER32.@) Suspend thread pending messages
3740  *
3741  * WaitMessage() suspends a thread until events appear in the thread's
3742  * queue.
3743  */
3744 BOOL WINAPI WaitMessage(void)
3745 {
3746     return (MsgWaitForMultipleObjectsEx( 0, NULL, INFINITE, QS_ALLINPUT, 0 ) != WAIT_FAILED);
3747 }
3748
3749
3750 /***********************************************************************
3751  *              MsgWaitForMultipleObjectsEx   (USER32.@)
3752  */
3753 DWORD WINAPI MsgWaitForMultipleObjectsEx( DWORD count, CONST HANDLE *pHandles,
3754                                           DWORD timeout, DWORD mask, DWORD flags )
3755 {
3756     HANDLE handles[MAXIMUM_WAIT_OBJECTS];
3757     DWORD i;
3758
3759     if (count > MAXIMUM_WAIT_OBJECTS-1)
3760     {
3761         SetLastError( ERROR_INVALID_PARAMETER );
3762         return WAIT_FAILED;
3763     }
3764
3765     /* set the queue mask */
3766     SERVER_START_REQ( set_queue_mask )
3767     {
3768         req->wake_mask    = (flags & MWMO_INPUTAVAILABLE) ? mask : 0;
3769         req->changed_mask = mask;
3770         req->skip_wait    = 0;
3771         wine_server_call( req );
3772     }
3773     SERVER_END_REQ;
3774
3775     /* add the queue to the handle list */
3776     for (i = 0; i < count; i++) handles[i] = pHandles[i];
3777     handles[count] = get_server_queue_handle();
3778
3779     return wow_handlers.wait_message( count+1, handles, timeout, mask, flags );
3780 }
3781
3782
3783 /***********************************************************************
3784  *              MsgWaitForMultipleObjects (USER32.@)
3785  */
3786 DWORD WINAPI MsgWaitForMultipleObjects( DWORD count, CONST HANDLE *handles,
3787                                         BOOL wait_all, DWORD timeout, DWORD mask )
3788 {
3789     return MsgWaitForMultipleObjectsEx( count, handles, timeout, mask,
3790                                         wait_all ? MWMO_WAITALL : 0 );
3791 }
3792
3793
3794 /***********************************************************************
3795  *              WaitForInputIdle (USER32.@)
3796  */
3797 DWORD WINAPI WaitForInputIdle( HANDLE hProcess, DWORD dwTimeOut )
3798 {
3799     DWORD start_time, elapsed, ret;
3800     HANDLE handles[2];
3801
3802     handles[0] = hProcess;
3803     SERVER_START_REQ( get_process_idle_event )
3804     {
3805         req->handle = wine_server_obj_handle( hProcess );
3806         wine_server_call_err( req );
3807         handles[1] = wine_server_ptr_handle( reply->event );
3808     }
3809     SERVER_END_REQ;
3810     if (!handles[1]) return WAIT_FAILED;  /* no event to wait on */
3811
3812     start_time = GetTickCount();
3813     elapsed = 0;
3814
3815     TRACE("waiting for %p\n", handles[1] );
3816     do
3817     {
3818         ret = MsgWaitForMultipleObjects ( 2, handles, FALSE, dwTimeOut - elapsed, QS_SENDMESSAGE );
3819         switch (ret)
3820         {
3821         case WAIT_OBJECT_0:
3822             return 0;
3823         case WAIT_OBJECT_0+2:
3824             process_sent_messages();
3825             break;
3826         case WAIT_TIMEOUT:
3827         case WAIT_FAILED:
3828             TRACE("timeout or error\n");
3829             return ret;
3830         default:
3831             TRACE("finished\n");
3832             return 0;
3833         }
3834         if (dwTimeOut != INFINITE)
3835         {
3836             elapsed = GetTickCount() - start_time;
3837             if (elapsed > dwTimeOut)
3838                 break;
3839         }
3840     }
3841     while (1);
3842
3843     return WAIT_TIMEOUT;
3844 }
3845
3846
3847 /***********************************************************************
3848  *              RegisterWindowMessageA (USER32.@)
3849  *              RegisterWindowMessage (USER.118)
3850  */
3851 UINT WINAPI RegisterWindowMessageA( LPCSTR str )
3852 {
3853     UINT ret = GlobalAddAtomA(str);
3854     TRACE("%s, ret=%x\n", str, ret);
3855     return ret;
3856 }
3857
3858
3859 /***********************************************************************
3860  *              RegisterWindowMessageW (USER32.@)
3861  */
3862 UINT WINAPI RegisterWindowMessageW( LPCWSTR str )
3863 {
3864     UINT ret = GlobalAddAtomW(str);
3865     TRACE("%s ret=%x\n", debugstr_w(str), ret);
3866     return ret;
3867 }
3868
3869 typedef struct BroadcastParm
3870 {
3871     DWORD flags;
3872     LPDWORD recipients;
3873     UINT msg;
3874     WPARAM wp;
3875     LPARAM lp;
3876     DWORD success;
3877     HWINSTA winsta;
3878 } BroadcastParm;
3879
3880 static BOOL CALLBACK bcast_childwindow( HWND hw, LPARAM lp )
3881 {
3882     BroadcastParm *parm = (BroadcastParm*)lp;
3883     DWORD_PTR retval = 0;
3884     LRESULT lresult;
3885
3886     if (parm->flags & BSF_IGNORECURRENTTASK && WIN_IsCurrentProcess(hw))
3887     {
3888         TRACE("Not telling myself %p\n", hw);
3889         return TRUE;
3890     }
3891
3892     /* I don't know 100% for sure if this is what Windows does, but it fits the tests */
3893     if (parm->flags & BSF_QUERY)
3894     {
3895         TRACE("Telling window %p using SendMessageTimeout\n", hw);
3896
3897         /* Not tested for conflicting flags */
3898         if (parm->flags & BSF_FORCEIFHUNG || parm->flags & BSF_NOHANG)
3899             lresult = SendMessageTimeoutW( hw, parm->msg, parm->wp, parm->lp, SMTO_ABORTIFHUNG, 2000, &retval );
3900         else if (parm->flags & BSF_NOTIMEOUTIFNOTHUNG)
3901             lresult = SendMessageTimeoutW( hw, parm->msg, parm->wp, parm->lp, SMTO_NOTIMEOUTIFNOTHUNG, 2000, &retval );
3902         else
3903             lresult = SendMessageTimeoutW( hw, parm->msg, parm->wp, parm->lp, SMTO_NORMAL, 2000, &retval );
3904
3905         if (!lresult && GetLastError() == ERROR_TIMEOUT)
3906         {
3907             WARN("Timed out!\n");
3908             if (!(parm->flags & BSF_FORCEIFHUNG))
3909                 goto fail;
3910         }
3911         if (retval == BROADCAST_QUERY_DENY)
3912             goto fail;
3913
3914         return TRUE;
3915
3916 fail:
3917         parm->success = 0;
3918         return FALSE;
3919     }
3920     else if (parm->flags & BSF_POSTMESSAGE)
3921     {
3922         TRACE("Telling window %p using PostMessage\n", hw);
3923         PostMessageW( hw, parm->msg, parm->wp, parm->lp );
3924     }
3925     else
3926     {
3927         TRACE("Telling window %p using SendNotifyMessage\n", hw);
3928         SendNotifyMessageW( hw, parm->msg, parm->wp, parm->lp );
3929     }
3930
3931     return TRUE;
3932 }
3933
3934 static BOOL CALLBACK bcast_desktop( LPWSTR desktop, LPARAM lp )
3935 {
3936     BOOL ret;
3937     HDESK hdesktop;
3938     BroadcastParm *parm = (BroadcastParm*)lp;
3939
3940     TRACE("desktop: %s\n", debugstr_w( desktop ));
3941
3942     hdesktop = open_winstation_desktop( parm->winsta, desktop, 0, FALSE, DESKTOP_ENUMERATE|DESKTOP_WRITEOBJECTS|STANDARD_RIGHTS_WRITE );
3943     if (!hdesktop)
3944     {
3945         FIXME("Could not open desktop %s\n", debugstr_w(desktop));
3946         return TRUE;
3947     }
3948
3949     ret = EnumDesktopWindows( hdesktop, bcast_childwindow, lp );
3950     CloseDesktop(hdesktop);
3951     TRACE("-->%d\n", ret);
3952     return parm->success;
3953 }
3954
3955 static BOOL CALLBACK bcast_winsta( LPWSTR winsta, LPARAM lp )
3956 {
3957     BOOL ret;
3958     HWINSTA hwinsta = OpenWindowStationW( winsta, FALSE, WINSTA_ENUMDESKTOPS );
3959     TRACE("hwinsta: %p/%s/%08x\n", hwinsta, debugstr_w( winsta ), GetLastError());
3960     if (!hwinsta)
3961         return TRUE;
3962     ((BroadcastParm *)lp)->winsta = hwinsta;
3963     ret = EnumDesktopsW( hwinsta, bcast_desktop, lp );
3964     CloseWindowStation( hwinsta );
3965     TRACE("-->%d\n", ret);
3966     return ret;
3967 }
3968
3969 /***********************************************************************
3970  *              BroadcastSystemMessageA (USER32.@)
3971  *              BroadcastSystemMessage  (USER32.@)
3972  */
3973 LONG WINAPI BroadcastSystemMessageA( DWORD flags, LPDWORD recipients, UINT msg, WPARAM wp, LPARAM lp )
3974 {
3975     return BroadcastSystemMessageExA( flags, recipients, msg, wp, lp, NULL );
3976 }
3977
3978
3979 /***********************************************************************
3980  *              BroadcastSystemMessageW (USER32.@)
3981  */
3982 LONG WINAPI BroadcastSystemMessageW( DWORD flags, LPDWORD recipients, UINT msg, WPARAM wp, LPARAM lp )
3983 {
3984     return BroadcastSystemMessageExW( flags, recipients, msg, wp, lp, NULL );
3985 }
3986
3987 /***********************************************************************
3988  *              BroadcastSystemMessageExA (USER32.@)
3989  */
3990 LONG WINAPI BroadcastSystemMessageExA( DWORD flags, LPDWORD recipients, UINT msg, WPARAM wp, LPARAM lp, PBSMINFO pinfo )
3991 {
3992     map_wparam_AtoW( msg, &wp, WMCHAR_MAP_NOMAPPING );
3993     return BroadcastSystemMessageExW( flags, recipients, msg, wp, lp, NULL );
3994 }
3995
3996
3997 /***********************************************************************
3998  *              BroadcastSystemMessageExW (USER32.@)
3999  */
4000 LONG WINAPI BroadcastSystemMessageExW( DWORD flags, LPDWORD recipients, UINT msg, WPARAM wp, LPARAM lp, PBSMINFO pinfo )
4001 {
4002     BroadcastParm parm;
4003     DWORD recips = BSM_ALLCOMPONENTS;
4004     BOOL ret = TRUE;
4005     static const DWORD all_flags = ( BSF_QUERY | BSF_IGNORECURRENTTASK | BSF_FLUSHDISK | BSF_NOHANG
4006                                    | BSF_POSTMESSAGE | BSF_FORCEIFHUNG | BSF_NOTIMEOUTIFNOTHUNG
4007                                    | BSF_ALLOWSFW | BSF_SENDNOTIFYMESSAGE | BSF_RETURNHDESK | BSF_LUID );
4008
4009     TRACE("Flags: %08x, recipients: %p(0x%x), msg: %04x, wparam: %08lx, lparam: %08lx\n", flags, recipients,
4010          (recipients ? *recipients : recips), msg, wp, lp);
4011
4012     if (flags & ~all_flags)
4013     {
4014         SetLastError(ERROR_INVALID_PARAMETER);
4015         return 0;
4016     }
4017
4018     if (!recipients)
4019         recipients = &recips;
4020
4021     if ( pinfo && flags & BSF_QUERY )
4022         FIXME("Not returning PBSMINFO information yet\n");
4023
4024     parm.flags = flags;
4025     parm.recipients = recipients;
4026     parm.msg = msg;
4027     parm.wp = wp;
4028     parm.lp = lp;
4029     parm.success = TRUE;
4030
4031     if (*recipients & BSM_ALLDESKTOPS || *recipients == BSM_ALLCOMPONENTS)
4032         ret = EnumWindowStationsW(bcast_winsta, (LONG_PTR)&parm);
4033     else if (*recipients & BSM_APPLICATIONS)
4034     {
4035         EnumWindows(bcast_childwindow, (LONG_PTR)&parm);
4036         ret = parm.success;
4037     }
4038     else
4039         FIXME("Recipients %08x not supported!\n", *recipients);
4040
4041     return ret;
4042 }
4043
4044 /***********************************************************************
4045  *              SetMessageQueue (USER32.@)
4046  */
4047 BOOL WINAPI SetMessageQueue( INT size )
4048 {
4049     /* now obsolete the message queue will be expanded dynamically as necessary */
4050     return TRUE;
4051 }
4052
4053
4054 /***********************************************************************
4055  *              MessageBeep (USER32.@)
4056  */
4057 BOOL WINAPI MessageBeep( UINT i )
4058 {
4059     BOOL active = TRUE;
4060     SystemParametersInfoA( SPI_GETBEEP, 0, &active, FALSE );
4061     if (active) USER_Driver->pBeep();
4062     return TRUE;
4063 }
4064
4065
4066 /***********************************************************************
4067  *              SetTimer (USER32.@)
4068  */
4069 UINT_PTR WINAPI SetTimer( HWND hwnd, UINT_PTR id, UINT timeout, TIMERPROC proc )
4070 {
4071     UINT_PTR ret;
4072     WNDPROC winproc = 0;
4073
4074     if (proc) winproc = WINPROC_AllocProc( (WNDPROC)proc, FALSE );
4075
4076     SERVER_START_REQ( set_win_timer )
4077     {
4078         req->win    = wine_server_user_handle( hwnd );
4079         req->msg    = WM_TIMER;
4080         req->id     = id;
4081         req->rate   = max( timeout, SYS_TIMER_RATE );
4082         req->lparam = (ULONG_PTR)winproc;
4083         if (!wine_server_call_err( req ))
4084         {
4085             ret = reply->id;
4086             if (!ret) ret = TRUE;
4087         }
4088         else ret = 0;
4089     }
4090     SERVER_END_REQ;
4091
4092     TRACE("Added %p %lx %p timeout %d\n", hwnd, id, winproc, timeout );
4093     return ret;
4094 }
4095
4096
4097 /***********************************************************************
4098  *              SetSystemTimer (USER32.@)
4099  */
4100 UINT_PTR WINAPI SetSystemTimer( HWND hwnd, UINT_PTR id, UINT timeout, TIMERPROC proc )
4101 {
4102     UINT_PTR ret;
4103     WNDPROC winproc = 0;
4104
4105     if (proc) winproc = WINPROC_AllocProc( (WNDPROC)proc, FALSE );
4106
4107     SERVER_START_REQ( set_win_timer )
4108     {
4109         req->win    = wine_server_user_handle( hwnd );
4110         req->msg    = WM_SYSTIMER;
4111         req->id     = id;
4112         req->rate   = max( timeout, SYS_TIMER_RATE );
4113         req->lparam = (ULONG_PTR)winproc;
4114         if (!wine_server_call_err( req ))
4115         {
4116             ret = reply->id;
4117             if (!ret) ret = TRUE;
4118         }
4119         else ret = 0;
4120     }
4121     SERVER_END_REQ;
4122
4123     TRACE("Added %p %lx %p timeout %d\n", hwnd, id, winproc, timeout );
4124     return ret;
4125 }
4126
4127
4128 /***********************************************************************
4129  *              KillTimer (USER32.@)
4130  */
4131 BOOL WINAPI KillTimer( HWND hwnd, UINT_PTR id )
4132 {
4133     BOOL ret;
4134
4135     SERVER_START_REQ( kill_win_timer )
4136     {
4137         req->win = wine_server_user_handle( hwnd );
4138         req->msg = WM_TIMER;
4139         req->id  = id;
4140         ret = !wine_server_call_err( req );
4141     }
4142     SERVER_END_REQ;
4143     return ret;
4144 }
4145
4146
4147 /***********************************************************************
4148  *              KillSystemTimer (USER32.@)
4149  */
4150 BOOL WINAPI KillSystemTimer( HWND hwnd, UINT_PTR id )
4151 {
4152     BOOL ret;
4153
4154     SERVER_START_REQ( kill_win_timer )
4155     {
4156         req->win = wine_server_user_handle( hwnd );
4157         req->msg = WM_SYSTIMER;
4158         req->id  = id;
4159         ret = !wine_server_call_err( req );
4160     }
4161     SERVER_END_REQ;
4162     return ret;
4163 }
4164
4165
4166 /**********************************************************************
4167  *              GetGUIThreadInfo  (USER32.@)
4168  */
4169 BOOL WINAPI GetGUIThreadInfo( DWORD id, GUITHREADINFO *info )
4170 {
4171     BOOL ret;
4172
4173     SERVER_START_REQ( get_thread_input )
4174     {
4175         req->tid = id;
4176         if ((ret = !wine_server_call_err( req )))
4177         {
4178             info->flags          = 0;
4179             info->hwndActive     = wine_server_ptr_handle( reply->active );
4180             info->hwndFocus      = wine_server_ptr_handle( reply->focus );
4181             info->hwndCapture    = wine_server_ptr_handle( reply->capture );
4182             info->hwndMenuOwner  = wine_server_ptr_handle( reply->menu_owner );
4183             info->hwndMoveSize   = wine_server_ptr_handle( reply->move_size );
4184             info->hwndCaret      = wine_server_ptr_handle( reply->caret );
4185             info->rcCaret.left   = reply->rect.left;
4186             info->rcCaret.top    = reply->rect.top;
4187             info->rcCaret.right  = reply->rect.right;
4188             info->rcCaret.bottom = reply->rect.bottom;
4189             if (reply->menu_owner) info->flags |= GUI_INMENUMODE;
4190             if (reply->move_size) info->flags |= GUI_INMOVESIZE;
4191             if (reply->caret) info->flags |= GUI_CARETBLINKING;
4192         }
4193     }
4194     SERVER_END_REQ;
4195     return ret;
4196 }
4197
4198
4199 /******************************************************************
4200  *              IsHungAppWindow (USER32.@)
4201  *
4202  */
4203 BOOL WINAPI IsHungAppWindow( HWND hWnd )
4204 {
4205     BOOL ret;
4206
4207     SERVER_START_REQ( is_window_hung )
4208     {
4209         req->win = wine_server_user_handle( hWnd );
4210         ret = !wine_server_call_err( req ) && reply->is_hung;
4211     }
4212     SERVER_END_REQ;
4213     return ret;
4214 }
4215
4216 /******************************************************************
4217  *      ChangeWindowMessageFilter (USER32.@)
4218  */
4219 BOOL WINAPI ChangeWindowMessageFilter( UINT message, DWORD flag )
4220 {
4221     FIXME( "%x %08x\n", message, flag );
4222     return TRUE;
4223 }