1 /*
2 * Window messaging support
3 *
4 * Copyright 2001 Alexandre Julliard
5 * Copyright 2008 Maarten Lankhorst
6 *
7 * This library is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU Lesser General Public
9 * License as published by the Free Software Foundation; either
10 * version 2.1 of the License, or (at your option) any later version.
11 *
12 * This library is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Lesser General Public License for more details.
16 *
17 * You should have received a copy of the GNU Lesser General Public
18 * License along with this library; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
20 */
21
22 #include "config.h"
23 #include "wine/port.h"
24
25 #include <assert.h>
26 #include <stdarg.h>
27
28 #include "ntstatus.h"
29 #define WIN32_NO_STATUS
30 #include "windef.h"
31 #include "winbase.h"
32 #include "wingdi.h"
33 #include "winuser.h"
34 #include "winerror.h"
35 #include "winnls.h"
36 #include "dbt.h"
37 #include "dde.h"
38 #include "imm.h"
39 #include "ddk/imm.h"
40 #include "wine/unicode.h"
41 #include "wine/server.h"
42 #include "user_private.h"
43 #include "win.h"
44 #include "controls.h"
45 #include "wine/debug.h"
46
47 WINE_DEFAULT_DEBUG_CHANNEL(msg);
48 WINE_DECLARE_DEBUG_CHANNEL(relay);
49 WINE_DECLARE_DEBUG_CHANNEL(key);
50
51 #define WM_NCMOUSEFIRST WM_NCMOUSEMOVE
52 #define WM_NCMOUSELAST (WM_NCMOUSEFIRST+(WM_MOUSELAST-WM_MOUSEFIRST))
53
54 #define MAX_PACK_COUNT 4
55
56 #define SYS_TIMER_RATE 55 /* min. timer rate in ms (actually 54.925)*/
57
58 /* description of the data fields that need to be packed along with a sent message */
59 struct packed_message
60 {
61 int count;
62 const void *data[MAX_PACK_COUNT];
63 size_t size[MAX_PACK_COUNT];
64 };
65
66 /* info about the message currently being received by the current thread */
67 struct received_message_info
68 {
69 enum message_type type;
70 MSG msg;
71 UINT flags; /* InSendMessageEx return flags */
72 };
73
74 /* structure to group all parameters for sent messages of the various kinds */
75 struct send_message_info
76 {
77 enum message_type type;
78 DWORD dest_tid;
79 HWND hwnd;
80 UINT msg;
81 WPARAM wparam;
82 LPARAM lparam;
83 UINT flags; /* flags for SendMessageTimeout */
84 UINT timeout; /* timeout for SendMessageTimeout */
85 SENDASYNCPROC callback; /* callback function for SendMessageCallback */
86 ULONG_PTR data; /* callback data */
87 enum wm_char_mapping wm_char;
88 };
89
90
91 /* Message class descriptor */
92 static const WCHAR messageW[] = {'M','e','s','s','a','g','e',0};
93 static LRESULT WINAPI message_winproc( HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam );
94 const struct builtin_class_descr MESSAGE_builtin_class =
95 {
96 messageW, /* name */
97 0, /* style */
98 NULL, /* procA (winproc is Unicode only) */
99 message_winproc, /* procW */
100 0, /* extra */
101 IDC_ARROW, /* cursor */
102 0 /* brush */
103 };
104
105
106
107 /* flag for messages that contain pointers */
108 /* 32 messages per entry, messages 0..31 map to bits 0..31 */
109
110 #define SET(msg) (1 << ((msg) & 31))
111
112 static const unsigned int message_pointer_flags[] =
113 {
114 /* 0x00 - 0x1f */
115 SET(WM_CREATE) | SET(WM_SETTEXT) | SET(WM_GETTEXT) |
116 SET(WM_WININICHANGE) | SET(WM_DEVMODECHANGE),
117 /* 0x20 - 0x3f */
118 SET(WM_GETMINMAXINFO) | SET(WM_DRAWITEM) | SET(WM_MEASUREITEM) | SET(WM_DELETEITEM) |
119 SET(WM_COMPAREITEM),
120 /* 0x40 - 0x5f */
121 SET(WM_WINDOWPOSCHANGING) | SET(WM_WINDOWPOSCHANGED) | SET(WM_COPYDATA) |
122 SET(WM_NOTIFY) | SET(WM_HELP),
123 /* 0x60 - 0x7f */
124 SET(WM_STYLECHANGING) | SET(WM_STYLECHANGED),
125 /* 0x80 - 0x9f */
126 SET(WM_NCCREATE) | SET(WM_NCCALCSIZE) | SET(WM_GETDLGCODE),
127 /* 0xa0 - 0xbf */
128 SET(EM_GETSEL) | SET(EM_GETRECT) | SET(EM_SETRECT) | SET(EM_SETRECTNP),
129 /* 0xc0 - 0xdf */
130 SET(EM_REPLACESEL) | SET(EM_GETLINE) | SET(EM_SETTABSTOPS),
131 /* 0xe0 - 0xff */
132 SET(SBM_GETRANGE) | SET(SBM_SETSCROLLINFO) | SET(SBM_GETSCROLLINFO) | SET(SBM_GETSCROLLBARINFO),
133 /* 0x100 - 0x11f */
134 0,
135 /* 0x120 - 0x13f */
136 0,
137 /* 0x140 - 0x15f */
138 SET(CB_GETEDITSEL) | SET(CB_ADDSTRING) | SET(CB_DIR) | SET(CB_GETLBTEXT) |
139 SET(CB_INSERTSTRING) | SET(CB_FINDSTRING) | SET(CB_SELECTSTRING) |
140 SET(CB_GETDROPPEDCONTROLRECT) | SET(CB_FINDSTRINGEXACT),
141 /* 0x160 - 0x17f */
142 0,
143 /* 0x180 - 0x19f */
144 SET(LB_ADDSTRING) | SET(LB_INSERTSTRING) | SET(LB_GETTEXT) | SET(LB_SELECTSTRING) |
145 SET(LB_DIR) | SET(LB_FINDSTRING) |
146 SET(LB_GETSELITEMS) | SET(LB_SETTABSTOPS) | SET(LB_ADDFILE) | SET(LB_GETITEMRECT),
147 /* 0x1a0 - 0x1bf */
148 SET(LB_FINDSTRINGEXACT),
149 /* 0x1c0 - 0x1df */
150 0,
151 /* 0x1e0 - 0x1ff */
152 0,
153 /* 0x200 - 0x21f */
154 SET(WM_NEXTMENU) | SET(WM_SIZING) | SET(WM_MOVING) | SET(WM_DEVICECHANGE),
155 /* 0x220 - 0x23f */
156 SET(WM_MDICREATE) | SET(WM_MDIGETACTIVE) | SET(WM_DROPOBJECT) |
157 SET(WM_QUERYDROPOBJECT) | SET(WM_DRAGLOOP) | SET(WM_DRAGSELECT) | SET(WM_DRAGMOVE),
158 /* 0x240 - 0x25f */
159 0,
160 /* 0x260 - 0x27f */
161 0,
162 /* 0x280 - 0x29f */
163 0,
164 /* 0x2a0 - 0x2bf */
165 0,
166 /* 0x2c0 - 0x2df */
167 0,
168 /* 0x2e0 - 0x2ff */
169 0,
170 /* 0x300 - 0x31f */
171 SET(WM_ASKCBFORMATNAME)
172 };
173
174 /* flags for messages that contain Unicode strings */
175 static const unsigned int message_unicode_flags[] =
176 {
177 /* 0x00 - 0x1f */
178 SET(WM_CREATE) | SET(WM_SETTEXT) | SET(WM_GETTEXT) | SET(WM_GETTEXTLENGTH) |
179 SET(WM_WININICHANGE) | SET(WM_DEVMODECHANGE),
180 /* 0x20 - 0x3f */
181 SET(WM_CHARTOITEM),
182 /* 0x40 - 0x5f */
183 0,
184 /* 0x60 - 0x7f */
185 0,
186 /* 0x80 - 0x9f */
187 SET(WM_NCCREATE),
188 /* 0xa0 - 0xbf */
189 0,
190 /* 0xc0 - 0xdf */
191 SET(EM_REPLACESEL) | SET(EM_GETLINE) | SET(EM_SETPASSWORDCHAR),
192 /* 0xe0 - 0xff */
193 0,
194 /* 0x100 - 0x11f */
195 SET(WM_CHAR) | SET(WM_DEADCHAR) | SET(WM_SYSCHAR) | SET(WM_SYSDEADCHAR),
196 /* 0x120 - 0x13f */
197 SET(WM_MENUCHAR),
198 /* 0x140 - 0x15f */
199 SET(CB_ADDSTRING) | SET(CB_DIR) | SET(CB_GETLBTEXT) | SET(CB_GETLBTEXTLEN) |
200 SET(CB_INSERTSTRING) | SET(CB_FINDSTRING) | SET(CB_SELECTSTRING) | SET(CB_FINDSTRINGEXACT),
201 /* 0x160 - 0x17f */
202 0,
203 /* 0x180 - 0x19f */
204 SET(LB_ADDSTRING) | SET(LB_INSERTSTRING) | SET(LB_GETTEXT) | SET(LB_GETTEXTLEN) |
205 SET(LB_SELECTSTRING) | SET(LB_DIR) | SET(LB_FINDSTRING) | SET(LB_ADDFILE),
206 /* 0x1a0 - 0x1bf */
207 SET(LB_FINDSTRINGEXACT),
208 /* 0x1c0 - 0x1df */
209 0,
210 /* 0x1e0 - 0x1ff */
211 0,
212 /* 0x200 - 0x21f */
213 0,
214 /* 0x220 - 0x23f */
215 SET(WM_MDICREATE),
216 /* 0x240 - 0x25f */
217 0,
218 /* 0x260 - 0x27f */
219 0,
220 /* 0x280 - 0x29f */
221 SET(WM_IME_CHAR),
222 /* 0x2a0 - 0x2bf */
223 0,
224 /* 0x2c0 - 0x2df */
225 0,
226 /* 0x2e0 - 0x2ff */
227 0,
228 /* 0x300 - 0x31f */
229 SET(WM_PAINTCLIPBOARD) | SET(WM_SIZECLIPBOARD) | SET(WM_ASKCBFORMATNAME)
230 };
231
232 /* check whether a given message type includes pointers */
233 static inline int is_pointer_message( UINT message )
234 {
235 if (message >= 8*sizeof(message_pointer_flags)) return FALSE;
236 return (message_pointer_flags[message / 32] & SET(message)) != 0;
237 }
238
239 /* check whether a given message type contains Unicode (or ASCII) chars */
240 static inline int is_unicode_message( UINT message )
241 {
242 if (message >= 8*sizeof(message_unicode_flags)) return FALSE;
243 return (message_unicode_flags[message / 32] & SET(message)) != 0;
244 }
245
246 #undef SET
247
248 /* add a data field to a packed message */
249 static inline void push_data( struct packed_message *data, const void *ptr, size_t size )
250 {
251 data->data[data->count] = ptr;
252 data->size[data->count] = size;
253 data->count++;
254 }
255
256 /* add a string to a packed message */
257 static inline void push_string( struct packed_message *data, LPCWSTR str )
258 {
259 push_data( data, str, (strlenW(str) + 1) * sizeof(WCHAR) );
260 }
261
262 /* make sure that the buffer contains a valid null-terminated Unicode string */
263 static inline BOOL check_string( LPCWSTR str, size_t size )
264 {
265 for (size /= sizeof(WCHAR); size; size--, str++)
266 if (!*str) return TRUE;
267 return FALSE;
268 }
269
270 /* make sure that there is space for 'size' bytes in buffer, growing it if needed */
271 static inline void *get_buffer_space( void **buffer, size_t size )
272 {
273 void *ret;
274
275 if (*buffer)
276 {
277 if (!(ret = HeapReAlloc( GetProcessHeap(), 0, *buffer, size )))
278 HeapFree( GetProcessHeap(), 0, *buffer );
279 }
280 else ret = HeapAlloc( GetProcessHeap(), 0, size );
281
282 *buffer = ret;
283 return ret;
284 }
285
286 /* check whether a combobox expects strings or ids in CB_ADDSTRING/CB_INSERTSTRING */
287 static inline BOOL combobox_has_strings( HWND hwnd )
288 {
289 DWORD style = GetWindowLongA( hwnd, GWL_STYLE );
290 return (!(style & (CBS_OWNERDRAWFIXED | CBS_OWNERDRAWVARIABLE)) || (style & CBS_HASSTRINGS));
291 }
292
293 /* check whether a listbox expects strings or ids in LB_ADDSTRING/LB_INSERTSTRING */
294 static inline BOOL listbox_has_strings( HWND hwnd )
295 {
296 DWORD style = GetWindowLongA( hwnd, GWL_STYLE );
297 return (!(style & (LBS_OWNERDRAWFIXED | LBS_OWNERDRAWVARIABLE)) || (style & LBS_HASSTRINGS));
298 }
299
300 /* check whether message is in the range of keyboard messages */
301 static inline BOOL is_keyboard_message( UINT message )
302 {
303 return (message >= WM_KEYFIRST && message <= WM_KEYLAST);
304 }
305
306 /* check whether message is in the range of mouse messages */
307 static inline BOOL is_mouse_message( UINT message )
308 {
309 return ((message >= WM_NCMOUSEFIRST && message <= WM_NCMOUSELAST) ||
310 (message >= WM_MOUSEFIRST && message <= WM_MOUSELAST));
311 }
312
313 /* check whether message matches the specified hwnd filter */
314 static inline BOOL check_hwnd_filter( const MSG *msg, HWND hwnd_filter )
315 {
316 if (!hwnd_filter || hwnd_filter == GetDesktopWindow()) return TRUE;
317 return (msg->hwnd == hwnd_filter || IsChild( hwnd_filter, msg->hwnd ));
318 }
319
320 /* check for pending WM_CHAR message with DBCS trailing byte */
321 static inline BOOL get_pending_wmchar( MSG *msg, UINT first, UINT last, BOOL remove )
322 {
323 struct wm_char_mapping_data *data = get_user_thread_info()->wmchar_data;
324
325 if (!data || !data->get_msg.message) return FALSE;
326 if ((first || last) && (first > WM_CHAR || last < WM_CHAR)) return FALSE;
327 if (!msg) return FALSE;
328 *msg = data->get_msg;
329 if (remove) data->get_msg.message = 0;
330 return TRUE;
331 }
332
333
334 /***********************************************************************
335 * message_winproc
336 *
337 * Window procedure for "Message" windows (HWND_MESSAGE parent).
338 */
339 static LRESULT WINAPI message_winproc( HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam )
340 {
341 if (message == WM_NCCREATE) return TRUE;
342 return 0; /* all other messages are ignored */
343 }
344
345
346 /***********************************************************************
347 * broadcast_message_callback
348 *
349 * Helper callback for broadcasting messages.
350 */
351 static BOOL CALLBACK broadcast_message_callback( HWND hwnd, LPARAM lparam )
352 {
353 struct send_message_info *info = (struct send_message_info *)lparam;
354 if (!(GetWindowLongW( hwnd, GWL_STYLE ) & (WS_POPUP|WS_CAPTION))) return TRUE;
355 switch(info->type)
356 {
357 case MSG_UNICODE:
358 SendMessageTimeoutW( hwnd, info->msg, info->wparam, info->lparam,
359 info->flags, info->timeout, NULL );
360 break;
361 case MSG_ASCII:
362 SendMessageTimeoutA( hwnd, info->msg, info->wparam, info->lparam,
363 info->flags, info->timeout, NULL );
364 break;
365 case MSG_NOTIFY:
366 SendNotifyMessageW( hwnd, info->msg, info->wparam, info->lparam );
367 break;
368 case MSG_CALLBACK:
369 SendMessageCallbackW( hwnd, info->msg, info->wparam, info->lparam,
370 info->callback, info->data );
371 break;
372 case MSG_POSTED:
373 PostMessageW( hwnd, info->msg, info->wparam, info->lparam );
374 break;
375 default:
376 ERR( "bad type %d\n", info->type );
377 break;
378 }
379 return TRUE;
380 }
381
382
383 /***********************************************************************
384 * map_wparam_AtoW
385 *
386 * Convert the wparam of an ASCII message to Unicode.
387 */
388 BOOL map_wparam_AtoW( UINT message, WPARAM *wparam, enum wm_char_mapping mapping )
389 {
390 char ch[2];
391 WCHAR wch[2];
392
393 wch[0] = wch[1] = 0;
394 switch(message)
395 {
396 case WM_CHAR:
397 /* WM_CHAR is magic: a DBCS char can be sent/posted as two consecutive WM_CHAR
398 * messages, in which case the first char is stored, and the conversion
399 * to Unicode only takes place once the second char is sent/posted.
400 */
401 if (mapping != WMCHAR_MAP_NOMAPPING)
402 {
403 struct wm_char_mapping_data *data = get_user_thread_info()->wmchar_data;
404 BYTE low = LOBYTE(*wparam);
405
406 if (HIBYTE(*wparam))
407 {
408 ch[0] = low;
409 ch[1] = HIBYTE(*wparam);
410 RtlMultiByteToUnicodeN( wch, sizeof(wch), NULL, ch, 2 );
411 TRACE( "map %02x,%02x -> %04x mapping %u\n", (BYTE)ch[0], (BYTE)ch[1], wch[0], mapping );
412 if (data) data->lead_byte[mapping] = 0;
413 }
414 else if (data && data->lead_byte[mapping])
415 {
416 ch[0] = data->lead_byte[mapping];
417 ch[1] = low;
418 RtlMultiByteToUnicodeN( wch, sizeof(wch), NULL, ch, 2 );
419 TRACE( "map stored %02x,%02x -> %04x mapping %u\n", (BYTE)ch[0], (BYTE)ch[1], wch[0], mapping );
420 data->lead_byte[mapping] = 0;
421 }
422 else if (!IsDBCSLeadByte( low ))
423 {
424 ch[0] = low;
425 RtlMultiByteToUnicodeN( wch, sizeof(wch), NULL, ch, 1 );
426 TRACE( "map %02x -> %04x\n", (BYTE)ch[0], wch[0] );
427 if (data) data->lead_byte[mapping] = 0;
428 }
429 else /* store it and wait for trail byte */
430 {
431 if (!data)
432 {
433 if (!(data = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*data) )))
434 return FALSE;
435 get_user_thread_info()->wmchar_data = data;
436 }
437 TRACE( "storing lead byte %02x mapping %u\n", low, mapping );
438 data->lead_byte[mapping] = low;
439 return FALSE;
440 }
441 *wparam = MAKEWPARAM(wch[0], wch[1]);
442 break;
443 }
444 /* else fall through */
445 case WM_CHARTOITEM:
446 case EM_SETPASSWORDCHAR:
447 case WM_DEADCHAR:
448 case WM_SYSCHAR:
449 case WM_SYSDEADCHAR:
450 case WM_MENUCHAR:
451 ch[0] = LOBYTE(*wparam);
452 ch[1] = HIBYTE(*wparam);
453 RtlMultiByteToUnicodeN( wch, sizeof(wch), NULL, ch, 2 );
454 *wparam = MAKEWPARAM(wch[0], wch[1]);
455 break;
456 case WM_IME_CHAR:
457 ch[0] = HIBYTE(*wparam);
458 ch[1] = LOBYTE(*wparam);
459 if (ch[0]) RtlMultiByteToUnicodeN( wch, sizeof(wch[0]), NULL, ch, 2 );
460 else RtlMultiByteToUnicodeN( wch, sizeof(wch[0]), NULL, ch + 1, 1 );
461 *wparam = MAKEWPARAM(wch[0], HIWORD(*wparam));
462 break;
463 }
464 return TRUE;
465 }
466
467
468 /***********************************************************************
469 * map_wparam_WtoA
470 *
471 * Convert the wparam of a Unicode message to ASCII.
472 */
473 static void map_wparam_WtoA( MSG *msg, BOOL remove )
474 {
475 BYTE ch[2];
476 WCHAR wch[2];
477 DWORD len;
478
479 switch(msg->message)
480 {
481 case WM_CHAR:
482 if (!HIWORD(msg->wParam))
483 {
484 wch[0] = LOWORD(msg->wParam);
485 ch[0] = ch[1] = 0;
486 RtlUnicodeToMultiByteN( (LPSTR)ch, 2, &len, wch, sizeof(wch[0]) );
487 if (len == 2) /* DBCS char */
488 {
489 struct wm_char_mapping_data *data = get_user_thread_info()->wmchar_data;
490 if (!data)
491 {
492 if (!(data = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*data) ))) return;
493 get_user_thread_info()->wmchar_data = data;
494 }
495 if (remove)
496 {
497 data->get_msg = *msg;
498 data->get_msg.wParam = ch[1];
499 }
500 msg->wParam = ch[0];
501 return;
502 }
503 }
504 /* else fall through */
505 case WM_CHARTOITEM:
506 case EM_SETPASSWORDCHAR:
507 case WM_DEADCHAR:
508 case WM_SYSCHAR:
509 case WM_SYSDEADCHAR:
510 case WM_MENUCHAR:
511 wch[0] = LOWORD(msg->wParam);
512 wch[1] = HIWORD(msg->wParam);
513 ch[0] = ch[1] = 0;
514 RtlUnicodeToMultiByteN( (LPSTR)ch, 2, NULL, wch, sizeof(wch) );
515 msg->wParam = MAKEWPARAM( ch[0] | (ch[1] << 8), 0 );
516 break;
517 case WM_IME_CHAR:
518 wch[0] = LOWORD(msg->wParam);
519 ch[0] = ch[1] = 0;
520 RtlUnicodeToMultiByteN( (LPSTR)ch, 2, &len, wch, sizeof(wch[0]) );
521 if (len == 2)
522 msg->wParam = MAKEWPARAM( (ch[0] << 8) | ch[1], HIWORD(msg->wParam) );
523 else
524 msg->wParam = MAKEWPARAM( ch[0], HIWORD(msg->wParam) );
525 break;
526 }
527 }
528
529
530 /***********************************************************************
531 * pack_message
532 *
533 * Pack a message for sending to another process.
534 * Return the size of the data we expect in the message reply.
535 * Set data->count to -1 if there is an error.
536 */
537 static size_t pack_message( HWND hwnd, UINT message, WPARAM wparam, LPARAM lparam,
538 struct packed_message *data )
539 {
540 data->count = 0;
541 switch(message)
542 {
543 case WM_NCCREATE:
544 case WM_CREATE:
545 {
546 CREATESTRUCTW *cs = (CREATESTRUCTW *)lparam;
547 push_data( data, cs, sizeof(*cs) );
548 if (HIWORD(cs->lpszName)) push_string( data, cs->lpszName );
549 if (HIWORD(cs->lpszClass)) push_string( data, cs->lpszClass );
550 return sizeof(*cs);
551 }
552 case WM_GETTEXT:
553 case WM_ASKCBFORMATNAME:
554 return wparam * sizeof(WCHAR);
555 case WM_WININICHANGE:
556 if (lparam) push_string(data, (LPWSTR)lparam );
557 return 0;
558 case WM_SETTEXT:
559 case WM_DEVMODECHANGE:
560 case CB_DIR:
561 case LB_DIR:
562 case LB_ADDFILE:
563 case EM_REPLACESEL:
564 push_string( data, (LPWSTR)lparam );
565 return 0;
566 case WM_GETMINMAXINFO:
567 push_data( data, (MINMAXINFO *)lparam, sizeof(MINMAXINFO) );
568 return sizeof(MINMAXINFO);
569 case WM_DRAWITEM:
570 push_data( data, (DRAWITEMSTRUCT *)lparam, sizeof(DRAWITEMSTRUCT) );
571 return 0;
572 case WM_MEASUREITEM:
573 push_data( data, (MEASUREITEMSTRUCT *)lparam, sizeof(MEASUREITEMSTRUCT) );
574 return sizeof(MEASUREITEMSTRUCT);
575 case WM_DELETEITEM:
576 push_data( data, (DELETEITEMSTRUCT *)lparam, sizeof(DELETEITEMSTRUCT) );
577 return 0;
578 case WM_COMPAREITEM:
579 push_data( data, (COMPAREITEMSTRUCT *)lparam, sizeof(COMPAREITEMSTRUCT) );
580 return 0;
581 case WM_WINDOWPOSCHANGING:
582 case WM_WINDOWPOSCHANGED:
583 push_data( data, (WINDOWPOS *)lparam, sizeof(WINDOWPOS) );
584 return sizeof(WINDOWPOS);
585 case WM_COPYDATA:
586 {
587 COPYDATASTRUCT *cp = (COPYDATASTRUCT *)lparam;
588 push_data( data, cp, sizeof(*cp) );
589 if (cp->lpData) push_data( data, cp->lpData, cp->cbData );
590 return 0;
591 }
592 case WM_NOTIFY:
593 /* WM_NOTIFY cannot be sent across processes (MSDN) */
594 data->count = -1;
595 return 0;
596 case WM_HELP:
597 push_data( data, (HELPINFO *)lparam, sizeof(HELPINFO) );
598 return 0;
599 case WM_STYLECHANGING:
600 case WM_STYLECHANGED:
601 push_data( data, (STYLESTRUCT *)lparam, sizeof(STYLESTRUCT) );
602 return 0;
603 case WM_NCCALCSIZE:
604 if (!wparam)
605 {
606 push_data( data, (RECT *)lparam, sizeof(RECT) );
607 return sizeof(RECT);
608 }
609 else
610 {
611 NCCALCSIZE_PARAMS *nc = (NCCALCSIZE_PARAMS *)lparam;
612 push_data( data, nc, sizeof(*nc) );
613 push_data( data, nc->lppos, sizeof(*nc->lppos) );
614 return sizeof(*nc) + sizeof(*nc->lppos);
615 }
616 case WM_GETDLGCODE:
617 if (lparam) push_data( data, (MSG *)lparam, sizeof(MSG) );
618 return sizeof(MSG);
619 case SBM_SETSCROLLINFO:
620 push_data( data, (SCROLLINFO *)lparam, sizeof(SCROLLINFO) );
621 return 0;
622 case SBM_GETSCROLLINFO:
623 push_data( data, (SCROLLINFO *)lparam, sizeof(SCROLLINFO) );
624 return sizeof(SCROLLINFO);
625 case SBM_GETSCROLLBARINFO:
626 {
627 const SCROLLBARINFO *info = (const SCROLLBARINFO *)lparam;
628 size_t size = min( info->cbSize, sizeof(SCROLLBARINFO) );
629 push_data( data, info, size );
630 return size;
631 }
632 case EM_GETSEL:
633 case SBM_GETRANGE:
634 case CB_GETEDITSEL:
635 {
636 size_t size = 0;
637 if (wparam) size += sizeof(DWORD);
638 if (lparam) size += sizeof(DWORD);
639 return size;
640 }
641 case EM_GETRECT:
642 case LB_GETITEMRECT:
643 case CB_GETDROPPEDCONTROLRECT:
644 return sizeof(RECT);
645 case EM_SETRECT:
646 case EM_SETRECTNP:
647 push_data( data, (RECT *)lparam, sizeof(RECT) );
648 return 0;
649 case EM_GETLINE:
650 {
651 WORD *pw = (WORD *)lparam;
652 push_data( data, pw, sizeof(*pw) );
653 return *pw * sizeof(WCHAR);
654 }
655 case EM_SETTABSTOPS:
656 case LB_SETTABSTOPS:
657 if (wparam) push_data( data, (UINT *)lparam, sizeof(UINT) * wparam );
658 return 0;
659 case CB_ADDSTRING:
660 case CB_INSERTSTRING:
661 case CB_FINDSTRING:
662 case CB_FINDSTRINGEXACT:
663 case CB_SELECTSTRING:
664 if (combobox_has_strings( hwnd )) push_string( data, (LPWSTR)lparam );
665 return 0;
666 case CB_GETLBTEXT:
667 if (!combobox_has_strings( hwnd )) return sizeof(ULONG_PTR);
668 return (SendMessageW( hwnd, CB_GETLBTEXTLEN, wparam, 0 ) + 1) * sizeof(WCHAR);
669 case LB_ADDSTRING:
670 case LB_INSERTSTRING:
671 case LB_FINDSTRING:
672 case LB_FINDSTRINGEXACT:
673 case LB_SELECTSTRING:
674 if (listbox_has_strings( hwnd )) push_string( data, (LPWSTR)lparam );
675 return 0;
676 case LB_GETTEXT:
677 if (!listbox_has_strings( hwnd )) return sizeof(ULONG_PTR);
678 return (SendMessageW( hwnd, LB_GETTEXTLEN, wparam, 0 ) + 1) * sizeof(WCHAR);
679 case LB_GETSELITEMS:
680 return wparam * sizeof(UINT);
681 case WM_NEXTMENU:
682 push_data( data, (MDINEXTMENU *)lparam, sizeof(MDINEXTMENU) );
683 return sizeof(MDINEXTMENU);
684 case WM_SIZING:
685 case WM_MOVING:
686 push_data( data, (RECT *)lparam, sizeof(RECT) );
687 return sizeof(RECT);
688 case WM_MDICREATE:
689 {
690 MDICREATESTRUCTW *cs = (MDICREATESTRUCTW *)lparam;
691 push_data( data, cs, sizeof(*cs) );
692 if (HIWORD(cs->szTitle)) push_string( data, cs->szTitle );
693 if (HIWORD(cs->szClass)) push_string( data, cs->szClass );
694 return sizeof(*cs);
695 }
696 case WM_MDIGETACTIVE:
697 if (lparam) return sizeof(BOOL);
698 return 0;
699 case WM_DEVICECHANGE:
700 {
701 DEV_BROADCAST_HDR *header = (DEV_BROADCAST_HDR *)lparam;
702 push_data( data, header, header->dbch_size );
703 return 0;
704 }
705 case WM_WINE_SETWINDOWPOS:
706 push_data( data, (WINDOWPOS *)lparam, sizeof(WINDOWPOS) );
707 return 0;
708 case WM_WINE_KEYBOARD_LL_HOOK:
709 {
710 struct hook_extra_info *h_extra = (struct hook_extra_info *)lparam;
711 push_data( data, h_extra, sizeof(*h_extra) );
712 push_data( data, (LPVOID)h_extra->lparam, sizeof(KBDLLHOOKSTRUCT) );
713 return 0;
714 }
715 case WM_WINE_MOUSE_LL_HOOK:
716 {
717 struct hook_extra_info *h_extra = (struct hook_extra_info *)lparam;
718 push_data( data, h_extra, sizeof(*h_extra) );
719 push_data( data, (LPVOID)h_extra->lparam, sizeof(MSLLHOOKSTRUCT) );
720 return 0;
721 }
722 case WM_NCPAINT:
723 if (wparam <= 1) return 0;
724 FIXME( "WM_NCPAINT hdc packing not supported yet\n" );
725 data->count = -1;
726 return 0;
727 case WM_PAINT:
728 if (!wparam) return 0;
729 /* fall through */
730
731 /* these contain an HFONT */
732 case WM_SETFONT:
733 case WM_GETFONT:
734 /* these contain an HDC */
735 case WM_ERASEBKGND:
736 case WM_ICONERASEBKGND:
737 case WM_CTLCOLORMSGBOX:
738 case WM_CTLCOLOREDIT:
739 case WM_CTLCOLORLISTBOX:
740 case WM_CTLCOLORBTN:
741 case WM_CTLCOLORDLG:
742 case WM_CTLCOLORSCROLLBAR:
743 case WM_CTLCOLORSTATIC:
744 case WM_PRINT:
745 case WM_PRINTCLIENT:
746 /* these contain an HGLOBAL */
747 case WM_PAINTCLIPBOARD:
748 case WM_SIZECLIPBOARD:
749 /* these contain HICON */
750 case WM_GETICON:
751 case WM_SETICON:
752 case WM_QUERYDRAGICON:
753 case WM_QUERYPARKICON:
754 /* these contain pointers */
755 case WM_DROPOBJECT:
756 case WM_QUERYDROPOBJECT:
757 case WM_DRAGLOOP:
758 case WM_DRAGSELECT:
759 case WM_DRAGMOVE:
760 FIXME( "msg %x (%s) not supported yet\n", message, SPY_GetMsgName(message, hwnd) );
761 data->count = -1;
762 return 0;
763 }
764 return 0;
765 }
766
767
768 /***********************************************************************
769 * unpack_message
770 *
771 * Unpack a message received from another process.
772 */
773 static BOOL unpack_message( HWND hwnd, UINT message, WPARAM *wparam, LPARAM *lparam,
774 void **buffer, size_t size )
775 {
776 size_t minsize = 0;
777
778 switch(message)
779 {
780 case WM_NCCREATE:
781 case WM_CREATE:
782 {
783 CREATESTRUCTW *cs = *buffer;
784 WCHAR *str = (WCHAR *)(cs + 1);
785 if (size < sizeof(*cs)) return FALSE;
786 size -= sizeof(*cs);
787 if (HIWORD(cs->lpszName))
788 {
789 if (!check_string( str, size )) return FALSE;
790 cs->lpszName = str;
791 size -= (strlenW(str) + 1) * sizeof(WCHAR);
792 str += strlenW(str) + 1;
793 }
794 if (HIWORD(cs->lpszClass))
795 {
796 if (!check_string( str, size )) return FALSE;
797 cs->lpszClass = str;
798 }
799 break;
800 }
801 case WM_GETTEXT:
802 case WM_ASKCBFORMATNAME:
803 if (!get_buffer_space( buffer, (*wparam * sizeof(WCHAR)) )) return FALSE;
804 break;
805 case WM_WININICHANGE:
806 if (!*lparam) return TRUE;
807 /* fall through */
808 case WM_SETTEXT:
809 case WM_DEVMODECHANGE:
810 case CB_DIR:
811 case LB_DIR:
812 case LB_ADDFILE:
813 case EM_REPLACESEL:
814 if (!check_string( *buffer, size )) return FALSE;
815 break;
816 case WM_GETMINMAXINFO:
817 minsize = sizeof(MINMAXINFO);
818 break;
819 case WM_DRAWITEM:
820 minsize = sizeof(DRAWITEMSTRUCT);
821 break;
822 case WM_MEASUREITEM:
823 minsize = sizeof(MEASUREITEMSTRUCT);
824 break;
825 case WM_DELETEITEM:
826 minsize = sizeof(DELETEITEMSTRUCT);
827 break;
828 case WM_COMPAREITEM:
829 minsize = sizeof(COMPAREITEMSTRUCT);
830 break;
831 case WM_WINDOWPOSCHANGING:
832 case WM_WINDOWPOSCHANGED:
833 case WM_WINE_SETWINDOWPOS:
834 minsize = sizeof(WINDOWPOS);
835 break;
836 case WM_COPYDATA:
837 {
838 COPYDATASTRUCT *cp = *buffer;
839 if (size < sizeof(*cp)) return FALSE;
840 if (cp->lpData)
841 {
842 minsize = sizeof(*cp) + cp->cbData;
843 cp->lpData = cp + 1;
844 }
845 break;
846 }
847 case WM_NOTIFY:
848 /* WM_NOTIFY cannot be sent across processes (MSDN) */
849 return FALSE;
850 case WM_HELP:
851 minsize = sizeof(HELPINFO);
852 break;
853 case WM_STYLECHANGING:
854 case WM_STYLECHANGED:
855 minsize = sizeof(STYLESTRUCT);
856 break;
857 case WM_NCCALCSIZE:
858 if (!*wparam) minsize = sizeof(RECT);
859 else
860 {
861 NCCALCSIZE_PARAMS *nc = *buffer;
862 if (size < sizeof(*nc) + sizeof(*nc->lppos)) return FALSE;
863 <