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