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