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