msvcr80: Add some 64-bit only exports.
[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 "wingdi.h"
32 #include "controls.h"
33 #include "win.h"
34 #include "user_private.h"
35 #include "wine/unicode.h"
36 #include "wine/debug.h"
37
38 WINE_DECLARE_DEBUG_CHANNEL(msg);
39 WINE_DECLARE_DEBUG_CHANNEL(relay);
40 WINE_DEFAULT_DEBUG_CHANNEL(win);
41
42 typedef struct tagWINDOWPROC
43 {
44     WNDPROC        procA;    /* ASCII window proc */
45     WNDPROC        procW;    /* Unicode window proc */
46 } WINDOWPROC;
47
48 #define MAX_WINPROCS  4096
49 #define MAX_WINPROC_RECURSION  64
50 #define WINPROC_PROC16  ((WINDOWPROC *)1)  /* placeholder for 16-bit window procs */
51
52 static LRESULT WINAPI ButtonWndProcA( HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam );
53 static LRESULT WINAPI ButtonWndProcW( HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam );
54 static LRESULT WINAPI ComboWndProcA( HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam );
55 static LRESULT WINAPI ComboWndProcW( HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam );
56 LRESULT WINAPI EditWndProcA( HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam );
57 static LRESULT WINAPI EditWndProcW( HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam );
58 static LRESULT WINAPI ListBoxWndProcA( HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam );
59 static LRESULT WINAPI ListBoxWndProcW( HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam );
60 static LRESULT WINAPI MDIClientWndProcA( HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam );
61 static LRESULT WINAPI MDIClientWndProcW( HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam );
62 static LRESULT WINAPI ScrollBarWndProcA( HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam );
63 static LRESULT WINAPI ScrollBarWndProcW( HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam );
64 static LRESULT WINAPI StaticWndProcA( HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam );
65 static LRESULT WINAPI StaticWndProcW( HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam );
66
67 static WINDOWPROC winproc_array[MAX_WINPROCS] =
68 {
69     { ButtonWndProcA, ButtonWndProcW },        /* WINPROC_BUTTON */
70     { ComboWndProcA, ComboWndProcW },          /* WINPROC_COMBO */
71     { DefWindowProcA, DefWindowProcW },        /* WINPROC_DEFWND */
72     { DefDlgProcA, DefDlgProcW },              /* WINPROC_DIALOG */
73     { EditWndProcA, EditWndProcW },            /* WINPROC_EDIT */
74     { ListBoxWndProcA, ListBoxWndProcW },      /* WINPROC_LISTBOX */
75     { MDIClientWndProcA, MDIClientWndProcW },  /* WINPROC_MDICLIENT */
76     { ScrollBarWndProcA, ScrollBarWndProcW },  /* WINPROC_SCROLLBAR */
77     { StaticWndProcA, StaticWndProcW },        /* WINPROC_STATIC */
78     { NULL, DesktopWndProc },                  /* WINPROC_DESKTOP */
79     { NULL, IconTitleWndProc },                /* WINPROC_ICONTITLE */
80     { NULL, PopupMenuWndProc },                /* WINPROC_MENU */
81     { NULL, MessageWndProc },                  /* WINPROC_MESSAGE */
82 };
83
84 static UINT winproc_used = NB_BUILTIN_WINPROCS;
85
86 static CRITICAL_SECTION winproc_cs;
87 static CRITICAL_SECTION_DEBUG critsect_debug =
88 {
89     0, 0, &winproc_cs,
90     { &critsect_debug.ProcessLocksList, &critsect_debug.ProcessLocksList },
91       0, 0, { (DWORD_PTR)(__FILE__ ": winproc_cs") }
92 };
93 static CRITICAL_SECTION winproc_cs = { &critsect_debug, -1, 0, 0, 0, 0 };
94
95 static inline void *get_buffer( void *static_buffer, size_t size, size_t need )
96 {
97     if (size >= need) return static_buffer;
98     return HeapAlloc( GetProcessHeap(), 0, need );
99 }
100
101 static inline void free_buffer( void *static_buffer, void *buffer )
102 {
103     if (buffer != static_buffer) HeapFree( GetProcessHeap(), 0, buffer );
104 }
105
106 /* find an existing winproc for a given function and type */
107 /* FIXME: probably should do something more clever than a linear search */
108 static inline WINDOWPROC *find_winproc( WNDPROC func, BOOL unicode )
109 {
110     unsigned int i;
111
112     for (i = 0; i < NB_BUILTIN_AW_WINPROCS; i++)
113     {
114         /* match either proc, some apps confuse A and W */
115         if (winproc_array[i].procA != func && winproc_array[i].procW != func) continue;
116         return &winproc_array[i];
117     }
118     for (i = NB_BUILTIN_AW_WINPROCS; i < winproc_used; i++)
119     {
120         if (!unicode && winproc_array[i].procA != func) continue;
121         if (unicode && winproc_array[i].procW != func) continue;
122         return &winproc_array[i];
123     }
124     return NULL;
125 }
126
127 /* return the window proc for a given handle, or NULL for an invalid handle,
128  * or WINPROC_PROC16 for a handle to a 16-bit proc. */
129 static inline WINDOWPROC *handle_to_proc( WNDPROC handle )
130 {
131     UINT index = LOWORD(handle);
132     if ((ULONG_PTR)handle >> 16 != WINPROC_HANDLE) return NULL;
133     if (index >= MAX_WINPROCS) return WINPROC_PROC16;
134     if (index >= winproc_used) return NULL;
135     return &winproc_array[index];
136 }
137
138 /* create a handle for a given window proc */
139 static inline WNDPROC proc_to_handle( WINDOWPROC *proc )
140 {
141     return (WNDPROC)(ULONG_PTR)((proc - winproc_array) | (WINPROC_HANDLE << 16));
142 }
143
144 /* allocate and initialize a new winproc */
145 static inline WINDOWPROC *alloc_winproc( WNDPROC func, BOOL unicode )
146 {
147     WINDOWPROC *proc;
148
149     /* check if the function is already a win proc */
150     if (!func) return NULL;
151     if ((proc = handle_to_proc( func ))) return proc;
152
153     EnterCriticalSection( &winproc_cs );
154
155     /* check if we already have a winproc for that function */
156     if (!(proc = find_winproc( func, unicode )))
157     {
158         if (winproc_used < MAX_WINPROCS)
159         {
160             proc = &winproc_array[winproc_used++];
161             if (unicode) proc->procW = func;
162             else proc->procA = func;
163             TRACE( "allocated %p for %c %p (%d/%d used)\n",
164                    proc_to_handle(proc), unicode ? 'W' : 'A', func,
165                    winproc_used, MAX_WINPROCS );
166         }
167         else FIXME( "too many winprocs, cannot allocate one for %p\n", func );
168     }
169     else TRACE( "reusing %p for %p\n", proc_to_handle(proc), func );
170
171     LeaveCriticalSection( &winproc_cs );
172     return proc;
173 }
174
175 #ifdef __i386__
176 /* Some window procedures modify register they shouldn't, or are not
177  * properly declared stdcall; so we need a small assembly wrapper to
178  * call them. */
179 extern LRESULT WINPROC_wrapper( WNDPROC proc, HWND hwnd, UINT msg,
180                                 WPARAM wParam, LPARAM lParam );
181 __ASM_GLOBAL_FUNC( WINPROC_wrapper,
182                    "pushl %ebp\n\t"
183                    __ASM_CFI(".cfi_adjust_cfa_offset 4\n\t")
184                    __ASM_CFI(".cfi_rel_offset %ebp,0\n\t")
185                    "movl %esp,%ebp\n\t"
186                    __ASM_CFI(".cfi_def_cfa_register %ebp\n\t")
187                    "pushl %edi\n\t"
188                    __ASM_CFI(".cfi_rel_offset %edi,-4\n\t")
189                    "pushl %esi\n\t"
190                    __ASM_CFI(".cfi_rel_offset %esi,-8\n\t")
191                    "pushl %ebx\n\t"
192                    __ASM_CFI(".cfi_rel_offset %ebx,-12\n\t")
193                    "subl $12,%esp\n\t"
194                    "pushl 24(%ebp)\n\t"
195                    "pushl 20(%ebp)\n\t"
196                    "pushl 16(%ebp)\n\t"
197                    "pushl 12(%ebp)\n\t"
198                    "movl 8(%ebp),%eax\n\t"
199                    "call *%eax\n\t"
200                    "leal -12(%ebp),%esp\n\t"
201                    "popl %ebx\n\t"
202                    __ASM_CFI(".cfi_same_value %ebx\n\t")
203                    "popl %esi\n\t"
204                    __ASM_CFI(".cfi_same_value %esi\n\t")
205                    "popl %edi\n\t"
206                    __ASM_CFI(".cfi_same_value %edi\n\t")
207                    "leave\n\t"
208                    __ASM_CFI(".cfi_def_cfa %esp,4\n\t")
209                    __ASM_CFI(".cfi_same_value %ebp\n\t")
210                    "ret" )
211 #else
212 static inline LRESULT WINPROC_wrapper( WNDPROC proc, HWND hwnd, UINT msg,
213                                        WPARAM wParam, LPARAM lParam )
214 {
215     return proc( hwnd, msg, wParam, lParam );
216 }
217 #endif  /* __i386__ */
218
219 static WPARAM map_wparam_char_WtoA( WPARAM wParam, DWORD len )
220 {
221     WCHAR wch = wParam;
222     BYTE ch[2];
223
224     RtlUnicodeToMultiByteN( (LPSTR)ch, len, &len, &wch, sizeof(wch) );
225     if (len == 2)
226         return MAKEWPARAM( (ch[0] << 8) | ch[1], HIWORD(wParam) );
227     else
228         return MAKEWPARAM( ch[0], HIWORD(wParam) );
229 }
230
231 /* call a 32-bit window procedure */
232 static LRESULT call_window_proc( HWND hwnd, UINT msg, WPARAM wp, LPARAM lp, LRESULT *result, void *arg )
233 {
234     WNDPROC proc = arg;
235
236     USER_CheckNotLock();
237
238     hwnd = WIN_GetFullHandle( hwnd );
239     if (TRACE_ON(relay))
240         DPRINTF( "%04x:Call window proc %p (hwnd=%p,msg=%s,wp=%08lx,lp=%08lx)\n",
241                  GetCurrentThreadId(), proc, hwnd, SPY_GetMsgName(msg, hwnd), wp, lp );
242
243     *result = WINPROC_wrapper( proc, hwnd, msg, wp, lp );
244
245     if (TRACE_ON(relay))
246         DPRINTF( "%04x:Ret  window proc %p (hwnd=%p,msg=%s,wp=%08lx,lp=%08lx) retval=%08lx\n",
247                  GetCurrentThreadId(), proc, hwnd, SPY_GetMsgName(msg, hwnd), wp, lp, *result );
248     return *result;
249 }
250
251 /* call a 32-bit dialog procedure */
252 static LRESULT call_dialog_proc( HWND hwnd, UINT msg, WPARAM wp, LPARAM lp, LRESULT *result, void *arg )
253 {
254     WNDPROC proc = arg;
255     LRESULT ret;
256
257     USER_CheckNotLock();
258
259     hwnd = WIN_GetFullHandle( hwnd );
260     if (TRACE_ON(relay))
261         DPRINTF( "%04x:Call dialog proc %p (hwnd=%p,msg=%s,wp=%08lx,lp=%08lx)\n",
262                  GetCurrentThreadId(), proc, hwnd, SPY_GetMsgName(msg, hwnd), wp, lp );
263
264     ret = WINPROC_wrapper( proc, hwnd, msg, wp, lp );
265     *result = GetWindowLongPtrW( hwnd, DWLP_MSGRESULT );
266
267     if (TRACE_ON(relay))
268         DPRINTF( "%04x:Ret  dialog proc %p (hwnd=%p,msg=%s,wp=%08lx,lp=%08lx) retval=%08lx result=%08lx\n",
269                  GetCurrentThreadId(), proc, hwnd, SPY_GetMsgName(msg, hwnd), wp, lp, ret, *result );
270     return ret;
271 }
272
273
274 /**********************************************************************
275  *           WINPROC_GetProc
276  *
277  * Get a window procedure pointer that can be passed to the Windows program.
278  */
279 WNDPROC WINPROC_GetProc( WNDPROC proc, BOOL unicode )
280 {
281     WINDOWPROC *ptr = handle_to_proc( proc );
282
283     if (!ptr || ptr == WINPROC_PROC16) return proc;
284     if (unicode)
285     {
286         if (ptr->procW) return ptr->procW;
287         return proc;
288     }
289     else
290     {
291         if (ptr->procA) return ptr->procA;
292         return proc;
293     }
294 }
295
296
297 /**********************************************************************
298  *           WINPROC_AllocProc
299  *
300  * Allocate a window procedure for a window or class.
301  *
302  * Note that allocated winprocs are never freed; the idea is that even if an app creates a
303  * lot of windows, it will usually only have a limited number of window procedures, so the
304  * array won't grow too large, and this way we avoid the need to track allocations per window.
305  */
306 WNDPROC WINPROC_AllocProc( WNDPROC func, BOOL unicode )
307 {
308     WINDOWPROC *proc;
309
310     if (!(proc = alloc_winproc( func, unicode ))) return NULL;
311     if (proc == WINPROC_PROC16) return func;
312     return proc_to_handle( proc );
313 }
314
315
316 /**********************************************************************
317  *           WINPROC_IsUnicode
318  *
319  * Return the window procedure type, or the default value if not a winproc handle.
320  */
321 BOOL WINPROC_IsUnicode( WNDPROC proc, BOOL def_val )
322 {
323     WINDOWPROC *ptr = handle_to_proc( proc );
324
325     if (!ptr) return def_val;
326     if (ptr == WINPROC_PROC16) return FALSE;  /* 16-bit is always A */
327     if (ptr->procA && ptr->procW) return def_val;  /* can be both */
328     return (ptr->procW != NULL);
329 }
330
331
332 /**********************************************************************
333  *           WINPROC_TestLBForStr
334  *
335  * Return TRUE if the lparam is a string
336  */
337 static inline BOOL WINPROC_TestLBForStr( HWND hwnd, UINT msg )
338 {
339     DWORD style = GetWindowLongA( hwnd, GWL_STYLE );
340     if (msg <= CB_MSGMAX)
341         return (!(style & (CBS_OWNERDRAWFIXED | CBS_OWNERDRAWVARIABLE)) || (style & CBS_HASSTRINGS));
342     else
343         return (!(style & (LBS_OWNERDRAWFIXED | LBS_OWNERDRAWVARIABLE)) || (style & LBS_HASSTRINGS));
344
345 }
346
347
348 /**********************************************************************
349  *           WINPROC_CallProcAtoW
350  *
351  * Call a window procedure, translating args from Ansi to Unicode.
352  */
353 LRESULT WINPROC_CallProcAtoW( winproc_callback_t callback, HWND hwnd, UINT msg, WPARAM wParam,
354                               LPARAM lParam, LRESULT *result, void *arg, enum wm_char_mapping mapping )
355 {
356     LRESULT ret = 0;
357
358     TRACE_(msg)("(hwnd=%p,msg=%s,wp=%08lx,lp=%08lx)\n",
359                 hwnd, SPY_GetMsgName(msg, hwnd), wParam, lParam);
360
361     switch(msg)
362     {
363     case WM_NCCREATE:
364     case WM_CREATE:
365         {
366             WCHAR *ptr, buffer[512];
367             CREATESTRUCTA *csA = (CREATESTRUCTA *)lParam;
368             CREATESTRUCTW csW = *(CREATESTRUCTW *)csA;
369             MDICREATESTRUCTW mdi_cs;
370             DWORD name_lenA = 0, name_lenW = 0, class_lenA = 0, class_lenW = 0;
371
372             if (!IS_INTRESOURCE(csA->lpszClass))
373             {
374                 class_lenA = strlen(csA->lpszClass) + 1;
375                 RtlMultiByteToUnicodeSize( &class_lenW, csA->lpszClass, class_lenA );
376             }
377             if (!IS_INTRESOURCE(csA->lpszName))
378             {
379                 name_lenA = strlen(csA->lpszName) + 1;
380                 RtlMultiByteToUnicodeSize( &name_lenW, csA->lpszName, name_lenA );
381             }
382
383             if (!(ptr = get_buffer( buffer, sizeof(buffer), class_lenW + name_lenW ))) break;
384
385             if (class_lenW)
386             {
387                 csW.lpszClass = ptr;
388                 RtlMultiByteToUnicodeN( ptr, class_lenW, NULL, csA->lpszClass, class_lenA );
389             }
390             if (name_lenW)
391             {
392                 csW.lpszName = ptr + class_lenW/sizeof(WCHAR);
393                 RtlMultiByteToUnicodeN( ptr + class_lenW/sizeof(WCHAR), name_lenW, NULL,
394                                         csA->lpszName, name_lenA );
395             }
396
397             if (GetWindowLongW(hwnd, GWL_EXSTYLE) & WS_EX_MDICHILD)
398             {
399                 mdi_cs = *(MDICREATESTRUCTW *)csA->lpCreateParams;
400                 mdi_cs.szTitle = csW.lpszName;
401                 mdi_cs.szClass = csW.lpszClass;
402                 csW.lpCreateParams = &mdi_cs;
403             }
404
405             ret = callback( hwnd, msg, wParam, (LPARAM)&csW, result, arg );
406             free_buffer( buffer, ptr );
407         }
408         break;
409
410     case WM_MDICREATE:
411         {
412             WCHAR *ptr, buffer[512];
413             DWORD title_lenA = 0, title_lenW = 0, class_lenA = 0, class_lenW = 0;
414             MDICREATESTRUCTA *csA = (MDICREATESTRUCTA *)lParam;
415             MDICREATESTRUCTW csW;
416
417             memcpy( &csW, csA, sizeof(csW) );
418
419             if (!IS_INTRESOURCE(csA->szTitle))
420             {
421                 title_lenA = strlen(csA->szTitle) + 1;
422                 RtlMultiByteToUnicodeSize( &title_lenW, csA->szTitle, title_lenA );
423             }
424             if (!IS_INTRESOURCE(csA->szClass))
425             {
426                 class_lenA = strlen(csA->szClass) + 1;
427                 RtlMultiByteToUnicodeSize( &class_lenW, csA->szClass, class_lenA );
428             }
429
430             if (!(ptr = get_buffer( buffer, sizeof(buffer), title_lenW + class_lenW ))) break;
431
432             if (title_lenW)
433             {
434                 csW.szTitle = ptr;
435                 RtlMultiByteToUnicodeN( ptr, title_lenW, NULL, csA->szTitle, title_lenA );
436             }
437             if (class_lenW)
438             {
439                 csW.szClass = ptr + title_lenW/sizeof(WCHAR);
440                 RtlMultiByteToUnicodeN( ptr + title_lenW/sizeof(WCHAR), class_lenW, NULL,
441                                         csA->szClass, class_lenA );
442             }
443             ret = callback( hwnd, msg, wParam, (LPARAM)&csW, result, arg );
444             free_buffer( buffer, ptr );
445         }
446         break;
447
448     case WM_GETTEXT:
449     case WM_ASKCBFORMATNAME:
450         {
451             WCHAR *ptr, buffer[512];
452             LPSTR str = (LPSTR)lParam;
453             DWORD len = wParam * sizeof(WCHAR);
454
455             if (!(ptr = get_buffer( buffer, sizeof(buffer), len ))) break;
456             ret = callback( hwnd, msg, wParam, (LPARAM)ptr, result, arg );
457             if (wParam)
458             {
459                 len = 0;
460                 if (*result)
461                     RtlUnicodeToMultiByteN( str, wParam - 1, &len, ptr, strlenW(ptr) * sizeof(WCHAR) );
462                 str[len] = 0;
463                 *result = len;
464             }
465             free_buffer( buffer, ptr );
466         }
467         break;
468
469     case LB_ADDSTRING:
470     case LB_INSERTSTRING:
471     case LB_FINDSTRING:
472     case LB_FINDSTRINGEXACT:
473     case LB_SELECTSTRING:
474     case CB_ADDSTRING:
475     case CB_INSERTSTRING:
476     case CB_FINDSTRING:
477     case CB_FINDSTRINGEXACT:
478     case CB_SELECTSTRING:
479         if (!lParam || !WINPROC_TestLBForStr( hwnd, msg ))
480         {
481             ret = callback( hwnd, msg, wParam, lParam, result, arg );
482             break;
483         }
484         /* fall through */
485     case WM_SETTEXT:
486     case WM_WININICHANGE:
487     case WM_DEVMODECHANGE:
488     case CB_DIR:
489     case LB_DIR:
490     case LB_ADDFILE:
491     case EM_REPLACESEL:
492         if (!lParam) ret = callback( hwnd, msg, wParam, lParam, result, arg );
493         else
494         {
495             WCHAR *ptr, buffer[512];
496             LPCSTR strA = (LPCSTR)lParam;
497             DWORD lenW, lenA = strlen(strA) + 1;
498
499             RtlMultiByteToUnicodeSize( &lenW, strA, lenA );
500             if ((ptr = get_buffer( buffer, sizeof(buffer), lenW )))
501             {
502                 RtlMultiByteToUnicodeN( ptr, lenW, NULL, strA, lenA );
503                 ret = callback( hwnd, msg, wParam, (LPARAM)ptr, result, arg );
504                 free_buffer( buffer, ptr );
505             }
506         }
507         break;
508
509     case LB_GETTEXT:
510     case CB_GETLBTEXT:
511         if (lParam && WINPROC_TestLBForStr( hwnd, msg ))
512         {
513             WCHAR buffer[512];  /* FIXME: fixed sized buffer */
514
515             ret = callback( hwnd, msg, wParam, (LPARAM)buffer, result, arg );
516             if (*result >= 0)
517             {
518                 DWORD len;
519                 RtlUnicodeToMultiByteN( (LPSTR)lParam, ~0u, &len,
520                                         buffer, (strlenW(buffer) + 1) * sizeof(WCHAR) );
521                 *result = len - 1;
522             }
523         }
524         else ret = callback( hwnd, msg, wParam, lParam, result, arg );
525         break;
526
527     case EM_GETLINE:
528         {
529             WCHAR *ptr, buffer[512];
530             WORD len = *(WORD *)lParam;
531
532             if (!(ptr = get_buffer( buffer, sizeof(buffer), len * sizeof(WCHAR) ))) break;
533             *((WORD *)ptr) = len;   /* store the length */
534             ret = callback( hwnd, msg, wParam, (LPARAM)ptr, result, arg );
535             if (*result)
536             {
537                 DWORD reslen;
538                 RtlUnicodeToMultiByteN( (LPSTR)lParam, len, &reslen, ptr, *result * sizeof(WCHAR) );
539                 if (reslen < len) ((LPSTR)lParam)[reslen] = 0;
540                 *result = reslen;
541             }
542             free_buffer( buffer, ptr );
543         }
544         break;
545
546     case WM_GETDLGCODE:
547         if (lParam)
548         {
549             MSG newmsg = *(MSG *)lParam;
550             if (map_wparam_AtoW( newmsg.message, &newmsg.wParam, WMCHAR_MAP_NOMAPPING ))
551                 ret = callback( hwnd, msg, wParam, (LPARAM)&newmsg, result, arg );
552         }
553         else ret = callback( hwnd, msg, wParam, lParam, result, arg );
554         break;
555
556     case WM_CHARTOITEM:
557     case WM_MENUCHAR:
558     case WM_CHAR:
559     case WM_DEADCHAR:
560     case WM_SYSCHAR:
561     case WM_SYSDEADCHAR:
562     case EM_SETPASSWORDCHAR:
563     case WM_IME_CHAR:
564         if (map_wparam_AtoW( msg, &wParam, mapping ))
565             ret = callback( hwnd, msg, wParam, lParam, result, arg );
566         break;
567
568     case WM_GETTEXTLENGTH:
569     case CB_GETLBTEXTLEN:
570     case LB_GETTEXTLEN:
571         ret = callback( hwnd, msg, wParam, lParam, result, arg );
572         if (*result >= 0)
573         {
574             WCHAR *ptr, buffer[512];
575             LRESULT tmp;
576             DWORD len = *result + 1;
577             /* Determine respective GETTEXT message */
578             UINT msgGetText = (msg == WM_GETTEXTLENGTH) ? WM_GETTEXT :
579                               ((msg == CB_GETLBTEXTLEN) ? CB_GETLBTEXT : LB_GETTEXT);
580             /* wParam differs between the messages */
581             WPARAM wp = (msg == WM_GETTEXTLENGTH) ? len : wParam;
582
583             if (!(ptr = get_buffer( buffer, sizeof(buffer), len * sizeof(WCHAR) ))) break;
584
585             if (callback == call_window_proc)  /* FIXME: hack */
586                 callback( hwnd, msgGetText, wp, (LPARAM)ptr, &tmp, arg );
587             else
588                 tmp = SendMessageW( hwnd, msgGetText, wp, (LPARAM)ptr );
589             RtlUnicodeToMultiByteSize( &len, ptr, tmp * sizeof(WCHAR) );
590             *result = len;
591             free_buffer( buffer, ptr );
592         }
593         break;
594
595     case WM_PAINTCLIPBOARD:
596     case WM_SIZECLIPBOARD:
597         FIXME_(msg)( "message %s (0x%x) needs translation, please report\n",
598                      SPY_GetMsgName(msg, hwnd), msg );
599         break;
600
601     default:
602         ret = callback( hwnd, msg, wParam, lParam, result, arg );
603         break;
604     }
605     return ret;
606 }
607
608
609 /**********************************************************************
610  *           WINPROC_CallProcWtoA
611  *
612  * Call a window procedure, translating args from Unicode to Ansi.
613  */
614 static LRESULT WINPROC_CallProcWtoA( winproc_callback_t callback, HWND hwnd, UINT msg, WPARAM wParam,
615                                      LPARAM lParam, LRESULT *result, void *arg )
616 {
617     LRESULT ret = 0;
618
619     TRACE_(msg)("(hwnd=%p,msg=%s,wp=%08lx,lp=%08lx)\n",
620                 hwnd, SPY_GetMsgName(msg, hwnd), wParam, lParam);
621
622     switch(msg)
623     {
624     case WM_NCCREATE:
625     case WM_CREATE:
626         {
627             char buffer[1024], *cls;
628             CREATESTRUCTW *csW = (CREATESTRUCTW *)lParam;
629             CREATESTRUCTA csA = *(CREATESTRUCTA *)csW;
630             MDICREATESTRUCTA mdi_cs;
631             DWORD name_lenA = 0, name_lenW = 0, class_lenA = 0, class_lenW = 0;
632
633             if (!IS_INTRESOURCE(csW->lpszClass))
634             {
635                 class_lenW = (strlenW(csW->lpszClass) + 1) * sizeof(WCHAR);
636                 RtlUnicodeToMultiByteSize(&class_lenA, csW->lpszClass, class_lenW);
637             }
638             if (!IS_INTRESOURCE(csW->lpszName))
639             {
640                 name_lenW = (strlenW(csW->lpszName) + 1) * sizeof(WCHAR);
641                 RtlUnicodeToMultiByteSize(&name_lenA, csW->lpszName, name_lenW);
642             }
643
644             if (!(cls = get_buffer( buffer, sizeof(buffer), class_lenA + name_lenA ))) break;
645
646             if (class_lenA)
647             {
648                 RtlUnicodeToMultiByteN(cls, class_lenA, NULL, csW->lpszClass, class_lenW);
649                 csA.lpszClass = cls;
650             }
651             if (name_lenA)
652             {
653                 char *name = cls + class_lenA;
654                 RtlUnicodeToMultiByteN(name, name_lenA, NULL, csW->lpszName, name_lenW);
655                 csA.lpszName = name;
656             }
657
658             if (GetWindowLongW(hwnd, GWL_EXSTYLE) & WS_EX_MDICHILD)
659             {
660                 mdi_cs = *(MDICREATESTRUCTA *)csW->lpCreateParams;
661                 mdi_cs.szTitle = csA.lpszName;
662                 mdi_cs.szClass = csA.lpszClass;
663                 csA.lpCreateParams = &mdi_cs;
664             }
665
666             ret = callback( hwnd, msg, wParam, (LPARAM)&csA, result, arg );
667             free_buffer( buffer, cls );
668         }
669         break;
670
671     case WM_GETTEXT:
672     case WM_ASKCBFORMATNAME:
673         {
674             char *ptr, buffer[512];
675             DWORD len = wParam * 2;
676
677             if (!(ptr = get_buffer( buffer, sizeof(buffer), len ))) break;
678             ret = callback( hwnd, msg, wParam, (LPARAM)ptr, result, arg );
679             if (len)
680             {
681                 if (*result)
682                 {
683                     RtlMultiByteToUnicodeN( (LPWSTR)lParam, wParam*sizeof(WCHAR), &len, ptr, strlen(ptr)+1 );
684                     *result = len/sizeof(WCHAR) - 1;  /* do not count terminating null */
685                 }
686                 ((LPWSTR)lParam)[*result] = 0;
687             }
688             free_buffer( buffer, ptr );
689         }
690         break;
691
692     case LB_ADDSTRING:
693     case LB_INSERTSTRING:
694     case LB_FINDSTRING:
695     case LB_FINDSTRINGEXACT:
696     case LB_SELECTSTRING:
697     case CB_ADDSTRING:
698     case CB_INSERTSTRING:
699     case CB_FINDSTRING:
700     case CB_FINDSTRINGEXACT:
701     case CB_SELECTSTRING:
702         if (!lParam || !WINPROC_TestLBForStr( hwnd, msg ))
703         {
704             ret = callback( hwnd, msg, wParam, lParam, result, arg );
705             break;
706         }
707         /* fall through */
708     case WM_SETTEXT:
709     case WM_WININICHANGE:
710     case WM_DEVMODECHANGE:
711     case CB_DIR:
712     case LB_DIR:
713     case LB_ADDFILE:
714     case EM_REPLACESEL:
715         if (!lParam) ret = callback( hwnd, msg, wParam, lParam, result, arg );
716         else
717         {
718             char *ptr, buffer[512];
719             LPCWSTR strW = (LPCWSTR)lParam;
720             DWORD lenA, lenW = (strlenW(strW) + 1) * sizeof(WCHAR);
721
722             RtlUnicodeToMultiByteSize( &lenA, strW, lenW );
723             if ((ptr = get_buffer( buffer, sizeof(buffer), lenA )))
724             {
725                 RtlUnicodeToMultiByteN( ptr, lenA, NULL, strW, lenW );
726                 ret = callback( hwnd, msg, wParam, (LPARAM)ptr, result, arg );
727                 free_buffer( buffer, ptr );
728             }
729         }
730         break;
731
732     case WM_MDICREATE:
733         {
734             char *ptr, buffer[1024];
735             DWORD title_lenA = 0, title_lenW = 0, class_lenA = 0, class_lenW = 0;
736             MDICREATESTRUCTW *csW = (MDICREATESTRUCTW *)lParam;
737             MDICREATESTRUCTA csA;
738
739             memcpy( &csA, csW, sizeof(csA) );
740
741             if (!IS_INTRESOURCE(csW->szTitle))
742             {
743                 title_lenW = (strlenW(csW->szTitle) + 1) * sizeof(WCHAR);
744                 RtlUnicodeToMultiByteSize( &title_lenA, csW->szTitle, title_lenW );
745             }
746             if (!IS_INTRESOURCE(csW->szClass))
747             {
748                 class_lenW = (strlenW(csW->szClass) + 1) * sizeof(WCHAR);
749                 RtlUnicodeToMultiByteSize( &class_lenA, csW->szClass, class_lenW );
750             }
751
752             if (!(ptr = get_buffer( buffer, sizeof(buffer), title_lenA + class_lenA ))) break;
753
754             if (title_lenA)
755             {
756                 RtlUnicodeToMultiByteN( ptr, title_lenA, NULL, csW->szTitle, title_lenW );
757                 csA.szTitle = ptr;
758             }
759             if (class_lenA)
760             {
761                 RtlUnicodeToMultiByteN( ptr + title_lenA, class_lenA, NULL, csW->szClass, class_lenW );
762                 csA.szClass = ptr + title_lenA;
763             }
764             ret = callback( hwnd, msg, wParam, (LPARAM)&csA, result, arg );
765             free_buffer( buffer, ptr );
766         }
767         break;
768
769     case LB_GETTEXT:
770     case CB_GETLBTEXT:
771         if (lParam && WINPROC_TestLBForStr( hwnd, msg ))
772         {
773             char buffer[512];  /* FIXME: fixed sized buffer */
774
775             ret = callback( hwnd, msg, wParam, (LPARAM)buffer, result, arg );
776             if (*result >= 0)
777             {
778                 DWORD len;
779                 RtlMultiByteToUnicodeN( (LPWSTR)lParam, ~0u, &len, buffer, strlen(buffer) + 1 );
780                 *result = len / sizeof(WCHAR) - 1;
781             }
782         }
783         else ret = callback( hwnd, msg, wParam, lParam, result, arg );
784         break;
785
786     case EM_GETLINE:
787         {
788             char *ptr, buffer[512];
789             WORD len = *(WORD *)lParam;
790
791             if (!(ptr = get_buffer( buffer, sizeof(buffer), len * 2 ))) break;
792             *((WORD *)ptr) = len * 2;   /* store the length */
793             ret = callback( hwnd, msg, wParam, (LPARAM)ptr, result, arg );
794             if (*result)
795             {
796                 DWORD reslen;
797                 RtlMultiByteToUnicodeN( (LPWSTR)lParam, len*sizeof(WCHAR), &reslen, ptr, *result );
798                 *result = reslen / sizeof(WCHAR);
799                 if (*result < len) ((LPWSTR)lParam)[*result] = 0;
800             }
801             free_buffer( buffer, ptr );
802         }
803         break;
804
805     case WM_GETDLGCODE:
806         if (lParam)
807         {
808             MSG newmsg = *(MSG *)lParam;
809             switch(newmsg.message)
810             {
811             case WM_CHAR:
812             case WM_DEADCHAR:
813             case WM_SYSCHAR:
814             case WM_SYSDEADCHAR:
815                 newmsg.wParam = map_wparam_char_WtoA( newmsg.wParam, 1 );
816                 break;
817             case WM_IME_CHAR:
818                 newmsg.wParam = map_wparam_char_WtoA( newmsg.wParam, 2 );
819                 break;
820             }
821             ret = callback( hwnd, msg, wParam, (LPARAM)&newmsg, result, arg );
822         }
823         else ret = callback( hwnd, msg, wParam, lParam, result, arg );
824         break;
825
826     case WM_CHAR:
827         {
828             WCHAR wch = wParam;
829             char ch[2];
830             DWORD len;
831
832             RtlUnicodeToMultiByteN( ch, 2, &len, &wch, sizeof(wch) );
833             ret = callback( hwnd, msg, (BYTE)ch[0], lParam, result, arg );
834             if (len == 2) ret = callback( hwnd, msg, (BYTE)ch[1], lParam, result, arg );
835         }
836         break;
837
838     case WM_CHARTOITEM:
839     case WM_MENUCHAR:
840     case WM_DEADCHAR:
841     case WM_SYSCHAR:
842     case WM_SYSDEADCHAR:
843     case EM_SETPASSWORDCHAR:
844         ret = callback( hwnd, msg, map_wparam_char_WtoA(wParam,1), lParam, result, arg );
845         break;
846
847     case WM_IME_CHAR:
848         ret = callback( hwnd, msg, map_wparam_char_WtoA(wParam,2), lParam, result, arg );
849         break;
850
851     case WM_PAINTCLIPBOARD:
852     case WM_SIZECLIPBOARD:
853         FIXME_(msg)( "message %s (%04x) needs translation, please report\n",
854                      SPY_GetMsgName(msg, hwnd), msg );
855         break;
856
857     default:
858         ret = callback( hwnd, msg, wParam, lParam, result, arg );
859         break;
860     }
861
862     return ret;
863 }
864
865
866 /**********************************************************************
867  *              WINPROC_call_window
868  *
869  * Call the window procedure of the specified window.
870  */
871 BOOL WINPROC_call_window( HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam,
872                           LRESULT *result, BOOL unicode, enum wm_char_mapping mapping )
873 {
874     struct user_thread_info *thread_info = get_user_thread_info();
875     WND *wndPtr;
876     WNDPROC func;
877     WINDOWPROC *proc;
878
879     if (!(wndPtr = WIN_GetPtr( hwnd ))) return FALSE;
880     if (wndPtr == WND_OTHER_PROCESS || wndPtr == WND_DESKTOP) return FALSE;
881     if (wndPtr->tid != GetCurrentThreadId())
882     {
883         WIN_ReleasePtr( wndPtr );
884         return FALSE;
885     }
886     func = wndPtr->winproc;
887     proc = handle_to_proc( wndPtr->winproc );
888     WIN_ReleasePtr( wndPtr );
889
890     if (!proc) return TRUE;
891
892     if (thread_info->recursion_count > MAX_WINPROC_RECURSION) return FALSE;
893     thread_info->recursion_count++;
894
895     if (unicode)
896     {
897         if (proc == WINPROC_PROC16)
898             WINPROC_CallProcWtoA( wow_handlers.call_window_proc, hwnd, msg, wParam, lParam, result, func );
899         else if (proc->procW)
900             call_window_proc( hwnd, msg, wParam, lParam, result, proc->procW );
901         else
902             WINPROC_CallProcWtoA( call_window_proc, hwnd, msg, wParam, lParam, result, proc->procA );
903     }
904     else
905     {
906         if (proc == WINPROC_PROC16)
907             wow_handlers.call_window_proc( hwnd, msg, wParam, lParam, result, func );
908         else if (proc->procA)
909             call_window_proc( hwnd, msg, wParam, lParam, result, proc->procA );
910         else
911             WINPROC_CallProcAtoW( call_window_proc, hwnd, msg, wParam, lParam, result, proc->procW, mapping );
912     }
913     thread_info->recursion_count--;
914     return TRUE;
915 }
916
917
918 /**********************************************************************
919  *              CallWindowProcA (USER32.@)
920  *
921  * The CallWindowProc() function invokes the windows procedure _func_,
922  * with _hwnd_ as the target window, the message specified by _msg_, and
923  * the message parameters _wParam_ and _lParam_.
924  *
925  * Some kinds of argument conversion may be done, I'm not sure what.
926  *
927  * CallWindowProc() may be used for windows subclassing. Use
928  * SetWindowLong() to set a new windows procedure for windows of the
929  * subclass, and handle subclassed messages in the new windows
930  * procedure. The new windows procedure may then use CallWindowProc()
931  * with _func_ set to the parent class's windows procedure to dispatch
932  * the message to the superclass.
933  *
934  * RETURNS
935  *
936  *    The return value is message dependent.
937  *
938  * CONFORMANCE
939  *
940  *   ECMA-234, Win32
941  */
942 LRESULT WINAPI CallWindowProcA(
943     WNDPROC func,  /* [in] window procedure */
944     HWND hwnd,     /* [in] target window */
945     UINT msg,      /* [in] message */
946     WPARAM wParam, /* [in] message dependent parameter */
947     LPARAM lParam  /* [in] message dependent parameter */
948 ) {
949     WINDOWPROC *proc;
950     LRESULT result;
951
952     if (!func) return 0;
953
954     if (!(proc = handle_to_proc( func )))
955         call_window_proc( hwnd, msg, wParam, lParam, &result, func );
956     else if (proc == WINPROC_PROC16)
957         wow_handlers.call_window_proc( hwnd, msg, wParam, lParam, &result, func );
958     else if (proc->procA)
959         call_window_proc( hwnd, msg, wParam, lParam, &result, proc->procA );
960     else
961         WINPROC_CallProcAtoW( call_window_proc, hwnd, msg, wParam, lParam, &result,
962                               proc->procW, WMCHAR_MAP_CALLWINDOWPROC );
963     return result;
964 }
965
966
967 /**********************************************************************
968  *              CallWindowProcW (USER32.@)
969  *
970  * See CallWindowProcA.
971  */
972 LRESULT WINAPI CallWindowProcW( WNDPROC func, HWND hwnd, UINT msg,
973                                   WPARAM wParam, LPARAM lParam )
974 {
975     WINDOWPROC *proc;
976     LRESULT result;
977
978     if (!func) return 0;
979
980     if (!(proc = handle_to_proc( func )))
981         call_window_proc( hwnd, msg, wParam, lParam, &result, func );
982     else if (proc == WINPROC_PROC16)
983         WINPROC_CallProcWtoA( wow_handlers.call_window_proc, hwnd, msg, wParam, lParam, &result, func );
984     else if (proc->procW)
985         call_window_proc( hwnd, msg, wParam, lParam, &result, proc->procW );
986     else
987         WINPROC_CallProcWtoA( call_window_proc, hwnd, msg, wParam, lParam, &result, proc->procA );
988     return result;
989 }
990
991
992 /**********************************************************************
993  *              WINPROC_CallDlgProcA
994  */
995 INT_PTR WINPROC_CallDlgProcA( DLGPROC func, HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam )
996 {
997     WINDOWPROC *proc;
998     LRESULT result;
999     INT_PTR ret;
1000
1001     if (!func) return 0;
1002
1003     if (!(proc = handle_to_proc( func )))
1004         ret = call_dialog_proc( hwnd, msg, wParam, lParam, &result, func );
1005     else if (proc == WINPROC_PROC16)
1006     {
1007         ret = wow_handlers.call_dialog_proc( hwnd, msg, wParam, lParam, &result, func );
1008         SetWindowLongPtrW( hwnd, DWLP_MSGRESULT, result );
1009     }
1010     else if (proc->procW)
1011     {
1012         ret = WINPROC_CallProcAtoW( call_dialog_proc, hwnd, msg, wParam, lParam, &result,
1013                                     proc->procW, WMCHAR_MAP_CALLWINDOWPROC );
1014         SetWindowLongPtrW( hwnd, DWLP_MSGRESULT, result );
1015     }
1016     else
1017         ret = call_dialog_proc( hwnd, msg, wParam, lParam, &result, proc->procA );
1018     return ret;
1019 }
1020
1021
1022 /**********************************************************************
1023  *              WINPROC_CallDlgProcW
1024  */
1025 INT_PTR WINPROC_CallDlgProcW( DLGPROC func, HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam )
1026 {
1027     WINDOWPROC *proc;
1028     LRESULT result;
1029     INT_PTR ret;
1030
1031     if (!func) return 0;
1032
1033     if (!(proc = handle_to_proc( func )))
1034         ret = call_dialog_proc( hwnd, msg, wParam, lParam, &result, func );
1035     else if (proc == WINPROC_PROC16)
1036     {
1037         ret = WINPROC_CallProcWtoA( wow_handlers.call_dialog_proc, hwnd, msg, wParam, lParam, &result, func );
1038         SetWindowLongPtrW( hwnd, DWLP_MSGRESULT, result );
1039     }
1040     else if (proc->procA)
1041     {
1042         ret = WINPROC_CallProcWtoA( call_dialog_proc, hwnd, msg, wParam, lParam, &result, proc->procA );
1043         SetWindowLongPtrW( hwnd, DWLP_MSGRESULT, result );
1044     }
1045     else
1046         ret = call_dialog_proc( hwnd, msg, wParam, lParam, &result, proc->procW );
1047     return ret;
1048 }
1049
1050
1051 /***********************************************************************
1052  * Window procedures for builtin classes
1053  */
1054
1055 static LRESULT WINAPI ButtonWndProcA( HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam )
1056 {
1057     return wow_handlers.button_proc( hwnd, msg, wParam, lParam, FALSE );
1058 }
1059
1060 static LRESULT WINAPI ButtonWndProcW( HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam )
1061 {
1062     return wow_handlers.button_proc( hwnd, msg, wParam, lParam, TRUE );
1063 }
1064
1065 static LRESULT WINAPI ComboWndProcA( HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam )
1066 {
1067     return wow_handlers.combo_proc( hwnd, message, wParam, lParam, FALSE );
1068 }
1069
1070 static LRESULT WINAPI ComboWndProcW( HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam )
1071 {
1072     return wow_handlers.combo_proc( hwnd, message, wParam, lParam, TRUE );
1073 }
1074
1075 LRESULT WINAPI EditWndProcA( HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam )
1076 {
1077     return wow_handlers.edit_proc( hwnd, msg, wParam, lParam, FALSE );
1078 }
1079
1080 static LRESULT WINAPI EditWndProcW( HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam )
1081 {
1082     return wow_handlers.edit_proc( hwnd, msg, wParam, lParam, TRUE );
1083 }
1084
1085 static LRESULT WINAPI ListBoxWndProcA( HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam )
1086 {
1087     return wow_handlers.listbox_proc( hwnd, msg, wParam, lParam, FALSE );
1088 }
1089
1090 static LRESULT WINAPI ListBoxWndProcW( HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam )
1091 {
1092     return wow_handlers.listbox_proc( hwnd, msg, wParam, lParam, TRUE );
1093 }
1094
1095 static LRESULT WINAPI MDIClientWndProcA( HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam )
1096 {
1097     return wow_handlers.mdiclient_proc( hwnd, msg, wParam, lParam, FALSE );
1098 }
1099
1100 static LRESULT WINAPI MDIClientWndProcW( HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam )
1101 {
1102     return wow_handlers.mdiclient_proc( hwnd, msg, wParam, lParam, TRUE );
1103 }
1104
1105 static LRESULT WINAPI ScrollBarWndProcA( HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam )
1106 {
1107     return wow_handlers.scrollbar_proc( hwnd, msg, wParam, lParam, FALSE );
1108 }
1109
1110 static LRESULT WINAPI ScrollBarWndProcW( HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam )
1111 {
1112     return wow_handlers.scrollbar_proc( hwnd, msg, wParam, lParam, TRUE );
1113 }
1114
1115 static LRESULT WINAPI StaticWndProcA( HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam )
1116 {
1117     return wow_handlers.static_proc( hwnd, msg, wParam, lParam, FALSE );
1118 }
1119
1120 static LRESULT WINAPI StaticWndProcW( HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam )
1121 {
1122     return wow_handlers.static_proc( hwnd, msg, wParam, lParam, TRUE );
1123 }
1124
1125 static DWORD wait_message( DWORD count, CONST HANDLE *handles, DWORD timeout, DWORD mask, DWORD flags )
1126 {
1127     DWORD ret = USER_Driver->pMsgWaitForMultipleObjectsEx( count, handles, timeout, mask, flags );
1128     if (ret == WAIT_TIMEOUT && !count && !timeout) NtYieldExecution();
1129     if ((mask & QS_INPUT) == QS_INPUT) get_user_thread_info()->message_count = 0;
1130     return ret;
1131 }
1132
1133 /**********************************************************************
1134  *              UserRegisterWowHandlers (USER32.@)
1135  *
1136  * NOTE: no attempt has been made to be compatible here,
1137  * the Windows function is most likely completely different.
1138  */
1139 void WINAPI UserRegisterWowHandlers( const struct wow_handlers16 *new, struct wow_handlers32 *orig )
1140 {
1141     orig->button_proc     = ButtonWndProc_common;
1142     orig->combo_proc      = ComboWndProc_common;
1143     orig->edit_proc       = EditWndProc_common;
1144     orig->listbox_proc    = ListBoxWndProc_common;
1145     orig->mdiclient_proc  = MDIClientWndProc_common;
1146     orig->scrollbar_proc  = ScrollBarWndProc_common;
1147     orig->static_proc     = StaticWndProc_common;
1148     orig->wait_message    = wait_message;
1149     orig->create_window   = WIN_CreateWindowEx;
1150     orig->get_win_handle  = WIN_GetFullHandle;
1151     orig->alloc_winproc   = WINPROC_AllocProc;
1152     orig->get_dialog_info = DIALOG_get_info;
1153     orig->dialog_box_loop = DIALOG_DoDialogBox;
1154     orig->get_icon_param  = get_icon_param;
1155     orig->set_icon_param  = set_icon_param;
1156
1157     wow_handlers = *new;
1158 }
1159
1160 struct wow_handlers16 wow_handlers =
1161 {
1162     ButtonWndProc_common,
1163     ComboWndProc_common,
1164     EditWndProc_common,
1165     ListBoxWndProc_common,
1166     MDIClientWndProc_common,
1167     ScrollBarWndProc_common,
1168     StaticWndProc_common,
1169     wait_message,
1170     WIN_CreateWindowEx,
1171     NULL,  /* call_window_proc */
1172     NULL,  /* call_dialog_proc */
1173     NULL,  /* free_icon_param */
1174 };