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