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