2 * Window procedure callbacks
4 * Copyright 1995 Martin von Loewis
5 * Copyright 1996 Alexandre Julliard
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.
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.
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
23 #include "wine/port.h"
34 #include "user_private.h"
35 #include "wine/unicode.h"
36 #include "wine/debug.h"
38 WINE_DECLARE_DEBUG_CHANNEL(msg
);
39 WINE_DECLARE_DEBUG_CHANNEL(relay
);
40 WINE_DEFAULT_DEBUG_CHANNEL(win
);
42 typedef struct tagWINDOWPROC
44 WNDPROC procA
; /* ASCII window proc */
45 WNDPROC procW
; /* Unicode window proc */
48 #define MAX_WINPROCS 4096
49 #define MAX_WINPROC_RECURSION 64
50 #define WINPROC_PROC16 ((WINDOWPROC *)1) /* placeholder for 16-bit window procs */
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
);
67 static WINDOWPROC winproc_array
[MAX_WINPROCS
] =
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 { ImeWndProcA
, ImeWndProcW
}, /* WINPROC_IME */
79 { NULL
, DesktopWndProc
}, /* WINPROC_DESKTOP */
80 { NULL
, IconTitleWndProc
}, /* WINPROC_ICONTITLE */
81 { NULL
, PopupMenuWndProc
}, /* WINPROC_MENU */
82 { NULL
, MessageWndProc
}, /* WINPROC_MESSAGE */
85 static UINT winproc_used
= NB_BUILTIN_WINPROCS
;
87 static CRITICAL_SECTION winproc_cs
;
88 static CRITICAL_SECTION_DEBUG critsect_debug
=
91 { &critsect_debug
.ProcessLocksList
, &critsect_debug
.ProcessLocksList
},
92 0, 0, { (DWORD_PTR
)(__FILE__
": winproc_cs") }
94 static CRITICAL_SECTION winproc_cs
= { &critsect_debug
, -1, 0, 0, 0, 0 };
96 static inline void *get_buffer( void *static_buffer
, size_t size
, size_t need
)
98 if (size
>= need
) return static_buffer
;
99 return HeapAlloc( GetProcessHeap(), 0, need
);
102 static inline void free_buffer( void *static_buffer
, void *buffer
)
104 if (buffer
!= static_buffer
) HeapFree( GetProcessHeap(), 0, buffer
);
107 /* find an existing winproc for a given function and type */
108 /* FIXME: probably should do something more clever than a linear search */
109 static inline WINDOWPROC
*find_winproc( WNDPROC func
, BOOL unicode
)
113 for (i
= 0; i
< NB_BUILTIN_AW_WINPROCS
; i
++)
115 /* match either proc, some apps confuse A and W */
116 if (winproc_array
[i
].procA
!= func
&& winproc_array
[i
].procW
!= func
) continue;
117 return &winproc_array
[i
];
119 for (i
= NB_BUILTIN_AW_WINPROCS
; i
< winproc_used
; i
++)
121 if (!unicode
&& winproc_array
[i
].procA
!= func
) continue;
122 if (unicode
&& winproc_array
[i
].procW
!= func
) continue;
123 return &winproc_array
[i
];
128 /* return the window proc for a given handle, or NULL for an invalid handle,
129 * or WINPROC_PROC16 for a handle to a 16-bit proc. */
130 static inline WINDOWPROC
*handle_to_proc( WNDPROC handle
)
132 UINT index
= LOWORD(handle
);
133 if ((ULONG_PTR
)handle
>> 16 != WINPROC_HANDLE
) return NULL
;
134 if (index
>= MAX_WINPROCS
) return WINPROC_PROC16
;
135 if (index
>= winproc_used
) return NULL
;
136 return &winproc_array
[index
];
139 /* create a handle for a given window proc */
140 static inline WNDPROC
proc_to_handle( WINDOWPROC
*proc
)
142 return (WNDPROC
)(ULONG_PTR
)((proc
- winproc_array
) | (WINPROC_HANDLE
<< 16));
145 /* allocate and initialize a new winproc */
146 static inline WINDOWPROC
*alloc_winproc( WNDPROC func
, BOOL unicode
)
150 /* check if the function is already a win proc */
151 if (!func
) return NULL
;
152 if ((proc
= handle_to_proc( func
))) return proc
;
154 EnterCriticalSection( &winproc_cs
);
156 /* check if we already have a winproc for that function */
157 if (!(proc
= find_winproc( func
, unicode
)))
159 if (winproc_used
< MAX_WINPROCS
)
161 proc
= &winproc_array
[winproc_used
++];
162 if (unicode
) proc
->procW
= func
;
163 else proc
->procA
= func
;
164 TRACE( "allocated %p for %c %p (%d/%d used)\n",
165 proc_to_handle(proc
), unicode
? 'W' : 'A', func
,
166 winproc_used
, MAX_WINPROCS
);
168 else WARN( "too many winprocs, cannot allocate one for %p\n", func
);
170 else TRACE( "reusing %p for %p\n", proc_to_handle(proc
), func
);
172 LeaveCriticalSection( &winproc_cs
);
177 /* Some window procedures modify register they shouldn't, or are not
178 * properly declared stdcall; so we need a small assembly wrapper to
180 extern LRESULT
WINPROC_wrapper( WNDPROC proc
, HWND hwnd
, UINT msg
,
181 WPARAM wParam
, LPARAM lParam
);
182 __ASM_GLOBAL_FUNC( WINPROC_wrapper
,
184 __ASM_CFI(".cfi_adjust_cfa_offset 4\n\t")
185 __ASM_CFI(".cfi_rel_offset %ebp,0\n\t")
187 __ASM_CFI(".cfi_def_cfa_register %ebp\n\t")
189 __ASM_CFI(".cfi_rel_offset %edi,-4\n\t")
191 __ASM_CFI(".cfi_rel_offset %esi,-8\n\t")
193 __ASM_CFI(".cfi_rel_offset %ebx,-12\n\t")
194 /* TreePad X Enterprise assumes that edi is < 0x80000000 in WM_TIMER messages */
201 "movl 8(%ebp),%eax\n\t"
203 "leal -12(%ebp),%esp\n\t"
205 __ASM_CFI(".cfi_same_value %ebx\n\t")
207 __ASM_CFI(".cfi_same_value %esi\n\t")
209 __ASM_CFI(".cfi_same_value %edi\n\t")
211 __ASM_CFI(".cfi_def_cfa %esp,4\n\t")
212 __ASM_CFI(".cfi_same_value %ebp\n\t")
215 static inline LRESULT
WINPROC_wrapper( WNDPROC proc
, HWND hwnd
, UINT msg
,
216 WPARAM wParam
, LPARAM lParam
)
218 return proc( hwnd
, msg
, wParam
, lParam
);
220 #endif /* __i386__ */
222 static WPARAM
map_wparam_char_WtoA( WPARAM wParam
, DWORD len
)
226 DWORD cp
= get_input_codepage();
228 len
= WideCharToMultiByte( cp
, 0, &wch
, 1, (LPSTR
)ch
, len
, NULL
, NULL
);
230 return MAKEWPARAM( (ch
[0] << 8) | ch
[1], HIWORD(wParam
) );
232 return MAKEWPARAM( ch
[0], HIWORD(wParam
) );
235 /* call a 32-bit window procedure */
236 static LRESULT
call_window_proc( HWND hwnd
, UINT msg
, WPARAM wp
, LPARAM lp
, LRESULT
*result
, void *arg
)
238 DPI_AWARENESS_CONTEXT context
;
243 hwnd
= WIN_GetFullHandle( hwnd
);
244 TRACE_(relay
)( "\1Call window proc %p (hwnd=%p,msg=%s,wp=%08lx,lp=%08lx)\n",
245 proc
, hwnd
, SPY_GetMsgName(msg
, hwnd
), wp
, lp
);
247 context
= SetThreadDpiAwarenessContext( GetWindowDpiAwarenessContext( hwnd
));
248 *result
= WINPROC_wrapper( proc
, hwnd
, msg
, wp
, lp
);
249 SetThreadDpiAwarenessContext( context
);
251 TRACE_(relay
)( "\1Ret window proc %p (hwnd=%p,msg=%s,wp=%08lx,lp=%08lx) retval=%08lx\n",
252 proc
, hwnd
, SPY_GetMsgName(msg
, hwnd
), wp
, lp
, *result
);
256 /* call a 32-bit dialog procedure */
257 static LRESULT
call_dialog_proc( HWND hwnd
, UINT msg
, WPARAM wp
, LPARAM lp
, LRESULT
*result
, void *arg
)
259 DPI_AWARENESS_CONTEXT context
;
265 hwnd
= WIN_GetFullHandle( hwnd
);
266 TRACE_(relay
)( "\1Call dialog proc %p (hwnd=%p,msg=%s,wp=%08lx,lp=%08lx)\n",
267 proc
, hwnd
, SPY_GetMsgName(msg
, hwnd
), wp
, lp
);
269 context
= SetThreadDpiAwarenessContext( GetWindowDpiAwarenessContext( hwnd
));
270 ret
= WINPROC_wrapper( proc
, hwnd
, msg
, wp
, lp
);
271 *result
= GetWindowLongPtrW( hwnd
, DWLP_MSGRESULT
);
272 SetThreadDpiAwarenessContext( context
);
274 TRACE_(relay
)( "\1Ret dialog proc %p (hwnd=%p,msg=%s,wp=%08lx,lp=%08lx) retval=%08lx result=%08lx\n",
275 proc
, hwnd
, SPY_GetMsgName(msg
, hwnd
), wp
, lp
, ret
, *result
);
280 /**********************************************************************
283 * Get a window procedure pointer that can be passed to the Windows program.
285 WNDPROC
WINPROC_GetProc( WNDPROC proc
, BOOL unicode
)
287 WINDOWPROC
*ptr
= handle_to_proc( proc
);
289 if (!ptr
|| ptr
== WINPROC_PROC16
) return proc
;
292 if (ptr
->procW
) return ptr
->procW
;
297 if (ptr
->procA
) return ptr
->procA
;
303 /**********************************************************************
306 * Allocate a window procedure for a window or class.
308 * Note that allocated winprocs are never freed; the idea is that even if an app creates a
309 * lot of windows, it will usually only have a limited number of window procedures, so the
310 * array won't grow too large, and this way we avoid the need to track allocations per window.
312 WNDPROC
WINPROC_AllocProc( WNDPROC func
, BOOL unicode
)
316 if (!(proc
= alloc_winproc( func
, unicode
))) return func
;
317 if (proc
== WINPROC_PROC16
) return func
;
318 return proc_to_handle( proc
);
322 /**********************************************************************
325 * Return the window procedure type, or the default value if not a winproc handle.
327 BOOL
WINPROC_IsUnicode( WNDPROC proc
, BOOL def_val
)
329 WINDOWPROC
*ptr
= handle_to_proc( proc
);
331 if (!ptr
) return def_val
;
332 if (ptr
== WINPROC_PROC16
) return FALSE
; /* 16-bit is always A */
333 if (ptr
->procA
&& ptr
->procW
) return def_val
; /* can be both */
334 return (ptr
->procW
!= NULL
);
338 /**********************************************************************
339 * WINPROC_TestLBForStr
341 * Return TRUE if the lparam is a string
343 static inline BOOL
WINPROC_TestLBForStr( HWND hwnd
, UINT msg
)
345 DWORD style
= GetWindowLongA( hwnd
, GWL_STYLE
);
346 if (msg
<= CB_MSGMAX
)
347 return (!(style
& (CBS_OWNERDRAWFIXED
| CBS_OWNERDRAWVARIABLE
)) || (style
& CBS_HASSTRINGS
));
349 return (!(style
& (LBS_OWNERDRAWFIXED
| LBS_OWNERDRAWVARIABLE
)) || (style
& LBS_HASSTRINGS
));
354 /**********************************************************************
355 * WINPROC_CallProcAtoW
357 * Call a window procedure, translating args from Ansi to Unicode.
359 LRESULT
WINPROC_CallProcAtoW( winproc_callback_t callback
, HWND hwnd
, UINT msg
, WPARAM wParam
,
360 LPARAM lParam
, LRESULT
*result
, void *arg
, enum wm_char_mapping mapping
)
364 TRACE_(msg
)("(hwnd=%p,msg=%s,wp=%08lx,lp=%08lx)\n",
365 hwnd
, SPY_GetMsgName(msg
, hwnd
), wParam
, lParam
);
372 WCHAR
*ptr
, buffer
[512];
373 CREATESTRUCTA
*csA
= (CREATESTRUCTA
*)lParam
;
374 CREATESTRUCTW csW
= *(CREATESTRUCTW
*)csA
;
375 MDICREATESTRUCTW mdi_cs
;
376 DWORD name_lenA
= 0, name_lenW
= 0, class_lenA
= 0, class_lenW
= 0;
378 if (!IS_INTRESOURCE(csA
->lpszClass
))
380 class_lenA
= strlen(csA
->lpszClass
) + 1;
381 RtlMultiByteToUnicodeSize( &class_lenW
, csA
->lpszClass
, class_lenA
);
383 if (!IS_INTRESOURCE(csA
->lpszName
))
385 name_lenA
= strlen(csA
->lpszName
) + 1;
386 RtlMultiByteToUnicodeSize( &name_lenW
, csA
->lpszName
, name_lenA
);
389 if (!(ptr
= get_buffer( buffer
, sizeof(buffer
), class_lenW
+ name_lenW
))) break;
394 RtlMultiByteToUnicodeN( ptr
, class_lenW
, NULL
, csA
->lpszClass
, class_lenA
);
398 csW
.lpszName
= ptr
+ class_lenW
/sizeof(WCHAR
);
399 RtlMultiByteToUnicodeN( ptr
+ class_lenW
/sizeof(WCHAR
), name_lenW
, NULL
,
400 csA
->lpszName
, name_lenA
);
403 if (GetWindowLongW(hwnd
, GWL_EXSTYLE
) & WS_EX_MDICHILD
)
405 mdi_cs
= *(MDICREATESTRUCTW
*)csA
->lpCreateParams
;
406 mdi_cs
.szTitle
= csW
.lpszName
;
407 mdi_cs
.szClass
= csW
.lpszClass
;
408 csW
.lpCreateParams
= &mdi_cs
;
411 ret
= callback( hwnd
, msg
, wParam
, (LPARAM
)&csW
, result
, arg
);
412 free_buffer( buffer
, ptr
);
418 WCHAR
*ptr
, buffer
[512];
419 DWORD title_lenA
= 0, title_lenW
= 0, class_lenA
= 0, class_lenW
= 0;
420 MDICREATESTRUCTA
*csA
= (MDICREATESTRUCTA
*)lParam
;
421 MDICREATESTRUCTW csW
;
423 memcpy( &csW
, csA
, sizeof(csW
) );
425 if (!IS_INTRESOURCE(csA
->szTitle
))
427 title_lenA
= strlen(csA
->szTitle
) + 1;
428 RtlMultiByteToUnicodeSize( &title_lenW
, csA
->szTitle
, title_lenA
);
430 if (!IS_INTRESOURCE(csA
->szClass
))
432 class_lenA
= strlen(csA
->szClass
) + 1;
433 RtlMultiByteToUnicodeSize( &class_lenW
, csA
->szClass
, class_lenA
);
436 if (!(ptr
= get_buffer( buffer
, sizeof(buffer
), title_lenW
+ class_lenW
))) break;
441 RtlMultiByteToUnicodeN( ptr
, title_lenW
, NULL
, csA
->szTitle
, title_lenA
);
445 csW
.szClass
= ptr
+ title_lenW
/sizeof(WCHAR
);
446 RtlMultiByteToUnicodeN( ptr
+ title_lenW
/sizeof(WCHAR
), class_lenW
, NULL
,
447 csA
->szClass
, class_lenA
);
449 ret
= callback( hwnd
, msg
, wParam
, (LPARAM
)&csW
, result
, arg
);
450 free_buffer( buffer
, ptr
);
455 case WM_ASKCBFORMATNAME
:
457 WCHAR
*ptr
, buffer
[512];
458 LPSTR str
= (LPSTR
)lParam
;
459 DWORD len
= wParam
* sizeof(WCHAR
);
461 if (!(ptr
= get_buffer( buffer
, sizeof(buffer
), len
))) break;
462 ret
= callback( hwnd
, msg
, wParam
, (LPARAM
)ptr
, result
, arg
);
467 RtlUnicodeToMultiByteN( str
, wParam
- 1, &len
, ptr
, ret
* sizeof(WCHAR
) );
471 free_buffer( buffer
, ptr
);
476 case LB_INSERTSTRING
:
478 case LB_FINDSTRINGEXACT
:
479 case LB_SELECTSTRING
:
481 case CB_INSERTSTRING
:
483 case CB_FINDSTRINGEXACT
:
484 case CB_SELECTSTRING
:
485 if (!lParam
|| !WINPROC_TestLBForStr( hwnd
, msg
))
487 ret
= callback( hwnd
, msg
, wParam
, lParam
, result
, arg
);
492 case WM_WININICHANGE
:
493 case WM_DEVMODECHANGE
:
498 if (!lParam
) ret
= callback( hwnd
, msg
, wParam
, lParam
, result
, arg
);
501 WCHAR
*ptr
, buffer
[512];
502 LPCSTR strA
= (LPCSTR
)lParam
;
503 DWORD lenW
, lenA
= strlen(strA
) + 1;
505 RtlMultiByteToUnicodeSize( &lenW
, strA
, lenA
);
506 if ((ptr
= get_buffer( buffer
, sizeof(buffer
), lenW
)))
508 RtlMultiByteToUnicodeN( ptr
, lenW
, NULL
, strA
, lenA
);
509 ret
= callback( hwnd
, msg
, wParam
, (LPARAM
)ptr
, result
, arg
);
510 free_buffer( buffer
, ptr
);
517 if (lParam
&& WINPROC_TestLBForStr( hwnd
, msg
))
519 WCHAR buffer
[512]; /* FIXME: fixed sized buffer */
521 ret
= callback( hwnd
, msg
, wParam
, (LPARAM
)buffer
, result
, arg
);
525 RtlUnicodeToMultiByteN( (LPSTR
)lParam
, ~0u, &len
,
526 buffer
, (strlenW(buffer
) + 1) * sizeof(WCHAR
) );
530 else ret
= callback( hwnd
, msg
, wParam
, lParam
, result
, arg
);
535 WCHAR
*ptr
, buffer
[512];
536 WORD len
= *(WORD
*)lParam
;
538 if (!(ptr
= get_buffer( buffer
, sizeof(buffer
), len
* sizeof(WCHAR
) ))) break;
539 *((WORD
*)ptr
) = len
; /* store the length */
540 ret
= callback( hwnd
, msg
, wParam
, (LPARAM
)ptr
, result
, arg
);
544 RtlUnicodeToMultiByteN( (LPSTR
)lParam
, len
, &reslen
, ptr
, *result
* sizeof(WCHAR
) );
545 if (reslen
< len
) ((LPSTR
)lParam
)[reslen
] = 0;
548 free_buffer( buffer
, ptr
);
555 MSG newmsg
= *(MSG
*)lParam
;
556 if (map_wparam_AtoW( newmsg
.message
, &newmsg
.wParam
, WMCHAR_MAP_NOMAPPING
))
557 ret
= callback( hwnd
, msg
, wParam
, (LPARAM
)&newmsg
, result
, arg
);
559 else ret
= callback( hwnd
, msg
, wParam
, lParam
, result
, arg
);
568 case EM_SETPASSWORDCHAR
:
570 if (map_wparam_AtoW( msg
, &wParam
, mapping
))
571 ret
= callback( hwnd
, msg
, wParam
, lParam
, result
, arg
);
574 case WM_GETTEXTLENGTH
:
575 case CB_GETLBTEXTLEN
:
577 ret
= callback( hwnd
, msg
, wParam
, lParam
, result
, arg
);
580 WCHAR
*ptr
, buffer
[512];
582 DWORD len
= *result
+ 1;
583 /* Determine respective GETTEXT message */
584 UINT msgGetText
= (msg
== WM_GETTEXTLENGTH
) ? WM_GETTEXT
:
585 ((msg
== CB_GETLBTEXTLEN
) ? CB_GETLBTEXT
: LB_GETTEXT
);
586 /* wParam differs between the messages */
587 WPARAM wp
= (msg
== WM_GETTEXTLENGTH
) ? len
: wParam
;
589 if (!(ptr
= get_buffer( buffer
, sizeof(buffer
), len
* sizeof(WCHAR
) ))) break;
591 if (callback
== call_window_proc
) /* FIXME: hack */
592 callback( hwnd
, msgGetText
, wp
, (LPARAM
)ptr
, &tmp
, arg
);
594 tmp
= SendMessageW( hwnd
, msgGetText
, wp
, (LPARAM
)ptr
);
595 RtlUnicodeToMultiByteSize( &len
, ptr
, tmp
* sizeof(WCHAR
) );
597 free_buffer( buffer
, ptr
);
601 case WM_PAINTCLIPBOARD
:
602 case WM_SIZECLIPBOARD
:
603 FIXME_(msg
)( "message %s (0x%x) needs translation, please report\n",
604 SPY_GetMsgName(msg
, hwnd
), msg
);
608 ret
= callback( hwnd
, msg
, wParam
, lParam
, result
, arg
);
615 /**********************************************************************
616 * WINPROC_CallProcWtoA
618 * Call a window procedure, translating args from Unicode to Ansi.
620 static LRESULT
WINPROC_CallProcWtoA( winproc_callback_t callback
, HWND hwnd
, UINT msg
, WPARAM wParam
,
621 LPARAM lParam
, LRESULT
*result
, void *arg
)
625 TRACE_(msg
)("(hwnd=%p,msg=%s,wp=%08lx,lp=%08lx)\n",
626 hwnd
, SPY_GetMsgName(msg
, hwnd
), wParam
, lParam
);
633 char buffer
[1024], *cls
;
634 CREATESTRUCTW
*csW
= (CREATESTRUCTW
*)lParam
;
635 CREATESTRUCTA csA
= *(CREATESTRUCTA
*)csW
;
636 MDICREATESTRUCTA mdi_cs
;
637 DWORD name_lenA
= 0, name_lenW
= 0, class_lenA
= 0, class_lenW
= 0;
639 if (!IS_INTRESOURCE(csW
->lpszClass
))
641 class_lenW
= (strlenW(csW
->lpszClass
) + 1) * sizeof(WCHAR
);
642 RtlUnicodeToMultiByteSize(&class_lenA
, csW
->lpszClass
, class_lenW
);
644 if (!IS_INTRESOURCE(csW
->lpszName
))
646 name_lenW
= (strlenW(csW
->lpszName
) + 1) * sizeof(WCHAR
);
647 RtlUnicodeToMultiByteSize(&name_lenA
, csW
->lpszName
, name_lenW
);
650 if (!(cls
= get_buffer( buffer
, sizeof(buffer
), class_lenA
+ name_lenA
))) break;
654 RtlUnicodeToMultiByteN(cls
, class_lenA
, NULL
, csW
->lpszClass
, class_lenW
);
659 char *name
= cls
+ class_lenA
;
660 RtlUnicodeToMultiByteN(name
, name_lenA
, NULL
, csW
->lpszName
, name_lenW
);
664 if (GetWindowLongW(hwnd
, GWL_EXSTYLE
) & WS_EX_MDICHILD
)
666 mdi_cs
= *(MDICREATESTRUCTA
*)csW
->lpCreateParams
;
667 mdi_cs
.szTitle
= csA
.lpszName
;
668 mdi_cs
.szClass
= csA
.lpszClass
;
669 csA
.lpCreateParams
= &mdi_cs
;
672 ret
= callback( hwnd
, msg
, wParam
, (LPARAM
)&csA
, result
, arg
);
673 free_buffer( buffer
, cls
);
678 case WM_ASKCBFORMATNAME
:
680 char *ptr
, buffer
[512];
681 DWORD len
= wParam
* 2;
683 if (!(ptr
= get_buffer( buffer
, sizeof(buffer
), len
))) break;
684 ret
= callback( hwnd
, msg
, wParam
, (LPARAM
)ptr
, result
, arg
);
689 RtlMultiByteToUnicodeN( (LPWSTR
)lParam
, wParam
*sizeof(WCHAR
), &len
, ptr
, ret
+ 1 );
690 *result
= len
/sizeof(WCHAR
) - 1; /* do not count terminating null */
692 ((LPWSTR
)lParam
)[*result
] = 0;
694 free_buffer( buffer
, ptr
);
699 case LB_INSERTSTRING
:
701 case LB_FINDSTRINGEXACT
:
702 case LB_SELECTSTRING
:
704 case CB_INSERTSTRING
:
706 case CB_FINDSTRINGEXACT
:
707 case CB_SELECTSTRING
:
708 if (!lParam
|| !WINPROC_TestLBForStr( hwnd
, msg
))
710 ret
= callback( hwnd
, msg
, wParam
, lParam
, result
, arg
);
715 case WM_WININICHANGE
:
716 case WM_DEVMODECHANGE
:
721 if (!lParam
) ret
= callback( hwnd
, msg
, wParam
, lParam
, result
, arg
);
724 char *ptr
, buffer
[512];
725 LPCWSTR strW
= (LPCWSTR
)lParam
;
726 DWORD lenA
, lenW
= (strlenW(strW
) + 1) * sizeof(WCHAR
);
728 RtlUnicodeToMultiByteSize( &lenA
, strW
, lenW
);
729 if ((ptr
= get_buffer( buffer
, sizeof(buffer
), lenA
)))
731 RtlUnicodeToMultiByteN( ptr
, lenA
, NULL
, strW
, lenW
);
732 ret
= callback( hwnd
, msg
, wParam
, (LPARAM
)ptr
, result
, arg
);
733 free_buffer( buffer
, ptr
);
740 char *ptr
, buffer
[1024];
741 DWORD title_lenA
= 0, title_lenW
= 0, class_lenA
= 0, class_lenW
= 0;
742 MDICREATESTRUCTW
*csW
= (MDICREATESTRUCTW
*)lParam
;
743 MDICREATESTRUCTA csA
;
745 memcpy( &csA
, csW
, sizeof(csA
) );
747 if (!IS_INTRESOURCE(csW
->szTitle
))
749 title_lenW
= (strlenW(csW
->szTitle
) + 1) * sizeof(WCHAR
);
750 RtlUnicodeToMultiByteSize( &title_lenA
, csW
->szTitle
, title_lenW
);
752 if (!IS_INTRESOURCE(csW
->szClass
))
754 class_lenW
= (strlenW(csW
->szClass
) + 1) * sizeof(WCHAR
);
755 RtlUnicodeToMultiByteSize( &class_lenA
, csW
->szClass
, class_lenW
);
758 if (!(ptr
= get_buffer( buffer
, sizeof(buffer
), title_lenA
+ class_lenA
))) break;
762 RtlUnicodeToMultiByteN( ptr
, title_lenA
, NULL
, csW
->szTitle
, title_lenW
);
767 RtlUnicodeToMultiByteN( ptr
+ title_lenA
, class_lenA
, NULL
, csW
->szClass
, class_lenW
);
768 csA
.szClass
= ptr
+ title_lenA
;
770 ret
= callback( hwnd
, msg
, wParam
, (LPARAM
)&csA
, result
, arg
);
771 free_buffer( buffer
, ptr
);
777 if (lParam
&& WINPROC_TestLBForStr( hwnd
, msg
))
779 char buffer
[512]; /* FIXME: fixed sized buffer */
781 ret
= callback( hwnd
, msg
, wParam
, (LPARAM
)buffer
, result
, arg
);
785 RtlMultiByteToUnicodeN( (LPWSTR
)lParam
, ~0u, &len
, buffer
, strlen(buffer
) + 1 );
786 *result
= len
/ sizeof(WCHAR
) - 1;
789 else ret
= callback( hwnd
, msg
, wParam
, lParam
, result
, arg
);
794 char *ptr
, buffer
[512];
795 WORD len
= *(WORD
*)lParam
;
797 if (!(ptr
= get_buffer( buffer
, sizeof(buffer
), len
* 2 ))) break;
798 *((WORD
*)ptr
) = len
* 2; /* store the length */
799 ret
= callback( hwnd
, msg
, wParam
, (LPARAM
)ptr
, result
, arg
);
803 RtlMultiByteToUnicodeN( (LPWSTR
)lParam
, len
*sizeof(WCHAR
), &reslen
, ptr
, *result
);
804 *result
= reslen
/ sizeof(WCHAR
);
805 if (*result
< len
) ((LPWSTR
)lParam
)[*result
] = 0;
807 free_buffer( buffer
, ptr
);
814 MSG newmsg
= *(MSG
*)lParam
;
815 switch(newmsg
.message
)
821 newmsg
.wParam
= map_wparam_char_WtoA( newmsg
.wParam
, 1 );
824 newmsg
.wParam
= map_wparam_char_WtoA( newmsg
.wParam
, 2 );
827 ret
= callback( hwnd
, msg
, wParam
, (LPARAM
)&newmsg
, result
, arg
);
829 else ret
= callback( hwnd
, msg
, wParam
, lParam
, result
, arg
);
836 DWORD cp
= get_input_codepage();
837 DWORD len
= WideCharToMultiByte( cp
, 0, &wch
, 1, ch
, 2, NULL
, NULL
);
838 ret
= callback( hwnd
, msg
, (BYTE
)ch
[0], lParam
, result
, arg
);
839 if (len
== 2) ret
= callback( hwnd
, msg
, (BYTE
)ch
[1], lParam
, result
, arg
);
848 case EM_SETPASSWORDCHAR
:
849 ret
= callback( hwnd
, msg
, map_wparam_char_WtoA(wParam
,1), lParam
, result
, arg
);
853 ret
= callback( hwnd
, msg
, map_wparam_char_WtoA(wParam
,2), lParam
, result
, arg
);
856 case WM_PAINTCLIPBOARD
:
857 case WM_SIZECLIPBOARD
:
858 FIXME_(msg
)( "message %s (%04x) needs translation, please report\n",
859 SPY_GetMsgName(msg
, hwnd
), msg
);
863 ret
= callback( hwnd
, msg
, wParam
, lParam
, result
, arg
);
871 /**********************************************************************
872 * WINPROC_call_window
874 * Call the window procedure of the specified window.
876 BOOL
WINPROC_call_window( HWND hwnd
, UINT msg
, WPARAM wParam
, LPARAM lParam
,
877 LRESULT
*result
, BOOL unicode
, enum wm_char_mapping mapping
)
879 struct user_thread_info
*thread_info
= get_user_thread_info();
880 BOOL unicode_win
, is_dialog
;
885 if (!(wndPtr
= WIN_GetPtr( hwnd
))) return FALSE
;
886 if (wndPtr
== WND_OTHER_PROCESS
|| wndPtr
== WND_DESKTOP
) return FALSE
;
887 if (wndPtr
->tid
!= GetCurrentThreadId())
889 WIN_ReleasePtr( wndPtr
);
892 func
= wndPtr
->winproc
;
893 proc
= handle_to_proc( wndPtr
->winproc
);
894 unicode_win
= wndPtr
->flags
& WIN_ISUNICODE
;
895 is_dialog
= wndPtr
->dlgInfo
!= NULL
;
896 WIN_ReleasePtr( wndPtr
);
898 if (thread_info
->recursion_count
> MAX_WINPROC_RECURSION
) return FALSE
;
899 thread_info
->recursion_count
++;
903 if (proc
== WINPROC_PROC16
)
904 WINPROC_CallProcWtoA( wow_handlers
.call_window_proc
, hwnd
, msg
, wParam
, lParam
, result
, func
);
909 if (proc
&& proc
->procW
)
910 call_window_proc( hwnd
, msg
, wParam
, lParam
, result
, proc
->procW
);
912 call_window_proc( hwnd
, msg
, wParam
, lParam
, result
, func
);
916 if (proc
&& proc
->procA
)
917 WINPROC_CallProcWtoA( call_window_proc
, hwnd
, msg
, wParam
, lParam
, result
, proc
->procA
);
919 WINPROC_CallProcWtoA( call_window_proc
, hwnd
, msg
, wParam
, lParam
, result
, func
);
922 else if (proc
&& proc
->procW
)
923 call_window_proc( hwnd
, msg
, wParam
, lParam
, result
, proc
->procW
);
925 WINPROC_CallProcWtoA( call_window_proc
, hwnd
, msg
, wParam
, lParam
, result
, proc
->procA
);
926 else if (unicode_win
)
927 call_window_proc( hwnd
, msg
, wParam
, lParam
, result
, func
);
929 WINPROC_CallProcWtoA( call_window_proc
, hwnd
, msg
, wParam
, lParam
, result
, func
);
933 if (proc
== WINPROC_PROC16
)
934 wow_handlers
.call_window_proc( hwnd
, msg
, wParam
, lParam
, result
, func
);
939 if (proc
&& proc
->procW
)
940 WINPROC_CallProcAtoW( call_window_proc
, hwnd
, msg
, wParam
, lParam
, result
, proc
->procW
, mapping
);
942 WINPROC_CallProcAtoW( call_window_proc
, hwnd
, msg
, wParam
, lParam
, result
, func
, mapping
);
946 if (proc
&& proc
->procA
)
947 call_window_proc( hwnd
, msg
, wParam
, lParam
, result
, proc
->procA
);
949 call_window_proc( hwnd
, msg
, wParam
, lParam
, result
, func
);
952 else if (proc
&& proc
->procA
)
953 call_window_proc( hwnd
, msg
, wParam
, lParam
, result
, proc
->procA
);
955 WINPROC_CallProcAtoW( call_window_proc
, hwnd
, msg
, wParam
, lParam
, result
, proc
->procW
, mapping
);
956 else if (unicode_win
)
957 WINPROC_CallProcAtoW( call_window_proc
, hwnd
, msg
, wParam
, lParam
, result
, func
, mapping
);
959 call_window_proc( hwnd
, msg
, wParam
, lParam
, result
, func
);
961 thread_info
->recursion_count
--;
966 /**********************************************************************
967 * CallWindowProcA (USER32.@)
969 * The CallWindowProc() function invokes the windows procedure _func_,
970 * with _hwnd_ as the target window, the message specified by _msg_, and
971 * the message parameters _wParam_ and _lParam_.
973 * Some kinds of argument conversion may be done, I'm not sure what.
975 * CallWindowProc() may be used for windows subclassing. Use
976 * SetWindowLong() to set a new windows procedure for windows of the
977 * subclass, and handle subclassed messages in the new windows
978 * procedure. The new windows procedure may then use CallWindowProc()
979 * with _func_ set to the parent class's windows procedure to dispatch
980 * the message to the superclass.
984 * The return value is message dependent.
990 LRESULT WINAPI
CallWindowProcA(
991 WNDPROC func
, /* [in] window procedure */
992 HWND hwnd
, /* [in] target window */
993 UINT msg
, /* [in] message */
994 WPARAM wParam
, /* [in] message dependent parameter */
995 LPARAM lParam
/* [in] message dependent parameter */
1000 if (!func
) return 0;
1002 if (!(proc
= handle_to_proc( func
)))
1003 call_window_proc( hwnd
, msg
, wParam
, lParam
, &result
, func
);
1004 else if (proc
== WINPROC_PROC16
)
1005 wow_handlers
.call_window_proc( hwnd
, msg
, wParam
, lParam
, &result
, func
);
1006 else if (proc
->procA
)
1007 call_window_proc( hwnd
, msg
, wParam
, lParam
, &result
, proc
->procA
);
1009 WINPROC_CallProcAtoW( call_window_proc
, hwnd
, msg
, wParam
, lParam
, &result
,
1010 proc
->procW
, WMCHAR_MAP_CALLWINDOWPROC
);
1015 /**********************************************************************
1016 * CallWindowProcW (USER32.@)
1018 * See CallWindowProcA.
1020 LRESULT WINAPI
CallWindowProcW( WNDPROC func
, HWND hwnd
, UINT msg
,
1021 WPARAM wParam
, LPARAM lParam
)
1026 if (!func
) return 0;
1028 if (!(proc
= handle_to_proc( func
)))
1029 call_window_proc( hwnd
, msg
, wParam
, lParam
, &result
, func
);
1030 else if (proc
== WINPROC_PROC16
)
1031 WINPROC_CallProcWtoA( wow_handlers
.call_window_proc
, hwnd
, msg
, wParam
, lParam
, &result
, func
);
1032 else if (proc
->procW
)
1033 call_window_proc( hwnd
, msg
, wParam
, lParam
, &result
, proc
->procW
);
1035 WINPROC_CallProcWtoA( call_window_proc
, hwnd
, msg
, wParam
, lParam
, &result
, proc
->procA
);
1040 /**********************************************************************
1041 * WINPROC_CallDlgProcA
1043 INT_PTR
WINPROC_CallDlgProcA( DLGPROC func
, HWND hwnd
, UINT msg
, WPARAM wParam
, LPARAM lParam
)
1049 if (!func
) return 0;
1051 if (!(proc
= handle_to_proc( func
)))
1052 ret
= call_dialog_proc( hwnd
, msg
, wParam
, lParam
, &result
, func
);
1053 else if (proc
== WINPROC_PROC16
)
1055 ret
= wow_handlers
.call_dialog_proc( hwnd
, msg
, wParam
, lParam
, &result
, func
);
1056 SetWindowLongPtrW( hwnd
, DWLP_MSGRESULT
, result
);
1059 ret
= call_dialog_proc( hwnd
, msg
, wParam
, lParam
, &result
, proc
->procW
? proc
->procW
: proc
->procA
);
1065 /**********************************************************************
1066 * WINPROC_CallDlgProcW
1068 INT_PTR
WINPROC_CallDlgProcW( DLGPROC func
, HWND hwnd
, UINT msg
, WPARAM wParam
, LPARAM lParam
)
1074 if (!func
) return 0;
1076 if (!(proc
= handle_to_proc( func
)))
1077 ret
= call_dialog_proc( hwnd
, msg
, wParam
, lParam
, &result
, func
);
1078 else if (proc
== WINPROC_PROC16
)
1080 ret
= WINPROC_CallProcWtoA( wow_handlers
.call_dialog_proc
, hwnd
, msg
, wParam
, lParam
, &result
, func
);
1081 SetWindowLongPtrW( hwnd
, DWLP_MSGRESULT
, result
);
1084 ret
= call_dialog_proc( hwnd
, msg
, wParam
, lParam
, &result
, proc
->procW
? proc
->procW
: proc
->procA
);
1090 /***********************************************************************
1091 * Window procedures for builtin classes
1094 static LRESULT WINAPI
ButtonWndProcA( HWND hwnd
, UINT msg
, WPARAM wParam
, LPARAM lParam
)
1096 return wow_handlers
.button_proc( hwnd
, msg
, wParam
, lParam
, FALSE
);
1099 static LRESULT WINAPI
ButtonWndProcW( HWND hwnd
, UINT msg
, WPARAM wParam
, LPARAM lParam
)
1101 return wow_handlers
.button_proc( hwnd
, msg
, wParam
, lParam
, TRUE
);
1104 static LRESULT WINAPI
ComboWndProcA( HWND hwnd
, UINT message
, WPARAM wParam
, LPARAM lParam
)
1106 return wow_handlers
.combo_proc( hwnd
, message
, wParam
, lParam
, FALSE
);
1109 static LRESULT WINAPI
ComboWndProcW( HWND hwnd
, UINT message
, WPARAM wParam
, LPARAM lParam
)
1111 return wow_handlers
.combo_proc( hwnd
, message
, wParam
, lParam
, TRUE
);
1114 LRESULT WINAPI
EditWndProcA( HWND hwnd
, UINT msg
, WPARAM wParam
, LPARAM lParam
)
1116 return wow_handlers
.edit_proc( hwnd
, msg
, wParam
, lParam
, FALSE
);
1119 static LRESULT WINAPI
EditWndProcW( HWND hwnd
, UINT msg
, WPARAM wParam
, LPARAM lParam
)
1121 return wow_handlers
.edit_proc( hwnd
, msg
, wParam
, lParam
, TRUE
);
1124 static LRESULT WINAPI
ListBoxWndProcA( HWND hwnd
, UINT msg
, WPARAM wParam
, LPARAM lParam
)
1126 return wow_handlers
.listbox_proc( hwnd
, msg
, wParam
, lParam
, FALSE
);
1129 static LRESULT WINAPI
ListBoxWndProcW( HWND hwnd
, UINT msg
, WPARAM wParam
, LPARAM lParam
)
1131 return wow_handlers
.listbox_proc( hwnd
, msg
, wParam
, lParam
, TRUE
);
1134 static LRESULT WINAPI
MDIClientWndProcA( HWND hwnd
, UINT msg
, WPARAM wParam
, LPARAM lParam
)
1136 return wow_handlers
.mdiclient_proc( hwnd
, msg
, wParam
, lParam
, FALSE
);
1139 static LRESULT WINAPI
MDIClientWndProcW( HWND hwnd
, UINT msg
, WPARAM wParam
, LPARAM lParam
)
1141 return wow_handlers
.mdiclient_proc( hwnd
, msg
, wParam
, lParam
, TRUE
);
1144 static LRESULT WINAPI
ScrollBarWndProcA( HWND hwnd
, UINT msg
, WPARAM wParam
, LPARAM lParam
)
1146 return wow_handlers
.scrollbar_proc( hwnd
, msg
, wParam
, lParam
, FALSE
);
1149 static LRESULT WINAPI
ScrollBarWndProcW( HWND hwnd
, UINT msg
, WPARAM wParam
, LPARAM lParam
)
1151 return wow_handlers
.scrollbar_proc( hwnd
, msg
, wParam
, lParam
, TRUE
);
1154 static LRESULT WINAPI
StaticWndProcA( HWND hwnd
, UINT msg
, WPARAM wParam
, LPARAM lParam
)
1156 return wow_handlers
.static_proc( hwnd
, msg
, wParam
, lParam
, FALSE
);
1159 static LRESULT WINAPI
StaticWndProcW( HWND hwnd
, UINT msg
, WPARAM wParam
, LPARAM lParam
)
1161 return wow_handlers
.static_proc( hwnd
, msg
, wParam
, lParam
, TRUE
);
1164 static DWORD
wait_message( DWORD count
, const HANDLE
*handles
, DWORD timeout
, DWORD mask
, DWORD flags
)
1166 DWORD ret
= USER_Driver
->pMsgWaitForMultipleObjectsEx( count
, handles
, timeout
, mask
, flags
);
1167 if (ret
== WAIT_TIMEOUT
&& !count
&& !timeout
) NtYieldExecution();
1168 if ((mask
& QS_INPUT
) == QS_INPUT
) get_user_thread_info()->message_count
= 0;
1172 /**********************************************************************
1173 * UserRegisterWowHandlers (USER32.@)
1175 * NOTE: no attempt has been made to be compatible here,
1176 * the Windows function is most likely completely different.
1178 void WINAPI
UserRegisterWowHandlers( const struct wow_handlers16
*new, struct wow_handlers32
*orig
)
1180 orig
->button_proc
= ButtonWndProc_common
;
1181 orig
->combo_proc
= ComboWndProc_common
;
1182 orig
->edit_proc
= EditWndProc_common
;
1183 orig
->listbox_proc
= ListBoxWndProc_common
;
1184 orig
->mdiclient_proc
= MDIClientWndProc_common
;
1185 orig
->scrollbar_proc
= ScrollBarWndProc_common
;
1186 orig
->static_proc
= StaticWndProc_common
;
1187 orig
->wait_message
= wait_message
;
1188 orig
->create_window
= WIN_CreateWindowEx
;
1189 orig
->get_win_handle
= WIN_GetFullHandle
;
1190 orig
->alloc_winproc
= WINPROC_AllocProc
;
1191 orig
->get_dialog_info
= DIALOG_get_info
;
1192 orig
->dialog_box_loop
= DIALOG_DoDialogBox
;
1193 orig
->get_icon_param
= get_icon_param
;
1194 orig
->set_icon_param
= set_icon_param
;
1196 wow_handlers
= *new;
1199 struct wow_handlers16 wow_handlers
=
1201 ButtonWndProc_common
,
1202 ComboWndProc_common
,
1204 ListBoxWndProc_common
,
1205 MDIClientWndProc_common
,
1206 ScrollBarWndProc_common
,
1207 StaticWndProc_common
,
1210 NULL
, /* call_window_proc */
1211 NULL
, /* call_dialog_proc */
1212 NULL
, /* free_icon_param */