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