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