wininet/tests: Don't crash on W2K and below.
[wine] / dlls / user32 / 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
20  */
21
22 #include "config.h"
23 #include "wine/port.h"
24
25 #include <assert.h>
26 #include <stdarg.h>
27 #include <string.h>
28
29 #include "windef.h"
30 #include "winbase.h"
31 #include "wownt32.h"
32 #include "wine/winbase16.h"
33 #include "wine/winuser16.h"
34 #include "controls.h"
35 #include "win.h"
36 #include "user_private.h"
37 #include "dde.h"
38 #include "winternl.h"
39 #include "wine/unicode.h"
40 #include "wine/debug.h"
41
42 WINE_DECLARE_DEBUG_CHANNEL(msg);
43 WINE_DECLARE_DEBUG_CHANNEL(relay);
44 WINE_DEFAULT_DEBUG_CHANNEL(win);
45
46 typedef struct tagWINDOWPROC
47 {
48     WNDPROC16      proc16;   /* 16-bit window proc */
49     WNDPROC        procA;    /* ASCII window proc */
50     WNDPROC        procW;    /* Unicode window proc */
51 } WINDOWPROC;
52
53 #define WINPROC_HANDLE (~0UL >> 16)
54 #define MAX_WINPROCS  8192
55 #define BUILTIN_WINPROCS 9  /* first BUILTIN_WINPROCS entries are reserved for builtin procs */
56 #define MAX_WINPROC_RECURSION  64
57
58 WNDPROC EDIT_winproc_handle = 0;
59
60 static WINDOWPROC winproc_array[MAX_WINPROCS];
61 static UINT builtin_used;
62 static UINT winproc_used = BUILTIN_WINPROCS;
63
64 static CRITICAL_SECTION winproc_cs;
65 static CRITICAL_SECTION_DEBUG critsect_debug =
66 {
67     0, 0, &winproc_cs,
68     { &critsect_debug.ProcessLocksList, &critsect_debug.ProcessLocksList },
69       0, 0, { (DWORD_PTR)(__FILE__ ": winproc_cs") }
70 };
71 static CRITICAL_SECTION winproc_cs = { &critsect_debug, -1, 0, 0, 0, 0 };
72
73 static inline void *get_buffer( void *static_buffer, size_t size, size_t need )
74 {
75     if (size >= need) return static_buffer;
76     return HeapAlloc( GetProcessHeap(), 0, need );
77 }
78
79 static inline void free_buffer( void *static_buffer, void *buffer )
80 {
81     if (buffer != static_buffer) HeapFree( GetProcessHeap(), 0, buffer );
82 }
83
84 /* find an existing winproc for a given 16-bit function and type */
85 /* FIXME: probably should do something more clever than a linear search */
86 static inline WINDOWPROC *find_winproc16( WNDPROC16 func )
87 {
88     unsigned int i;
89
90     for (i = BUILTIN_WINPROCS; i < winproc_used; i++)
91     {
92         if (winproc_array[i].proc16 == func) return &winproc_array[i];
93     }
94     return NULL;
95 }
96
97 /* find an existing winproc for a given function and type */
98 /* FIXME: probably should do something more clever than a linear search */
99 static inline WINDOWPROC *find_winproc( WNDPROC funcA, WNDPROC funcW )
100 {
101     unsigned int i;
102
103     for (i = 0; i < builtin_used; i++)
104     {
105         /* match either proc, some apps confuse A and W */
106         if (funcA && winproc_array[i].procA != funcA && winproc_array[i].procW != funcA) continue;
107         if (funcW && winproc_array[i].procA != funcW && winproc_array[i].procW != funcW) continue;
108         return &winproc_array[i];
109     }
110     for (i = BUILTIN_WINPROCS; i < winproc_used; i++)
111     {
112         if (funcA && winproc_array[i].procA != funcA) continue;
113         if (funcW && winproc_array[i].procW != funcW) continue;
114         return &winproc_array[i];
115     }
116     return NULL;
117 }
118
119 /* return the window proc for a given handle, or NULL for an invalid handle */
120 static inline WINDOWPROC *handle_to_proc( WNDPROC handle )
121 {
122     UINT index = LOWORD(handle);
123     if ((ULONG_PTR)handle >> 16 != WINPROC_HANDLE) return NULL;
124     if (index >= winproc_used) return NULL;
125     return &winproc_array[index];
126 }
127
128 /* create a handle for a given window proc */
129 static inline WNDPROC proc_to_handle( WINDOWPROC *proc )
130 {
131     return (WNDPROC)(ULONG_PTR)((proc - winproc_array) | (WINPROC_HANDLE << 16));
132 }
133
134 /* allocate and initialize a new winproc */
135 static inline WINDOWPROC *alloc_winproc( WNDPROC funcA, WNDPROC funcW )
136 {
137     WINDOWPROC *proc;
138
139     /* check if the function is already a win proc */
140     if (funcA && (proc = handle_to_proc( funcA ))) return proc;
141     if (funcW && (proc = handle_to_proc( funcW ))) return proc;
142     if (!funcA && !funcW) return NULL;
143
144     EnterCriticalSection( &winproc_cs );
145
146     /* check if we already have a winproc for that function */
147     if (!(proc = find_winproc( funcA, funcW )))
148     {
149         if (funcA && funcW)
150         {
151             assert( builtin_used < BUILTIN_WINPROCS );
152             proc = &winproc_array[builtin_used++];
153             proc->procA = funcA;
154             proc->procW = funcW;
155             TRACE( "allocated %p for builtin %p/%p (%d/%d used)\n",
156                    proc_to_handle(proc), funcA, funcW, builtin_used, BUILTIN_WINPROCS );
157         }
158         else if (winproc_used < MAX_WINPROCS)
159         {
160             proc = &winproc_array[winproc_used++];
161             proc->procA = funcA;
162             proc->procW = funcW;
163             TRACE( "allocated %p for %c %p (%d/%d used)\n",
164                    proc_to_handle(proc), funcA ? 'A' : 'W', funcA ? funcA : funcW,
165                    winproc_used, MAX_WINPROCS );
166         }
167         else FIXME( "too many winprocs, cannot allocate one for %p/%p\n", funcA, funcW );
168     }
169     else TRACE( "reusing %p for %p/%p\n", proc_to_handle(proc), funcA, funcW );
170
171     LeaveCriticalSection( &winproc_cs );
172     return proc;
173 }
174
175
176 #ifdef __i386__
177
178 #include "pshpack1.h"
179
180 /* Window procedure 16-to-32-bit thunk */
181 typedef struct
182 {
183     BYTE        popl_eax;        /* popl  %eax (return address) */
184     BYTE        pushl_func;      /* pushl $proc */
185     WINDOWPROC *proc;
186     BYTE        pushl_eax;       /* pushl %eax */
187     BYTE        ljmp;            /* ljmp relay*/
188     DWORD       relay_offset;    /* __wine_call_wndproc */
189     WORD        relay_sel;
190 } WINPROC_THUNK;
191
192 #include "poppack.h"
193
194 #define MAX_THUNKS  (0x10000 / sizeof(WINPROC_THUNK))
195
196 static WINPROC_THUNK *thunk_array;
197 static UINT thunk_selector;
198 static UINT thunk_used;
199
200 /* return the window proc for a given handle, or NULL for an invalid handle */
201 static inline WINDOWPROC *handle16_to_proc( WNDPROC16 handle )
202 {
203     if (HIWORD(handle) == thunk_selector)
204     {
205         UINT index = LOWORD(handle) / sizeof(WINPROC_THUNK);
206         /* check alignment */
207         if (index * sizeof(WINPROC_THUNK) != LOWORD(handle)) return NULL;
208         /* check array limits */
209         if (index >= thunk_used) return NULL;
210         return thunk_array[index].proc;
211     }
212     return handle_to_proc( (WNDPROC)handle );
213 }
214
215 /* allocate a 16-bit thunk for an existing window proc */
216 static WNDPROC16 alloc_win16_thunk( WINDOWPROC *proc )
217 {
218     static FARPROC16 relay;
219     UINT i;
220
221     if (proc->proc16) return proc->proc16;
222
223     EnterCriticalSection( &winproc_cs );
224
225     if (!thunk_array)  /* allocate the array and its selector */
226     {
227         LDT_ENTRY entry;
228
229         if (!(thunk_selector = wine_ldt_alloc_entries(1))) goto done;
230         if (!(thunk_array = VirtualAlloc( NULL, MAX_THUNKS * sizeof(WINPROC_THUNK), MEM_COMMIT,
231                                           PAGE_EXECUTE_READWRITE ))) goto done;
232         wine_ldt_set_base( &entry, thunk_array );
233         wine_ldt_set_limit( &entry, MAX_THUNKS * sizeof(WINPROC_THUNK) - 1 );
234         wine_ldt_set_flags( &entry, WINE_LDT_FLAGS_CODE | WINE_LDT_FLAGS_32BIT );
235         wine_ldt_set_entry( thunk_selector, &entry );
236         relay = GetProcAddress16( GetModuleHandle16("user"), "__wine_call_wndproc" );
237     }
238
239     /* check if it already exists */
240     for (i = 0; i < thunk_used; i++) if (thunk_array[i].proc == proc) break;
241
242     if (i == thunk_used)  /* create a new one */
243     {
244         WINPROC_THUNK *thunk;
245
246         if (thunk_used >= MAX_THUNKS) goto done;
247         thunk = &thunk_array[thunk_used++];
248         thunk->popl_eax     = 0x58;   /* popl  %eax */
249         thunk->pushl_func   = 0x68;   /* pushl $proc */
250         thunk->proc         = proc;
251         thunk->pushl_eax    = 0x50;   /* pushl %eax */
252         thunk->ljmp         = 0xea;   /* ljmp   relay*/
253         thunk->relay_offset = OFFSETOF(relay);
254         thunk->relay_sel    = SELECTOROF(relay);
255     }
256     proc->proc16 = (WNDPROC16)MAKESEGPTR( thunk_selector, i * sizeof(WINPROC_THUNK) );
257 done:
258     LeaveCriticalSection( &winproc_cs );
259     return proc->proc16;
260 }
261
262 #else  /* __i386__ */
263
264 static inline WINDOWPROC *handle16_to_proc( WNDPROC16 handle )
265 {
266     return handle_to_proc( (WNDPROC)handle );
267 }
268
269 static inline WNDPROC16 alloc_win16_thunk( WINDOWPROC *proc )
270 {
271     return 0;
272 }
273
274 #endif  /* __i386__ */
275
276
277 #ifdef __i386__
278 /* Some window procedures modify register they shouldn't, or are not
279  * properly declared stdcall; so we need a small assembly wrapper to
280  * call them. */
281 extern LRESULT WINPROC_wrapper( WNDPROC proc, HWND hwnd, UINT msg,
282                                 WPARAM wParam, LPARAM lParam );
283 __ASM_GLOBAL_FUNC( WINPROC_wrapper,
284                    "pushl %ebp\n\t"
285                    "movl %esp,%ebp\n\t"
286                    "pushl %edi\n\t"
287                    "pushl %esi\n\t"
288                    "pushl %ebx\n\t"
289                    "subl $12,%esp\n\t"
290                    "pushl 24(%ebp)\n\t"
291                    "pushl 20(%ebp)\n\t"
292                    "pushl 16(%ebp)\n\t"
293                    "pushl 12(%ebp)\n\t"
294                    "movl 8(%ebp),%eax\n\t"
295                    "call *%eax\n\t"
296                    "leal -12(%ebp),%esp\n\t"
297                    "popl %ebx\n\t"
298                    "popl %esi\n\t"
299                    "popl %edi\n\t"
300                    "leave\n\t"
301                    "ret" )
302 #else
303 static inline LRESULT WINPROC_wrapper( WNDPROC proc, HWND hwnd, UINT msg,
304                                        WPARAM wParam, LPARAM lParam )
305 {
306     return proc( hwnd, msg, wParam, lParam );
307 }
308 #endif  /* __i386__ */
309
310 static void RECT16to32( const RECT16 *from, RECT *to )
311 {
312     to->left   = from->left;
313     to->top    = from->top;
314     to->right  = from->right;
315     to->bottom = from->bottom;
316 }
317
318 static void RECT32to16( const RECT *from, RECT16 *to )
319 {
320     to->left   = from->left;
321     to->top    = from->top;
322     to->right  = from->right;
323     to->bottom = from->bottom;
324 }
325
326 static void MINMAXINFO32to16( const MINMAXINFO *from, MINMAXINFO16 *to )
327 {
328     to->ptReserved.x     = from->ptReserved.x;
329     to->ptReserved.y     = from->ptReserved.y;
330     to->ptMaxSize.x      = from->ptMaxSize.x;
331     to->ptMaxSize.y      = from->ptMaxSize.y;
332     to->ptMaxPosition.x  = from->ptMaxPosition.x;
333     to->ptMaxPosition.y  = from->ptMaxPosition.y;
334     to->ptMinTrackSize.x = from->ptMinTrackSize.x;
335     to->ptMinTrackSize.y = from->ptMinTrackSize.y;
336     to->ptMaxTrackSize.x = from->ptMaxTrackSize.x;
337     to->ptMaxTrackSize.y = from->ptMaxTrackSize.y;
338 }
339
340 static void MINMAXINFO16to32( const MINMAXINFO16 *from, MINMAXINFO *to )
341 {
342     to->ptReserved.x     = from->ptReserved.x;
343     to->ptReserved.y     = from->ptReserved.y;
344     to->ptMaxSize.x      = from->ptMaxSize.x;
345     to->ptMaxSize.y      = from->ptMaxSize.y;
346     to->ptMaxPosition.x  = from->ptMaxPosition.x;
347     to->ptMaxPosition.y  = from->ptMaxPosition.y;
348     to->ptMinTrackSize.x = from->ptMinTrackSize.x;
349     to->ptMinTrackSize.y = from->ptMinTrackSize.y;
350     to->ptMaxTrackSize.x = from->ptMaxTrackSize.x;
351     to->ptMaxTrackSize.y = from->ptMaxTrackSize.y;
352 }
353
354 static void WINDOWPOS32to16( const WINDOWPOS* from, WINDOWPOS16* to )
355 {
356     to->hwnd            = HWND_16(from->hwnd);
357     to->hwndInsertAfter = HWND_16(from->hwndInsertAfter);
358     to->x               = from->x;
359     to->y               = from->y;
360     to->cx              = from->cx;
361     to->cy              = from->cy;
362     to->flags           = from->flags;
363 }
364
365 static void WINDOWPOS16to32( const WINDOWPOS16* from, WINDOWPOS* to )
366 {
367     to->hwnd            = WIN_Handle32(from->hwnd);
368     to->hwndInsertAfter = (from->hwndInsertAfter == (HWND16)-1) ?
369                            HWND_TOPMOST : WIN_Handle32(from->hwndInsertAfter);
370     to->x               = from->x;
371     to->y               = from->y;
372     to->cx              = from->cx;
373     to->cy              = from->cy;
374     to->flags           = from->flags;
375 }
376
377 /* The strings are not copied */
378 static void CREATESTRUCT32Ato16( const CREATESTRUCTA* from, CREATESTRUCT16* to )
379 {
380     to->lpCreateParams = (SEGPTR)from->lpCreateParams;
381     to->hInstance      = HINSTANCE_16(from->hInstance);
382     to->hMenu          = HMENU_16(from->hMenu);
383     to->hwndParent     = HWND_16(from->hwndParent);
384     to->cy             = from->cy;
385     to->cx             = from->cx;
386     to->y              = from->y;
387     to->x              = from->x;
388     to->style          = from->style;
389     to->dwExStyle      = from->dwExStyle;
390 }
391
392 static void CREATESTRUCT16to32A( const CREATESTRUCT16* from, CREATESTRUCTA *to )
393
394 {
395     to->lpCreateParams = (LPVOID)from->lpCreateParams;
396     to->hInstance      = HINSTANCE_32(from->hInstance);
397     to->hMenu          = HMENU_32(from->hMenu);
398     to->hwndParent     = WIN_Handle32(from->hwndParent);
399     to->cy             = from->cy;
400     to->cx             = from->cx;
401     to->y              = from->y;
402     to->x              = from->x;
403     to->style          = from->style;
404     to->dwExStyle      = from->dwExStyle;
405     to->lpszName       = MapSL(from->lpszName);
406     to->lpszClass      = MapSL(from->lpszClass);
407 }
408
409 /* The strings are not copied */
410 static void MDICREATESTRUCT32Ato16( const MDICREATESTRUCTA* from, MDICREATESTRUCT16* to )
411 {
412     to->hOwner = HINSTANCE_16(from->hOwner);
413     to->x      = from->x;
414     to->y      = from->y;
415     to->cx     = from->cx;
416     to->cy     = from->cy;
417     to->style  = from->style;
418     to->lParam = from->lParam;
419 }
420
421 static void MDICREATESTRUCT16to32A( const MDICREATESTRUCT16* from, MDICREATESTRUCTA *to )
422 {
423     to->hOwner = HINSTANCE_32(from->hOwner);
424     to->x      = from->x;
425     to->y      = from->y;
426     to->cx     = from->cx;
427     to->cy     = from->cy;
428     to->style  = from->style;
429     to->lParam = from->lParam;
430     to->szTitle = MapSL(from->szTitle);
431     to->szClass = MapSL(from->szClass);
432 }
433
434 static WPARAM map_wparam_char_WtoA( WPARAM wParam, DWORD len )
435 {
436     WCHAR wch = wParam;
437     BYTE ch[2];
438
439     RtlUnicodeToMultiByteN( (LPSTR)ch, len, &len, &wch, sizeof(wch) );
440     if (len == 2)
441         return MAKEWPARAM( (ch[0] << 8) | ch[1], HIWORD(wParam) );
442     else
443         return MAKEWPARAM( ch[0], HIWORD(wParam) );
444 }
445
446 /* call a 32-bit window procedure */
447 static LRESULT call_window_proc( HWND hwnd, UINT msg, WPARAM wp, LPARAM lp, LRESULT *result, void *arg )
448 {
449     WNDPROC proc = arg;
450
451     USER_CheckNotLock();
452
453     hwnd = WIN_GetFullHandle( hwnd );
454     if (TRACE_ON(relay))
455         DPRINTF( "%04x:Call window proc %p (hwnd=%p,msg=%s,wp=%08lx,lp=%08lx)\n",
456                  GetCurrentThreadId(), proc, hwnd, SPY_GetMsgName(msg, hwnd), wp, lp );
457
458     *result = WINPROC_wrapper( proc, hwnd, msg, wp, lp );
459
460     if (TRACE_ON(relay))
461         DPRINTF( "%04x:Ret  window proc %p (hwnd=%p,msg=%s,wp=%08lx,lp=%08lx) retval=%08lx\n",
462                  GetCurrentThreadId(), proc, hwnd, SPY_GetMsgName(msg, hwnd), wp, lp, *result );
463     return *result;
464 }
465
466 /* call a 32-bit dialog procedure */
467 static LRESULT call_dialog_proc( HWND hwnd, UINT msg, WPARAM wp, LPARAM lp, LRESULT *result, void *arg )
468 {
469     WNDPROC proc = arg;
470     LRESULT ret;
471
472     USER_CheckNotLock();
473
474     hwnd = WIN_GetFullHandle( hwnd );
475     if (TRACE_ON(relay))
476         DPRINTF( "%04x:Call dialog proc %p (hwnd=%p,msg=%s,wp=%08lx,lp=%08lx)\n",
477                  GetCurrentThreadId(), proc, hwnd, SPY_GetMsgName(msg, hwnd), wp, lp );
478
479     ret = WINPROC_wrapper( proc, hwnd, msg, wp, lp );
480     *result = GetWindowLongPtrW( hwnd, DWLP_MSGRESULT );
481
482     if (TRACE_ON(relay))
483         DPRINTF( "%04x:Ret  dialog proc %p (hwnd=%p,msg=%s,wp=%08lx,lp=%08lx) retval=%08lx result=%08lx\n",
484                  GetCurrentThreadId(), proc, hwnd, SPY_GetMsgName(msg, hwnd), wp, lp, ret, *result );
485     return ret;
486 }
487
488 /* call a 16-bit window procedure */
489 static LRESULT call_window_proc16( HWND16 hwnd, UINT16 msg, WPARAM16 wParam, LPARAM lParam,
490                                    LRESULT *result, void *arg )
491 {
492     WNDPROC16 proc = arg;
493     CONTEXT86 context;
494     size_t size = 0;
495     struct
496     {
497         WORD params[5];
498         union
499         {
500             CREATESTRUCT16 cs16;
501             DRAWITEMSTRUCT16 dis16;
502             COMPAREITEMSTRUCT16 cis16;
503         } u;
504     } args;
505
506     USER_CheckNotLock();
507
508     /* Window procedures want ax = hInstance, ds = es = ss */
509
510     memset(&context, 0, sizeof(context));
511     context.SegDs = context.SegEs = SELECTOROF(NtCurrentTeb()->WOW32Reserved);
512     context.SegFs = wine_get_fs();
513     context.SegGs = wine_get_gs();
514     if (!(context.Eax = GetWindowWord( HWND_32(hwnd), GWLP_HINSTANCE ))) context.Eax = context.SegDs;
515     context.SegCs = SELECTOROF(proc);
516     context.Eip   = OFFSETOF(proc);
517     context.Ebp   = OFFSETOF(NtCurrentTeb()->WOW32Reserved) + FIELD_OFFSET(STACK16FRAME, bp);
518
519     if (lParam)
520     {
521         /* Some programs (eg. the "Undocumented Windows" examples, JWP) only
522            work if structures passed in lParam are placed in the stack/data
523            segment. Programmers easily make the mistake of converting lParam
524            to a near rather than a far pointer, since Windows apparently
525            allows this. We copy the structures to the 16 bit stack; this is
526            ugly but makes these programs work. */
527         switch (msg)
528         {
529           case WM_CREATE:
530           case WM_NCCREATE:
531             size = sizeof(CREATESTRUCT16); break;
532           case WM_DRAWITEM:
533             size = sizeof(DRAWITEMSTRUCT16); break;
534           case WM_COMPAREITEM:
535             size = sizeof(COMPAREITEMSTRUCT16); break;
536         }
537         if (size)
538         {
539             memcpy( &args.u, MapSL(lParam), size );
540             lParam = PtrToUlong(NtCurrentTeb()->WOW32Reserved) - size;
541         }
542     }
543
544     args.params[4] = hwnd;
545     args.params[3] = msg;
546     args.params[2] = wParam;
547     args.params[1] = HIWORD(lParam);
548     args.params[0] = LOWORD(lParam);
549     WOWCallback16Ex( 0, WCB16_REGS, sizeof(args.params) + size, &args, (DWORD *)&context );
550     *result = MAKELONG( LOWORD(context.Eax), LOWORD(context.Edx) );
551     return *result;
552 }
553
554 /* call a 16-bit dialog procedure */
555 static LRESULT call_dialog_proc16( HWND16 hwnd, UINT16 msg, WPARAM16 wp, LPARAM lp,
556                                    LRESULT *result, void *arg )
557 {
558     LRESULT ret = call_window_proc16( hwnd, msg, wp, lp, result, arg );
559     *result = GetWindowLongPtrW( WIN_Handle32(hwnd), DWLP_MSGRESULT );
560     return LOWORD(ret);
561 }
562
563 /* helper callback for 32W->16 conversion */
564 static LRESULT call_window_proc_Ato16( HWND hwnd, UINT msg, WPARAM wp, LPARAM lp,
565                                        LRESULT *result, void *arg )
566 {
567     return WINPROC_CallProc32ATo16( call_window_proc16, hwnd, msg, wp, lp, result, arg );
568 }
569
570 /* helper callback for 32W->16 conversion */
571 static LRESULT call_dialog_proc_Ato16( HWND hwnd, UINT msg, WPARAM wp, LPARAM lp,
572                                        LRESULT *result, void *arg )
573 {
574     return WINPROC_CallProc32ATo16( call_dialog_proc16, hwnd, msg, wp, lp, result, arg );
575 }
576
577 /* helper callback for 16->32W conversion */
578 static LRESULT call_window_proc_AtoW( HWND hwnd, UINT msg, WPARAM wp, LPARAM lp,
579                                       LRESULT *result, void *arg )
580 {
581     return WINPROC_CallProcAtoW( call_window_proc, hwnd, msg, wp, lp, result,
582                                  arg, WMCHAR_MAP_CALLWINDOWPROC );
583 }
584
585 /* helper callback for 16->32W conversion */
586 static LRESULT call_dialog_proc_AtoW( HWND hwnd, UINT msg, WPARAM wp, LPARAM lp,
587                                       LRESULT *result, void *arg )
588 {
589     return WINPROC_CallProcAtoW( call_dialog_proc, hwnd, msg, wp, lp, result,
590                                  arg, WMCHAR_MAP_CALLWINDOWPROC );
591 }
592
593
594 /**********************************************************************
595  *           WINPROC_GetProc16
596  *
597  * Get a window procedure pointer that can be passed to the Windows program.
598  */
599 WNDPROC16 WINPROC_GetProc16( WNDPROC proc, BOOL unicode )
600 {
601     WINDOWPROC *ptr;
602
603     if (unicode) ptr = alloc_winproc( NULL, proc );
604     else ptr = alloc_winproc( proc, NULL );
605
606     if (!ptr) return 0;
607     return alloc_win16_thunk( ptr );
608 }
609
610
611 /**********************************************************************
612  *           WINPROC_GetProc
613  *
614  * Get a window procedure pointer that can be passed to the Windows program.
615  */
616 WNDPROC WINPROC_GetProc( WNDPROC proc, BOOL unicode )
617 {
618     WINDOWPROC *ptr = handle_to_proc( proc );
619
620     if (!ptr) return proc;
621     if (unicode)
622     {
623         if (ptr->procW) return ptr->procW;
624         return proc;
625     }
626     else
627     {
628         if (ptr->procA) return ptr->procA;
629         return proc;
630     }
631 }
632
633
634 /**********************************************************************
635  *           WINPROC_AllocProc16
636  *
637  * Allocate a window procedure for a window or class.
638  *
639  * Note that allocated winprocs are never freed; the idea is that even if an app creates a
640  * lot of windows, it will usually only have a limited number of window procedures, so the
641  * array won't grow too large, and this way we avoid the need to track allocations per window.
642  */
643 WNDPROC WINPROC_AllocProc16( WNDPROC16 func )
644 {
645     WINDOWPROC *proc;
646
647     if (!func) return NULL;
648
649     /* check if the function is already a win proc */
650     if (!(proc = handle16_to_proc( func )))
651     {
652         EnterCriticalSection( &winproc_cs );
653
654         /* then check if we already have a winproc for that function */
655         if (!(proc = find_winproc16( func )))
656         {
657             if (winproc_used < MAX_WINPROCS)
658             {
659                 proc = &winproc_array[winproc_used++];
660                 proc->proc16 = func;
661                 TRACE( "allocated %p for %p/16-bit (%d/%d used)\n",
662                        proc_to_handle(proc), func, winproc_used, MAX_WINPROCS );
663             }
664             else FIXME( "too many winprocs, cannot allocate one for 16-bit %p\n", func );
665         }
666         else TRACE( "reusing %p for %p/16-bit\n", proc_to_handle(proc), func );
667
668         LeaveCriticalSection( &winproc_cs );
669     }
670     return proc_to_handle( proc );
671 }
672
673
674 /**********************************************************************
675  *           WINPROC_AllocProc
676  *
677  * Allocate a window procedure for a window or class.
678  *
679  * Note that allocated winprocs are never freed; the idea is that even if an app creates a
680  * lot of windows, it will usually only have a limited number of window procedures, so the
681  * array won't grow too large, and this way we avoid the need to track allocations per window.
682  */
683 WNDPROC WINPROC_AllocProc( WNDPROC funcA, WNDPROC funcW )
684 {
685     WINDOWPROC *proc;
686
687     if (!(proc = alloc_winproc( funcA, funcW ))) return NULL;
688     return proc_to_handle( proc );
689 }
690
691
692 /**********************************************************************
693  *           WINPROC_IsUnicode
694  *
695  * Return the window procedure type, or the default value if not a winproc handle.
696  */
697 BOOL WINPROC_IsUnicode( WNDPROC proc, BOOL def_val )
698 {
699     WINDOWPROC *ptr = handle_to_proc( proc );
700
701     if (!ptr) return def_val;
702     if (ptr->procA && ptr->procW) return def_val;  /* can be both */
703     return (ptr->procW != NULL);
704 }
705
706
707 /**********************************************************************
708  *           WINPROC_TestLBForStr
709  *
710  * Return TRUE if the lparam is a string
711  */
712 static inline BOOL WINPROC_TestLBForStr( HWND hwnd, UINT msg )
713 {
714     DWORD style = GetWindowLongA( hwnd, GWL_STYLE );
715     if (msg <= CB_MSGMAX)
716         return (!(style & (CBS_OWNERDRAWFIXED | CBS_OWNERDRAWVARIABLE)) || (style & CBS_HASSTRINGS));
717     else
718         return (!(style & (LBS_OWNERDRAWFIXED | LBS_OWNERDRAWVARIABLE)) || (style & LBS_HASSTRINGS));
719
720 }
721
722
723 static UINT_PTR convert_handle_16_to_32(HANDLE16 src, unsigned int flags)
724 {
725     HANDLE      dst;
726     UINT        sz = GlobalSize16(src);
727     LPSTR       ptr16, ptr32;
728
729     if (!(dst = GlobalAlloc(flags, sz)))
730         return 0;
731     ptr16 = GlobalLock16(src);
732     ptr32 = GlobalLock(dst);
733     if (ptr16 != NULL && ptr32 != NULL) memcpy(ptr32, ptr16, sz);
734     GlobalUnlock16(src);
735     GlobalUnlock(dst);
736
737     return (UINT_PTR)dst;
738 }
739
740 static HANDLE16 convert_handle_32_to_16(UINT_PTR src, unsigned int flags)
741 {
742     HANDLE16    dst;
743     UINT        sz = GlobalSize((HANDLE)src);
744     LPSTR       ptr16, ptr32;
745
746     if (!(dst = GlobalAlloc16(flags, sz)))
747         return 0;
748     ptr32 = GlobalLock((HANDLE)src);
749     ptr16 = GlobalLock16(dst);
750     if (ptr16 != NULL && ptr32 != NULL) memcpy(ptr16, ptr32, sz);
751     GlobalUnlock((HANDLE)src);
752     GlobalUnlock16(dst);
753
754     return dst;
755 }
756
757
758 /**********************************************************************
759  *           WINPROC_CallProcAtoW
760  *
761  * Call a window procedure, translating args from Ansi to Unicode.
762  */
763 LRESULT WINPROC_CallProcAtoW( winproc_callback_t callback, HWND hwnd, UINT msg, WPARAM wParam,
764                               LPARAM lParam, LRESULT *result, void *arg, enum wm_char_mapping mapping )
765 {
766     LRESULT ret = 0;
767
768     TRACE_(msg)("(hwnd=%p,msg=%s,wp=%08lx,lp=%08lx)\n",
769                 hwnd, SPY_GetMsgName(msg, hwnd), wParam, lParam);
770
771     switch(msg)
772     {
773     case WM_NCCREATE:
774     case WM_CREATE:
775         {
776             WCHAR *ptr, buffer[512];
777             CREATESTRUCTA *csA = (CREATESTRUCTA *)lParam;
778             CREATESTRUCTW csW = *(CREATESTRUCTW *)csA;
779             MDICREATESTRUCTW mdi_cs;
780             DWORD name_lenA = 0, name_lenW = 0, class_lenA = 0, class_lenW = 0;
781
782             if (!IS_INTRESOURCE(csA->lpszClass))
783             {
784                 class_lenA = strlen(csA->lpszClass) + 1;
785                 RtlMultiByteToUnicodeSize( &class_lenW, csA->lpszClass, class_lenA );
786             }
787             if (!IS_INTRESOURCE(csA->lpszName))
788             {
789                 name_lenA = strlen(csA->lpszName) + 1;
790                 RtlMultiByteToUnicodeSize( &name_lenW, csA->lpszName, name_lenA );
791             }
792
793             if (!(ptr = get_buffer( buffer, sizeof(buffer), class_lenW + name_lenW ))) break;
794
795             if (class_lenW)
796             {
797                 csW.lpszClass = ptr;
798                 RtlMultiByteToUnicodeN( ptr, class_lenW, NULL, csA->lpszClass, class_lenA );
799             }
800             if (name_lenW)
801             {
802                 csW.lpszName = ptr + class_lenW/sizeof(WCHAR);
803                 RtlMultiByteToUnicodeN( ptr + class_lenW/sizeof(WCHAR), name_lenW, NULL,
804                                         csA->lpszName, name_lenA );
805             }
806
807             if (GetWindowLongW(hwnd, GWL_EXSTYLE) & WS_EX_MDICHILD)
808             {
809                 mdi_cs = *(MDICREATESTRUCTW *)csA->lpCreateParams;
810                 mdi_cs.szTitle = csW.lpszName;
811                 mdi_cs.szClass = csW.lpszClass;
812                 csW.lpCreateParams = &mdi_cs;
813             }
814
815             ret = callback( hwnd, msg, wParam, (LPARAM)&csW, result, arg );
816             free_buffer( buffer, ptr );
817         }
818         break;
819
820     case WM_MDICREATE:
821         {
822             WCHAR *ptr, buffer[512];
823             DWORD title_lenA = 0, title_lenW = 0, class_lenA = 0, class_lenW = 0;
824             MDICREATESTRUCTA *csA = (MDICREATESTRUCTA *)lParam;
825             MDICREATESTRUCTW csW;
826
827             memcpy( &csW, csA, sizeof(csW) );
828
829             if (!IS_INTRESOURCE(csA->szTitle))
830             {
831                 title_lenA = strlen(csA->szTitle) + 1;
832                 RtlMultiByteToUnicodeSize( &title_lenW, csA->szTitle, title_lenA );
833             }
834             if (!IS_INTRESOURCE(csA->szClass))
835             {
836                 class_lenA = strlen(csA->szClass) + 1;
837                 RtlMultiByteToUnicodeSize( &class_lenW, csA->szClass, class_lenA );
838             }
839
840             if (!(ptr = get_buffer( buffer, sizeof(buffer), title_lenW + class_lenW ))) break;
841
842             if (title_lenW)
843             {
844                 csW.szTitle = ptr;
845                 RtlMultiByteToUnicodeN( ptr, title_lenW, NULL, csA->szTitle, title_lenA );
846             }
847             if (class_lenW)
848             {
849                 csW.szClass = ptr + title_lenW/sizeof(WCHAR);
850                 RtlMultiByteToUnicodeN( ptr + title_lenW/sizeof(WCHAR), class_lenW, NULL,
851                                         csA->szClass, class_lenA );
852             }
853             ret = callback( hwnd, msg, wParam, (LPARAM)&csW, result, arg );
854             free_buffer( buffer, ptr );
855         }
856         break;
857
858     case WM_GETTEXT:
859     case WM_ASKCBFORMATNAME:
860         {
861             WCHAR *ptr, buffer[512];
862             LPSTR str = (LPSTR)lParam;
863             DWORD len = wParam * sizeof(WCHAR);
864
865             if (!(ptr = get_buffer( buffer, sizeof(buffer), len ))) break;
866             ret = callback( hwnd, msg, wParam, (LPARAM)ptr, result, arg );
867             if (wParam)
868             {
869                 len = 0;
870                 if (*result)
871                     RtlUnicodeToMultiByteN( str, wParam - 1, &len, ptr, strlenW(ptr) * sizeof(WCHAR) );
872                 str[len] = 0;
873                 *result = len;
874             }
875             free_buffer( buffer, ptr );
876         }
877         break;
878
879     case LB_ADDSTRING:
880     case LB_INSERTSTRING:
881     case LB_FINDSTRING:
882     case LB_FINDSTRINGEXACT:
883     case LB_SELECTSTRING:
884     case CB_ADDSTRING:
885     case CB_INSERTSTRING:
886     case CB_FINDSTRING:
887     case CB_FINDSTRINGEXACT:
888     case CB_SELECTSTRING:
889         if (!lParam || !WINPROC_TestLBForStr( hwnd, msg ))
890         {
891             ret = callback( hwnd, msg, wParam, lParam, result, arg );
892             break;
893         }
894         /* fall through */
895     case WM_SETTEXT:
896     case WM_WININICHANGE:
897     case WM_DEVMODECHANGE:
898     case CB_DIR:
899     case LB_DIR:
900     case LB_ADDFILE:
901     case EM_REPLACESEL:
902         if (!lParam) ret = callback( hwnd, msg, wParam, lParam, result, arg );
903         else
904         {
905             WCHAR *ptr, buffer[512];
906             LPCSTR strA = (LPCSTR)lParam;
907             DWORD lenW, lenA = strlen(strA) + 1;
908
909             RtlMultiByteToUnicodeSize( &lenW, strA, lenA );
910             if ((ptr = get_buffer( buffer, sizeof(buffer), lenW )))
911             {
912                 RtlMultiByteToUnicodeN( ptr, lenW, NULL, strA, lenA );
913                 ret = callback( hwnd, msg, wParam, (LPARAM)ptr, result, arg );
914                 free_buffer( buffer, ptr );
915             }
916         }
917         break;
918
919     case LB_GETTEXT:
920     case CB_GETLBTEXT:
921         if (lParam && WINPROC_TestLBForStr( hwnd, msg ))
922         {
923             WCHAR buffer[512];  /* FIXME: fixed sized buffer */
924
925             ret = callback( hwnd, msg, wParam, (LPARAM)buffer, result, arg );
926             if (*result >= 0)
927             {
928                 DWORD len;
929                 RtlUnicodeToMultiByteN( (LPSTR)lParam, ~0u, &len,
930                                         buffer, (strlenW(buffer) + 1) * sizeof(WCHAR) );
931                 *result = len - 1;
932             }
933         }
934         else ret = callback( hwnd, msg, wParam, lParam, result, arg );
935         break;
936
937     case EM_GETLINE:
938         {
939             WCHAR *ptr, buffer[512];
940             WORD len = *(WORD *)lParam;
941
942             if (!(ptr = get_buffer( buffer, sizeof(buffer), len * sizeof(WCHAR) ))) break;
943             *((WORD *)ptr) = len;   /* store the length */
944             ret = callback( hwnd, msg, wParam, (LPARAM)ptr, result, arg );
945             if (*result)
946             {
947                 DWORD reslen;
948                 RtlUnicodeToMultiByteN( (LPSTR)lParam, len, &reslen, ptr, *result * sizeof(WCHAR) );
949                 if (reslen < len) ((LPSTR)lParam)[reslen] = 0;
950                 *result = reslen;
951             }
952             free_buffer( buffer, ptr );
953         }
954         break;
955
956     case WM_GETDLGCODE:
957         if (lParam)
958         {
959             MSG newmsg = *(MSG *)lParam;
960             if (map_wparam_AtoW( newmsg.message, &newmsg.wParam, WMCHAR_MAP_NOMAPPING ))
961                 ret = callback( hwnd, msg, wParam, (LPARAM)&newmsg, result, arg );
962         }
963         else ret = callback( hwnd, msg, wParam, lParam, result, arg );
964         break;
965
966     case WM_CHARTOITEM:
967     case WM_MENUCHAR:
968     case WM_CHAR:
969     case WM_DEADCHAR:
970     case WM_SYSCHAR:
971     case WM_SYSDEADCHAR:
972     case EM_SETPASSWORDCHAR:
973     case WM_IME_CHAR:
974         if (map_wparam_AtoW( msg, &wParam, mapping ))
975             ret = callback( hwnd, msg, wParam, lParam, result, arg );
976         break;
977
978     case WM_GETTEXTLENGTH:
979     case CB_GETLBTEXTLEN:
980     case LB_GETTEXTLEN:
981         ret = callback( hwnd, msg, wParam, lParam, result, arg );
982         if (*result >= 0)
983         {
984             WCHAR *ptr, buffer[512];
985             LRESULT tmp;
986             DWORD len = *result + 1;
987             /* Determine respective GETTEXT message */
988             UINT msgGetText = (msg == WM_GETTEXTLENGTH) ? WM_GETTEXT :
989                               ((msg == CB_GETLBTEXTLEN) ? CB_GETLBTEXT : LB_GETTEXT);
990             /* wParam differs between the messages */
991             WPARAM wp = (msg == WM_GETTEXTLENGTH) ? len : wParam;
992
993             if (!(ptr = get_buffer( buffer, sizeof(buffer), len * sizeof(WCHAR) ))) break;
994
995             if (callback == call_window_proc)  /* FIXME: hack */
996                 callback( hwnd, msgGetText, wp, (LPARAM)ptr, &tmp, arg );
997             else
998                 tmp = SendMessageW( hwnd, msgGetText, wp, (LPARAM)ptr );
999             RtlUnicodeToMultiByteSize( &len, ptr, tmp * sizeof(WCHAR) );
1000             *result = len;
1001             free_buffer( buffer, ptr );
1002         }
1003         break;
1004
1005     case WM_PAINTCLIPBOARD:
1006     case WM_SIZECLIPBOARD:
1007         FIXME_(msg)( "message %s (0x%x) needs translation, please report\n",
1008                      SPY_GetMsgName(msg, hwnd), msg );
1009         break;
1010
1011     default:
1012         ret = callback( hwnd, msg, wParam, lParam, result, arg );
1013         break;
1014     }
1015     return ret;
1016 }
1017
1018
1019 /**********************************************************************
1020  *           WINPROC_CallProcWtoA
1021  *
1022  * Call a window procedure, translating args from Unicode to Ansi.
1023  */
1024 static LRESULT WINPROC_CallProcWtoA( winproc_callback_t callback, HWND hwnd, UINT msg, WPARAM wParam,
1025                                      LPARAM lParam, LRESULT *result, void *arg )
1026 {
1027     LRESULT ret = 0;
1028
1029     TRACE_(msg)("(hwnd=%p,msg=%s,wp=%08lx,lp=%08lx)\n",
1030                 hwnd, SPY_GetMsgName(msg, hwnd), wParam, lParam);
1031
1032     switch(msg)
1033     {
1034     case WM_NCCREATE:
1035     case WM_CREATE:
1036         {
1037             char buffer[1024], *cls;
1038             CREATESTRUCTW *csW = (CREATESTRUCTW *)lParam;
1039             CREATESTRUCTA csA = *(CREATESTRUCTA *)csW;
1040             MDICREATESTRUCTA mdi_cs;
1041             DWORD name_lenA = 0, name_lenW = 0, class_lenA = 0, class_lenW = 0;
1042
1043             if (!IS_INTRESOURCE(csW->lpszClass))
1044             {
1045                 class_lenW = (strlenW(csW->lpszClass) + 1) * sizeof(WCHAR);
1046                 RtlUnicodeToMultiByteSize(&class_lenA, csW->lpszClass, class_lenW);
1047             }
1048             if (!IS_INTRESOURCE(csW->lpszName))
1049             {
1050                 name_lenW = (strlenW(csW->lpszName) + 1) * sizeof(WCHAR);
1051                 RtlUnicodeToMultiByteSize(&name_lenA, csW->lpszName, name_lenW);
1052             }
1053
1054             if (!(cls = get_buffer( buffer, sizeof(buffer), class_lenA + name_lenA ))) break;
1055
1056             if (class_lenA)
1057             {
1058                 RtlUnicodeToMultiByteN(cls, class_lenA, NULL, csW->lpszClass, class_lenW);
1059                 csA.lpszClass = cls;
1060             }
1061             if (name_lenA)
1062             {
1063                 char *name = cls + class_lenA;
1064                 RtlUnicodeToMultiByteN(name, name_lenA, NULL, csW->lpszName, name_lenW);
1065                 csA.lpszName = name;
1066             }
1067
1068             if (GetWindowLongW(hwnd, GWL_EXSTYLE) & WS_EX_MDICHILD)
1069             {
1070                 mdi_cs = *(MDICREATESTRUCTA *)csW->lpCreateParams;
1071                 mdi_cs.szTitle = csA.lpszName;
1072                 mdi_cs.szClass = csA.lpszClass;
1073                 csA.lpCreateParams = &mdi_cs;
1074             }
1075
1076             ret = callback( hwnd, msg, wParam, (LPARAM)&csA, result, arg );
1077             free_buffer( buffer, cls );
1078         }
1079         break;
1080
1081     case WM_GETTEXT:
1082     case WM_ASKCBFORMATNAME:
1083         {
1084             char *ptr, buffer[512];
1085             DWORD len = wParam * 2;
1086
1087             if (!(ptr = get_buffer( buffer, sizeof(buffer), len ))) break;
1088             ret = callback( hwnd, msg, wParam, (LPARAM)ptr, result, arg );
1089             if (len)
1090             {
1091                 if (*result)
1092                 {
1093                     RtlMultiByteToUnicodeN( (LPWSTR)lParam, wParam*sizeof(WCHAR), &len, ptr, strlen(ptr)+1 );
1094                     *result = len/sizeof(WCHAR) - 1;  /* do not count terminating null */
1095                 }
1096                 ((LPWSTR)lParam)[*result] = 0;
1097             }
1098             free_buffer( buffer, ptr );
1099         }
1100         break;
1101
1102     case LB_ADDSTRING:
1103     case LB_INSERTSTRING:
1104     case LB_FINDSTRING:
1105     case LB_FINDSTRINGEXACT:
1106     case LB_SELECTSTRING:
1107     case CB_ADDSTRING:
1108     case CB_INSERTSTRING:
1109     case CB_FINDSTRING:
1110     case CB_FINDSTRINGEXACT:
1111     case CB_SELECTSTRING:
1112         if (!lParam || !WINPROC_TestLBForStr( hwnd, msg ))
1113         {
1114             ret = callback( hwnd, msg, wParam, lParam, result, arg );
1115             break;
1116         }
1117         /* fall through */
1118     case WM_SETTEXT:
1119     case WM_WININICHANGE:
1120     case WM_DEVMODECHANGE:
1121     case CB_DIR:
1122     case LB_DIR:
1123     case LB_ADDFILE:
1124     case EM_REPLACESEL:
1125         if (!lParam) ret = callback( hwnd, msg, wParam, lParam, result, arg );
1126         else
1127         {
1128             char *ptr, buffer[512];
1129             LPCWSTR strW = (LPCWSTR)lParam;
1130             DWORD lenA, lenW = (strlenW(strW) + 1) * sizeof(WCHAR);
1131
1132             RtlUnicodeToMultiByteSize( &lenA, strW, lenW );
1133             if ((ptr = get_buffer( buffer, sizeof(buffer), lenA )))
1134             {
1135                 RtlUnicodeToMultiByteN( ptr, lenA, NULL, strW, lenW );
1136                 ret = callback( hwnd, msg, wParam, (LPARAM)ptr, result, arg );
1137                 free_buffer( buffer, ptr );
1138             }
1139         }
1140         break;
1141
1142     case WM_MDICREATE:
1143         {
1144             char *ptr, buffer[1024];
1145             DWORD title_lenA = 0, title_lenW = 0, class_lenA = 0, class_lenW = 0;
1146             MDICREATESTRUCTW *csW = (MDICREATESTRUCTW *)lParam;
1147             MDICREATESTRUCTA csA;
1148
1149             memcpy( &csA, csW, sizeof(csA) );
1150
1151             if (!IS_INTRESOURCE(csW->szTitle))
1152             {
1153                 title_lenW = (strlenW(csW->szTitle) + 1) * sizeof(WCHAR);
1154                 RtlUnicodeToMultiByteSize( &title_lenA, csW->szTitle, title_lenW );
1155             }
1156             if (!IS_INTRESOURCE(csW->szClass))
1157             {
1158                 class_lenW = (strlenW(csW->szClass) + 1) * sizeof(WCHAR);
1159                 RtlUnicodeToMultiByteSize( &class_lenA, csW->szClass, class_lenW );
1160             }
1161
1162             if (!(ptr = get_buffer( buffer, sizeof(buffer), title_lenA + class_lenA ))) break;
1163
1164             if (title_lenA)
1165             {
1166                 RtlUnicodeToMultiByteN( ptr, title_lenA, NULL, csW->szTitle, title_lenW );
1167                 csA.szTitle = ptr;
1168             }
1169             if (class_lenA)
1170             {
1171                 RtlUnicodeToMultiByteN( ptr + title_lenA, class_lenA, NULL, csW->szClass, class_lenW );
1172                 csA.szClass = ptr + title_lenA;
1173             }
1174             ret = callback( hwnd, msg, wParam, (LPARAM)&csA, result, arg );
1175             free_buffer( buffer, ptr );
1176         }
1177         break;
1178
1179     case LB_GETTEXT:
1180     case CB_GETLBTEXT:
1181         if (lParam && WINPROC_TestLBForStr( hwnd, msg ))
1182         {
1183             char buffer[512];  /* FIXME: fixed sized buffer */
1184
1185             ret = callback( hwnd, msg, wParam, (LPARAM)buffer, result, arg );
1186             if (*result >= 0)
1187             {
1188                 DWORD len;
1189                 RtlMultiByteToUnicodeN( (LPWSTR)lParam, ~0u, &len, buffer, strlen(buffer) + 1 );
1190                 *result = len / sizeof(WCHAR) - 1;
1191             }
1192         }
1193         else ret = callback( hwnd, msg, wParam, lParam, result, arg );
1194         break;
1195
1196     case EM_GETLINE:
1197         {
1198             char *ptr, buffer[512];
1199             WORD len = *(WORD *)lParam;
1200
1201             if (!(ptr = get_buffer( buffer, sizeof(buffer), len * 2 ))) break;
1202             *((WORD *)ptr) = len * 2;   /* store the length */
1203             ret = callback( hwnd, msg, wParam, (LPARAM)ptr, result, arg );
1204             if (*result)
1205             {
1206                 DWORD reslen;
1207                 RtlMultiByteToUnicodeN( (LPWSTR)lParam, len*sizeof(WCHAR), &reslen, ptr, *result );
1208                 *result = reslen / sizeof(WCHAR);
1209                 if (*result < len) ((LPWSTR)lParam)[*result] = 0;
1210             }
1211             free_buffer( buffer, ptr );
1212         }
1213         break;
1214
1215     case WM_GETDLGCODE:
1216         if (lParam)
1217         {
1218             MSG newmsg = *(MSG *)lParam;
1219             switch(newmsg.message)
1220             {
1221             case WM_CHAR:
1222             case WM_DEADCHAR:
1223             case WM_SYSCHAR:
1224             case WM_SYSDEADCHAR:
1225                 newmsg.wParam = map_wparam_char_WtoA( newmsg.wParam, 1 );
1226                 break;
1227             case WM_IME_CHAR:
1228                 newmsg.wParam = map_wparam_char_WtoA( newmsg.wParam, 2 );
1229                 break;
1230             }
1231             ret = callback( hwnd, msg, wParam, (LPARAM)&newmsg, result, arg );
1232         }
1233         else ret = callback( hwnd, msg, wParam, lParam, result, arg );
1234         break;
1235
1236     case WM_CHAR:
1237         {
1238             WCHAR wch = wParam;
1239             char ch[2];
1240             DWORD len;
1241
1242             RtlUnicodeToMultiByteN( ch, 2, &len, &wch, sizeof(wch) );
1243             ret = callback( hwnd, msg, (BYTE)ch[0], lParam, result, arg );
1244             if (len == 2) ret = callback( hwnd, msg, (BYTE)ch[1], lParam, result, arg );
1245         }
1246         break;
1247
1248     case WM_CHARTOITEM:
1249     case WM_MENUCHAR:
1250     case WM_DEADCHAR:
1251     case WM_SYSCHAR:
1252     case WM_SYSDEADCHAR:
1253     case EM_SETPASSWORDCHAR:
1254         ret = callback( hwnd, msg, map_wparam_char_WtoA(wParam,1), lParam, result, arg );
1255         break;
1256
1257     case WM_IME_CHAR:
1258         ret = callback( hwnd, msg, map_wparam_char_WtoA(wParam,2), lParam, result, arg );
1259         break;
1260
1261     case WM_PAINTCLIPBOARD:
1262     case WM_SIZECLIPBOARD:
1263         FIXME_(msg)( "message %s (%04x) needs translation, please report\n",
1264                      SPY_GetMsgName(msg, hwnd), msg );
1265         break;
1266
1267     default:
1268         ret = callback( hwnd, msg, wParam, lParam, result, arg );
1269         break;
1270     }
1271
1272     return ret;
1273 }
1274
1275
1276 /**********************************************************************
1277  *           WINPROC_CallProc16To32A
1278  */
1279 LRESULT WINPROC_CallProc16To32A( winproc_callback_t callback, HWND16 hwnd, UINT16 msg,
1280                                  WPARAM16 wParam, LPARAM lParam, LRESULT *result, void *arg )
1281 {
1282     LRESULT ret = 0;
1283     HWND hwnd32 = WIN_Handle32( hwnd );
1284
1285     TRACE_(msg)("(hwnd=%p,msg=%s,wp=%08x,lp=%08lx)\n",
1286                  hwnd32, SPY_GetMsgName(msg, hwnd32), wParam, lParam);
1287
1288     switch(msg)
1289     {
1290     case WM_NCCREATE:
1291     case WM_CREATE:
1292         {
1293             CREATESTRUCT16 *cs16 = MapSL(lParam);
1294             CREATESTRUCTA cs;
1295             MDICREATESTRUCTA mdi_cs;
1296
1297             CREATESTRUCT16to32A( cs16, &cs );
1298             if (GetWindowLongW(hwnd32, GWL_EXSTYLE) & WS_EX_MDICHILD)
1299             {
1300                 MDICREATESTRUCT16 *mdi_cs16 = MapSL(cs16->lpCreateParams);
1301                 MDICREATESTRUCT16to32A(mdi_cs16, &mdi_cs);
1302                 cs.lpCreateParams = &mdi_cs;
1303             }
1304             ret = callback( hwnd32, msg, wParam, (LPARAM)&cs, result, arg );
1305             CREATESTRUCT32Ato16( &cs, cs16 );
1306         }
1307         break;
1308     case WM_MDICREATE:
1309         {
1310             MDICREATESTRUCT16 *cs16 = MapSL(lParam);
1311             MDICREATESTRUCTA cs;
1312
1313             MDICREATESTRUCT16to32A( cs16, &cs );
1314             ret = callback( hwnd32, msg, wParam, (LPARAM)&cs, result, arg );
1315             MDICREATESTRUCT32Ato16( &cs, cs16 );
1316         }
1317         break;
1318     case WM_MDIACTIVATE:
1319         if (lParam)
1320             ret = callback( hwnd32, msg, (WPARAM)WIN_Handle32( HIWORD(lParam) ),
1321                             (LPARAM)WIN_Handle32( LOWORD(lParam) ), result, arg );
1322         else /* message sent to MDI client */
1323             ret = callback( hwnd32, msg, wParam, lParam, result, arg );
1324         break;
1325     case WM_MDIGETACTIVE:
1326         {
1327             BOOL maximized = FALSE;
1328             ret = callback( hwnd32, msg, wParam, (LPARAM)&maximized, result, arg );
1329             *result = MAKELRESULT( LOWORD(*result), maximized );
1330         }
1331         break;
1332     case WM_MDISETMENU:
1333         ret = callback( hwnd32, wParam ? WM_MDIREFRESHMENU : WM_MDISETMENU,
1334                         (WPARAM)HMENU_32(LOWORD(lParam)), (LPARAM)HMENU_32(HIWORD(lParam)),
1335                         result, arg );
1336         break;
1337     case WM_GETMINMAXINFO:
1338         {
1339             MINMAXINFO16 *mmi16 = MapSL(lParam);
1340             MINMAXINFO mmi;
1341
1342             MINMAXINFO16to32( mmi16, &mmi );
1343             ret = callback( hwnd32, msg, wParam, (LPARAM)&mmi, result, arg );
1344             MINMAXINFO32to16( &mmi, mmi16 );
1345         }
1346         break;
1347     case WM_WINDOWPOSCHANGING:
1348     case WM_WINDOWPOSCHANGED:
1349         {
1350             WINDOWPOS16 *winpos16 = MapSL(lParam);
1351             WINDOWPOS winpos;
1352
1353             WINDOWPOS16to32( winpos16, &winpos );
1354             ret = callback( hwnd32, msg, wParam, (LPARAM)&winpos, result, arg );
1355             WINDOWPOS32to16( &winpos, winpos16 );
1356         }
1357         break;
1358     case WM_NCCALCSIZE:
1359         {
1360             NCCALCSIZE_PARAMS16 *nc16 = MapSL(lParam);
1361             NCCALCSIZE_PARAMS nc;
1362             WINDOWPOS winpos;
1363
1364             RECT16to32( &nc16->rgrc[0], &nc.rgrc[0] );
1365             if (wParam)
1366             {
1367                 RECT16to32( &nc16->rgrc[1], &nc.rgrc[1] );
1368                 RECT16to32( &nc16->rgrc[2], &nc.rgrc[2] );
1369                 WINDOWPOS16to32( MapSL(nc16->lppos), &winpos );
1370                 nc.lppos = &winpos;
1371             }
1372             ret = callback( hwnd32, msg, wParam, (LPARAM)&nc, result, arg );
1373             RECT32to16( &nc.rgrc[0], &nc16->rgrc[0] );
1374             if (wParam)
1375             {
1376                 RECT32to16( &nc.rgrc[1], &nc16->rgrc[1] );
1377                 RECT32to16( &nc.rgrc[2], &nc16->rgrc[2] );
1378                 WINDOWPOS32to16( &winpos, MapSL(nc16->lppos) );
1379             }
1380         }
1381         break;
1382     case WM_COMPAREITEM:
1383         {
1384             COMPAREITEMSTRUCT16* cis16 = MapSL(lParam);
1385             COMPAREITEMSTRUCT cis;
1386             cis.CtlType    = cis16->CtlType;
1387             cis.CtlID      = cis16->CtlID;
1388             cis.hwndItem   = WIN_Handle32( cis16->hwndItem );
1389             cis.itemID1    = cis16->itemID1;
1390             cis.itemData1  = cis16->itemData1;
1391             cis.itemID2    = cis16->itemID2;
1392             cis.itemData2  = cis16->itemData2;
1393             cis.dwLocaleId = 0;  /* FIXME */
1394             ret = callback( hwnd32, msg, wParam, (LPARAM)&cis, result, arg );
1395         }
1396         break;
1397     case WM_DELETEITEM:
1398         {
1399             DELETEITEMSTRUCT16* dis16 = MapSL(lParam);
1400             DELETEITEMSTRUCT dis;
1401             dis.CtlType  = dis16->CtlType;
1402             dis.CtlID    = dis16->CtlID;
1403             dis.hwndItem = WIN_Handle32( dis16->hwndItem );
1404             dis.itemData = dis16->itemData;
1405             ret = callback( hwnd32, msg, wParam, (LPARAM)&dis, result, arg );
1406         }
1407         break;
1408     case WM_MEASUREITEM:
1409         {
1410             MEASUREITEMSTRUCT16* mis16 = MapSL(lParam);
1411             MEASUREITEMSTRUCT mis;
1412             mis.CtlType    = mis16->CtlType;
1413             mis.CtlID      = mis16->CtlID;
1414             mis.itemID     = mis16->itemID;
1415             mis.itemWidth  = mis16->itemWidth;
1416             mis.itemHeight = mis16->itemHeight;
1417             mis.itemData   = mis16->itemData;
1418             ret = callback( hwnd32, msg, wParam, (LPARAM)&mis, result, arg );
1419             mis16->itemWidth  = (UINT16)mis.itemWidth;
1420             mis16->itemHeight = (UINT16)mis.itemHeight;
1421         }
1422         break;
1423     case WM_DRAWITEM:
1424         {
1425             DRAWITEMSTRUCT16* dis16 = MapSL(lParam);
1426             DRAWITEMSTRUCT dis;
1427             dis.CtlType       = dis16->CtlType;
1428             dis.CtlID         = dis16->CtlID;
1429             dis.itemID        = dis16->itemID;
1430             dis.itemAction    = dis16->itemAction;
1431             dis.itemState     = dis16->itemState;
1432             dis.hwndItem      = (dis.CtlType == ODT_MENU) ? (HWND)HMENU_32(dis16->hwndItem)
1433                                                           : WIN_Handle32( dis16->hwndItem );
1434             dis.hDC           = HDC_32(dis16->hDC);
1435             dis.itemData      = dis16->itemData;
1436             dis.rcItem.left   = dis16->rcItem.left;
1437             dis.rcItem.top    = dis16->rcItem.top;
1438             dis.rcItem.right  = dis16->rcItem.right;
1439             dis.rcItem.bottom = dis16->rcItem.bottom;
1440             ret = callback( hwnd32, msg, wParam, (LPARAM)&dis, result, arg );
1441         }
1442         break;
1443     case WM_COPYDATA:
1444         {
1445             COPYDATASTRUCT16 *cds16 = MapSL(lParam);
1446             COPYDATASTRUCT cds;
1447             cds.dwData = cds16->dwData;
1448             cds.cbData = cds16->cbData;
1449             cds.lpData = MapSL(cds16->lpData);
1450             ret = callback( hwnd32, msg, wParam, (LPARAM)&cds, result, arg );
1451         }
1452         break;
1453     case WM_GETDLGCODE:
1454         if (lParam)
1455         {
1456             MSG16 *msg16 = MapSL(lParam);
1457             MSG msg32;
1458             msg32.hwnd    = WIN_Handle32( msg16->hwnd );
1459             msg32.message = msg16->message;
1460             msg32.wParam  = msg16->wParam;
1461             msg32.lParam  = msg16->lParam;
1462             msg32.time    = msg16->time;
1463             msg32.pt.x    = msg16->pt.x;
1464             msg32.pt.y    = msg16->pt.y;
1465             ret = callback( hwnd32, msg, wParam, (LPARAM)&msg32, result, arg );
1466         }
1467         else
1468             ret = callback( hwnd32, msg, wParam, lParam, result, arg );
1469         break;
1470     case WM_NEXTMENU:
1471         {
1472             MDINEXTMENU next;
1473             next.hmenuIn   = (HMENU)lParam;
1474             next.hmenuNext = 0;
1475             next.hwndNext  = 0;
1476             ret = callback( hwnd32, msg, wParam, (LPARAM)&next, result, arg );
1477             *result = MAKELONG( HMENU_16(next.hmenuNext), HWND_16(next.hwndNext) );
1478         }
1479         break;
1480     case WM_ACTIVATE:
1481     case WM_CHARTOITEM:
1482     case WM_COMMAND:
1483     case WM_VKEYTOITEM:
1484         ret = callback( hwnd32, msg, MAKEWPARAM( wParam, HIWORD(lParam) ),
1485                         (LPARAM)WIN_Handle32( LOWORD(lParam) ), result, arg );
1486         break;
1487     case WM_HSCROLL:
1488     case WM_VSCROLL:
1489         ret = callback( hwnd32, msg, MAKEWPARAM( wParam, LOWORD(lParam) ),
1490                         (LPARAM)WIN_Handle32( HIWORD(lParam) ), result, arg );
1491         break;
1492     case WM_CTLCOLOR:
1493         if (HIWORD(lParam) <= CTLCOLOR_STATIC)
1494             ret = callback( hwnd32, WM_CTLCOLORMSGBOX + HIWORD(lParam),
1495                             (WPARAM)HDC_32(wParam), (LPARAM)WIN_Handle32( LOWORD(lParam) ),
1496                             result, arg );
1497         break;
1498     case WM_GETTEXT:
1499     case WM_SETTEXT:
1500     case WM_WININICHANGE:
1501     case WM_DEVMODECHANGE:
1502     case WM_ASKCBFORMATNAME:
1503     case WM_NOTIFY:
1504         ret = callback( hwnd32, msg, wParam, (LPARAM)MapSL(lParam), result, arg );
1505         break;
1506     case WM_MENUCHAR:
1507         ret = callback( hwnd32, msg, MAKEWPARAM( wParam, LOWORD(lParam) ),
1508                         (LPARAM)HMENU_32(HIWORD(lParam)), result, arg );
1509         break;
1510     case WM_MENUSELECT:
1511         if((LOWORD(lParam) & MF_POPUP) && (LOWORD(lParam) != 0xFFFF))
1512         {
1513             HMENU hmenu = HMENU_32(HIWORD(lParam));
1514             UINT pos = MENU_FindSubMenu( &hmenu, HMENU_32(wParam) );
1515             if (pos == 0xffff) pos = 0;  /* NO_SELECTED_ITEM */
1516             wParam = pos;
1517         }
1518         ret = callback( hwnd32, msg, MAKEWPARAM( wParam, LOWORD(lParam) ),
1519                         (LPARAM)HMENU_32(HIWORD(lParam)), result, arg );
1520         break;
1521     case WM_PARENTNOTIFY:
1522         if ((wParam == WM_CREATE) || (wParam == WM_DESTROY))
1523             ret = callback( hwnd32, msg, MAKEWPARAM( wParam, HIWORD(lParam) ),
1524                             (LPARAM)WIN_Handle32( LOWORD(lParam) ), result, arg );
1525         else
1526             ret = callback( hwnd32, msg, wParam, lParam, result, arg );
1527         break;
1528     case WM_ACTIVATEAPP:
1529         /* We need this when SetActiveWindow sends a Sendmessage16() to
1530          * a 32-bit window. Might be superfluous with 32-bit interprocess
1531          * message queues. */
1532         if (lParam) lParam = HTASK_32(lParam);
1533         ret = callback( hwnd32, msg, wParam, lParam, result, arg );
1534         break;
1535     case WM_DDE_INITIATE:
1536     case WM_DDE_TERMINATE:
1537     case WM_DDE_UNADVISE:
1538     case WM_DDE_REQUEST:
1539         ret = callback( hwnd32, msg, (WPARAM)WIN_Handle32(wParam), lParam, result, arg );
1540         break;
1541     case WM_DDE_ADVISE:
1542     case WM_DDE_DATA:
1543     case WM_DDE_POKE:
1544         {
1545             HANDLE16 lo16 = LOWORD(lParam);
1546             UINT_PTR lo32 = 0;
1547             if (lo16 && !(lo32 = convert_handle_16_to_32(lo16, GMEM_DDESHARE))) break;
1548             lParam = PackDDElParam( msg, lo32, HIWORD(lParam) );
1549             ret = callback( hwnd32, msg, (WPARAM)WIN_Handle32(wParam), lParam, result, arg );
1550         }
1551         break; /* FIXME don't know how to free allocated memory (handle)  !! */
1552     case WM_DDE_ACK:
1553         {
1554             UINT_PTR lo = LOWORD(lParam);
1555             UINT_PTR hi = HIWORD(lParam);
1556             int flag = 0;
1557             char buf[2];
1558
1559             if (GlobalGetAtomNameA(hi, buf, 2) > 0) flag |= 1;
1560             if (GlobalSize16(hi) != 0) flag |= 2;
1561             switch (flag)
1562             {
1563             case 0:
1564                 if (hi)
1565                 {
1566                     MESSAGE("DDE_ACK: neither atom nor handle!!!\n");
1567                     hi = 0;
1568                 }
1569                 break;
1570             case 1:
1571                 break; /* atom, nothing to do */
1572             case 3:
1573                 MESSAGE("DDE_ACK: %lx both atom and handle... choosing handle\n", hi);
1574                 /* fall thru */
1575             case 2:
1576                 hi = convert_handle_16_to_32(hi, GMEM_DDESHARE);
1577                 break;
1578             }
1579             lParam = PackDDElParam( WM_DDE_ACK, lo, hi );
1580             ret = callback( hwnd32, msg, (WPARAM)WIN_Handle32(wParam), lParam, result, arg );
1581         }
1582         break; /* FIXME don't know how to free allocated memory (handle) !! */
1583     case WM_DDE_EXECUTE:
1584         lParam = convert_handle_16_to_32( lParam, GMEM_DDESHARE );
1585         ret = callback( hwnd32, msg, wParam, lParam, result, arg );
1586         break; /* FIXME don't know how to free allocated memory (handle) !! */
1587     case WM_PAINTCLIPBOARD:
1588     case WM_SIZECLIPBOARD:
1589         FIXME_(msg)( "message %04x needs translation\n", msg );
1590         break;
1591     default:
1592         ret = callback( hwnd32, msg, wParam, lParam, result, arg );
1593         break;
1594     }
1595     return ret;
1596 }
1597
1598
1599 /**********************************************************************
1600  *           __wine_call_wndproc   (USER.1010)
1601  */
1602 LRESULT WINAPI __wine_call_wndproc( HWND16 hwnd, UINT16 msg, WPARAM16 wParam, LPARAM lParam,
1603                                     WINDOWPROC *proc )
1604 {
1605     LRESULT result;
1606
1607     if (proc->procA)
1608         WINPROC_CallProc16To32A( call_window_proc, hwnd, msg, wParam, lParam, &result, proc->procA );
1609     else
1610         WINPROC_CallProc16To32A( call_window_proc_AtoW, hwnd, msg, wParam, lParam, &result, proc->procW );
1611     return result;
1612 }
1613
1614
1615 /**********************************************************************
1616  *           WINPROC_CallProc32ATo16
1617  *
1618  * Call a 16-bit window procedure, translating the 32-bit args.
1619  */
1620 LRESULT WINPROC_CallProc32ATo16( winproc_callback16_t callback, HWND hwnd, UINT msg,
1621                                  WPARAM wParam, LPARAM lParam, LRESULT *result, void *arg )
1622 {
1623     LRESULT ret = 0;
1624
1625     TRACE_(msg)("(hwnd=%p,msg=%s,wp=%08lx,lp=%08lx)\n",
1626                 hwnd, SPY_GetMsgName(msg, hwnd), wParam, lParam);
1627
1628     switch(msg)
1629     {
1630     case WM_NCCREATE:
1631     case WM_CREATE:
1632         {
1633             CREATESTRUCTA *cs32 = (CREATESTRUCTA *)lParam;
1634             CREATESTRUCT16 cs;
1635             MDICREATESTRUCT16 mdi_cs16;
1636             BOOL mdi_child = (GetWindowLongW(hwnd, GWL_EXSTYLE) & WS_EX_MDICHILD);
1637
1638             CREATESTRUCT32Ato16( cs32, &cs );
1639             cs.lpszName  = MapLS( cs32->lpszName );
1640             cs.lpszClass = MapLS( cs32->lpszClass );
1641
1642             if (mdi_child)
1643             {
1644                 MDICREATESTRUCTA *mdi_cs = (MDICREATESTRUCTA *)cs32->lpCreateParams;
1645                 MDICREATESTRUCT32Ato16( mdi_cs, &mdi_cs16 );
1646                 mdi_cs16.szTitle = MapLS( mdi_cs->szTitle );
1647                 mdi_cs16.szClass = MapLS( mdi_cs->szClass );
1648                 cs.lpCreateParams = MapLS( &mdi_cs16 );
1649             }
1650             lParam = MapLS( &cs );
1651             ret = callback( HWND_16(hwnd), msg, wParam, lParam, result, arg );
1652             UnMapLS( lParam );
1653             UnMapLS( cs.lpszName );
1654             UnMapLS( cs.lpszClass );
1655             if (mdi_child)
1656             {
1657                 UnMapLS( cs.lpCreateParams );
1658                 UnMapLS( mdi_cs16.szTitle );
1659                 UnMapLS( mdi_cs16.szClass );
1660             }
1661         }
1662         break;
1663     case WM_MDICREATE:
1664         {
1665             MDICREATESTRUCTA *cs32 = (MDICREATESTRUCTA *)lParam;
1666             MDICREATESTRUCT16 cs;
1667
1668             MDICREATESTRUCT32Ato16( cs32, &cs );
1669             cs.szTitle = MapLS( cs32->szTitle );
1670             cs.szClass = MapLS( cs32->szClass );
1671             lParam = MapLS( &cs );
1672             ret = callback( HWND_16(hwnd), msg, wParam, lParam, result, arg );
1673             UnMapLS( lParam );
1674             UnMapLS( cs.szTitle );
1675             UnMapLS( cs.szClass );
1676         }
1677         break;
1678     case WM_MDIACTIVATE:
1679         if (GetWindowLongW( hwnd, GWL_EXSTYLE ) & WS_EX_MDICHILD)
1680             ret = callback( HWND_16(hwnd), msg, ((HWND)lParam == hwnd),
1681                             MAKELPARAM( LOWORD(lParam), LOWORD(wParam) ), result, arg );
1682         else
1683             ret = callback( HWND_16(hwnd), msg, HWND_16( (HWND)wParam ), 0, result, arg );
1684         break;
1685     case WM_MDIGETACTIVE:
1686         ret = callback( HWND_16(hwnd), msg, wParam, lParam, result, arg );
1687         if (lParam) *(BOOL *)lParam = (BOOL16)HIWORD(*result);
1688         *result = (LRESULT)WIN_Handle32( LOWORD(*result) );
1689         break;
1690     case WM_MDISETMENU:
1691         ret = callback( HWND_16(hwnd), msg, (lParam == 0),
1692                         MAKELPARAM( LOWORD(wParam), LOWORD(lParam) ), result, arg );
1693         break;
1694     case WM_GETMINMAXINFO:
1695         {
1696             MINMAXINFO *mmi32 = (MINMAXINFO *)lParam;
1697             MINMAXINFO16 mmi;
1698
1699             MINMAXINFO32to16( mmi32, &mmi );
1700             lParam = MapLS( &mmi );
1701             ret = callback( HWND_16(hwnd), msg, wParam, lParam, result, arg );
1702             UnMapLS( lParam );
1703             MINMAXINFO16to32( &mmi, mmi32 );
1704         }
1705         break;
1706     case WM_NCCALCSIZE:
1707         {
1708             NCCALCSIZE_PARAMS *nc32 = (NCCALCSIZE_PARAMS *)lParam;
1709             NCCALCSIZE_PARAMS16 nc;
1710             WINDOWPOS16 winpos;
1711
1712             RECT32to16( &nc32->rgrc[0], &nc.rgrc[0] );
1713             if (wParam)
1714             {
1715                 RECT32to16( &nc32->rgrc[1], &nc.rgrc[1] );
1716                 RECT32to16( &nc32->rgrc[2], &nc.rgrc[2] );
1717                 WINDOWPOS32to16( nc32->lppos, &winpos );
1718                 nc.lppos = MapLS( &winpos );
1719             }
1720             lParam = MapLS( &nc );
1721             ret = callback( HWND_16(hwnd), msg, wParam, lParam, result, arg );
1722             UnMapLS( lParam );
1723             RECT16to32( &nc.rgrc[0], &nc32->rgrc[0] );
1724             if (wParam)
1725             {
1726                 RECT16to32( &nc.rgrc[1], &nc32->rgrc[1] );
1727                 RECT16to32( &nc.rgrc[2], &nc32->rgrc[2] );
1728                 WINDOWPOS16to32( &winpos, nc32->lppos );
1729                 UnMapLS( nc.lppos );
1730             }
1731         }
1732         break;
1733     case WM_WINDOWPOSCHANGING:
1734     case WM_WINDOWPOSCHANGED:
1735         {
1736             WINDOWPOS *winpos32 = (WINDOWPOS *)lParam;
1737             WINDOWPOS16 winpos;
1738
1739             WINDOWPOS32to16( winpos32, &winpos );
1740             lParam = MapLS( &winpos );
1741             ret = callback( HWND_16(hwnd), msg, wParam, lParam, result, arg );
1742             UnMapLS( lParam );
1743             WINDOWPOS16to32( &winpos, winpos32 );
1744         }
1745         break;
1746     case WM_COMPAREITEM:
1747         {
1748             COMPAREITEMSTRUCT *cis32 = (COMPAREITEMSTRUCT *)lParam;
1749             COMPAREITEMSTRUCT16 cis;
1750             cis.CtlType    = cis32->CtlType;
1751             cis.CtlID      = cis32->CtlID;
1752             cis.hwndItem   = HWND_16( cis32->hwndItem );
1753             cis.itemID1    = cis32->itemID1;
1754             cis.itemData1  = cis32->itemData1;
1755             cis.itemID2    = cis32->itemID2;
1756             cis.itemData2  = cis32->itemData2;
1757             lParam = MapLS( &cis );
1758             ret = callback( HWND_16(hwnd), msg, wParam, lParam, result, arg );
1759             UnMapLS( lParam );
1760         }
1761         break;
1762     case WM_DELETEITEM:
1763         {
1764             DELETEITEMSTRUCT *dis32 = (DELETEITEMSTRUCT *)lParam;
1765             DELETEITEMSTRUCT16 dis;
1766             dis.CtlType  = dis32->CtlType;
1767             dis.CtlID    = dis32->CtlID;
1768             dis.itemID   = dis32->itemID;
1769             dis.hwndItem = (dis.CtlType == ODT_MENU) ? (HWND16)LOWORD(dis32->hwndItem)
1770                                                      : HWND_16( dis32->hwndItem );
1771             dis.itemData = dis32->itemData;
1772             lParam = MapLS( &dis );
1773             ret = callback( HWND_16(hwnd), msg, wParam, lParam, result, arg );
1774             UnMapLS( lParam );
1775         }
1776         break;
1777     case WM_DRAWITEM:
1778         {
1779             DRAWITEMSTRUCT *dis32 = (DRAWITEMSTRUCT *)lParam;
1780             DRAWITEMSTRUCT16 dis;
1781             dis.CtlType       = dis32->CtlType;
1782             dis.CtlID         = dis32->CtlID;
1783             dis.itemID        = dis32->itemID;
1784             dis.itemAction    = dis32->itemAction;
1785             dis.itemState     = dis32->itemState;
1786             dis.hwndItem      = HWND_16( dis32->hwndItem );
1787             dis.hDC           = HDC_16(dis32->hDC);
1788             dis.itemData      = dis32->itemData;
1789             dis.rcItem.left   = dis32->rcItem.left;
1790             dis.rcItem.top    = dis32->rcItem.top;
1791             dis.rcItem.right  = dis32->rcItem.right;
1792             dis.rcItem.bottom = dis32->rcItem.bottom;
1793             lParam = MapLS( &dis );
1794             ret = callback( HWND_16(hwnd), msg, wParam, lParam, result, arg );
1795             UnMapLS( lParam );
1796         }
1797         break;
1798     case WM_MEASUREITEM:
1799         {
1800             MEASUREITEMSTRUCT *mis32 = (MEASUREITEMSTRUCT *)lParam;
1801             MEASUREITEMSTRUCT16 mis;
1802             mis.CtlType    = mis32->CtlType;
1803             mis.CtlID      = mis32->CtlID;
1804             mis.itemID     = mis32->itemID;
1805             mis.itemWidth  = mis32->itemWidth;
1806             mis.itemHeight = mis32->itemHeight;
1807             mis.itemData   = mis32->itemData;
1808             lParam = MapLS( &mis );
1809             ret = callback( HWND_16(hwnd), msg, wParam, lParam, result, arg );
1810             UnMapLS( lParam );
1811             mis32->itemWidth  = mis.itemWidth;
1812             mis32->itemHeight = mis.itemHeight;
1813         }
1814         break;
1815     case WM_COPYDATA:
1816         {
1817             COPYDATASTRUCT *cds32 = (COPYDATASTRUCT *)lParam;
1818             COPYDATASTRUCT16 cds;
1819
1820             cds.dwData = cds32->dwData;
1821             cds.cbData = cds32->cbData;
1822             cds.lpData = MapLS( cds32->lpData );
1823             lParam = MapLS( &cds );
1824             ret = callback( HWND_16(hwnd), msg, wParam, lParam, result, arg );
1825             UnMapLS( lParam );
1826             UnMapLS( cds.lpData );
1827         }
1828         break;
1829     case WM_GETDLGCODE:
1830         if (lParam)
1831         {
1832             MSG *msg32 = (MSG *)lParam;
1833             MSG16 msg16;
1834
1835             msg16.hwnd    = HWND_16( msg32->hwnd );
1836             msg16.message = msg32->message;
1837             msg16.wParam  = msg32->wParam;
1838             msg16.lParam  = msg32->lParam;
1839             msg16.time    = msg32->time;
1840             msg16.pt.x    = msg32->pt.x;
1841             msg16.pt.y    = msg32->pt.y;
1842             lParam = MapLS( &msg16 );
1843             ret = callback( HWND_16(hwnd), msg, wParam, lParam, result, arg );
1844             UnMapLS( lParam );
1845         }
1846         else
1847             ret = callback( HWND_16(hwnd), msg, wParam, lParam, result, arg );
1848         break;
1849     case WM_NEXTMENU:
1850         {
1851             MDINEXTMENU *next = (MDINEXTMENU *)lParam;
1852             ret = callback( HWND_16(hwnd), msg, wParam, (LPARAM)next->hmenuIn, result, arg );
1853             next->hmenuNext = HMENU_32( LOWORD(*result) );
1854             next->hwndNext  = WIN_Handle32( HIWORD(*result) );
1855             *result = 0;
1856         }
1857         break;
1858     case WM_GETTEXT:
1859     case WM_ASKCBFORMATNAME:
1860         wParam = min( wParam, 0xff80 ); /* Must be < 64K */
1861         /* fall through */
1862     case WM_NOTIFY:
1863     case WM_SETTEXT:
1864     case WM_WININICHANGE:
1865     case WM_DEVMODECHANGE:
1866         lParam = MapLS( (void *)lParam );
1867         ret = callback( HWND_16(hwnd), msg, wParam, lParam, result, arg );
1868         UnMapLS( lParam );
1869         break;
1870     case WM_ACTIVATE:
1871     case WM_CHARTOITEM:
1872     case WM_COMMAND:
1873     case WM_VKEYTOITEM:
1874         ret = callback( HWND_16(hwnd), msg, wParam, MAKELPARAM( (HWND16)lParam, HIWORD(wParam) ),
1875                         result, arg );
1876         break;
1877     case WM_HSCROLL:
1878     case WM_VSCROLL:
1879         ret = callback( HWND_16(hwnd), msg, wParam, MAKELPARAM( HIWORD(wParam), (HWND16)lParam ),
1880                         result, arg );
1881         break;
1882     case WM_CTLCOLORMSGBOX:
1883     case WM_CTLCOLOREDIT:
1884     case WM_CTLCOLORLISTBOX:
1885     case WM_CTLCOLORBTN:
1886     case WM_CTLCOLORDLG:
1887     case WM_CTLCOLORSCROLLBAR:
1888     case WM_CTLCOLORSTATIC:
1889         ret = callback( HWND_16(hwnd), WM_CTLCOLOR, wParam,
1890                         MAKELPARAM( (HWND16)lParam, msg - WM_CTLCOLORMSGBOX ), result, arg );
1891         break;
1892     case WM_MENUSELECT:
1893         if(HIWORD(wParam) & MF_POPUP)
1894         {
1895             HMENU hmenu;
1896             if ((HIWORD(wParam) != 0xffff) || lParam)
1897             {
1898                 if ((hmenu = GetSubMenu( (HMENU)lParam, LOWORD(wParam) )))
1899                 {
1900                     ret = callback( HWND_16(hwnd), msg, HMENU_16(hmenu),
1901                                     MAKELPARAM( HIWORD(wParam), (HMENU16)lParam ), result, arg );
1902                     break;
1903                 }
1904             }
1905         }
1906         /* fall through */
1907     case WM_MENUCHAR:
1908         ret = callback( HWND_16(hwnd), msg, wParam,
1909                         MAKELPARAM( HIWORD(wParam), (HMENU16)lParam ), result, arg );
1910         break;
1911     case WM_PARENTNOTIFY:
1912         if ((LOWORD(wParam) == WM_CREATE) || (LOWORD(wParam) == WM_DESTROY))
1913             ret = callback( HWND_16(hwnd), msg, wParam,
1914                             MAKELPARAM( (HWND16)lParam, HIWORD(wParam) ), result, arg );
1915         else
1916             ret = callback( HWND_16(hwnd), msg, wParam, lParam, result, arg );
1917         break;
1918     case WM_ACTIVATEAPP:
1919         ret = callback( HWND_16(hwnd), msg, wParam, HTASK_16( (HANDLE)lParam ), result, arg );
1920         break;
1921     case WM_PAINT:
1922         if (IsIconic( hwnd ) && GetClassLongPtrW( hwnd, GCLP_HICON ))
1923             ret = callback( HWND_16(hwnd), WM_PAINTICON, 1, lParam, result, arg );
1924         else
1925             ret = callback( HWND_16(hwnd), WM_PAINT, wParam, lParam, result, arg );
1926         break;
1927     case WM_ERASEBKGND:
1928         if (IsIconic( hwnd ) && GetClassLongPtrW( hwnd, GCLP_HICON )) msg = WM_ICONERASEBKGND;
1929         ret = callback( HWND_16(hwnd), msg, wParam, lParam, result, arg );
1930         break;
1931     case WM_DDE_INITIATE:
1932     case WM_DDE_TERMINATE:
1933     case WM_DDE_UNADVISE:
1934     case WM_DDE_REQUEST:
1935         ret = callback( HWND_16(hwnd), msg, HWND_16((HWND)wParam), lParam, result, arg );
1936         break;
1937     case WM_DDE_ADVISE:
1938     case WM_DDE_DATA:
1939     case WM_DDE_POKE:
1940         {
1941             UINT_PTR lo32, hi;
1942             HANDLE16 lo16 = 0;
1943
1944             UnpackDDElParam( msg, lParam, &lo32, &hi );
1945             if (lo32 && !(lo16 = convert_handle_32_to_16(lo32, GMEM_DDESHARE))) break;
1946             ret = callback( HWND_16(hwnd), msg, HWND_16((HWND)wParam),
1947                             MAKELPARAM(lo16, hi), result, arg );
1948         }
1949         break; /* FIXME don't know how to free allocated memory (handle)  !! */
1950     case WM_DDE_ACK:
1951         {
1952             UINT_PTR lo, hi;
1953             int flag = 0;
1954             char buf[2];
1955
1956             UnpackDDElParam( msg, lParam, &lo, &hi );
1957
1958             if (GlobalGetAtomNameA((ATOM)hi, buf, sizeof(buf)) > 0) flag |= 1;
1959             if (GlobalSize((HANDLE)hi) != 0) flag |= 2;
1960             switch (flag)
1961             {
1962             case 0:
1963                 if (hi)
1964                 {
1965                     MESSAGE("DDE_ACK: neither atom nor handle!!!\n");
1966                     hi = 0;
1967                 }
1968                 break;
1969             case 1:
1970                 break; /* atom, nothing to do */
1971             case 3:
1972                 MESSAGE("DDE_ACK: %lx both atom and handle... choosing handle\n", hi);
1973                 /* fall thru */
1974             case 2:
1975                 hi = convert_handle_32_to_16(hi, GMEM_DDESHARE);
1976                 break;
1977             }
1978             ret = callback( HWND_16(hwnd), msg, HWND_16((HWND)wParam),
1979                             MAKELPARAM(lo, hi), result, arg );
1980         }
1981         break; /* FIXME don't know how to free allocated memory (handle) !! */
1982     case WM_DDE_EXECUTE:
1983         lParam = convert_handle_32_to_16(lParam, GMEM_DDESHARE);
1984         ret = callback( HWND_16(hwnd), msg, wParam, lParam, result, arg );
1985         break; /* FIXME don't know how to free allocated memory (handle) !! */
1986     case SBM_SETRANGE:
1987         ret = callback( HWND_16(hwnd), SBM_SETRANGE16, 0, MAKELPARAM(wParam, lParam), result, arg );
1988         break;
1989     case SBM_GETRANGE:
1990         ret = callback( HWND_16(hwnd), SBM_GETRANGE16, wParam, lParam, result, arg );
1991         *(LPINT)wParam = LOWORD(*result);
1992         *(LPINT)lParam = HIWORD(*result);
1993         break;
1994     case BM_GETCHECK:
1995     case BM_SETCHECK:
1996     case BM_GETSTATE:
1997     case BM_SETSTATE:
1998     case BM_SETSTYLE:
1999         ret = callback( HWND_16(hwnd), msg + BM_GETCHECK16 - BM_GETCHECK, wParam, lParam, result, arg );
2000         break;
2001     case EM_GETSEL:
2002     case EM_GETRECT:
2003     case EM_SETRECT:
2004     case EM_SETRECTNP:
2005     case EM_SCROLL:
2006     case EM_LINESCROLL:
2007     case EM_SCROLLCARET:
2008     case EM_GETMODIFY:
2009     case EM_SETMODIFY:
2010     case EM_GETLINECOUNT:
2011     case EM_LINEINDEX:
2012     case EM_SETHANDLE:
2013     case EM_GETHANDLE:
2014     case EM_GETTHUMB:
2015     case EM_LINELENGTH:
2016     case EM_REPLACESEL:
2017     case EM_GETLINE:
2018     case EM_LIMITTEXT:
2019     case EM_CANUNDO:
2020     case EM_UNDO:
2021     case EM_FMTLINES:
2022     case EM_LINEFROMCHAR:
2023     case EM_SETTABSTOPS:
2024     case EM_SETPASSWORDCHAR:
2025     case EM_EMPTYUNDOBUFFER:
2026     case EM_GETFIRSTVISIBLELINE:
2027     case EM_SETREADONLY:
2028     case EM_SETWORDBREAKPROC:
2029     case EM_GETWORDBREAKPROC:
2030     case EM_GETPASSWORDCHAR:
2031         ret = callback( HWND_16(hwnd), msg + EM_GETSEL16 - EM_GETSEL, wParam, lParam, result, arg );
2032         break;
2033     case EM_SETSEL:
2034         ret = callback( HWND_16(hwnd), EM_SETSEL16, 0, MAKELPARAM( wParam, lParam ), result, arg );
2035         break;
2036     case LB_CARETOFF:
2037     case LB_CARETON:
2038     case LB_DELETESTRING:
2039     case LB_GETANCHORINDEX:
2040     case LB_GETCARETINDEX:
2041     case LB_GETCOUNT:
2042     case LB_GETCURSEL:
2043     case LB_GETHORIZONTALEXTENT:
2044     case LB_GETITEMDATA:
2045     case LB_GETITEMHEIGHT:
2046     case LB_GETSEL:
2047     case LB_GETSELCOUNT:
2048     case LB_GETTEXTLEN:
2049     case LB_GETTOPINDEX:
2050     case LB_RESETCONTENT:
2051     case LB_SELITEMRANGE:
2052     case LB_SELITEMRANGEEX:
2053     case LB_SETANCHORINDEX:
2054     case LB_SETCARETINDEX:
2055     case LB_SETCOLUMNWIDTH:
2056     case LB_SETCURSEL:
2057     case LB_SETHORIZONTALEXTENT:
2058     case LB_SETITEMDATA:
2059     case LB_SETITEMHEIGHT:
2060     case LB_SETSEL:
2061     case LB_SETTOPINDEX:
2062         ret = callback( HWND_16(hwnd), msg + LB_ADDSTRING16 - LB_ADDSTRING, wParam, lParam, result, arg );
2063         break;
2064     case LB_ADDSTRING:
2065     case LB_FINDSTRING:
2066     case LB_FINDSTRINGEXACT:
2067     case LB_INSERTSTRING:
2068     case LB_SELECTSTRING:
2069     case LB_GETTEXT:
2070     case LB_DIR:
2071     case LB_ADDFILE:
2072         lParam = MapLS( (LPSTR)lParam );
2073         ret = callback( HWND_16(hwnd), msg + LB_ADDSTRING16 - LB_ADDSTRING, wParam, lParam, result, arg );
2074         UnMapLS( lParam );
2075         break;
2076     case LB_GETSELITEMS:
2077         {
2078             INT *items32 = (INT *)lParam;
2079             INT16 *items, buffer[512];
2080             unsigned int i;
2081
2082             wParam = min( wParam, 0x7f80 ); /* Must be < 64K */
2083             if (!(items = get_buffer( buffer, sizeof(buffer), wParam * sizeof(INT16) ))) break;
2084             lParam = MapLS( items );
2085             ret = callback( HWND_16(hwnd), LB_GETSELITEMS16, wParam, lParam, result, arg );
2086             UnMapLS( lParam );
2087             for (i = 0; i < wParam; i++) items32[i] = items[i];
2088             free_buffer( buffer, items );
2089         }
2090         break;
2091     case LB_SETTABSTOPS:
2092         if (wParam)
2093         {
2094             INT *stops32 = (INT *)lParam;
2095             INT16 *stops, buffer[512];
2096             unsigned int i;
2097
2098             wParam = min( wParam, 0x7f80 ); /* Must be < 64K */
2099             if (!(stops = get_buffer( buffer, sizeof(buffer), wParam * sizeof(INT16) ))) break;
2100             for (i = 0; i < wParam; i++) stops[i] = stops32[i];
2101             lParam = MapLS( stops );
2102             ret = callback( HWND_16(hwnd), LB_SETTABSTOPS16, wParam, lParam, result, arg );
2103             UnMapLS( lParam );
2104             free_buffer( buffer, stops );
2105         }
2106         else ret = callback( HWND_16(hwnd), LB_SETTABSTOPS16, wParam, lParam, result, arg );
2107         break;
2108     case CB_DELETESTRING:
2109     case CB_GETCOUNT:
2110     case CB_GETLBTEXTLEN:
2111     case CB_LIMITTEXT:
2112     case CB_RESETCONTENT:
2113     case CB_SETEDITSEL:
2114     case CB_GETCURSEL:
2115     case CB_SETCURSEL:
2116     case CB_SHOWDROPDOWN:
2117     case CB_SETITEMDATA:
2118     case CB_SETITEMHEIGHT:
2119     case CB_GETITEMHEIGHT:
2120     case CB_SETEXTENDEDUI:
2121     case CB_GETEXTENDEDUI:
2122     case CB_GETDROPPEDSTATE:
2123         ret = callback( HWND_16(hwnd), msg + CB_GETEDITSEL16 - CB_GETEDITSEL, wParam, lParam, result, arg );
2124         break;
2125     case CB_GETEDITSEL:
2126         ret = callback( HWND_16(hwnd), CB_GETEDITSEL16, wParam, lParam, result, arg );
2127         if (wParam) *((PUINT)(wParam)) = LOWORD(*result);
2128         if (lParam) *((PUINT)(lParam)) = HIWORD(*result);  /* FIXME: substract 1? */
2129         break;
2130     case CB_ADDSTRING:
2131     case CB_FINDSTRING:
2132     case CB_FINDSTRINGEXACT:
2133     case CB_INSERTSTRING:
2134     case CB_SELECTSTRING:
2135     case CB_DIR:
2136     case CB_GETLBTEXT:
2137         lParam = MapLS( (LPSTR)lParam );
2138         ret = callback( HWND_16(hwnd), msg + CB_GETEDITSEL16 - CB_GETEDITSEL, wParam, lParam, result, arg );
2139         UnMapLS( lParam );
2140         break;
2141     case LB_GETITEMRECT:
2142     case CB_GETDROPPEDCONTROLRECT:
2143         {
2144             RECT *r32 = (RECT *)lParam;
2145             RECT16 rect;
2146             lParam = MapLS( &rect );
2147             ret = callback( HWND_16(hwnd),
2148                             (msg == LB_GETITEMRECT) ? LB_GETITEMRECT16 : CB_GETDROPPEDCONTROLRECT16,
2149                             wParam, lParam, result, arg );
2150             UnMapLS( lParam );
2151             RECT16to32( &rect, r32 );
2152         }
2153         break;
2154     case WM_PAINTCLIPBOARD:
2155     case WM_SIZECLIPBOARD:
2156         FIXME_(msg)( "message %04x needs translation\n", msg );
2157         break;
2158     /* the following messages should not be sent to 16-bit apps */
2159     case WM_SIZING:
2160     case WM_MOVING:
2161     case WM_CAPTURECHANGED:
2162     case WM_STYLECHANGING:
2163     case WM_STYLECHANGED:
2164         break;
2165     default:
2166         ret = callback( HWND_16(hwnd), msg, wParam, lParam, result, arg );
2167         break;
2168     }
2169     return ret;
2170 }
2171
2172
2173 /**********************************************************************
2174  *              WINPROC_call_window
2175  *
2176  * Call the window procedure of the specified window.
2177  */
2178 BOOL WINPROC_call_window( HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam,
2179                           LRESULT *result, BOOL unicode, enum wm_char_mapping mapping )
2180 {
2181     struct user_thread_info *thread_info = get_user_thread_info();
2182     WND *wndPtr;
2183     WINDOWPROC *proc;
2184
2185     if (!(wndPtr = WIN_GetPtr( hwnd ))) return FALSE;
2186     if (wndPtr == WND_OTHER_PROCESS || wndPtr == WND_DESKTOP) return FALSE;
2187     if (wndPtr->tid != GetCurrentThreadId())
2188     {
2189         WIN_ReleasePtr( wndPtr );
2190         return FALSE;
2191     }
2192     proc = handle_to_proc( wndPtr->winproc );
2193     WIN_ReleasePtr( wndPtr );
2194
2195     if (!proc) return TRUE;
2196
2197     if (thread_info->recursion_count > MAX_WINPROC_RECURSION) return FALSE;
2198     thread_info->recursion_count++;
2199
2200     if (unicode)
2201     {
2202         if (proc->procW)
2203             call_window_proc( hwnd, msg, wParam, lParam, result, proc->procW );
2204         else if (proc->procA)
2205             WINPROC_CallProcWtoA( call_window_proc, hwnd, msg, wParam, lParam, result, proc->procA );
2206         else
2207             WINPROC_CallProcWtoA( call_window_proc_Ato16, hwnd, msg, wParam, lParam, result, proc->proc16 );
2208     }
2209     else
2210     {
2211         if (proc->procA)
2212             call_window_proc( hwnd, msg, wParam, lParam, result, proc->procA );
2213         else if (proc->procW)
2214             WINPROC_CallProcAtoW( call_window_proc, hwnd, msg, wParam, lParam, result, proc->procW, mapping );
2215         else
2216             WINPROC_CallProc32ATo16( call_window_proc16, hwnd, msg, wParam, lParam, result, proc->proc16 );
2217     }
2218     thread_info->recursion_count--;
2219     return TRUE;
2220 }
2221
2222
2223 /**********************************************************************
2224  *              CallWindowProc (USER.122)
2225  */
2226 LRESULT WINAPI CallWindowProc16( WNDPROC16 func, HWND16 hwnd, UINT16 msg,
2227                                  WPARAM16 wParam, LPARAM lParam )
2228 {
2229     WINDOWPROC *proc;
2230     LRESULT result;
2231
2232     if (!func) return 0;
2233
2234     if (!(proc = handle16_to_proc( func )))
2235         call_window_proc16( hwnd, msg, wParam, lParam, &result, func );
2236     else if (proc->procA)
2237         WINPROC_CallProc16To32A( call_window_proc, hwnd, msg, wParam, lParam, &result, proc->procA );
2238     else if (proc->procW)
2239         WINPROC_CallProc16To32A( call_window_proc_AtoW, hwnd, msg, wParam, lParam, &result, proc->procW );
2240     else
2241         call_window_proc16( hwnd, msg, wParam, lParam, &result, proc->proc16 );
2242
2243     return result;
2244 }
2245
2246
2247 /**********************************************************************
2248  *              CallWindowProcA (USER32.@)
2249  *
2250  * The CallWindowProc() function invokes the windows procedure _func_,
2251  * with _hwnd_ as the target window, the message specified by _msg_, and
2252  * the message parameters _wParam_ and _lParam_.
2253  *
2254  * Some kinds of argument conversion may be done, I'm not sure what.
2255  *
2256  * CallWindowProc() may be used for windows subclassing. Use
2257  * SetWindowLong() to set a new windows procedure for windows of the
2258  * subclass, and handle subclassed messages in the new windows
2259  * procedure. The new windows procedure may then use CallWindowProc()
2260  * with _func_ set to the parent class's windows procedure to dispatch
2261  * the message to the superclass.
2262  *
2263  * RETURNS
2264  *
2265  *    The return value is message dependent.
2266  *
2267  * CONFORMANCE
2268  *
2269  *   ECMA-234, Win32
2270  */
2271 LRESULT WINAPI CallWindowProcA(
2272     WNDPROC func,  /* [in] window procedure */
2273     HWND hwnd,     /* [in] target window */
2274     UINT msg,      /* [in] message */
2275     WPARAM wParam, /* [in] message dependent parameter */
2276     LPARAM lParam  /* [in] message dependent parameter */
2277 ) {
2278     WINDOWPROC *proc;
2279     LRESULT result;
2280
2281     if (!func) return 0;
2282
2283     if (!(proc = handle_to_proc( func )))
2284         call_window_proc( hwnd, msg, wParam, lParam, &result, func );
2285     else if (proc->procA)
2286         call_window_proc( hwnd, msg, wParam, lParam, &result, proc->procA );
2287     else if (proc->procW)
2288         WINPROC_CallProcAtoW( call_window_proc, hwnd, msg, wParam, lParam, &result,
2289                               proc->procW, WMCHAR_MAP_CALLWINDOWPROC );
2290     else
2291         WINPROC_CallProc32ATo16( call_window_proc16, hwnd, msg, wParam, lParam, &result, proc->proc16 );
2292     return result;
2293 }
2294
2295
2296 /**********************************************************************
2297  *              CallWindowProcW (USER32.@)
2298  *
2299  * See CallWindowProcA.
2300  */
2301 LRESULT WINAPI CallWindowProcW( WNDPROC func, HWND hwnd, UINT msg,
2302                                   WPARAM wParam, LPARAM lParam )
2303 {
2304     WINDOWPROC *proc;
2305     LRESULT result;
2306
2307     if (!func) return 0;
2308
2309     if (!(proc = handle_to_proc( func )))
2310         call_window_proc( hwnd, msg, wParam, lParam, &result, func );
2311     else if (proc->procW)
2312         call_window_proc( hwnd, msg, wParam, lParam, &result, proc->procW );
2313     else if (proc->procA)
2314         WINPROC_CallProcWtoA( call_window_proc, hwnd, msg, wParam, lParam, &result, proc->procA );
2315     else
2316         WINPROC_CallProcWtoA( call_window_proc_Ato16, hwnd, msg, wParam, lParam, &result, proc->proc16 );
2317     return result;
2318 }
2319
2320
2321 /**********************************************************************
2322  *              WINPROC_CallDlgProc16
2323  */
2324 INT_PTR WINPROC_CallDlgProc16( DLGPROC16 func, HWND16 hwnd, UINT16 msg, WPARAM16 wParam, LPARAM lParam )
2325 {
2326     WINDOWPROC *proc;
2327     LRESULT result;
2328     INT_PTR ret;
2329
2330     if (!func) return 0;
2331
2332     if (!(proc = handle16_to_proc( (WNDPROC16)func )))
2333     {
2334         ret = call_dialog_proc16( hwnd, msg, wParam, lParam, &result, func );
2335     }
2336     else if (proc->procA)
2337     {
2338         ret = WINPROC_CallProc16To32A( call_dialog_proc, hwnd, msg, wParam, lParam,
2339                                        &result, proc->procA );
2340         SetWindowLongPtrW( WIN_Handle32(hwnd), DWLP_MSGRESULT, result );
2341     }
2342     else if (proc->procW)
2343     {
2344         ret = WINPROC_CallProc16To32A( call_dialog_proc_AtoW, hwnd, msg, wParam, lParam,
2345                                        &result, proc->procW );
2346         SetWindowLongPtrW( WIN_Handle32(hwnd), DWLP_MSGRESULT, result );
2347     }
2348     else
2349     {
2350         ret = call_dialog_proc16( hwnd, msg, wParam, lParam, &result, proc->proc16 );
2351     }
2352     return ret;
2353 }
2354
2355
2356 /**********************************************************************
2357  *              WINPROC_CallDlgProcA
2358  */
2359 INT_PTR WINPROC_CallDlgProcA( DLGPROC func, HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam )
2360 {
2361     WINDOWPROC *proc;
2362     LRESULT result;
2363     INT_PTR ret;
2364
2365     if (!func) return 0;
2366
2367     if (!(proc = handle_to_proc( func )))
2368         ret = call_dialog_proc( hwnd, msg, wParam, lParam, &result, func );
2369     else if (proc->procA)
2370         ret = call_dialog_proc( hwnd, msg, wParam, lParam, &result, proc->procA );
2371     else if (proc->procW)
2372     {
2373         ret = WINPROC_CallProcAtoW( call_dialog_proc, hwnd, msg, wParam, lParam, &result,
2374                                     proc->procW, WMCHAR_MAP_CALLWINDOWPROC );
2375         SetWindowLongPtrW( hwnd, DWLP_MSGRESULT, result );
2376     }
2377     else
2378     {
2379         ret = WINPROC_CallProc32ATo16( call_dialog_proc16, hwnd, msg, wParam, lParam, &result, proc->proc16 );
2380         SetWindowLongPtrW( hwnd, DWLP_MSGRESULT, result );
2381     }
2382     return ret;
2383 }
2384
2385
2386 /**********************************************************************
2387  *              WINPROC_CallDlgProcW
2388  */
2389 INT_PTR WINPROC_CallDlgProcW( DLGPROC func, HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam )
2390 {
2391     WINDOWPROC *proc;
2392     LRESULT result;
2393     INT_PTR ret;
2394
2395     if (!func) return 0;
2396
2397     if (!(proc = handle_to_proc( func )))
2398         ret = call_dialog_proc( hwnd, msg, wParam, lParam, &result, func );
2399     else if (proc->procW)
2400         ret = call_dialog_proc( hwnd, msg, wParam, lParam, &result, proc->procW );
2401     else if (proc->procA)
2402     {
2403         ret = WINPROC_CallProcWtoA( call_dialog_proc, hwnd, msg, wParam, lParam, &result, proc->procA );
2404         SetWindowLongPtrW( hwnd, DWLP_MSGRESULT, result );
2405     }
2406     else
2407     {
2408         ret = WINPROC_CallProcWtoA( call_dialog_proc_Ato16, hwnd, msg, wParam, lParam, &result, proc->proc16 );
2409         SetWindowLongPtrW( hwnd, DWLP_MSGRESULT, result );
2410     }
2411     return ret;
2412 }