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