user32: Pack the MSG structure in messages to allow crossing 32/64 boundaries.
[wine/multimedia.git] / dlls / user32 / message.c
blob5bee54b04e214d978f02804f8adf8d1a71833eb5
1 /*
2 * Window messaging support
4 * Copyright 2001 Alexandre Julliard
5 * Copyright 2008 Maarten Lankhorst
7 * This library is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU Lesser General Public
9 * License as published by the Free Software Foundation; either
10 * version 2.1 of the License, or (at your option) any later version.
12 * This library is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Lesser General Public License for more details.
17 * You should have received a copy of the GNU Lesser General Public
18 * License along with this library; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
22 #include "config.h"
23 #include "wine/port.h"
25 #include <assert.h>
26 #include <stdarg.h>
28 #include "ntstatus.h"
29 #define WIN32_NO_STATUS
30 #include "windef.h"
31 #include "winbase.h"
32 #include "wingdi.h"
33 #include "winuser.h"
34 #include "winerror.h"
35 #include "winnls.h"
36 #include "dbt.h"
37 #include "dde.h"
38 #include "imm.h"
39 #include "ddk/imm.h"
40 #include "wine/unicode.h"
41 #include "wine/server.h"
42 #include "user_private.h"
43 #include "win.h"
44 #include "controls.h"
45 #include "wine/debug.h"
46 #include "wine/exception.h"
48 WINE_DEFAULT_DEBUG_CHANNEL(msg);
49 WINE_DECLARE_DEBUG_CHANNEL(relay);
50 WINE_DECLARE_DEBUG_CHANNEL(key);
52 #define WM_NCMOUSEFIRST WM_NCMOUSEMOVE
53 #define WM_NCMOUSELAST (WM_NCMOUSEFIRST+(WM_MOUSELAST-WM_MOUSEFIRST))
55 #define MAX_PACK_COUNT 4
57 #define SYS_TIMER_RATE 55 /* min. timer rate in ms (actually 54.925)*/
59 /* the various structures that can be sent in messages, in platform-independent layout */
60 struct packed_CREATESTRUCTW
62 ULONGLONG lpCreateParams;
63 ULONGLONG hInstance;
64 user_handle_t hMenu;
65 DWORD __pad1;
66 user_handle_t hwndParent;
67 DWORD __pad2;
68 INT cy;
69 INT cx;
70 INT y;
71 INT x;
72 LONG style;
73 ULONGLONG lpszName;
74 ULONGLONG lpszClass;
75 DWORD dwExStyle;
76 DWORD __pad3;
79 struct packed_DRAWITEMSTRUCT
81 UINT CtlType;
82 UINT CtlID;
83 UINT itemID;
84 UINT itemAction;
85 UINT itemState;
86 user_handle_t hwndItem;
87 DWORD __pad1;
88 user_handle_t hDC;
89 DWORD __pad2;
90 RECT rcItem;
91 ULONGLONG itemData;
94 struct packed_MEASUREITEMSTRUCT
96 UINT CtlType;
97 UINT CtlID;
98 UINT itemID;
99 UINT itemWidth;
100 UINT itemHeight;
101 ULONGLONG itemData;
104 struct packed_DELETEITEMSTRUCT
106 UINT CtlType;
107 UINT CtlID;
108 UINT itemID;
109 user_handle_t hwndItem;
110 DWORD __pad;
111 ULONGLONG itemData;
114 struct packed_COMPAREITEMSTRUCT
116 UINT CtlType;
117 UINT CtlID;
118 user_handle_t hwndItem;
119 DWORD __pad1;
120 UINT itemID1;
121 ULONGLONG itemData1;
122 UINT itemID2;
123 ULONGLONG itemData2;
124 DWORD dwLocaleId;
125 DWORD __pad2;
128 struct packed_WINDOWPOS
130 user_handle_t hwnd;
131 DWORD __pad1;
132 user_handle_t hwndInsertAfter;
133 DWORD __pad2;
134 INT x;
135 INT y;
136 INT cx;
137 INT cy;
138 UINT flags;
139 DWORD __pad3;
142 struct packed_COPYDATASTRUCT
144 ULONGLONG dwData;
145 DWORD cbData;
146 ULONGLONG lpData;
149 struct packed_HELPINFO
151 UINT cbSize;
152 INT iContextType;
153 INT iCtrlId;
154 user_handle_t hItemHandle;
155 DWORD __pad;
156 ULONGLONG dwContextId;
157 POINT MousePos;
160 struct packed_NCCALCSIZE_PARAMS
162 RECT rgrc[3];
163 ULONGLONG __pad1;
164 user_handle_t hwnd;
165 DWORD __pad2;
166 user_handle_t hwndInsertAfter;
167 DWORD __pad3;
168 INT x;
169 INT y;
170 INT cx;
171 INT cy;
172 UINT flags;
173 DWORD __pad4;
176 struct packed_MSG
178 user_handle_t hwnd;
179 DWORD __pad1;
180 UINT message;
181 ULONGLONG wParam;
182 ULONGLONG lParam;
183 DWORD time;
184 POINT pt;
185 DWORD __pad2;
188 /* the structures are unpacked on top of the packed ones, so make sure they fit */
189 C_ASSERT( sizeof(struct packed_CREATESTRUCTW) >= sizeof(CREATESTRUCTW) );
190 C_ASSERT( sizeof(struct packed_DRAWITEMSTRUCT) >= sizeof(DRAWITEMSTRUCT) );
191 C_ASSERT( sizeof(struct packed_MEASUREITEMSTRUCT) >= sizeof(MEASUREITEMSTRUCT) );
192 C_ASSERT( sizeof(struct packed_DELETEITEMSTRUCT) >= sizeof(DELETEITEMSTRUCT) );
193 C_ASSERT( sizeof(struct packed_COMPAREITEMSTRUCT) >= sizeof(COMPAREITEMSTRUCT) );
194 C_ASSERT( sizeof(struct packed_WINDOWPOS) >= sizeof(WINDOWPOS) );
195 C_ASSERT( sizeof(struct packed_COPYDATASTRUCT) >= sizeof(COPYDATASTRUCT) );
196 C_ASSERT( sizeof(struct packed_HELPINFO) >= sizeof(HELPINFO) );
197 C_ASSERT( sizeof(struct packed_NCCALCSIZE_PARAMS) >= sizeof(NCCALCSIZE_PARAMS) + sizeof(WINDOWPOS) );
198 C_ASSERT( sizeof(struct packed_MSG) >= sizeof(MSG) );
200 union packed_structs
202 struct packed_CREATESTRUCTW cs;
203 struct packed_DRAWITEMSTRUCT dis;
204 struct packed_MEASUREITEMSTRUCT mis;
205 struct packed_DELETEITEMSTRUCT dls;
206 struct packed_COMPAREITEMSTRUCT cis;
207 struct packed_WINDOWPOS wp;
208 struct packed_COPYDATASTRUCT cds;
209 struct packed_HELPINFO hi;
210 struct packed_NCCALCSIZE_PARAMS ncp;
211 struct packed_MSG msg;
214 /* description of the data fields that need to be packed along with a sent message */
215 struct packed_message
217 union packed_structs ps;
218 int count;
219 const void *data[MAX_PACK_COUNT];
220 size_t size[MAX_PACK_COUNT];
223 /* info about the message currently being received by the current thread */
224 struct received_message_info
226 enum message_type type;
227 MSG msg;
228 UINT flags; /* InSendMessageEx return flags */
231 /* structure to group all parameters for sent messages of the various kinds */
232 struct send_message_info
234 enum message_type type;
235 DWORD dest_tid;
236 HWND hwnd;
237 UINT msg;
238 WPARAM wparam;
239 LPARAM lparam;
240 UINT flags; /* flags for SendMessageTimeout */
241 UINT timeout; /* timeout for SendMessageTimeout */
242 SENDASYNCPROC callback; /* callback function for SendMessageCallback */
243 ULONG_PTR data; /* callback data */
244 enum wm_char_mapping wm_char;
248 /* Message class descriptor */
249 static const WCHAR messageW[] = {'M','e','s','s','a','g','e',0};
251 const struct builtin_class_descr MESSAGE_builtin_class =
253 messageW, /* name */
254 0, /* style */
255 WINPROC_MESSAGE, /* proc */
256 0, /* extra */
257 IDC_ARROW, /* cursor */
258 0 /* brush */
263 /* flag for messages that contain pointers */
264 /* 32 messages per entry, messages 0..31 map to bits 0..31 */
266 #define SET(msg) (1 << ((msg) & 31))
268 static const unsigned int message_pointer_flags[] =
270 /* 0x00 - 0x1f */
271 SET(WM_CREATE) | SET(WM_SETTEXT) | SET(WM_GETTEXT) |
272 SET(WM_WININICHANGE) | SET(WM_DEVMODECHANGE),
273 /* 0x20 - 0x3f */
274 SET(WM_GETMINMAXINFO) | SET(WM_DRAWITEM) | SET(WM_MEASUREITEM) | SET(WM_DELETEITEM) |
275 SET(WM_COMPAREITEM),
276 /* 0x40 - 0x5f */
277 SET(WM_WINDOWPOSCHANGING) | SET(WM_WINDOWPOSCHANGED) | SET(WM_COPYDATA) |
278 SET(WM_NOTIFY) | SET(WM_HELP),
279 /* 0x60 - 0x7f */
280 SET(WM_STYLECHANGING) | SET(WM_STYLECHANGED),
281 /* 0x80 - 0x9f */
282 SET(WM_NCCREATE) | SET(WM_NCCALCSIZE) | SET(WM_GETDLGCODE),
283 /* 0xa0 - 0xbf */
284 SET(EM_GETSEL) | SET(EM_GETRECT) | SET(EM_SETRECT) | SET(EM_SETRECTNP),
285 /* 0xc0 - 0xdf */
286 SET(EM_REPLACESEL) | SET(EM_GETLINE) | SET(EM_SETTABSTOPS),
287 /* 0xe0 - 0xff */
288 SET(SBM_GETRANGE) | SET(SBM_SETSCROLLINFO) | SET(SBM_GETSCROLLINFO) | SET(SBM_GETSCROLLBARINFO),
289 /* 0x100 - 0x11f */
291 /* 0x120 - 0x13f */
293 /* 0x140 - 0x15f */
294 SET(CB_GETEDITSEL) | SET(CB_ADDSTRING) | SET(CB_DIR) | SET(CB_GETLBTEXT) |
295 SET(CB_INSERTSTRING) | SET(CB_FINDSTRING) | SET(CB_SELECTSTRING) |
296 SET(CB_GETDROPPEDCONTROLRECT) | SET(CB_FINDSTRINGEXACT),
297 /* 0x160 - 0x17f */
299 /* 0x180 - 0x19f */
300 SET(LB_ADDSTRING) | SET(LB_INSERTSTRING) | SET(LB_GETTEXT) | SET(LB_SELECTSTRING) |
301 SET(LB_DIR) | SET(LB_FINDSTRING) |
302 SET(LB_GETSELITEMS) | SET(LB_SETTABSTOPS) | SET(LB_ADDFILE) | SET(LB_GETITEMRECT),
303 /* 0x1a0 - 0x1bf */
304 SET(LB_FINDSTRINGEXACT),
305 /* 0x1c0 - 0x1df */
307 /* 0x1e0 - 0x1ff */
309 /* 0x200 - 0x21f */
310 SET(WM_NEXTMENU) | SET(WM_SIZING) | SET(WM_MOVING) | SET(WM_DEVICECHANGE),
311 /* 0x220 - 0x23f */
312 SET(WM_MDICREATE) | SET(WM_MDIGETACTIVE) | SET(WM_DROPOBJECT) |
313 SET(WM_QUERYDROPOBJECT) | SET(WM_DRAGLOOP) | SET(WM_DRAGSELECT) | SET(WM_DRAGMOVE),
314 /* 0x240 - 0x25f */
316 /* 0x260 - 0x27f */
318 /* 0x280 - 0x29f */
320 /* 0x2a0 - 0x2bf */
322 /* 0x2c0 - 0x2df */
324 /* 0x2e0 - 0x2ff */
326 /* 0x300 - 0x31f */
327 SET(WM_ASKCBFORMATNAME)
330 /* flags for messages that contain Unicode strings */
331 static const unsigned int message_unicode_flags[] =
333 /* 0x00 - 0x1f */
334 SET(WM_CREATE) | SET(WM_SETTEXT) | SET(WM_GETTEXT) | SET(WM_GETTEXTLENGTH) |
335 SET(WM_WININICHANGE) | SET(WM_DEVMODECHANGE),
336 /* 0x20 - 0x3f */
337 SET(WM_CHARTOITEM),
338 /* 0x40 - 0x5f */
340 /* 0x60 - 0x7f */
342 /* 0x80 - 0x9f */
343 SET(WM_NCCREATE),
344 /* 0xa0 - 0xbf */
346 /* 0xc0 - 0xdf */
347 SET(EM_REPLACESEL) | SET(EM_GETLINE) | SET(EM_SETPASSWORDCHAR),
348 /* 0xe0 - 0xff */
350 /* 0x100 - 0x11f */
351 SET(WM_CHAR) | SET(WM_DEADCHAR) | SET(WM_SYSCHAR) | SET(WM_SYSDEADCHAR),
352 /* 0x120 - 0x13f */
353 SET(WM_MENUCHAR),
354 /* 0x140 - 0x15f */
355 SET(CB_ADDSTRING) | SET(CB_DIR) | SET(CB_GETLBTEXT) | SET(CB_GETLBTEXTLEN) |
356 SET(CB_INSERTSTRING) | SET(CB_FINDSTRING) | SET(CB_SELECTSTRING) | SET(CB_FINDSTRINGEXACT),
357 /* 0x160 - 0x17f */
359 /* 0x180 - 0x19f */
360 SET(LB_ADDSTRING) | SET(LB_INSERTSTRING) | SET(LB_GETTEXT) | SET(LB_GETTEXTLEN) |
361 SET(LB_SELECTSTRING) | SET(LB_DIR) | SET(LB_FINDSTRING) | SET(LB_ADDFILE),
362 /* 0x1a0 - 0x1bf */
363 SET(LB_FINDSTRINGEXACT),
364 /* 0x1c0 - 0x1df */
366 /* 0x1e0 - 0x1ff */
368 /* 0x200 - 0x21f */
370 /* 0x220 - 0x23f */
371 SET(WM_MDICREATE),
372 /* 0x240 - 0x25f */
374 /* 0x260 - 0x27f */
376 /* 0x280 - 0x29f */
377 SET(WM_IME_CHAR),
378 /* 0x2a0 - 0x2bf */
380 /* 0x2c0 - 0x2df */
382 /* 0x2e0 - 0x2ff */
384 /* 0x300 - 0x31f */
385 SET(WM_PAINTCLIPBOARD) | SET(WM_SIZECLIPBOARD) | SET(WM_ASKCBFORMATNAME)
388 /* check whether a given message type includes pointers */
389 static inline int is_pointer_message( UINT message )
391 if (message >= 8*sizeof(message_pointer_flags)) return FALSE;
392 return (message_pointer_flags[message / 32] & SET(message)) != 0;
395 /* check whether a given message type contains Unicode (or ASCII) chars */
396 static inline int is_unicode_message( UINT message )
398 if (message >= 8*sizeof(message_unicode_flags)) return FALSE;
399 return (message_unicode_flags[message / 32] & SET(message)) != 0;
402 #undef SET
404 /* add a data field to a packed message */
405 static inline void push_data( struct packed_message *data, const void *ptr, size_t size )
407 data->data[data->count] = ptr;
408 data->size[data->count] = size;
409 data->count++;
412 /* add a string to a packed message */
413 static inline void push_string( struct packed_message *data, LPCWSTR str )
415 push_data( data, str, (strlenW(str) + 1) * sizeof(WCHAR) );
418 /* make sure that the buffer contains a valid null-terminated Unicode string */
419 static inline BOOL check_string( LPCWSTR str, size_t size )
421 for (size /= sizeof(WCHAR); size; size--, str++)
422 if (!*str) return TRUE;
423 return FALSE;
426 /* pack a pointer into a 32/64 portable format */
427 static inline ULONGLONG pack_ptr( const void *ptr )
429 return (ULONG_PTR)ptr;
432 /* unpack a potentially 64-bit pointer, returning 0 when truncated */
433 static inline void *unpack_ptr( ULONGLONG ptr64 )
435 if ((ULONG_PTR)ptr64 != ptr64) return 0;
436 return (void *)(ULONG_PTR)ptr64;
439 /* make sure that there is space for 'size' bytes in buffer, growing it if needed */
440 static inline void *get_buffer_space( void **buffer, size_t size )
442 void *ret;
444 if (*buffer)
446 if (!(ret = HeapReAlloc( GetProcessHeap(), 0, *buffer, size )))
447 HeapFree( GetProcessHeap(), 0, *buffer );
449 else ret = HeapAlloc( GetProcessHeap(), 0, size );
451 *buffer = ret;
452 return ret;
455 /* check whether a combobox expects strings or ids in CB_ADDSTRING/CB_INSERTSTRING */
456 static inline BOOL combobox_has_strings( HWND hwnd )
458 DWORD style = GetWindowLongA( hwnd, GWL_STYLE );
459 return (!(style & (CBS_OWNERDRAWFIXED | CBS_OWNERDRAWVARIABLE)) || (style & CBS_HASSTRINGS));
462 /* check whether a listbox expects strings or ids in LB_ADDSTRING/LB_INSERTSTRING */
463 static inline BOOL listbox_has_strings( HWND hwnd )
465 DWORD style = GetWindowLongA( hwnd, GWL_STYLE );
466 return (!(style & (LBS_OWNERDRAWFIXED | LBS_OWNERDRAWVARIABLE)) || (style & LBS_HASSTRINGS));
469 /* check whether message is in the range of keyboard messages */
470 static inline BOOL is_keyboard_message( UINT message )
472 return (message >= WM_KEYFIRST && message <= WM_KEYLAST);
475 /* check whether message is in the range of mouse messages */
476 static inline BOOL is_mouse_message( UINT message )
478 return ((message >= WM_NCMOUSEFIRST && message <= WM_NCMOUSELAST) ||
479 (message >= WM_MOUSEFIRST && message <= WM_MOUSELAST));
482 /* check whether message matches the specified hwnd filter */
483 static inline BOOL check_hwnd_filter( const MSG *msg, HWND hwnd_filter )
485 if (!hwnd_filter || hwnd_filter == GetDesktopWindow()) return TRUE;
486 return (msg->hwnd == hwnd_filter || IsChild( hwnd_filter, msg->hwnd ));
489 /* check for pending WM_CHAR message with DBCS trailing byte */
490 static inline BOOL get_pending_wmchar( MSG *msg, UINT first, UINT last, BOOL remove )
492 struct wm_char_mapping_data *data = get_user_thread_info()->wmchar_data;
494 if (!data || !data->get_msg.message) return FALSE;
495 if ((first || last) && (first > WM_CHAR || last < WM_CHAR)) return FALSE;
496 if (!msg) return FALSE;
497 *msg = data->get_msg;
498 if (remove) data->get_msg.message = 0;
499 return TRUE;
503 /***********************************************************************
504 * MessageWndProc
506 * Window procedure for "Message" windows (HWND_MESSAGE parent).
508 LRESULT WINAPI MessageWndProc( HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam )
510 if (message == WM_NCCREATE) return TRUE;
511 return 0; /* all other messages are ignored */
515 /***********************************************************************
516 * broadcast_message_callback
518 * Helper callback for broadcasting messages.
520 static BOOL CALLBACK broadcast_message_callback( HWND hwnd, LPARAM lparam )
522 struct send_message_info *info = (struct send_message_info *)lparam;
523 if (!(GetWindowLongW( hwnd, GWL_STYLE ) & (WS_POPUP|WS_CAPTION))) return TRUE;
524 switch(info->type)
526 case MSG_UNICODE:
527 SendMessageTimeoutW( hwnd, info->msg, info->wparam, info->lparam,
528 info->flags, info->timeout, NULL );
529 break;
530 case MSG_ASCII:
531 SendMessageTimeoutA( hwnd, info->msg, info->wparam, info->lparam,
532 info->flags, info->timeout, NULL );
533 break;
534 case MSG_NOTIFY:
535 SendNotifyMessageW( hwnd, info->msg, info->wparam, info->lparam );
536 break;
537 case MSG_CALLBACK:
538 SendMessageCallbackW( hwnd, info->msg, info->wparam, info->lparam,
539 info->callback, info->data );
540 break;
541 case MSG_POSTED:
542 PostMessageW( hwnd, info->msg, info->wparam, info->lparam );
543 break;
544 default:
545 ERR( "bad type %d\n", info->type );
546 break;
548 return TRUE;
552 /***********************************************************************
553 * map_wparam_AtoW
555 * Convert the wparam of an ASCII message to Unicode.
557 BOOL map_wparam_AtoW( UINT message, WPARAM *wparam, enum wm_char_mapping mapping )
559 char ch[2];
560 WCHAR wch[2];
562 wch[0] = wch[1] = 0;
563 switch(message)
565 case WM_CHAR:
566 /* WM_CHAR is magic: a DBCS char can be sent/posted as two consecutive WM_CHAR
567 * messages, in which case the first char is stored, and the conversion
568 * to Unicode only takes place once the second char is sent/posted.
570 if (mapping != WMCHAR_MAP_NOMAPPING)
572 struct wm_char_mapping_data *data = get_user_thread_info()->wmchar_data;
573 BYTE low = LOBYTE(*wparam);
575 if (HIBYTE(*wparam))
577 ch[0] = low;
578 ch[1] = HIBYTE(*wparam);
579 RtlMultiByteToUnicodeN( wch, sizeof(wch), NULL, ch, 2 );
580 TRACE( "map %02x,%02x -> %04x mapping %u\n", (BYTE)ch[0], (BYTE)ch[1], wch[0], mapping );
581 if (data) data->lead_byte[mapping] = 0;
583 else if (data && data->lead_byte[mapping])
585 ch[0] = data->lead_byte[mapping];
586 ch[1] = low;
587 RtlMultiByteToUnicodeN( wch, sizeof(wch), NULL, ch, 2 );
588 TRACE( "map stored %02x,%02x -> %04x mapping %u\n", (BYTE)ch[0], (BYTE)ch[1], wch[0], mapping );
589 data->lead_byte[mapping] = 0;
591 else if (!IsDBCSLeadByte( low ))
593 ch[0] = low;
594 RtlMultiByteToUnicodeN( wch, sizeof(wch), NULL, ch, 1 );
595 TRACE( "map %02x -> %04x\n", (BYTE)ch[0], wch[0] );
596 if (data) data->lead_byte[mapping] = 0;
598 else /* store it and wait for trail byte */
600 if (!data)
602 if (!(data = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*data) )))
603 return FALSE;
604 get_user_thread_info()->wmchar_data = data;
606 TRACE( "storing lead byte %02x mapping %u\n", low, mapping );
607 data->lead_byte[mapping] = low;
608 return FALSE;
610 *wparam = MAKEWPARAM(wch[0], wch[1]);
611 break;
613 /* else fall through */
614 case WM_CHARTOITEM:
615 case EM_SETPASSWORDCHAR:
616 case WM_DEADCHAR:
617 case WM_SYSCHAR:
618 case WM_SYSDEADCHAR:
619 case WM_MENUCHAR:
620 ch[0] = LOBYTE(*wparam);
621 ch[1] = HIBYTE(*wparam);
622 RtlMultiByteToUnicodeN( wch, sizeof(wch), NULL, ch, 2 );
623 *wparam = MAKEWPARAM(wch[0], wch[1]);
624 break;
625 case WM_IME_CHAR:
626 ch[0] = HIBYTE(*wparam);
627 ch[1] = LOBYTE(*wparam);
628 if (ch[0]) RtlMultiByteToUnicodeN( wch, sizeof(wch[0]), NULL, ch, 2 );
629 else RtlMultiByteToUnicodeN( wch, sizeof(wch[0]), NULL, ch + 1, 1 );
630 *wparam = MAKEWPARAM(wch[0], HIWORD(*wparam));
631 break;
633 return TRUE;
637 /***********************************************************************
638 * map_wparam_WtoA
640 * Convert the wparam of a Unicode message to ASCII.
642 static void map_wparam_WtoA( MSG *msg, BOOL remove )
644 BYTE ch[2];
645 WCHAR wch[2];
646 DWORD len;
648 switch(msg->message)
650 case WM_CHAR:
651 if (!HIWORD(msg->wParam))
653 wch[0] = LOWORD(msg->wParam);
654 ch[0] = ch[1] = 0;
655 RtlUnicodeToMultiByteN( (LPSTR)ch, 2, &len, wch, sizeof(wch[0]) );
656 if (len == 2) /* DBCS char */
658 struct wm_char_mapping_data *data = get_user_thread_info()->wmchar_data;
659 if (!data)
661 if (!(data = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*data) ))) return;
662 get_user_thread_info()->wmchar_data = data;
664 if (remove)
666 data->get_msg = *msg;
667 data->get_msg.wParam = ch[1];
669 msg->wParam = ch[0];
670 return;
673 /* else fall through */
674 case WM_CHARTOITEM:
675 case EM_SETPASSWORDCHAR:
676 case WM_DEADCHAR:
677 case WM_SYSCHAR:
678 case WM_SYSDEADCHAR:
679 case WM_MENUCHAR:
680 wch[0] = LOWORD(msg->wParam);
681 wch[1] = HIWORD(msg->wParam);
682 ch[0] = ch[1] = 0;
683 RtlUnicodeToMultiByteN( (LPSTR)ch, 2, NULL, wch, sizeof(wch) );
684 msg->wParam = MAKEWPARAM( ch[0] | (ch[1] << 8), 0 );
685 break;
686 case WM_IME_CHAR:
687 wch[0] = LOWORD(msg->wParam);
688 ch[0] = ch[1] = 0;
689 RtlUnicodeToMultiByteN( (LPSTR)ch, 2, &len, wch, sizeof(wch[0]) );
690 if (len == 2)
691 msg->wParam = MAKEWPARAM( (ch[0] << 8) | ch[1], HIWORD(msg->wParam) );
692 else
693 msg->wParam = MAKEWPARAM( ch[0], HIWORD(msg->wParam) );
694 break;
699 /***********************************************************************
700 * pack_message
702 * Pack a message for sending to another process.
703 * Return the size of the data we expect in the message reply.
704 * Set data->count to -1 if there is an error.
706 static size_t pack_message( HWND hwnd, UINT message, WPARAM wparam, LPARAM lparam,
707 struct packed_message *data )
709 data->count = 0;
710 switch(message)
712 case WM_NCCREATE:
713 case WM_CREATE:
715 CREATESTRUCTW *cs = (CREATESTRUCTW *)lparam;
716 data->ps.cs.lpCreateParams = pack_ptr( cs->lpCreateParams );
717 data->ps.cs.hInstance = pack_ptr( cs->hInstance );
718 data->ps.cs.hMenu = wine_server_user_handle( cs->hMenu );
719 data->ps.cs.hwndParent = wine_server_user_handle( cs->hwndParent );
720 data->ps.cs.cy = cs->cy;
721 data->ps.cs.cx = cs->cx;
722 data->ps.cs.y = cs->y;
723 data->ps.cs.x = cs->x;
724 data->ps.cs.style = cs->style;
725 data->ps.cs.dwExStyle = cs->dwExStyle;
726 data->ps.cs.lpszName = pack_ptr( cs->lpszName );
727 data->ps.cs.lpszClass = pack_ptr( cs->lpszClass );
728 push_data( data, &data->ps.cs, sizeof(data->ps.cs) );
729 if (!IS_INTRESOURCE(cs->lpszName)) push_string( data, cs->lpszName );
730 if (!IS_INTRESOURCE(cs->lpszClass)) push_string( data, cs->lpszClass );
731 return sizeof(data->ps.cs);
733 case WM_GETTEXT:
734 case WM_ASKCBFORMATNAME:
735 return wparam * sizeof(WCHAR);
736 case WM_WININICHANGE:
737 if (lparam) push_string(data, (LPWSTR)lparam );
738 return 0;
739 case WM_SETTEXT:
740 case WM_DEVMODECHANGE:
741 case CB_DIR:
742 case LB_DIR:
743 case LB_ADDFILE:
744 case EM_REPLACESEL:
745 push_string( data, (LPWSTR)lparam );
746 return 0;
747 case WM_GETMINMAXINFO:
748 push_data( data, (MINMAXINFO *)lparam, sizeof(MINMAXINFO) );
749 return sizeof(MINMAXINFO);
750 case WM_DRAWITEM:
752 DRAWITEMSTRUCT *dis = (DRAWITEMSTRUCT *)lparam;
753 data->ps.dis.CtlType = dis->CtlType;
754 data->ps.dis.CtlID = dis->CtlID;
755 data->ps.dis.itemID = dis->itemID;
756 data->ps.dis.itemAction = dis->itemAction;
757 data->ps.dis.itemState = dis->itemState;
758 data->ps.dis.hwndItem = wine_server_user_handle( dis->hwndItem );
759 data->ps.dis.hDC = wine_server_user_handle( dis->hDC ); /* FIXME */
760 data->ps.dis.rcItem = dis->rcItem;
761 data->ps.dis.itemData = dis->itemData;
762 push_data( data, &data->ps.dis, sizeof(data->ps.dis) );
763 return 0;
765 case WM_MEASUREITEM:
767 MEASUREITEMSTRUCT *mis = (MEASUREITEMSTRUCT *)lparam;
768 data->ps.mis.CtlType = mis->CtlType;
769 data->ps.mis.CtlID = mis->CtlID;
770 data->ps.mis.itemID = mis->itemID;
771 data->ps.mis.itemWidth = mis->itemWidth;
772 data->ps.mis.itemHeight = mis->itemHeight;
773 data->ps.mis.itemData = mis->itemData;
774 push_data( data, &data->ps.mis, sizeof(data->ps.mis) );
775 return sizeof(data->ps.mis);
777 case WM_DELETEITEM:
779 DELETEITEMSTRUCT *dls = (DELETEITEMSTRUCT *)lparam;
780 data->ps.dls.CtlType = dls->CtlType;
781 data->ps.dls.CtlID = dls->CtlID;
782 data->ps.dls.itemID = dls->itemID;
783 data->ps.dls.hwndItem = wine_server_user_handle( dls->hwndItem );
784 data->ps.dls.itemData = dls->itemData;
785 push_data( data, &data->ps.dls, sizeof(data->ps.dls) );
786 return 0;
788 case WM_COMPAREITEM:
790 COMPAREITEMSTRUCT *cis = (COMPAREITEMSTRUCT *)lparam;
791 data->ps.cis.CtlType = cis->CtlType;
792 data->ps.cis.CtlID = cis->CtlID;
793 data->ps.cis.hwndItem = wine_server_user_handle( cis->hwndItem );
794 data->ps.cis.itemID1 = cis->itemID1;
795 data->ps.cis.itemData1 = cis->itemData1;
796 data->ps.cis.itemID2 = cis->itemID2;
797 data->ps.cis.itemData2 = cis->itemData2;
798 data->ps.cis.dwLocaleId = cis->dwLocaleId;
799 push_data( data, &data->ps.cis, sizeof(data->ps.cis) );
800 return 0;
802 case WM_WINDOWPOSCHANGING:
803 case WM_WINDOWPOSCHANGED:
805 WINDOWPOS *wp = (WINDOWPOS *)lparam;
806 data->ps.wp.hwnd = wine_server_user_handle( wp->hwnd );
807 data->ps.wp.hwndInsertAfter = wine_server_user_handle( wp->hwndInsertAfter );
808 data->ps.wp.x = wp->x;
809 data->ps.wp.y = wp->y;
810 data->ps.wp.cx = wp->cx;
811 data->ps.wp.cy = wp->cy;
812 data->ps.wp.flags = wp->flags;
813 push_data( data, &data->ps.wp, sizeof(data->ps.wp) );
814 return sizeof(data->ps.wp);
816 case WM_COPYDATA:
818 COPYDATASTRUCT *cds = (COPYDATASTRUCT *)lparam;
819 data->ps.cds.cbData = cds->cbData;
820 data->ps.cds.dwData = cds->dwData;
821 data->ps.cds.lpData = pack_ptr( cds->lpData );
822 push_data( data, &data->ps.cds, sizeof(data->ps.cds) );
823 if (cds->lpData) push_data( data, cds->lpData, cds->cbData );
824 return 0;
826 case WM_NOTIFY:
827 /* WM_NOTIFY cannot be sent across processes (MSDN) */
828 data->count = -1;
829 return 0;
830 case WM_HELP:
832 HELPINFO *hi = (HELPINFO *)lparam;
833 data->ps.hi.iContextType = hi->iContextType;
834 data->ps.hi.iCtrlId = hi->iCtrlId;
835 data->ps.hi.hItemHandle = wine_server_user_handle( hi->hItemHandle );
836 data->ps.hi.dwContextId = hi->dwContextId;
837 data->ps.hi.MousePos = hi->MousePos;
838 push_data( data, &data->ps.hi, sizeof(data->ps.hi) );
839 return 0;
841 case WM_STYLECHANGING:
842 case WM_STYLECHANGED:
843 push_data( data, (STYLESTRUCT *)lparam, sizeof(STYLESTRUCT) );
844 return 0;
845 case WM_NCCALCSIZE:
846 if (!wparam)
848 push_data( data, (RECT *)lparam, sizeof(RECT) );
849 return sizeof(RECT);
851 else
853 NCCALCSIZE_PARAMS *ncp = (NCCALCSIZE_PARAMS *)lparam;
854 data->ps.ncp.rgrc[0] = ncp->rgrc[0];
855 data->ps.ncp.rgrc[1] = ncp->rgrc[1];
856 data->ps.ncp.rgrc[2] = ncp->rgrc[2];
857 data->ps.ncp.hwnd = wine_server_user_handle( ncp->lppos->hwnd );
858 data->ps.ncp.hwndInsertAfter = wine_server_user_handle( ncp->lppos->hwndInsertAfter );
859 data->ps.ncp.x = ncp->lppos->x;
860 data->ps.ncp.y = ncp->lppos->y;
861 data->ps.ncp.cx = ncp->lppos->cx;
862 data->ps.ncp.cy = ncp->lppos->cy;
863 data->ps.ncp.flags = ncp->lppos->flags;
864 push_data( data, &data->ps.ncp, sizeof(data->ps.ncp) );
865 return sizeof(data->ps.ncp);
867 case WM_GETDLGCODE:
868 if (lparam)
870 MSG *msg = (MSG *)lparam;
871 data->ps.msg.hwnd = wine_server_user_handle( msg->hwnd );
872 data->ps.msg.message = msg->message;
873 data->ps.msg.wParam = msg->wParam;
874 data->ps.msg.lParam = msg->lParam;
875 data->ps.msg.time = msg->time;
876 data->ps.msg.pt = msg->pt;
877 push_data( data, &data->ps.msg, sizeof(data->ps.msg) );
878 return sizeof(data->ps.msg);
880 return 0;
881 case SBM_SETSCROLLINFO:
882 push_data( data, (SCROLLINFO *)lparam, sizeof(SCROLLINFO) );
883 return 0;
884 case SBM_GETSCROLLINFO:
885 push_data( data, (SCROLLINFO *)lparam, sizeof(SCROLLINFO) );
886 return sizeof(SCROLLINFO);
887 case SBM_GETSCROLLBARINFO:
889 const SCROLLBARINFO *info = (const SCROLLBARINFO *)lparam;
890 size_t size = min( info->cbSize, sizeof(SCROLLBARINFO) );
891 push_data( data, info, size );
892 return size;
894 case EM_GETSEL:
895 case SBM_GETRANGE:
896 case CB_GETEDITSEL:
898 size_t size = 0;
899 if (wparam) size += sizeof(DWORD);
900 if (lparam) size += sizeof(DWORD);
901 return size;
903 case EM_GETRECT:
904 case LB_GETITEMRECT:
905 case CB_GETDROPPEDCONTROLRECT:
906 return sizeof(RECT);
907 case EM_SETRECT:
908 case EM_SETRECTNP:
909 push_data( data, (RECT *)lparam, sizeof(RECT) );
910 return 0;
911 case EM_GETLINE:
913 WORD *pw = (WORD *)lparam;
914 push_data( data, pw, sizeof(*pw) );
915 return *pw * sizeof(WCHAR);
917 case EM_SETTABSTOPS:
918 case LB_SETTABSTOPS:
919 if (wparam) push_data( data, (UINT *)lparam, sizeof(UINT) * wparam );
920 return 0;
921 case CB_ADDSTRING:
922 case CB_INSERTSTRING:
923 case CB_FINDSTRING:
924 case CB_FINDSTRINGEXACT:
925 case CB_SELECTSTRING:
926 if (combobox_has_strings( hwnd )) push_string( data, (LPWSTR)lparam );
927 return 0;
928 case CB_GETLBTEXT:
929 if (!combobox_has_strings( hwnd )) return sizeof(ULONG_PTR);
930 return (SendMessageW( hwnd, CB_GETLBTEXTLEN, wparam, 0 ) + 1) * sizeof(WCHAR);
931 case LB_ADDSTRING:
932 case LB_INSERTSTRING:
933 case LB_FINDSTRING:
934 case LB_FINDSTRINGEXACT:
935 case LB_SELECTSTRING:
936 if (listbox_has_strings( hwnd )) push_string( data, (LPWSTR)lparam );
937 return 0;
938 case LB_GETTEXT:
939 if (!listbox_has_strings( hwnd )) return sizeof(ULONG_PTR);
940 return (SendMessageW( hwnd, LB_GETTEXTLEN, wparam, 0 ) + 1) * sizeof(WCHAR);
941 case LB_GETSELITEMS:
942 return wparam * sizeof(UINT);
943 case WM_NEXTMENU:
944 push_data( data, (MDINEXTMENU *)lparam, sizeof(MDINEXTMENU) );
945 return sizeof(MDINEXTMENU);
946 case WM_SIZING:
947 case WM_MOVING:
948 push_data( data, (RECT *)lparam, sizeof(RECT) );
949 return sizeof(RECT);
950 case WM_MDICREATE:
952 MDICREATESTRUCTW *cs = (MDICREATESTRUCTW *)lparam;
953 push_data( data, cs, sizeof(*cs) );
954 if (!IS_INTRESOURCE(cs->szTitle)) push_string( data, cs->szTitle );
955 if (!IS_INTRESOURCE(cs->szClass)) push_string( data, cs->szClass );
956 return sizeof(*cs);
958 case WM_MDIGETACTIVE:
959 if (lparam) return sizeof(BOOL);
960 return 0;
961 case WM_DEVICECHANGE:
963 DEV_BROADCAST_HDR *header = (DEV_BROADCAST_HDR *)lparam;
964 push_data( data, header, header->dbch_size );
965 return 0;
967 case WM_WINE_SETWINDOWPOS:
968 push_data( data, (WINDOWPOS *)lparam, sizeof(WINDOWPOS) );
969 return 0;
970 case WM_WINE_KEYBOARD_LL_HOOK:
972 struct hook_extra_info *h_extra = (struct hook_extra_info *)lparam;
973 push_data( data, h_extra, sizeof(*h_extra) );
974 push_data( data, (LPVOID)h_extra->lparam, sizeof(KBDLLHOOKSTRUCT) );
975 return 0;
977 case WM_WINE_MOUSE_LL_HOOK:
979 struct hook_extra_info *h_extra = (struct hook_extra_info *)lparam;
980 push_data( data, h_extra, sizeof(*h_extra) );
981 push_data( data, (LPVOID)h_extra->lparam, sizeof(MSLLHOOKSTRUCT) );
982 return 0;
984 case WM_NCPAINT:
985 if (wparam <= 1) return 0;
986 FIXME( "WM_NCPAINT hdc packing not supported yet\n" );
987 data->count = -1;
988 return 0;
989 case WM_PAINT:
990 if (!wparam) return 0;
991 /* fall through */
993 /* these contain an HFONT */
994 case WM_SETFONT:
995 case WM_GETFONT:
996 /* these contain an HDC */
997 case WM_ERASEBKGND:
998 case WM_ICONERASEBKGND:
999 case WM_CTLCOLORMSGBOX:
1000 case WM_CTLCOLOREDIT:
1001 case WM_CTLCOLORLISTBOX:
1002 case WM_CTLCOLORBTN:
1003 case WM_CTLCOLORDLG:
1004 case WM_CTLCOLORSCROLLBAR:
1005 case WM_CTLCOLORSTATIC:
1006 case WM_PRINT:
1007 case WM_PRINTCLIENT:
1008 /* these contain an HGLOBAL */
1009 case WM_PAINTCLIPBOARD:
1010 case WM_SIZECLIPBOARD:
1011 /* these contain HICON */
1012 case WM_GETICON:
1013 case WM_SETICON:
1014 case WM_QUERYDRAGICON:
1015 case WM_QUERYPARKICON:
1016 /* these contain pointers */
1017 case WM_DROPOBJECT:
1018 case WM_QUERYDROPOBJECT:
1019 case WM_DRAGLOOP:
1020 case WM_DRAGSELECT:
1021 case WM_DRAGMOVE:
1022 FIXME( "msg %x (%s) not supported yet\n", message, SPY_GetMsgName(message, hwnd) );
1023 data->count = -1;
1024 return 0;
1026 return 0;
1030 /***********************************************************************
1031 * unpack_message
1033 * Unpack a message received from another process.
1035 static BOOL unpack_message( HWND hwnd, UINT message, WPARAM *wparam, LPARAM *lparam,
1036 void **buffer, size_t size )
1038 size_t minsize = 0;
1039 union packed_structs *ps = *buffer;
1041 switch(message)
1043 case WM_NCCREATE:
1044 case WM_CREATE:
1046 CREATESTRUCTW cs;
1047 WCHAR *str = (WCHAR *)(&ps->cs + 1);
1048 if (size < sizeof(ps->cs)) return FALSE;
1049 size -= sizeof(ps->cs);
1050 cs.lpCreateParams = unpack_ptr( ps->cs.lpCreateParams );
1051 cs.hInstance = unpack_ptr( ps->cs.hInstance );
1052 cs.hMenu = wine_server_ptr_handle( ps->cs.hMenu );
1053 cs.hwndParent = wine_server_ptr_handle( ps->cs.hwndParent );
1054 cs.cy = ps->cs.cy;
1055 cs.cx = ps->cs.cx;
1056 cs.y = ps->cs.y;
1057 cs.x = ps->cs.x;
1058 cs.style = ps->cs.style;
1059 cs.dwExStyle = ps->cs.dwExStyle;
1060 cs.lpszName = unpack_ptr( ps->cs.lpszName );
1061 cs.lpszClass = unpack_ptr( ps->cs.lpszClass );
1062 if (ps->cs.lpszName >> 16)
1064 if (!check_string( str, size )) return FALSE;
1065 cs.lpszName = str;
1066 size -= (strlenW(str) + 1) * sizeof(WCHAR);
1067 str += strlenW(str) + 1;
1069 if (ps->cs.lpszClass >> 16)
1071 if (!check_string( str, size )) return FALSE;
1072 cs.lpszClass = str;
1074 memcpy( &ps->cs, &cs, sizeof(cs) );
1075 break;
1077 case WM_GETTEXT:
1078 case WM_ASKCBFORMATNAME:
1079 if (!get_buffer_space( buffer, (*wparam * sizeof(WCHAR)) )) return FALSE;
1080 break;
1081 case WM_WININICHANGE:
1082 if (!*lparam) return TRUE;
1083 /* fall through */
1084 case WM_SETTEXT:
1085 case WM_DEVMODECHANGE:
1086 case CB_DIR:
1087 case LB_DIR:
1088 case LB_ADDFILE:
1089 case EM_REPLACESEL:
1090 if (!check_string( *buffer, size )) return FALSE;
1091 break;
1092 case WM_GETMINMAXINFO:
1093 minsize = sizeof(MINMAXINFO);
1094 break;
1095 case WM_DRAWITEM:
1097 DRAWITEMSTRUCT dis;
1098 if (size < sizeof(ps->dis)) return FALSE;
1099 dis.CtlType = ps->dis.CtlType;
1100 dis.CtlID = ps->dis.CtlID;
1101 dis.itemID = ps->dis.itemID;
1102 dis.itemAction = ps->dis.itemAction;
1103 dis.itemState = ps->dis.itemState;
1104 dis.hwndItem = wine_server_ptr_handle( ps->dis.hwndItem );
1105 dis.hDC = wine_server_ptr_handle( ps->dis.hDC );
1106 dis.rcItem = ps->dis.rcItem;
1107 dis.itemData = (ULONG_PTR)unpack_ptr( ps->dis.itemData );
1108 memcpy( &ps->dis, &dis, sizeof(dis) );
1109 break;
1111 case WM_MEASUREITEM:
1113 MEASUREITEMSTRUCT mis;
1114 if (size < sizeof(ps->mis)) return FALSE;
1115 mis.CtlType = ps->mis.CtlType;
1116 mis.CtlID = ps->mis.CtlID;
1117 mis.itemID = ps->mis.itemID;
1118 mis.itemWidth = ps->mis.itemWidth;
1119 mis.itemHeight = ps->mis.itemHeight;
1120 mis.itemData = (ULONG_PTR)unpack_ptr( ps->mis.itemData );
1121 memcpy( &ps->mis, &mis, sizeof(mis) );
1122 break;
1124 case WM_DELETEITEM:
1126 DELETEITEMSTRUCT dls;
1127 if (size < sizeof(ps->dls)) return FALSE;
1128 dls.CtlType = ps->dls.CtlType;
1129 dls.CtlID = ps->dls.CtlID;
1130 dls.itemID = ps->dls.itemID;
1131 dls.hwndItem = wine_server_ptr_handle( ps->dls.hwndItem );
1132 dls.itemData = (ULONG_PTR)unpack_ptr( ps->dls.itemData );
1133 memcpy( &ps->dls, &dls, sizeof(dls) );
1134 break;
1136 case WM_COMPAREITEM:
1138 COMPAREITEMSTRUCT cis;
1139 if (size < sizeof(ps->cis)) return FALSE;
1140 cis.CtlType = ps->cis.CtlType;
1141 cis.CtlID = ps->cis.CtlID;
1142 cis.hwndItem = wine_server_ptr_handle( ps->cis.hwndItem );
1143 cis.itemID1 = ps->cis.itemID1;
1144 cis.itemData1 = (ULONG_PTR)unpack_ptr( ps->cis.itemData1 );
1145 cis.itemID2 = ps->cis.itemID2;
1146 cis.itemData2 = (ULONG_PTR)unpack_ptr( ps->cis.itemData2 );
1147 cis.dwLocaleId = ps->cis.dwLocaleId;
1148 memcpy( &ps->cis, &cis, sizeof(cis) );
1149 break;
1151 case WM_WINDOWPOSCHANGING:
1152 case WM_WINDOWPOSCHANGED:
1153 case WM_WINE_SETWINDOWPOS:
1155 WINDOWPOS wp;
1156 if (size < sizeof(ps->wp)) return FALSE;
1157 wp.hwnd = wine_server_ptr_handle( ps->wp.hwnd );
1158 wp.hwndInsertAfter = wine_server_ptr_handle( ps->wp.hwndInsertAfter );
1159 wp.x = ps->wp.x;
1160 wp.y = ps->wp.y;
1161 wp.cx = ps->wp.cx;
1162 wp.cy = ps->wp.cy;
1163 wp.flags = ps->wp.flags;
1164 memcpy( &ps->wp, &wp, sizeof(wp) );
1165 break;
1167 case WM_COPYDATA:
1169 COPYDATASTRUCT cds;
1170 if (size < sizeof(ps->cds)) return FALSE;
1171 cds.dwData = (ULONG_PTR)unpack_ptr( ps->cds.dwData );
1172 if (ps->cds.lpData)
1174 cds.cbData = ps->cds.cbData;
1175 cds.lpData = &ps->cds + 1;
1176 minsize = sizeof(ps->cds) + cds.cbData;
1178 else
1180 cds.cbData = 0;
1181 cds.lpData = 0;
1183 memcpy( &ps->cds, &cds, sizeof(cds) );
1184 break;
1186 case WM_NOTIFY:
1187 /* WM_NOTIFY cannot be sent across processes (MSDN) */
1188 return FALSE;
1189 case WM_HELP:
1191 HELPINFO hi;
1192 if (size < sizeof(ps->hi)) return FALSE;
1193 hi.cbSize = sizeof(hi);
1194 hi.iContextType = ps->hi.iContextType;
1195 hi.iCtrlId = ps->hi.iCtrlId;
1196 hi.hItemHandle = wine_server_ptr_handle( ps->hi.hItemHandle );
1197 hi.dwContextId = (ULONG_PTR)unpack_ptr( ps->hi.dwContextId );
1198 hi.MousePos = ps->hi.MousePos;
1199 memcpy( &ps->hi, &hi, sizeof(hi) );
1200 break;
1202 case WM_STYLECHANGING:
1203 case WM_STYLECHANGED:
1204 minsize = sizeof(STYLESTRUCT);
1205 break;
1206 case WM_NCCALCSIZE:
1207 if (!*wparam) minsize = sizeof(RECT);
1208 else
1210 NCCALCSIZE_PARAMS ncp;
1211 WINDOWPOS wp;
1212 if (size < sizeof(ps->ncp)) return FALSE;
1213 ncp.rgrc[0] = ps->ncp.rgrc[0];
1214 ncp.rgrc[1] = ps->ncp.rgrc[1];
1215 ncp.rgrc[2] = ps->ncp.rgrc[2];
1216 wp.hwnd = wine_server_ptr_handle( ps->ncp.hwnd );
1217 wp.hwndInsertAfter = wine_server_ptr_handle( ps->ncp.hwndInsertAfter );
1218 wp.x = ps->ncp.x;
1219 wp.y = ps->ncp.y;
1220 wp.cx = ps->ncp.cx;
1221 wp.cy = ps->ncp.cy;
1222 wp.flags = ps->ncp.flags;
1223 ncp.lppos = (WINDOWPOS *)((NCCALCSIZE_PARAMS *)&ps->ncp + 1);
1224 memcpy( &ps->ncp, &ncp, sizeof(ncp) );
1225 *ncp.lppos = wp;
1227 break;
1228 case WM_GETDLGCODE:
1229 if (*lparam)
1231 MSG msg;
1232 if (size < sizeof(ps->msg)) return FALSE;
1233 msg.hwnd = wine_server_ptr_handle( ps->msg.hwnd );
1234 msg.message = ps->msg.message;
1235 msg.wParam = (ULONG_PTR)unpack_ptr( ps->msg.wParam );
1236 msg.lParam = (ULONG_PTR)unpack_ptr( ps->msg.lParam );
1237 msg.time = ps->msg.time;
1238 msg.pt = ps->msg.pt;
1239 memcpy( &ps->msg, &msg, sizeof(msg) );
1240 break;
1242 return TRUE;
1243 case SBM_SETSCROLLINFO:
1244 minsize = sizeof(SCROLLINFO);
1245 break;
1246 case SBM_GETSCROLLINFO:
1247 if (!get_buffer_space( buffer, sizeof(SCROLLINFO ))) return FALSE;
1248 break;
1249 case SBM_GETSCROLLBARINFO:
1250 if (!get_buffer_space( buffer, sizeof(SCROLLBARINFO ))) return FALSE;
1251 break;
1252 case EM_GETSEL:
1253 case SBM_GETRANGE:
1254 case CB_GETEDITSEL:
1255 if (*wparam || *lparam)
1257 if (!get_buffer_space( buffer, 2*sizeof(DWORD) )) return FALSE;
1258 if (*wparam) *wparam = (WPARAM)*buffer;
1259 if (*lparam) *lparam = (LPARAM)((DWORD *)*buffer + 1);
1261 return TRUE;
1262 case EM_GETRECT:
1263 case LB_GETITEMRECT:
1264 case CB_GETDROPPEDCONTROLRECT:
1265 if (!get_buffer_space( buffer, sizeof(RECT) )) return FALSE;
1266 break;
1267 case EM_SETRECT:
1268 case EM_SETRECTNP:
1269 minsize = sizeof(RECT);
1270 break;
1271 case EM_GETLINE:
1273 WORD len;
1274 if (size < sizeof(WORD)) return FALSE;
1275 len = *(WORD *)*buffer;
1276 if (!get_buffer_space( buffer, (len + 1) * sizeof(WCHAR) )) return FALSE;
1277 *lparam = (LPARAM)*buffer + sizeof(WORD); /* don't erase WORD at start of buffer */
1278 return TRUE;
1280 case EM_SETTABSTOPS:
1281 case LB_SETTABSTOPS:
1282 if (!*wparam) return TRUE;
1283 minsize = *wparam * sizeof(UINT);
1284 break;
1285 case CB_ADDSTRING:
1286 case CB_INSERTSTRING:
1287 case CB_FINDSTRING:
1288 case CB_FINDSTRINGEXACT:
1289 case CB_SELECTSTRING:
1290 case LB_ADDSTRING:
1291 case LB_INSERTSTRING:
1292 case LB_FINDSTRING:
1293 case LB_FINDSTRINGEXACT:
1294 case LB_SELECTSTRING:
1295 if (!*buffer) return TRUE;
1296 if (!check_string( *buffer, size )) return FALSE;
1297 break;
1298 case CB_GETLBTEXT:
1300 size = sizeof(ULONG_PTR);
1301 if (combobox_has_strings( hwnd ))
1302 size = (SendMessageW( hwnd, CB_GETLBTEXTLEN, *wparam, 0 ) + 1) * sizeof(WCHAR);
1303 if (!get_buffer_space( buffer, size )) return FALSE;
1304 break;
1306 case LB_GETTEXT:
1308 size = sizeof(ULONG_PTR);
1309 if (listbox_has_strings( hwnd ))
1310 size = (SendMessageW( hwnd, LB_GETTEXTLEN, *wparam, 0 ) + 1) * sizeof(WCHAR);
1311 if (!get_buffer_space( buffer, size )) return FALSE;
1312 break;
1314 case LB_GETSELITEMS:
1315 if (!get_buffer_space( buffer, *wparam * sizeof(UINT) )) return FALSE;
1316 break;
1317 case WM_NEXTMENU:
1318 minsize = sizeof(MDINEXTMENU);
1319 if (!get_buffer_space( buffer, sizeof(MDINEXTMENU) )) return FALSE;
1320 break;
1321 case WM_SIZING:
1322 case WM_MOVING:
1323 minsize = sizeof(RECT);
1324 if (!get_buffer_space( buffer, sizeof(RECT) )) return FALSE;
1325 break;
1326 case WM_MDICREATE:
1328 MDICREATESTRUCTW *cs = *buffer;
1329 WCHAR *str = (WCHAR *)(cs + 1);
1330 if (size < sizeof(*cs)) return FALSE;
1331 size -= sizeof(*cs);
1332 if (!IS_INTRESOURCE(cs->szTitle))
1334 if (!check_string( str, size )) return FALSE;
1335 cs->szTitle = str;
1336 size -= (strlenW(str) + 1) * sizeof(WCHAR);
1337 str += strlenW(str) + 1;
1339 if (!IS_INTRESOURCE(cs->szClass))
1341 if (!check_string( str, size )) return FALSE;
1342 cs->szClass = str;
1344 break;
1346 case WM_MDIGETACTIVE:
1347 if (!*lparam) return TRUE;
1348 if (!get_buffer_space( buffer, sizeof(BOOL) )) return FALSE;
1349 break;
1350 case WM_DEVICECHANGE:
1351 minsize = sizeof(DEV_BROADCAST_HDR);
1352 break;
1353 case WM_WINE_KEYBOARD_LL_HOOK:
1354 case WM_WINE_MOUSE_LL_HOOK:
1356 struct hook_extra_info *h_extra = *buffer;
1358 minsize = sizeof(struct hook_extra_info) +
1359 (message == WM_WINE_KEYBOARD_LL_HOOK ? sizeof(KBDLLHOOKSTRUCT)
1360 : sizeof(MSLLHOOKSTRUCT));
1361 if (size < minsize) return FALSE;
1362 h_extra->lparam = (LPARAM)(h_extra + 1);
1363 break;
1365 case WM_NCPAINT:
1366 if (*wparam <= 1) return TRUE;
1367 FIXME( "WM_NCPAINT hdc unpacking not supported\n" );
1368 return FALSE;
1369 case WM_PAINT:
1370 if (!*wparam) return TRUE;
1371 /* fall through */
1373 /* these contain an HFONT */
1374 case WM_SETFONT:
1375 case WM_GETFONT:
1376 /* these contain an HDC */
1377 case WM_ERASEBKGND:
1378 case WM_ICONERASEBKGND:
1379 case WM_CTLCOLORMSGBOX:
1380 case WM_CTLCOLOREDIT:
1381 case WM_CTLCOLORLISTBOX:
1382 case WM_CTLCOLORBTN:
1383 case WM_CTLCOLORDLG:
1384 case WM_CTLCOLORSCROLLBAR:
1385 case WM_CTLCOLORSTATIC:
1386 case WM_PRINT:
1387 case WM_PRINTCLIENT:
1388 /* these contain an HGLOBAL */
1389 case WM_PAINTCLIPBOARD:
1390 case WM_SIZECLIPBOARD:
1391 /* these contain HICON */
1392 case WM_GETICON:
1393 case WM_SETICON:
1394 case WM_QUERYDRAGICON:
1395 case WM_QUERYPARKICON:
1396 /* these contain pointers */
1397 case WM_DROPOBJECT:
1398 case WM_QUERYDROPOBJECT:
1399 case WM_DRAGLOOP:
1400 case WM_DRAGSELECT:
1401 case WM_DRAGMOVE:
1402 FIXME( "msg %x (%s) not supported yet\n", message, SPY_GetMsgName(message, hwnd) );
1403 return FALSE;
1405 default:
1406 return TRUE; /* message doesn't need any unpacking */
1409 /* default exit for most messages: check minsize and store buffer in lparam */
1410 if (size < minsize) return FALSE;
1411 *lparam = (LPARAM)*buffer;
1412 return TRUE;
1416 /***********************************************************************
1417 * pack_reply
1419 * Pack a reply to a message for sending to another process.
1421 static void pack_reply( HWND hwnd, UINT message, WPARAM wparam, LPARAM lparam,
1422 LRESULT res, struct packed_message *data )
1424 data->count = 0;
1425 switch(message)
1427 case WM_NCCREATE:
1428 case WM_CREATE:
1430 CREATESTRUCTW *cs = (CREATESTRUCTW *)lparam;
1431 data->ps.cs.lpCreateParams = (ULONG_PTR)cs->lpCreateParams;
1432 data->ps.cs.hInstance = (ULONG_PTR)cs->hInstance;
1433 data->ps.cs.hMenu = wine_server_user_handle( cs->hMenu );
1434 data->ps.cs.hwndParent = wine_server_user_handle( cs->hwndParent );
1435 data->ps.cs.cy = cs->cy;
1436 data->ps.cs.cx = cs->cx;
1437 data->ps.cs.y = cs->y;
1438 data->ps.cs.x = cs->x;
1439 data->ps.cs.style = cs->style;
1440 data->ps.cs.dwExStyle = cs->dwExStyle;
1441 data->ps.cs.lpszName = (ULONG_PTR)cs->lpszName;
1442 data->ps.cs.lpszClass = (ULONG_PTR)cs->lpszClass;
1443 push_data( data, &data->ps.cs, sizeof(data->ps.cs) );
1444 break;
1446 case WM_GETTEXT:
1447 case CB_GETLBTEXT:
1448 case LB_GETTEXT:
1449 push_data( data, (WCHAR *)lparam, (res + 1) * sizeof(WCHAR) );
1450 break;
1451 case WM_GETMINMAXINFO:
1452 push_data( data, (MINMAXINFO *)lparam, sizeof(MINMAXINFO) );
1453 break;
1454 case WM_MEASUREITEM:
1456 MEASUREITEMSTRUCT *mis = (MEASUREITEMSTRUCT *)lparam;
1457 data->ps.mis.CtlType = mis->CtlType;
1458 data->ps.mis.CtlID = mis->CtlID;
1459 data->ps.mis.itemID = mis->itemID;
1460 data->ps.mis.itemWidth = mis->itemWidth;
1461 data->ps.mis.itemHeight = mis->itemHeight;
1462 data->ps.mis.itemData = mis->itemData;
1463 push_data( data, &data->ps.mis, sizeof(data->ps.mis) );
1464 break;
1466 case WM_WINDOWPOSCHANGING:
1467 case WM_WINDOWPOSCHANGED:
1469 WINDOWPOS *wp = (WINDOWPOS *)lparam;
1470 data->ps.wp.hwnd = wine_server_user_handle( wp->hwnd );
1471 data->ps.wp.hwndInsertAfter = wine_server_user_handle( wp->hwndInsertAfter );
1472 data->ps.wp.x = wp->x;
1473 data->ps.wp.y = wp->y;
1474 data->ps.wp.cx = wp->cx;
1475 data->ps.wp.cy = wp->cy;
1476 data->ps.wp.flags = wp->flags;
1477 push_data( data, &data->ps.wp, sizeof(data->ps.wp) );
1478 break;
1480 case WM_GETDLGCODE:
1481 if (lparam)
1483 MSG *msg = (MSG *)lparam;
1484 data->ps.msg.hwnd = wine_server_user_handle( msg->hwnd );
1485 data->ps.msg.message = msg->message;
1486 data->ps.msg.wParam = msg->wParam;
1487 data->ps.msg.lParam = msg->lParam;
1488 data->ps.msg.time = msg->time;
1489 data->ps.msg.pt = msg->pt;
1490 push_data( data, &data->ps.msg, sizeof(data->ps.msg) );
1492 break;
1493 case SBM_GETSCROLLINFO:
1494 push_data( data, (SCROLLINFO *)lparam, sizeof(SCROLLINFO) );
1495 break;
1496 case EM_GETRECT:
1497 case LB_GETITEMRECT:
1498 case CB_GETDROPPEDCONTROLRECT:
1499 case WM_SIZING:
1500 case WM_MOVING:
1501 push_data( data, (RECT *)lparam, sizeof(RECT) );
1502 break;
1503 case EM_GETLINE:
1505 WORD *ptr = (WORD *)lparam;
1506 push_data( data, ptr, ptr[-1] * sizeof(WCHAR) );
1507 break;
1509 case LB_GETSELITEMS:
1510 push_data( data, (UINT *)lparam, wparam * sizeof(UINT) );
1511 break;
1512 case WM_MDIGETACTIVE:
1513 if (lparam) push_data( data, (BOOL *)lparam, sizeof(BOOL) );
1514 break;
1515 case WM_NCCALCSIZE:
1516 if (!wparam)
1517 push_data( data, (RECT *)lparam, sizeof(RECT) );
1518 else
1520 NCCALCSIZE_PARAMS *ncp = (NCCALCSIZE_PARAMS *)lparam;
1521 data->ps.ncp.rgrc[0] = ncp->rgrc[0];
1522 data->ps.ncp.rgrc[1] = ncp->rgrc[1];
1523 data->ps.ncp.rgrc[2] = ncp->rgrc[2];
1524 data->ps.ncp.hwnd = wine_server_user_handle( ncp->lppos->hwnd );
1525 data->ps.ncp.hwndInsertAfter = wine_server_user_handle( ncp->lppos->hwndInsertAfter );
1526 data->ps.ncp.x = ncp->lppos->x;
1527 data->ps.ncp.y = ncp->lppos->y;
1528 data->ps.ncp.cx = ncp->lppos->cx;
1529 data->ps.ncp.cy = ncp->lppos->cy;
1530 data->ps.ncp.flags = ncp->lppos->flags;
1531 push_data( data, &data->ps.ncp, sizeof(data->ps.ncp) );
1533 break;
1534 case EM_GETSEL:
1535 case SBM_GETRANGE:
1536 case CB_GETEDITSEL:
1537 if (wparam) push_data( data, (DWORD *)wparam, sizeof(DWORD) );
1538 if (lparam) push_data( data, (DWORD *)lparam, sizeof(DWORD) );
1539 break;
1540 case WM_NEXTMENU:
1541 push_data( data, (MDINEXTMENU *)lparam, sizeof(MDINEXTMENU) );
1542 break;
1543 case WM_MDICREATE:
1544 push_data( data, (MDICREATESTRUCTW *)lparam, sizeof(MDICREATESTRUCTW) );
1545 break;
1546 case WM_ASKCBFORMATNAME:
1547 push_data( data, (WCHAR *)lparam, (strlenW((WCHAR *)lparam) + 1) * sizeof(WCHAR) );
1548 break;
1553 /***********************************************************************
1554 * unpack_reply
1556 * Unpack a message reply received from another process.
1558 static void unpack_reply( HWND hwnd, UINT message, WPARAM wparam, LPARAM lparam,
1559 void *buffer, size_t size )
1561 union packed_structs *ps = buffer;
1563 switch(message)
1565 case WM_NCCREATE:
1566 case WM_CREATE:
1567 if (size >= sizeof(ps->cs))
1569 CREATESTRUCTW *cs = (CREATESTRUCTW *)lparam;
1570 cs->lpCreateParams = unpack_ptr( ps->cs.lpCreateParams );
1571 cs->hInstance = unpack_ptr( ps->cs.hInstance );
1572 cs->hMenu = wine_server_ptr_handle( ps->cs.hMenu );
1573 cs->hwndParent = wine_server_ptr_handle( ps->cs.hwndParent );
1574 cs->cy = ps->cs.cy;
1575 cs->cx = ps->cs.cx;
1576 cs->y = ps->cs.y;
1577 cs->x = ps->cs.x;
1578 cs->style = ps->cs.style;
1579 cs->dwExStyle = ps->cs.dwExStyle;
1580 /* don't allow changing name and class pointers */
1582 break;
1583 case WM_GETTEXT:
1584 case WM_ASKCBFORMATNAME:
1585 memcpy( (WCHAR *)lparam, buffer, min( wparam*sizeof(WCHAR), size ));
1586 break;
1587 case WM_GETMINMAXINFO:
1588 memcpy( (MINMAXINFO *)lparam, buffer, min( sizeof(MINMAXINFO), size ));
1589 break;
1590 case WM_MEASUREITEM:
1591 if (size >= sizeof(ps->mis))
1593 MEASUREITEMSTRUCT *mis = (MEASUREITEMSTRUCT *)lparam;
1594 mis->CtlType = ps->mis.CtlType;
1595 mis->CtlID = ps->mis.CtlID;
1596 mis->itemID = ps->mis.itemID;
1597 mis->itemWidth = ps->mis.itemWidth;
1598 mis->itemHeight = ps->mis.itemHeight;
1599 mis->itemData = (ULONG_PTR)unpack_ptr( ps->mis.itemData );
1601 break;
1602 case WM_WINDOWPOSCHANGING:
1603 case WM_WINDOWPOSCHANGED:
1604 if (size >= sizeof(ps->wp))
1606 WINDOWPOS *wp = (WINDOWPOS *)lparam;
1607 wp->hwnd = wine_server_ptr_handle( ps->wp.hwnd );
1608 wp->hwndInsertAfter = wine_server_ptr_handle( ps->wp.hwndInsertAfter );
1609 wp->x = ps->wp.x;
1610 wp->y = ps->wp.y;
1611 wp->cx = ps->wp.cx;
1612 wp->cy = ps->wp.cy;
1613 wp->flags = ps->wp.flags;
1615 break;
1616 case WM_GETDLGCODE:
1617 if (lparam && size >= sizeof(ps->msg))
1619 MSG *msg = (MSG *)lparam;
1620 msg->hwnd = wine_server_ptr_handle( ps->msg.hwnd );
1621 msg->message = ps->msg.message;
1622 msg->wParam = (ULONG_PTR)unpack_ptr( ps->msg.wParam );
1623 msg->lParam = (ULONG_PTR)unpack_ptr( ps->msg.lParam );
1624 msg->time = ps->msg.time;
1625 msg->pt = ps->msg.pt;
1627 break;
1628 case SBM_GETSCROLLINFO:
1629 memcpy( (SCROLLINFO *)lparam, buffer, min( sizeof(SCROLLINFO), size ));
1630 break;
1631 case SBM_GETSCROLLBARINFO:
1632 memcpy( (SCROLLBARINFO *)lparam, buffer, min( sizeof(SCROLLBARINFO), size ));
1633 break;
1634 case EM_GETRECT:
1635 case CB_GETDROPPEDCONTROLRECT:
1636 case LB_GETITEMRECT:
1637 case WM_SIZING:
1638 case WM_MOVING:
1639 memcpy( (RECT *)lparam, buffer, min( sizeof(RECT), size ));
1640 break;
1641 case EM_GETLINE:
1642 size = min( size, (size_t)*(WORD *)lparam );
1643 memcpy( (WCHAR *)lparam, buffer, size );
1644 break;
1645 case LB_GETSELITEMS:
1646 memcpy( (UINT *)lparam, buffer, min( wparam*sizeof(UINT), size ));
1647 break;
1648 case LB_GETTEXT:
1649 case CB_GETLBTEXT:
1650 memcpy( (WCHAR *)lparam, buffer, size );
1651 break;
1652 case WM_NEXTMENU:
1653 memcpy( (MDINEXTMENU *)lparam, buffer, min( sizeof(MDINEXTMENU), size ));
1654 break;
1655 case WM_MDIGETACTIVE:
1656 if (lparam) memcpy( (BOOL *)lparam, buffer, min( sizeof(BOOL), size ));
1657 break;
1658 case WM_NCCALCSIZE:
1659 if (!wparam)
1660 memcpy( (RECT *)lparam, buffer, min( sizeof(RECT), size ));
1661 else if (size >= sizeof(ps->ncp))
1663 NCCALCSIZE_PARAMS *ncp = (NCCALCSIZE_PARAMS *)lparam;
1664 ncp->rgrc[0] = ps->ncp.rgrc[0];
1665 ncp->rgrc[1] = ps->ncp.rgrc[1];
1666 ncp->rgrc[2] = ps->ncp.rgrc[2];
1667 ncp->lppos->hwnd = wine_server_ptr_handle( ps->ncp.hwnd );
1668 ncp->lppos->hwndInsertAfter = wine_server_ptr_handle( ps->ncp.hwndInsertAfter );
1669 ncp->lppos->x = ps->ncp.x;
1670 ncp->lppos->y = ps->ncp.y;
1671 ncp->lppos->cx = ps->ncp.cx;
1672 ncp->lppos->cy = ps->ncp.cy;
1673 ncp->lppos->flags = ps->ncp.flags;
1675 break;
1676 case EM_GETSEL:
1677 case SBM_GETRANGE:
1678 case CB_GETEDITSEL:
1679 if (wparam)
1681 memcpy( (DWORD *)wparam, buffer, min( sizeof(DWORD), size ));
1682 if (size <= sizeof(DWORD)) break;
1683 size -= sizeof(DWORD);
1684 buffer = (DWORD *)buffer + 1;
1686 if (lparam) memcpy( (DWORD *)lparam, buffer, min( sizeof(DWORD), size ));
1687 break;
1688 case WM_MDICREATE:
1690 MDICREATESTRUCTW *cs = (MDICREATESTRUCTW *)lparam;
1691 LPCWSTR title = cs->szTitle, class = cs->szClass;
1692 memcpy( cs, buffer, min( sizeof(*cs), size ));
1693 cs->szTitle = title; /* restore the original pointers */
1694 cs->szClass = class;
1695 break;
1697 default:
1698 ERR( "should not happen: unexpected message %x\n", message );
1699 break;
1704 /***********************************************************************
1705 * reply_message
1707 * Send a reply to a sent message.
1709 static void reply_message( struct received_message_info *info, LRESULT result, BOOL remove )
1711 struct packed_message data;
1712 int i, replied = info->flags & ISMEX_REPLIED;
1714 if (info->flags & ISMEX_NOTIFY) return; /* notify messages don't get replies */
1715 if (!remove && replied) return; /* replied already */
1717 memset( &data, 0, sizeof(data) );
1718 info->flags |= ISMEX_REPLIED;
1720 if (info->type == MSG_OTHER_PROCESS && !replied)
1722 pack_reply( info->msg.hwnd, info->msg.message, info->msg.wParam,
1723 info->msg.lParam, result, &data );
1726 SERVER_START_REQ( reply_message )
1728 req->result = result;
1729 req->remove = remove;
1730 for (i = 0; i < data.count; i++) wine_server_add_data( req, data.data[i], data.size[i] );
1731 wine_server_call( req );
1733 SERVER_END_REQ;
1737 /***********************************************************************
1738 * handle_internal_message
1740 * Handle an internal Wine message instead of calling the window proc.
1742 static LRESULT handle_internal_message( HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam )
1744 switch(msg)
1746 case WM_WINE_DESTROYWINDOW:
1747 return WIN_DestroyWindow( hwnd );
1748 case WM_WINE_SETWINDOWPOS:
1749 if (is_desktop_window( hwnd )) return 0;
1750 return USER_SetWindowPos( (WINDOWPOS *)lparam );
1751 case WM_WINE_SHOWWINDOW:
1752 if (is_desktop_window( hwnd )) return 0;
1753 return ShowWindow( hwnd, wparam );
1754 case WM_WINE_SETPARENT:
1755 if (is_desktop_window( hwnd )) return 0;
1756 return (LRESULT)SetParent( hwnd, (HWND)wparam );
1757 case WM_WINE_SETWINDOWLONG:
1758 return WIN_SetWindowLong( hwnd, (short)LOWORD(wparam), HIWORD(wparam), lparam, TRUE );
1759 case WM_WINE_ENABLEWINDOW:
1760 if (is_desktop_window( hwnd )) return 0;
1761 return EnableWindow( hwnd, wparam );
1762 case WM_WINE_SETACTIVEWINDOW:
1763 if (is_desktop_window( hwnd )) return 0;
1764 return (LRESULT)SetActiveWindow( (HWND)wparam );
1765 case WM_WINE_KEYBOARD_LL_HOOK:
1766 case WM_WINE_MOUSE_LL_HOOK:
1768 struct hook_extra_info *h_extra = (struct hook_extra_info *)lparam;
1770 return call_current_hook( h_extra->handle, HC_ACTION, wparam, h_extra->lparam );
1772 default:
1773 if (msg >= WM_WINE_FIRST_DRIVER_MSG && msg <= WM_WINE_LAST_DRIVER_MSG)
1774 return USER_Driver->pWindowMessage( hwnd, msg, wparam, lparam );
1775 FIXME( "unknown internal message %x\n", msg );
1776 return 0;
1780 /* since the WM_DDE_ACK response to a WM_DDE_EXECUTE message should contain the handle
1781 * to the memory handle, we keep track (in the server side) of all pairs of handle
1782 * used (the client passes its value and the content of the memory handle), and
1783 * the server stored both values (the client, and the local one, created after the
1784 * content). When a ACK message is generated, the list of pair is searched for a
1785 * matching pair, so that the client memory handle can be returned.
1787 struct DDE_pair {
1788 HGLOBAL client_hMem;
1789 HGLOBAL server_hMem;
1792 static struct DDE_pair* dde_pairs;
1793 static int dde_num_alloc;
1794 static int dde_num_used;
1796 static CRITICAL_SECTION dde_crst;
1797 static CRITICAL_SECTION_DEBUG critsect_debug =
1799 0, 0, &dde_crst,
1800 { &critsect_debug.ProcessLocksList, &critsect_debug.ProcessLocksList },
1801 0, 0, { (DWORD_PTR)(__FILE__ ": dde_crst") }
1803 static CRITICAL_SECTION dde_crst = { &critsect_debug, -1, 0, 0, 0, 0 };
1805 static BOOL dde_add_pair(HGLOBAL chm, HGLOBAL shm)
1807 int i;
1808 #define GROWBY 4
1810 EnterCriticalSection(&dde_crst);
1812 /* now remember the pair of hMem on both sides */
1813 if (dde_num_used == dde_num_alloc)
1815 struct DDE_pair* tmp;
1816 if (dde_pairs)
1817 tmp = HeapReAlloc( GetProcessHeap(), 0, dde_pairs,
1818 (dde_num_alloc + GROWBY) * sizeof(struct DDE_pair));
1819 else
1820 tmp = HeapAlloc( GetProcessHeap(), 0,
1821 (dde_num_alloc + GROWBY) * sizeof(struct DDE_pair));
1823 if (!tmp)
1825 LeaveCriticalSection(&dde_crst);
1826 return FALSE;
1828 dde_pairs = tmp;
1829 /* zero out newly allocated part */
1830 memset(&dde_pairs[dde_num_alloc], 0, GROWBY * sizeof(struct DDE_pair));
1831 dde_num_alloc += GROWBY;
1833 #undef GROWBY
1834 for (i = 0; i < dde_num_alloc; i++)
1836 if (dde_pairs[i].server_hMem == 0)
1838 dde_pairs[i].client_hMem = chm;
1839 dde_pairs[i].server_hMem = shm;
1840 dde_num_used++;
1841 break;
1844 LeaveCriticalSection(&dde_crst);
1845 return TRUE;
1848 static HGLOBAL dde_get_pair(HGLOBAL shm)
1850 int i;
1851 HGLOBAL ret = 0;
1853 EnterCriticalSection(&dde_crst);
1854 for (i = 0; i < dde_num_alloc; i++)
1856 if (dde_pairs[i].server_hMem == shm)
1858 /* free this pair */
1859 dde_pairs[i].server_hMem = 0;
1860 dde_num_used--;
1861 ret = dde_pairs[i].client_hMem;
1862 break;
1865 LeaveCriticalSection(&dde_crst);
1866 return ret;
1869 /***********************************************************************
1870 * post_dde_message
1872 * Post a DDE message
1874 static BOOL post_dde_message( struct packed_message *data, const struct send_message_info *info )
1876 void* ptr = NULL;
1877 int size = 0;
1878 UINT_PTR uiLo, uiHi;
1879 LPARAM lp = 0;
1880 HGLOBAL hunlock = 0;
1881 int i;
1882 DWORD res;
1884 if (!UnpackDDElParam( info->msg, info->lparam, &uiLo, &uiHi ))
1885 return FALSE;
1887 lp = info->lparam;
1888 switch (info->msg)
1890 /* DDE messages which don't require packing are:
1891 * WM_DDE_INITIATE
1892 * WM_DDE_TERMINATE
1893 * WM_DDE_REQUEST
1894 * WM_DDE_UNADVISE
1896 case WM_DDE_ACK:
1897 if (HIWORD(uiHi))
1899 /* uiHi should contain a hMem from WM_DDE_EXECUTE */
1900 HGLOBAL h = dde_get_pair( (HANDLE)uiHi );
1901 if (h)
1903 /* send back the value of h on the other side */
1904 push_data( data, &h, sizeof(HGLOBAL) );
1905 lp = uiLo;
1906 TRACE( "send dde-ack %lx %08lx => %p\n", uiLo, uiHi, h );
1909 else
1911 /* uiHi should contain either an atom or 0 */
1912 TRACE( "send dde-ack %lx atom=%lx\n", uiLo, uiHi );
1913 lp = MAKELONG( uiLo, uiHi );
1915 break;
1916 case WM_DDE_ADVISE:
1917 case WM_DDE_DATA:
1918 case WM_DDE_POKE:
1919 size = 0;
1920 if (uiLo)
1922 size = GlobalSize( (HGLOBAL)uiLo ) ;
1923 if ((info->msg == WM_DDE_ADVISE && size < sizeof(DDEADVISE)) ||
1924 (info->msg == WM_DDE_DATA && size < FIELD_OFFSET(DDEDATA, Value)) ||
1925 (info->msg == WM_DDE_POKE && size < FIELD_OFFSET(DDEPOKE, Value))
1927 return FALSE;
1929 else if (info->msg != WM_DDE_DATA) return FALSE;
1931 lp = uiHi;
1932 if (uiLo)
1934 if ((ptr = GlobalLock( (HGLOBAL)uiLo) ))
1936 DDEDATA *dde_data = ptr;
1937 TRACE("unused %d, fResponse %d, fRelease %d, fDeferUpd %d, fAckReq %d, cfFormat %d\n",
1938 dde_data->unused, dde_data->fResponse, dde_data->fRelease,
1939 dde_data->reserved, dde_data->fAckReq, dde_data->cfFormat);
1940 push_data( data, ptr, size );
1941 hunlock = (HGLOBAL)uiLo;
1944 TRACE( "send ddepack %u %lx\n", size, uiHi );
1945 break;
1946 case WM_DDE_EXECUTE:
1947 if (info->lparam)
1949 if ((ptr = GlobalLock( (HGLOBAL)info->lparam) ))
1951 push_data(data, ptr, GlobalSize( (HGLOBAL)info->lparam ));
1952 /* so that the other side can send it back on ACK */
1953 lp = info->lparam;
1954 hunlock = (HGLOBAL)info->lparam;
1957 break;
1959 SERVER_START_REQ( send_message )
1961 req->id = info->dest_tid;
1962 req->type = info->type;
1963 req->flags = 0;
1964 req->win = wine_server_user_handle( info->hwnd );
1965 req->msg = info->msg;
1966 req->wparam = info->wparam;
1967 req->lparam = lp;
1968 req->timeout = TIMEOUT_INFINITE;
1969 for (i = 0; i < data->count; i++)
1970 wine_server_add_data( req, data->data[i], data->size[i] );
1971 if ((res = wine_server_call( req )))
1973 if (res == STATUS_INVALID_PARAMETER)
1974 /* FIXME: find a STATUS_ value for this one */
1975 SetLastError( ERROR_INVALID_THREAD_ID );
1976 else
1977 SetLastError( RtlNtStatusToDosError(res) );
1979 else
1980 FreeDDElParam(info->msg, info->lparam);
1982 SERVER_END_REQ;
1983 if (hunlock) GlobalUnlock(hunlock);
1985 return !res;
1988 /***********************************************************************
1989 * unpack_dde_message
1991 * Unpack a posted DDE message received from another process.
1993 static BOOL unpack_dde_message( HWND hwnd, UINT message, WPARAM *wparam, LPARAM *lparam,
1994 void **buffer, size_t size )
1996 UINT_PTR uiLo, uiHi;
1997 HGLOBAL hMem = 0;
1998 void* ptr;
2000 switch (message)
2002 case WM_DDE_ACK:
2003 if (size)
2005 /* hMem is being passed */
2006 if (size != sizeof(HGLOBAL)) return FALSE;
2007 if (!buffer || !*buffer) return FALSE;
2008 uiLo = *lparam;
2009 memcpy( &hMem, *buffer, size );
2010 uiHi = (UINT_PTR)hMem;
2011 TRACE("recv dde-ack %lx mem=%lx[%lx]\n", uiLo, uiHi, GlobalSize( hMem ));
2013 else
2015 uiLo = LOWORD( *lparam );
2016 uiHi = HIWORD( *lparam );
2017 TRACE("recv dde-ack %lx atom=%lx\n", uiLo, uiHi);
2019 *lparam = PackDDElParam( WM_DDE_ACK, uiLo, uiHi );
2020 break;
2021 case WM_DDE_ADVISE:
2022 case WM_DDE_DATA:
2023 case WM_DDE_POKE:
2024 if ((!buffer || !*buffer) && message != WM_DDE_DATA) return FALSE;
2025 uiHi = *lparam;
2026 if (size)
2028 if (!(hMem = GlobalAlloc( GMEM_MOVEABLE|GMEM_DDESHARE, size )))
2029 return FALSE;
2030 if ((ptr = GlobalLock( hMem )))
2032 memcpy( ptr, *buffer, size );
2033 GlobalUnlock( hMem );
2035 else
2037 GlobalFree( hMem );
2038 return FALSE;
2041 uiLo = (UINT_PTR)hMem;
2043 *lparam = PackDDElParam( message, uiLo, uiHi );
2044 break;
2045 case WM_DDE_EXECUTE:
2046 if (size)
2048 if (!buffer || !*buffer) return FALSE;
2049 if (!(hMem = GlobalAlloc( GMEM_MOVEABLE|GMEM_DDESHARE, size ))) return FALSE;
2050 if ((ptr = GlobalLock( hMem )))
2052 memcpy( ptr, *buffer, size );
2053 GlobalUnlock( hMem );
2054 TRACE( "exec: pairing c=%08lx s=%p\n", *lparam, hMem );
2055 if (!dde_add_pair( (HGLOBAL)*lparam, hMem ))
2057 GlobalFree( hMem );
2058 return FALSE;
2061 else
2063 GlobalFree( hMem );
2064 return FALSE;
2066 } else return FALSE;
2067 *lparam = (LPARAM)hMem;
2068 break;
2070 return TRUE;
2073 /***********************************************************************
2074 * call_window_proc
2076 * Call a window procedure and the corresponding hooks.
2078 static LRESULT call_window_proc( HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam,
2079 BOOL unicode, BOOL same_thread, enum wm_char_mapping mapping )
2081 LRESULT result = 0;
2082 CWPSTRUCT cwp;
2083 CWPRETSTRUCT cwpret;
2085 if (msg & 0x80000000)
2087 result = handle_internal_message( hwnd, msg, wparam, lparam );
2088 goto done;
2091 /* first the WH_CALLWNDPROC hook */
2092 hwnd = WIN_GetFullHandle( hwnd );
2093 cwp.lParam = lparam;
2094 cwp.wParam = wparam;
2095 cwp.message = msg;
2096 cwp.hwnd = hwnd;
2097 HOOK_CallHooks( WH_CALLWNDPROC, HC_ACTION, same_thread, (LPARAM)&cwp, unicode );
2099 /* now call the window procedure */
2100 if (!WINPROC_call_window( hwnd, msg, wparam, lparam, &result, unicode, mapping )) goto done;
2102 /* and finally the WH_CALLWNDPROCRET hook */
2103 cwpret.lResult = result;
2104 cwpret.lParam = lparam;
2105 cwpret.wParam = wparam;
2106 cwpret.message = msg;
2107 cwpret.hwnd = hwnd;
2108 HOOK_CallHooks( WH_CALLWNDPROCRET, HC_ACTION, same_thread, (LPARAM)&cwpret, unicode );
2109 done:
2110 return result;
2114 /***********************************************************************
2115 * send_parent_notify
2117 * Send a WM_PARENTNOTIFY to all ancestors of the given window, unless
2118 * the window has the WS_EX_NOPARENTNOTIFY style.
2120 static void send_parent_notify( HWND hwnd, WORD event, WORD idChild, POINT pt )
2122 /* pt has to be in the client coordinates of the parent window */
2123 MapWindowPoints( 0, hwnd, &pt, 1 );
2124 for (;;)
2126 HWND parent;
2128 if (!(GetWindowLongW( hwnd, GWL_STYLE ) & WS_CHILD)) break;
2129 if (GetWindowLongW( hwnd, GWL_EXSTYLE ) & WS_EX_NOPARENTNOTIFY) break;
2130 if (!(parent = GetParent(hwnd))) break;
2131 if (parent == GetDesktopWindow()) break;
2132 MapWindowPoints( hwnd, parent, &pt, 1 );
2133 hwnd = parent;
2134 SendMessageW( hwnd, WM_PARENTNOTIFY,
2135 MAKEWPARAM( event, idChild ), MAKELPARAM( pt.x, pt.y ) );
2140 /***********************************************************************
2141 * accept_hardware_message
2143 * Tell the server we have passed the message to the app
2144 * (even though we may end up dropping it later on)
2146 static void accept_hardware_message( UINT hw_id, BOOL remove, HWND new_hwnd )
2148 SERVER_START_REQ( accept_hardware_message )
2150 req->hw_id = hw_id;
2151 req->remove = remove;
2152 req->new_win = wine_server_user_handle( new_hwnd );
2153 if (wine_server_call( req ))
2154 FIXME("Failed to reply to MSG_HARDWARE message. Message may not be removed from queue.\n");
2156 SERVER_END_REQ;
2160 /***********************************************************************
2161 * process_keyboard_message
2163 * returns TRUE if the contents of 'msg' should be passed to the application
2165 static BOOL process_keyboard_message( MSG *msg, UINT hw_id, HWND hwnd_filter,
2166 UINT first, UINT last, BOOL remove )
2168 EVENTMSG event;
2170 if (msg->message == WM_KEYDOWN || msg->message == WM_SYSKEYDOWN ||
2171 msg->message == WM_KEYUP || msg->message == WM_SYSKEYUP)
2172 switch (msg->wParam)
2174 case VK_LSHIFT: case VK_RSHIFT:
2175 msg->wParam = VK_SHIFT;
2176 break;
2177 case VK_LCONTROL: case VK_RCONTROL:
2178 msg->wParam = VK_CONTROL;
2179 break;
2180 case VK_LMENU: case VK_RMENU:
2181 msg->wParam = VK_MENU;
2182 break;
2185 /* FIXME: is this really the right place for this hook? */
2186 event.message = msg->message;
2187 event.hwnd = msg->hwnd;
2188 event.time = msg->time;
2189 event.paramL = (msg->wParam & 0xFF) | (HIWORD(msg->lParam) << 8);
2190 event.paramH = msg->lParam & 0x7FFF;
2191 if (HIWORD(msg->lParam) & 0x0100) event.paramH |= 0x8000; /* special_key - bit */
2192 HOOK_CallHooks( WH_JOURNALRECORD, HC_ACTION, 0, (LPARAM)&event, TRUE );
2194 /* check message filters */
2195 if (msg->message < first || msg->message > last) return FALSE;
2196 if (!check_hwnd_filter( msg, hwnd_filter )) return FALSE;
2198 if (remove)
2200 if((msg->message == WM_KEYDOWN) &&
2201 (msg->hwnd != GetDesktopWindow()))
2203 /* Handle F1 key by sending out WM_HELP message */
2204 if (msg->wParam == VK_F1)
2206 PostMessageW( msg->hwnd, WM_KEYF1, 0, 0 );
2208 else if(msg->wParam >= VK_BROWSER_BACK &&
2209 msg->wParam <= VK_LAUNCH_APP2)
2211 /* FIXME: Process keystate */
2212 SendMessageW(msg->hwnd, WM_APPCOMMAND, (WPARAM)msg->hwnd, MAKELPARAM(0, (FAPPCOMMAND_KEY | (msg->wParam - VK_BROWSER_BACK + 1))));
2215 else if (msg->message == WM_KEYUP)
2217 /* Handle VK_APPS key by posting a WM_CONTEXTMENU message */
2218 if (msg->wParam == VK_APPS && !MENU_IsMenuActive())
2219 PostMessageW(msg->hwnd, WM_CONTEXTMENU, (WPARAM)msg->hwnd, -1);
2223 if (HOOK_CallHooks( WH_KEYBOARD, remove ? HC_ACTION : HC_NOREMOVE,
2224 LOWORD(msg->wParam), msg->lParam, TRUE ))
2226 /* skip this message */
2227 HOOK_CallHooks( WH_CBT, HCBT_KEYSKIPPED, LOWORD(msg->wParam), msg->lParam, TRUE );
2228 accept_hardware_message( hw_id, TRUE, 0 );
2229 return FALSE;
2231 accept_hardware_message( hw_id, remove, 0 );
2233 if ( msg->message == WM_KEYDOWN || msg->message == WM_KEYUP )
2234 if ( ImmProcessKey(msg->hwnd, GetKeyboardLayout(0), msg->wParam, msg->lParam, 0) )
2235 msg->wParam = VK_PROCESSKEY;
2237 return TRUE;
2241 /***********************************************************************
2242 * process_mouse_message
2244 * returns TRUE if the contents of 'msg' should be passed to the application
2246 static BOOL process_mouse_message( MSG *msg, UINT hw_id, ULONG_PTR extra_info, HWND hwnd_filter,
2247 UINT first, UINT last, BOOL remove )
2249 static MSG clk_msg;
2251 POINT pt;
2252 UINT message;
2253 INT hittest;
2254 EVENTMSG event;
2255 GUITHREADINFO info;
2256 MOUSEHOOKSTRUCT hook;
2257 BOOL eatMsg;
2259 /* find the window to dispatch this mouse message to */
2261 GetGUIThreadInfo( GetCurrentThreadId(), &info );
2262 if (info.hwndCapture)
2264 hittest = HTCLIENT;
2265 msg->hwnd = info.hwndCapture;
2267 else
2269 msg->hwnd = WINPOS_WindowFromPoint( msg->hwnd, msg->pt, &hittest );
2272 if (!msg->hwnd || !WIN_IsCurrentThread( msg->hwnd ))
2274 accept_hardware_message( hw_id, TRUE, msg->hwnd );
2275 return FALSE;
2278 /* FIXME: is this really the right place for this hook? */
2279 event.message = msg->message;
2280 event.time = msg->time;
2281 event.hwnd = msg->hwnd;
2282 event.paramL = msg->pt.x;
2283 event.paramH = msg->pt.y;
2284 HOOK_CallHooks( WH_JOURNALRECORD, HC_ACTION, 0, (LPARAM)&event, TRUE );
2286 if (!check_hwnd_filter( msg, hwnd_filter )) return FALSE;
2288 pt = msg->pt;
2289 message = msg->message;
2290 /* Note: windows has no concept of a non-client wheel message */
2291 if (message != WM_MOUSEWHEEL)
2293 if (hittest != HTCLIENT)
2295 message += WM_NCMOUSEMOVE - WM_MOUSEMOVE;
2296 msg->wParam = hittest;
2298 else
2300 /* coordinates don't get translated while tracking a menu */
2301 /* FIXME: should differentiate popups and top-level menus */
2302 if (!(info.flags & GUI_INMENUMODE))
2303 ScreenToClient( msg->hwnd, &pt );
2306 msg->lParam = MAKELONG( pt.x, pt.y );
2308 /* translate double clicks */
2310 if ((msg->message == WM_LBUTTONDOWN) ||
2311 (msg->message == WM_RBUTTONDOWN) ||
2312 (msg->message == WM_MBUTTONDOWN) ||
2313 (msg->message == WM_XBUTTONDOWN))
2315 BOOL update = remove;
2317 /* translate double clicks -
2318 * note that ...MOUSEMOVEs can slip in between
2319 * ...BUTTONDOWN and ...BUTTONDBLCLK messages */
2321 if ((info.flags & (GUI_INMENUMODE|GUI_INMOVESIZE)) ||
2322 hittest != HTCLIENT ||
2323 (GetClassLongA( msg->hwnd, GCL_STYLE ) & CS_DBLCLKS))
2325 if ((msg->message == clk_msg.message) &&
2326 (msg->hwnd == clk_msg.hwnd) &&
2327 (msg->wParam == clk_msg.wParam) &&
2328 (msg->time - clk_msg.time < GetDoubleClickTime()) &&
2329 (abs(msg->pt.x - clk_msg.pt.x) < GetSystemMetrics(SM_CXDOUBLECLK)/2) &&
2330 (abs(msg->pt.y - clk_msg.pt.y) < GetSystemMetrics(SM_CYDOUBLECLK)/2))
2332 message += (WM_LBUTTONDBLCLK - WM_LBUTTONDOWN);
2333 if (update)
2335 clk_msg.message = 0; /* clear the double click conditions */
2336 update = FALSE;
2340 if (message < first || message > last) return FALSE;
2341 /* update static double click conditions */
2342 if (update) clk_msg = *msg;
2344 else
2346 if (message < first || message > last) return FALSE;
2349 /* message is accepted now (but may still get dropped) */
2351 hook.pt = msg->pt;
2352 hook.hwnd = msg->hwnd;
2353 hook.wHitTestCode = hittest;
2354 hook.dwExtraInfo = extra_info;
2355 if (HOOK_CallHooks( WH_MOUSE, remove ? HC_ACTION : HC_NOREMOVE,
2356 message, (LPARAM)&hook, TRUE ))
2358 hook.pt = msg->pt;
2359 hook.hwnd = msg->hwnd;
2360 hook.wHitTestCode = hittest;
2361 hook.dwExtraInfo = extra_info;
2362 HOOK_CallHooks( WH_CBT, HCBT_CLICKSKIPPED, message, (LPARAM)&hook, TRUE );
2363 accept_hardware_message( hw_id, TRUE, 0 );
2364 return FALSE;
2367 if ((hittest == HTERROR) || (hittest == HTNOWHERE))
2369 SendMessageW( msg->hwnd, WM_SETCURSOR, (WPARAM)msg->hwnd,
2370 MAKELONG( hittest, msg->message ));
2371 accept_hardware_message( hw_id, TRUE, 0 );
2372 return FALSE;
2375 accept_hardware_message( hw_id, remove, 0 );
2377 if (!remove || info.hwndCapture)
2379 msg->message = message;
2380 return TRUE;
2383 eatMsg = FALSE;
2385 if ((msg->message == WM_LBUTTONDOWN) ||
2386 (msg->message == WM_RBUTTONDOWN) ||
2387 (msg->message == WM_MBUTTONDOWN) ||
2388 (msg->message == WM_XBUTTONDOWN))
2390 /* Send the WM_PARENTNOTIFY,
2391 * note that even for double/nonclient clicks
2392 * notification message is still WM_L/M/RBUTTONDOWN.
2394 send_parent_notify( msg->hwnd, msg->message, 0, msg->pt );
2396 /* Activate the window if needed */
2398 if (msg->hwnd != info.hwndActive)
2400 HWND hwndTop = msg->hwnd;
2401 while (hwndTop)
2403 if ((GetWindowLongW( hwndTop, GWL_STYLE ) & (WS_POPUP|WS_CHILD)) != WS_CHILD) break;
2404 hwndTop = GetParent( hwndTop );
2407 if (hwndTop && hwndTop != GetDesktopWindow())
2409 LONG ret = SendMessageW( msg->hwnd, WM_MOUSEACTIVATE, (WPARAM)hwndTop,
2410 MAKELONG( hittest, msg->message ) );
2411 switch(ret)
2413 case MA_NOACTIVATEANDEAT:
2414 eatMsg = TRUE;
2415 /* fall through */
2416 case MA_NOACTIVATE:
2417 break;
2418 case MA_ACTIVATEANDEAT:
2419 eatMsg = TRUE;
2420 /* fall through */
2421 case MA_ACTIVATE:
2422 case 0:
2423 if (!FOCUS_MouseActivate( hwndTop )) eatMsg = TRUE;
2424 break;
2425 default:
2426 WARN( "unknown WM_MOUSEACTIVATE code %d\n", ret );
2427 break;
2433 /* send the WM_SETCURSOR message */
2435 /* Windows sends the normal mouse message as the message parameter
2436 in the WM_SETCURSOR message even if it's non-client mouse message */
2437 SendMessageW( msg->hwnd, WM_SETCURSOR, (WPARAM)msg->hwnd, MAKELONG( hittest, msg->message ));
2439 msg->message = message;
2440 return !eatMsg;
2444 /***********************************************************************
2445 * process_hardware_message
2447 * Process a hardware message; return TRUE if message should be passed on to the app
2449 static BOOL process_hardware_message( MSG *msg, UINT hw_id, ULONG_PTR extra_info, HWND hwnd_filter,
2450 UINT first, UINT last, BOOL remove )
2452 if (is_keyboard_message( msg->message ))
2453 return process_keyboard_message( msg, hw_id, hwnd_filter, first, last, remove );
2455 if (is_mouse_message( msg->message ))
2456 return process_mouse_message( msg, hw_id, extra_info, hwnd_filter, first, last, remove );
2458 ERR( "unknown message type %x\n", msg->message );
2459 return FALSE;
2463 /***********************************************************************
2464 * call_sendmsg_callback
2466 * Call the callback function of SendMessageCallback.
2468 static inline void call_sendmsg_callback( SENDASYNCPROC callback, HWND hwnd, UINT msg,
2469 ULONG_PTR data, LRESULT result )
2471 if (!callback) return;
2473 if (TRACE_ON(relay))
2474 DPRINTF( "%04x:Call message callback %p (hwnd=%p,msg=%s,data=%08lx,result=%08lx)\n",
2475 GetCurrentThreadId(), callback, hwnd, SPY_GetMsgName( msg, hwnd ),
2476 data, result );
2477 callback( hwnd, msg, data, result );
2478 if (TRACE_ON(relay))
2479 DPRINTF( "%04x:Ret message callback %p (hwnd=%p,msg=%s,data=%08lx,result=%08lx)\n",
2480 GetCurrentThreadId(), callback, hwnd, SPY_GetMsgName( msg, hwnd ),
2481 data, result );
2485 /***********************************************************************
2486 * peek_message
2488 * Peek for a message matching the given parameters. Return FALSE if none available.
2489 * All pending sent messages are processed before returning.
2491 static BOOL peek_message( MSG *msg, HWND hwnd, UINT first, UINT last, UINT flags, UINT changed_mask )
2493 LRESULT result;
2494 struct user_thread_info *thread_info = get_user_thread_info();
2495 struct received_message_info info, *old_info;
2496 unsigned int hw_id = 0; /* id of previous hardware message */
2497 void *buffer;
2498 size_t buffer_size = 256;
2500 if (!(buffer = HeapAlloc( GetProcessHeap(), 0, buffer_size ))) return FALSE;
2502 if (!first && !last) last = ~0;
2503 if (hwnd == HWND_BROADCAST) hwnd = HWND_TOPMOST;
2505 for (;;)
2507 NTSTATUS res;
2508 size_t size = 0;
2509 const message_data_t *msg_data = buffer;
2511 SERVER_START_REQ( get_message )
2513 req->flags = flags;
2514 req->get_win = wine_server_user_handle( hwnd );
2515 req->get_first = first;
2516 req->get_last = last;
2517 req->hw_id = hw_id;
2518 req->wake_mask = changed_mask & (QS_SENDMESSAGE | QS_SMRESULT);
2519 req->changed_mask = changed_mask;
2520 wine_server_set_reply( req, buffer, buffer_size );
2521 if (!(res = wine_server_call( req )))
2523 size = wine_server_reply_size( reply );
2524 info.type = reply->type;
2525 info.msg.hwnd = wine_server_ptr_handle( reply->win );
2526 info.msg.message = reply->msg;
2527 info.msg.wParam = reply->wparam;
2528 info.msg.lParam = reply->lparam;
2529 info.msg.time = reply->time;
2530 info.msg.pt.x = 0;
2531 info.msg.pt.y = 0;
2532 hw_id = 0;
2533 thread_info->active_hooks = reply->active_hooks;
2535 else buffer_size = reply->total;
2537 SERVER_END_REQ;
2539 if (res)
2541 HeapFree( GetProcessHeap(), 0, buffer );
2542 if (res != STATUS_BUFFER_OVERFLOW) return FALSE;
2543 if (!(buffer = HeapAlloc( GetProcessHeap(), 0, buffer_size ))) return FALSE;
2544 continue;
2547 TRACE( "got type %d msg %x (%s) hwnd %p wp %lx lp %lx\n",
2548 info.type, info.msg.message,
2549 (info.type == MSG_WINEVENT) ? "MSG_WINEVENT" : SPY_GetMsgName(info.msg.message, info.msg.hwnd),
2550 info.msg.hwnd, info.msg.wParam, info.msg.lParam );
2552 switch(info.type)
2554 case MSG_ASCII:
2555 case MSG_UNICODE:
2556 info.flags = ISMEX_SEND;
2557 break;
2558 case MSG_NOTIFY:
2559 info.flags = ISMEX_NOTIFY;
2560 break;
2561 case MSG_CALLBACK:
2562 info.flags = ISMEX_CALLBACK;
2563 break;
2564 case MSG_CALLBACK_RESULT:
2565 if (size >= sizeof(msg_data->callback))
2566 call_sendmsg_callback( wine_server_get_ptr(msg_data->callback.callback),
2567 info.msg.hwnd, info.msg.message,
2568 msg_data->callback.data, msg_data->callback.result );
2569 continue;
2570 case MSG_WINEVENT:
2571 if (size >= sizeof(msg_data->winevent))
2573 WINEVENTPROC hook_proc;
2575 hook_proc = wine_server_get_ptr( msg_data->winevent.hook_proc );
2576 size -= sizeof(msg_data->winevent);
2577 if (size)
2579 WCHAR module[MAX_PATH];
2581 size = min( size, (MAX_PATH - 1) * sizeof(WCHAR) );
2582 memcpy( module, &msg_data->winevent + 1, size );
2583 module[size / sizeof(WCHAR)] = 0;
2584 if (!(hook_proc = get_hook_proc( hook_proc, module )))
2586 ERR( "invalid winevent hook module name %s\n", debugstr_w(module) );
2587 continue;
2591 if (TRACE_ON(relay))
2592 DPRINTF( "%04x:Call winevent proc %p (hook=%04x,event=%x,hwnd=%p,object_id=%lx,child_id=%lx,tid=%04x,time=%x)\n",
2593 GetCurrentThreadId(), hook_proc,
2594 msg_data->winevent.hook, info.msg.message, info.msg.hwnd, info.msg.wParam,
2595 info.msg.lParam, msg_data->winevent.tid, info.msg.time);
2597 hook_proc( wine_server_ptr_handle( msg_data->winevent.hook ), info.msg.message,
2598 info.msg.hwnd, info.msg.wParam, info.msg.lParam,
2599 msg_data->winevent.tid, info.msg.time );
2601 if (TRACE_ON(relay))
2602 DPRINTF( "%04x:Ret winevent proc %p (hook=%04x,event=%x,hwnd=%p,object_id=%lx,child_id=%lx,tid=%04x,time=%x)\n",
2603 GetCurrentThreadId(), hook_proc,
2604 msg_data->winevent.hook, info.msg.message, info.msg.hwnd, info.msg.wParam,
2605 info.msg.lParam, msg_data->winevent.tid, info.msg.time);
2607 continue;
2608 case MSG_OTHER_PROCESS:
2609 info.flags = ISMEX_SEND;
2610 if (!unpack_message( info.msg.hwnd, info.msg.message, &info.msg.wParam,
2611 &info.msg.lParam, &buffer, size ))
2613 /* ignore it */
2614 reply_message( &info, 0, TRUE );
2615 continue;
2617 break;
2618 case MSG_HARDWARE:
2619 if (size >= sizeof(msg_data->hardware))
2621 info.msg.pt.x = msg_data->hardware.x;
2622 info.msg.pt.y = msg_data->hardware.y;
2623 hw_id = msg_data->hardware.hw_id;
2624 if (!process_hardware_message( &info.msg, hw_id, msg_data->hardware.info,
2625 hwnd, first, last, flags & PM_REMOVE ))
2627 TRACE("dropping msg %x\n", info.msg.message );
2628 continue; /* ignore it */
2630 *msg = info.msg;
2631 thread_info->GetMessagePosVal = MAKELONG( info.msg.pt.x, info.msg.pt.y );
2632 thread_info->GetMessageTimeVal = info.msg.time;
2633 thread_info->GetMessageExtraInfoVal = msg_data->hardware.info;
2634 HeapFree( GetProcessHeap(), 0, buffer );
2635 HOOK_CallHooks( WH_GETMESSAGE, HC_ACTION, flags & PM_REMOVE, (LPARAM)msg, TRUE );
2636 return TRUE;
2638 continue;
2639 case MSG_POSTED:
2640 if (info.msg.message & 0x80000000) /* internal message */
2642 if (flags & PM_REMOVE)
2644 handle_internal_message( info.msg.hwnd, info.msg.message,
2645 info.msg.wParam, info.msg.lParam );
2646 /* if this is a nested call return right away */
2647 if (first == info.msg.message && last == info.msg.message) return FALSE;
2649 else
2650 peek_message( msg, info.msg.hwnd, info.msg.message,
2651 info.msg.message, flags | PM_REMOVE, changed_mask );
2652 continue;
2654 if (info.msg.message >= WM_DDE_FIRST && info.msg.message <= WM_DDE_LAST)
2656 if (!unpack_dde_message( info.msg.hwnd, info.msg.message, &info.msg.wParam,
2657 &info.msg.lParam, &buffer, size ))
2658 continue; /* ignore it */
2660 *msg = info.msg;
2661 msg->pt.x = (short)LOWORD( thread_info->GetMessagePosVal );
2662 msg->pt.y = (short)HIWORD( thread_info->GetMessagePosVal );
2663 thread_info->GetMessageTimeVal = info.msg.time;
2664 thread_info->GetMessageExtraInfoVal = 0;
2665 HeapFree( GetProcessHeap(), 0, buffer );
2666 HOOK_CallHooks( WH_GETMESSAGE, HC_ACTION, flags & PM_REMOVE, (LPARAM)msg, TRUE );
2667 return TRUE;
2670 /* if we get here, we have a sent message; call the window procedure */
2671 old_info = thread_info->receive_info;
2672 thread_info->receive_info = &info;
2673 result = call_window_proc( info.msg.hwnd, info.msg.message, info.msg.wParam,
2674 info.msg.lParam, (info.type != MSG_ASCII), FALSE,
2675 WMCHAR_MAP_RECVMESSAGE );
2676 reply_message( &info, result, TRUE );
2677 thread_info->receive_info = old_info;
2679 /* if some PM_QS* flags were specified, only handle sent messages from now on */
2680 if (HIWORD(flags) && !changed_mask) flags = PM_QS_SENDMESSAGE | LOWORD(flags);
2685 /***********************************************************************
2686 * process_sent_messages
2688 * Process all pending sent messages.
2690 static inline void process_sent_messages(void)
2692 MSG msg;
2693 peek_message( &msg, 0, 0, 0, PM_REMOVE | PM_QS_SENDMESSAGE, 0 );
2697 /***********************************************************************
2698 * get_server_queue_handle
2700 * Get a handle to the server message queue for the current thread.
2702 static HANDLE get_server_queue_handle(void)
2704 struct user_thread_info *thread_info = get_user_thread_info();
2705 HANDLE ret;
2707 if (!(ret = thread_info->server_queue))
2709 SERVER_START_REQ( get_msg_queue )
2711 wine_server_call( req );
2712 ret = wine_server_ptr_handle( reply->handle );
2714 SERVER_END_REQ;
2715 thread_info->server_queue = ret;
2716 if (!ret) ERR( "Cannot get server thread queue\n" );
2718 return ret;
2722 /***********************************************************************
2723 * wait_message_reply
2725 * Wait until a sent message gets replied to.
2727 static void wait_message_reply( UINT flags )
2729 HANDLE server_queue = get_server_queue_handle();
2731 for (;;)
2733 unsigned int wake_bits = 0;
2735 SERVER_START_REQ( set_queue_mask )
2737 req->wake_mask = QS_SMRESULT | ((flags & SMTO_BLOCK) ? 0 : QS_SENDMESSAGE);
2738 req->changed_mask = req->wake_mask;
2739 req->skip_wait = 1;
2740 if (!wine_server_call( req ))
2741 wake_bits = reply->wake_bits;
2743 SERVER_END_REQ;
2745 if (wake_bits & QS_SMRESULT) return; /* got a result */
2746 if (wake_bits & QS_SENDMESSAGE)
2748 /* Process the sent message immediately */
2749 process_sent_messages();
2750 continue;
2753 wow_handlers.wait_message( 1, &server_queue, INFINITE, QS_SENDMESSAGE, 0 );
2757 /***********************************************************************
2758 * put_message_in_queue
2760 * Put a sent message into the destination queue.
2761 * For inter-process message, reply_size is set to expected size of reply data.
2763 static BOOL put_message_in_queue( const struct send_message_info *info, size_t *reply_size )
2765 struct packed_message data;
2766 message_data_t msg_data;
2767 unsigned int res;
2768 int i;
2769 timeout_t timeout = TIMEOUT_INFINITE;
2771 /* Check for INFINITE timeout for compatibility with Win9x,
2772 * although Windows >= NT does not do so
2774 if (info->type != MSG_NOTIFY &&
2775 info->type != MSG_CALLBACK &&
2776 info->type != MSG_POSTED &&
2777 info->timeout &&
2778 info->timeout != INFINITE)
2780 /* timeout is signed despite the prototype */
2781 timeout = (timeout_t)max( 0, (int)info->timeout ) * -10000;
2784 memset( &data, 0, sizeof(data) );
2785 if (info->type == MSG_OTHER_PROCESS)
2787 *reply_size = pack_message( info->hwnd, info->msg, info->wparam, info->lparam, &data );
2788 if (data.count == -1)
2790 WARN( "cannot pack message %x\n", info->msg );
2791 return FALSE;
2794 else if (info->type == MSG_CALLBACK)
2796 msg_data.callback.callback = wine_server_client_ptr( info->callback );
2797 msg_data.callback.data = info->data;
2798 msg_data.callback.result = 0;
2799 data.data[0] = &msg_data;
2800 data.size[0] = sizeof(msg_data.callback);
2801 data.count = 1;
2803 else if (info->type == MSG_POSTED && info->msg >= WM_DDE_FIRST && info->msg <= WM_DDE_LAST)
2805 return post_dde_message( &data, info );
2808 SERVER_START_REQ( send_message )
2810 req->id = info->dest_tid;
2811 req->type = info->type;
2812 req->flags = 0;
2813 req->win = wine_server_user_handle( info->hwnd );
2814 req->msg = info->msg;
2815 req->wparam = info->wparam;
2816 req->lparam = info->lparam;
2817 req->timeout = timeout;
2819 if (info->flags & SMTO_ABORTIFHUNG) req->flags |= SEND_MSG_ABORT_IF_HUNG;
2820 for (i = 0; i < data.count; i++) wine_server_add_data( req, data.data[i], data.size[i] );
2821 if ((res = wine_server_call( req )))
2823 if (res == STATUS_INVALID_PARAMETER)
2824 /* FIXME: find a STATUS_ value for this one */
2825 SetLastError( ERROR_INVALID_THREAD_ID );
2826 else
2827 SetLastError( RtlNtStatusToDosError(res) );
2830 SERVER_END_REQ;
2831 return !res;
2835 /***********************************************************************
2836 * retrieve_reply
2838 * Retrieve a message reply from the server.
2840 static LRESULT retrieve_reply( const struct send_message_info *info,
2841 size_t reply_size, LRESULT *result )
2843 NTSTATUS status;
2844 void *reply_data = NULL;
2846 if (reply_size)
2848 if (!(reply_data = HeapAlloc( GetProcessHeap(), 0, reply_size )))
2850 WARN( "no memory for reply, will be truncated\n" );
2851 reply_size = 0;
2854 SERVER_START_REQ( get_message_reply )
2856 req->cancel = 1;
2857 if (reply_size) wine_server_set_reply( req, reply_data, reply_size );
2858 if (!(status = wine_server_call( req ))) *result = reply->result;
2859 reply_size = wine_server_reply_size( reply );
2861 SERVER_END_REQ;
2862 if (!status && reply_size)
2863 unpack_reply( info->hwnd, info->msg, info->wparam, info->lparam, reply_data, reply_size );
2865 HeapFree( GetProcessHeap(), 0, reply_data );
2867 TRACE( "hwnd %p msg %x (%s) wp %lx lp %lx got reply %lx (err=%d)\n",
2868 info->hwnd, info->msg, SPY_GetMsgName(info->msg, info->hwnd), info->wparam,
2869 info->lparam, *result, status );
2871 /* MSDN states that last error is 0 on timeout, but at least NT4 returns ERROR_TIMEOUT */
2872 if (status) SetLastError( RtlNtStatusToDosError(status) );
2873 return !status;
2877 /***********************************************************************
2878 * send_inter_thread_message
2880 static LRESULT send_inter_thread_message( const struct send_message_info *info, LRESULT *res_ptr )
2882 size_t reply_size = 0;
2884 TRACE( "hwnd %p msg %x (%s) wp %lx lp %lx\n",
2885 info->hwnd, info->msg, SPY_GetMsgName(info->msg, info->hwnd), info->wparam, info->lparam );
2887 USER_CheckNotLock();
2889 if (!put_message_in_queue( info, &reply_size )) return 0;
2891 /* there's no reply to wait for on notify/callback messages */
2892 if (info->type == MSG_NOTIFY || info->type == MSG_CALLBACK) return 1;
2894 wait_message_reply( info->flags );
2895 return retrieve_reply( info, reply_size, res_ptr );
2899 /***********************************************************************
2900 * send_inter_thread_callback
2902 static LRESULT send_inter_thread_callback( HWND hwnd, UINT msg, WPARAM wp, LPARAM lp,
2903 LRESULT *result, void *arg )
2905 struct send_message_info *info = arg;
2906 info->hwnd = hwnd;
2907 info->msg = msg;
2908 info->wparam = wp;
2909 info->lparam = lp;
2910 return send_inter_thread_message( info, result );
2914 /***********************************************************************
2915 * send_message
2917 * Backend implementation of the various SendMessage functions.
2919 static BOOL send_message( struct send_message_info *info, DWORD_PTR *res_ptr, BOOL unicode )
2921 DWORD dest_pid;
2922 BOOL ret;
2923 LRESULT result;
2925 if (is_broadcast(info->hwnd))
2927 EnumWindows( broadcast_message_callback, (LPARAM)info );
2928 if (res_ptr) *res_ptr = 1;
2929 return TRUE;
2932 if (!(info->dest_tid = GetWindowThreadProcessId( info->hwnd, &dest_pid ))) return FALSE;
2934 if (USER_IsExitingThread( info->dest_tid )) return FALSE;
2936 SPY_EnterMessage( SPY_SENDMESSAGE, info->hwnd, info->msg, info->wparam, info->lparam );
2938 if (info->dest_tid == GetCurrentThreadId())
2940 result = call_window_proc( info->hwnd, info->msg, info->wparam, info->lparam,
2941 unicode, TRUE, info->wm_char );
2942 if (info->type == MSG_CALLBACK)
2943 call_sendmsg_callback( info->callback, info->hwnd, info->msg, info->data, result );
2944 ret = TRUE;
2946 else
2948 if (dest_pid != GetCurrentProcessId() && (info->type == MSG_ASCII || info->type == MSG_UNICODE))
2949 info->type = MSG_OTHER_PROCESS;
2951 /* MSG_ASCII can be sent unconverted except for WM_CHAR; everything else needs to be Unicode */
2952 if (!unicode && is_unicode_message( info->msg ) &&
2953 (info->type != MSG_ASCII || info->msg == WM_CHAR))
2954 ret = WINPROC_CallProcAtoW( send_inter_thread_callback, info->hwnd, info->msg,
2955 info->wparam, info->lparam, &result, info, info->wm_char );
2956 else
2957 ret = send_inter_thread_message( info, &result );
2960 SPY_ExitMessage( SPY_RESULT_OK, info->hwnd, info->msg, result, info->wparam, info->lparam );
2961 if (ret && res_ptr) *res_ptr = result;
2962 return ret;
2966 /***********************************************************************
2967 * MSG_SendInternalMessageTimeout
2969 * Same as SendMessageTimeoutW but sends the message to a specific thread
2970 * without requiring a window handle. Only works for internal Wine messages.
2972 LRESULT MSG_SendInternalMessageTimeout( DWORD dest_pid, DWORD dest_tid,
2973 UINT msg, WPARAM wparam, LPARAM lparam,
2974 UINT flags, UINT timeout, PDWORD_PTR res_ptr )
2976 struct send_message_info info;
2977 LRESULT ret, result;
2979 assert( msg & 0x80000000 ); /* must be an internal Wine message */
2981 info.type = MSG_UNICODE;
2982 info.dest_tid = dest_tid;
2983 info.hwnd = 0;
2984 info.msg = msg;
2985 info.wparam = wparam;
2986 info.lparam = lparam;
2987 info.flags = flags;
2988 info.timeout = timeout;
2990 if (USER_IsExitingThread( dest_tid )) return 0;
2992 if (dest_tid == GetCurrentThreadId())
2994 result = handle_internal_message( 0, msg, wparam, lparam );
2995 ret = 1;
2997 else
2999 if (dest_pid != GetCurrentProcessId()) info.type = MSG_OTHER_PROCESS;
3000 ret = send_inter_thread_message( &info, &result );
3002 if (ret && res_ptr) *res_ptr = result;
3003 return ret;
3007 /***********************************************************************
3008 * SendMessageTimeoutW (USER32.@)
3010 LRESULT WINAPI SendMessageTimeoutW( HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam,
3011 UINT flags, UINT timeout, PDWORD_PTR res_ptr )
3013 struct send_message_info info;
3015 info.type = MSG_UNICODE;
3016 info.hwnd = hwnd;
3017 info.msg = msg;
3018 info.wparam = wparam;
3019 info.lparam = lparam;
3020 info.flags = flags;
3021 info.timeout = timeout;
3023 return send_message( &info, res_ptr, TRUE );
3026 /***********************************************************************
3027 * SendMessageTimeoutA (USER32.@)
3029 LRESULT WINAPI SendMessageTimeoutA( HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam,
3030 UINT flags, UINT timeout, PDWORD_PTR res_ptr )
3032 struct send_message_info info;
3034 info.type = MSG_ASCII;
3035 info.hwnd = hwnd;
3036 info.msg = msg;
3037 info.wparam = wparam;
3038 info.lparam = lparam;
3039 info.flags = flags;
3040 info.timeout = timeout;
3041 info.wm_char = WMCHAR_MAP_SENDMESSAGETIMEOUT;
3043 return send_message( &info, res_ptr, FALSE );
3047 /***********************************************************************
3048 * SendMessageW (USER32.@)
3050 LRESULT WINAPI SendMessageW( HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam )
3052 DWORD_PTR res = 0;
3053 struct send_message_info info;
3055 info.type = MSG_UNICODE;
3056 info.hwnd = hwnd;
3057 info.msg = msg;
3058 info.wparam = wparam;
3059 info.lparam = lparam;
3060 info.flags = SMTO_NORMAL;
3061 info.timeout = 0;
3063 send_message( &info, &res, TRUE );
3064 return res;
3068 /***********************************************************************
3069 * SendMessageA (USER32.@)
3071 LRESULT WINAPI SendMessageA( HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam )
3073 DWORD_PTR res = 0;
3074 struct send_message_info info;
3076 info.type = MSG_ASCII;
3077 info.hwnd = hwnd;
3078 info.msg = msg;
3079 info.wparam = wparam;
3080 info.lparam = lparam;
3081 info.flags = SMTO_NORMAL;
3082 info.timeout = 0;
3083 info.wm_char = WMCHAR_MAP_SENDMESSAGE;
3085 send_message( &info, &res, FALSE );
3086 return res;
3090 /***********************************************************************
3091 * SendNotifyMessageA (USER32.@)
3093 BOOL WINAPI SendNotifyMessageA( HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam )
3095 struct send_message_info info;
3097 if (is_pointer_message(msg))
3099 SetLastError( ERROR_MESSAGE_SYNC_ONLY );
3100 return FALSE;
3103 info.type = MSG_NOTIFY;
3104 info.hwnd = hwnd;
3105 info.msg = msg;
3106 info.wparam = wparam;
3107 info.lparam = lparam;
3108 info.flags = 0;
3109 info.wm_char = WMCHAR_MAP_SENDMESSAGETIMEOUT;
3111 return send_message( &info, NULL, FALSE );
3115 /***********************************************************************
3116 * SendNotifyMessageW (USER32.@)
3118 BOOL WINAPI SendNotifyMessageW( HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam )
3120 struct send_message_info info;
3122 if (is_pointer_message(msg))
3124 SetLastError( ERROR_MESSAGE_SYNC_ONLY );
3125 return FALSE;
3128 info.type = MSG_NOTIFY;
3129 info.hwnd = hwnd;
3130 info.msg = msg;
3131 info.wparam = wparam;
3132 info.lparam = lparam;
3133 info.flags = 0;
3135 return send_message( &info, NULL, TRUE );
3139 /***********************************************************************
3140 * SendMessageCallbackA (USER32.@)
3142 BOOL WINAPI SendMessageCallbackA( HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam,
3143 SENDASYNCPROC callback, ULONG_PTR data )
3145 struct send_message_info info;
3147 if (is_pointer_message(msg))
3149 SetLastError( ERROR_MESSAGE_SYNC_ONLY );
3150 return FALSE;
3153 info.type = MSG_CALLBACK;
3154 info.hwnd = hwnd;
3155 info.msg = msg;
3156 info.wparam = wparam;
3157 info.lparam = lparam;
3158 info.callback = callback;
3159 info.data = data;
3160 info.flags = 0;
3161 info.wm_char = WMCHAR_MAP_SENDMESSAGETIMEOUT;
3163 return send_message( &info, NULL, FALSE );
3167 /***********************************************************************
3168 * SendMessageCallbackW (USER32.@)
3170 BOOL WINAPI SendMessageCallbackW( HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam,
3171 SENDASYNCPROC callback, ULONG_PTR data )
3173 struct send_message_info info;
3175 if (is_pointer_message(msg))
3177 SetLastError( ERROR_MESSAGE_SYNC_ONLY );
3178 return FALSE;
3181 info.type = MSG_CALLBACK;
3182 info.hwnd = hwnd;
3183 info.msg = msg;
3184 info.wparam = wparam;
3185 info.lparam = lparam;
3186 info.callback = callback;
3187 info.data = data;
3188 info.flags = 0;
3190 return send_message( &info, NULL, TRUE );
3194 /***********************************************************************
3195 * ReplyMessage (USER32.@)
3197 BOOL WINAPI ReplyMessage( LRESULT result )
3199 struct received_message_info *info = get_user_thread_info()->receive_info;
3201 if (!info) return FALSE;
3202 reply_message( info, result, FALSE );
3203 return TRUE;
3207 /***********************************************************************
3208 * InSendMessage (USER32.@)
3210 BOOL WINAPI InSendMessage(void)
3212 return (InSendMessageEx(NULL) & (ISMEX_SEND|ISMEX_REPLIED)) == ISMEX_SEND;
3216 /***********************************************************************
3217 * InSendMessageEx (USER32.@)
3219 DWORD WINAPI InSendMessageEx( LPVOID reserved )
3221 struct received_message_info *info = get_user_thread_info()->receive_info;
3223 if (info) return info->flags;
3224 return ISMEX_NOSEND;
3228 /***********************************************************************
3229 * PostMessageA (USER32.@)
3231 BOOL WINAPI PostMessageA( HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam )
3233 if (!map_wparam_AtoW( msg, &wparam, WMCHAR_MAP_POSTMESSAGE )) return TRUE;
3234 return PostMessageW( hwnd, msg, wparam, lparam );
3238 /***********************************************************************
3239 * PostMessageW (USER32.@)
3241 BOOL WINAPI PostMessageW( HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam )
3243 struct send_message_info info;
3245 if (is_pointer_message( msg ))
3247 SetLastError( ERROR_MESSAGE_SYNC_ONLY );
3248 return FALSE;
3251 TRACE( "hwnd %p msg %x (%s) wp %lx lp %lx\n",
3252 hwnd, msg, SPY_GetMsgName(msg, hwnd), wparam, lparam );
3254 info.type = MSG_POSTED;
3255 info.hwnd = hwnd;
3256 info.msg = msg;
3257 info.wparam = wparam;
3258 info.lparam = lparam;
3259 info.flags = 0;
3261 if (is_broadcast(hwnd))
3263 EnumWindows( broadcast_message_callback, (LPARAM)&info );
3264 return TRUE;
3267 if (!hwnd) return PostThreadMessageW( GetCurrentThreadId(), msg, wparam, lparam );
3269 if (!(info.dest_tid = GetWindowThreadProcessId( hwnd, NULL ))) return FALSE;
3271 if (USER_IsExitingThread( info.dest_tid )) return TRUE;
3273 return put_message_in_queue( &info, NULL );
3277 /**********************************************************************
3278 * PostThreadMessageA (USER32.@)
3280 BOOL WINAPI PostThreadMessageA( DWORD thread, UINT msg, WPARAM wparam, LPARAM lparam )
3282 if (!map_wparam_AtoW( msg, &wparam, WMCHAR_MAP_POSTMESSAGE )) return TRUE;
3283 return PostThreadMessageW( thread, msg, wparam, lparam );
3287 /**********************************************************************
3288 * PostThreadMessageW (USER32.@)
3290 BOOL WINAPI PostThreadMessageW( DWORD thread, UINT msg, WPARAM wparam, LPARAM lparam )
3292 struct send_message_info info;
3294 if (is_pointer_message( msg ))
3296 SetLastError( ERROR_MESSAGE_SYNC_ONLY );
3297 return FALSE;
3299 if (USER_IsExitingThread( thread )) return TRUE;
3301 info.type = MSG_POSTED;
3302 info.dest_tid = thread;
3303 info.hwnd = 0;
3304 info.msg = msg;
3305 info.wparam = wparam;
3306 info.lparam = lparam;
3307 info.flags = 0;
3308 return put_message_in_queue( &info, NULL );
3312 /***********************************************************************
3313 * PostQuitMessage (USER32.@)
3315 * Posts a quit message to the current thread's message queue.
3317 * PARAMS
3318 * exit_code [I] Exit code to return from message loop.
3320 * RETURNS
3321 * Nothing.
3323 * NOTES
3324 * This function is not the same as calling:
3325 *|PostThreadMessage(GetCurrentThreadId(), WM_QUIT, exit_code, 0);
3326 * It instead sets a flag in the message queue that signals it to generate
3327 * a WM_QUIT message when there are no other pending sent or posted messages
3328 * in the queue.
3330 void WINAPI PostQuitMessage( INT exit_code )
3332 SERVER_START_REQ( post_quit_message )
3334 req->exit_code = exit_code;
3335 wine_server_call( req );
3337 SERVER_END_REQ;
3341 /***********************************************************************
3342 * PeekMessageW (USER32.@)
3344 BOOL WINAPI PeekMessageW( MSG *msg_out, HWND hwnd, UINT first, UINT last, UINT flags )
3346 MSG msg;
3348 USER_CheckNotLock();
3350 /* check for graphics events */
3351 USER_Driver->pMsgWaitForMultipleObjectsEx( 0, NULL, 0, QS_ALLINPUT, 0 );
3353 if (!peek_message( &msg, hwnd, first, last, flags, 0 ))
3355 if (!(flags & PM_NOYIELD)) wow_handlers.wait_message( 0, NULL, 0, 0, 0 );
3356 return FALSE;
3359 /* copy back our internal safe copy of message data to msg_out.
3360 * msg_out is a variable from the *program*, so it can't be used
3361 * internally as it can get "corrupted" by our use of SendMessage()
3362 * (back to the program) inside the message handling itself. */
3363 if (!msg_out)
3365 SetLastError( ERROR_NOACCESS );
3366 return FALSE;
3368 *msg_out = msg;
3369 return TRUE;
3373 /***********************************************************************
3374 * PeekMessageA (USER32.@)
3376 BOOL WINAPI PeekMessageA( MSG *msg, HWND hwnd, UINT first, UINT last, UINT flags )
3378 if (get_pending_wmchar( msg, first, last, (flags & PM_REMOVE) )) return TRUE;
3379 if (!PeekMessageW( msg, hwnd, first, last, flags )) return FALSE;
3380 map_wparam_WtoA( msg, (flags & PM_REMOVE) );
3381 return TRUE;
3385 /***********************************************************************
3386 * GetMessageW (USER32.@)
3388 BOOL WINAPI GetMessageW( MSG *msg, HWND hwnd, UINT first, UINT last )
3390 HANDLE server_queue = get_server_queue_handle();
3391 unsigned int mask = QS_POSTMESSAGE | QS_SENDMESSAGE; /* Always selected */
3393 USER_CheckNotLock();
3395 /* check for graphics events */
3396 USER_Driver->pMsgWaitForMultipleObjectsEx( 0, NULL, 0, QS_ALLINPUT, 0 );
3398 if (first || last)
3400 if ((first <= WM_KEYLAST) && (last >= WM_KEYFIRST)) mask |= QS_KEY;
3401 if ( ((first <= WM_MOUSELAST) && (last >= WM_MOUSEFIRST)) ||
3402 ((first <= WM_NCMOUSELAST) && (last >= WM_NCMOUSEFIRST)) ) mask |= QS_MOUSE;
3403 if ((first <= WM_TIMER) && (last >= WM_TIMER)) mask |= QS_TIMER;
3404 if ((first <= WM_SYSTIMER) && (last >= WM_SYSTIMER)) mask |= QS_TIMER;
3405 if ((first <= WM_PAINT) && (last >= WM_PAINT)) mask |= QS_PAINT;
3407 else mask = QS_ALLINPUT;
3409 while (!peek_message( msg, hwnd, first, last, PM_REMOVE | (mask << 16), mask ))
3411 wow_handlers.wait_message( 1, &server_queue, INFINITE, mask, 0 );
3414 return (msg->message != WM_QUIT);
3418 /***********************************************************************
3419 * GetMessageA (USER32.@)
3421 BOOL WINAPI GetMessageA( MSG *msg, HWND hwnd, UINT first, UINT last )
3423 if (get_pending_wmchar( msg, first, last, TRUE )) return TRUE;
3424 GetMessageW( msg, hwnd, first, last );
3425 map_wparam_WtoA( msg, TRUE );
3426 return (msg->message != WM_QUIT);
3430 /***********************************************************************
3431 * IsDialogMessageA (USER32.@)
3432 * IsDialogMessage (USER32.@)
3434 BOOL WINAPI IsDialogMessageA( HWND hwndDlg, LPMSG pmsg )
3436 MSG msg = *pmsg;
3437 map_wparam_AtoW( msg.message, &msg.wParam, WMCHAR_MAP_NOMAPPING );
3438 return IsDialogMessageW( hwndDlg, &msg );
3442 /***********************************************************************
3443 * TranslateMessage (USER32.@)
3445 * Implementation of TranslateMessage.
3447 * TranslateMessage translates virtual-key messages into character-messages,
3448 * as follows :
3449 * WM_KEYDOWN/WM_KEYUP combinations produce a WM_CHAR or WM_DEADCHAR message.
3450 * ditto replacing WM_* with WM_SYS*
3451 * This produces WM_CHAR messages only for keys mapped to ASCII characters
3452 * by the keyboard driver.
3454 * If the message is WM_KEYDOWN, WM_KEYUP, WM_SYSKEYDOWN, or WM_SYSKEYUP, the
3455 * return value is nonzero, regardless of the translation.
3458 BOOL WINAPI TranslateMessage( const MSG *msg )
3460 UINT message;
3461 WCHAR wp[2];
3462 BYTE state[256];
3464 if (msg->message < WM_KEYFIRST || msg->message > WM_KEYLAST) return FALSE;
3465 if (msg->message != WM_KEYDOWN && msg->message != WM_SYSKEYDOWN) return TRUE;
3467 TRACE_(key)("Translating key %s (%04lX), scancode %04x\n",
3468 SPY_GetVKeyName(msg->wParam), msg->wParam, HIWORD(msg->lParam));
3470 switch (msg->wParam)
3472 case VK_PACKET:
3473 message = (msg->message == WM_KEYDOWN) ? WM_CHAR : WM_SYSCHAR;
3474 TRACE_(key)("PostMessageW(%p,%s,%04x,%08x)\n",
3475 msg->hwnd, SPY_GetMsgName(message, msg->hwnd), HIWORD(msg->lParam), LOWORD(msg->lParam));
3476 PostMessageW( msg->hwnd, message, HIWORD(msg->lParam), LOWORD(msg->lParam));
3477 return TRUE;
3479 case VK_PROCESSKEY:
3480 return ImmTranslateMessage(msg->hwnd, msg->message, msg->wParam, msg->lParam);
3483 GetKeyboardState( state );
3484 /* FIXME : should handle ToUnicode yielding 2 */
3485 switch (ToUnicode(msg->wParam, HIWORD(msg->lParam), state, wp, 2, 0))
3487 case 1:
3488 message = (msg->message == WM_KEYDOWN) ? WM_CHAR : WM_SYSCHAR;
3489 TRACE_(key)("1 -> PostMessageW(%p,%s,%04x,%08lx)\n",
3490 msg->hwnd, SPY_GetMsgName(message, msg->hwnd), wp[0], msg->lParam);
3491 PostMessageW( msg->hwnd, message, wp[0], msg->lParam );
3492 break;
3494 case -1:
3495 message = (msg->message == WM_KEYDOWN) ? WM_DEADCHAR : WM_SYSDEADCHAR;
3496 TRACE_(key)("-1 -> PostMessageW(%p,%s,%04x,%08lx)\n",
3497 msg->hwnd, SPY_GetMsgName(message, msg->hwnd), wp[0], msg->lParam);
3498 PostMessageW( msg->hwnd, message, wp[0], msg->lParam );
3499 break;
3501 return TRUE;
3505 /***********************************************************************
3506 * DispatchMessageA (USER32.@)
3508 * See DispatchMessageW.
3510 LRESULT WINAPI DECLSPEC_HOTPATCH DispatchMessageA( const MSG* msg )
3512 LRESULT retval;
3514 /* Process timer messages */
3515 if ((msg->message == WM_TIMER) || (msg->message == WM_SYSTIMER))
3517 if (msg->lParam)
3519 __TRY
3521 retval = CallWindowProcA( (WNDPROC)msg->lParam, msg->hwnd,
3522 msg->message, msg->wParam, GetTickCount() );
3524 __EXCEPT_PAGE_FAULT
3526 retval = 0;
3528 __ENDTRY
3529 return retval;
3532 if (!msg->hwnd) return 0;
3534 SPY_EnterMessage( SPY_DISPATCHMESSAGE, msg->hwnd, msg->message,
3535 msg->wParam, msg->lParam );
3537 if (!WINPROC_call_window( msg->hwnd, msg->message, msg->wParam, msg->lParam,
3538 &retval, FALSE, WMCHAR_MAP_DISPATCHMESSAGE ))
3540 if (!IsWindow( msg->hwnd )) SetLastError( ERROR_INVALID_WINDOW_HANDLE );
3541 else SetLastError( ERROR_MESSAGE_SYNC_ONLY );
3542 retval = 0;
3545 SPY_ExitMessage( SPY_RESULT_OK, msg->hwnd, msg->message, retval,
3546 msg->wParam, msg->lParam );
3548 if (msg->message == WM_PAINT)
3550 /* send a WM_NCPAINT and WM_ERASEBKGND if the non-client area is still invalid */
3551 HRGN hrgn = CreateRectRgn( 0, 0, 0, 0 );
3552 GetUpdateRgn( msg->hwnd, hrgn, TRUE );
3553 DeleteObject( hrgn );
3555 return retval;
3559 /***********************************************************************
3560 * DispatchMessageW (USER32.@) Process a message
3562 * Process the message specified in the structure *_msg_.
3564 * If the lpMsg parameter points to a WM_TIMER message and the
3565 * parameter of the WM_TIMER message is not NULL, the lParam parameter
3566 * points to the function that is called instead of the window
3567 * procedure. The function stored in lParam (timer callback) is protected
3568 * from causing page-faults.
3570 * The message must be valid.
3572 * RETURNS
3574 * DispatchMessage() returns the result of the window procedure invoked.
3576 * CONFORMANCE
3578 * ECMA-234, Win32
3581 LRESULT WINAPI DECLSPEC_HOTPATCH DispatchMessageW( const MSG* msg )
3583 LRESULT retval;
3585 /* Process timer messages */
3586 if ((msg->message == WM_TIMER) || (msg->message == WM_SYSTIMER))
3588 if (msg->lParam)
3590 __TRY
3592 retval = CallWindowProcW( (WNDPROC)msg->lParam, msg->hwnd,
3593 msg->message, msg->wParam, GetTickCount() );
3595 __EXCEPT_PAGE_FAULT
3597 retval = 0;
3599 __ENDTRY
3600 return retval;
3603 if (!msg->hwnd) return 0;
3605 SPY_EnterMessage( SPY_DISPATCHMESSAGE, msg->hwnd, msg->message,
3606 msg->wParam, msg->lParam );
3608 if (!WINPROC_call_window( msg->hwnd, msg->message, msg->wParam, msg->lParam,
3609 &retval, TRUE, WMCHAR_MAP_DISPATCHMESSAGE ))
3611 if (!IsWindow( msg->hwnd )) SetLastError( ERROR_INVALID_WINDOW_HANDLE );
3612 else SetLastError( ERROR_MESSAGE_SYNC_ONLY );
3613 retval = 0;
3616 SPY_ExitMessage( SPY_RESULT_OK, msg->hwnd, msg->message, retval,
3617 msg->wParam, msg->lParam );
3619 if (msg->message == WM_PAINT)
3621 /* send a WM_NCPAINT and WM_ERASEBKGND if the non-client area is still invalid */
3622 HRGN hrgn = CreateRectRgn( 0, 0, 0, 0 );
3623 GetUpdateRgn( msg->hwnd, hrgn, TRUE );
3624 DeleteObject( hrgn );
3626 return retval;
3630 /***********************************************************************
3631 * GetMessagePos (USER.119)
3632 * GetMessagePos (USER32.@)
3634 * The GetMessagePos() function returns a long value representing a
3635 * cursor position, in screen coordinates, when the last message
3636 * retrieved by the GetMessage() function occurs. The x-coordinate is
3637 * in the low-order word of the return value, the y-coordinate is in
3638 * the high-order word. The application can use the MAKEPOINT()
3639 * macro to obtain a POINT structure from the return value.
3641 * For the current cursor position, use GetCursorPos().
3643 * RETURNS
3645 * Cursor position of last message on success, zero on failure.
3647 * CONFORMANCE
3649 * ECMA-234, Win32
3652 DWORD WINAPI GetMessagePos(void)
3654 return get_user_thread_info()->GetMessagePosVal;
3658 /***********************************************************************
3659 * GetMessageTime (USER.120)
3660 * GetMessageTime (USER32.@)
3662 * GetMessageTime() returns the message time for the last message
3663 * retrieved by the function. The time is measured in milliseconds with
3664 * the same offset as GetTickCount().
3666 * Since the tick count wraps, this is only useful for moderately short
3667 * relative time comparisons.
3669 * RETURNS
3671 * Time of last message on success, zero on failure.
3673 LONG WINAPI GetMessageTime(void)
3675 return get_user_thread_info()->GetMessageTimeVal;
3679 /***********************************************************************
3680 * GetMessageExtraInfo (USER.288)
3681 * GetMessageExtraInfo (USER32.@)
3683 LPARAM WINAPI GetMessageExtraInfo(void)
3685 return get_user_thread_info()->GetMessageExtraInfoVal;
3689 /***********************************************************************
3690 * SetMessageExtraInfo (USER32.@)
3692 LPARAM WINAPI SetMessageExtraInfo(LPARAM lParam)
3694 struct user_thread_info *thread_info = get_user_thread_info();
3695 LONG old_value = thread_info->GetMessageExtraInfoVal;
3696 thread_info->GetMessageExtraInfoVal = lParam;
3697 return old_value;
3701 /***********************************************************************
3702 * WaitMessage (USER.112) Suspend thread pending messages
3703 * WaitMessage (USER32.@) Suspend thread pending messages
3705 * WaitMessage() suspends a thread until events appear in the thread's
3706 * queue.
3708 BOOL WINAPI WaitMessage(void)
3710 return (MsgWaitForMultipleObjectsEx( 0, NULL, INFINITE, QS_ALLINPUT, 0 ) != WAIT_FAILED);
3714 /***********************************************************************
3715 * MsgWaitForMultipleObjectsEx (USER32.@)
3717 DWORD WINAPI MsgWaitForMultipleObjectsEx( DWORD count, CONST HANDLE *pHandles,
3718 DWORD timeout, DWORD mask, DWORD flags )
3720 HANDLE handles[MAXIMUM_WAIT_OBJECTS];
3721 DWORD i;
3723 if (count > MAXIMUM_WAIT_OBJECTS-1)
3725 SetLastError( ERROR_INVALID_PARAMETER );
3726 return WAIT_FAILED;
3729 /* set the queue mask */
3730 SERVER_START_REQ( set_queue_mask )
3732 req->wake_mask = (flags & MWMO_INPUTAVAILABLE) ? mask : 0;
3733 req->changed_mask = mask;
3734 req->skip_wait = 0;
3735 wine_server_call( req );
3737 SERVER_END_REQ;
3739 /* add the queue to the handle list */
3740 for (i = 0; i < count; i++) handles[i] = pHandles[i];
3741 handles[count] = get_server_queue_handle();
3743 return wow_handlers.wait_message( count+1, handles, timeout, mask, flags );
3747 /***********************************************************************
3748 * MsgWaitForMultipleObjects (USER32.@)
3750 DWORD WINAPI MsgWaitForMultipleObjects( DWORD count, CONST HANDLE *handles,
3751 BOOL wait_all, DWORD timeout, DWORD mask )
3753 return MsgWaitForMultipleObjectsEx( count, handles, timeout, mask,
3754 wait_all ? MWMO_WAITALL : 0 );
3758 /***********************************************************************
3759 * WaitForInputIdle (USER32.@)
3761 DWORD WINAPI WaitForInputIdle( HANDLE hProcess, DWORD dwTimeOut )
3763 DWORD start_time, elapsed, ret;
3764 HANDLE handles[2];
3766 handles[0] = hProcess;
3767 SERVER_START_REQ( get_process_idle_event )
3769 req->handle = wine_server_obj_handle( hProcess );
3770 wine_server_call_err( req );
3771 handles[1] = wine_server_ptr_handle( reply->event );
3773 SERVER_END_REQ;
3774 if (!handles[1]) return WAIT_FAILED; /* no event to wait on */
3776 start_time = GetTickCount();
3777 elapsed = 0;
3779 TRACE("waiting for %p\n", handles[1] );
3782 ret = MsgWaitForMultipleObjects ( 2, handles, FALSE, dwTimeOut - elapsed, QS_SENDMESSAGE );
3783 switch (ret)
3785 case WAIT_OBJECT_0:
3786 return 0;
3787 case WAIT_OBJECT_0+2:
3788 process_sent_messages();
3789 break;
3790 case WAIT_TIMEOUT:
3791 case WAIT_FAILED:
3792 TRACE("timeout or error\n");
3793 return ret;
3794 default:
3795 TRACE("finished\n");
3796 return 0;
3798 if (dwTimeOut != INFINITE)
3800 elapsed = GetTickCount() - start_time;
3801 if (elapsed > dwTimeOut)
3802 break;
3805 while (1);
3807 return WAIT_TIMEOUT;
3811 /***********************************************************************
3812 * RegisterWindowMessageA (USER32.@)
3813 * RegisterWindowMessage (USER.118)
3815 UINT WINAPI RegisterWindowMessageA( LPCSTR str )
3817 UINT ret = GlobalAddAtomA(str);
3818 TRACE("%s, ret=%x\n", str, ret);
3819 return ret;
3823 /***********************************************************************
3824 * RegisterWindowMessageW (USER32.@)
3826 UINT WINAPI RegisterWindowMessageW( LPCWSTR str )
3828 UINT ret = GlobalAddAtomW(str);
3829 TRACE("%s ret=%x\n", debugstr_w(str), ret);
3830 return ret;
3833 typedef struct BroadcastParm
3835 DWORD flags;
3836 LPDWORD recipients;
3837 UINT msg;
3838 WPARAM wp;
3839 LPARAM lp;
3840 DWORD success;
3841 HWINSTA winsta;
3842 } BroadcastParm;
3844 static BOOL CALLBACK bcast_childwindow( HWND hw, LPARAM lp )
3846 BroadcastParm *parm = (BroadcastParm*)lp;
3847 DWORD_PTR retval = 0;
3848 LRESULT lresult;
3850 if (parm->flags & BSF_IGNORECURRENTTASK && WIN_IsCurrentProcess(hw))
3852 TRACE("Not telling myself %p\n", hw);
3853 return TRUE;
3856 /* I don't know 100% for sure if this is what Windows does, but it fits the tests */
3857 if (parm->flags & BSF_QUERY)
3859 TRACE("Telling window %p using SendMessageTimeout\n", hw);
3861 /* Not tested for conflicting flags */
3862 if (parm->flags & BSF_FORCEIFHUNG || parm->flags & BSF_NOHANG)
3863 lresult = SendMessageTimeoutW( hw, parm->msg, parm->wp, parm->lp, SMTO_ABORTIFHUNG, 2000, &retval );
3864 else if (parm->flags & BSF_NOTIMEOUTIFNOTHUNG)
3865 lresult = SendMessageTimeoutW( hw, parm->msg, parm->wp, parm->lp, SMTO_NOTIMEOUTIFNOTHUNG, 2000, &retval );
3866 else
3867 lresult = SendMessageTimeoutW( hw, parm->msg, parm->wp, parm->lp, SMTO_NORMAL, 2000, &retval );
3869 if (!lresult && GetLastError() == ERROR_TIMEOUT)
3871 WARN("Timed out!\n");
3872 if (!(parm->flags & BSF_FORCEIFHUNG))
3873 goto fail;
3875 if (retval == BROADCAST_QUERY_DENY)
3876 goto fail;
3878 return TRUE;
3880 fail:
3881 parm->success = 0;
3882 return FALSE;
3884 else if (parm->flags & BSF_POSTMESSAGE)
3886 TRACE("Telling window %p using PostMessage\n", hw);
3887 PostMessageW( hw, parm->msg, parm->wp, parm->lp );
3889 else
3891 TRACE("Telling window %p using SendNotifyMessage\n", hw);
3892 SendNotifyMessageW( hw, parm->msg, parm->wp, parm->lp );
3895 return TRUE;
3898 static BOOL CALLBACK bcast_desktop( LPWSTR desktop, LPARAM lp )
3900 BOOL ret;
3901 HDESK hdesktop;
3902 BroadcastParm *parm = (BroadcastParm*)lp;
3904 TRACE("desktop: %s\n", debugstr_w( desktop ));
3906 hdesktop = open_winstation_desktop( parm->winsta, desktop, 0, FALSE, DESKTOP_ENUMERATE|DESKTOP_WRITEOBJECTS|STANDARD_RIGHTS_WRITE );
3907 if (!hdesktop)
3909 FIXME("Could not open desktop %s\n", debugstr_w(desktop));
3910 return TRUE;
3913 ret = EnumDesktopWindows( hdesktop, bcast_childwindow, lp );
3914 CloseDesktop(hdesktop);
3915 TRACE("-->%d\n", ret);
3916 return parm->success;
3919 static BOOL CALLBACK bcast_winsta( LPWSTR winsta, LPARAM lp )
3921 BOOL ret;
3922 HWINSTA hwinsta = OpenWindowStationW( winsta, FALSE, WINSTA_ENUMDESKTOPS );
3923 TRACE("hwinsta: %p/%s/%08x\n", hwinsta, debugstr_w( winsta ), GetLastError());
3924 if (!hwinsta)
3925 return TRUE;
3926 ((BroadcastParm *)lp)->winsta = hwinsta;
3927 ret = EnumDesktopsW( hwinsta, bcast_desktop, lp );
3928 CloseWindowStation( hwinsta );
3929 TRACE("-->%d\n", ret);
3930 return ret;
3933 /***********************************************************************
3934 * BroadcastSystemMessageA (USER32.@)
3935 * BroadcastSystemMessage (USER32.@)
3937 LONG WINAPI BroadcastSystemMessageA( DWORD flags, LPDWORD recipients, UINT msg, WPARAM wp, LPARAM lp )
3939 return BroadcastSystemMessageExA( flags, recipients, msg, wp, lp, NULL );
3943 /***********************************************************************
3944 * BroadcastSystemMessageW (USER32.@)
3946 LONG WINAPI BroadcastSystemMessageW( DWORD flags, LPDWORD recipients, UINT msg, WPARAM wp, LPARAM lp )
3948 return BroadcastSystemMessageExW( flags, recipients, msg, wp, lp, NULL );
3951 /***********************************************************************
3952 * BroadcastSystemMessageExA (USER32.@)
3954 LONG WINAPI BroadcastSystemMessageExA( DWORD flags, LPDWORD recipients, UINT msg, WPARAM wp, LPARAM lp, PBSMINFO pinfo )
3956 map_wparam_AtoW( msg, &wp, WMCHAR_MAP_NOMAPPING );
3957 return BroadcastSystemMessageExW( flags, recipients, msg, wp, lp, NULL );
3961 /***********************************************************************
3962 * BroadcastSystemMessageExW (USER32.@)
3964 LONG WINAPI BroadcastSystemMessageExW( DWORD flags, LPDWORD recipients, UINT msg, WPARAM wp, LPARAM lp, PBSMINFO pinfo )
3966 BroadcastParm parm;
3967 DWORD recips = BSM_ALLCOMPONENTS;
3968 BOOL ret = TRUE;
3969 static const DWORD all_flags = ( BSF_QUERY | BSF_IGNORECURRENTTASK | BSF_FLUSHDISK | BSF_NOHANG
3970 | BSF_POSTMESSAGE | BSF_FORCEIFHUNG | BSF_NOTIMEOUTIFNOTHUNG
3971 | BSF_ALLOWSFW | BSF_SENDNOTIFYMESSAGE | BSF_RETURNHDESK | BSF_LUID );
3973 TRACE("Flags: %08x, recipients: %p(0x%x), msg: %04x, wparam: %08lx, lparam: %08lx\n", flags, recipients,
3974 (recipients ? *recipients : recips), msg, wp, lp);
3976 if (flags & ~all_flags)
3978 SetLastError(ERROR_INVALID_PARAMETER);
3979 return 0;
3982 if (!recipients)
3983 recipients = &recips;
3985 if ( pinfo && flags & BSF_QUERY )
3986 FIXME("Not returning PBSMINFO information yet\n");
3988 parm.flags = flags;
3989 parm.recipients = recipients;
3990 parm.msg = msg;
3991 parm.wp = wp;
3992 parm.lp = lp;
3993 parm.success = TRUE;
3995 if (*recipients & BSM_ALLDESKTOPS || *recipients == BSM_ALLCOMPONENTS)
3996 ret = EnumWindowStationsW(bcast_winsta, (LONG_PTR)&parm);
3997 else if (*recipients & BSM_APPLICATIONS)
3999 EnumWindows(bcast_childwindow, (LONG_PTR)&parm);
4000 ret = parm.success;
4002 else
4003 FIXME("Recipients %08x not supported!\n", *recipients);
4005 return ret;
4008 /***********************************************************************
4009 * SetMessageQueue (USER32.@)
4011 BOOL WINAPI SetMessageQueue( INT size )
4013 /* now obsolete the message queue will be expanded dynamically as necessary */
4014 return TRUE;
4018 /***********************************************************************
4019 * MessageBeep (USER32.@)
4021 BOOL WINAPI MessageBeep( UINT i )
4023 BOOL active = TRUE;
4024 SystemParametersInfoA( SPI_GETBEEP, 0, &active, FALSE );
4025 if (active) USER_Driver->pBeep();
4026 return TRUE;
4030 /***********************************************************************
4031 * SetTimer (USER32.@)
4033 UINT_PTR WINAPI SetTimer( HWND hwnd, UINT_PTR id, UINT timeout, TIMERPROC proc )
4035 UINT_PTR ret;
4036 WNDPROC winproc = 0;
4038 if (proc) winproc = WINPROC_AllocProc( (WNDPROC)proc, FALSE );
4040 SERVER_START_REQ( set_win_timer )
4042 req->win = wine_server_user_handle( hwnd );
4043 req->msg = WM_TIMER;
4044 req->id = id;
4045 req->rate = max( timeout, SYS_TIMER_RATE );
4046 req->lparam = (ULONG_PTR)winproc;
4047 if (!wine_server_call_err( req ))
4049 ret = reply->id;
4050 if (!ret) ret = TRUE;
4052 else ret = 0;
4054 SERVER_END_REQ;
4056 TRACE("Added %p %lx %p timeout %d\n", hwnd, id, winproc, timeout );
4057 return ret;
4061 /***********************************************************************
4062 * SetSystemTimer (USER32.@)
4064 UINT_PTR WINAPI SetSystemTimer( HWND hwnd, UINT_PTR id, UINT timeout, TIMERPROC proc )
4066 UINT_PTR ret;
4067 WNDPROC winproc = 0;
4069 if (proc) winproc = WINPROC_AllocProc( (WNDPROC)proc, FALSE );
4071 SERVER_START_REQ( set_win_timer )
4073 req->win = wine_server_user_handle( hwnd );
4074 req->msg = WM_SYSTIMER;
4075 req->id = id;
4076 req->rate = max( timeout, SYS_TIMER_RATE );
4077 req->lparam = (ULONG_PTR)winproc;
4078 if (!wine_server_call_err( req ))
4080 ret = reply->id;
4081 if (!ret) ret = TRUE;
4083 else ret = 0;
4085 SERVER_END_REQ;
4087 TRACE("Added %p %lx %p timeout %d\n", hwnd, id, winproc, timeout );
4088 return ret;
4092 /***********************************************************************
4093 * KillTimer (USER32.@)
4095 BOOL WINAPI KillTimer( HWND hwnd, UINT_PTR id )
4097 BOOL ret;
4099 SERVER_START_REQ( kill_win_timer )
4101 req->win = wine_server_user_handle( hwnd );
4102 req->msg = WM_TIMER;
4103 req->id = id;
4104 ret = !wine_server_call_err( req );
4106 SERVER_END_REQ;
4107 return ret;
4111 /***********************************************************************
4112 * KillSystemTimer (USER32.@)
4114 BOOL WINAPI KillSystemTimer( HWND hwnd, UINT_PTR id )
4116 BOOL ret;
4118 SERVER_START_REQ( kill_win_timer )
4120 req->win = wine_server_user_handle( hwnd );
4121 req->msg = WM_SYSTIMER;
4122 req->id = id;
4123 ret = !wine_server_call_err( req );
4125 SERVER_END_REQ;
4126 return ret;
4130 /**********************************************************************
4131 * GetGUIThreadInfo (USER32.@)
4133 BOOL WINAPI GetGUIThreadInfo( DWORD id, GUITHREADINFO *info )
4135 BOOL ret;
4137 SERVER_START_REQ( get_thread_input )
4139 req->tid = id;
4140 if ((ret = !wine_server_call_err( req )))
4142 info->flags = 0;
4143 info->hwndActive = wine_server_ptr_handle( reply->active );
4144 info->hwndFocus = wine_server_ptr_handle( reply->focus );
4145 info->hwndCapture = wine_server_ptr_handle( reply->capture );
4146 info->hwndMenuOwner = wine_server_ptr_handle( reply->menu_owner );
4147 info->hwndMoveSize = wine_server_ptr_handle( reply->move_size );
4148 info->hwndCaret = wine_server_ptr_handle( reply->caret );
4149 info->rcCaret.left = reply->rect.left;
4150 info->rcCaret.top = reply->rect.top;
4151 info->rcCaret.right = reply->rect.right;
4152 info->rcCaret.bottom = reply->rect.bottom;
4153 if (reply->menu_owner) info->flags |= GUI_INMENUMODE;
4154 if (reply->move_size) info->flags |= GUI_INMOVESIZE;
4155 if (reply->caret) info->flags |= GUI_CARETBLINKING;
4158 SERVER_END_REQ;
4159 return ret;
4163 /******************************************************************
4164 * IsHungAppWindow (USER32.@)
4167 BOOL WINAPI IsHungAppWindow( HWND hWnd )
4169 BOOL ret;
4171 SERVER_START_REQ( is_window_hung )
4173 req->win = wine_server_user_handle( hWnd );
4174 ret = !wine_server_call_err( req ) && reply->is_hung;
4176 SERVER_END_REQ;
4177 return ret;
4180 /******************************************************************
4181 * ChangeWindowMessageFilter (USER32.@)
4183 BOOL WINAPI ChangeWindowMessageFilter( UINT message, DWORD flag )
4185 FIXME( "%x %08x\n", message, flag );
4186 return TRUE;