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