user: Added fast A->W mapping for the remaining messages.
[wine] / dlls / user / winproc.c
1 /*
2  * Window procedure callbacks
3  *
4  * Copyright 1995 Martin von Loewis
5  * Copyright 1996 Alexandre Julliard
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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
20  */
21
22 #include "config.h"
23 #include "wine/port.h"
24
25 #include <assert.h>
26 #include <stdarg.h>
27 #include <string.h>
28
29 #include "windef.h"
30 #include "winbase.h"
31 #include "wingdi.h"
32 #include "wownt32.h"
33 #include "wine/winbase16.h"
34 #include "wine/winuser16.h"
35 #include "controls.h"
36 #include "win.h"
37 #include "winproc.h"
38 #include "user_private.h"
39 #include "dde.h"
40 #include "winternl.h"
41 #include "wine/unicode.h"
42 #include "wine/debug.h"
43
44 WINE_DECLARE_DEBUG_CHANNEL(msg);
45 WINE_DECLARE_DEBUG_CHANNEL(relay);
46 WINE_DEFAULT_DEBUG_CHANNEL(win);
47
48 typedef struct tagWINDOWPROC
49 {
50     WNDPROC16      proc16;   /* 16-bit window proc */
51     WNDPROC        procA;    /* ASCII window proc */
52     WNDPROC        procW;    /* Unicode window proc */
53 } WINDOWPROC;
54
55 #define WINPROC_HANDLE (~0UL >> 16)
56 #define MAX_WINPROCS  8192
57
58 static WINDOWPROC winproc_array[MAX_WINPROCS];
59 static UINT winproc_used;
60
61 static CRITICAL_SECTION winproc_cs;
62 static CRITICAL_SECTION_DEBUG critsect_debug =
63 {
64     0, 0, &winproc_cs,
65     { &critsect_debug.ProcessLocksList, &critsect_debug.ProcessLocksList },
66       0, 0, { (DWORD_PTR)(__FILE__ ": winproc_cs") }
67 };
68 static CRITICAL_SECTION winproc_cs = { &critsect_debug, -1, 0, 0, 0, 0 };
69
70 static inline void *get_buffer( void *static_buffer, size_t size, size_t need )
71 {
72     if (size >= need) return static_buffer;
73     return HeapAlloc( GetProcessHeap(), 0, need );
74 }
75
76 static inline void free_buffer( void *static_buffer, void *buffer )
77 {
78     if (buffer != static_buffer) HeapFree( GetProcessHeap(), 0, buffer );
79 }
80
81 /* map a Unicode string to a 16-bit pointer */
82 inline static SEGPTR map_str_32W_to_16( LPCWSTR str )
83 {
84     LPSTR ret;
85     INT len;
86
87     if (!HIWORD(str)) return (SEGPTR)LOWORD(str);
88     len = WideCharToMultiByte( CP_ACP, 0, str, -1, NULL, 0, NULL, NULL );
89     if ((ret = HeapAlloc( GetProcessHeap(), 0, len )))
90         WideCharToMultiByte( CP_ACP, 0, str, -1, ret, len, NULL, NULL );
91     return MapLS(ret);
92 }
93
94 /* unmap a Unicode string that was converted to a 16-bit pointer */
95 inline static void unmap_str_32W_to_16( SEGPTR str )
96 {
97     if (!HIWORD(str)) return;
98     HeapFree( GetProcessHeap(), 0, MapSL(str) );
99     UnMapLS( str );
100 }
101
102 /* map a 16-bit pointer to a Unicode string */
103 inline static LPWSTR map_str_16_to_32W( SEGPTR str )
104 {
105     LPWSTR ret;
106     INT len;
107
108     if (!HIWORD(str)) return (LPWSTR)(ULONG_PTR)LOWORD(str);
109     len = MultiByteToWideChar( CP_ACP, 0, MapSL(str), -1, NULL, 0 );
110     if ((ret = HeapAlloc( GetProcessHeap(), 0, len * sizeof(WCHAR) )))
111         MultiByteToWideChar( CP_ACP, 0, MapSL(str), -1, ret, len );
112     return ret;
113 }
114
115 /* unmap a 16-bit pointer that was converted to a Unicode string */
116 inline static void unmap_str_16_to_32W( LPCWSTR str )
117 {
118     if (HIWORD(str)) HeapFree( GetProcessHeap(), 0, (void *)str );
119 }
120
121 /* find an existing winproc for a given 16-bit function and type */
122 /* FIXME: probably should do something more clever than a linear search */
123 static inline WINDOWPROC *find_winproc16( WNDPROC16 func )
124 {
125     unsigned int i;
126
127     for (i = 0; i < winproc_used; i++)
128     {
129         if (winproc_array[i].proc16 == func) return &winproc_array[i];
130     }
131     return NULL;
132 }
133
134 /* find an existing winproc for a given function and type */
135 /* FIXME: probably should do something more clever than a linear search */
136 static inline WINDOWPROC *find_winproc( WNDPROC funcA, WNDPROC funcW )
137 {
138     unsigned int i;
139
140     for (i = 0; i < winproc_used; i++)
141     {
142         if (funcA && winproc_array[i].procA != funcA) continue;
143         if (funcW && winproc_array[i].procW != funcW) continue;
144         return &winproc_array[i];
145     }
146     return NULL;
147 }
148
149 /* return the window proc for a given handle, or NULL for an invalid handle */
150 static inline WINDOWPROC *handle_to_proc( WNDPROC handle )
151 {
152     UINT index = LOWORD(handle);
153     if ((ULONG_PTR)handle >> 16 != WINPROC_HANDLE) return NULL;
154     if (index >= winproc_used) return NULL;
155     return &winproc_array[index];
156 }
157
158 /* create a handle for a given window proc */
159 static inline WNDPROC proc_to_handle( WINDOWPROC *proc )
160 {
161     return (WNDPROC)(ULONG_PTR)((proc - winproc_array) | (WINPROC_HANDLE << 16));
162 }
163
164 /* allocate and initialize a new winproc */
165 static inline WINDOWPROC *alloc_winproc( WNDPROC funcA, WNDPROC funcW )
166 {
167     WINDOWPROC *proc;
168
169     /* check if the function is already a win proc */
170     if (funcA && (proc = handle_to_proc( funcA ))) return proc;
171     if (funcW && (proc = handle_to_proc( funcW ))) return proc;
172     if (!funcA && !funcW) return NULL;
173
174     EnterCriticalSection( &winproc_cs );
175
176     /* check if we already have a winproc for that function */
177     if (!(proc = find_winproc( funcA, funcW )))
178     {
179         if (winproc_used < MAX_WINPROCS)
180         {
181             proc = &winproc_array[winproc_used++];
182             proc->procA = funcA;
183             proc->procW = funcW;
184             TRACE( "allocated %p for %p/%p (%d/%d used)\n",
185                    proc_to_handle(proc), funcA, funcW, winproc_used, MAX_WINPROCS );
186         }
187         else FIXME( "too many winprocs, cannot allocate one for %p/%p\n", funcA, funcW );
188     }
189     else TRACE( "reusing %p for %p/%p\n", proc_to_handle(proc), funcA, funcW );
190
191     LeaveCriticalSection( &winproc_cs );
192     return proc;
193 }
194
195
196 #ifdef __i386__
197
198 #include "pshpack1.h"
199
200 /* Window procedure 16-to-32-bit thunk */
201 typedef struct
202 {
203     BYTE        popl_eax;        /* popl  %eax (return address) */
204     BYTE        pushl_func;      /* pushl $proc */
205     WINDOWPROC *proc;
206     BYTE        pushl_eax;       /* pushl %eax */
207     BYTE        ljmp;            /* ljmp relay*/
208     DWORD       relay_offset;    /* __wine_call_wndproc */
209     WORD        relay_sel;
210 } WINPROC_THUNK;
211
212 #include "poppack.h"
213
214 #define MAX_THUNKS  (0x10000 / sizeof(WINPROC_THUNK))
215
216 static WINPROC_THUNK *thunk_array;
217 static UINT thunk_selector;
218 static UINT thunk_used;
219
220 /* return the window proc for a given handle, or NULL for an invalid handle */
221 static inline WINDOWPROC *handle16_to_proc( WNDPROC16 handle )
222 {
223     if (HIWORD(handle) == thunk_selector)
224     {
225         UINT index = LOWORD(handle) / sizeof(WINPROC_THUNK);
226         /* check alignment */
227         if (index * sizeof(WINPROC_THUNK) != LOWORD(handle)) return NULL;
228         /* check array limits */
229         if (index >= thunk_used) return NULL;
230         return thunk_array[index].proc;
231     }
232     return handle_to_proc( (WNDPROC)handle );
233 }
234
235 /* allocate a 16-bit thunk for an existing window proc */
236 static WNDPROC16 alloc_win16_thunk( WINDOWPROC *proc )
237 {
238     static FARPROC16 relay;
239     UINT i;
240
241     if (proc->proc16) return proc->proc16;
242
243     EnterCriticalSection( &winproc_cs );
244
245     if (!thunk_array)  /* allocate the array and its selector */
246     {
247         LDT_ENTRY entry;
248
249         if (!(thunk_selector = wine_ldt_alloc_entries(1))) goto done;
250         if (!(thunk_array = VirtualAlloc( NULL, MAX_THUNKS * sizeof(WINPROC_THUNK), MEM_COMMIT,
251                                           PAGE_EXECUTE_READWRITE ))) goto done;
252         wine_ldt_set_base( &entry, thunk_array );
253         wine_ldt_set_limit( &entry, MAX_THUNKS * sizeof(WINPROC_THUNK) - 1 );
254         wine_ldt_set_flags( &entry, WINE_LDT_FLAGS_CODE | WINE_LDT_FLAGS_32BIT );
255         wine_ldt_set_entry( thunk_selector, &entry );
256         relay = GetProcAddress16( GetModuleHandle16("user"), "__wine_call_wndproc" );
257     }
258
259     /* check if it already exists */
260     for (i = 0; i < thunk_used; i++) if (thunk_array[i].proc == proc) break;
261
262     if (i == thunk_used)  /* create a new one */
263     {
264         WINPROC_THUNK *thunk;
265
266         if (thunk_used >= MAX_THUNKS) goto done;
267         thunk = &thunk_array[thunk_used++];
268         thunk->popl_eax     = 0x58;   /* popl  %eax */
269         thunk->pushl_func   = 0x68;   /* pushl $proc */
270         thunk->proc         = proc;
271         thunk->pushl_eax    = 0x50;   /* pushl %eax */
272         thunk->ljmp         = 0xea;   /* ljmp   relay*/
273         thunk->relay_offset = OFFSETOF(relay);
274         thunk->relay_sel    = SELECTOROF(relay);
275     }
276     proc->proc16 = (WNDPROC16)MAKESEGPTR( thunk_selector, i * sizeof(WINPROC_THUNK) );
277 done:
278     LeaveCriticalSection( &winproc_cs );
279     return proc->proc16;
280 }
281
282 #else  /* __i386__ */
283
284 static inline WINDOWPROC *handle16_to_proc( WNDPROC16 handle )
285 {
286     return handle_to_proc( (WNDPROC)handle );
287 }
288
289 static inline WNDPROC16 alloc_win16_thunk( WINDOWPROC *proc )
290 {
291     return 0;
292 }
293
294 #endif  /* __i386__ */
295
296
297 #ifdef __i386__
298 /* Some window procedures modify register they shouldn't, or are not
299  * properly declared stdcall; so we need a small assembly wrapper to
300  * call them. */
301 extern LRESULT WINPROC_wrapper( WNDPROC proc, HWND hwnd, UINT msg,
302                                 WPARAM wParam, LPARAM lParam );
303 __ASM_GLOBAL_FUNC( WINPROC_wrapper,
304                    "pushl %ebp\n\t"
305                    "movl %esp,%ebp\n\t"
306                    "pushl %edi\n\t"
307                    "pushl %esi\n\t"
308                    "pushl %ebx\n\t"
309                    "subl $12,%esp\n\t"
310                    "pushl 24(%ebp)\n\t"
311                    "pushl 20(%ebp)\n\t"
312                    "pushl 16(%ebp)\n\t"
313                    "pushl 12(%ebp)\n\t"
314                    "movl 8(%ebp),%eax\n\t"
315                    "call *%eax\n\t"
316                    "leal -12(%ebp),%esp\n\t"
317                    "popl %ebx\n\t"
318                    "popl %esi\n\t"
319                    "popl %edi\n\t"
320                    "leave\n\t"
321                    "ret" );
322 #else
323 static inline LRESULT WINPROC_wrapper( WNDPROC proc, HWND hwnd, UINT msg,
324                                        WPARAM wParam, LPARAM lParam )
325 {
326     return proc( hwnd, msg, wParam, lParam );
327 }
328 #endif  /* __i386__ */
329
330
331 static void MINMAXINFO32to16( const MINMAXINFO *from, MINMAXINFO16 *to )
332 {
333     to->ptReserved.x     = from->ptReserved.x;
334     to->ptReserved.y     = from->ptReserved.y;
335     to->ptMaxSize.x      = from->ptMaxSize.x;
336     to->ptMaxSize.y      = from->ptMaxSize.y;
337     to->ptMaxPosition.x  = from->ptMaxPosition.x;
338     to->ptMaxPosition.y  = from->ptMaxPosition.y;
339     to->ptMinTrackSize.x = from->ptMinTrackSize.x;
340     to->ptMinTrackSize.y = from->ptMinTrackSize.y;
341     to->ptMaxTrackSize.x = from->ptMaxTrackSize.x;
342     to->ptMaxTrackSize.y = from->ptMaxTrackSize.y;
343 }
344
345 static void MINMAXINFO16to32( const MINMAXINFO16 *from, MINMAXINFO *to )
346 {
347     to->ptReserved.x     = from->ptReserved.x;
348     to->ptReserved.y     = from->ptReserved.y;
349     to->ptMaxSize.x      = from->ptMaxSize.x;
350     to->ptMaxSize.y      = from->ptMaxSize.y;
351     to->ptMaxPosition.x  = from->ptMaxPosition.x;
352     to->ptMaxPosition.y  = from->ptMaxPosition.y;
353     to->ptMinTrackSize.x = from->ptMinTrackSize.x;
354     to->ptMinTrackSize.y = from->ptMinTrackSize.y;
355     to->ptMaxTrackSize.x = from->ptMaxTrackSize.x;
356     to->ptMaxTrackSize.y = from->ptMaxTrackSize.y;
357 }
358
359 static void WINDOWPOS32to16( const WINDOWPOS* from, WINDOWPOS16* to )
360 {
361     to->hwnd            = HWND_16(from->hwnd);
362     to->hwndInsertAfter = HWND_16(from->hwndInsertAfter);
363     to->x               = from->x;
364     to->y               = from->y;
365     to->cx              = from->cx;
366     to->cy              = from->cy;
367     to->flags           = from->flags;
368 }
369
370 static void WINDOWPOS16to32( const WINDOWPOS16* from, WINDOWPOS* to )
371 {
372     to->hwnd            = WIN_Handle32(from->hwnd);
373     to->hwndInsertAfter = (from->hwndInsertAfter == (HWND16)-1) ?
374                            HWND_TOPMOST : WIN_Handle32(from->hwndInsertAfter);
375     to->x               = from->x;
376     to->y               = from->y;
377     to->cx              = from->cx;
378     to->cy              = from->cy;
379     to->flags           = from->flags;
380 }
381
382 /* The strings are not copied */
383 static void CREATESTRUCT32Ato16( const CREATESTRUCTA* from, CREATESTRUCT16* to )
384 {
385     to->lpCreateParams = (SEGPTR)from->lpCreateParams;
386     to->hInstance      = HINSTANCE_16(from->hInstance);
387     to->hMenu          = HMENU_16(from->hMenu);
388     to->hwndParent     = HWND_16(from->hwndParent);
389     to->cy             = from->cy;
390     to->cx             = from->cx;
391     to->y              = from->y;
392     to->x              = from->x;
393     to->style          = from->style;
394     to->dwExStyle      = from->dwExStyle;
395 }
396
397 static void CREATESTRUCT16to32A( const CREATESTRUCT16* from, CREATESTRUCTA *to )
398
399 {
400     to->lpCreateParams = (LPVOID)from->lpCreateParams;
401     to->hInstance      = HINSTANCE_32(from->hInstance);
402     to->hMenu          = HMENU_32(from->hMenu);
403     to->hwndParent     = WIN_Handle32(from->hwndParent);
404     to->cy             = from->cy;
405     to->cx             = from->cx;
406     to->y              = from->y;
407     to->x              = from->x;
408     to->style          = from->style;
409     to->dwExStyle      = from->dwExStyle;
410 }
411
412 /* The strings are not copied */
413 static void MDICREATESTRUCT32Ato16( const MDICREATESTRUCTA* from, MDICREATESTRUCT16* to )
414 {
415     to->hOwner = HINSTANCE_16(from->hOwner);
416     to->x      = from->x;
417     to->y      = from->y;
418     to->cx     = from->cx;
419     to->cy     = from->cy;
420     to->style  = from->style;
421     to->lParam = from->lParam;
422 }
423
424 static void MDICREATESTRUCT16to32A( const MDICREATESTRUCT16* from, MDICREATESTRUCTA *to )
425 {
426     to->hOwner = HINSTANCE_32(from->hOwner);
427     to->x      = from->x;
428     to->y      = from->y;
429     to->cx     = from->cx;
430     to->cy     = from->cy;
431     to->style  = from->style;
432     to->lParam = from->lParam;
433 }
434
435 static WPARAM map_wparam_char_AtoW( WPARAM wParam, DWORD len )
436 {
437     CHAR ch[2];
438     WCHAR wch;
439
440     ch[0] = (wParam >> 8);
441     ch[1] = wParam & 0xff;
442     if (len > 1 && ch[0])
443         RtlMultiByteToUnicodeN( &wch, sizeof(wch), NULL, ch, 2 );
444     else
445         RtlMultiByteToUnicodeN( &wch, sizeof(wch), NULL, ch + 1, 1 );
446     return MAKEWPARAM( wch, HIWORD(wParam) );
447 }
448
449 static WPARAM map_wparam_char_WtoA( WPARAM wParam, DWORD len )
450 {
451     WCHAR wch = wParam;
452     BYTE ch[2];
453
454     RtlUnicodeToMultiByteN( (LPSTR)ch, len, &len, &wch, sizeof(wch) );
455     if (len == 2)
456         return MAKEWPARAM( (ch[0] << 8) | ch[1], HIWORD(wParam) );
457     else
458         return MAKEWPARAM( ch[0], HIWORD(wParam) );
459 }
460
461 /* call a 32-bit window procedure */
462 static LRESULT call_window_proc( HWND hwnd, UINT msg, WPARAM wp, LPARAM lp, LRESULT *result, void *arg )
463 {
464     WNDPROC proc = arg;
465
466     USER_CheckNotLock();
467
468     hwnd = WIN_GetFullHandle( hwnd );
469     if (TRACE_ON(relay))
470         DPRINTF( "%04lx:Call window proc %p (hwnd=%p,msg=%s,wp=%08x,lp=%08lx)\n",
471                  GetCurrentThreadId(), proc, hwnd, SPY_GetMsgName(msg, hwnd), wp, lp );
472
473     *result = WINPROC_wrapper( proc, hwnd, msg, wp, lp );
474
475     if (TRACE_ON(relay))
476         DPRINTF( "%04lx:Ret  window proc %p (hwnd=%p,msg=%s,wp=%08x,lp=%08lx) retval=%08lx\n",
477                  GetCurrentThreadId(), proc, hwnd, SPY_GetMsgName(msg, hwnd), wp, lp, *result );
478     return *result;
479 }
480
481 /* call a 32-bit dialog procedure */
482 static LRESULT call_dialog_proc( HWND hwnd, UINT msg, WPARAM wp, LPARAM lp, LRESULT *result, void *arg )
483 {
484     WNDPROC proc = arg;
485     LRESULT ret;
486
487     USER_CheckNotLock();
488
489     hwnd = WIN_GetFullHandle( hwnd );
490     if (TRACE_ON(relay))
491         DPRINTF( "%04lx:Call dialog proc %p (hwnd=%p,msg=%s,wp=%08x,lp=%08lx)\n",
492                  GetCurrentThreadId(), proc, hwnd, SPY_GetMsgName(msg, hwnd), wp, lp );
493
494     ret = WINPROC_wrapper( proc, hwnd, msg, wp, lp );
495     *result = GetWindowLongPtrW( hwnd, DWLP_MSGRESULT );
496
497     if (TRACE_ON(relay))
498         DPRINTF( "%04lx:Ret  dialog proc %p (hwnd=%p,msg=%s,wp=%08x,lp=%08lx) retval=%08lx result=%08lx\n",
499                  GetCurrentThreadId(), proc, hwnd, SPY_GetMsgName(msg, hwnd), wp, lp, ret, *result );
500     return ret;
501 }
502
503 /**********************************************************************
504  *           WINPROC_CallWndProc32
505  *
506  * Call a 32-bit WndProc.
507  */
508 static LRESULT WINPROC_CallWndProc( WNDPROC proc, HWND hwnd, UINT msg,
509                                       WPARAM wParam, LPARAM lParam )
510 {
511     LRESULT retvalue;
512
513     USER_CheckNotLock();
514
515     hwnd = WIN_GetFullHandle( hwnd );
516     if (TRACE_ON(relay))
517         DPRINTF( "%04lx:Call window proc %p (hwnd=%p,msg=%s,wp=%08x,lp=%08lx)\n",
518                  GetCurrentThreadId(), proc, hwnd, SPY_GetMsgName(msg, hwnd), wParam, lParam );
519
520     retvalue = WINPROC_wrapper( proc, hwnd, msg, wParam, lParam );
521
522     if (TRACE_ON(relay))
523         DPRINTF( "%04lx:Ret  window proc %p (hwnd=%p,msg=%s,wp=%08x,lp=%08lx) retval=%08lx\n",
524                  GetCurrentThreadId(), proc, hwnd, SPY_GetMsgName(msg, hwnd), wParam, lParam, retvalue );
525     return retvalue;
526 }
527
528 /* call a 16-bit window procedure */
529 static LRESULT call_window_proc16( HWND16 hwnd, UINT16 msg, WPARAM16 wParam, LPARAM lParam,
530                                    LRESULT *result, void *arg )
531 {
532     WNDPROC16 proc = arg;
533     CONTEXT86 context;
534     size_t size = 0;
535     struct
536     {
537         WORD params[5];
538         union
539         {
540             CREATESTRUCT16 cs16;
541             DRAWITEMSTRUCT16 dis16;
542             COMPAREITEMSTRUCT16 cis16;
543         } u;
544     } args;
545
546     USER_CheckNotLock();
547
548     /* Window procedures want ax = hInstance, ds = es = ss */
549
550     memset(&context, 0, sizeof(context));
551     context.SegDs = context.SegEs = SELECTOROF(NtCurrentTeb()->WOW32Reserved);
552     context.SegFs = wine_get_fs();
553     context.SegGs = wine_get_gs();
554     if (!(context.Eax = GetWindowWord( HWND_32(hwnd), GWLP_HINSTANCE ))) context.Eax = context.SegDs;
555     context.SegCs = SELECTOROF(proc);
556     context.Eip   = OFFSETOF(proc);
557     context.Ebp   = OFFSETOF(NtCurrentTeb()->WOW32Reserved) + (WORD)&((STACK16FRAME*)0)->bp;
558
559     if (lParam)
560     {
561         /* Some programs (eg. the "Undocumented Windows" examples, JWP) only
562            work if structures passed in lParam are placed in the stack/data
563            segment. Programmers easily make the mistake of converting lParam
564            to a near rather than a far pointer, since Windows apparently
565            allows this. We copy the structures to the 16 bit stack; this is
566            ugly but makes these programs work. */
567         switch (msg)
568         {
569           case WM_CREATE:
570           case WM_NCCREATE:
571             size = sizeof(CREATESTRUCT16); break;
572           case WM_DRAWITEM:
573             size = sizeof(DRAWITEMSTRUCT16); break;
574           case WM_COMPAREITEM:
575             size = sizeof(COMPAREITEMSTRUCT16); break;
576         }
577         if (size)
578         {
579             memcpy( &args.u, MapSL(lParam), size );
580             lParam = (SEGPTR)NtCurrentTeb()->WOW32Reserved - size;
581         }
582     }
583
584     args.params[4] = hwnd;
585     args.params[3] = msg;
586     args.params[2] = wParam;
587     args.params[1] = HIWORD(lParam);
588     args.params[0] = LOWORD(lParam);
589     WOWCallback16Ex( 0, WCB16_REGS, sizeof(args.params) + size, &args, (DWORD *)&context );
590     *result = MAKELONG( LOWORD(context.Eax), LOWORD(context.Edx) );
591     return *result;
592 }
593
594 /* call a 16-bit dialog procedure */
595 static LRESULT call_dialog_proc16( HWND16 hwnd, UINT16 msg, WPARAM16 wp, LPARAM lp,
596                                    LRESULT *result, void *arg )
597 {
598     LRESULT ret = call_window_proc16( hwnd, msg, wp, lp, result, arg );
599     *result = GetWindowLongPtrW( WIN_Handle32(hwnd), DWLP_MSGRESULT );
600     return LOWORD(ret);
601 }
602
603
604 /**********************************************************************
605  *           WINPROC_GetProc16
606  *
607  * Get a window procedure pointer that can be passed to the Windows program.
608  */
609 WNDPROC16 WINPROC_GetProc16( WNDPROC proc, BOOL unicode )
610 {
611     WINDOWPROC *ptr;
612
613     if (unicode) ptr = alloc_winproc( NULL, proc );
614     else ptr = alloc_winproc( proc, NULL );
615
616     if (!ptr) return 0;
617     return alloc_win16_thunk( ptr );
618 }
619
620
621 /**********************************************************************
622  *           WINPROC_GetProc
623  *
624  * Get a window procedure pointer that can be passed to the Windows program.
625  */
626 WNDPROC WINPROC_GetProc( WNDPROC proc, BOOL unicode )
627 {
628     WINDOWPROC *ptr = handle_to_proc( proc );
629
630     if (!ptr) return proc;
631     if (unicode)
632     {
633         if (ptr->procW) return ptr->procW;
634         return proc;
635     }
636     else
637     {
638         if (ptr->procA) return ptr->procA;
639         return proc;
640     }
641 }
642
643
644 /**********************************************************************
645  *           WINPROC_AllocProc16
646  *
647  * Allocate a window procedure for a window or class.
648  *
649  * Note that allocated winprocs are never freed; the idea is that even if an app creates a
650  * lot of windows, it will usually only have a limited number of window procedures, so the
651  * array won't grow too large, and this way we avoid the need to track allocations per window.
652  */
653 WNDPROC WINPROC_AllocProc16( WNDPROC16 func )
654 {
655     WINDOWPROC *proc;
656
657     if (!func) return NULL;
658
659     /* check if the function is already a win proc */
660     if (!(proc = handle16_to_proc( func )))
661     {
662         EnterCriticalSection( &winproc_cs );
663
664         /* then check if we already have a winproc for that function */
665         if (!(proc = find_winproc16( func )))
666         {
667             if (winproc_used < MAX_WINPROCS)
668             {
669                 proc = &winproc_array[winproc_used++];
670                 proc->proc16 = func;
671                 TRACE( "allocated %p for %p/16-bit (%d/%d used)\n",
672                        proc_to_handle(proc), func, winproc_used, MAX_WINPROCS );
673             }
674             else FIXME( "too many winprocs, cannot allocate one for 16-bit %p\n", func );
675         }
676         else TRACE( "reusing %p for %p/16-bit\n", proc_to_handle(proc), func );
677
678         LeaveCriticalSection( &winproc_cs );
679     }
680     return proc_to_handle( proc );
681 }
682
683
684 /**********************************************************************
685  *           WINPROC_AllocProc
686  *
687  * Allocate a window procedure for a window or class.
688  *
689  * Note that allocated winprocs are never freed; the idea is that even if an app creates a
690  * lot of windows, it will usually only have a limited number of window procedures, so the
691  * array won't grow too large, and this way we avoid the need to track allocations per window.
692  */
693 WNDPROC WINPROC_AllocProc( WNDPROC funcA, WNDPROC funcW )
694 {
695     WINDOWPROC *proc;
696
697     if (!(proc = alloc_winproc( funcA, funcW ))) return NULL;
698     return proc_to_handle( proc );
699 }
700
701
702 /**********************************************************************
703  *           WINPROC_IsUnicode
704  *
705  * Return the window procedure type, or the default value if not a winproc handle.
706  */
707 BOOL WINPROC_IsUnicode( WNDPROC proc, BOOL def_val )
708 {
709     WINDOWPROC *ptr = handle_to_proc( proc );
710
711     if (!ptr) return def_val;
712     if (ptr->procA && ptr->procW) return def_val;  /* can be both */
713     return (ptr->procW != NULL);
714 }
715
716
717 /**********************************************************************
718  *           WINPROC_TestLBForStr
719  *
720  * Return TRUE if the lparam is a string
721  */
722 inline static BOOL WINPROC_TestLBForStr( HWND hwnd, UINT msg )
723 {
724     DWORD style = GetWindowLongA( hwnd, GWL_STYLE );
725     if (msg <= CB_MSGMAX)
726         return (!(style & (CBS_OWNERDRAWFIXED | CBS_OWNERDRAWVARIABLE)) || (style & CBS_HASSTRINGS));
727     else
728         return (!(style & (LBS_OWNERDRAWFIXED | LBS_OWNERDRAWVARIABLE)) || (style & LBS_HASSTRINGS));
729
730 }
731 /**********************************************************************
732  *           WINPROC_MapMsg32ATo32W
733  *
734  * Map a message from Ansi to Unicode.
735  * Return value is -1 on error, 0 if OK, 1 if an UnmapMsg call is needed.
736  *
737  * FIXME:
738  *  WM_GETTEXT/WM_SETTEXT and static control with SS_ICON style:
739  *  the first four bytes are the handle of the icon
740  *  when the WM_SETTEXT message has been used to set the icon
741  */
742 static INT WINPROC_MapMsg32ATo32W( HWND hwnd, UINT msg, WPARAM *pwparam, LPARAM *plparam )
743 {
744     switch(msg)
745     {
746     case WM_GETTEXT:
747     case WM_ASKCBFORMATNAME:
748         {
749             LPARAM *ptr = HeapAlloc( GetProcessHeap(), 0,
750                                      *pwparam * sizeof(WCHAR) + sizeof(LPARAM) );
751             if (!ptr) return -1;
752             *ptr++ = *plparam;  /* Store previous lParam */
753             *plparam = (LPARAM)ptr;
754         }
755         return 1;
756     /* lparam is string (0-terminated) */
757     case WM_SETTEXT:
758     case WM_WININICHANGE:
759     case WM_DEVMODECHANGE:
760     case CB_DIR:
761     case LB_DIR:
762     case LB_ADDFILE:
763     case EM_REPLACESEL:
764         if (!*plparam) return 0;
765         else
766         {
767             DWORD len = MultiByteToWideChar(CP_ACP, 0, (LPCSTR)*plparam, -1, NULL, 0);
768             WCHAR *buf = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
769             MultiByteToWideChar(CP_ACP, 0, (LPCSTR)*plparam, -1, buf, len);
770             *plparam = (LPARAM)buf;
771             return (*plparam ? 1 : -1);
772         }
773     default:  /* No translation needed */
774         return 0;
775     }
776 }
777
778
779 /**********************************************************************
780  *           WINPROC_UnmapMsg32ATo32W
781  *
782  * Unmap a message that was mapped from Ansi to Unicode.
783  */
784 static LRESULT WINPROC_UnmapMsg32ATo32W( HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam,
785                                          LRESULT result, WNDPROC dispatch )
786 {
787     switch(msg)
788     {
789     case WM_GETTEXT:
790     case WM_ASKCBFORMATNAME:
791         {
792             LPARAM *ptr = (LPARAM *)lParam - 1;
793             if (!wParam) result = 0;
794             else if (!(result = WideCharToMultiByte( CP_ACP, 0, (LPWSTR)lParam, -1,
795                                                     (LPSTR)*ptr, wParam, NULL, NULL )))
796             {
797                 ((LPSTR)*ptr)[wParam-1] = 0;
798                 result = wParam - 1;
799             }
800             else result--;  /* do not count terminating null */
801             HeapFree( GetProcessHeap(), 0, ptr );
802         }
803         break;
804     case WM_GETTEXTLENGTH:
805     case CB_GETLBTEXTLEN:
806     case LB_GETTEXTLEN:
807         if (result >= 0)
808         {
809             /* Determine respective GETTEXT message */
810             UINT msgGetText =
811               (msg == WM_GETTEXTLENGTH) ? WM_GETTEXT :
812               ((msg == CB_GETLBTEXTLEN) ? CB_GETLBTEXT : LB_GETTEXT);
813             /* wParam differs between the messages */
814             WPARAM wp = (msg == WM_GETTEXTLENGTH) ? (WPARAM)(result + 1) : wParam;
815
816             WCHAR* p = HeapAlloc (GetProcessHeap(), 0, (result + 1) * sizeof(WCHAR));
817
818             if (p)
819             {
820                 LRESULT n;
821
822                 if (dispatch)
823                     n = WINPROC_CallWndProc(dispatch, hwnd, msgGetText, wp, (LPARAM)p);
824                 else
825                     n = SendMessageW (hwnd, msgGetText, wp, (LPARAM)p);
826
827                 result = WideCharToMultiByte( CP_ACP, 0, p, n, NULL, 0, 0, NULL );
828                 HeapFree (GetProcessHeap(), 0, p);
829             }
830         }
831         break;
832
833     case WM_SETTEXT:
834     case WM_WININICHANGE:
835     case WM_DEVMODECHANGE:
836     case CB_DIR:
837     case LB_DIR:
838     case LB_ADDFILE:
839     case EM_REPLACESEL:
840         HeapFree( GetProcessHeap(), 0, (void *)lParam );
841         break;
842     }
843     return result;
844 }
845
846
847 static UINT convert_handle_16_to_32(HANDLE16 src, unsigned int flags)
848 {
849     HANDLE      dst;
850     UINT        sz = GlobalSize16(src);
851     LPSTR       ptr16, ptr32;
852
853     if (!(dst = GlobalAlloc(flags, sz)))
854         return 0;
855     ptr16 = GlobalLock16(src);
856     ptr32 = GlobalLock(dst);
857     if (ptr16 != NULL && ptr32 != NULL) memcpy(ptr32, ptr16, sz);
858     GlobalUnlock16(src);
859     GlobalUnlock(dst);
860
861     return (UINT)dst;
862 }
863
864 /**********************************************************************
865  *           WINPROC_MapMsg16To32A
866  *
867  * Map a message from 16- to 32-bit Ansi.
868  * Return value is -1 on error, 0 if OK, 1 if an UnmapMsg call is needed.
869  */
870 INT WINPROC_MapMsg16To32A( HWND hwnd, UINT16 msg16, WPARAM16 wParam16, UINT *pmsg32,
871                              WPARAM *pwparam32, LPARAM *plparam )
872 {
873     *pmsg32 = (UINT)msg16;
874     *pwparam32 = (WPARAM)wParam16;
875     switch(msg16)
876     {
877     case WM_ACTIVATE:
878     case WM_CHARTOITEM:
879     case WM_COMMAND:
880     case WM_VKEYTOITEM:
881         *pwparam32 = MAKEWPARAM( wParam16, HIWORD(*plparam) );
882         *plparam   = (LPARAM)WIN_Handle32( LOWORD(*plparam) );
883         return 0;
884     case WM_HSCROLL:
885     case WM_VSCROLL:
886         *pwparam32 = MAKEWPARAM( wParam16, LOWORD(*plparam) );
887         *plparam   = (LPARAM)WIN_Handle32( HIWORD(*plparam) );
888         return 0;
889     case WM_CTLCOLOR:
890         if ( HIWORD(*plparam) > CTLCOLOR_STATIC ) return -1;
891         *pmsg32    = WM_CTLCOLORMSGBOX + HIWORD(*plparam);
892         *pwparam32 = (WPARAM)HDC_32(wParam16);
893         *plparam   = (LPARAM)WIN_Handle32( LOWORD(*plparam) );
894         return 0;
895     case WM_COMPAREITEM:
896         {
897             COMPAREITEMSTRUCT16* cis16 = MapSL(*plparam);
898             COMPAREITEMSTRUCT *cis = HeapAlloc(GetProcessHeap(), 0, sizeof(*cis));
899             if (!cis) return -1;
900             cis->CtlType    = cis16->CtlType;
901             cis->CtlID      = cis16->CtlID;
902             cis->hwndItem   = WIN_Handle32( cis16->hwndItem );
903             cis->itemID1    = cis16->itemID1;
904             cis->itemData1  = cis16->itemData1;
905             cis->itemID2    = cis16->itemID2;
906             cis->itemData2  = cis16->itemData2;
907             cis->dwLocaleId = 0;  /* FIXME */
908             *plparam = (LPARAM)cis;
909         }
910         return 1;
911     case WM_COPYDATA:
912         {
913             PCOPYDATASTRUCT16 pcds16 =  MapSL(*plparam);
914             PCOPYDATASTRUCT pcds = HeapAlloc ( GetProcessHeap(), 0, sizeof(*pcds));
915             pcds->dwData = pcds16->dwData;
916             pcds->cbData = pcds16->cbData;
917             pcds->lpData = MapSL( pcds16->lpData);
918             *plparam = (LPARAM)pcds;
919         }
920         return 1;
921     case WM_DELETEITEM:
922         {
923             DELETEITEMSTRUCT16* dis16 = MapSL(*plparam);
924             DELETEITEMSTRUCT *dis = HeapAlloc(GetProcessHeap(), 0, sizeof(*dis));
925             if (!dis) return -1;
926             dis->CtlType  = dis16->CtlType;
927             dis->CtlID    = dis16->CtlID;
928             dis->hwndItem = WIN_Handle32( dis16->hwndItem );
929             dis->itemData = dis16->itemData;
930             *plparam = (LPARAM)dis;
931         }
932         return 1;
933     case WM_MEASUREITEM:
934         {
935             MEASUREITEMSTRUCT16* mis16 = MapSL(*plparam);
936             MEASUREITEMSTRUCT *mis = HeapAlloc(GetProcessHeap(), 0,
937                                                 sizeof(*mis) + sizeof(LPARAM));
938             if (!mis) return -1;
939             mis->CtlType    = mis16->CtlType;
940             mis->CtlID      = mis16->CtlID;
941             mis->itemID     = mis16->itemID;
942             mis->itemWidth  = mis16->itemWidth;
943             mis->itemHeight = mis16->itemHeight;
944             mis->itemData   = mis16->itemData;
945             *(LPARAM *)(mis + 1) = *plparam;  /* Store the previous lParam */
946             *plparam = (LPARAM)mis;
947         }
948         return 1;
949     case WM_DRAWITEM:
950         {
951             DRAWITEMSTRUCT16* dis16 = MapSL(*plparam);
952             DRAWITEMSTRUCT *dis = HeapAlloc(GetProcessHeap(), 0, sizeof(*dis));
953             if (!dis) return -1;
954             dis->CtlType       = dis16->CtlType;
955             dis->CtlID         = dis16->CtlID;
956             dis->itemID        = dis16->itemID;
957             dis->itemAction    = dis16->itemAction;
958             dis->itemState     = dis16->itemState;
959             dis->hwndItem      = (dis->CtlType == ODT_MENU) ? (HWND)HMENU_32(dis16->hwndItem)
960                                                             : WIN_Handle32( dis16->hwndItem );
961             dis->hDC           = HDC_32(dis16->hDC);
962             dis->itemData      = dis16->itemData;
963             dis->rcItem.left   = dis16->rcItem.left;
964             dis->rcItem.top    = dis16->rcItem.top;
965             dis->rcItem.right  = dis16->rcItem.right;
966             dis->rcItem.bottom = dis16->rcItem.bottom;
967             *plparam = (LPARAM)dis;
968         }
969         return 1;
970     case WM_GETMINMAXINFO:
971         {
972             MINMAXINFO *mmi = HeapAlloc( GetProcessHeap(), 0, sizeof(*mmi) + sizeof(LPARAM));
973             if (!mmi) return -1;
974             MINMAXINFO16to32( MapSL(*plparam), mmi );
975             *(LPARAM *)(mmi + 1) = *plparam;  /* Store the previous lParam */
976             *plparam = (LPARAM)mmi;
977         }
978         return 1;
979     case WM_GETTEXT:
980     case WM_SETTEXT:
981     case WM_WININICHANGE:
982     case WM_DEVMODECHANGE:
983     case WM_ASKCBFORMATNAME:
984         *plparam = (LPARAM)MapSL(*plparam);
985         return 0;
986     case WM_MDICREATE:
987         {
988             MDICREATESTRUCT16 *cs16 = MapSL(*plparam);
989             MDICREATESTRUCTA *cs = HeapAlloc( GetProcessHeap(), 0, sizeof(*cs) + sizeof(LPARAM) );
990             if (!cs) return -1;
991             MDICREATESTRUCT16to32A( cs16, cs );
992             cs->szTitle = MapSL(cs16->szTitle);
993             cs->szClass = MapSL(cs16->szClass);
994             *(LPARAM *)(cs + 1) = *plparam;  /* Store the previous lParam */
995             *plparam = (LPARAM)cs;
996         }
997         return 1;
998     case WM_MDIGETACTIVE:
999         *plparam = (LPARAM)HeapAlloc( GetProcessHeap(), 0, sizeof(BOOL) );
1000         *(BOOL*)(*plparam) = 0;
1001         return 1;
1002     case WM_MDISETMENU:
1003         if(wParam16) *pmsg32=WM_MDIREFRESHMENU;
1004         *pwparam32 = (WPARAM)HMENU_32(LOWORD(*plparam));
1005         *plparam   = (LPARAM)HMENU_32(HIWORD(*plparam));
1006         return 0;
1007     case WM_MENUCHAR:
1008         *pwparam32 = MAKEWPARAM( wParam16, LOWORD(*plparam) );
1009         *plparam   = (LPARAM)HMENU_32(HIWORD(*plparam));
1010         return 0;
1011     case WM_MENUSELECT:
1012         if((LOWORD(*plparam) & MF_POPUP) && (LOWORD(*plparam) != 0xFFFF))
1013         {
1014             HMENU hmenu=HMENU_32(HIWORD(*plparam));
1015             UINT Pos=MENU_FindSubMenu( &hmenu, HMENU_32(wParam16));
1016             if(Pos==0xFFFF) Pos=0; /* NO_SELECTED_ITEM */
1017             *pwparam32 = MAKEWPARAM( Pos, LOWORD(*plparam) );
1018         }
1019         else *pwparam32 = MAKEWPARAM( wParam16, LOWORD(*plparam) );
1020         *plparam   = (LPARAM)HMENU_32(HIWORD(*plparam));
1021         return 0;
1022     case WM_MDIACTIVATE:
1023         if( *plparam )
1024         {
1025             *pwparam32 = (WPARAM)WIN_Handle32( HIWORD(*plparam) );
1026             *plparam   = (LPARAM)WIN_Handle32( LOWORD(*plparam) );
1027         }
1028         else /* message sent to MDI client */
1029             *pwparam32 = wParam16;
1030         return 0;
1031     case WM_NCCALCSIZE:
1032         {
1033             NCCALCSIZE_PARAMS16 *nc16;
1034             NCCALCSIZE_PARAMS *nc;
1035
1036             nc = HeapAlloc( GetProcessHeap(), 0, sizeof(*nc) + sizeof(LPARAM) );
1037             if (!nc) return -1;
1038             nc16 = MapSL(*plparam);
1039             nc->rgrc[0].left   = nc16->rgrc[0].left;
1040             nc->rgrc[0].top    = nc16->rgrc[0].top;
1041             nc->rgrc[0].right  = nc16->rgrc[0].right;
1042             nc->rgrc[0].bottom = nc16->rgrc[0].bottom;
1043             if (wParam16)
1044             {
1045                 nc->lppos = HeapAlloc( GetProcessHeap(), 0, sizeof(*nc->lppos) );
1046                 nc->rgrc[1].left   = nc16->rgrc[1].left;
1047                 nc->rgrc[1].top    = nc16->rgrc[1].top;
1048                 nc->rgrc[1].right  = nc16->rgrc[1].right;
1049                 nc->rgrc[1].bottom = nc16->rgrc[1].bottom;
1050                 nc->rgrc[2].left   = nc16->rgrc[2].left;
1051                 nc->rgrc[2].top    = nc16->rgrc[2].top;
1052                 nc->rgrc[2].right  = nc16->rgrc[2].right;
1053                 nc->rgrc[2].bottom = nc16->rgrc[2].bottom;
1054                 if (nc->lppos) WINDOWPOS16to32( MapSL(nc16->lppos), nc->lppos );
1055             }
1056             *(LPARAM *)(nc + 1) = *plparam;  /* Store the previous lParam */
1057             *plparam = (LPARAM)nc;
1058         }
1059         return 1;
1060     case WM_NCCREATE:
1061     case WM_CREATE:
1062         {
1063             CREATESTRUCT16 *cs16 = MapSL(*plparam);
1064             CREATESTRUCTA *cs = HeapAlloc( GetProcessHeap(), 0, sizeof(*cs) + sizeof(LPARAM) );
1065             if (!cs) return -1;
1066             CREATESTRUCT16to32A( cs16, cs );
1067             cs->lpszName  = MapSL(cs16->lpszName);
1068             cs->lpszClass = MapSL(cs16->lpszClass);
1069
1070             if (GetWindowLongW(hwnd, GWL_EXSTYLE) & WS_EX_MDICHILD)
1071             {
1072                 MDICREATESTRUCT16 *mdi_cs16;
1073                 MDICREATESTRUCTA *mdi_cs = HeapAlloc(GetProcessHeap(), 0, sizeof(*mdi_cs));
1074                 if (!mdi_cs)
1075                 {
1076                     HeapFree(GetProcessHeap(), 0, cs);
1077                     return -1;
1078                 }
1079                 mdi_cs16 = (MDICREATESTRUCT16 *)MapSL(cs16->lpCreateParams);
1080                 MDICREATESTRUCT16to32A(mdi_cs16, mdi_cs);
1081                 mdi_cs->szTitle = MapSL(mdi_cs16->szTitle);
1082                 mdi_cs->szClass = MapSL(mdi_cs16->szClass);
1083
1084                 cs->lpCreateParams = mdi_cs;
1085             }
1086             *(LPARAM *)(cs + 1) = *plparam;  /* Store the previous lParam */
1087             *plparam = (LPARAM)cs;
1088         }
1089         return 1;
1090     case WM_PARENTNOTIFY:
1091         if ((wParam16 == WM_CREATE) || (wParam16 == WM_DESTROY))
1092         {
1093             *pwparam32 = MAKEWPARAM( wParam16, HIWORD(*plparam) );
1094             *plparam   = (LPARAM)WIN_Handle32( LOWORD(*plparam) );
1095         }
1096         return 0;
1097     case WM_WINDOWPOSCHANGING:
1098     case WM_WINDOWPOSCHANGED:
1099         {
1100             WINDOWPOS *wp = HeapAlloc( GetProcessHeap(), 0, sizeof(*wp) + sizeof(LPARAM) );
1101             if (!wp) return -1;
1102             WINDOWPOS16to32( MapSL(*plparam), wp );
1103             *(LPARAM *)(wp + 1) = *plparam;  /* Store the previous lParam */
1104             *plparam = (LPARAM)wp;
1105         }
1106         return 1;
1107     case WM_GETDLGCODE:
1108         if (*plparam)
1109         {
1110             LPMSG16 msg16 = MapSL(*plparam);
1111             LPMSG msg32 = HeapAlloc( GetProcessHeap(), 0, sizeof(MSG) );
1112
1113             if (!msg32) return -1;
1114             msg32->hwnd = WIN_Handle32( msg16->hwnd );
1115             msg32->message = msg16->message;
1116             msg32->wParam = msg16->wParam;
1117             msg32->lParam = msg16->lParam;
1118             msg32->time = msg16->time;
1119             msg32->pt.x = msg16->pt.x;
1120             msg32->pt.y = msg16->pt.y;
1121             *plparam = (LPARAM)msg32;
1122             return 1;
1123         }
1124         else return 0;
1125     case WM_NOTIFY:
1126         *plparam = (LPARAM)MapSL(*plparam);
1127         return 0;
1128     case WM_ACTIVATEAPP:
1129         /* We need this when SetActiveWindow sends a Sendmessage16() to
1130          * a 32bit window. Might be superflous with 32bit interprocess
1131          * message queues. */
1132         if (*plparam) *plparam = HTASK_32( *plparam );
1133         return 0;
1134     case WM_NEXTMENU:
1135         {
1136             MDINEXTMENU *next = HeapAlloc( GetProcessHeap(), 0, sizeof(*next) );
1137             if (!next) return -1;
1138             next->hmenuIn = (HMENU)*plparam;
1139             next->hmenuNext = 0;
1140             next->hwndNext = 0;
1141             *plparam = (LPARAM)next;
1142             return 1;
1143         }
1144     case WM_PAINTCLIPBOARD:
1145     case WM_SIZECLIPBOARD:
1146         FIXME_(msg)("message %04x needs translation\n",msg16 );
1147         return -1;
1148     case WM_DDE_INITIATE:
1149     case WM_DDE_TERMINATE:
1150     case WM_DDE_UNADVISE:
1151     case WM_DDE_REQUEST:
1152         *pwparam32 = (WPARAM)WIN_Handle32(wParam16);
1153         return 0;
1154     case WM_DDE_ADVISE:
1155     case WM_DDE_DATA:
1156     case WM_DDE_POKE:
1157         {
1158             HANDLE16    lo16;
1159             ATOM        hi;
1160             UINT lo32 = 0;
1161
1162             *pwparam32 = (WPARAM)WIN_Handle32(wParam16);
1163             lo16 = LOWORD(*plparam);
1164             hi = HIWORD(*plparam);
1165             if (lo16 && !(lo32 = convert_handle_16_to_32(lo16, GMEM_DDESHARE)))
1166                 return -1;
1167             *plparam = PackDDElParam(msg16, lo32, hi);
1168         }
1169         return 0; /* FIXME don't know how to free allocated memory (handle)  !! */
1170     case WM_DDE_ACK:
1171         {
1172             UINT        lo, hi;
1173             int         flag = 0;
1174             char        buf[2];
1175
1176             *pwparam32 = (WPARAM)WIN_Handle32(wParam16);
1177
1178             lo = LOWORD(*plparam);
1179             hi = HIWORD(*plparam);
1180
1181             if (GlobalGetAtomNameA(hi, buf, 2) > 0) flag |= 1;
1182             if (GlobalSize16(hi) != 0) flag |= 2;
1183             switch (flag)
1184             {
1185             case 0:
1186                 if (hi)
1187                 {
1188                     MESSAGE("DDE_ACK: neither atom nor handle!!!\n");
1189                     hi = 0;
1190                 }
1191                 break;
1192             case 1:
1193                 break; /* atom, nothing to do */
1194             case 3:
1195                 MESSAGE("DDE_ACK: %x both atom and handle... choosing handle\n", hi);
1196                 /* fall thru */
1197             case 2:
1198                 hi = convert_handle_16_to_32(hi, GMEM_DDESHARE);
1199                 break;
1200             }
1201             *plparam = PackDDElParam(WM_DDE_ACK, lo, hi);
1202         }
1203         return 0; /* FIXME don't know how to free allocated memory (handle) !! */
1204     case WM_DDE_EXECUTE:
1205         *plparam = convert_handle_16_to_32(*plparam, GMEM_DDESHARE);
1206         return 0; /* FIXME don't know how to free allocated memory (handle) !! */
1207     default:  /* No translation needed */
1208         return 0;
1209     }
1210 }
1211
1212
1213 /**********************************************************************
1214  *           WINPROC_UnmapMsg16To32A
1215  *
1216  * Unmap a message that was mapped from 16- to 32-bit Ansi.
1217  */
1218 static LRESULT WINPROC_UnmapMsg16To32A( HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam,
1219                                         LRESULT result )
1220 {
1221     switch(msg)
1222     {
1223     case WM_COMPAREITEM:
1224     case WM_DELETEITEM:
1225     case WM_DRAWITEM:
1226     case WM_COPYDATA:
1227         HeapFree( GetProcessHeap(), 0, (LPVOID)lParam );
1228         break;
1229     case WM_MEASUREITEM:
1230         {
1231             MEASUREITEMSTRUCT16 *mis16;
1232             MEASUREITEMSTRUCT *mis = (MEASUREITEMSTRUCT *)lParam;
1233             lParam = *(LPARAM *)(mis + 1);
1234             mis16 = MapSL(lParam);
1235             mis16->itemWidth  = (UINT16)mis->itemWidth;
1236             mis16->itemHeight = (UINT16)mis->itemHeight;
1237             HeapFree( GetProcessHeap(), 0, mis );
1238         }
1239         break;
1240     case WM_GETMINMAXINFO:
1241         {
1242             MINMAXINFO *mmi = (MINMAXINFO *)lParam;
1243             lParam = *(LPARAM *)(mmi + 1);
1244             MINMAXINFO32to16( mmi, MapSL(lParam));
1245             HeapFree( GetProcessHeap(), 0, mmi );
1246         }
1247         break;
1248     case WM_MDICREATE:
1249         {
1250             MDICREATESTRUCTA *cs = (MDICREATESTRUCTA *)lParam;
1251             lParam = *(LPARAM *)(cs + 1);
1252             MDICREATESTRUCT32Ato16( cs, MapSL(lParam) );
1253             HeapFree( GetProcessHeap(), 0, cs );
1254         }
1255         break;
1256     case WM_MDIGETACTIVE:
1257         result = MAKELONG( LOWORD(result), (BOOL16)(*(BOOL *)lParam) );
1258         HeapFree( GetProcessHeap(), 0, (BOOL *)lParam );
1259         break;
1260     case WM_NCCALCSIZE:
1261         {
1262             NCCALCSIZE_PARAMS16 *nc16;
1263             NCCALCSIZE_PARAMS *nc = (NCCALCSIZE_PARAMS *)lParam;
1264             lParam = *(LPARAM *)(nc + 1);
1265             nc16 = MapSL(lParam);
1266             nc16->rgrc[0].left   = nc->rgrc[0].left;
1267             nc16->rgrc[0].top    = nc->rgrc[0].top;
1268             nc16->rgrc[0].right  = nc->rgrc[0].right;
1269             nc16->rgrc[0].bottom = nc->rgrc[0].bottom;
1270             if (wParam)
1271             {
1272                 nc16->rgrc[1].left   = nc->rgrc[1].left;
1273                 nc16->rgrc[1].top    = nc->rgrc[1].top;
1274                 nc16->rgrc[1].right  = nc->rgrc[1].right;
1275                 nc16->rgrc[1].bottom = nc->rgrc[1].bottom;
1276                 nc16->rgrc[2].left   = nc->rgrc[2].left;
1277                 nc16->rgrc[2].top    = nc->rgrc[2].top;
1278                 nc16->rgrc[2].right  = nc->rgrc[2].right;
1279                 nc16->rgrc[2].bottom = nc->rgrc[2].bottom;
1280                 if (nc->lppos)
1281                 {
1282                     WINDOWPOS32to16( nc->lppos, MapSL(nc16->lppos));
1283                     HeapFree( GetProcessHeap(), 0, nc->lppos );
1284                 }
1285             }
1286             HeapFree( GetProcessHeap(), 0, nc );
1287         }
1288         break;
1289     case WM_NCCREATE:
1290     case WM_CREATE:
1291         {
1292             CREATESTRUCTA *cs = (CREATESTRUCTA *)lParam;
1293             lParam = *(LPARAM *)(cs + 1);
1294             CREATESTRUCT32Ato16( cs, MapSL(lParam) );
1295
1296             if (GetWindowLongW(hwnd, GWL_EXSTYLE) & WS_EX_MDICHILD)
1297                 HeapFree(GetProcessHeap(), 0, cs->lpCreateParams);
1298
1299             HeapFree( GetProcessHeap(), 0, cs );
1300         }
1301         break;
1302     case WM_WINDOWPOSCHANGING:
1303     case WM_WINDOWPOSCHANGED:
1304         {
1305             WINDOWPOS *wp = (WINDOWPOS *)lParam;
1306             lParam = *(LPARAM *)(wp + 1);
1307             WINDOWPOS32to16(wp, MapSL(lParam));
1308             HeapFree( GetProcessHeap(), 0, wp );
1309         }
1310         break;
1311     case WM_GETDLGCODE:
1312         if (lParam)
1313         {
1314             LPMSG msg32 = (LPMSG)lParam;
1315             HeapFree( GetProcessHeap(), 0, msg32 );
1316         }
1317         break;
1318     case WM_NEXTMENU:
1319         {
1320             MDINEXTMENU *next = (MDINEXTMENU *)lParam;
1321             result = MAKELONG( HMENU_16(next->hmenuNext), HWND_16(next->hwndNext) );
1322             HeapFree( GetProcessHeap(), 0, next );
1323         }
1324         break;
1325     }
1326     return result;
1327 }
1328
1329
1330 /**********************************************************************
1331  *           WINPROC_MapMsg16To32W
1332  *
1333  * Map a message from 16- to 32-bit Unicode.
1334  * Return value is -1 on error, 0 if OK, 1 if an UnmapMsg call is needed.
1335  */
1336 static INT WINPROC_MapMsg16To32W( HWND hwnd, UINT16 msg16, WPARAM16 wParam16, UINT *pmsg32,
1337                                   WPARAM *pwparam32, LPARAM *plparam )
1338 {
1339     *pmsg32=(UINT)msg16;
1340     *pwparam32 = (WPARAM)wParam16;
1341     switch(msg16)
1342     {
1343     case WM_GETTEXT:
1344     case WM_SETTEXT:
1345     case WM_WININICHANGE:
1346     case WM_DEVMODECHANGE:
1347     case WM_ASKCBFORMATNAME:
1348         *plparam = (LPARAM)MapSL(*plparam);
1349         return WINPROC_MapMsg32ATo32W( hwnd, *pmsg32, pwparam32, plparam );
1350     case WM_GETTEXTLENGTH:
1351     case CB_GETLBTEXTLEN:
1352     case LB_GETTEXTLEN:
1353         return 1;  /* need to map result */
1354     case WM_NCCREATE:
1355     case WM_CREATE:
1356         {
1357             CREATESTRUCT16 *cs16 = MapSL(*plparam);
1358             CREATESTRUCTW *cs = HeapAlloc( GetProcessHeap(), 0, sizeof(*cs) + sizeof(LPARAM) );
1359             if (!cs) return -1;
1360             CREATESTRUCT16to32A( cs16, (CREATESTRUCTA *)cs );
1361             cs->lpszName  = map_str_16_to_32W(cs16->lpszName);
1362             cs->lpszClass = map_str_16_to_32W(cs16->lpszClass);
1363
1364             if (GetWindowLongW(hwnd, GWL_EXSTYLE) & WS_EX_MDICHILD)
1365             {
1366                 MDICREATESTRUCT16 *mdi_cs16;
1367                 MDICREATESTRUCTW *mdi_cs = HeapAlloc(GetProcessHeap(), 0, sizeof(*mdi_cs));
1368                 if (!mdi_cs)
1369                 {
1370                     HeapFree(GetProcessHeap(), 0, cs);
1371                     return -1;
1372                 }
1373                 mdi_cs16 = (MDICREATESTRUCT16 *)MapSL(cs16->lpCreateParams);
1374                 MDICREATESTRUCT16to32A(mdi_cs16, (MDICREATESTRUCTA *)mdi_cs);
1375                 mdi_cs->szTitle = map_str_16_to_32W(mdi_cs16->szTitle);
1376                 mdi_cs->szClass = map_str_16_to_32W(mdi_cs16->szClass);
1377
1378                 cs->lpCreateParams = mdi_cs;
1379             }
1380             *(LPARAM *)(cs + 1) = *plparam;  /* Store the previous lParam */
1381             *plparam = (LPARAM)cs;
1382         }
1383         return 1;
1384     case WM_MDICREATE:
1385         {
1386             MDICREATESTRUCT16 *cs16 = MapSL(*plparam);
1387             MDICREATESTRUCTW *cs = HeapAlloc( GetProcessHeap(), 0, sizeof(*cs) + sizeof(LPARAM) );
1388             if (!cs) return -1;
1389             MDICREATESTRUCT16to32A( cs16, (MDICREATESTRUCTA *)cs );
1390             cs->szTitle = map_str_16_to_32W(cs16->szTitle);
1391             cs->szClass = map_str_16_to_32W(cs16->szClass);
1392             *(LPARAM *)(cs + 1) = *plparam;  /* Store the previous lParam */
1393             *plparam = (LPARAM)cs;
1394         }
1395         return 1;
1396     case WM_GETDLGCODE:
1397         if (*plparam)
1398         {
1399             LPMSG16 msg16 = MapSL(*plparam);
1400             LPMSG msg32 = HeapAlloc( GetProcessHeap(), 0, sizeof(MSG) );
1401
1402             if (!msg32) return -1;
1403             msg32->hwnd = WIN_Handle32( msg16->hwnd );
1404             msg32->message = msg16->message;
1405             msg32->wParam = msg16->wParam;
1406             msg32->lParam = msg16->lParam;
1407             msg32->time = msg16->time;
1408             msg32->pt.x = msg16->pt.x;
1409             msg32->pt.y = msg16->pt.y;
1410             switch(msg32->message)
1411             {
1412             case WM_CHAR:
1413             case WM_DEADCHAR:
1414             case WM_SYSCHAR:
1415             case WM_SYSDEADCHAR:
1416                 msg32->wParam = map_wparam_char_AtoW( msg16->wParam, 1 );
1417                 break;
1418             }
1419             *plparam = (LPARAM)msg32;
1420             return 1;
1421         }
1422         else return 0;
1423
1424     case WM_CHARTOITEM:
1425         *pwparam32 = MAKEWPARAM( map_wparam_char_AtoW( wParam16, 1 ), HIWORD(*plparam) );
1426         *plparam   = (LPARAM)WIN_Handle32( LOWORD(*plparam) );
1427         return 0;
1428     case WM_MENUCHAR:
1429         *pwparam32 = MAKEWPARAM( map_wparam_char_AtoW( wParam16, 1 ), LOWORD(*plparam) );
1430         *plparam   = (LPARAM)HMENU_32(HIWORD(*plparam));
1431         return 0;
1432     case WM_CHAR:
1433     case WM_DEADCHAR:
1434     case WM_SYSCHAR:
1435     case WM_SYSDEADCHAR:
1436         *pwparam32 = map_wparam_char_AtoW( wParam16, 1 );
1437         return 0;
1438     case WM_IME_CHAR:
1439         *pwparam32 = map_wparam_char_AtoW( wParam16, 2 );
1440         return 0;
1441
1442     default:  /* No Unicode translation needed */
1443         return WINPROC_MapMsg16To32A( hwnd, msg16, wParam16, pmsg32,
1444                                       pwparam32, plparam );
1445     }
1446 }
1447
1448
1449 /**********************************************************************
1450  *           WINPROC_UnmapMsg16To32W
1451  *
1452  * Unmap a message that was mapped from 16- to 32-bit Unicode.
1453  */
1454 static LRESULT WINPROC_UnmapMsg16To32W( HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam,
1455                                         LRESULT result, WNDPROC dispatch )
1456 {
1457     switch(msg)
1458     {
1459     case WM_GETTEXT:
1460     case WM_SETTEXT:
1461     case WM_GETTEXTLENGTH:
1462     case CB_GETLBTEXTLEN:
1463     case LB_GETTEXTLEN:
1464     case WM_ASKCBFORMATNAME:
1465         return WINPROC_UnmapMsg32ATo32W( hwnd, msg, wParam, lParam, result, dispatch );
1466     case WM_NCCREATE:
1467     case WM_CREATE:
1468         {
1469             CREATESTRUCTW *cs = (CREATESTRUCTW *)lParam;
1470             lParam = *(LPARAM *)(cs + 1);
1471             CREATESTRUCT32Ato16( (CREATESTRUCTA *)cs, MapSL(lParam) );
1472             unmap_str_16_to_32W( cs->lpszName );
1473             unmap_str_16_to_32W( cs->lpszClass );
1474
1475             if (GetWindowLongW(hwnd, GWL_EXSTYLE) & WS_EX_MDICHILD)
1476             {
1477                 MDICREATESTRUCTW *mdi_cs = (MDICREATESTRUCTW *)cs->lpCreateParams;
1478                 unmap_str_16_to_32W( mdi_cs->szTitle );
1479                 unmap_str_16_to_32W( mdi_cs->szClass );
1480                 HeapFree(GetProcessHeap(), 0, cs->lpCreateParams);
1481             }
1482             HeapFree( GetProcessHeap(), 0, cs );
1483         }
1484         break;
1485     case WM_MDICREATE:
1486         {
1487             MDICREATESTRUCTW *cs = (MDICREATESTRUCTW *)lParam;
1488             lParam = *(LPARAM *)(cs + 1);
1489             MDICREATESTRUCT32Ato16( (MDICREATESTRUCTA *)cs, MapSL(lParam) );
1490             unmap_str_16_to_32W( cs->szTitle );
1491             unmap_str_16_to_32W( cs->szClass );
1492             HeapFree( GetProcessHeap(), 0, cs );
1493         }
1494         break;
1495     case WM_GETDLGCODE:
1496         if (lParam)
1497         {
1498             LPMSG msg32 = (LPMSG)lParam;
1499             HeapFree( GetProcessHeap(), 0, msg32 );
1500         }
1501         break;
1502     default:
1503         return WINPROC_UnmapMsg16To32A( hwnd, msg, wParam, lParam, result );
1504     }
1505     return result;
1506 }
1507
1508 static HANDLE16 convert_handle_32_to_16(UINT src, unsigned int flags)
1509 {
1510     HANDLE16    dst;
1511     UINT        sz = GlobalSize((HANDLE)src);
1512     LPSTR       ptr16, ptr32;
1513
1514     if (!(dst = GlobalAlloc16(flags, sz)))
1515         return 0;
1516     ptr32 = GlobalLock((HANDLE)src);
1517     ptr16 = GlobalLock16(dst);
1518     if (ptr16 != NULL && ptr32 != NULL) memcpy(ptr16, ptr32, sz);
1519     GlobalUnlock((HANDLE)src);
1520     GlobalUnlock16(dst);
1521
1522     return dst;
1523 }
1524
1525
1526 /**********************************************************************
1527  *           WINPROC_MapMsg32ATo16
1528  *
1529  * Map a message from 32-bit Ansi to 16-bit.
1530  * Return value is -1 on error, 0 if OK, 1 if an UnmapMsg call is needed.
1531  */
1532 INT WINPROC_MapMsg32ATo16( HWND hwnd, UINT msg32, WPARAM wParam32,
1533                              UINT16 *pmsg16, WPARAM16 *pwparam16,
1534                              LPARAM *plparam )
1535 {
1536     *pmsg16 = (UINT16)msg32;
1537     *pwparam16 = (WPARAM16)LOWORD(wParam32);
1538     switch(msg32)
1539     {
1540     case SBM_SETRANGE:
1541         *pmsg16 = SBM_SETRANGE16;
1542         *plparam = MAKELPARAM(wParam32, *plparam);
1543         *pwparam16 = 0;
1544         return 0;
1545
1546     case SBM_GETRANGE:
1547         *pmsg16 = SBM_GETRANGE16;
1548         return 1;
1549
1550     case BM_GETCHECK:
1551     case BM_SETCHECK:
1552     case BM_GETSTATE:
1553     case BM_SETSTATE:
1554     case BM_SETSTYLE:
1555         *pmsg16 = (UINT16)msg32 + (BM_GETCHECK16 - BM_GETCHECK);
1556         return 0;
1557
1558     case EM_GETSEL:
1559     case EM_GETRECT:
1560     case EM_SETRECT:
1561     case EM_SETRECTNP:
1562     case EM_SCROLL:
1563     case EM_LINESCROLL:
1564     case EM_SCROLLCARET:
1565     case EM_GETMODIFY:
1566     case EM_SETMODIFY:
1567     case EM_GETLINECOUNT:
1568     case EM_LINEINDEX:
1569     case EM_SETHANDLE:
1570     case EM_GETHANDLE:
1571     case EM_GETTHUMB:
1572     case EM_LINELENGTH:
1573     case EM_REPLACESEL:
1574     case EM_GETLINE:
1575     case EM_LIMITTEXT:
1576     case EM_CANUNDO:
1577     case EM_UNDO:
1578     case EM_FMTLINES:
1579     case EM_LINEFROMCHAR:
1580     case EM_SETTABSTOPS:
1581     case EM_SETPASSWORDCHAR:
1582     case EM_EMPTYUNDOBUFFER:
1583     case EM_GETFIRSTVISIBLELINE:
1584     case EM_SETREADONLY:
1585     case EM_SETWORDBREAKPROC:
1586     case EM_GETWORDBREAKPROC:
1587     case EM_GETPASSWORDCHAR:
1588         *pmsg16 = (UINT16)msg32 + (EM_GETSEL16 - EM_GETSEL);
1589         return 0;
1590
1591     case LB_CARETOFF:
1592     case LB_CARETON:
1593     case LB_DELETESTRING:
1594     case LB_GETANCHORINDEX:
1595     case LB_GETCARETINDEX:
1596     case LB_GETCOUNT:
1597     case LB_GETCURSEL:
1598     case LB_GETHORIZONTALEXTENT:
1599     case LB_GETITEMDATA:
1600     case LB_GETITEMHEIGHT:
1601     case LB_GETSEL:
1602     case LB_GETSELCOUNT:
1603     case LB_GETTEXTLEN:
1604     case LB_GETTOPINDEX:
1605     case LB_RESETCONTENT:
1606     case LB_SELITEMRANGE:
1607     case LB_SELITEMRANGEEX:
1608     case LB_SETANCHORINDEX:
1609     case LB_SETCARETINDEX:
1610     case LB_SETCOLUMNWIDTH:
1611     case LB_SETCURSEL:
1612     case LB_SETHORIZONTALEXTENT:
1613     case LB_SETITEMDATA:
1614     case LB_SETITEMHEIGHT:
1615     case LB_SETSEL:
1616     case LB_SETTOPINDEX:
1617         *pmsg16 = (UINT16)msg32 + (LB_ADDSTRING16 - LB_ADDSTRING);
1618         return 0;
1619     case CB_DELETESTRING:
1620     case CB_GETCOUNT:
1621     case CB_GETLBTEXTLEN:
1622     case CB_LIMITTEXT:
1623     case CB_RESETCONTENT:
1624     case CB_SETEDITSEL:
1625     case CB_GETCURSEL:
1626     case CB_SETCURSEL:
1627     case CB_SHOWDROPDOWN:
1628     case CB_SETITEMDATA:
1629     case CB_SETITEMHEIGHT:
1630     case CB_GETITEMHEIGHT:
1631     case CB_SETEXTENDEDUI:
1632     case CB_GETEXTENDEDUI:
1633     case CB_GETDROPPEDSTATE:
1634         *pmsg16 = (UINT16)msg32 + (CB_GETEDITSEL16 - CB_GETEDITSEL);
1635         return 0;
1636     case CB_GETEDITSEL:
1637         *pmsg16 = CB_GETEDITSEL16;
1638         return 1;
1639
1640     case LB_ADDSTRING:
1641     case LB_FINDSTRING:
1642     case LB_FINDSTRINGEXACT:
1643     case LB_INSERTSTRING:
1644     case LB_SELECTSTRING:
1645     case LB_DIR:
1646     case LB_ADDFILE:
1647         *plparam = (LPARAM)MapLS( (LPSTR)*plparam );
1648         *pmsg16 = (UINT16)msg32 + (LB_ADDSTRING16 - LB_ADDSTRING);
1649         return 1;
1650
1651     case CB_ADDSTRING:
1652     case CB_FINDSTRING:
1653     case CB_FINDSTRINGEXACT:
1654     case CB_INSERTSTRING:
1655     case CB_SELECTSTRING:
1656     case CB_DIR:
1657         *plparam = (LPARAM)MapLS( (LPSTR)*plparam );
1658         *pmsg16 = (UINT16)msg32 + (CB_GETEDITSEL16 - CB_GETEDITSEL);
1659         return 1;
1660
1661     case LB_GETITEMRECT:
1662         {
1663             RECT16 *rect = HeapAlloc( GetProcessHeap(), 0, sizeof(RECT16) + sizeof(LPARAM) );
1664             if (!rect) return -1;
1665             *(LPARAM *)(rect + 1) = *plparam;  /* Store the previous lParam */
1666             *plparam = MapLS( rect );
1667         }
1668         *pmsg16 = LB_GETITEMRECT16;
1669         return 1;
1670     case LB_GETSELITEMS:
1671         {
1672             LPARAM *items; /* old LPARAM first, then *pwparam16 x INT16 entries */
1673
1674             *pwparam16 = (WPARAM16)min( wParam32, 0x7f80 ); /* Must be < 64K */
1675             if (!(items = HeapAlloc( GetProcessHeap(), 0,
1676                                      *pwparam16 * sizeof(INT16) + sizeof(LPARAM)))) return -1;
1677             *items++ = *plparam;  /* Store the previous lParam */
1678             *plparam = MapLS( items );
1679         }
1680         *pmsg16 = LB_GETSELITEMS16;
1681         return 1;
1682     case LB_SETTABSTOPS:
1683         if (wParam32)
1684         {
1685             INT i;
1686             LPINT16 stops;
1687             *pwparam16 = (WPARAM16)min( wParam32, 0x7f80 ); /* Must be < 64K */
1688             if (!(stops = HeapAlloc( GetProcessHeap(), 0,
1689                                      *pwparam16 * sizeof(INT16) + sizeof(LPARAM)))) return -1;
1690             for (i = 0; i < *pwparam16; i++) stops[i] = *((LPINT)*plparam+i);
1691             *plparam = MapLS( stops );
1692             return 1;
1693         }
1694         *pmsg16 = LB_SETTABSTOPS16;
1695         return 0;
1696
1697     case CB_GETDROPPEDCONTROLRECT:
1698         {
1699             RECT16 *rect = HeapAlloc( GetProcessHeap(), 0, sizeof(RECT16) + sizeof(LPARAM) );
1700             if (!rect) return -1;
1701             *(LPARAM *)(rect + 1) = *plparam;  /* Store the previous lParam */
1702             *plparam = (LPARAM)MapLS(rect);
1703         }
1704         *pmsg16 = CB_GETDROPPEDCONTROLRECT16;
1705         return 1;
1706
1707     case LB_GETTEXT:
1708         *plparam = (LPARAM)MapLS( (LPVOID)(*plparam) );
1709         *pmsg16 = LB_GETTEXT16;
1710         return 1;
1711
1712     case CB_GETLBTEXT:
1713         *plparam = (LPARAM)MapLS( (LPVOID)(*plparam) );
1714         *pmsg16 = CB_GETLBTEXT16;
1715         return 1;
1716
1717     case EM_SETSEL:
1718         *pwparam16 = 0;
1719         *plparam = MAKELONG( (INT16)(INT)wParam32, (INT16)*plparam );
1720         *pmsg16 = EM_SETSEL16;
1721         return 0;
1722
1723     case WM_ACTIVATE:
1724     case WM_CHARTOITEM:
1725     case WM_COMMAND:
1726     case WM_VKEYTOITEM:
1727         *plparam = MAKELPARAM( (HWND16)*plparam, HIWORD(wParam32) );
1728         return 0;
1729     case WM_HSCROLL:
1730     case WM_VSCROLL:
1731         *plparam = MAKELPARAM( HIWORD(wParam32), (HWND16)*plparam );
1732         return 0;
1733     case WM_COPYDATA:
1734         {
1735             PCOPYDATASTRUCT pcds32 = (PCOPYDATASTRUCT) *plparam;
1736             PCOPYDATASTRUCT16 pcds = HeapAlloc( GetProcessHeap(), 0, sizeof( *pcds));
1737             pcds->dwData = pcds32->dwData;
1738             pcds->cbData = pcds32->cbData;
1739             pcds->lpData = MapLS( pcds32->lpData);
1740             *plparam = MapLS( pcds );
1741         }
1742         return 1;
1743     case WM_CTLCOLORMSGBOX:
1744     case WM_CTLCOLOREDIT:
1745     case WM_CTLCOLORLISTBOX:
1746     case WM_CTLCOLORBTN:
1747     case WM_CTLCOLORDLG:
1748     case WM_CTLCOLORSCROLLBAR:
1749     case WM_CTLCOLORSTATIC:
1750         *pmsg16  = WM_CTLCOLOR;
1751         *plparam = MAKELPARAM( (HWND16)*plparam,
1752                                (WORD)msg32 - WM_CTLCOLORMSGBOX );
1753         return 0;
1754     case WM_COMPAREITEM:
1755         {
1756             COMPAREITEMSTRUCT *cis32 = (COMPAREITEMSTRUCT *)*plparam;
1757             COMPAREITEMSTRUCT16 *cis = HeapAlloc( GetProcessHeap(), 0, sizeof(COMPAREITEMSTRUCT16));
1758             if (!cis) return -1;
1759             cis->CtlType    = (UINT16)cis32->CtlType;
1760             cis->CtlID      = (UINT16)cis32->CtlID;
1761             cis->hwndItem   = HWND_16( cis32->hwndItem );
1762             cis->itemID1    = (UINT16)cis32->itemID1;
1763             cis->itemData1  = cis32->itemData1;
1764             cis->itemID2    = (UINT16)cis32->itemID2;
1765             cis->itemData2  = cis32->itemData2;
1766             *plparam = MapLS( cis );
1767         }
1768         return 1;
1769     case WM_DELETEITEM:
1770         {
1771             DELETEITEMSTRUCT *dis32 = (DELETEITEMSTRUCT *)*plparam;
1772             DELETEITEMSTRUCT16 *dis = HeapAlloc( GetProcessHeap(), 0, sizeof(DELETEITEMSTRUCT16) );
1773             if (!dis) return -1;
1774             dis->CtlType  = (UINT16)dis32->CtlType;
1775             dis->CtlID    = (UINT16)dis32->CtlID;
1776             dis->itemID   = (UINT16)dis32->itemID;
1777             dis->hwndItem = (dis->CtlType == ODT_MENU) ? (HWND16)LOWORD(dis32->hwndItem)
1778                                                        : HWND_16( dis32->hwndItem );
1779             dis->itemData = dis32->itemData;
1780             *plparam = MapLS( dis );
1781         }
1782         return 1;
1783     case WM_DRAWITEM:
1784         {
1785             DRAWITEMSTRUCT *dis32 = (DRAWITEMSTRUCT *)*plparam;
1786             DRAWITEMSTRUCT16 *dis = HeapAlloc( GetProcessHeap(), 0, sizeof(DRAWITEMSTRUCT16) );
1787             if (!dis) return -1;
1788             dis->CtlType       = (UINT16)dis32->CtlType;
1789             dis->CtlID         = (UINT16)dis32->CtlID;
1790             dis->itemID        = (UINT16)dis32->itemID;
1791             dis->itemAction    = (UINT16)dis32->itemAction;
1792             dis->itemState     = (UINT16)dis32->itemState;
1793             dis->hwndItem      = HWND_16( dis32->hwndItem );
1794             dis->hDC           = HDC_16(dis32->hDC);
1795             dis->itemData      = dis32->itemData;
1796             dis->rcItem.left   = dis32->rcItem.left;
1797             dis->rcItem.top    = dis32->rcItem.top;
1798             dis->rcItem.right  = dis32->rcItem.right;
1799             dis->rcItem.bottom = dis32->rcItem.bottom;
1800             *plparam = MapLS( dis );
1801         }
1802         return 1;
1803     case WM_MEASUREITEM:
1804         {
1805             MEASUREITEMSTRUCT *mis32 = (MEASUREITEMSTRUCT *)*plparam;
1806             MEASUREITEMSTRUCT16 *mis = HeapAlloc( GetProcessHeap(), 0, sizeof(*mis)+sizeof(LPARAM));
1807             if (!mis) return -1;
1808             mis->CtlType    = (UINT16)mis32->CtlType;
1809             mis->CtlID      = (UINT16)mis32->CtlID;
1810             mis->itemID     = (UINT16)mis32->itemID;
1811             mis->itemWidth  = (UINT16)mis32->itemWidth;
1812             mis->itemHeight = (UINT16)mis32->itemHeight;
1813             mis->itemData   = mis32->itemData;
1814             *(LPARAM *)(mis + 1) = *plparam;  /* Store the previous lParam */
1815             *plparam = MapLS( mis );
1816         }
1817         return 1;
1818     case WM_GETMINMAXINFO:
1819         {
1820             MINMAXINFO16 *mmi = HeapAlloc( GetProcessHeap(), 0, sizeof(*mmi) + sizeof(LPARAM) );
1821             if (!mmi) return -1;
1822             MINMAXINFO32to16( (MINMAXINFO *)*plparam, mmi );
1823             *(LPARAM *)(mmi + 1) = *plparam;  /* Store the previous lParam */
1824             *plparam = MapLS( mmi );
1825         }
1826         return 1;
1827     case WM_GETTEXT:
1828     case WM_ASKCBFORMATNAME:
1829         {
1830             LPARAM *str; /* store LPARAM, then *pwparam16 char space */
1831             *pwparam16 = (WPARAM16)min( wParam32, 0xff80 ); /* Must be < 64K */
1832             if (!(str = HeapAlloc( GetProcessHeap(), 0, *pwparam16 + sizeof(LPARAM)))) return -1;
1833             *str++ = *plparam;  /* Store the previous lParam */
1834             *plparam = MapLS( str );
1835         }
1836         return 1;
1837     case WM_MDICREATE:
1838         {
1839             MDICREATESTRUCT16 *cs;
1840             MDICREATESTRUCTA *cs32 = (MDICREATESTRUCTA *)*plparam;
1841
1842             if (!(cs = HeapAlloc( GetProcessHeap(), 0, sizeof(MDICREATESTRUCT16) ))) return -1;
1843             MDICREATESTRUCT32Ato16( cs32, cs );
1844             cs->szTitle = MapLS( cs32->szTitle );
1845             cs->szClass = MapLS( cs32->szClass );
1846             *plparam = MapLS( cs );
1847         }
1848         return 1;
1849     case WM_MDIGETACTIVE:
1850         return 1;
1851     case WM_MDISETMENU:
1852         *plparam   = MAKELPARAM( (HMENU16)LOWORD(wParam32),
1853                                  (HMENU16)LOWORD(*plparam) );
1854         *pwparam16 = (*plparam == 0);
1855         return 0;
1856     case WM_MENUSELECT:
1857         if(HIWORD(wParam32) & MF_POPUP)
1858         {
1859             HMENU hmenu;
1860             if (((UINT)HIWORD(wParam32) != 0xFFFF) || (*plparam))
1861             {
1862                 if((hmenu = GetSubMenu((HMENU)*plparam, *pwparam16)))
1863                     *pwparam16=HMENU_16(hmenu);
1864             }
1865         }
1866         /* fall through */
1867     case WM_MENUCHAR:
1868         *plparam = MAKELPARAM( HIWORD(wParam32), (HMENU16)*plparam );
1869         return 0;
1870     case WM_MDIACTIVATE:
1871         if (GetWindowLongW( hwnd, GWL_EXSTYLE ) & WS_EX_MDICHILD)
1872         {
1873             *pwparam16 = ((HWND)*plparam == hwnd);
1874             *plparam = MAKELPARAM( (HWND16)LOWORD(*plparam),
1875                                    (HWND16)LOWORD(wParam32) );
1876         }
1877         else
1878         {
1879             *pwparam16 = HWND_16( (HWND)wParam32 );
1880             *plparam = 0;
1881         }
1882         return 0;
1883     case WM_NCCALCSIZE:
1884         {
1885             NCCALCSIZE_PARAMS *nc32 = (NCCALCSIZE_PARAMS *)*plparam;
1886             NCCALCSIZE_PARAMS16 *nc = HeapAlloc( GetProcessHeap(), 0, sizeof(*nc) + sizeof(LPARAM));
1887             if (!nc) return -1;
1888
1889             nc->rgrc[0].left   = nc32->rgrc[0].left;
1890             nc->rgrc[0].top    = nc32->rgrc[0].top;
1891             nc->rgrc[0].right  = nc32->rgrc[0].right;
1892             nc->rgrc[0].bottom = nc32->rgrc[0].bottom;
1893             if (wParam32)
1894             {
1895                 WINDOWPOS16 *wp;
1896                 nc->rgrc[1].left   = nc32->rgrc[1].left;
1897                 nc->rgrc[1].top    = nc32->rgrc[1].top;
1898                 nc->rgrc[1].right  = nc32->rgrc[1].right;
1899                 nc->rgrc[1].bottom = nc32->rgrc[1].bottom;
1900                 nc->rgrc[2].left   = nc32->rgrc[2].left;
1901                 nc->rgrc[2].top    = nc32->rgrc[2].top;
1902                 nc->rgrc[2].right  = nc32->rgrc[2].right;
1903                 nc->rgrc[2].bottom = nc32->rgrc[2].bottom;
1904                 if (!(wp = HeapAlloc( GetProcessHeap(), 0, sizeof(WINDOWPOS16) )))
1905                 {
1906                     HeapFree( GetProcessHeap(), 0, nc );
1907                     return -1;
1908                 }
1909                 WINDOWPOS32to16( nc32->lppos, wp );
1910                 nc->lppos = MapLS( wp );
1911             }
1912             *(LPARAM *)(nc + 1) = *plparam;  /* Store the previous lParam */
1913             *plparam = MapLS( nc );
1914         }
1915         return 1;
1916     case WM_NCCREATE:
1917     case WM_CREATE:
1918         {
1919             CREATESTRUCT16 *cs;
1920             CREATESTRUCTA *cs32 = (CREATESTRUCTA *)*plparam;
1921
1922             if (!(cs = HeapAlloc( GetProcessHeap(), 0, sizeof(CREATESTRUCT16) ))) return -1;
1923             CREATESTRUCT32Ato16( cs32, cs );
1924             cs->lpszName  = MapLS( cs32->lpszName );
1925             cs->lpszClass = MapLS( cs32->lpszClass );
1926
1927             if (GetWindowLongW(hwnd, GWL_EXSTYLE) & WS_EX_MDICHILD)
1928             {
1929                 MDICREATESTRUCT16 *mdi_cs16;
1930                 MDICREATESTRUCTA *mdi_cs = (MDICREATESTRUCTA *)cs32->lpCreateParams;
1931                 mdi_cs16 = HeapAlloc(GetProcessHeap(), 0, sizeof(*mdi_cs16));
1932                 if (!mdi_cs16)
1933                 {
1934                     HeapFree(GetProcessHeap(), 0, cs);
1935                     return -1;
1936                 }
1937                 MDICREATESTRUCT32Ato16(mdi_cs, mdi_cs16);
1938                 mdi_cs16->szTitle = MapLS( mdi_cs->szTitle );
1939                 mdi_cs16->szClass = MapLS( mdi_cs->szClass );
1940                 cs->lpCreateParams = MapLS( mdi_cs16 );
1941             }
1942             *plparam = MapLS( cs );
1943         }
1944         return 1;
1945     case WM_PARENTNOTIFY:
1946         if ((LOWORD(wParam32)==WM_CREATE) || (LOWORD(wParam32)==WM_DESTROY))
1947             *plparam = MAKELPARAM( (HWND16)*plparam, HIWORD(wParam32));
1948         /* else nothing to do */
1949         return 0;
1950     case WM_NOTIFY:
1951         *plparam = MapLS( (NMHDR *)*plparam ); /* NMHDR is already 32-bit */
1952         return 1;
1953     case WM_SETTEXT:
1954     case WM_WININICHANGE:
1955     case WM_DEVMODECHANGE:
1956         *plparam = MapLS( (LPSTR)*plparam );
1957         return 1;
1958     case WM_WINDOWPOSCHANGING:
1959     case WM_WINDOWPOSCHANGED:
1960         {
1961             WINDOWPOS16 *wp = HeapAlloc( GetProcessHeap(), 0, sizeof(*wp) + sizeof(LPARAM) );
1962             if (!wp) return -1;
1963             WINDOWPOS32to16( (WINDOWPOS *)*plparam, wp );
1964             *(LPARAM *)(wp + 1) = *plparam;  /* Store the previous lParam */
1965             *plparam = MapLS( wp );
1966         }
1967         return 1;
1968     case WM_GETDLGCODE:
1969          if (*plparam) {
1970             LPMSG msg32 = (LPMSG) *plparam;
1971             LPMSG16 msg16 = HeapAlloc( GetProcessHeap(), 0, sizeof(MSG16) );
1972
1973             if (!msg16) return -1;
1974             msg16->hwnd = HWND_16( msg32->hwnd );
1975             msg16->message = msg32->message;
1976             msg16->wParam = msg32->wParam;
1977             msg16->lParam = msg32->lParam;
1978             msg16->time = msg32->time;
1979             msg16->pt.x = msg32->pt.x;
1980             msg16->pt.y = msg32->pt.y;
1981             *plparam = MapLS( msg16 );
1982             return 1;
1983         }
1984         return 0;
1985
1986     case WM_ACTIVATEAPP:
1987         if (*plparam) *plparam = HTASK_16( (HANDLE)*plparam );
1988         return 0;
1989     case WM_NEXTMENU:
1990         {
1991             MDINEXTMENU *next = (MDINEXTMENU *)*plparam;
1992             *plparam = (LPARAM)next->hmenuIn;
1993             return 1;
1994         }
1995     case WM_PAINT:
1996         if (IsIconic( hwnd ) && GetClassLongPtrW( hwnd, GCLP_HICON ))
1997         {
1998             *pmsg16 = WM_PAINTICON;
1999             *pwparam16 = 1;
2000         }
2001         return 0;
2002     case WM_ERASEBKGND:
2003         if (IsIconic( hwnd ) && GetClassLongPtrW( hwnd, GCLP_HICON ))
2004             *pmsg16 = WM_ICONERASEBKGND;
2005         return 0;
2006     case WM_PAINTCLIPBOARD:
2007     case WM_SIZECLIPBOARD:
2008         FIXME_(msg)("message %04x needs translation\n", msg32 );
2009         return -1;
2010     /* following messages should not be sent to 16-bit apps */
2011     case WM_SIZING:
2012     case WM_MOVING:
2013     case WM_CAPTURECHANGED:
2014     case WM_STYLECHANGING:
2015     case WM_STYLECHANGED:
2016         return -1;
2017     case WM_DDE_INITIATE:
2018     case WM_DDE_TERMINATE:
2019     case WM_DDE_UNADVISE:
2020     case WM_DDE_REQUEST:
2021         *pwparam16 = HWND_16((HWND)wParam32);
2022         return 0;
2023     case WM_DDE_ADVISE:
2024     case WM_DDE_DATA:
2025     case WM_DDE_POKE:
2026         {
2027             UINT_PTR lo32, hi;
2028             HANDLE16    lo16 = 0;
2029
2030             *pwparam16 = HWND_16((HWND)wParam32);
2031             UnpackDDElParam(msg32, *plparam, &lo32, &hi);
2032             if (lo32 && !(lo16 = convert_handle_32_to_16(lo32, GMEM_DDESHARE)))
2033                 return -1;
2034             *plparam = MAKELPARAM(lo16, hi);
2035         }
2036         return 0; /* FIXME don't know how to free allocated memory (handle)  !! */
2037     case WM_DDE_ACK:
2038         {
2039             UINT_PTR    lo, hi;
2040             int         flag = 0;
2041             char        buf[2];
2042
2043             *pwparam16 = HWND_16((HWND)wParam32);
2044
2045             UnpackDDElParam(msg32, *plparam, &lo, &hi);
2046
2047             if (GlobalGetAtomNameA((ATOM)hi, buf, sizeof(buf)) > 0) flag |= 1;
2048             if (GlobalSize((HANDLE)hi) != 0) flag |= 2;
2049             switch (flag)
2050             {
2051             case 0:
2052                 if (hi)
2053                 {
2054                     MESSAGE("DDE_ACK: neither atom nor handle!!!\n");
2055                     hi = 0;
2056                 }
2057                 break;
2058             case 1:
2059                 break; /* atom, nothing to do */
2060             case 3:
2061                 MESSAGE("DDE_ACK: %x both atom and handle... choosing handle\n", hi);
2062                 /* fall thru */
2063             case 2:
2064                 hi = convert_handle_32_to_16(hi, GMEM_DDESHARE);
2065                 break;
2066             }
2067             *plparam = MAKELPARAM(lo, hi);
2068         }
2069         return 0; /* FIXME don't know how to free allocated memory (handle) !! */
2070     case WM_DDE_EXECUTE:
2071         *plparam = convert_handle_32_to_16(*plparam, GMEM_DDESHARE);
2072         return 0; /* FIXME don't know how to free allocated memory (handle) !! */
2073     default:  /* No translation needed */
2074         return 0;
2075     }
2076 }
2077
2078
2079 /**********************************************************************
2080  *           WINPROC_UnmapMsg32ATo16
2081  *
2082  * Unmap a message that was mapped from 32-bit Ansi to 16-bit.
2083  */
2084 static void WINPROC_UnmapMsg32ATo16( HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam,
2085                                      WPARAM16 wParam16, LPARAM lParam16, LRESULT *result )
2086 {
2087     switch(msg)
2088     {
2089     case SBM_GETRANGE:
2090         *(LPINT)wParam = LOWORD(*result);
2091         *(LPINT)lParam = HIWORD(*result);
2092         break;
2093
2094     case LB_ADDFILE:
2095     case LB_ADDSTRING:
2096     case LB_DIR:
2097     case LB_FINDSTRING:
2098     case LB_FINDSTRINGEXACT:
2099     case LB_INSERTSTRING:
2100     case LB_SELECTSTRING:
2101     case LB_GETTEXT:
2102     case CB_ADDSTRING:
2103     case CB_FINDSTRING:
2104     case CB_FINDSTRINGEXACT:
2105     case CB_INSERTSTRING:
2106     case CB_SELECTSTRING:
2107     case CB_DIR:
2108     case CB_GETLBTEXT:
2109     case WM_SETTEXT:
2110     case WM_WININICHANGE:
2111     case WM_DEVMODECHANGE:
2112         UnMapLS( (SEGPTR)lParam16 );
2113         break;
2114     case LB_SETTABSTOPS:
2115     case WM_COMPAREITEM:
2116     case WM_DELETEITEM:
2117     case WM_DRAWITEM:
2118         {
2119             void *ptr = MapSL( lParam16 );
2120             UnMapLS( lParam16 );
2121             HeapFree( GetProcessHeap(), 0, ptr );
2122         }
2123         break;
2124     case WM_COPYDATA:
2125         {
2126             PCOPYDATASTRUCT16 pcds = MapSL( lParam16 );
2127             UnMapLS( lParam16 );
2128             UnMapLS( pcds->lpData );
2129             HeapFree( GetProcessHeap(), 0, pcds );
2130         }
2131         break;
2132     case CB_GETDROPPEDCONTROLRECT:
2133     case LB_GETITEMRECT:
2134         {
2135             RECT *r32;
2136             RECT16 *rect = MapSL(lParam16);
2137             UnMapLS( lParam16 );
2138             lParam16 = *(LPARAM *)(rect + 1);
2139             r32 = (RECT *)lParam16;
2140             r32->left   = rect->left;
2141             r32->top    = rect->top;
2142             r32->right  = rect->right;
2143             r32->bottom = rect->bottom;
2144             HeapFree( GetProcessHeap(), 0, rect );
2145         }
2146         break;
2147     case LB_GETSELITEMS:
2148         {
2149             INT i;
2150             LPINT16 items = MapSL(lParam16);
2151             UnMapLS( lParam16 );
2152             lParam16 = *((LPARAM *)items - 1);
2153             for (i = 0; i < wParam16; i++) *((LPINT)lParam16 + i) = items[i];
2154             HeapFree( GetProcessHeap(), 0, (LPARAM *)items - 1 );
2155         }
2156         break;
2157
2158     case CB_GETEDITSEL:
2159         if( wParam )
2160             *((PUINT)(wParam)) = LOWORD(*result);
2161         if( lParam )
2162             *((PUINT)(lParam)) = HIWORD(*result);  /* FIXME: substract 1? */
2163         break;
2164
2165     case WM_MEASUREITEM:
2166         {
2167             MEASUREITEMSTRUCT16 *mis = MapSL(lParam16);
2168             MEASUREITEMSTRUCT *mis32 = *(MEASUREITEMSTRUCT **)(mis + 1);
2169             mis32->itemWidth  = mis->itemWidth;
2170             mis32->itemHeight = mis->itemHeight;
2171             UnMapLS( lParam16 );
2172             HeapFree( GetProcessHeap(), 0, mis );
2173         }
2174         break;
2175     case WM_GETMINMAXINFO:
2176         {
2177             MINMAXINFO16 *mmi = MapSL(lParam16);
2178             UnMapLS( lParam16 );
2179             lParam16 = *(LPARAM *)(mmi + 1);
2180             MINMAXINFO16to32( mmi, (MINMAXINFO *)lParam16 );
2181             HeapFree( GetProcessHeap(), 0, mmi );
2182         }
2183         break;
2184     case WM_GETTEXT:
2185     case WM_ASKCBFORMATNAME:
2186         {
2187             LPSTR str = MapSL(lParam16);
2188             UnMapLS( lParam16 );
2189             lParam16 = *((LPARAM *)str - 1);
2190             lstrcpynA( (LPSTR)lParam16, str, wParam16 );
2191             HeapFree( GetProcessHeap(), 0, (LPARAM *)str - 1 );
2192         }
2193         break;
2194     case WM_MDICREATE:
2195         {
2196             MDICREATESTRUCT16 *cs = MapSL(lParam16);
2197             UnMapLS( cs->szTitle );
2198             UnMapLS( cs->szClass );
2199             UnMapLS( lParam16 );
2200             HeapFree( GetProcessHeap(), 0, cs );
2201         }
2202         break;
2203     case WM_MDIGETACTIVE:
2204         if (lParam) *(BOOL *)lParam = (BOOL16)HIWORD(*result);
2205         *result = (LRESULT)WIN_Handle32( LOWORD(*result) );
2206         break;
2207     case WM_NCCALCSIZE:
2208         {
2209             NCCALCSIZE_PARAMS *nc32;
2210             NCCALCSIZE_PARAMS16 *nc = MapSL(lParam16);
2211             UnMapLS( lParam16 );
2212             lParam16 = *(LPARAM *)(nc + 1);
2213             nc32 = (NCCALCSIZE_PARAMS *)lParam16;
2214             nc32->rgrc[0].left   = nc->rgrc[0].left;
2215             nc32->rgrc[0].top    = nc->rgrc[0].top;
2216             nc32->rgrc[0].right  = nc->rgrc[0].right;
2217             nc32->rgrc[0].bottom = nc->rgrc[0].bottom;
2218             if (wParam16)
2219             {
2220                 WINDOWPOS16 *pos = MapSL(nc->lppos);
2221                 UnMapLS( nc->lppos );
2222                 nc32->rgrc[1].left   = nc->rgrc[1].left;
2223                 nc32->rgrc[1].top    = nc->rgrc[1].top;
2224                 nc32->rgrc[1].right  = nc->rgrc[1].right;
2225                 nc32->rgrc[1].bottom = nc->rgrc[1].bottom;
2226                 nc32->rgrc[2].left   = nc->rgrc[2].left;
2227                 nc32->rgrc[2].top    = nc->rgrc[2].top;
2228                 nc32->rgrc[2].right  = nc->rgrc[2].right;
2229                 nc32->rgrc[2].bottom = nc->rgrc[2].bottom;
2230                 WINDOWPOS16to32( pos, nc32->lppos );
2231                 HeapFree( GetProcessHeap(), 0, pos );
2232             }
2233             HeapFree( GetProcessHeap(), 0, nc );
2234         }
2235         break;
2236     case WM_NCCREATE:
2237     case WM_CREATE:
2238         {
2239             CREATESTRUCT16 *cs = MapSL(lParam16);
2240             UnMapLS( lParam16 );
2241             UnMapLS( cs->lpszName );
2242             UnMapLS( cs->lpszClass );
2243             if (GetWindowLongW(hwnd, GWL_EXSTYLE) & WS_EX_MDICHILD)
2244             {
2245                 MDICREATESTRUCT16 *mdi_cs16 = (MDICREATESTRUCT16 *)MapSL(cs->lpCreateParams);
2246                 UnMapLS( cs->lpCreateParams );
2247                 UnMapLS( mdi_cs16->szTitle );
2248                 UnMapLS( mdi_cs16->szClass );
2249                 HeapFree(GetProcessHeap(), 0, mdi_cs16);
2250             }
2251             HeapFree( GetProcessHeap(), 0, cs );
2252         }
2253         break;
2254     case WM_WINDOWPOSCHANGING:
2255     case WM_WINDOWPOSCHANGED:
2256         {
2257             WINDOWPOS16 *wp = MapSL(lParam16);
2258             UnMapLS( lParam16 );
2259             lParam16 = *(LPARAM *)(wp + 1);
2260             WINDOWPOS16to32( wp, (WINDOWPOS *)lParam16 );
2261             HeapFree( GetProcessHeap(), 0, wp );
2262         }
2263         break;
2264     case WM_NOTIFY:
2265         UnMapLS(lParam16);
2266         break;
2267     case WM_GETDLGCODE:
2268         if (lParam16)
2269         {
2270             LPMSG16 msg16 = MapSL(lParam16);
2271             UnMapLS( lParam16 );
2272             HeapFree( GetProcessHeap(), 0, msg16 );
2273         }
2274         break;
2275     case WM_NEXTMENU:
2276         {
2277             MDINEXTMENU *next = (MDINEXTMENU *)lParam;
2278             next->hmenuNext = HMENU_32( LOWORD(*result) );
2279             next->hwndNext = WIN_Handle32( HIWORD(*result) );
2280             *result = 0;
2281         }
2282         break;
2283     }
2284 }
2285
2286
2287 /**********************************************************************
2288  *           WINPROC_MapMsg32WTo16
2289  *
2290  * Map a message from 32-bit Unicode to 16-bit.
2291  * Return value is -1 on error, 0 if OK, 1 if an UnmapMsg call is needed.
2292  */
2293 static INT WINPROC_MapMsg32WTo16( HWND hwnd, UINT msg32, WPARAM wParam32,
2294                                   UINT16 *pmsg16, WPARAM16 *pwparam16, LPARAM *plparam )
2295 {
2296     *pmsg16    = LOWORD(msg32);
2297     *pwparam16 = LOWORD(wParam32);
2298     switch(msg32)
2299     {
2300     case LB_ADDSTRING:
2301     case LB_FINDSTRING:
2302     case LB_FINDSTRINGEXACT:
2303     case LB_INSERTSTRING:
2304     case LB_SELECTSTRING:
2305     case LB_DIR:
2306     case LB_ADDFILE:
2307         *plparam = map_str_32W_to_16( (LPWSTR)*plparam );
2308         *pmsg16 = (UINT16)msg32 + (LB_ADDSTRING16 - LB_ADDSTRING);
2309         return 1;
2310
2311     case CB_ADDSTRING:
2312     case CB_FINDSTRING:
2313     case CB_FINDSTRINGEXACT:
2314     case CB_INSERTSTRING:
2315     case CB_SELECTSTRING:
2316     case CB_DIR:
2317         *plparam = map_str_32W_to_16( (LPWSTR)*plparam );
2318         *pmsg16 = (UINT16)msg32 + (CB_ADDSTRING16 - CB_ADDSTRING);
2319         return 1;
2320
2321     case WM_NCCREATE:
2322     case WM_CREATE:
2323         {
2324             CREATESTRUCT16 *cs;
2325             CREATESTRUCTW *cs32 = (CREATESTRUCTW *)*plparam;
2326
2327             if (!(cs = HeapAlloc( GetProcessHeap(), 0, sizeof(CREATESTRUCT16) ))) return -1;
2328             CREATESTRUCT32Ato16( (CREATESTRUCTA *)cs32, cs );
2329             cs->lpszName  = map_str_32W_to_16( cs32->lpszName );
2330             cs->lpszClass = map_str_32W_to_16( cs32->lpszClass );
2331
2332             if (GetWindowLongW(hwnd, GWL_EXSTYLE) & WS_EX_MDICHILD)
2333             {
2334                 MDICREATESTRUCT16 *mdi_cs16;
2335                 MDICREATESTRUCTW *mdi_cs = (MDICREATESTRUCTW *)cs32->lpCreateParams;
2336                 mdi_cs16 = HeapAlloc(GetProcessHeap(), 0, sizeof(*mdi_cs16));
2337                 if (!mdi_cs16)
2338                 {
2339                     HeapFree(GetProcessHeap(), 0, cs);
2340                     return -1;
2341                 }
2342                 MDICREATESTRUCT32Ato16((MDICREATESTRUCTA *)mdi_cs, mdi_cs16);
2343                 mdi_cs16->szTitle = map_str_32W_to_16(mdi_cs->szTitle);
2344                 mdi_cs16->szClass = map_str_32W_to_16(mdi_cs->szClass);
2345                 cs->lpCreateParams = MapLS(mdi_cs16);
2346             }
2347             *plparam   = MapLS(cs);
2348         }
2349         return 1;
2350     case WM_MDICREATE:
2351         {
2352             MDICREATESTRUCT16 *cs;
2353             MDICREATESTRUCTW *cs32 = (MDICREATESTRUCTW *)*plparam;
2354
2355             if (!(cs = HeapAlloc( GetProcessHeap(), 0, sizeof(MDICREATESTRUCT16) ))) return -1;
2356             MDICREATESTRUCT32Ato16( (MDICREATESTRUCTA *)cs32, cs );
2357             cs->szTitle = map_str_32W_to_16( cs32->szTitle );
2358             cs->szClass = map_str_32W_to_16( cs32->szClass );
2359             *plparam   = MapLS(cs);
2360         }
2361         return 1;
2362     case WM_SETTEXT:
2363     case WM_WININICHANGE:
2364     case WM_DEVMODECHANGE:
2365         *plparam = map_str_32W_to_16( (LPWSTR)*plparam );
2366         return 1;
2367     case LB_GETTEXT:
2368     case CB_GETLBTEXT:
2369         if ( WINPROC_TestLBForStr( hwnd, msg32 ))
2370         {
2371             LPSTR str = HeapAlloc( GetProcessHeap(), 0, 512 ); /* FIXME: fixed sized buffer */
2372             if (!str) return -1;
2373             *pmsg16    = (msg32 == LB_GETTEXT) ? LB_GETTEXT16 : CB_GETLBTEXT16;
2374             *plparam   = (LPARAM)MapLS(str);
2375         }
2376         return 1;
2377
2378     case WM_CHARTOITEM:
2379         *pwparam16 = map_wparam_char_WtoA( wParam32, 1 );
2380         *plparam = MAKELPARAM( (HWND16)*plparam, HIWORD(wParam32) );
2381         return 0;
2382     case WM_MENUCHAR:
2383         *pwparam16 = map_wparam_char_WtoA( wParam32, 1 );
2384         *plparam = MAKELPARAM( HIWORD(wParam32), (HMENU16)*plparam );
2385         return 0;
2386     case WM_CHAR:
2387     case WM_DEADCHAR:
2388     case WM_SYSCHAR:
2389     case WM_SYSDEADCHAR:
2390         *pwparam16 = map_wparam_char_WtoA( wParam32, 1 );
2391         return 0;
2392     case WM_IME_CHAR:
2393         *pwparam16 = map_wparam_char_WtoA( wParam32, 2 );
2394         return 0;
2395
2396     default:  /* No Unicode translation needed (?) */
2397         return WINPROC_MapMsg32ATo16( hwnd, msg32, wParam32, pmsg16,
2398                                       pwparam16, plparam );
2399     }
2400 }
2401
2402
2403 /**********************************************************************
2404  *           WINPROC_UnmapMsg32WTo16
2405  *
2406  * Unmap a message that was mapped from 32-bit Unicode to 16-bit.
2407  */
2408 static void WINPROC_UnmapMsg32WTo16( HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam,
2409                                      WPARAM16 wParam16, LPARAM lParam16, LRESULT *result )
2410 {
2411     switch(msg)
2412     {
2413     case LB_ADDSTRING:
2414     case LB_FINDSTRING:
2415     case LB_FINDSTRINGEXACT:
2416     case LB_INSERTSTRING:
2417     case LB_SELECTSTRING:
2418     case LB_DIR:
2419     case LB_ADDFILE:
2420     case CB_ADDSTRING:
2421     case CB_FINDSTRING:
2422     case CB_FINDSTRINGEXACT:
2423     case CB_INSERTSTRING:
2424     case CB_SELECTSTRING:
2425     case CB_DIR:
2426     case WM_SETTEXT:
2427     case WM_WININICHANGE:
2428     case WM_DEVMODECHANGE:
2429         unmap_str_32W_to_16( lParam16 );
2430         break;
2431     case WM_NCCREATE:
2432     case WM_CREATE:
2433         {
2434             CREATESTRUCT16 *cs = MapSL(lParam16);
2435             UnMapLS( lParam16 );
2436             unmap_str_32W_to_16( cs->lpszName );
2437             unmap_str_32W_to_16( cs->lpszClass );
2438
2439             if (GetWindowLongW(hwnd, GWL_EXSTYLE) & WS_EX_MDICHILD)
2440             {
2441                 MDICREATESTRUCT16 *mdi_cs16 = (MDICREATESTRUCT16 *)MapSL(cs->lpCreateParams);
2442                 UnMapLS( cs->lpCreateParams );
2443                 unmap_str_32W_to_16(mdi_cs16->szTitle);
2444                 unmap_str_32W_to_16(mdi_cs16->szClass);
2445                 HeapFree(GetProcessHeap(), 0, mdi_cs16);
2446             }
2447             HeapFree( GetProcessHeap(), 0, cs );
2448         }
2449         break;
2450     case WM_MDICREATE:
2451         {
2452             MDICREATESTRUCT16 *cs = MapSL(lParam16);
2453             UnMapLS( lParam16 );
2454             unmap_str_32W_to_16( cs->szTitle );
2455             unmap_str_32W_to_16( cs->szClass );
2456             HeapFree( GetProcessHeap(), 0, cs );
2457         }
2458         break;
2459     case WM_GETTEXT:
2460     case WM_ASKCBFORMATNAME:
2461         {
2462             LPSTR str = MapSL(lParam16);
2463             UnMapLS( lParam16 );
2464             lParam16 = *((LPARAM *)str - 1);
2465             MultiByteToWideChar( CP_ACP, 0, str, -1, (LPWSTR)lParam16, 0x7fffffff );
2466             *result = strlenW( (LPWSTR)lParam16 );
2467             HeapFree( GetProcessHeap(), 0, (LPARAM *)str - 1 );
2468         }
2469         break;
2470     case LB_GETTEXT:
2471     case CB_GETLBTEXT:
2472         if ( WINPROC_TestLBForStr( hwnd, msg ))
2473         {
2474             LPSTR str = MapSL(lParam16);
2475             UnMapLS( lParam16 );
2476             *result = MultiByteToWideChar( CP_ACP, 0, str, -1, (LPWSTR)lParam, 0x7fffffff ) - 1;
2477             HeapFree( GetProcessHeap(), 0, (LPARAM *)str );
2478         }
2479         break;
2480     default:
2481         WINPROC_UnmapMsg32ATo16( hwnd, msg, wParam, lParam, wParam16, lParam16, result );
2482         break;
2483     }
2484 }
2485
2486
2487 /**********************************************************************
2488  *           WINPROC_CallProcAtoW
2489  *
2490  * Call a window procedure, translating args from Ansi to Unicode.
2491  */
2492 LRESULT WINPROC_CallProcAtoW( winproc_callback_t callback, HWND hwnd, UINT msg, WPARAM wParam,
2493                               LPARAM lParam, LRESULT *result, void *arg )
2494 {
2495     LRESULT ret = 0;
2496
2497     TRACE_(msg)("(hwnd=%p,msg=%s,wp=%08x,lp=%08lx)\n",
2498                 hwnd, SPY_GetMsgName(msg, hwnd), wParam, lParam);
2499
2500     switch(msg)
2501     {
2502     case WM_NCCREATE:
2503     case WM_CREATE:
2504         {
2505             WCHAR *ptr, buffer[512];
2506             CREATESTRUCTA *csA = (CREATESTRUCTA *)lParam;
2507             CREATESTRUCTW csW = *(CREATESTRUCTW *)csA;
2508             MDICREATESTRUCTW mdi_cs;
2509             DWORD name_lenA = 0, name_lenW = 0, class_lenA = 0, class_lenW = 0;
2510
2511             if (HIWORD(csA->lpszClass))
2512             {
2513                 class_lenA = strlen(csA->lpszClass) + 1;
2514                 RtlMultiByteToUnicodeSize( &class_lenW, csA->lpszClass, class_lenA );
2515             }
2516             if (HIWORD(csA->lpszName))
2517             {
2518                 name_lenA = strlen(csA->lpszName) + 1;
2519                 RtlMultiByteToUnicodeSize( &name_lenW, csA->lpszName, name_lenA );
2520             }
2521
2522             if (!(ptr = get_buffer( buffer, sizeof(buffer), class_lenW + name_lenW ))) break;
2523
2524             if (class_lenW)
2525             {
2526                 csW.lpszClass = ptr;
2527                 RtlMultiByteToUnicodeN( ptr, class_lenW, NULL, csA->lpszClass, class_lenA );
2528             }
2529             if (name_lenW)
2530             {
2531                 csW.lpszName = ptr + class_lenW/sizeof(WCHAR);
2532                 RtlMultiByteToUnicodeN( ptr + class_lenW/sizeof(WCHAR), name_lenW, NULL,
2533                                         csA->lpszName, name_lenA );
2534             }
2535
2536             if (GetWindowLongW(hwnd, GWL_EXSTYLE) & WS_EX_MDICHILD)
2537             {
2538                 mdi_cs = *(MDICREATESTRUCTW *)csA->lpCreateParams;
2539                 mdi_cs.szTitle = csW.lpszName;
2540                 mdi_cs.szClass = csW.lpszClass;
2541                 csW.lpCreateParams = &mdi_cs;
2542             }
2543
2544             ret = callback( hwnd, msg, wParam, (LPARAM)&csW, result, arg );
2545             free_buffer( buffer, ptr );
2546         }
2547         break;
2548
2549     case WM_MDICREATE:
2550         {
2551             WCHAR *ptr, buffer[512];
2552             DWORD title_lenA = 0, title_lenW = 0, class_lenA = 0, class_lenW = 0;
2553             MDICREATESTRUCTA *csA = (MDICREATESTRUCTA *)lParam;
2554             MDICREATESTRUCTW csW;
2555
2556             memcpy( &csW, csA, sizeof(csW) );
2557
2558             if (HIWORD(csA->szTitle))
2559             {
2560                 title_lenA = strlen(csA->szTitle) + 1;
2561                 RtlMultiByteToUnicodeSize( &title_lenW, csA->szTitle, title_lenA );
2562             }
2563             if (HIWORD(csA->szClass))
2564             {
2565                 class_lenA = strlen(csA->szClass) + 1;
2566                 RtlMultiByteToUnicodeSize( &class_lenW, csA->szClass, class_lenA );
2567             }
2568
2569             if (!(ptr = get_buffer( buffer, sizeof(buffer), title_lenW + class_lenW ))) break;
2570
2571             if (title_lenW)
2572             {
2573                 csW.szTitle = ptr;
2574                 RtlMultiByteToUnicodeN( ptr, title_lenW, NULL, csA->szTitle, title_lenA );
2575             }
2576             if (class_lenW)
2577             {
2578                 csW.szClass = ptr + title_lenW/sizeof(WCHAR);
2579                 RtlMultiByteToUnicodeN( ptr + title_lenW/sizeof(WCHAR), class_lenW, NULL,
2580                                         csA->szClass, class_lenA );
2581             }
2582             ret = callback( hwnd, msg, wParam, (LPARAM)&csW, result, arg );
2583             free_buffer( buffer, ptr );
2584         }
2585         break;
2586
2587     case WM_GETTEXT:
2588     case WM_ASKCBFORMATNAME:
2589         {
2590             WCHAR *ptr, buffer[512];
2591             LPSTR str = (LPSTR)lParam;
2592             DWORD len = wParam * sizeof(WCHAR);
2593
2594             if (!(ptr = get_buffer( buffer, sizeof(buffer), len ))) break;
2595             ret = callback( hwnd, msg, wParam, (LPARAM)ptr, result, arg );
2596             if (*result && wParam)
2597             {
2598                 RtlUnicodeToMultiByteN( str, wParam - 1, &len, ptr, strlenW(ptr) * sizeof(WCHAR) );
2599                 str[len] = 0;
2600                 *result = len;
2601             }
2602             free_buffer( buffer, ptr );
2603         }
2604         break;
2605
2606     case LB_ADDSTRING:
2607     case LB_INSERTSTRING:
2608     case LB_FINDSTRING:
2609     case LB_FINDSTRINGEXACT:
2610     case LB_SELECTSTRING:
2611     case CB_ADDSTRING:
2612     case CB_INSERTSTRING:
2613     case CB_FINDSTRING:
2614     case CB_FINDSTRINGEXACT:
2615     case CB_SELECTSTRING:
2616         if (!lParam || !WINPROC_TestLBForStr( hwnd, msg ))
2617         {
2618             ret = callback( hwnd, msg, wParam, lParam, result, arg );
2619             break;
2620         }
2621         /* fall through */
2622     case WM_SETTEXT:
2623     case WM_WININICHANGE:
2624     case WM_DEVMODECHANGE:
2625     case CB_DIR:
2626     case LB_DIR:
2627     case LB_ADDFILE:
2628     case EM_REPLACESEL:
2629         if (!lParam) ret = callback( hwnd, msg, wParam, lParam, result, arg );
2630         else
2631         {
2632             WCHAR *ptr, buffer[512];
2633             LPCSTR strA = (LPCSTR)lParam;
2634             DWORD lenW, lenA = strlen(strA) + 1;
2635
2636             RtlMultiByteToUnicodeSize( &lenW, strA, lenA );
2637             if ((ptr = get_buffer( buffer, sizeof(buffer), lenW )))
2638             {
2639                 RtlMultiByteToUnicodeN( ptr, lenW, NULL, strA, lenA );
2640                 ret = callback( hwnd, msg, wParam, (LPARAM)ptr, result, arg );
2641                 free_buffer( buffer, ptr );
2642             }
2643         }
2644         break;
2645
2646     case LB_GETTEXT:
2647     case CB_GETLBTEXT:
2648         if (lParam && WINPROC_TestLBForStr( hwnd, msg ))
2649         {
2650             WCHAR buffer[512];  /* FIXME: fixed sized buffer */
2651
2652             ret = callback( hwnd, msg, wParam, (LPARAM)buffer, result, arg );
2653             if (*result >= 0)
2654             {
2655                 DWORD len;
2656                 RtlUnicodeToMultiByteN( (LPSTR)lParam, ~0u, &len,
2657                                         buffer, (strlenW(buffer) + 1) * sizeof(WCHAR) );
2658                 *result = len - 1;
2659             }
2660         }
2661         else ret = callback( hwnd, msg, wParam, lParam, result, arg );
2662         break;
2663
2664     case EM_GETLINE:
2665         {
2666             WCHAR *ptr, buffer[512];
2667             WORD len = *(WORD *)lParam;
2668
2669             if (!(ptr = get_buffer( buffer, sizeof(buffer), len * sizeof(WCHAR) ))) break;
2670             *((WORD *)ptr) = len;   /* store the length */
2671             ret = callback( hwnd, msg, wParam, (LPARAM)ptr, result, arg );
2672             if (*result)
2673             {
2674                 DWORD reslen;
2675                 RtlUnicodeToMultiByteN( (LPSTR)lParam, len, &reslen, ptr, *result * sizeof(WCHAR) );
2676                 if (reslen < len) ((LPSTR)lParam)[reslen] = 0;
2677                 *result = reslen;
2678             }
2679             free_buffer( buffer, ptr );
2680         }
2681         break;
2682
2683     case WM_CHARTOITEM:
2684     case WM_MENUCHAR:
2685     case WM_CHAR:
2686     case WM_DEADCHAR:
2687     case WM_SYSCHAR:
2688     case WM_SYSDEADCHAR:
2689     case EM_SETPASSWORDCHAR:
2690         ret = callback( hwnd, msg, map_wparam_char_AtoW(wParam,1), lParam, result, arg );
2691         break;
2692
2693     case WM_IME_CHAR:
2694         ret = callback( hwnd, msg, map_wparam_char_AtoW(wParam,2), lParam, result, arg );
2695         break;
2696
2697     case WM_GETTEXTLENGTH:
2698     case CB_GETLBTEXTLEN:
2699     case LB_GETTEXTLEN:
2700         ret = callback( hwnd, msg, wParam, lParam, result, arg );
2701         if (*result >= 0)
2702         {
2703             WCHAR *ptr, buffer[512];
2704             LRESULT tmp;
2705             DWORD len = *result + 1;
2706             /* Determine respective GETTEXT message */
2707             UINT msgGetText = (msg == WM_GETTEXTLENGTH) ? WM_GETTEXT :
2708                               ((msg == CB_GETLBTEXTLEN) ? CB_GETLBTEXT : LB_GETTEXT);
2709             /* wParam differs between the messages */
2710             WPARAM wp = (msg == WM_GETTEXTLENGTH) ? len : wParam;
2711
2712             if (!(ptr = get_buffer( buffer, sizeof(buffer), len * sizeof(WCHAR) ))) break;
2713
2714             if (callback == call_window_proc)  /* FIXME: hack */
2715                 callback( hwnd, msgGetText, wp, (LPARAM)ptr, &tmp, arg );
2716             else
2717                 tmp = SendMessageW( hwnd, msgGetText, wp, (LPARAM)ptr );
2718             RtlUnicodeToMultiByteSize( &len, ptr, tmp * sizeof(WCHAR) );
2719             *result = len;
2720             free_buffer( buffer, ptr );
2721         }
2722         break;
2723
2724     case WM_PAINTCLIPBOARD:
2725     case WM_SIZECLIPBOARD:
2726         FIXME_(msg)( "message %s (0x%x) needs translation, please report\n",
2727                      SPY_GetMsgName(msg, hwnd), msg );
2728         break;
2729
2730     default:
2731         ret = callback( hwnd, msg, wParam, lParam, result, arg );
2732         break;
2733     }
2734     return ret;
2735 }
2736
2737
2738 /**********************************************************************
2739  *           WINPROC_CallProcWtoA
2740  *
2741  * Call a window procedure, translating args from Unicode to Ansi.
2742  */
2743 static LRESULT WINPROC_CallProcWtoA( winproc_callback_t callback, HWND hwnd, UINT msg, WPARAM wParam,
2744                                      LPARAM lParam, LRESULT *result, void *arg )
2745 {
2746     LRESULT ret = 0;
2747
2748     TRACE_(msg)("(hwnd=%p,msg=%s,wp=%08x,lp=%08lx)\n",
2749                 hwnd, SPY_GetMsgName(msg, hwnd), wParam, lParam);
2750
2751     switch(msg)
2752     {
2753     case WM_NCCREATE:
2754     case WM_CREATE:
2755         {   /* csW->lpszName and csW->lpszClass are NOT supposed to be atoms
2756              * at this point.
2757              */
2758             char buffer[1024], *cls, *name;
2759             CREATESTRUCTW *csW = (CREATESTRUCTW *)lParam;
2760             CREATESTRUCTA csA = *(CREATESTRUCTA *)csW;
2761             MDICREATESTRUCTA mdi_cs;
2762             DWORD name_lenA, name_lenW, class_lenA, class_lenW;
2763
2764             class_lenW = strlenW(csW->lpszClass) * sizeof(WCHAR);
2765             RtlUnicodeToMultiByteSize(&class_lenA, csW->lpszClass, class_lenW);
2766
2767             if (csW->lpszName)
2768             {
2769                 name_lenW = strlenW(csW->lpszName) * sizeof(WCHAR);
2770                 RtlUnicodeToMultiByteSize(&name_lenA, csW->lpszName, name_lenW);
2771             }
2772             else
2773                 name_lenW = name_lenA = 0;
2774
2775             if (!(cls = get_buffer( buffer, sizeof(buffer), class_lenA + name_lenA + 2 ))) break;
2776
2777             RtlUnicodeToMultiByteN(cls, class_lenA, NULL, csW->lpszClass, class_lenW);
2778             cls[class_lenA] = 0;
2779             csA.lpszClass = cls;
2780
2781             if (csW->lpszName)
2782             {
2783                 name = cls + class_lenA + 1;
2784                 RtlUnicodeToMultiByteN(name, name_lenA, NULL, csW->lpszName, name_lenW);
2785                 name[name_lenA] = 0;
2786                 csA.lpszName = name;
2787             }
2788
2789             if (GetWindowLongW(hwnd, GWL_EXSTYLE) & WS_EX_MDICHILD)
2790             {
2791                 mdi_cs = *(MDICREATESTRUCTA *)csW->lpCreateParams;
2792                 mdi_cs.szTitle = csA.lpszName;
2793                 mdi_cs.szClass = csA.lpszClass;
2794                 csA.lpCreateParams = &mdi_cs;
2795             }
2796
2797             ret = callback( hwnd, msg, wParam, (LPARAM)&csA, result, arg );
2798             free_buffer( buffer, cls );
2799         }
2800         break;
2801
2802     case WM_GETTEXT:
2803     case WM_ASKCBFORMATNAME:
2804         {
2805             char *ptr, buffer[512];
2806             DWORD len = wParam * 2;
2807
2808             if (!(ptr = get_buffer( buffer, sizeof(buffer), len ))) break;
2809             ret = callback( hwnd, msg, wParam, (LPARAM)ptr, result, arg );
2810             if (*result && len)
2811             {
2812                 RtlMultiByteToUnicodeN( (LPWSTR)lParam, wParam*sizeof(WCHAR), &len, ptr, strlen(ptr)+1 );
2813                 *result = len/sizeof(WCHAR) - 1;  /* do not count terminating null */
2814                 ((LPWSTR)lParam)[*result] = 0;
2815             }
2816             free_buffer( buffer, ptr );
2817         }
2818         break;
2819
2820     case LB_ADDSTRING:
2821     case LB_INSERTSTRING:
2822     case LB_FINDSTRING:
2823     case LB_FINDSTRINGEXACT:
2824     case LB_SELECTSTRING:
2825     case CB_ADDSTRING:
2826     case CB_INSERTSTRING:
2827     case CB_FINDSTRING:
2828     case CB_FINDSTRINGEXACT:
2829     case CB_SELECTSTRING:
2830         if (!lParam || !WINPROC_TestLBForStr( hwnd, msg ))
2831         {
2832             ret = callback( hwnd, msg, wParam, lParam, result, arg );
2833             break;
2834         }
2835         /* fall through */
2836     case WM_SETTEXT:
2837     case WM_WININICHANGE:
2838     case WM_DEVMODECHANGE:
2839     case CB_DIR:
2840     case LB_DIR:
2841     case LB_ADDFILE:
2842     case EM_REPLACESEL:
2843         if (!lParam) ret = callback( hwnd, msg, wParam, lParam, result, arg );
2844         else
2845         {
2846             char *ptr, buffer[512];
2847             LPCWSTR strW = (LPCWSTR)lParam;
2848             DWORD lenA, lenW = (strlenW(strW) + 1) * sizeof(WCHAR);
2849
2850             RtlUnicodeToMultiByteSize( &lenA, strW, lenW );
2851             if ((ptr = get_buffer( buffer, sizeof(buffer), lenA )))
2852             {
2853                 RtlUnicodeToMultiByteN( ptr, lenA, NULL, strW, lenW );
2854                 ret = callback( hwnd, msg, wParam, (LPARAM)ptr, result, arg );
2855                 free_buffer( buffer, ptr );
2856             }
2857         }
2858         break;
2859
2860     case WM_MDICREATE:
2861         {
2862             char *ptr, buffer[1024];
2863             DWORD title_lenA = 0, title_lenW = 0, class_lenA = 0, class_lenW = 0;
2864             MDICREATESTRUCTW *csW = (MDICREATESTRUCTW *)lParam;
2865             MDICREATESTRUCTA csA;
2866
2867             memcpy( &csA, csW, sizeof(csA) );
2868
2869             if (HIWORD(csW->szTitle))
2870             {
2871                 title_lenW = (strlenW(csW->szTitle) + 1) * sizeof(WCHAR);
2872                 RtlUnicodeToMultiByteSize( &title_lenA, csW->szTitle, title_lenW );
2873             }
2874             if (HIWORD(csW->szClass))
2875             {
2876                 class_lenW = (strlenW(csW->szClass) + 1) * sizeof(WCHAR);
2877                 RtlUnicodeToMultiByteSize( &class_lenA, csW->szClass, class_lenW );
2878             }
2879
2880             if (!(ptr = get_buffer( buffer, sizeof(buffer), title_lenA + class_lenA ))) break;
2881
2882             if (title_lenA)
2883             {
2884                 RtlUnicodeToMultiByteN( ptr, title_lenA, NULL, csW->szTitle, title_lenW );
2885                 csA.szTitle = ptr;
2886             }
2887             if (class_lenA)
2888             {
2889                 RtlUnicodeToMultiByteN( ptr + title_lenA, class_lenA, NULL, csW->szClass, class_lenW );
2890                 csA.szClass = ptr + title_lenA;
2891             }
2892             ret = callback( hwnd, msg, wParam, (LPARAM)&csA, result, arg );
2893             free_buffer( buffer, ptr );
2894         }
2895         break;
2896
2897     case LB_GETTEXT:
2898     case CB_GETLBTEXT:
2899         if (lParam && WINPROC_TestLBForStr( hwnd, msg ))
2900         {
2901             char buffer[512];  /* FIXME: fixed sized buffer */
2902
2903             ret = callback( hwnd, msg, wParam, (LPARAM)buffer, result, arg );
2904             if (*result >= 0)
2905             {
2906                 DWORD len;
2907                 RtlMultiByteToUnicodeN( (LPWSTR)lParam, ~0u, &len, buffer, strlen(buffer) + 1 );
2908                 *result = len / sizeof(WCHAR) - 1;
2909             }
2910         }
2911         else ret = callback( hwnd, msg, wParam, lParam, result, arg );
2912         break;
2913
2914     case EM_GETLINE:
2915         {
2916             char *ptr, buffer[512];
2917             WORD len = *(WORD *)lParam;
2918
2919             if (!(ptr = get_buffer( buffer, sizeof(buffer), len * 2 ))) break;
2920             *((WORD *)ptr) = len * 2;   /* store the length */
2921             ret = callback( hwnd, msg, wParam, (LPARAM)ptr, result, arg );
2922             if (*result)
2923             {
2924                 DWORD reslen;
2925                 RtlMultiByteToUnicodeN( (LPWSTR)lParam, len*sizeof(WCHAR), &reslen, ptr, *result );
2926                 *result = reslen / sizeof(WCHAR);
2927                 if (*result < len) ((LPWSTR)lParam)[*result] = 0;
2928             }
2929             free_buffer( buffer, ptr );
2930         }
2931         break;
2932
2933     case WM_CHARTOITEM:
2934     case WM_MENUCHAR:
2935     case WM_CHAR:
2936     case WM_DEADCHAR:
2937     case WM_SYSCHAR:
2938     case WM_SYSDEADCHAR:
2939     case EM_SETPASSWORDCHAR:
2940         ret = callback( hwnd, msg, map_wparam_char_WtoA(wParam,1), lParam, result, arg );
2941         break;
2942
2943     case WM_IME_CHAR:
2944         ret = callback( hwnd, msg, map_wparam_char_WtoA(wParam,2), lParam, result, arg );
2945         break;
2946
2947     case WM_PAINTCLIPBOARD:
2948     case WM_SIZECLIPBOARD:
2949         FIXME_(msg)( "message %s (%04x) needs translation, please report\n",
2950                      SPY_GetMsgName(msg, hwnd), msg );
2951         break;
2952
2953     default:
2954         ret = callback( hwnd, msg, wParam, lParam, result, arg );
2955         break;
2956     }
2957
2958     return ret;
2959 }
2960
2961
2962 /**********************************************************************
2963  *           WINPROC_CallProc16To32A
2964  */
2965 LRESULT WINPROC_CallProc16To32A( winproc_callback_t callback, HWND16 hwnd, UINT16 msg,
2966                                  WPARAM16 wParam, LPARAM lParam, LRESULT *result, void *arg )
2967 {
2968     LRESULT ret;
2969     UINT msg32;
2970     WPARAM wParam32;
2971     HWND hwnd32 = WIN_Handle32( hwnd );
2972
2973     TRACE_(msg)("(hwnd=%p,msg=%s,wp=%08x,lp=%08lx)\n",
2974                  hwnd32, SPY_GetMsgName(msg, hwnd32), wParam, lParam);
2975
2976     if (WINPROC_MapMsg16To32A( hwnd32, msg, wParam, &msg32, &wParam32, &lParam ) == -1)
2977         return 0;
2978
2979     ret = callback( hwnd32, msg32, wParam32, lParam, result, arg );
2980     *result = WINPROC_UnmapMsg16To32A( hwnd32, msg32, wParam32, lParam, *result );
2981     return ret;
2982 }
2983
2984
2985 /**********************************************************************
2986  *           WINPROC_CallProc16To32W
2987  */
2988 static LRESULT WINPROC_CallProc16To32W( winproc_callback_t callback, HWND16 hwnd, UINT16 msg,
2989                                         WPARAM16 wParam, LPARAM lParam, LRESULT *result, void *arg )
2990 {
2991     LRESULT ret;
2992     UINT msg32;
2993     WPARAM wParam32;
2994     HWND hwnd32 = WIN_Handle32( hwnd );
2995
2996     TRACE_(msg)("(hwnd=%p,msg=%s,wp=%08x,lp=%08lx)\n",
2997                  hwnd32, SPY_GetMsgName(msg, hwnd32), wParam, lParam);
2998
2999     if (WINPROC_MapMsg16To32W( hwnd32, msg, wParam, &msg32, &wParam32, &lParam ) == -1)
3000         return 0;
3001
3002     ret = callback( hwnd32, msg32, wParam32, lParam, result, arg );
3003     *result = WINPROC_UnmapMsg16To32W( hwnd32, msg32, wParam32, lParam, *result,
3004                                        (callback == call_window_proc) ? arg : NULL  /*FIXME: hack*/ );
3005     return ret;
3006 }
3007
3008
3009 /**********************************************************************
3010  *           __wine_call_wndproc   (USER.1010)
3011  */
3012 LRESULT WINAPI __wine_call_wndproc( HWND16 hwnd, UINT16 msg, WPARAM16 wParam, LPARAM lParam,
3013                                     WINDOWPROC *proc )
3014 {
3015     LRESULT result;
3016
3017     if (proc->procA)
3018         WINPROC_CallProc16To32A( call_window_proc, hwnd, msg, wParam, lParam, &result, proc->procA );
3019     else
3020         WINPROC_CallProc16To32W( call_window_proc, hwnd, msg, wParam, lParam, &result, proc->procW );
3021     return result;
3022 }
3023
3024
3025 /**********************************************************************
3026  *           WINPROC_CallProc32ATo16
3027  *
3028  * Call a 16-bit window procedure, translating the 32-bit args.
3029  */
3030 LRESULT WINPROC_CallProc32ATo16( winproc_callback16_t callback, HWND hwnd, UINT msg,
3031                                  WPARAM wParam, LPARAM lParam, LRESULT *result, void *arg )
3032 {
3033     LRESULT ret;
3034     UINT16 msg16;
3035     WPARAM16 wParam16;
3036     LPARAM lParam16;
3037
3038     TRACE_(msg)("(hwnd=%p,msg=%s,wp=%08x,lp=%08lx)\n",
3039                 hwnd, SPY_GetMsgName(msg, hwnd), wParam, lParam);
3040
3041     lParam16 = lParam;
3042     if (WINPROC_MapMsg32ATo16( hwnd, msg, wParam, &msg16, &wParam16, &lParam16 ) == -1)
3043         return 0;
3044     ret = callback( HWND_16(hwnd), msg16, wParam16, lParam16, result, arg );
3045     WINPROC_UnmapMsg32ATo16( hwnd, msg, wParam, lParam, wParam16, lParam16, result );
3046     return ret;
3047 }
3048
3049
3050 /**********************************************************************
3051  *           WINPROC_CallProc32WTo16
3052  *
3053  * Call a 16-bit window procedure, translating the 32-bit args.
3054  */
3055 static LRESULT WINPROC_CallProc32WTo16( winproc_callback16_t callback, HWND hwnd, UINT msg,
3056                                         WPARAM wParam, LPARAM lParam, LRESULT *result, void *arg )
3057 {
3058     LRESULT ret;
3059     UINT16 msg16;
3060     WPARAM16 wParam16;
3061     LPARAM lParam16;
3062
3063     TRACE_(msg)("(hwnd=%p,msg=%s,wp=%08x,lp=%08lx)\n",
3064                 hwnd, SPY_GetMsgName(msg, hwnd), wParam, lParam);
3065
3066     lParam16 = lParam;
3067     if (WINPROC_MapMsg32WTo16( hwnd, msg, wParam, &msg16, &wParam16, &lParam16 ) == -1)
3068         return 0;
3069     ret = callback( HWND_16(hwnd), msg16, wParam16, lParam16, result, arg );
3070     WINPROC_UnmapMsg32WTo16( hwnd, msg, wParam, lParam, wParam16, lParam16, result );
3071     return ret;
3072 }
3073
3074
3075 /**********************************************************************
3076  *              CallWindowProc (USER.122)
3077  */
3078 LRESULT WINAPI CallWindowProc16( WNDPROC16 func, HWND16 hwnd, UINT16 msg,
3079                                  WPARAM16 wParam, LPARAM lParam )
3080 {
3081     WINDOWPROC *proc;
3082     LRESULT result;
3083
3084     if (!func) return 0;
3085
3086     if (!(proc = handle16_to_proc( func )))
3087         call_window_proc16( hwnd, msg, wParam, lParam, &result, func );
3088     else if (proc->procA)
3089         WINPROC_CallProc16To32A( call_window_proc, hwnd, msg, wParam, lParam, &result, proc->procA );
3090     else if (proc->procW)
3091         WINPROC_CallProc16To32W( call_window_proc, hwnd, msg, wParam, lParam, &result, proc->procW );
3092     else
3093         call_window_proc16( hwnd, msg, wParam, lParam, &result, proc->proc16 );
3094
3095     return result;
3096 }
3097
3098
3099 /**********************************************************************
3100  *              CallWindowProcA (USER32.@)
3101  *
3102  * The CallWindowProc() function invokes the windows procedure _func_,
3103  * with _hwnd_ as the target window, the message specified by _msg_, and
3104  * the message parameters _wParam_ and _lParam_.
3105  *
3106  * Some kinds of argument conversion may be done, I'm not sure what.
3107  *
3108  * CallWindowProc() may be used for windows subclassing. Use
3109  * SetWindowLong() to set a new windows procedure for windows of the
3110  * subclass, and handle subclassed messages in the new windows
3111  * procedure. The new windows procedure may then use CallWindowProc()
3112  * with _func_ set to the parent class's windows procedure to dispatch
3113  * the message to the superclass.
3114  *
3115  * RETURNS
3116  *
3117  *    The return value is message dependent.
3118  *
3119  * CONFORMANCE
3120  *
3121  *   ECMA-234, Win32
3122  */
3123 LRESULT WINAPI CallWindowProcA(
3124     WNDPROC func,  /* [in] window procedure */
3125     HWND hwnd,     /* [in] target window */
3126     UINT msg,      /* [in] message */
3127     WPARAM wParam, /* [in] message dependent parameter */
3128     LPARAM lParam  /* [in] message dependent parameter */
3129 ) {
3130     WINDOWPROC *proc;
3131     LRESULT result;
3132
3133     if (!func) return 0;
3134
3135     if (!(proc = handle_to_proc( func )))
3136         call_window_proc( hwnd, msg, wParam, lParam, &result, func );
3137     else if (proc->procA)
3138         call_window_proc( hwnd, msg, wParam, lParam, &result, proc->procA );
3139     else if (proc->procW)
3140         WINPROC_CallProcAtoW( call_window_proc, hwnd, msg, wParam, lParam, &result, proc->procW );
3141     else
3142         WINPROC_CallProc32ATo16( call_window_proc16, hwnd, msg, wParam, lParam, &result, proc->proc16 );
3143     return result;
3144 }
3145
3146
3147 /**********************************************************************
3148  *              CallWindowProcW (USER32.@)
3149  *
3150  * See CallWindowProcA.
3151  */
3152 LRESULT WINAPI CallWindowProcW( WNDPROC func, HWND hwnd, UINT msg,
3153                                   WPARAM wParam, LPARAM lParam )
3154 {
3155     WINDOWPROC *proc;
3156     LRESULT result;
3157
3158     if (!func) return 0;
3159
3160     if (!(proc = handle_to_proc( func )))
3161         call_window_proc( hwnd, msg, wParam, lParam, &result, func );
3162     else if (proc->procW)
3163         call_window_proc( hwnd, msg, wParam, lParam, &result, proc->procW );
3164     else if (proc->procA)
3165         WINPROC_CallProcWtoA( call_window_proc, hwnd, msg, wParam, lParam, &result, proc->procA );
3166     else
3167         WINPROC_CallProc32WTo16( call_window_proc16, hwnd, msg, wParam, lParam, &result, proc->proc16 );
3168     return result;
3169 }
3170
3171
3172 /**********************************************************************
3173  *              WINPROC_CallDlgProc16
3174  */
3175 INT_PTR WINPROC_CallDlgProc16( DLGPROC16 func, HWND16 hwnd, UINT16 msg, WPARAM16 wParam, LPARAM lParam )
3176 {
3177     WINDOWPROC *proc;
3178     LRESULT result;
3179     INT_PTR ret;
3180
3181     if (!func) return 0;
3182
3183     if (!(proc = handle16_to_proc( (WNDPROC16)func )))
3184     {
3185         ret = call_dialog_proc16( hwnd, msg, wParam, lParam, &result, func );
3186     }
3187     else if (proc->procA)
3188     {
3189         ret = WINPROC_CallProc16To32A( call_dialog_proc, hwnd, msg, wParam, lParam,
3190                                        &result, proc->procA );
3191         SetWindowLongPtrW( WIN_Handle32(hwnd), DWLP_MSGRESULT, result );
3192     }
3193     else if (proc->procW)
3194     {
3195         ret = WINPROC_CallProc16To32W( call_dialog_proc, hwnd, msg, wParam, lParam,
3196                                        &result, proc->procW );
3197         SetWindowLongPtrW( WIN_Handle32(hwnd), DWLP_MSGRESULT, result );
3198     }
3199     else
3200     {
3201         ret = call_dialog_proc16( hwnd, msg, wParam, lParam, &result, proc->proc16 );
3202     }
3203     return ret;
3204 }
3205
3206
3207 /**********************************************************************
3208  *              WINPROC_CallDlgProcA
3209  */
3210 INT_PTR WINPROC_CallDlgProcA( DLGPROC func, HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam )
3211 {
3212     WINDOWPROC *proc;
3213     LRESULT result;
3214     INT_PTR ret;
3215
3216     if (!func) return 0;
3217
3218     if (!(proc = handle_to_proc( (WNDPROC)func )))
3219         ret = call_dialog_proc( hwnd, msg, wParam, lParam, &result, func );
3220     else if (proc->procA)
3221         ret = call_dialog_proc( hwnd, msg, wParam, lParam, &result, proc->procA );
3222     else if (proc->procW)
3223     {
3224         ret = WINPROC_CallProcAtoW( call_dialog_proc, hwnd, msg, wParam, lParam, &result, proc->procW );
3225         SetWindowLongPtrW( hwnd, DWLP_MSGRESULT, result );
3226     }
3227     else
3228     {
3229         ret = WINPROC_CallProc32ATo16( call_dialog_proc16, hwnd, msg, wParam, lParam, &result, proc->proc16 );
3230         SetWindowLongPtrW( hwnd, DWLP_MSGRESULT, result );
3231     }
3232     return ret;
3233 }
3234
3235
3236 /**********************************************************************
3237  *              WINPROC_CallDlgProcW
3238  */
3239 INT_PTR WINPROC_CallDlgProcW( DLGPROC func, HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam )
3240 {
3241     WINDOWPROC *proc;
3242     LRESULT result;
3243     INT_PTR ret;
3244
3245     if (!func) return 0;
3246
3247     if (!(proc = handle_to_proc( (WNDPROC)func )))
3248         ret = call_dialog_proc( hwnd, msg, wParam, lParam, &result, func );
3249     else if (proc->procW)
3250         ret = call_dialog_proc( hwnd, msg, wParam, lParam, &result, proc->procW );
3251     else if (proc->procA)
3252     {
3253         ret = WINPROC_CallProcWtoA( call_dialog_proc, hwnd, msg, wParam, lParam, &result, proc->procA );
3254         SetWindowLongPtrW( hwnd, DWLP_MSGRESULT, result );
3255     }
3256     else
3257     {
3258         ret = WINPROC_CallProc32WTo16( call_dialog_proc16, hwnd, msg, wParam, lParam, &result, proc->proc16 );
3259         SetWindowLongPtrW( hwnd, DWLP_MSGRESULT, result );
3260     }
3261     return ret;
3262 }