user: Added fast A->W mapping for LB_GETTEXT and CB_GETLBTEXT.
[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     case WM_GETTEXTLENGTH:
774     case CB_GETLBTEXTLEN:
775     case LB_GETTEXTLEN:
776         return 1;  /* need to map result */
777
778 /* Multiline edit */
779     case EM_GETLINE:
780         { WORD len = (WORD)*plparam;
781           LPARAM *ptr = HeapAlloc( GetProcessHeap(), 0, sizeof(LPARAM) + sizeof (WORD) + len*sizeof(WCHAR) );
782           if (!ptr) return -1;
783           *ptr++ = *plparam;  /* Store previous lParam */
784           *((WORD *) ptr) = len;   /* Store the length */
785           *plparam = (LPARAM)ptr;
786         }
787         return 1;
788
789     case WM_CHARTOITEM:
790     case WM_MENUCHAR:
791     case WM_CHAR:
792     case WM_DEADCHAR:
793     case WM_SYSCHAR:
794     case WM_SYSDEADCHAR:
795     case EM_SETPASSWORDCHAR:
796         *pwparam = map_wparam_char_AtoW( *pwparam, 1 );
797         return 0;
798
799     case WM_IME_CHAR:
800         *pwparam = map_wparam_char_AtoW( *pwparam, 2 );
801         return 0;
802
803     case WM_PAINTCLIPBOARD:
804     case WM_SIZECLIPBOARD:
805         FIXME_(msg)("message %s (0x%x) needs translation, please report\n", SPY_GetMsgName(msg, hwnd), msg );
806         return -1;
807     default:  /* No translation needed */
808         return 0;
809     }
810 }
811
812
813 /**********************************************************************
814  *           WINPROC_UnmapMsg32ATo32W
815  *
816  * Unmap a message that was mapped from Ansi to Unicode.
817  */
818 static LRESULT WINPROC_UnmapMsg32ATo32W( HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam,
819                                          LRESULT result, WNDPROC dispatch )
820 {
821     switch(msg)
822     {
823     case WM_GETTEXT:
824     case WM_ASKCBFORMATNAME:
825         {
826             LPARAM *ptr = (LPARAM *)lParam - 1;
827             if (!wParam) result = 0;
828             else if (!(result = WideCharToMultiByte( CP_ACP, 0, (LPWSTR)lParam, -1,
829                                                     (LPSTR)*ptr, wParam, NULL, NULL )))
830             {
831                 ((LPSTR)*ptr)[wParam-1] = 0;
832                 result = wParam - 1;
833             }
834             else result--;  /* do not count terminating null */
835             HeapFree( GetProcessHeap(), 0, ptr );
836         }
837         break;
838     case WM_GETTEXTLENGTH:
839     case CB_GETLBTEXTLEN:
840     case LB_GETTEXTLEN:
841         if (result >= 0)
842         {
843             /* Determine respective GETTEXT message */
844             UINT msgGetText =
845               (msg == WM_GETTEXTLENGTH) ? WM_GETTEXT :
846               ((msg == CB_GETLBTEXTLEN) ? CB_GETLBTEXT : LB_GETTEXT);
847             /* wParam differs between the messages */
848             WPARAM wp = (msg == WM_GETTEXTLENGTH) ? (WPARAM)(result + 1) : wParam;
849
850             WCHAR* p = HeapAlloc (GetProcessHeap(), 0, (result + 1) * sizeof(WCHAR));
851
852             if (p)
853             {
854                 LRESULT n;
855
856                 if (dispatch)
857                     n = WINPROC_CallWndProc(dispatch, hwnd, msgGetText, wp, (LPARAM)p);
858                 else
859                     n = SendMessageW (hwnd, msgGetText, wp, (LPARAM)p);
860
861                 result = WideCharToMultiByte( CP_ACP, 0, p, n, NULL, 0, 0, NULL );
862                 HeapFree (GetProcessHeap(), 0, p);
863             }
864         }
865         break;
866
867     case WM_SETTEXT:
868     case WM_WININICHANGE:
869     case WM_DEVMODECHANGE:
870     case CB_DIR:
871     case LB_DIR:
872     case LB_ADDFILE:
873     case EM_REPLACESEL:
874         HeapFree( GetProcessHeap(), 0, (void *)lParam );
875         break;
876
877 /* Multiline edit */
878     case EM_GETLINE:
879         {
880             LPARAM * ptr = (LPARAM *)lParam - 1;  /* get the old lParam */
881             WORD len = *(WORD *) lParam;
882             result = WideCharToMultiByte( CP_ACP, 0, (LPWSTR)lParam, result,
883                                           (LPSTR)*ptr, len, NULL, NULL );
884             if (result < len) ((LPSTR)*ptr)[result] = 0;
885             HeapFree( GetProcessHeap(), 0, ptr );
886         }
887         break;
888     }
889     return result;
890 }
891
892
893 static UINT convert_handle_16_to_32(HANDLE16 src, unsigned int flags)
894 {
895     HANDLE      dst;
896     UINT        sz = GlobalSize16(src);
897     LPSTR       ptr16, ptr32;
898
899     if (!(dst = GlobalAlloc(flags, sz)))
900         return 0;
901     ptr16 = GlobalLock16(src);
902     ptr32 = GlobalLock(dst);
903     if (ptr16 != NULL && ptr32 != NULL) memcpy(ptr32, ptr16, sz);
904     GlobalUnlock16(src);
905     GlobalUnlock(dst);
906
907     return (UINT)dst;
908 }
909
910 /**********************************************************************
911  *           WINPROC_MapMsg16To32A
912  *
913  * Map a message from 16- to 32-bit Ansi.
914  * Return value is -1 on error, 0 if OK, 1 if an UnmapMsg call is needed.
915  */
916 INT WINPROC_MapMsg16To32A( HWND hwnd, UINT16 msg16, WPARAM16 wParam16, UINT *pmsg32,
917                              WPARAM *pwparam32, LPARAM *plparam )
918 {
919     *pmsg32 = (UINT)msg16;
920     *pwparam32 = (WPARAM)wParam16;
921     switch(msg16)
922     {
923     case WM_ACTIVATE:
924     case WM_CHARTOITEM:
925     case WM_COMMAND:
926     case WM_VKEYTOITEM:
927         *pwparam32 = MAKEWPARAM( wParam16, HIWORD(*plparam) );
928         *plparam   = (LPARAM)WIN_Handle32( LOWORD(*plparam) );
929         return 0;
930     case WM_HSCROLL:
931     case WM_VSCROLL:
932         *pwparam32 = MAKEWPARAM( wParam16, LOWORD(*plparam) );
933         *plparam   = (LPARAM)WIN_Handle32( HIWORD(*plparam) );
934         return 0;
935     case WM_CTLCOLOR:
936         if ( HIWORD(*plparam) > CTLCOLOR_STATIC ) return -1;
937         *pmsg32    = WM_CTLCOLORMSGBOX + HIWORD(*plparam);
938         *pwparam32 = (WPARAM)HDC_32(wParam16);
939         *plparam   = (LPARAM)WIN_Handle32( LOWORD(*plparam) );
940         return 0;
941     case WM_COMPAREITEM:
942         {
943             COMPAREITEMSTRUCT16* cis16 = MapSL(*plparam);
944             COMPAREITEMSTRUCT *cis = HeapAlloc(GetProcessHeap(), 0, sizeof(*cis));
945             if (!cis) return -1;
946             cis->CtlType    = cis16->CtlType;
947             cis->CtlID      = cis16->CtlID;
948             cis->hwndItem   = WIN_Handle32( cis16->hwndItem );
949             cis->itemID1    = cis16->itemID1;
950             cis->itemData1  = cis16->itemData1;
951             cis->itemID2    = cis16->itemID2;
952             cis->itemData2  = cis16->itemData2;
953             cis->dwLocaleId = 0;  /* FIXME */
954             *plparam = (LPARAM)cis;
955         }
956         return 1;
957     case WM_COPYDATA:
958         {
959             PCOPYDATASTRUCT16 pcds16 =  MapSL(*plparam);
960             PCOPYDATASTRUCT pcds = HeapAlloc ( GetProcessHeap(), 0, sizeof(*pcds));
961             pcds->dwData = pcds16->dwData;
962             pcds->cbData = pcds16->cbData;
963             pcds->lpData = MapSL( pcds16->lpData);
964             *plparam = (LPARAM)pcds;
965         }
966         return 1;
967     case WM_DELETEITEM:
968         {
969             DELETEITEMSTRUCT16* dis16 = MapSL(*plparam);
970             DELETEITEMSTRUCT *dis = HeapAlloc(GetProcessHeap(), 0, sizeof(*dis));
971             if (!dis) return -1;
972             dis->CtlType  = dis16->CtlType;
973             dis->CtlID    = dis16->CtlID;
974             dis->hwndItem = WIN_Handle32( dis16->hwndItem );
975             dis->itemData = dis16->itemData;
976             *plparam = (LPARAM)dis;
977         }
978         return 1;
979     case WM_MEASUREITEM:
980         {
981             MEASUREITEMSTRUCT16* mis16 = MapSL(*plparam);
982             MEASUREITEMSTRUCT *mis = HeapAlloc(GetProcessHeap(), 0,
983                                                 sizeof(*mis) + sizeof(LPARAM));
984             if (!mis) return -1;
985             mis->CtlType    = mis16->CtlType;
986             mis->CtlID      = mis16->CtlID;
987             mis->itemID     = mis16->itemID;
988             mis->itemWidth  = mis16->itemWidth;
989             mis->itemHeight = mis16->itemHeight;
990             mis->itemData   = mis16->itemData;
991             *(LPARAM *)(mis + 1) = *plparam;  /* Store the previous lParam */
992             *plparam = (LPARAM)mis;
993         }
994         return 1;
995     case WM_DRAWITEM:
996         {
997             DRAWITEMSTRUCT16* dis16 = MapSL(*plparam);
998             DRAWITEMSTRUCT *dis = HeapAlloc(GetProcessHeap(), 0, sizeof(*dis));
999             if (!dis) return -1;
1000             dis->CtlType       = dis16->CtlType;
1001             dis->CtlID         = dis16->CtlID;
1002             dis->itemID        = dis16->itemID;
1003             dis->itemAction    = dis16->itemAction;
1004             dis->itemState     = dis16->itemState;
1005             dis->hwndItem      = (dis->CtlType == ODT_MENU) ? (HWND)HMENU_32(dis16->hwndItem)
1006                                                             : WIN_Handle32( dis16->hwndItem );
1007             dis->hDC           = HDC_32(dis16->hDC);
1008             dis->itemData      = dis16->itemData;
1009             dis->rcItem.left   = dis16->rcItem.left;
1010             dis->rcItem.top    = dis16->rcItem.top;
1011             dis->rcItem.right  = dis16->rcItem.right;
1012             dis->rcItem.bottom = dis16->rcItem.bottom;
1013             *plparam = (LPARAM)dis;
1014         }
1015         return 1;
1016     case WM_GETMINMAXINFO:
1017         {
1018             MINMAXINFO *mmi = HeapAlloc( GetProcessHeap(), 0, sizeof(*mmi) + sizeof(LPARAM));
1019             if (!mmi) return -1;
1020             MINMAXINFO16to32( MapSL(*plparam), mmi );
1021             *(LPARAM *)(mmi + 1) = *plparam;  /* Store the previous lParam */
1022             *plparam = (LPARAM)mmi;
1023         }
1024         return 1;
1025     case WM_GETTEXT:
1026     case WM_SETTEXT:
1027     case WM_WININICHANGE:
1028     case WM_DEVMODECHANGE:
1029     case WM_ASKCBFORMATNAME:
1030         *plparam = (LPARAM)MapSL(*plparam);
1031         return 0;
1032     case WM_MDICREATE:
1033         {
1034             MDICREATESTRUCT16 *cs16 = MapSL(*plparam);
1035             MDICREATESTRUCTA *cs = HeapAlloc( GetProcessHeap(), 0, sizeof(*cs) + sizeof(LPARAM) );
1036             if (!cs) return -1;
1037             MDICREATESTRUCT16to32A( cs16, cs );
1038             cs->szTitle = MapSL(cs16->szTitle);
1039             cs->szClass = MapSL(cs16->szClass);
1040             *(LPARAM *)(cs + 1) = *plparam;  /* Store the previous lParam */
1041             *plparam = (LPARAM)cs;
1042         }
1043         return 1;
1044     case WM_MDIGETACTIVE:
1045         *plparam = (LPARAM)HeapAlloc( GetProcessHeap(), 0, sizeof(BOOL) );
1046         *(BOOL*)(*plparam) = 0;
1047         return 1;
1048     case WM_MDISETMENU:
1049         if(wParam16) *pmsg32=WM_MDIREFRESHMENU;
1050         *pwparam32 = (WPARAM)HMENU_32(LOWORD(*plparam));
1051         *plparam   = (LPARAM)HMENU_32(HIWORD(*plparam));
1052         return 0;
1053     case WM_MENUCHAR:
1054         *pwparam32 = MAKEWPARAM( wParam16, LOWORD(*plparam) );
1055         *plparam   = (LPARAM)HMENU_32(HIWORD(*plparam));
1056         return 0;
1057     case WM_MENUSELECT:
1058         if((LOWORD(*plparam) & MF_POPUP) && (LOWORD(*plparam) != 0xFFFF))
1059         {
1060             HMENU hmenu=HMENU_32(HIWORD(*plparam));
1061             UINT Pos=MENU_FindSubMenu( &hmenu, HMENU_32(wParam16));
1062             if(Pos==0xFFFF) Pos=0; /* NO_SELECTED_ITEM */
1063             *pwparam32 = MAKEWPARAM( Pos, LOWORD(*plparam) );
1064         }
1065         else *pwparam32 = MAKEWPARAM( wParam16, LOWORD(*plparam) );
1066         *plparam   = (LPARAM)HMENU_32(HIWORD(*plparam));
1067         return 0;
1068     case WM_MDIACTIVATE:
1069         if( *plparam )
1070         {
1071             *pwparam32 = (WPARAM)WIN_Handle32( HIWORD(*plparam) );
1072             *plparam   = (LPARAM)WIN_Handle32( LOWORD(*plparam) );
1073         }
1074         else /* message sent to MDI client */
1075             *pwparam32 = wParam16;
1076         return 0;
1077     case WM_NCCALCSIZE:
1078         {
1079             NCCALCSIZE_PARAMS16 *nc16;
1080             NCCALCSIZE_PARAMS *nc;
1081
1082             nc = HeapAlloc( GetProcessHeap(), 0, sizeof(*nc) + sizeof(LPARAM) );
1083             if (!nc) return -1;
1084             nc16 = MapSL(*plparam);
1085             nc->rgrc[0].left   = nc16->rgrc[0].left;
1086             nc->rgrc[0].top    = nc16->rgrc[0].top;
1087             nc->rgrc[0].right  = nc16->rgrc[0].right;
1088             nc->rgrc[0].bottom = nc16->rgrc[0].bottom;
1089             if (wParam16)
1090             {
1091                 nc->lppos = HeapAlloc( GetProcessHeap(), 0, sizeof(*nc->lppos) );
1092                 nc->rgrc[1].left   = nc16->rgrc[1].left;
1093                 nc->rgrc[1].top    = nc16->rgrc[1].top;
1094                 nc->rgrc[1].right  = nc16->rgrc[1].right;
1095                 nc->rgrc[1].bottom = nc16->rgrc[1].bottom;
1096                 nc->rgrc[2].left   = nc16->rgrc[2].left;
1097                 nc->rgrc[2].top    = nc16->rgrc[2].top;
1098                 nc->rgrc[2].right  = nc16->rgrc[2].right;
1099                 nc->rgrc[2].bottom = nc16->rgrc[2].bottom;
1100                 if (nc->lppos) WINDOWPOS16to32( MapSL(nc16->lppos), nc->lppos );
1101             }
1102             *(LPARAM *)(nc + 1) = *plparam;  /* Store the previous lParam */
1103             *plparam = (LPARAM)nc;
1104         }
1105         return 1;
1106     case WM_NCCREATE:
1107     case WM_CREATE:
1108         {
1109             CREATESTRUCT16 *cs16 = MapSL(*plparam);
1110             CREATESTRUCTA *cs = HeapAlloc( GetProcessHeap(), 0, sizeof(*cs) + sizeof(LPARAM) );
1111             if (!cs) return -1;
1112             CREATESTRUCT16to32A( cs16, cs );
1113             cs->lpszName  = MapSL(cs16->lpszName);
1114             cs->lpszClass = MapSL(cs16->lpszClass);
1115
1116             if (GetWindowLongW(hwnd, GWL_EXSTYLE) & WS_EX_MDICHILD)
1117             {
1118                 MDICREATESTRUCT16 *mdi_cs16;
1119                 MDICREATESTRUCTA *mdi_cs = HeapAlloc(GetProcessHeap(), 0, sizeof(*mdi_cs));
1120                 if (!mdi_cs)
1121                 {
1122                     HeapFree(GetProcessHeap(), 0, cs);
1123                     return -1;
1124                 }
1125                 mdi_cs16 = (MDICREATESTRUCT16 *)MapSL(cs16->lpCreateParams);
1126                 MDICREATESTRUCT16to32A(mdi_cs16, mdi_cs);
1127                 mdi_cs->szTitle = MapSL(mdi_cs16->szTitle);
1128                 mdi_cs->szClass = MapSL(mdi_cs16->szClass);
1129
1130                 cs->lpCreateParams = mdi_cs;
1131             }
1132             *(LPARAM *)(cs + 1) = *plparam;  /* Store the previous lParam */
1133             *plparam = (LPARAM)cs;
1134         }
1135         return 1;
1136     case WM_PARENTNOTIFY:
1137         if ((wParam16 == WM_CREATE) || (wParam16 == WM_DESTROY))
1138         {
1139             *pwparam32 = MAKEWPARAM( wParam16, HIWORD(*plparam) );
1140             *plparam   = (LPARAM)WIN_Handle32( LOWORD(*plparam) );
1141         }
1142         return 0;
1143     case WM_WINDOWPOSCHANGING:
1144     case WM_WINDOWPOSCHANGED:
1145         {
1146             WINDOWPOS *wp = HeapAlloc( GetProcessHeap(), 0, sizeof(*wp) + sizeof(LPARAM) );
1147             if (!wp) return -1;
1148             WINDOWPOS16to32( MapSL(*plparam), wp );
1149             *(LPARAM *)(wp + 1) = *plparam;  /* Store the previous lParam */
1150             *plparam = (LPARAM)wp;
1151         }
1152         return 1;
1153     case WM_GETDLGCODE:
1154         if (*plparam)
1155         {
1156             LPMSG16 msg16 = MapSL(*plparam);
1157             LPMSG msg32 = HeapAlloc( GetProcessHeap(), 0, sizeof(MSG) );
1158
1159             if (!msg32) return -1;
1160             msg32->hwnd = WIN_Handle32( msg16->hwnd );
1161             msg32->message = msg16->message;
1162             msg32->wParam = msg16->wParam;
1163             msg32->lParam = msg16->lParam;
1164             msg32->time = msg16->time;
1165             msg32->pt.x = msg16->pt.x;
1166             msg32->pt.y = msg16->pt.y;
1167             *plparam = (LPARAM)msg32;
1168             return 1;
1169         }
1170         else return 0;
1171     case WM_NOTIFY:
1172         *plparam = (LPARAM)MapSL(*plparam);
1173         return 0;
1174     case WM_ACTIVATEAPP:
1175         /* We need this when SetActiveWindow sends a Sendmessage16() to
1176          * a 32bit window. Might be superflous with 32bit interprocess
1177          * message queues. */
1178         if (*plparam) *plparam = HTASK_32( *plparam );
1179         return 0;
1180     case WM_NEXTMENU:
1181         {
1182             MDINEXTMENU *next = HeapAlloc( GetProcessHeap(), 0, sizeof(*next) );
1183             if (!next) return -1;
1184             next->hmenuIn = (HMENU)*plparam;
1185             next->hmenuNext = 0;
1186             next->hwndNext = 0;
1187             *plparam = (LPARAM)next;
1188             return 1;
1189         }
1190     case WM_PAINTCLIPBOARD:
1191     case WM_SIZECLIPBOARD:
1192         FIXME_(msg)("message %04x needs translation\n",msg16 );
1193         return -1;
1194     case WM_DDE_INITIATE:
1195     case WM_DDE_TERMINATE:
1196     case WM_DDE_UNADVISE:
1197     case WM_DDE_REQUEST:
1198         *pwparam32 = (WPARAM)WIN_Handle32(wParam16);
1199         return 0;
1200     case WM_DDE_ADVISE:
1201     case WM_DDE_DATA:
1202     case WM_DDE_POKE:
1203         {
1204             HANDLE16    lo16;
1205             ATOM        hi;
1206             UINT lo32 = 0;
1207
1208             *pwparam32 = (WPARAM)WIN_Handle32(wParam16);
1209             lo16 = LOWORD(*plparam);
1210             hi = HIWORD(*plparam);
1211             if (lo16 && !(lo32 = convert_handle_16_to_32(lo16, GMEM_DDESHARE)))
1212                 return -1;
1213             *plparam = PackDDElParam(msg16, lo32, hi);
1214         }
1215         return 0; /* FIXME don't know how to free allocated memory (handle)  !! */
1216     case WM_DDE_ACK:
1217         {
1218             UINT        lo, hi;
1219             int         flag = 0;
1220             char        buf[2];
1221
1222             *pwparam32 = (WPARAM)WIN_Handle32(wParam16);
1223
1224             lo = LOWORD(*plparam);
1225             hi = HIWORD(*plparam);
1226
1227             if (GlobalGetAtomNameA(hi, buf, 2) > 0) flag |= 1;
1228             if (GlobalSize16(hi) != 0) flag |= 2;
1229             switch (flag)
1230             {
1231             case 0:
1232                 if (hi)
1233                 {
1234                     MESSAGE("DDE_ACK: neither atom nor handle!!!\n");
1235                     hi = 0;
1236                 }
1237                 break;
1238             case 1:
1239                 break; /* atom, nothing to do */
1240             case 3:
1241                 MESSAGE("DDE_ACK: %x both atom and handle... choosing handle\n", hi);
1242                 /* fall thru */
1243             case 2:
1244                 hi = convert_handle_16_to_32(hi, GMEM_DDESHARE);
1245                 break;
1246             }
1247             *plparam = PackDDElParam(WM_DDE_ACK, lo, hi);
1248         }
1249         return 0; /* FIXME don't know how to free allocated memory (handle) !! */
1250     case WM_DDE_EXECUTE:
1251         *plparam = convert_handle_16_to_32(*plparam, GMEM_DDESHARE);
1252         return 0; /* FIXME don't know how to free allocated memory (handle) !! */
1253     default:  /* No translation needed */
1254         return 0;
1255     }
1256 }
1257
1258
1259 /**********************************************************************
1260  *           WINPROC_UnmapMsg16To32A
1261  *
1262  * Unmap a message that was mapped from 16- to 32-bit Ansi.
1263  */
1264 static LRESULT WINPROC_UnmapMsg16To32A( HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam,
1265                                         LRESULT result )
1266 {
1267     switch(msg)
1268     {
1269     case WM_COMPAREITEM:
1270     case WM_DELETEITEM:
1271     case WM_DRAWITEM:
1272     case WM_COPYDATA:
1273         HeapFree( GetProcessHeap(), 0, (LPVOID)lParam );
1274         break;
1275     case WM_MEASUREITEM:
1276         {
1277             MEASUREITEMSTRUCT16 *mis16;
1278             MEASUREITEMSTRUCT *mis = (MEASUREITEMSTRUCT *)lParam;
1279             lParam = *(LPARAM *)(mis + 1);
1280             mis16 = MapSL(lParam);
1281             mis16->itemWidth  = (UINT16)mis->itemWidth;
1282             mis16->itemHeight = (UINT16)mis->itemHeight;
1283             HeapFree( GetProcessHeap(), 0, mis );
1284         }
1285         break;
1286     case WM_GETMINMAXINFO:
1287         {
1288             MINMAXINFO *mmi = (MINMAXINFO *)lParam;
1289             lParam = *(LPARAM *)(mmi + 1);
1290             MINMAXINFO32to16( mmi, MapSL(lParam));
1291             HeapFree( GetProcessHeap(), 0, mmi );
1292         }
1293         break;
1294     case WM_MDICREATE:
1295         {
1296             MDICREATESTRUCTA *cs = (MDICREATESTRUCTA *)lParam;
1297             lParam = *(LPARAM *)(cs + 1);
1298             MDICREATESTRUCT32Ato16( cs, MapSL(lParam) );
1299             HeapFree( GetProcessHeap(), 0, cs );
1300         }
1301         break;
1302     case WM_MDIGETACTIVE:
1303         result = MAKELONG( LOWORD(result), (BOOL16)(*(BOOL *)lParam) );
1304         HeapFree( GetProcessHeap(), 0, (BOOL *)lParam );
1305         break;
1306     case WM_NCCALCSIZE:
1307         {
1308             NCCALCSIZE_PARAMS16 *nc16;
1309             NCCALCSIZE_PARAMS *nc = (NCCALCSIZE_PARAMS *)lParam;
1310             lParam = *(LPARAM *)(nc + 1);
1311             nc16 = MapSL(lParam);
1312             nc16->rgrc[0].left   = nc->rgrc[0].left;
1313             nc16->rgrc[0].top    = nc->rgrc[0].top;
1314             nc16->rgrc[0].right  = nc->rgrc[0].right;
1315             nc16->rgrc[0].bottom = nc->rgrc[0].bottom;
1316             if (wParam)
1317             {
1318                 nc16->rgrc[1].left   = nc->rgrc[1].left;
1319                 nc16->rgrc[1].top    = nc->rgrc[1].top;
1320                 nc16->rgrc[1].right  = nc->rgrc[1].right;
1321                 nc16->rgrc[1].bottom = nc->rgrc[1].bottom;
1322                 nc16->rgrc[2].left   = nc->rgrc[2].left;
1323                 nc16->rgrc[2].top    = nc->rgrc[2].top;
1324                 nc16->rgrc[2].right  = nc->rgrc[2].right;
1325                 nc16->rgrc[2].bottom = nc->rgrc[2].bottom;
1326                 if (nc->lppos)
1327                 {
1328                     WINDOWPOS32to16( nc->lppos, MapSL(nc16->lppos));
1329                     HeapFree( GetProcessHeap(), 0, nc->lppos );
1330                 }
1331             }
1332             HeapFree( GetProcessHeap(), 0, nc );
1333         }
1334         break;
1335     case WM_NCCREATE:
1336     case WM_CREATE:
1337         {
1338             CREATESTRUCTA *cs = (CREATESTRUCTA *)lParam;
1339             lParam = *(LPARAM *)(cs + 1);
1340             CREATESTRUCT32Ato16( cs, MapSL(lParam) );
1341
1342             if (GetWindowLongW(hwnd, GWL_EXSTYLE) & WS_EX_MDICHILD)
1343                 HeapFree(GetProcessHeap(), 0, cs->lpCreateParams);
1344
1345             HeapFree( GetProcessHeap(), 0, cs );
1346         }
1347         break;
1348     case WM_WINDOWPOSCHANGING:
1349     case WM_WINDOWPOSCHANGED:
1350         {
1351             WINDOWPOS *wp = (WINDOWPOS *)lParam;
1352             lParam = *(LPARAM *)(wp + 1);
1353             WINDOWPOS32to16(wp, MapSL(lParam));
1354             HeapFree( GetProcessHeap(), 0, wp );
1355         }
1356         break;
1357     case WM_GETDLGCODE:
1358         if (lParam)
1359         {
1360             LPMSG msg32 = (LPMSG)lParam;
1361             HeapFree( GetProcessHeap(), 0, msg32 );
1362         }
1363         break;
1364     case WM_NEXTMENU:
1365         {
1366             MDINEXTMENU *next = (MDINEXTMENU *)lParam;
1367             result = MAKELONG( HMENU_16(next->hmenuNext), HWND_16(next->hwndNext) );
1368             HeapFree( GetProcessHeap(), 0, next );
1369         }
1370         break;
1371     }
1372     return result;
1373 }
1374
1375
1376 /**********************************************************************
1377  *           WINPROC_MapMsg16To32W
1378  *
1379  * Map a message from 16- to 32-bit Unicode.
1380  * Return value is -1 on error, 0 if OK, 1 if an UnmapMsg call is needed.
1381  */
1382 static INT WINPROC_MapMsg16To32W( HWND hwnd, UINT16 msg16, WPARAM16 wParam16, UINT *pmsg32,
1383                                   WPARAM *pwparam32, LPARAM *plparam )
1384 {
1385     *pmsg32=(UINT)msg16;
1386     *pwparam32 = (WPARAM)wParam16;
1387     switch(msg16)
1388     {
1389     case WM_GETTEXT:
1390     case WM_SETTEXT:
1391     case WM_WININICHANGE:
1392     case WM_DEVMODECHANGE:
1393     case WM_ASKCBFORMATNAME:
1394         *plparam = (LPARAM)MapSL(*plparam);
1395         return WINPROC_MapMsg32ATo32W( hwnd, *pmsg32, pwparam32, plparam );
1396     case WM_GETTEXTLENGTH:
1397     case CB_GETLBTEXTLEN:
1398     case LB_GETTEXTLEN:
1399         return 1;  /* need to map result */
1400     case WM_NCCREATE:
1401     case WM_CREATE:
1402         {
1403             CREATESTRUCT16 *cs16 = MapSL(*plparam);
1404             CREATESTRUCTW *cs = HeapAlloc( GetProcessHeap(), 0, sizeof(*cs) + sizeof(LPARAM) );
1405             if (!cs) return -1;
1406             CREATESTRUCT16to32A( cs16, (CREATESTRUCTA *)cs );
1407             cs->lpszName  = map_str_16_to_32W(cs16->lpszName);
1408             cs->lpszClass = map_str_16_to_32W(cs16->lpszClass);
1409
1410             if (GetWindowLongW(hwnd, GWL_EXSTYLE) & WS_EX_MDICHILD)
1411             {
1412                 MDICREATESTRUCT16 *mdi_cs16;
1413                 MDICREATESTRUCTW *mdi_cs = HeapAlloc(GetProcessHeap(), 0, sizeof(*mdi_cs));
1414                 if (!mdi_cs)
1415                 {
1416                     HeapFree(GetProcessHeap(), 0, cs);
1417                     return -1;
1418                 }
1419                 mdi_cs16 = (MDICREATESTRUCT16 *)MapSL(cs16->lpCreateParams);
1420                 MDICREATESTRUCT16to32A(mdi_cs16, (MDICREATESTRUCTA *)mdi_cs);
1421                 mdi_cs->szTitle = map_str_16_to_32W(mdi_cs16->szTitle);
1422                 mdi_cs->szClass = map_str_16_to_32W(mdi_cs16->szClass);
1423
1424                 cs->lpCreateParams = mdi_cs;
1425             }
1426             *(LPARAM *)(cs + 1) = *plparam;  /* Store the previous lParam */
1427             *plparam = (LPARAM)cs;
1428         }
1429         return 1;
1430     case WM_MDICREATE:
1431         {
1432             MDICREATESTRUCT16 *cs16 = MapSL(*plparam);
1433             MDICREATESTRUCTW *cs = HeapAlloc( GetProcessHeap(), 0, sizeof(*cs) + sizeof(LPARAM) );
1434             if (!cs) return -1;
1435             MDICREATESTRUCT16to32A( cs16, (MDICREATESTRUCTA *)cs );
1436             cs->szTitle = map_str_16_to_32W(cs16->szTitle);
1437             cs->szClass = map_str_16_to_32W(cs16->szClass);
1438             *(LPARAM *)(cs + 1) = *plparam;  /* Store the previous lParam */
1439             *plparam = (LPARAM)cs;
1440         }
1441         return 1;
1442     case WM_GETDLGCODE:
1443         if (*plparam)
1444         {
1445             LPMSG16 msg16 = MapSL(*plparam);
1446             LPMSG msg32 = HeapAlloc( GetProcessHeap(), 0, sizeof(MSG) );
1447
1448             if (!msg32) return -1;
1449             msg32->hwnd = WIN_Handle32( msg16->hwnd );
1450             msg32->message = msg16->message;
1451             msg32->wParam = msg16->wParam;
1452             msg32->lParam = msg16->lParam;
1453             msg32->time = msg16->time;
1454             msg32->pt.x = msg16->pt.x;
1455             msg32->pt.y = msg16->pt.y;
1456             switch(msg32->message)
1457             {
1458             case WM_CHAR:
1459             case WM_DEADCHAR:
1460             case WM_SYSCHAR:
1461             case WM_SYSDEADCHAR:
1462                 msg32->wParam = map_wparam_char_AtoW( msg16->wParam, 1 );
1463                 break;
1464             }
1465             *plparam = (LPARAM)msg32;
1466             return 1;
1467         }
1468         else return 0;
1469
1470     case WM_CHARTOITEM:
1471         *pwparam32 = MAKEWPARAM( map_wparam_char_AtoW( wParam16, 1 ), HIWORD(*plparam) );
1472         *plparam   = (LPARAM)WIN_Handle32( LOWORD(*plparam) );
1473         return 0;
1474     case WM_MENUCHAR:
1475         *pwparam32 = MAKEWPARAM( map_wparam_char_AtoW( wParam16, 1 ), LOWORD(*plparam) );
1476         *plparam   = (LPARAM)HMENU_32(HIWORD(*plparam));
1477         return 0;
1478     case WM_CHAR:
1479     case WM_DEADCHAR:
1480     case WM_SYSCHAR:
1481     case WM_SYSDEADCHAR:
1482         *pwparam32 = map_wparam_char_AtoW( wParam16, 1 );
1483         return 0;
1484     case WM_IME_CHAR:
1485         *pwparam32 = map_wparam_char_AtoW( wParam16, 2 );
1486         return 0;
1487
1488     default:  /* No Unicode translation needed */
1489         return WINPROC_MapMsg16To32A( hwnd, msg16, wParam16, pmsg32,
1490                                       pwparam32, plparam );
1491     }
1492 }
1493
1494
1495 /**********************************************************************
1496  *           WINPROC_UnmapMsg16To32W
1497  *
1498  * Unmap a message that was mapped from 16- to 32-bit Unicode.
1499  */
1500 static LRESULT WINPROC_UnmapMsg16To32W( HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam,
1501                                         LRESULT result, WNDPROC dispatch )
1502 {
1503     switch(msg)
1504     {
1505     case WM_GETTEXT:
1506     case WM_SETTEXT:
1507     case WM_GETTEXTLENGTH:
1508     case CB_GETLBTEXTLEN:
1509     case LB_GETTEXTLEN:
1510     case WM_ASKCBFORMATNAME:
1511         return WINPROC_UnmapMsg32ATo32W( hwnd, msg, wParam, lParam, result, dispatch );
1512     case WM_NCCREATE:
1513     case WM_CREATE:
1514         {
1515             CREATESTRUCTW *cs = (CREATESTRUCTW *)lParam;
1516             lParam = *(LPARAM *)(cs + 1);
1517             CREATESTRUCT32Ato16( (CREATESTRUCTA *)cs, MapSL(lParam) );
1518             unmap_str_16_to_32W( cs->lpszName );
1519             unmap_str_16_to_32W( cs->lpszClass );
1520
1521             if (GetWindowLongW(hwnd, GWL_EXSTYLE) & WS_EX_MDICHILD)
1522             {
1523                 MDICREATESTRUCTW *mdi_cs = (MDICREATESTRUCTW *)cs->lpCreateParams;
1524                 unmap_str_16_to_32W( mdi_cs->szTitle );
1525                 unmap_str_16_to_32W( mdi_cs->szClass );
1526                 HeapFree(GetProcessHeap(), 0, cs->lpCreateParams);
1527             }
1528             HeapFree( GetProcessHeap(), 0, cs );
1529         }
1530         break;
1531     case WM_MDICREATE:
1532         {
1533             MDICREATESTRUCTW *cs = (MDICREATESTRUCTW *)lParam;
1534             lParam = *(LPARAM *)(cs + 1);
1535             MDICREATESTRUCT32Ato16( (MDICREATESTRUCTA *)cs, MapSL(lParam) );
1536             unmap_str_16_to_32W( cs->szTitle );
1537             unmap_str_16_to_32W( cs->szClass );
1538             HeapFree( GetProcessHeap(), 0, cs );
1539         }
1540         break;
1541     case WM_GETDLGCODE:
1542         if (lParam)
1543         {
1544             LPMSG msg32 = (LPMSG)lParam;
1545             HeapFree( GetProcessHeap(), 0, msg32 );
1546         }
1547         break;
1548     default:
1549         return WINPROC_UnmapMsg16To32A( hwnd, msg, wParam, lParam, result );
1550     }
1551     return result;
1552 }
1553
1554 static HANDLE16 convert_handle_32_to_16(UINT src, unsigned int flags)
1555 {
1556     HANDLE16    dst;
1557     UINT        sz = GlobalSize((HANDLE)src);
1558     LPSTR       ptr16, ptr32;
1559
1560     if (!(dst = GlobalAlloc16(flags, sz)))
1561         return 0;
1562     ptr32 = GlobalLock((HANDLE)src);
1563     ptr16 = GlobalLock16(dst);
1564     if (ptr16 != NULL && ptr32 != NULL) memcpy(ptr16, ptr32, sz);
1565     GlobalUnlock((HANDLE)src);
1566     GlobalUnlock16(dst);
1567
1568     return dst;
1569 }
1570
1571
1572 /**********************************************************************
1573  *           WINPROC_MapMsg32ATo16
1574  *
1575  * Map a message from 32-bit Ansi to 16-bit.
1576  * Return value is -1 on error, 0 if OK, 1 if an UnmapMsg call is needed.
1577  */
1578 INT WINPROC_MapMsg32ATo16( HWND hwnd, UINT msg32, WPARAM wParam32,
1579                              UINT16 *pmsg16, WPARAM16 *pwparam16,
1580                              LPARAM *plparam )
1581 {
1582     *pmsg16 = (UINT16)msg32;
1583     *pwparam16 = (WPARAM16)LOWORD(wParam32);
1584     switch(msg32)
1585     {
1586     case SBM_SETRANGE:
1587         *pmsg16 = SBM_SETRANGE16;
1588         *plparam = MAKELPARAM(wParam32, *plparam);
1589         *pwparam16 = 0;
1590         return 0;
1591
1592     case SBM_GETRANGE:
1593         *pmsg16 = SBM_GETRANGE16;
1594         return 1;
1595
1596     case BM_GETCHECK:
1597     case BM_SETCHECK:
1598     case BM_GETSTATE:
1599     case BM_SETSTATE:
1600     case BM_SETSTYLE:
1601         *pmsg16 = (UINT16)msg32 + (BM_GETCHECK16 - BM_GETCHECK);
1602         return 0;
1603
1604     case EM_GETSEL:
1605     case EM_GETRECT:
1606     case EM_SETRECT:
1607     case EM_SETRECTNP:
1608     case EM_SCROLL:
1609     case EM_LINESCROLL:
1610     case EM_SCROLLCARET:
1611     case EM_GETMODIFY:
1612     case EM_SETMODIFY:
1613     case EM_GETLINECOUNT:
1614     case EM_LINEINDEX:
1615     case EM_SETHANDLE:
1616     case EM_GETHANDLE:
1617     case EM_GETTHUMB:
1618     case EM_LINELENGTH:
1619     case EM_REPLACESEL:
1620     case EM_GETLINE:
1621     case EM_LIMITTEXT:
1622     case EM_CANUNDO:
1623     case EM_UNDO:
1624     case EM_FMTLINES:
1625     case EM_LINEFROMCHAR:
1626     case EM_SETTABSTOPS:
1627     case EM_SETPASSWORDCHAR:
1628     case EM_EMPTYUNDOBUFFER:
1629     case EM_GETFIRSTVISIBLELINE:
1630     case EM_SETREADONLY:
1631     case EM_SETWORDBREAKPROC:
1632     case EM_GETWORDBREAKPROC:
1633     case EM_GETPASSWORDCHAR:
1634         *pmsg16 = (UINT16)msg32 + (EM_GETSEL16 - EM_GETSEL);
1635         return 0;
1636
1637     case LB_CARETOFF:
1638     case LB_CARETON:
1639     case LB_DELETESTRING:
1640     case LB_GETANCHORINDEX:
1641     case LB_GETCARETINDEX:
1642     case LB_GETCOUNT:
1643     case LB_GETCURSEL:
1644     case LB_GETHORIZONTALEXTENT:
1645     case LB_GETITEMDATA:
1646     case LB_GETITEMHEIGHT:
1647     case LB_GETSEL:
1648     case LB_GETSELCOUNT:
1649     case LB_GETTEXTLEN:
1650     case LB_GETTOPINDEX:
1651     case LB_RESETCONTENT:
1652     case LB_SELITEMRANGE:
1653     case LB_SELITEMRANGEEX:
1654     case LB_SETANCHORINDEX:
1655     case LB_SETCARETINDEX:
1656     case LB_SETCOLUMNWIDTH:
1657     case LB_SETCURSEL:
1658     case LB_SETHORIZONTALEXTENT:
1659     case LB_SETITEMDATA:
1660     case LB_SETITEMHEIGHT:
1661     case LB_SETSEL:
1662     case LB_SETTOPINDEX:
1663         *pmsg16 = (UINT16)msg32 + (LB_ADDSTRING16 - LB_ADDSTRING);
1664         return 0;
1665     case CB_DELETESTRING:
1666     case CB_GETCOUNT:
1667     case CB_GETLBTEXTLEN:
1668     case CB_LIMITTEXT:
1669     case CB_RESETCONTENT:
1670     case CB_SETEDITSEL:
1671     case CB_GETCURSEL:
1672     case CB_SETCURSEL:
1673     case CB_SHOWDROPDOWN:
1674     case CB_SETITEMDATA:
1675     case CB_SETITEMHEIGHT:
1676     case CB_GETITEMHEIGHT:
1677     case CB_SETEXTENDEDUI:
1678     case CB_GETEXTENDEDUI:
1679     case CB_GETDROPPEDSTATE:
1680         *pmsg16 = (UINT16)msg32 + (CB_GETEDITSEL16 - CB_GETEDITSEL);
1681         return 0;
1682     case CB_GETEDITSEL:
1683         *pmsg16 = CB_GETEDITSEL16;
1684         return 1;
1685
1686     case LB_ADDSTRING:
1687     case LB_FINDSTRING:
1688     case LB_FINDSTRINGEXACT:
1689     case LB_INSERTSTRING:
1690     case LB_SELECTSTRING:
1691     case LB_DIR:
1692     case LB_ADDFILE:
1693         *plparam = (LPARAM)MapLS( (LPSTR)*plparam );
1694         *pmsg16 = (UINT16)msg32 + (LB_ADDSTRING16 - LB_ADDSTRING);
1695         return 1;
1696
1697     case CB_ADDSTRING:
1698     case CB_FINDSTRING:
1699     case CB_FINDSTRINGEXACT:
1700     case CB_INSERTSTRING:
1701     case CB_SELECTSTRING:
1702     case CB_DIR:
1703         *plparam = (LPARAM)MapLS( (LPSTR)*plparam );
1704         *pmsg16 = (UINT16)msg32 + (CB_GETEDITSEL16 - CB_GETEDITSEL);
1705         return 1;
1706
1707     case LB_GETITEMRECT:
1708         {
1709             RECT16 *rect = HeapAlloc( GetProcessHeap(), 0, sizeof(RECT16) + sizeof(LPARAM) );
1710             if (!rect) return -1;
1711             *(LPARAM *)(rect + 1) = *plparam;  /* Store the previous lParam */
1712             *plparam = MapLS( rect );
1713         }
1714         *pmsg16 = LB_GETITEMRECT16;
1715         return 1;
1716     case LB_GETSELITEMS:
1717         {
1718             LPARAM *items; /* old LPARAM first, then *pwparam16 x INT16 entries */
1719
1720             *pwparam16 = (WPARAM16)min( wParam32, 0x7f80 ); /* Must be < 64K */
1721             if (!(items = HeapAlloc( GetProcessHeap(), 0,
1722                                      *pwparam16 * sizeof(INT16) + sizeof(LPARAM)))) return -1;
1723             *items++ = *plparam;  /* Store the previous lParam */
1724             *plparam = MapLS( items );
1725         }
1726         *pmsg16 = LB_GETSELITEMS16;
1727         return 1;
1728     case LB_SETTABSTOPS:
1729         if (wParam32)
1730         {
1731             INT i;
1732             LPINT16 stops;
1733             *pwparam16 = (WPARAM16)min( wParam32, 0x7f80 ); /* Must be < 64K */
1734             if (!(stops = HeapAlloc( GetProcessHeap(), 0,
1735                                      *pwparam16 * sizeof(INT16) + sizeof(LPARAM)))) return -1;
1736             for (i = 0; i < *pwparam16; i++) stops[i] = *((LPINT)*plparam+i);
1737             *plparam = MapLS( stops );
1738             return 1;
1739         }
1740         *pmsg16 = LB_SETTABSTOPS16;
1741         return 0;
1742
1743     case CB_GETDROPPEDCONTROLRECT:
1744         {
1745             RECT16 *rect = HeapAlloc( GetProcessHeap(), 0, sizeof(RECT16) + sizeof(LPARAM) );
1746             if (!rect) return -1;
1747             *(LPARAM *)(rect + 1) = *plparam;  /* Store the previous lParam */
1748             *plparam = (LPARAM)MapLS(rect);
1749         }
1750         *pmsg16 = CB_GETDROPPEDCONTROLRECT16;
1751         return 1;
1752
1753     case LB_GETTEXT:
1754         *plparam = (LPARAM)MapLS( (LPVOID)(*plparam) );
1755         *pmsg16 = LB_GETTEXT16;
1756         return 1;
1757
1758     case CB_GETLBTEXT:
1759         *plparam = (LPARAM)MapLS( (LPVOID)(*plparam) );
1760         *pmsg16 = CB_GETLBTEXT16;
1761         return 1;
1762
1763     case EM_SETSEL:
1764         *pwparam16 = 0;
1765         *plparam = MAKELONG( (INT16)(INT)wParam32, (INT16)*plparam );
1766         *pmsg16 = EM_SETSEL16;
1767         return 0;
1768
1769     case WM_ACTIVATE:
1770     case WM_CHARTOITEM:
1771     case WM_COMMAND:
1772     case WM_VKEYTOITEM:
1773         *plparam = MAKELPARAM( (HWND16)*plparam, HIWORD(wParam32) );
1774         return 0;
1775     case WM_HSCROLL:
1776     case WM_VSCROLL:
1777         *plparam = MAKELPARAM( HIWORD(wParam32), (HWND16)*plparam );
1778         return 0;
1779     case WM_COPYDATA:
1780         {
1781             PCOPYDATASTRUCT pcds32 = (PCOPYDATASTRUCT) *plparam;
1782             PCOPYDATASTRUCT16 pcds = HeapAlloc( GetProcessHeap(), 0, sizeof( *pcds));
1783             pcds->dwData = pcds32->dwData;
1784             pcds->cbData = pcds32->cbData;
1785             pcds->lpData = MapLS( pcds32->lpData);
1786             *plparam = MapLS( pcds );
1787         }
1788         return 1;
1789     case WM_CTLCOLORMSGBOX:
1790     case WM_CTLCOLOREDIT:
1791     case WM_CTLCOLORLISTBOX:
1792     case WM_CTLCOLORBTN:
1793     case WM_CTLCOLORDLG:
1794     case WM_CTLCOLORSCROLLBAR:
1795     case WM_CTLCOLORSTATIC:
1796         *pmsg16  = WM_CTLCOLOR;
1797         *plparam = MAKELPARAM( (HWND16)*plparam,
1798                                (WORD)msg32 - WM_CTLCOLORMSGBOX );
1799         return 0;
1800     case WM_COMPAREITEM:
1801         {
1802             COMPAREITEMSTRUCT *cis32 = (COMPAREITEMSTRUCT *)*plparam;
1803             COMPAREITEMSTRUCT16 *cis = HeapAlloc( GetProcessHeap(), 0, sizeof(COMPAREITEMSTRUCT16));
1804             if (!cis) return -1;
1805             cis->CtlType    = (UINT16)cis32->CtlType;
1806             cis->CtlID      = (UINT16)cis32->CtlID;
1807             cis->hwndItem   = HWND_16( cis32->hwndItem );
1808             cis->itemID1    = (UINT16)cis32->itemID1;
1809             cis->itemData1  = cis32->itemData1;
1810             cis->itemID2    = (UINT16)cis32->itemID2;
1811             cis->itemData2  = cis32->itemData2;
1812             *plparam = MapLS( cis );
1813         }
1814         return 1;
1815     case WM_DELETEITEM:
1816         {
1817             DELETEITEMSTRUCT *dis32 = (DELETEITEMSTRUCT *)*plparam;
1818             DELETEITEMSTRUCT16 *dis = HeapAlloc( GetProcessHeap(), 0, sizeof(DELETEITEMSTRUCT16) );
1819             if (!dis) return -1;
1820             dis->CtlType  = (UINT16)dis32->CtlType;
1821             dis->CtlID    = (UINT16)dis32->CtlID;
1822             dis->itemID   = (UINT16)dis32->itemID;
1823             dis->hwndItem = (dis->CtlType == ODT_MENU) ? (HWND16)LOWORD(dis32->hwndItem)
1824                                                        : HWND_16( dis32->hwndItem );
1825             dis->itemData = dis32->itemData;
1826             *plparam = MapLS( dis );
1827         }
1828         return 1;
1829     case WM_DRAWITEM:
1830         {
1831             DRAWITEMSTRUCT *dis32 = (DRAWITEMSTRUCT *)*plparam;
1832             DRAWITEMSTRUCT16 *dis = HeapAlloc( GetProcessHeap(), 0, sizeof(DRAWITEMSTRUCT16) );
1833             if (!dis) return -1;
1834             dis->CtlType       = (UINT16)dis32->CtlType;
1835             dis->CtlID         = (UINT16)dis32->CtlID;
1836             dis->itemID        = (UINT16)dis32->itemID;
1837             dis->itemAction    = (UINT16)dis32->itemAction;
1838             dis->itemState     = (UINT16)dis32->itemState;
1839             dis->hwndItem      = HWND_16( dis32->hwndItem );
1840             dis->hDC           = HDC_16(dis32->hDC);
1841             dis->itemData      = dis32->itemData;
1842             dis->rcItem.left   = dis32->rcItem.left;
1843             dis->rcItem.top    = dis32->rcItem.top;
1844             dis->rcItem.right  = dis32->rcItem.right;
1845             dis->rcItem.bottom = dis32->rcItem.bottom;
1846             *plparam = MapLS( dis );
1847         }
1848         return 1;
1849     case WM_MEASUREITEM:
1850         {
1851             MEASUREITEMSTRUCT *mis32 = (MEASUREITEMSTRUCT *)*plparam;
1852             MEASUREITEMSTRUCT16 *mis = HeapAlloc( GetProcessHeap(), 0, sizeof(*mis)+sizeof(LPARAM));
1853             if (!mis) return -1;
1854             mis->CtlType    = (UINT16)mis32->CtlType;
1855             mis->CtlID      = (UINT16)mis32->CtlID;
1856             mis->itemID     = (UINT16)mis32->itemID;
1857             mis->itemWidth  = (UINT16)mis32->itemWidth;
1858             mis->itemHeight = (UINT16)mis32->itemHeight;
1859             mis->itemData   = mis32->itemData;
1860             *(LPARAM *)(mis + 1) = *plparam;  /* Store the previous lParam */
1861             *plparam = MapLS( mis );
1862         }
1863         return 1;
1864     case WM_GETMINMAXINFO:
1865         {
1866             MINMAXINFO16 *mmi = HeapAlloc( GetProcessHeap(), 0, sizeof(*mmi) + sizeof(LPARAM) );
1867             if (!mmi) return -1;
1868             MINMAXINFO32to16( (MINMAXINFO *)*plparam, mmi );
1869             *(LPARAM *)(mmi + 1) = *plparam;  /* Store the previous lParam */
1870             *plparam = MapLS( mmi );
1871         }
1872         return 1;
1873     case WM_GETTEXT:
1874     case WM_ASKCBFORMATNAME:
1875         {
1876             LPARAM *str; /* store LPARAM, then *pwparam16 char space */
1877             *pwparam16 = (WPARAM16)min( wParam32, 0xff80 ); /* Must be < 64K */
1878             if (!(str = HeapAlloc( GetProcessHeap(), 0, *pwparam16 + sizeof(LPARAM)))) return -1;
1879             *str++ = *plparam;  /* Store the previous lParam */
1880             *plparam = MapLS( str );
1881         }
1882         return 1;
1883     case WM_MDICREATE:
1884         {
1885             MDICREATESTRUCT16 *cs;
1886             MDICREATESTRUCTA *cs32 = (MDICREATESTRUCTA *)*plparam;
1887
1888             if (!(cs = HeapAlloc( GetProcessHeap(), 0, sizeof(MDICREATESTRUCT16) ))) return -1;
1889             MDICREATESTRUCT32Ato16( cs32, cs );
1890             cs->szTitle = MapLS( cs32->szTitle );
1891             cs->szClass = MapLS( cs32->szClass );
1892             *plparam = MapLS( cs );
1893         }
1894         return 1;
1895     case WM_MDIGETACTIVE:
1896         return 1;
1897     case WM_MDISETMENU:
1898         *plparam   = MAKELPARAM( (HMENU16)LOWORD(wParam32),
1899                                  (HMENU16)LOWORD(*plparam) );
1900         *pwparam16 = (*plparam == 0);
1901         return 0;
1902     case WM_MENUSELECT:
1903         if(HIWORD(wParam32) & MF_POPUP)
1904         {
1905             HMENU hmenu;
1906             if (((UINT)HIWORD(wParam32) != 0xFFFF) || (*plparam))
1907             {
1908                 if((hmenu = GetSubMenu((HMENU)*plparam, *pwparam16)))
1909                     *pwparam16=HMENU_16(hmenu);
1910             }
1911         }
1912         /* fall through */
1913     case WM_MENUCHAR:
1914         *plparam = MAKELPARAM( HIWORD(wParam32), (HMENU16)*plparam );
1915         return 0;
1916     case WM_MDIACTIVATE:
1917         if (GetWindowLongW( hwnd, GWL_EXSTYLE ) & WS_EX_MDICHILD)
1918         {
1919             *pwparam16 = ((HWND)*plparam == hwnd);
1920             *plparam = MAKELPARAM( (HWND16)LOWORD(*plparam),
1921                                    (HWND16)LOWORD(wParam32) );
1922         }
1923         else
1924         {
1925             *pwparam16 = HWND_16( (HWND)wParam32 );
1926             *plparam = 0;
1927         }
1928         return 0;
1929     case WM_NCCALCSIZE:
1930         {
1931             NCCALCSIZE_PARAMS *nc32 = (NCCALCSIZE_PARAMS *)*plparam;
1932             NCCALCSIZE_PARAMS16 *nc = HeapAlloc( GetProcessHeap(), 0, sizeof(*nc) + sizeof(LPARAM));
1933             if (!nc) return -1;
1934
1935             nc->rgrc[0].left   = nc32->rgrc[0].left;
1936             nc->rgrc[0].top    = nc32->rgrc[0].top;
1937             nc->rgrc[0].right  = nc32->rgrc[0].right;
1938             nc->rgrc[0].bottom = nc32->rgrc[0].bottom;
1939             if (wParam32)
1940             {
1941                 WINDOWPOS16 *wp;
1942                 nc->rgrc[1].left   = nc32->rgrc[1].left;
1943                 nc->rgrc[1].top    = nc32->rgrc[1].top;
1944                 nc->rgrc[1].right  = nc32->rgrc[1].right;
1945                 nc->rgrc[1].bottom = nc32->rgrc[1].bottom;
1946                 nc->rgrc[2].left   = nc32->rgrc[2].left;
1947                 nc->rgrc[2].top    = nc32->rgrc[2].top;
1948                 nc->rgrc[2].right  = nc32->rgrc[2].right;
1949                 nc->rgrc[2].bottom = nc32->rgrc[2].bottom;
1950                 if (!(wp = HeapAlloc( GetProcessHeap(), 0, sizeof(WINDOWPOS16) )))
1951                 {
1952                     HeapFree( GetProcessHeap(), 0, nc );
1953                     return -1;
1954                 }
1955                 WINDOWPOS32to16( nc32->lppos, wp );
1956                 nc->lppos = MapLS( wp );
1957             }
1958             *(LPARAM *)(nc + 1) = *plparam;  /* Store the previous lParam */
1959             *plparam = MapLS( nc );
1960         }
1961         return 1;
1962     case WM_NCCREATE:
1963     case WM_CREATE:
1964         {
1965             CREATESTRUCT16 *cs;
1966             CREATESTRUCTA *cs32 = (CREATESTRUCTA *)*plparam;
1967
1968             if (!(cs = HeapAlloc( GetProcessHeap(), 0, sizeof(CREATESTRUCT16) ))) return -1;
1969             CREATESTRUCT32Ato16( cs32, cs );
1970             cs->lpszName  = MapLS( cs32->lpszName );
1971             cs->lpszClass = MapLS( cs32->lpszClass );
1972
1973             if (GetWindowLongW(hwnd, GWL_EXSTYLE) & WS_EX_MDICHILD)
1974             {
1975                 MDICREATESTRUCT16 *mdi_cs16;
1976                 MDICREATESTRUCTA *mdi_cs = (MDICREATESTRUCTA *)cs32->lpCreateParams;
1977                 mdi_cs16 = HeapAlloc(GetProcessHeap(), 0, sizeof(*mdi_cs16));
1978                 if (!mdi_cs16)
1979                 {
1980                     HeapFree(GetProcessHeap(), 0, cs);
1981                     return -1;
1982                 }
1983                 MDICREATESTRUCT32Ato16(mdi_cs, mdi_cs16);
1984                 mdi_cs16->szTitle = MapLS( mdi_cs->szTitle );
1985                 mdi_cs16->szClass = MapLS( mdi_cs->szClass );
1986                 cs->lpCreateParams = MapLS( mdi_cs16 );
1987             }
1988             *plparam = MapLS( cs );
1989         }
1990         return 1;
1991     case WM_PARENTNOTIFY:
1992         if ((LOWORD(wParam32)==WM_CREATE) || (LOWORD(wParam32)==WM_DESTROY))
1993             *plparam = MAKELPARAM( (HWND16)*plparam, HIWORD(wParam32));
1994         /* else nothing to do */
1995         return 0;
1996     case WM_NOTIFY:
1997         *plparam = MapLS( (NMHDR *)*plparam ); /* NMHDR is already 32-bit */
1998         return 1;
1999     case WM_SETTEXT:
2000     case WM_WININICHANGE:
2001     case WM_DEVMODECHANGE:
2002         *plparam = MapLS( (LPSTR)*plparam );
2003         return 1;
2004     case WM_WINDOWPOSCHANGING:
2005     case WM_WINDOWPOSCHANGED:
2006         {
2007             WINDOWPOS16 *wp = HeapAlloc( GetProcessHeap(), 0, sizeof(*wp) + sizeof(LPARAM) );
2008             if (!wp) return -1;
2009             WINDOWPOS32to16( (WINDOWPOS *)*plparam, wp );
2010             *(LPARAM *)(wp + 1) = *plparam;  /* Store the previous lParam */
2011             *plparam = MapLS( wp );
2012         }
2013         return 1;
2014     case WM_GETDLGCODE:
2015          if (*plparam) {
2016             LPMSG msg32 = (LPMSG) *plparam;
2017             LPMSG16 msg16 = HeapAlloc( GetProcessHeap(), 0, sizeof(MSG16) );
2018
2019             if (!msg16) return -1;
2020             msg16->hwnd = HWND_16( msg32->hwnd );
2021             msg16->message = msg32->message;
2022             msg16->wParam = msg32->wParam;
2023             msg16->lParam = msg32->lParam;
2024             msg16->time = msg32->time;
2025             msg16->pt.x = msg32->pt.x;
2026             msg16->pt.y = msg32->pt.y;
2027             *plparam = MapLS( msg16 );
2028             return 1;
2029         }
2030         return 0;
2031
2032     case WM_ACTIVATEAPP:
2033         if (*plparam) *plparam = HTASK_16( (HANDLE)*plparam );
2034         return 0;
2035     case WM_NEXTMENU:
2036         {
2037             MDINEXTMENU *next = (MDINEXTMENU *)*plparam;
2038             *plparam = (LPARAM)next->hmenuIn;
2039             return 1;
2040         }
2041     case WM_PAINT:
2042         if (IsIconic( hwnd ) && GetClassLongPtrW( hwnd, GCLP_HICON ))
2043         {
2044             *pmsg16 = WM_PAINTICON;
2045             *pwparam16 = 1;
2046         }
2047         return 0;
2048     case WM_ERASEBKGND:
2049         if (IsIconic( hwnd ) && GetClassLongPtrW( hwnd, GCLP_HICON ))
2050             *pmsg16 = WM_ICONERASEBKGND;
2051         return 0;
2052     case WM_PAINTCLIPBOARD:
2053     case WM_SIZECLIPBOARD:
2054         FIXME_(msg)("message %04x needs translation\n", msg32 );
2055         return -1;
2056     /* following messages should not be sent to 16-bit apps */
2057     case WM_SIZING:
2058     case WM_MOVING:
2059     case WM_CAPTURECHANGED:
2060     case WM_STYLECHANGING:
2061     case WM_STYLECHANGED:
2062         return -1;
2063     case WM_DDE_INITIATE:
2064     case WM_DDE_TERMINATE:
2065     case WM_DDE_UNADVISE:
2066     case WM_DDE_REQUEST:
2067         *pwparam16 = HWND_16((HWND)wParam32);
2068         return 0;
2069     case WM_DDE_ADVISE:
2070     case WM_DDE_DATA:
2071     case WM_DDE_POKE:
2072         {
2073             UINT_PTR lo32, hi;
2074             HANDLE16    lo16 = 0;
2075
2076             *pwparam16 = HWND_16((HWND)wParam32);
2077             UnpackDDElParam(msg32, *plparam, &lo32, &hi);
2078             if (lo32 && !(lo16 = convert_handle_32_to_16(lo32, GMEM_DDESHARE)))
2079                 return -1;
2080             *plparam = MAKELPARAM(lo16, hi);
2081         }
2082         return 0; /* FIXME don't know how to free allocated memory (handle)  !! */
2083     case WM_DDE_ACK:
2084         {
2085             UINT_PTR    lo, hi;
2086             int         flag = 0;
2087             char        buf[2];
2088
2089             *pwparam16 = HWND_16((HWND)wParam32);
2090
2091             UnpackDDElParam(msg32, *plparam, &lo, &hi);
2092
2093             if (GlobalGetAtomNameA((ATOM)hi, buf, sizeof(buf)) > 0) flag |= 1;
2094             if (GlobalSize((HANDLE)hi) != 0) flag |= 2;
2095             switch (flag)
2096             {
2097             case 0:
2098                 if (hi)
2099                 {
2100                     MESSAGE("DDE_ACK: neither atom nor handle!!!\n");
2101                     hi = 0;
2102                 }
2103                 break;
2104             case 1:
2105                 break; /* atom, nothing to do */
2106             case 3:
2107                 MESSAGE("DDE_ACK: %x both atom and handle... choosing handle\n", hi);
2108                 /* fall thru */
2109             case 2:
2110                 hi = convert_handle_32_to_16(hi, GMEM_DDESHARE);
2111                 break;
2112             }
2113             *plparam = MAKELPARAM(lo, hi);
2114         }
2115         return 0; /* FIXME don't know how to free allocated memory (handle) !! */
2116     case WM_DDE_EXECUTE:
2117         *plparam = convert_handle_32_to_16(*plparam, GMEM_DDESHARE);
2118         return 0; /* FIXME don't know how to free allocated memory (handle) !! */
2119     default:  /* No translation needed */
2120         return 0;
2121     }
2122 }
2123
2124
2125 /**********************************************************************
2126  *           WINPROC_UnmapMsg32ATo16
2127  *
2128  * Unmap a message that was mapped from 32-bit Ansi to 16-bit.
2129  */
2130 static void WINPROC_UnmapMsg32ATo16( HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam,
2131                                      WPARAM16 wParam16, LPARAM lParam16, LRESULT *result )
2132 {
2133     switch(msg)
2134     {
2135     case SBM_GETRANGE:
2136         *(LPINT)wParam = LOWORD(*result);
2137         *(LPINT)lParam = HIWORD(*result);
2138         break;
2139
2140     case LB_ADDFILE:
2141     case LB_ADDSTRING:
2142     case LB_DIR:
2143     case LB_FINDSTRING:
2144     case LB_FINDSTRINGEXACT:
2145     case LB_INSERTSTRING:
2146     case LB_SELECTSTRING:
2147     case LB_GETTEXT:
2148     case CB_ADDSTRING:
2149     case CB_FINDSTRING:
2150     case CB_FINDSTRINGEXACT:
2151     case CB_INSERTSTRING:
2152     case CB_SELECTSTRING:
2153     case CB_DIR:
2154     case CB_GETLBTEXT:
2155     case WM_SETTEXT:
2156     case WM_WININICHANGE:
2157     case WM_DEVMODECHANGE:
2158         UnMapLS( (SEGPTR)lParam16 );
2159         break;
2160     case LB_SETTABSTOPS:
2161     case WM_COMPAREITEM:
2162     case WM_DELETEITEM:
2163     case WM_DRAWITEM:
2164         {
2165             void *ptr = MapSL( lParam16 );
2166             UnMapLS( lParam16 );
2167             HeapFree( GetProcessHeap(), 0, ptr );
2168         }
2169         break;
2170     case WM_COPYDATA:
2171         {
2172             PCOPYDATASTRUCT16 pcds = MapSL( lParam16 );
2173             UnMapLS( lParam16 );
2174             UnMapLS( pcds->lpData );
2175             HeapFree( GetProcessHeap(), 0, pcds );
2176         }
2177         break;
2178     case CB_GETDROPPEDCONTROLRECT:
2179     case LB_GETITEMRECT:
2180         {
2181             RECT *r32;
2182             RECT16 *rect = MapSL(lParam16);
2183             UnMapLS( lParam16 );
2184             lParam16 = *(LPARAM *)(rect + 1);
2185             r32 = (RECT *)lParam16;
2186             r32->left   = rect->left;
2187             r32->top    = rect->top;
2188             r32->right  = rect->right;
2189             r32->bottom = rect->bottom;
2190             HeapFree( GetProcessHeap(), 0, rect );
2191         }
2192         break;
2193     case LB_GETSELITEMS:
2194         {
2195             INT i;
2196             LPINT16 items = MapSL(lParam16);
2197             UnMapLS( lParam16 );
2198             lParam16 = *((LPARAM *)items - 1);
2199             for (i = 0; i < wParam16; i++) *((LPINT)lParam16 + i) = items[i];
2200             HeapFree( GetProcessHeap(), 0, (LPARAM *)items - 1 );
2201         }
2202         break;
2203
2204     case CB_GETEDITSEL:
2205         if( wParam )
2206             *((PUINT)(wParam)) = LOWORD(*result);
2207         if( lParam )
2208             *((PUINT)(lParam)) = HIWORD(*result);  /* FIXME: substract 1? */
2209         break;
2210
2211     case WM_MEASUREITEM:
2212         {
2213             MEASUREITEMSTRUCT16 *mis = MapSL(lParam16);
2214             MEASUREITEMSTRUCT *mis32 = *(MEASUREITEMSTRUCT **)(mis + 1);
2215             mis32->itemWidth  = mis->itemWidth;
2216             mis32->itemHeight = mis->itemHeight;
2217             UnMapLS( lParam16 );
2218             HeapFree( GetProcessHeap(), 0, mis );
2219         }
2220         break;
2221     case WM_GETMINMAXINFO:
2222         {
2223             MINMAXINFO16 *mmi = MapSL(lParam16);
2224             UnMapLS( lParam16 );
2225             lParam16 = *(LPARAM *)(mmi + 1);
2226             MINMAXINFO16to32( mmi, (MINMAXINFO *)lParam16 );
2227             HeapFree( GetProcessHeap(), 0, mmi );
2228         }
2229         break;
2230     case WM_GETTEXT:
2231     case WM_ASKCBFORMATNAME:
2232         {
2233             LPSTR str = MapSL(lParam16);
2234             UnMapLS( lParam16 );
2235             lParam16 = *((LPARAM *)str - 1);
2236             lstrcpynA( (LPSTR)lParam16, str, wParam16 );
2237             HeapFree( GetProcessHeap(), 0, (LPARAM *)str - 1 );
2238         }
2239         break;
2240     case WM_MDICREATE:
2241         {
2242             MDICREATESTRUCT16 *cs = MapSL(lParam16);
2243             UnMapLS( cs->szTitle );
2244             UnMapLS( cs->szClass );
2245             UnMapLS( lParam16 );
2246             HeapFree( GetProcessHeap(), 0, cs );
2247         }
2248         break;
2249     case WM_MDIGETACTIVE:
2250         if (lParam) *(BOOL *)lParam = (BOOL16)HIWORD(*result);
2251         *result = (LRESULT)WIN_Handle32( LOWORD(*result) );
2252         break;
2253     case WM_NCCALCSIZE:
2254         {
2255             NCCALCSIZE_PARAMS *nc32;
2256             NCCALCSIZE_PARAMS16 *nc = MapSL(lParam16);
2257             UnMapLS( lParam16 );
2258             lParam16 = *(LPARAM *)(nc + 1);
2259             nc32 = (NCCALCSIZE_PARAMS *)lParam16;
2260             nc32->rgrc[0].left   = nc->rgrc[0].left;
2261             nc32->rgrc[0].top    = nc->rgrc[0].top;
2262             nc32->rgrc[0].right  = nc->rgrc[0].right;
2263             nc32->rgrc[0].bottom = nc->rgrc[0].bottom;
2264             if (wParam16)
2265             {
2266                 WINDOWPOS16 *pos = MapSL(nc->lppos);
2267                 UnMapLS( nc->lppos );
2268                 nc32->rgrc[1].left   = nc->rgrc[1].left;
2269                 nc32->rgrc[1].top    = nc->rgrc[1].top;
2270                 nc32->rgrc[1].right  = nc->rgrc[1].right;
2271                 nc32->rgrc[1].bottom = nc->rgrc[1].bottom;
2272                 nc32->rgrc[2].left   = nc->rgrc[2].left;
2273                 nc32->rgrc[2].top    = nc->rgrc[2].top;
2274                 nc32->rgrc[2].right  = nc->rgrc[2].right;
2275                 nc32->rgrc[2].bottom = nc->rgrc[2].bottom;
2276                 WINDOWPOS16to32( pos, nc32->lppos );
2277                 HeapFree( GetProcessHeap(), 0, pos );
2278             }
2279             HeapFree( GetProcessHeap(), 0, nc );
2280         }
2281         break;
2282     case WM_NCCREATE:
2283     case WM_CREATE:
2284         {
2285             CREATESTRUCT16 *cs = MapSL(lParam16);
2286             UnMapLS( lParam16 );
2287             UnMapLS( cs->lpszName );
2288             UnMapLS( cs->lpszClass );
2289             if (GetWindowLongW(hwnd, GWL_EXSTYLE) & WS_EX_MDICHILD)
2290             {
2291                 MDICREATESTRUCT16 *mdi_cs16 = (MDICREATESTRUCT16 *)MapSL(cs->lpCreateParams);
2292                 UnMapLS( cs->lpCreateParams );
2293                 UnMapLS( mdi_cs16->szTitle );
2294                 UnMapLS( mdi_cs16->szClass );
2295                 HeapFree(GetProcessHeap(), 0, mdi_cs16);
2296             }
2297             HeapFree( GetProcessHeap(), 0, cs );
2298         }
2299         break;
2300     case WM_WINDOWPOSCHANGING:
2301     case WM_WINDOWPOSCHANGED:
2302         {
2303             WINDOWPOS16 *wp = MapSL(lParam16);
2304             UnMapLS( lParam16 );
2305             lParam16 = *(LPARAM *)(wp + 1);
2306             WINDOWPOS16to32( wp, (WINDOWPOS *)lParam16 );
2307             HeapFree( GetProcessHeap(), 0, wp );
2308         }
2309         break;
2310     case WM_NOTIFY:
2311         UnMapLS(lParam16);
2312         break;
2313     case WM_GETDLGCODE:
2314         if (lParam16)
2315         {
2316             LPMSG16 msg16 = MapSL(lParam16);
2317             UnMapLS( lParam16 );
2318             HeapFree( GetProcessHeap(), 0, msg16 );
2319         }
2320         break;
2321     case WM_NEXTMENU:
2322         {
2323             MDINEXTMENU *next = (MDINEXTMENU *)lParam;
2324             next->hmenuNext = HMENU_32( LOWORD(*result) );
2325             next->hwndNext = WIN_Handle32( HIWORD(*result) );
2326             *result = 0;
2327         }
2328         break;
2329     }
2330 }
2331
2332
2333 /**********************************************************************
2334  *           WINPROC_MapMsg32WTo16
2335  *
2336  * Map a message from 32-bit Unicode to 16-bit.
2337  * Return value is -1 on error, 0 if OK, 1 if an UnmapMsg call is needed.
2338  */
2339 static INT WINPROC_MapMsg32WTo16( HWND hwnd, UINT msg32, WPARAM wParam32,
2340                                   UINT16 *pmsg16, WPARAM16 *pwparam16, LPARAM *plparam )
2341 {
2342     *pmsg16    = LOWORD(msg32);
2343     *pwparam16 = LOWORD(wParam32);
2344     switch(msg32)
2345     {
2346     case LB_ADDSTRING:
2347     case LB_FINDSTRING:
2348     case LB_FINDSTRINGEXACT:
2349     case LB_INSERTSTRING:
2350     case LB_SELECTSTRING:
2351     case LB_DIR:
2352     case LB_ADDFILE:
2353         *plparam = map_str_32W_to_16( (LPWSTR)*plparam );
2354         *pmsg16 = (UINT16)msg32 + (LB_ADDSTRING16 - LB_ADDSTRING);
2355         return 1;
2356
2357     case CB_ADDSTRING:
2358     case CB_FINDSTRING:
2359     case CB_FINDSTRINGEXACT:
2360     case CB_INSERTSTRING:
2361     case CB_SELECTSTRING:
2362     case CB_DIR:
2363         *plparam = map_str_32W_to_16( (LPWSTR)*plparam );
2364         *pmsg16 = (UINT16)msg32 + (CB_ADDSTRING16 - CB_ADDSTRING);
2365         return 1;
2366
2367     case WM_NCCREATE:
2368     case WM_CREATE:
2369         {
2370             CREATESTRUCT16 *cs;
2371             CREATESTRUCTW *cs32 = (CREATESTRUCTW *)*plparam;
2372
2373             if (!(cs = HeapAlloc( GetProcessHeap(), 0, sizeof(CREATESTRUCT16) ))) return -1;
2374             CREATESTRUCT32Ato16( (CREATESTRUCTA *)cs32, cs );
2375             cs->lpszName  = map_str_32W_to_16( cs32->lpszName );
2376             cs->lpszClass = map_str_32W_to_16( cs32->lpszClass );
2377
2378             if (GetWindowLongW(hwnd, GWL_EXSTYLE) & WS_EX_MDICHILD)
2379             {
2380                 MDICREATESTRUCT16 *mdi_cs16;
2381                 MDICREATESTRUCTW *mdi_cs = (MDICREATESTRUCTW *)cs32->lpCreateParams;
2382                 mdi_cs16 = HeapAlloc(GetProcessHeap(), 0, sizeof(*mdi_cs16));
2383                 if (!mdi_cs16)
2384                 {
2385                     HeapFree(GetProcessHeap(), 0, cs);
2386                     return -1;
2387                 }
2388                 MDICREATESTRUCT32Ato16((MDICREATESTRUCTA *)mdi_cs, mdi_cs16);
2389                 mdi_cs16->szTitle = map_str_32W_to_16(mdi_cs->szTitle);
2390                 mdi_cs16->szClass = map_str_32W_to_16(mdi_cs->szClass);
2391                 cs->lpCreateParams = MapLS(mdi_cs16);
2392             }
2393             *plparam   = MapLS(cs);
2394         }
2395         return 1;
2396     case WM_MDICREATE:
2397         {
2398             MDICREATESTRUCT16 *cs;
2399             MDICREATESTRUCTW *cs32 = (MDICREATESTRUCTW *)*plparam;
2400
2401             if (!(cs = HeapAlloc( GetProcessHeap(), 0, sizeof(MDICREATESTRUCT16) ))) return -1;
2402             MDICREATESTRUCT32Ato16( (MDICREATESTRUCTA *)cs32, cs );
2403             cs->szTitle = map_str_32W_to_16( cs32->szTitle );
2404             cs->szClass = map_str_32W_to_16( cs32->szClass );
2405             *plparam   = MapLS(cs);
2406         }
2407         return 1;
2408     case WM_SETTEXT:
2409     case WM_WININICHANGE:
2410     case WM_DEVMODECHANGE:
2411         *plparam = map_str_32W_to_16( (LPWSTR)*plparam );
2412         return 1;
2413     case LB_GETTEXT:
2414     case CB_GETLBTEXT:
2415         if ( WINPROC_TestLBForStr( hwnd, msg32 ))
2416         {
2417             LPSTR str = HeapAlloc( GetProcessHeap(), 0, 512 ); /* FIXME: fixed sized buffer */
2418             if (!str) return -1;
2419             *pmsg16    = (msg32 == LB_GETTEXT) ? LB_GETTEXT16 : CB_GETLBTEXT16;
2420             *plparam   = (LPARAM)MapLS(str);
2421         }
2422         return 1;
2423
2424     case WM_CHARTOITEM:
2425         *pwparam16 = map_wparam_char_WtoA( wParam32, 1 );
2426         *plparam = MAKELPARAM( (HWND16)*plparam, HIWORD(wParam32) );
2427         return 0;
2428     case WM_MENUCHAR:
2429         *pwparam16 = map_wparam_char_WtoA( wParam32, 1 );
2430         *plparam = MAKELPARAM( HIWORD(wParam32), (HMENU16)*plparam );
2431         return 0;
2432     case WM_CHAR:
2433     case WM_DEADCHAR:
2434     case WM_SYSCHAR:
2435     case WM_SYSDEADCHAR:
2436         *pwparam16 = map_wparam_char_WtoA( wParam32, 1 );
2437         return 0;
2438     case WM_IME_CHAR:
2439         *pwparam16 = map_wparam_char_WtoA( wParam32, 2 );
2440         return 0;
2441
2442     default:  /* No Unicode translation needed (?) */
2443         return WINPROC_MapMsg32ATo16( hwnd, msg32, wParam32, pmsg16,
2444                                       pwparam16, plparam );
2445     }
2446 }
2447
2448
2449 /**********************************************************************
2450  *           WINPROC_UnmapMsg32WTo16
2451  *
2452  * Unmap a message that was mapped from 32-bit Unicode to 16-bit.
2453  */
2454 static void WINPROC_UnmapMsg32WTo16( HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam,
2455                                      WPARAM16 wParam16, LPARAM lParam16, LRESULT *result )
2456 {
2457     switch(msg)
2458     {
2459     case LB_ADDSTRING:
2460     case LB_FINDSTRING:
2461     case LB_FINDSTRINGEXACT:
2462     case LB_INSERTSTRING:
2463     case LB_SELECTSTRING:
2464     case LB_DIR:
2465     case LB_ADDFILE:
2466     case CB_ADDSTRING:
2467     case CB_FINDSTRING:
2468     case CB_FINDSTRINGEXACT:
2469     case CB_INSERTSTRING:
2470     case CB_SELECTSTRING:
2471     case CB_DIR:
2472     case WM_SETTEXT:
2473     case WM_WININICHANGE:
2474     case WM_DEVMODECHANGE:
2475         unmap_str_32W_to_16( lParam16 );
2476         break;
2477     case WM_NCCREATE:
2478     case WM_CREATE:
2479         {
2480             CREATESTRUCT16 *cs = MapSL(lParam16);
2481             UnMapLS( lParam16 );
2482             unmap_str_32W_to_16( cs->lpszName );
2483             unmap_str_32W_to_16( cs->lpszClass );
2484
2485             if (GetWindowLongW(hwnd, GWL_EXSTYLE) & WS_EX_MDICHILD)
2486             {
2487                 MDICREATESTRUCT16 *mdi_cs16 = (MDICREATESTRUCT16 *)MapSL(cs->lpCreateParams);
2488                 UnMapLS( cs->lpCreateParams );
2489                 unmap_str_32W_to_16(mdi_cs16->szTitle);
2490                 unmap_str_32W_to_16(mdi_cs16->szClass);
2491                 HeapFree(GetProcessHeap(), 0, mdi_cs16);
2492             }
2493             HeapFree( GetProcessHeap(), 0, cs );
2494         }
2495         break;
2496     case WM_MDICREATE:
2497         {
2498             MDICREATESTRUCT16 *cs = MapSL(lParam16);
2499             UnMapLS( lParam16 );
2500             unmap_str_32W_to_16( cs->szTitle );
2501             unmap_str_32W_to_16( cs->szClass );
2502             HeapFree( GetProcessHeap(), 0, cs );
2503         }
2504         break;
2505     case WM_GETTEXT:
2506     case WM_ASKCBFORMATNAME:
2507         {
2508             LPSTR str = MapSL(lParam16);
2509             UnMapLS( lParam16 );
2510             lParam16 = *((LPARAM *)str - 1);
2511             MultiByteToWideChar( CP_ACP, 0, str, -1, (LPWSTR)lParam16, 0x7fffffff );
2512             *result = strlenW( (LPWSTR)lParam16 );
2513             HeapFree( GetProcessHeap(), 0, (LPARAM *)str - 1 );
2514         }
2515         break;
2516     case LB_GETTEXT:
2517     case CB_GETLBTEXT:
2518         if ( WINPROC_TestLBForStr( hwnd, msg ))
2519         {
2520             LPSTR str = MapSL(lParam16);
2521             UnMapLS( lParam16 );
2522             *result = MultiByteToWideChar( CP_ACP, 0, str, -1, (LPWSTR)lParam, 0x7fffffff ) - 1;
2523             HeapFree( GetProcessHeap(), 0, (LPARAM *)str );
2524         }
2525         break;
2526     default:
2527         WINPROC_UnmapMsg32ATo16( hwnd, msg, wParam, lParam, wParam16, lParam16, result );
2528         break;
2529     }
2530 }
2531
2532
2533 /**********************************************************************
2534  *           WINPROC_CallProcAtoW
2535  *
2536  * Call a window procedure, translating args from Ansi to Unicode.
2537  */
2538 LRESULT WINPROC_CallProcAtoW( winproc_callback_t callback, HWND hwnd, UINT msg, WPARAM wParam,
2539                               LPARAM lParam, LRESULT *result, void *arg )
2540 {
2541     LRESULT ret = 0;
2542     int unmap;
2543
2544     TRACE_(msg)("(hwnd=%p,msg=%s,wp=%08x,lp=%08lx)\n",
2545                 hwnd, SPY_GetMsgName(msg, hwnd), wParam, lParam);
2546
2547     switch(msg)
2548     {
2549     case WM_NCCREATE:
2550     case WM_CREATE:
2551         {
2552             WCHAR *ptr, buffer[512];
2553             CREATESTRUCTA *csA = (CREATESTRUCTA *)lParam;
2554             CREATESTRUCTW csW = *(CREATESTRUCTW *)csA;
2555             MDICREATESTRUCTW mdi_cs;
2556             DWORD name_lenA = 0, name_lenW = 0, class_lenA = 0, class_lenW = 0;
2557
2558             if (HIWORD(csA->lpszClass))
2559             {
2560                 class_lenA = strlen(csA->lpszClass) + 1;
2561                 RtlMultiByteToUnicodeSize( &class_lenW, csA->lpszClass, class_lenA );
2562             }
2563             if (HIWORD(csA->lpszName))
2564             {
2565                 name_lenA = strlen(csA->lpszName) + 1;
2566                 RtlMultiByteToUnicodeSize( &name_lenW, csA->lpszName, name_lenA );
2567             }
2568
2569             if (!(ptr = get_buffer( buffer, sizeof(buffer), class_lenW + name_lenW ))) break;
2570
2571             if (class_lenW)
2572             {
2573                 csW.lpszClass = ptr;
2574                 RtlMultiByteToUnicodeN( ptr, class_lenW, NULL, csA->lpszClass, class_lenA );
2575             }
2576             if (name_lenW)
2577             {
2578                 csW.lpszName = ptr + class_lenW/sizeof(WCHAR);
2579                 RtlMultiByteToUnicodeN( ptr + class_lenW/sizeof(WCHAR), name_lenW, NULL,
2580                                         csA->lpszName, name_lenA );
2581             }
2582
2583             if (GetWindowLongW(hwnd, GWL_EXSTYLE) & WS_EX_MDICHILD)
2584             {
2585                 mdi_cs = *(MDICREATESTRUCTW *)csA->lpCreateParams;
2586                 mdi_cs.szTitle = csW.lpszName;
2587                 mdi_cs.szClass = csW.lpszClass;
2588                 csW.lpCreateParams = &mdi_cs;
2589             }
2590
2591             ret = callback( hwnd, msg, wParam, (LPARAM)&csW, result, arg );
2592             free_buffer( buffer, ptr );
2593         }
2594         break;
2595
2596     case WM_MDICREATE:
2597         {
2598             WCHAR *ptr, buffer[512];
2599             DWORD title_lenA = 0, title_lenW = 0, class_lenA = 0, class_lenW = 0;
2600             MDICREATESTRUCTA *csA = (MDICREATESTRUCTA *)lParam;
2601             MDICREATESTRUCTW csW;
2602
2603             memcpy( &csW, csA, sizeof(csW) );
2604
2605             if (HIWORD(csA->szTitle))
2606             {
2607                 title_lenA = strlen(csA->szTitle) + 1;
2608                 RtlMultiByteToUnicodeSize( &title_lenW, csA->szTitle, title_lenA );
2609             }
2610             if (HIWORD(csA->szClass))
2611             {
2612                 class_lenA = strlen(csA->szClass) + 1;
2613                 RtlMultiByteToUnicodeSize( &class_lenW, csA->szClass, class_lenA );
2614             }
2615
2616             if (!(ptr = get_buffer( buffer, sizeof(buffer), title_lenW + class_lenW ))) break;
2617
2618             if (title_lenW)
2619             {
2620                 csW.szTitle = ptr;
2621                 RtlMultiByteToUnicodeN( ptr, title_lenW, NULL, csA->szTitle, title_lenA );
2622             }
2623             if (class_lenW)
2624             {
2625                 csW.szClass = ptr + title_lenW/sizeof(WCHAR);
2626                 RtlMultiByteToUnicodeN( ptr + title_lenW/sizeof(WCHAR), class_lenW, NULL,
2627                                         csA->szClass, class_lenA );
2628             }
2629             ret = callback( hwnd, msg, wParam, (LPARAM)&csW, result, arg );
2630             free_buffer( buffer, ptr );
2631         }
2632         break;
2633
2634     case WM_GETTEXT:
2635     case WM_ASKCBFORMATNAME:
2636         {
2637             WCHAR *ptr, buffer[512];
2638             LPSTR str = (LPSTR)lParam;
2639             DWORD len = wParam * sizeof(WCHAR);
2640
2641             if (!(ptr = get_buffer( buffer, sizeof(buffer), len ))) break;
2642             ret = callback( hwnd, msg, wParam, (LPARAM)ptr, result, arg );
2643             if (*result && wParam)
2644             {
2645                 RtlUnicodeToMultiByteN( str, wParam - 1, &len, ptr, strlenW(ptr) * sizeof(WCHAR) );
2646                 str[len] = 0;
2647                 *result = len;
2648             }
2649             free_buffer( buffer, ptr );
2650         }
2651         break;
2652
2653     case LB_ADDSTRING:
2654     case LB_INSERTSTRING:
2655     case LB_FINDSTRING:
2656     case LB_FINDSTRINGEXACT:
2657     case LB_SELECTSTRING:
2658     case CB_ADDSTRING:
2659     case CB_INSERTSTRING:
2660     case CB_FINDSTRING:
2661     case CB_FINDSTRINGEXACT:
2662     case CB_SELECTSTRING:
2663         if (!lParam || !WINPROC_TestLBForStr( hwnd, msg ))
2664         {
2665             ret = callback( hwnd, msg, wParam, lParam, result, arg );
2666             break;
2667         }
2668         /* fall through */
2669     case WM_SETTEXT:
2670     case WM_WININICHANGE:
2671     case WM_DEVMODECHANGE:
2672     case CB_DIR:
2673     case LB_DIR:
2674     case LB_ADDFILE:
2675     case EM_REPLACESEL:
2676         if (!lParam) ret = callback( hwnd, msg, wParam, lParam, result, arg );
2677         else
2678         {
2679             WCHAR *ptr, buffer[512];
2680             LPCSTR strA = (LPCSTR)lParam;
2681             DWORD lenW, lenA = strlen(strA) + 1;
2682
2683             RtlMultiByteToUnicodeSize( &lenW, strA, lenA );
2684             if ((ptr = get_buffer( buffer, sizeof(buffer), lenW )))
2685             {
2686                 RtlMultiByteToUnicodeN( ptr, lenW, NULL, strA, lenA );
2687                 ret = callback( hwnd, msg, wParam, (LPARAM)ptr, result, arg );
2688                 free_buffer( buffer, ptr );
2689             }
2690         }
2691         break;
2692
2693     case LB_GETTEXT:
2694     case CB_GETLBTEXT:
2695         if (lParam && WINPROC_TestLBForStr( hwnd, msg ))
2696         {
2697             WCHAR buffer[512];  /* FIXME: fixed sized buffer */
2698
2699             ret = callback( hwnd, msg, wParam, (LPARAM)buffer, result, arg );
2700             if (*result >= 0)
2701             {
2702                 DWORD len;
2703                 RtlUnicodeToMultiByteN( (LPSTR)lParam, ~0u, &len,
2704                                         buffer, (strlenW(buffer) + 1) * sizeof(WCHAR) );
2705                 *result = len - 1;
2706             }
2707         }
2708         else ret = callback( hwnd, msg, wParam, lParam, result, arg );
2709         break;
2710
2711     default:
2712         if( (unmap = WINPROC_MapMsg32ATo32W( hwnd, msg, &wParam, &lParam )) == -1) {
2713             ERR_(msg)("Message translation failed. (msg=%s,wp=%08x,lp=%08lx)\n",
2714                       SPY_GetMsgName(msg, hwnd), wParam, lParam );
2715             return 0;
2716         }
2717         ret = callback( hwnd, msg, wParam, lParam, result, arg );
2718         if (!unmap) break;
2719         *result = WINPROC_UnmapMsg32ATo32W( hwnd, msg, wParam, lParam, *result,
2720                                             (callback == call_window_proc) ? arg : NULL  /*FIXME: hack*/ );
2721         break;
2722     }
2723     return ret;
2724 }
2725
2726
2727 /**********************************************************************
2728  *           WINPROC_CallProcWtoA
2729  *
2730  * Call a window procedure, translating args from Unicode to Ansi.
2731  */
2732 static LRESULT WINPROC_CallProcWtoA( winproc_callback_t callback, HWND hwnd, UINT msg, WPARAM wParam,
2733                                      LPARAM lParam, LRESULT *result, void *arg )
2734 {
2735     LRESULT ret = 0;
2736
2737     TRACE_(msg)("(hwnd=%p,msg=%s,wp=%08x,lp=%08lx)\n",
2738                 hwnd, SPY_GetMsgName(msg, hwnd), wParam, lParam);
2739
2740     switch(msg)
2741     {
2742     case WM_NCCREATE:
2743     case WM_CREATE:
2744         {   /* csW->lpszName and csW->lpszClass are NOT supposed to be atoms
2745              * at this point.
2746              */
2747             char buffer[1024], *cls, *name;
2748             CREATESTRUCTW *csW = (CREATESTRUCTW *)lParam;
2749             CREATESTRUCTA csA = *(CREATESTRUCTA *)csW;
2750             MDICREATESTRUCTA mdi_cs;
2751             DWORD name_lenA, name_lenW, class_lenA, class_lenW;
2752
2753             class_lenW = strlenW(csW->lpszClass) * sizeof(WCHAR);
2754             RtlUnicodeToMultiByteSize(&class_lenA, csW->lpszClass, class_lenW);
2755
2756             if (csW->lpszName)
2757             {
2758                 name_lenW = strlenW(csW->lpszName) * sizeof(WCHAR);
2759                 RtlUnicodeToMultiByteSize(&name_lenA, csW->lpszName, name_lenW);
2760             }
2761             else
2762                 name_lenW = name_lenA = 0;
2763
2764             if (!(cls = get_buffer( buffer, sizeof(buffer), class_lenA + name_lenA + 2 ))) break;
2765
2766             RtlUnicodeToMultiByteN(cls, class_lenA, NULL, csW->lpszClass, class_lenW);
2767             cls[class_lenA] = 0;
2768             csA.lpszClass = cls;
2769
2770             if (csW->lpszName)
2771             {
2772                 name = cls + class_lenA + 1;
2773                 RtlUnicodeToMultiByteN(name, name_lenA, NULL, csW->lpszName, name_lenW);
2774                 name[name_lenA] = 0;
2775                 csA.lpszName = name;
2776             }
2777
2778             if (GetWindowLongW(hwnd, GWL_EXSTYLE) & WS_EX_MDICHILD)
2779             {
2780                 mdi_cs = *(MDICREATESTRUCTA *)csW->lpCreateParams;
2781                 mdi_cs.szTitle = csA.lpszName;
2782                 mdi_cs.szClass = csA.lpszClass;
2783                 csA.lpCreateParams = &mdi_cs;
2784             }
2785
2786             ret = callback( hwnd, msg, wParam, (LPARAM)&csA, result, arg );
2787             free_buffer( buffer, cls );
2788         }
2789         break;
2790
2791     case WM_GETTEXT:
2792     case WM_ASKCBFORMATNAME:
2793         {
2794             char *ptr, buffer[512];
2795             DWORD len = wParam * 2;
2796
2797             if (!(ptr = get_buffer( buffer, sizeof(buffer), len ))) break;
2798             ret = callback( hwnd, msg, wParam, (LPARAM)ptr, result, arg );
2799             if (*result && len)
2800             {
2801                 RtlMultiByteToUnicodeN( (LPWSTR)lParam, wParam*sizeof(WCHAR), &len, ptr, strlen(ptr)+1 );
2802                 *result = len/sizeof(WCHAR) - 1;  /* do not count terminating null */
2803                 ((LPWSTR)lParam)[*result] = 0;
2804             }
2805             free_buffer( buffer, ptr );
2806         }
2807         break;
2808
2809     case LB_ADDSTRING:
2810     case LB_INSERTSTRING:
2811     case LB_FINDSTRING:
2812     case LB_FINDSTRINGEXACT:
2813     case LB_SELECTSTRING:
2814     case CB_ADDSTRING:
2815     case CB_INSERTSTRING:
2816     case CB_FINDSTRING:
2817     case CB_FINDSTRINGEXACT:
2818     case CB_SELECTSTRING:
2819         if (!lParam || !WINPROC_TestLBForStr( hwnd, msg ))
2820         {
2821             ret = callback( hwnd, msg, wParam, lParam, result, arg );
2822             break;
2823         }
2824         /* fall through */
2825     case WM_SETTEXT:
2826     case WM_WININICHANGE:
2827     case WM_DEVMODECHANGE:
2828     case CB_DIR:
2829     case LB_DIR:
2830     case LB_ADDFILE:
2831     case EM_REPLACESEL:
2832         if (!lParam) ret = callback( hwnd, msg, wParam, lParam, result, arg );
2833         else
2834         {
2835             char *ptr, buffer[512];
2836             LPCWSTR strW = (LPCWSTR)lParam;
2837             DWORD lenA, lenW = (strlenW(strW) + 1) * sizeof(WCHAR);
2838
2839             RtlUnicodeToMultiByteSize( &lenA, strW, lenW );
2840             if ((ptr = get_buffer( buffer, sizeof(buffer), lenA )))
2841             {
2842                 RtlUnicodeToMultiByteN( ptr, lenA, NULL, strW, lenW );
2843                 ret = callback( hwnd, msg, wParam, (LPARAM)ptr, result, arg );
2844                 free_buffer( buffer, ptr );
2845             }
2846         }
2847         break;
2848
2849     case WM_MDICREATE:
2850         {
2851             char *ptr, buffer[1024];
2852             DWORD title_lenA = 0, title_lenW = 0, class_lenA = 0, class_lenW = 0;
2853             MDICREATESTRUCTW *csW = (MDICREATESTRUCTW *)lParam;
2854             MDICREATESTRUCTA csA;
2855
2856             memcpy( &csA, csW, sizeof(csA) );
2857
2858             if (HIWORD(csW->szTitle))
2859             {
2860                 title_lenW = (strlenW(csW->szTitle) + 1) * sizeof(WCHAR);
2861                 RtlUnicodeToMultiByteSize( &title_lenA, csW->szTitle, title_lenW );
2862             }
2863             if (HIWORD(csW->szClass))
2864             {
2865                 class_lenW = (strlenW(csW->szClass) + 1) * sizeof(WCHAR);
2866                 RtlUnicodeToMultiByteSize( &class_lenA, csW->szClass, class_lenW );
2867             }
2868
2869             if (!(ptr = get_buffer( buffer, sizeof(buffer), title_lenA + class_lenA ))) break;
2870
2871             if (title_lenA)
2872             {
2873                 RtlUnicodeToMultiByteN( ptr, title_lenA, NULL, csW->szTitle, title_lenW );
2874                 csA.szTitle = ptr;
2875             }
2876             if (class_lenA)
2877             {
2878                 RtlUnicodeToMultiByteN( ptr + title_lenA, class_lenA, NULL, csW->szClass, class_lenW );
2879                 csA.szClass = ptr + title_lenA;
2880             }
2881             ret = callback( hwnd, msg, wParam, (LPARAM)&csA, result, arg );
2882             free_buffer( buffer, ptr );
2883         }
2884         break;
2885
2886     case LB_GETTEXT:
2887     case CB_GETLBTEXT:
2888         if (lParam && WINPROC_TestLBForStr( hwnd, msg ))
2889         {
2890             char buffer[512];  /* FIXME: fixed sized buffer */
2891
2892             ret = callback( hwnd, msg, wParam, (LPARAM)buffer, result, arg );
2893             if (*result >= 0)
2894             {
2895                 DWORD len;
2896                 RtlMultiByteToUnicodeN( (LPWSTR)lParam, ~0u, &len, buffer, strlen(buffer) + 1 );
2897                 *result = len / sizeof(WCHAR) - 1;
2898             }
2899         }
2900         else ret = callback( hwnd, msg, wParam, lParam, result, arg );
2901         break;
2902
2903     case EM_GETLINE:
2904         {
2905             char *ptr, buffer[512];
2906             WORD len = *(WORD *)lParam;
2907
2908             if (!(ptr = get_buffer( buffer, sizeof(buffer), len * 2 ))) break;
2909             *((WORD *)ptr) = len * 2;   /* store the length */
2910             ret = callback( hwnd, msg, wParam, (LPARAM)ptr, result, arg );
2911             if (*result)
2912             {
2913                 DWORD reslen;
2914                 RtlMultiByteToUnicodeN( (LPWSTR)lParam, len*sizeof(WCHAR), &reslen, buffer, *result );
2915                 *result = reslen / sizeof(WCHAR);
2916                 if (*result < len) ((LPWSTR)lParam)[*result] = 0;
2917             }
2918             free_buffer( buffer, ptr );
2919         }
2920         break;
2921
2922     case WM_CHARTOITEM:
2923     case WM_MENUCHAR:
2924     case WM_CHAR:
2925     case WM_DEADCHAR:
2926     case WM_SYSCHAR:
2927     case WM_SYSDEADCHAR:
2928     case EM_SETPASSWORDCHAR:
2929         ret = callback( hwnd, msg, map_wparam_char_WtoA(wParam,1), lParam, result, arg );
2930         break;
2931
2932     case WM_IME_CHAR:
2933         ret = callback( hwnd, msg, map_wparam_char_WtoA(wParam,2), lParam, result, arg );
2934         break;
2935
2936     case WM_PAINTCLIPBOARD:
2937     case WM_SIZECLIPBOARD:
2938         FIXME_(msg)( "message %s (%04x) needs translation, please report\n",
2939                      SPY_GetMsgName(msg, hwnd), msg );
2940         break;
2941
2942     default:
2943         ret = callback( hwnd, msg, wParam, lParam, result, arg );
2944         break;
2945     }
2946
2947     return ret;
2948 }
2949
2950
2951 /**********************************************************************
2952  *           WINPROC_CallProc16To32A
2953  */
2954 LRESULT WINPROC_CallProc16To32A( winproc_callback_t callback, HWND16 hwnd, UINT16 msg,
2955                                  WPARAM16 wParam, LPARAM lParam, LRESULT *result, void *arg )
2956 {
2957     LRESULT ret;
2958     UINT msg32;
2959     WPARAM wParam32;
2960     HWND hwnd32 = WIN_Handle32( hwnd );
2961
2962     TRACE_(msg)("(hwnd=%p,msg=%s,wp=%08x,lp=%08lx)\n",
2963                  hwnd32, SPY_GetMsgName(msg, hwnd32), wParam, lParam);
2964
2965     if (WINPROC_MapMsg16To32A( hwnd32, msg, wParam, &msg32, &wParam32, &lParam ) == -1)
2966         return 0;
2967
2968     ret = callback( hwnd32, msg32, wParam32, lParam, result, arg );
2969     *result = WINPROC_UnmapMsg16To32A( hwnd32, msg32, wParam32, lParam, *result );
2970     return ret;
2971 }
2972
2973
2974 /**********************************************************************
2975  *           WINPROC_CallProc16To32W
2976  */
2977 static LRESULT WINPROC_CallProc16To32W( winproc_callback_t callback, HWND16 hwnd, UINT16 msg,
2978                                         WPARAM16 wParam, LPARAM lParam, LRESULT *result, void *arg )
2979 {
2980     LRESULT ret;
2981     UINT msg32;
2982     WPARAM wParam32;
2983     HWND hwnd32 = WIN_Handle32( hwnd );
2984
2985     TRACE_(msg)("(hwnd=%p,msg=%s,wp=%08x,lp=%08lx)\n",
2986                  hwnd32, SPY_GetMsgName(msg, hwnd32), wParam, lParam);
2987
2988     if (WINPROC_MapMsg16To32W( hwnd32, msg, wParam, &msg32, &wParam32, &lParam ) == -1)
2989         return 0;
2990
2991     ret = callback( hwnd32, msg32, wParam32, lParam, result, arg );
2992     *result = WINPROC_UnmapMsg16To32W( hwnd32, msg32, wParam32, lParam, *result,
2993                                        (callback == call_window_proc) ? arg : NULL  /*FIXME: hack*/ );
2994     return ret;
2995 }
2996
2997
2998 /**********************************************************************
2999  *           __wine_call_wndproc   (USER.1010)
3000  */
3001 LRESULT WINAPI __wine_call_wndproc( HWND16 hwnd, UINT16 msg, WPARAM16 wParam, LPARAM lParam,
3002                                     WINDOWPROC *proc )
3003 {
3004     LRESULT result;
3005
3006     if (proc->procA)
3007         WINPROC_CallProc16To32A( call_window_proc, hwnd, msg, wParam, lParam, &result, proc->procA );
3008     else
3009         WINPROC_CallProc16To32W( call_window_proc, hwnd, msg, wParam, lParam, &result, proc->procW );
3010     return result;
3011 }
3012
3013
3014 /**********************************************************************
3015  *           WINPROC_CallProc32ATo16
3016  *
3017  * Call a 16-bit window procedure, translating the 32-bit args.
3018  */
3019 LRESULT WINPROC_CallProc32ATo16( winproc_callback16_t callback, HWND hwnd, UINT msg,
3020                                  WPARAM wParam, LPARAM lParam, LRESULT *result, void *arg )
3021 {
3022     LRESULT ret;
3023     UINT16 msg16;
3024     WPARAM16 wParam16;
3025     LPARAM lParam16;
3026
3027     TRACE_(msg)("(hwnd=%p,msg=%s,wp=%08x,lp=%08lx)\n",
3028                 hwnd, SPY_GetMsgName(msg, hwnd), wParam, lParam);
3029
3030     lParam16 = lParam;
3031     if (WINPROC_MapMsg32ATo16( hwnd, msg, wParam, &msg16, &wParam16, &lParam16 ) == -1)
3032         return 0;
3033     ret = callback( HWND_16(hwnd), msg16, wParam16, lParam16, result, arg );
3034     WINPROC_UnmapMsg32ATo16( hwnd, msg, wParam, lParam, wParam16, lParam16, result );
3035     return ret;
3036 }
3037
3038
3039 /**********************************************************************
3040  *           WINPROC_CallProc32WTo16
3041  *
3042  * Call a 16-bit window procedure, translating the 32-bit args.
3043  */
3044 static LRESULT WINPROC_CallProc32WTo16( winproc_callback16_t callback, HWND hwnd, UINT msg,
3045                                         WPARAM wParam, LPARAM lParam, LRESULT *result, void *arg )
3046 {
3047     LRESULT ret;
3048     UINT16 msg16;
3049     WPARAM16 wParam16;
3050     LPARAM lParam16;
3051
3052     TRACE_(msg)("(hwnd=%p,msg=%s,wp=%08x,lp=%08lx)\n",
3053                 hwnd, SPY_GetMsgName(msg, hwnd), wParam, lParam);
3054
3055     lParam16 = lParam;
3056     if (WINPROC_MapMsg32WTo16( hwnd, msg, wParam, &msg16, &wParam16, &lParam16 ) == -1)
3057         return 0;
3058     ret = callback( HWND_16(hwnd), msg16, wParam16, lParam16, result, arg );
3059     WINPROC_UnmapMsg32WTo16( hwnd, msg, wParam, lParam, wParam16, lParam16, result );
3060     return ret;
3061 }
3062
3063
3064 /**********************************************************************
3065  *              CallWindowProc (USER.122)
3066  */
3067 LRESULT WINAPI CallWindowProc16( WNDPROC16 func, HWND16 hwnd, UINT16 msg,
3068                                  WPARAM16 wParam, LPARAM lParam )
3069 {
3070     WINDOWPROC *proc;
3071     LRESULT result;
3072
3073     if (!func) return 0;
3074
3075     if (!(proc = handle16_to_proc( func )))
3076         call_window_proc16( hwnd, msg, wParam, lParam, &result, func );
3077     else if (proc->procA)
3078         WINPROC_CallProc16To32A( call_window_proc, hwnd, msg, wParam, lParam, &result, proc->procA );
3079     else if (proc->procW)
3080         WINPROC_CallProc16To32W( call_window_proc, hwnd, msg, wParam, lParam, &result, proc->procW );
3081     else
3082         call_window_proc16( hwnd, msg, wParam, lParam, &result, proc->proc16 );
3083
3084     return result;
3085 }
3086
3087
3088 /**********************************************************************
3089  *              CallWindowProcA (USER32.@)
3090  *
3091  * The CallWindowProc() function invokes the windows procedure _func_,
3092  * with _hwnd_ as the target window, the message specified by _msg_, and
3093  * the message parameters _wParam_ and _lParam_.
3094  *
3095  * Some kinds of argument conversion may be done, I'm not sure what.
3096  *
3097  * CallWindowProc() may be used for windows subclassing. Use
3098  * SetWindowLong() to set a new windows procedure for windows of the
3099  * subclass, and handle subclassed messages in the new windows
3100  * procedure. The new windows procedure may then use CallWindowProc()
3101  * with _func_ set to the parent class's windows procedure to dispatch
3102  * the message to the superclass.
3103  *
3104  * RETURNS
3105  *
3106  *    The return value is message dependent.
3107  *
3108  * CONFORMANCE
3109  *
3110  *   ECMA-234, Win32
3111  */
3112 LRESULT WINAPI CallWindowProcA(
3113     WNDPROC func,  /* [in] window procedure */
3114     HWND hwnd,     /* [in] target window */
3115     UINT msg,      /* [in] message */
3116     WPARAM wParam, /* [in] message dependent parameter */
3117     LPARAM lParam  /* [in] message dependent parameter */
3118 ) {
3119     WINDOWPROC *proc;
3120     LRESULT result;
3121
3122     if (!func) return 0;
3123
3124     if (!(proc = handle_to_proc( func )))
3125         call_window_proc( hwnd, msg, wParam, lParam, &result, func );
3126     else if (proc->procA)
3127         call_window_proc( hwnd, msg, wParam, lParam, &result, proc->procA );
3128     else if (proc->procW)
3129         WINPROC_CallProcAtoW( call_window_proc, hwnd, msg, wParam, lParam, &result, proc->procW );
3130     else
3131         WINPROC_CallProc32ATo16( call_window_proc16, hwnd, msg, wParam, lParam, &result, proc->proc16 );
3132     return result;
3133 }
3134
3135
3136 /**********************************************************************
3137  *              CallWindowProcW (USER32.@)
3138  *
3139  * See CallWindowProcA.
3140  */
3141 LRESULT WINAPI CallWindowProcW( WNDPROC func, HWND hwnd, UINT msg,
3142                                   WPARAM wParam, LPARAM lParam )
3143 {
3144     WINDOWPROC *proc;
3145     LRESULT result;
3146
3147     if (!func) return 0;
3148
3149     if (!(proc = handle_to_proc( func )))
3150         call_window_proc( hwnd, msg, wParam, lParam, &result, func );
3151     else if (proc->procW)
3152         call_window_proc( hwnd, msg, wParam, lParam, &result, proc->procW );
3153     else if (proc->procA)
3154         WINPROC_CallProcWtoA( call_window_proc, hwnd, msg, wParam, lParam, &result, proc->procA );
3155     else
3156         WINPROC_CallProc32WTo16( call_window_proc16, hwnd, msg, wParam, lParam, &result, proc->proc16 );
3157     return result;
3158 }
3159
3160
3161 /**********************************************************************
3162  *              WINPROC_CallDlgProc16
3163  */
3164 INT_PTR WINPROC_CallDlgProc16( DLGPROC16 func, HWND16 hwnd, UINT16 msg, WPARAM16 wParam, LPARAM lParam )
3165 {
3166     WINDOWPROC *proc;
3167     LRESULT result;
3168     INT_PTR ret;
3169
3170     if (!func) return 0;
3171
3172     if (!(proc = handle16_to_proc( (WNDPROC16)func )))
3173     {
3174         ret = call_dialog_proc16( hwnd, msg, wParam, lParam, &result, func );
3175     }
3176     else if (proc->procA)
3177     {
3178         ret = WINPROC_CallProc16To32A( call_dialog_proc, hwnd, msg, wParam, lParam,
3179                                        &result, proc->procA );
3180         SetWindowLongPtrW( WIN_Handle32(hwnd), DWLP_MSGRESULT, result );
3181     }
3182     else if (proc->procW)
3183     {
3184         ret = WINPROC_CallProc16To32W( call_dialog_proc, hwnd, msg, wParam, lParam,
3185                                        &result, proc->procW );
3186         SetWindowLongPtrW( WIN_Handle32(hwnd), DWLP_MSGRESULT, result );
3187     }
3188     else
3189     {
3190         ret = call_dialog_proc16( hwnd, msg, wParam, lParam, &result, proc->proc16 );
3191     }
3192     return ret;
3193 }
3194
3195
3196 /**********************************************************************
3197  *              WINPROC_CallDlgProcA
3198  */
3199 INT_PTR WINPROC_CallDlgProcA( DLGPROC func, HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam )
3200 {
3201     WINDOWPROC *proc;
3202     LRESULT result;
3203     INT_PTR ret;
3204
3205     if (!func) return 0;
3206
3207     if (!(proc = handle_to_proc( (WNDPROC)func )))
3208         ret = call_dialog_proc( hwnd, msg, wParam, lParam, &result, func );
3209     else if (proc->procA)
3210         ret = call_dialog_proc( hwnd, msg, wParam, lParam, &result, proc->procA );
3211     else if (proc->procW)
3212     {
3213         ret = WINPROC_CallProcAtoW( call_dialog_proc, hwnd, msg, wParam, lParam, &result, proc->procW );
3214         SetWindowLongPtrW( hwnd, DWLP_MSGRESULT, result );
3215     }
3216     else
3217     {
3218         ret = WINPROC_CallProc32ATo16( call_dialog_proc16, hwnd, msg, wParam, lParam, &result, proc->proc16 );
3219         SetWindowLongPtrW( hwnd, DWLP_MSGRESULT, result );
3220     }
3221     return ret;
3222 }
3223
3224
3225 /**********************************************************************
3226  *              WINPROC_CallDlgProcW
3227  */
3228 INT_PTR WINPROC_CallDlgProcW( DLGPROC func, HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam )
3229 {
3230     WINDOWPROC *proc;
3231     LRESULT result;
3232     INT_PTR ret;
3233
3234     if (!func) return 0;
3235
3236     if (!(proc = handle_to_proc( (WNDPROC)func )))
3237         ret = call_dialog_proc( hwnd, msg, wParam, lParam, &result, func );
3238     else if (proc->procW)
3239         ret = call_dialog_proc( hwnd, msg, wParam, lParam, &result, proc->procW );
3240     else if (proc->procA)
3241     {
3242         ret = WINPROC_CallProcWtoA( call_dialog_proc, hwnd, msg, wParam, lParam, &result, proc->procA );
3243         SetWindowLongPtrW( hwnd, DWLP_MSGRESULT, result );
3244     }
3245     else
3246     {
3247         ret = WINPROC_CallProc32WTo16( call_dialog_proc16, hwnd, msg, wParam, lParam, &result, proc->proc16 );
3248         SetWindowLongPtrW( hwnd, DWLP_MSGRESULT, result );
3249     }
3250     return ret;
3251 }