~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~ [ freetext search ] ~ [ file search ] ~

Wine Cross Reference
wine/dlls/user32/message.c

Version: ~ [ wine-1.1.8 ] ~ [ wine-1.1.7 ] ~ [ wine-1.0.1 ] ~ [ wine-1.1.6 ] ~ [ wine-1.1.5 ] ~ [ wine-1.1.4 ] ~ [ wine-1.1.3 ] ~ [ wine-1.1.2 ] ~ [ wine-1.1.1 ] ~ [ wine-1.1.0 ] ~ [ wine-1.0 ] ~ [ wine-1.0-rc5 ] ~ [ wine-1.0-rc4 ] ~ [ wine-1.0-rc3 ] ~ [ wine-1.0-rc2 ] ~ [ wine-1.0-rc1 ] ~ [ wine-0.9.61 ] ~ [ wine-0.9.60 ] ~ [ wine-0.9.59 ] ~ [ wine-0.9.58 ] ~ [ wine-0.9.57 ] ~ [ wine-0.9.56 ] ~ [ wine-0.9.55 ] ~ [ wine-0.9.54 ] ~ [ wine-0.9.53 ] ~ [ wine-0.9.52 ] ~ [ wine-0.9.51 ] ~ [ wine-0.9.50 ] ~ [ wine-0.9.49 ] ~ [ wine-0.9.48 ] ~ [ wine-0.9.47 ] ~ [ wine-0.9.46 ] ~ [ wine-0.9.45 ] ~ [ wine-0.9.44 ] ~ [ wine-0.9.43 ] ~ [ wine-0.9.42 ] ~ [ wine-0.9.41 ] ~ [ wine-0.9.40 ] ~ [ wine-0.9.39 ] ~ [ wine-0.9.38 ] ~ [ wine-0.9.37 ] ~ [ wine-0.9.36 ] ~ [ wine-0.9.35 ] ~ [ wine-0.9.34 ] ~ [ wine-0.9.33 ] ~ [ wine-0.9.32 ] ~ [ wine-0.9.31 ] ~ [ wine-0.9.30 ] ~ [ wine-0.9.29 ] ~ [ wine-0.9.28 ] ~ [ wine-0.9.27 ] ~ [ wine-0.9.26 ] ~ [ wine-0.9.25 ] ~ [ wine-0.9.24 ] ~ [ wine-0.9.23 ] ~ [ wine-0.9.22 ] ~ [ wine-0.9.21 ] ~ [ wine-0.9.20 ] ~ [ wine-0.9.19 ] ~ [ wine-0.9.18 ] ~ [ wine-0.9.17 ] ~ [ wine-0.9.16 ] ~ [ wine-0.9.15 ] ~ [ wine-0.9.14 ] ~ [ wine-0.9.13 ] ~ [ wine-0.9.12 ] ~ [ wine-0.9.11 ] ~ [ wine-0.9.10 ] ~ [ wine-0.9.9 ] ~ [ wine-0.9.8 ] ~ [ wine-0.9.7 ] ~ [ wine-0.9.6 ] ~ [ wine-0.9.5 ] ~ [ wine-0.9.4 ] ~ [ wine-0.9.3 ] ~ [ wine-0.9.2 ] ~ [ wine-0.9.1 ] ~ [ wine-0.9 ] ~ [ wine20050930 ] ~ [ wine20050830 ] ~ [ wine20050725 ] ~ [ wine20050628 ] ~ [ wine20050524 ] ~ [ wine20050419 ] ~ [ wine20050310 ] ~ [ wine20050211 ] ~ [ wine20050111 ] ~ [ wine20041201 ] ~ [ wine20041019 ] ~ [ wine20040914 ] ~ [ wine20040813 ] ~ [ wine20040716 ] ~ [ wine20040615 ] ~ [ wine20040505 ] ~ [ wine20040408 ] ~ [ wine20040309 ] ~ [ wine20040213 ] ~ [ wine20040121 ] ~ [ wine20031212 ] ~ [ wine20031118 ] ~ [ wine20031016 ] ~ [ wine20030911 ] ~ [ wine20030813 ] ~ [ wine20030709 ] ~ [ wine20030618 ] ~ [ wine20030508 ] ~ [ wine20030408 ] ~ [ wine20030318 ] ~ [ wine20030219 ] ~ [ wine20030115 ] ~ [ wine20021219 ] ~ [ wine20021125 ] ~ [ wine20021031 ] ~ [ wine20021007 ] ~ [ wine20020904 ] ~ [ wine20020804 ] ~ [ wine20020710 ] ~ [ wine20020605 ] ~ [ wine20020509 ] ~ [ wine20020411 ] ~ [ wine20020310 ] ~ [ wine20020228 ] ~ [ wine20011226 ] ~ [ wine20011108 ] ~ [ wine20011004 ] ~ [ wine20010824 ] ~ [ wine20010731 ] ~ [ wine20010629 ] ~ [ wine20010510 ] ~ [ wine20010418 ] ~ [ wine20010326 ] ~ [ wine20010305 ] ~ [ wine20010216 ] ~ [ wine20010112 ] ~ [ wine20001222 ] ~ [ wine20001202 ] ~ [ wine20001026 ] ~ [ wine20001002 ] ~ [ wine20000909 ] ~ [ wine20000821 ] ~ [ wine20000801 ] ~ [ wine20000716 ] ~ [ wine20000326 ] ~ [ wine20000227 ] ~ [ wine20000130 ] ~ [ wine20000109 ] ~

  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             <