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 #define WIN32_NO_STATUS
24 #include "user_private.h"
28 #include "wine/debug.h"
30 WINE_DEFAULT_DEBUG_CHANNEL(msg
);
31 WINE_DECLARE_DEBUG_CHANNEL(relay
);
33 static inline void *get_buffer( void *static_buffer
, size_t size
, size_t need
)
35 if (size
>= need
) return static_buffer
;
36 return HeapAlloc( GetProcessHeap(), 0, need
);
39 static inline void free_buffer( void *static_buffer
, void *buffer
)
41 if (buffer
!= static_buffer
) HeapFree( GetProcessHeap(), 0, buffer
);
45 /* Some window procedures modify registers they shouldn't, or are not
46 * properly declared stdcall; so we need a small assembly wrapper to
48 extern LRESULT
WINPROC_wrapper( WNDPROC proc
, HWND hwnd
, UINT msg
,
49 WPARAM wParam
, LPARAM lParam
);
50 __ASM_GLOBAL_FUNC( WINPROC_wrapper
,
52 __ASM_CFI(".cfi_adjust_cfa_offset 4\n\t")
53 __ASM_CFI(".cfi_rel_offset %ebp,0\n\t")
55 __ASM_CFI(".cfi_def_cfa_register %ebp\n\t")
57 __ASM_CFI(".cfi_rel_offset %edi,-4\n\t")
59 __ASM_CFI(".cfi_rel_offset %esi,-8\n\t")
61 __ASM_CFI(".cfi_rel_offset %ebx,-12\n\t")
62 /* TreePad X Enterprise assumes that edi is < 0x80000000 in WM_TIMER messages */
69 "movl 8(%ebp),%eax\n\t"
71 "leal -12(%ebp),%esp\n\t"
73 __ASM_CFI(".cfi_same_value %ebx\n\t")
75 __ASM_CFI(".cfi_same_value %esi\n\t")
77 __ASM_CFI(".cfi_same_value %edi\n\t")
79 __ASM_CFI(".cfi_def_cfa %esp,4\n\t")
80 __ASM_CFI(".cfi_same_value %ebp\n\t")
83 static inline LRESULT
WINPROC_wrapper( WNDPROC proc
, HWND hwnd
, UINT msg
,
84 WPARAM wParam
, LPARAM lParam
)
86 return proc( hwnd
, msg
, wParam
, lParam
);
90 static WPARAM
map_wparam_char_WtoA( WPARAM wParam
, DWORD len
)
94 DWORD cp
= get_input_codepage();
96 len
= WideCharToMultiByte( cp
, 0, &wch
, 1, (LPSTR
)ch
, len
, NULL
, NULL
);
98 return MAKEWPARAM( (ch
[0] << 8) | ch
[1], HIWORD(wParam
) );
100 return MAKEWPARAM( ch
[0], HIWORD(wParam
) );
103 /* call a 32-bit window procedure */
104 static LRESULT
call_window_proc( HWND hwnd
, UINT msg
, WPARAM wp
, LPARAM lp
, LRESULT
*result
, void *arg
)
108 TRACE_(relay
)( "\1Call window proc %p (hwnd=%p,msg=%s,wp=%08Ix,lp=%08Ix)\n",
109 proc
, hwnd
, SPY_GetMsgName(msg
, hwnd
), wp
, lp
);
111 *result
= WINPROC_wrapper( proc
, hwnd
, msg
, wp
, lp
);
113 TRACE_(relay
)( "\1Ret window proc %p (hwnd=%p,msg=%s,wp=%08Ix,lp=%08Ix) retval=%08Ix\n",
114 proc
, hwnd
, SPY_GetMsgName(msg
, hwnd
), wp
, lp
, *result
);
118 /* call a 32-bit dialog procedure */
119 static LRESULT
call_dialog_proc( HWND hwnd
, UINT msg
, WPARAM wp
, LPARAM lp
, LRESULT
*result
, void *arg
)
121 DPI_AWARENESS_CONTEXT context
;
125 hwnd
= WIN_GetFullHandle( hwnd
);
126 TRACE_(relay
)( "\1Call dialog proc %p (hwnd=%p,msg=%s,wp=%08Ix,lp=%08Ix)\n",
127 proc
, hwnd
, SPY_GetMsgName(msg
, hwnd
), wp
, lp
);
129 context
= SetThreadDpiAwarenessContext( GetWindowDpiAwarenessContext( hwnd
));
130 ret
= WINPROC_wrapper( proc
, hwnd
, msg
, wp
, lp
);
131 *result
= GetWindowLongPtrW( hwnd
, DWLP_MSGRESULT
);
132 SetThreadDpiAwarenessContext( context
);
134 TRACE_(relay
)( "\1Ret dialog proc %p (hwnd=%p,msg=%s,wp=%08Ix,lp=%08Ix) retval=%08Ix result=%08Ix\n",
135 proc
, hwnd
, SPY_GetMsgName(msg
, hwnd
), wp
, lp
, ret
, *result
);
140 /**********************************************************************
143 * Allocate a window procedure for a window or class.
145 * Note that allocated winprocs are never freed; the idea is that even if an app creates a
146 * lot of windows, it will usually only have a limited number of window procedures, so the
147 * array won't grow too large, and this way we avoid the need to track allocations per window.
149 static WNDPROC
WINPROC_AllocProc( WNDPROC func
, BOOL unicode
)
151 return (WNDPROC
)NtUserCallTwoParam( (UINT_PTR
)func
, !unicode
, NtUserAllocWinProc
);
155 /**********************************************************************
156 * WINPROC_TestLBForStr
158 * Return TRUE if the lparam is a string
160 static inline BOOL
WINPROC_TestLBForStr( HWND hwnd
, UINT msg
)
162 DWORD style
= GetWindowLongA( hwnd
, GWL_STYLE
);
163 if (msg
<= CB_MSGMAX
)
164 return (!(style
& (CBS_OWNERDRAWFIXED
| CBS_OWNERDRAWVARIABLE
)) || (style
& CBS_HASSTRINGS
));
166 return (!(style
& (LBS_OWNERDRAWFIXED
| LBS_OWNERDRAWVARIABLE
)) || (style
& LBS_HASSTRINGS
));
171 /**********************************************************************
172 * WINPROC_CallProcAtoW
174 * Call a window procedure, translating args from Ansi to Unicode.
176 LRESULT
WINPROC_CallProcAtoW( winproc_callback_t callback
, HWND hwnd
, UINT msg
, WPARAM wParam
,
177 LPARAM lParam
, LRESULT
*result
, void *arg
, enum wm_char_mapping mapping
)
181 TRACE( "(hwnd=%p,msg=%s,wp=%08Ix,lp=%08Ix)\n", hwnd
, SPY_GetMsgName(msg
, hwnd
), wParam
, lParam
);
188 WCHAR
*ptr
, buffer
[512];
189 CREATESTRUCTA
*csA
= (CREATESTRUCTA
*)lParam
;
190 CREATESTRUCTW csW
= *(CREATESTRUCTW
*)csA
;
191 MDICREATESTRUCTW mdi_cs
;
192 DWORD name_lenA
= 0, name_lenW
= 0, class_lenA
= 0, class_lenW
= 0;
194 if (!IS_INTRESOURCE(csA
->lpszClass
))
196 class_lenA
= strlen(csA
->lpszClass
) + 1;
197 RtlMultiByteToUnicodeSize( &class_lenW
, csA
->lpszClass
, class_lenA
);
199 if (!IS_INTRESOURCE(csA
->lpszName
))
201 name_lenA
= strlen(csA
->lpszName
) + 1;
202 RtlMultiByteToUnicodeSize( &name_lenW
, csA
->lpszName
, name_lenA
);
205 if (!(ptr
= get_buffer( buffer
, sizeof(buffer
), class_lenW
+ name_lenW
))) break;
210 RtlMultiByteToUnicodeN( ptr
, class_lenW
, NULL
, csA
->lpszClass
, class_lenA
);
214 csW
.lpszName
= ptr
+ class_lenW
/sizeof(WCHAR
);
215 RtlMultiByteToUnicodeN( ptr
+ class_lenW
/sizeof(WCHAR
), name_lenW
, NULL
,
216 csA
->lpszName
, name_lenA
);
219 if (GetWindowLongW(hwnd
, GWL_EXSTYLE
) & WS_EX_MDICHILD
)
221 mdi_cs
= *(MDICREATESTRUCTW
*)csA
->lpCreateParams
;
222 mdi_cs
.szTitle
= csW
.lpszName
;
223 mdi_cs
.szClass
= csW
.lpszClass
;
224 csW
.lpCreateParams
= &mdi_cs
;
227 ret
= callback( hwnd
, msg
, wParam
, (LPARAM
)&csW
, result
, arg
);
228 free_buffer( buffer
, ptr
);
234 WCHAR
*ptr
, buffer
[512];
235 DWORD title_lenA
= 0, title_lenW
= 0, class_lenA
= 0, class_lenW
= 0;
236 MDICREATESTRUCTA
*csA
= (MDICREATESTRUCTA
*)lParam
;
237 MDICREATESTRUCTW csW
;
239 memcpy( &csW
, csA
, sizeof(csW
) );
241 if (!IS_INTRESOURCE(csA
->szTitle
))
243 title_lenA
= strlen(csA
->szTitle
) + 1;
244 RtlMultiByteToUnicodeSize( &title_lenW
, csA
->szTitle
, title_lenA
);
246 if (!IS_INTRESOURCE(csA
->szClass
))
248 class_lenA
= strlen(csA
->szClass
) + 1;
249 RtlMultiByteToUnicodeSize( &class_lenW
, csA
->szClass
, class_lenA
);
252 if (!(ptr
= get_buffer( buffer
, sizeof(buffer
), title_lenW
+ class_lenW
))) break;
257 RtlMultiByteToUnicodeN( ptr
, title_lenW
, NULL
, csA
->szTitle
, title_lenA
);
261 csW
.szClass
= ptr
+ title_lenW
/sizeof(WCHAR
);
262 RtlMultiByteToUnicodeN( ptr
+ title_lenW
/sizeof(WCHAR
), class_lenW
, NULL
,
263 csA
->szClass
, class_lenA
);
265 ret
= callback( hwnd
, msg
, wParam
, (LPARAM
)&csW
, result
, arg
);
266 free_buffer( buffer
, ptr
);
271 case WM_ASKCBFORMATNAME
:
273 WCHAR
*ptr
, buffer
[512];
274 LPSTR str
= (LPSTR
)lParam
;
275 DWORD len
= wParam
* sizeof(WCHAR
);
277 if (!(ptr
= get_buffer( buffer
, sizeof(buffer
), len
))) break;
278 ret
= callback( hwnd
, msg
, wParam
, (LPARAM
)ptr
, result
, arg
);
283 RtlUnicodeToMultiByteN( str
, wParam
- 1, &len
, ptr
, ret
* sizeof(WCHAR
) );
287 free_buffer( buffer
, ptr
);
292 case LB_INSERTSTRING
:
294 case LB_FINDSTRINGEXACT
:
295 case LB_SELECTSTRING
:
297 case CB_INSERTSTRING
:
299 case CB_FINDSTRINGEXACT
:
300 case CB_SELECTSTRING
:
301 if (!lParam
|| !WINPROC_TestLBForStr( hwnd
, msg
))
303 ret
= callback( hwnd
, msg
, wParam
, lParam
, result
, arg
);
308 case WM_WININICHANGE
:
309 case WM_DEVMODECHANGE
:
314 if (!lParam
) ret
= callback( hwnd
, msg
, wParam
, lParam
, result
, arg
);
317 WCHAR
*ptr
, buffer
[512];
318 LPCSTR strA
= (LPCSTR
)lParam
;
319 DWORD lenW
, lenA
= strlen(strA
) + 1;
321 RtlMultiByteToUnicodeSize( &lenW
, strA
, lenA
);
322 if ((ptr
= get_buffer( buffer
, sizeof(buffer
), lenW
)))
324 RtlMultiByteToUnicodeN( ptr
, lenW
, NULL
, strA
, lenA
);
325 ret
= callback( hwnd
, msg
, wParam
, (LPARAM
)ptr
, result
, arg
);
326 free_buffer( buffer
, ptr
);
333 if (lParam
&& WINPROC_TestLBForStr( hwnd
, msg
))
335 WCHAR buffer
[512]; /* FIXME: fixed sized buffer */
337 ret
= callback( hwnd
, msg
, wParam
, (LPARAM
)buffer
, result
, arg
);
341 RtlUnicodeToMultiByteN( (LPSTR
)lParam
, 512 * 3, &len
,
342 buffer
, (lstrlenW(buffer
) + 1) * sizeof(WCHAR
) );
346 else ret
= callback( hwnd
, msg
, wParam
, lParam
, result
, arg
);
351 WCHAR
*ptr
, buffer
[512];
352 WORD len
= *(WORD
*)lParam
;
354 if (!(ptr
= get_buffer( buffer
, sizeof(buffer
), len
* sizeof(WCHAR
) ))) break;
355 *((WORD
*)ptr
) = len
; /* store the length */
356 ret
= callback( hwnd
, msg
, wParam
, (LPARAM
)ptr
, result
, arg
);
360 RtlUnicodeToMultiByteN( (LPSTR
)lParam
, len
, &reslen
, ptr
, *result
* sizeof(WCHAR
) );
361 if (reslen
< len
) ((LPSTR
)lParam
)[reslen
] = 0;
364 free_buffer( buffer
, ptr
);
371 MSG newmsg
= *(MSG
*)lParam
;
372 if (map_wparam_AtoW( newmsg
.message
, &newmsg
.wParam
, WMCHAR_MAP_NOMAPPING
))
373 ret
= callback( hwnd
, msg
, wParam
, (LPARAM
)&newmsg
, result
, arg
);
375 else ret
= callback( hwnd
, msg
, wParam
, lParam
, result
, arg
);
384 case EM_SETPASSWORDCHAR
:
386 if (map_wparam_AtoW( msg
, &wParam
, mapping
))
387 ret
= callback( hwnd
, msg
, wParam
, lParam
, result
, arg
);
390 case WM_GETTEXTLENGTH
:
391 case CB_GETLBTEXTLEN
:
393 ret
= callback( hwnd
, msg
, wParam
, lParam
, result
, arg
);
396 WCHAR
*ptr
, buffer
[512];
398 DWORD len
= *result
+ 1;
399 /* Determine respective GETTEXT message */
400 UINT msgGetText
= (msg
== WM_GETTEXTLENGTH
) ? WM_GETTEXT
:
401 ((msg
== CB_GETLBTEXTLEN
) ? CB_GETLBTEXT
: LB_GETTEXT
);
402 /* wParam differs between the messages */
403 WPARAM wp
= (msg
== WM_GETTEXTLENGTH
) ? len
: wParam
;
405 if (!(ptr
= get_buffer( buffer
, sizeof(buffer
), len
* sizeof(WCHAR
) ))) break;
407 if (callback
== call_window_proc
) /* FIXME: hack */
408 callback( hwnd
, msgGetText
, wp
, (LPARAM
)ptr
, &tmp
, arg
);
410 tmp
= SendMessageW( hwnd
, msgGetText
, wp
, (LPARAM
)ptr
);
411 RtlUnicodeToMultiByteSize( &len
, ptr
, tmp
* sizeof(WCHAR
) );
413 free_buffer( buffer
, ptr
);
417 case WM_PAINTCLIPBOARD
:
418 case WM_SIZECLIPBOARD
:
419 FIXME( "message %s (0x%x) needs translation, please report\n",
420 SPY_GetMsgName(msg
, hwnd
), msg
);
424 ret
= callback( hwnd
, msg
, wParam
, lParam
, result
, arg
);
431 /**********************************************************************
432 * WINPROC_CallProcWtoA
434 * Call a window procedure, translating args from Unicode to Ansi.
436 static LRESULT
WINPROC_CallProcWtoA( winproc_callback_t callback
, HWND hwnd
, UINT msg
, WPARAM wParam
,
437 LPARAM lParam
, LRESULT
*result
, void *arg
)
441 TRACE( "(hwnd=%p,msg=%s,wp=%08Ix,lp=%08Ix)\n", hwnd
, SPY_GetMsgName(msg
, hwnd
), wParam
, lParam
);
448 char buffer
[1024], *cls
;
449 CREATESTRUCTW
*csW
= (CREATESTRUCTW
*)lParam
;
450 CREATESTRUCTA csA
= *(CREATESTRUCTA
*)csW
;
451 MDICREATESTRUCTA mdi_cs
;
452 DWORD name_lenA
= 0, name_lenW
= 0, class_lenA
= 0, class_lenW
= 0;
453 char int_name_buf
[4];
455 if (!IS_INTRESOURCE(csW
->lpszClass
))
457 class_lenW
= (lstrlenW(csW
->lpszClass
) + 1) * sizeof(WCHAR
);
458 RtlUnicodeToMultiByteSize(&class_lenA
, csW
->lpszClass
, class_lenW
);
460 if (!IS_INTRESOURCE(csW
->lpszName
))
462 /* resource ID string is a special case */
463 if (csW
->lpszName
[0] == 0xffff)
465 int_name_buf
[0] = 0xff;
466 int_name_buf
[1] = csW
->lpszName
[1];
467 int_name_buf
[2] = csW
->lpszName
[1] >> 8;
469 csA
.lpszName
= int_name_buf
;
473 name_lenW
= (lstrlenW(csW
->lpszName
) + 1) * sizeof(WCHAR
);
474 RtlUnicodeToMultiByteSize(&name_lenA
, csW
->lpszName
, name_lenW
);
478 if (!(cls
= get_buffer( buffer
, sizeof(buffer
), class_lenA
+ name_lenA
))) break;
482 RtlUnicodeToMultiByteN(cls
, class_lenA
, NULL
, csW
->lpszClass
, class_lenW
);
487 char *name
= cls
+ class_lenA
;
488 RtlUnicodeToMultiByteN(name
, name_lenA
, NULL
, csW
->lpszName
, name_lenW
);
492 if (GetWindowLongW(hwnd
, GWL_EXSTYLE
) & WS_EX_MDICHILD
)
494 mdi_cs
= *(MDICREATESTRUCTA
*)csW
->lpCreateParams
;
495 mdi_cs
.szTitle
= csA
.lpszName
;
496 mdi_cs
.szClass
= csA
.lpszClass
;
497 csA
.lpCreateParams
= &mdi_cs
;
500 ret
= callback( hwnd
, msg
, wParam
, (LPARAM
)&csA
, result
, arg
);
501 free_buffer( buffer
, cls
);
506 case WM_ASKCBFORMATNAME
:
508 char *ptr
, buffer
[512];
509 DWORD len
= wParam
* 2;
511 if (!(ptr
= get_buffer( buffer
, sizeof(buffer
), len
))) break;
512 ret
= callback( hwnd
, msg
, wParam
, (LPARAM
)ptr
, result
, arg
);
517 RtlMultiByteToUnicodeN( (LPWSTR
)lParam
, wParam
*sizeof(WCHAR
), &len
, ptr
, ret
+ 1 );
518 *result
= len
/sizeof(WCHAR
) - 1; /* do not count terminating null */
520 ((LPWSTR
)lParam
)[*result
] = 0;
522 free_buffer( buffer
, ptr
);
527 case LB_INSERTSTRING
:
529 case LB_FINDSTRINGEXACT
:
530 case LB_SELECTSTRING
:
532 case CB_INSERTSTRING
:
534 case CB_FINDSTRINGEXACT
:
535 case CB_SELECTSTRING
:
536 if (!lParam
|| !WINPROC_TestLBForStr( hwnd
, msg
))
538 ret
= callback( hwnd
, msg
, wParam
, lParam
, result
, arg
);
543 case WM_WININICHANGE
:
544 case WM_DEVMODECHANGE
:
549 if (!lParam
) ret
= callback( hwnd
, msg
, wParam
, lParam
, result
, arg
);
552 char *ptr
, buffer
[512];
553 LPCWSTR strW
= (LPCWSTR
)lParam
;
554 DWORD lenA
, lenW
= (lstrlenW(strW
) + 1) * sizeof(WCHAR
);
556 RtlUnicodeToMultiByteSize( &lenA
, strW
, lenW
);
557 if ((ptr
= get_buffer( buffer
, sizeof(buffer
), lenA
)))
559 RtlUnicodeToMultiByteN( ptr
, lenA
, NULL
, strW
, lenW
);
560 ret
= callback( hwnd
, msg
, wParam
, (LPARAM
)ptr
, result
, arg
);
561 free_buffer( buffer
, ptr
);
568 char *ptr
, buffer
[1024];
569 DWORD title_lenA
= 0, title_lenW
= 0, class_lenA
= 0, class_lenW
= 0;
570 MDICREATESTRUCTW
*csW
= (MDICREATESTRUCTW
*)lParam
;
571 MDICREATESTRUCTA csA
;
573 memcpy( &csA
, csW
, sizeof(csA
) );
575 if (!IS_INTRESOURCE(csW
->szTitle
))
577 title_lenW
= (lstrlenW(csW
->szTitle
) + 1) * sizeof(WCHAR
);
578 RtlUnicodeToMultiByteSize( &title_lenA
, csW
->szTitle
, title_lenW
);
580 if (!IS_INTRESOURCE(csW
->szClass
))
582 class_lenW
= (lstrlenW(csW
->szClass
) + 1) * sizeof(WCHAR
);
583 RtlUnicodeToMultiByteSize( &class_lenA
, csW
->szClass
, class_lenW
);
586 if (!(ptr
= get_buffer( buffer
, sizeof(buffer
), title_lenA
+ class_lenA
))) break;
590 RtlUnicodeToMultiByteN( ptr
, title_lenA
, NULL
, csW
->szTitle
, title_lenW
);
595 RtlUnicodeToMultiByteN( ptr
+ title_lenA
, class_lenA
, NULL
, csW
->szClass
, class_lenW
);
596 csA
.szClass
= ptr
+ title_lenA
;
598 ret
= callback( hwnd
, msg
, wParam
, (LPARAM
)&csA
, result
, arg
);
599 free_buffer( buffer
, ptr
);
605 if (lParam
&& WINPROC_TestLBForStr( hwnd
, msg
))
607 char buffer
[512]; /* FIXME: fixed sized buffer */
609 ret
= callback( hwnd
, msg
, wParam
, (LPARAM
)buffer
, result
, arg
);
613 RtlMultiByteToUnicodeN( (LPWSTR
)lParam
, 512 * 3, &len
, buffer
, strlen(buffer
) + 1 );
614 *result
= len
/ sizeof(WCHAR
) - 1;
617 else ret
= callback( hwnd
, msg
, wParam
, lParam
, result
, arg
);
622 char *ptr
, buffer
[512];
623 WORD len
= *(WORD
*)lParam
;
625 if (!(ptr
= get_buffer( buffer
, sizeof(buffer
), len
* 2 ))) break;
626 *((WORD
*)ptr
) = len
* 2; /* store the length */
627 ret
= callback( hwnd
, msg
, wParam
, (LPARAM
)ptr
, result
, arg
);
631 RtlMultiByteToUnicodeN( (LPWSTR
)lParam
, len
*sizeof(WCHAR
), &reslen
, ptr
, *result
);
632 *result
= reslen
/ sizeof(WCHAR
);
633 if (*result
< len
) ((LPWSTR
)lParam
)[*result
] = 0;
635 free_buffer( buffer
, ptr
);
642 MSG newmsg
= *(MSG
*)lParam
;
643 switch(newmsg
.message
)
649 newmsg
.wParam
= map_wparam_char_WtoA( newmsg
.wParam
, 1 );
652 newmsg
.wParam
= map_wparam_char_WtoA( newmsg
.wParam
, 2 );
655 ret
= callback( hwnd
, msg
, wParam
, (LPARAM
)&newmsg
, result
, arg
);
657 else ret
= callback( hwnd
, msg
, wParam
, lParam
, result
, arg
);
664 DWORD cp
= get_input_codepage();
665 DWORD len
= WideCharToMultiByte( cp
, 0, &wch
, 1, ch
, 2, NULL
, NULL
);
666 ret
= callback( hwnd
, msg
, (BYTE
)ch
[0], lParam
, result
, arg
);
667 if (len
== 2) ret
= callback( hwnd
, msg
, (BYTE
)ch
[1], lParam
, result
, arg
);
676 case EM_SETPASSWORDCHAR
:
677 ret
= callback( hwnd
, msg
, map_wparam_char_WtoA(wParam
,1), lParam
, result
, arg
);
681 ret
= callback( hwnd
, msg
, map_wparam_char_WtoA(wParam
,2), lParam
, result
, arg
);
684 case WM_PAINTCLIPBOARD
:
685 case WM_SIZECLIPBOARD
:
686 FIXME( "message %s (%04x) needs translation, please report\n",
687 SPY_GetMsgName(msg
, hwnd
), msg
);
691 ret
= callback( hwnd
, msg
, wParam
, lParam
, result
, arg
);
699 LRESULT
dispatch_win_proc_params( struct win_proc_params
*params
)
701 DPI_AWARENESS_CONTEXT context
= SetThreadDpiAwarenessContext( params
->dpi_awareness
);
706 if (params
->procW
== WINPROC_PROC16
)
707 WINPROC_CallProcWtoA( wow_handlers
.call_window_proc
, params
->hwnd
, params
->msg
, params
->wparam
,
708 params
->lparam
, &result
, params
->func
);
709 else if (!params
->ansi_dst
)
710 call_window_proc( params
->hwnd
, params
->msg
, params
->wparam
, params
->lparam
,
711 &result
, params
->procW
);
713 WINPROC_CallProcWtoA( call_window_proc
, params
->hwnd
, params
->msg
, params
->wparam
,
714 params
->lparam
, &result
, params
->procA
);
718 if (params
->procA
== WINPROC_PROC16
)
719 wow_handlers
.call_window_proc( params
->hwnd
, params
->msg
, params
->wparam
, params
->lparam
,
720 &result
, params
->func
);
721 else if (!params
->ansi_dst
)
722 WINPROC_CallProcAtoW( call_window_proc
, params
->hwnd
, params
->msg
, params
->wparam
,
723 params
->lparam
, &result
, params
->procW
, params
->mapping
);
725 call_window_proc( params
->hwnd
, params
->msg
, params
->wparam
, params
->lparam
,
726 &result
, params
->procA
);
729 SetThreadDpiAwarenessContext( context
);
733 static size_t string_size( const void *str
, BOOL ansi
)
735 return ansi
? strlen( str
) + 1 : (wcslen( str
) + 1) * sizeof(WCHAR
);
738 /***********************************************************************
741 * Unpack a message received from win32u.
743 void unpack_message( HWND hwnd
, UINT message
, WPARAM
*wparam
, LPARAM
*lparam
, void *buffer
, BOOL ansi
)
750 CREATESTRUCTA
*cs
= buffer
;
751 char *str
= (char *)(cs
+ 1);
753 if (!IS_INTRESOURCE(cs
->lpszName
))
756 str
+= string_size( str
, ansi
);
758 if (!IS_INTRESOURCE(cs
->lpszClass
))
767 NCCALCSIZE_PARAMS
*ncp
= buffer
;
768 ncp
->lppos
= (WINDOWPOS
*)((NCCALCSIZE_PARAMS
*)ncp
+ 1);
773 COPYDATASTRUCT
*cds
= buffer
;
774 if (cds
->lpData
) cds
->lpData
= cds
+ 1;
782 *wparam
= (WPARAM
)ptr
++;
783 *lparam
= (LPARAM
)ptr
;
788 MDICREATESTRUCTA
*mcs
= buffer
;
789 char *str
= (char *)(mcs
+ 1);
791 if (!IS_INTRESOURCE(mcs
->szClass
))
794 str
+= string_size( mcs
->szClass
, ansi
);
796 if (!IS_INTRESOURCE(mcs
->szTitle
))
804 *lparam
= (LPARAM
)buffer
;
807 NTSTATUS WINAPI
User32CallWindowProc( void *args
, ULONG size
)
809 struct win_proc_params
*params
= args
;
810 size_t packed_size
= 0;
814 if (size
> sizeof(*params
))
816 const size_t offset
= (sizeof(*params
) + 15) & ~15;
817 packed_size
= size
- offset
;
818 buffer
= (char *)params
+ offset
;
820 unpack_message( params
->hwnd
, params
->msg
, ¶ms
->wparam
, ¶ms
->lparam
,
821 buffer
, params
->ansi
);
824 result
= dispatch_win_proc_params( params
);
828 LRESULT
*result_ptr
= (LRESULT
*)buffer
- 1;
829 *result_ptr
= result
;
830 return NtCallbackReturn( result_ptr
, sizeof(*result_ptr
) + packed_size
, STATUS_SUCCESS
);
832 return NtCallbackReturn( &result
, sizeof(result
), STATUS_SUCCESS
);
835 NTSTATUS WINAPI
User32CallSendAsyncCallback( void *args
, ULONG size
)
837 const struct send_async_params
*params
= args
;
838 params
->callback( params
->hwnd
, params
->msg
, params
->data
, params
->result
);
839 return STATUS_SUCCESS
;
842 /**********************************************************************
843 * CallWindowProcA (USER32.@)
845 * The CallWindowProc() function invokes the windows procedure _func_,
846 * with _hwnd_ as the target window, the message specified by _msg_, and
847 * the message parameters _wParam_ and _lParam_.
849 * Some kinds of argument conversion may be done, I'm not sure what.
851 * CallWindowProc() may be used for windows subclassing. Use
852 * SetWindowLong() to set a new windows procedure for windows of the
853 * subclass, and handle subclassed messages in the new windows
854 * procedure. The new windows procedure may then use CallWindowProc()
855 * with _func_ set to the parent class's windows procedure to dispatch
856 * the message to the superclass.
860 * The return value is message dependent.
866 LRESULT WINAPI DECLSPEC_HOTPATCH
CallWindowProcA( WNDPROC func
, HWND hwnd
, UINT msg
, WPARAM wParam
, LPARAM lParam
)
868 struct win_proc_params params
;
871 if (!NtUserMessageCall( hwnd
, msg
, wParam
, lParam
, ¶ms
, NtUserCallWindowProc
, TRUE
))
873 return dispatch_win_proc_params( ¶ms
);
877 /**********************************************************************
878 * CallWindowProcW (USER32.@)
880 * See CallWindowProcA.
882 LRESULT WINAPI
CallWindowProcW( WNDPROC func
, HWND hwnd
, UINT msg
, WPARAM wParam
, LPARAM lParam
)
884 struct win_proc_params params
;
887 if (!NtUserMessageCall( hwnd
, msg
, wParam
, lParam
, ¶ms
, NtUserCallWindowProc
, FALSE
))
889 return dispatch_win_proc_params( ¶ms
);
893 /**********************************************************************
894 * WINPROC_CallDlgProcA
896 INT_PTR
WINPROC_CallDlgProcA( HWND hwnd
, UINT msg
, WPARAM wParam
, LPARAM lParam
)
902 proc
= (DLGPROC
)NtUserGetWindowLongPtrA( hwnd
, DWLP_DLGPROC
);
904 proc
= (DLGPROC
)NtUserGetWindowLongA( hwnd
, DWLP_DLGPROC
);
907 if (!(func
= NtUserGetDialogProc( proc
, TRUE
)) &&
908 !(func
= NtUserGetDialogProc( proc
, FALSE
))) return 0;
910 if (func
== WINPROC_PROC16
)
913 ret
= wow_handlers
.call_dialog_proc( hwnd
, msg
, wParam
, lParam
, &result
, proc
);
914 SetWindowLongPtrW( hwnd
, DWLP_MSGRESULT
, result
);
918 return call_dialog_proc( hwnd
, msg
, wParam
, lParam
, &result
, func
);
922 /**********************************************************************
923 * WINPROC_CallDlgProcW
925 INT_PTR
WINPROC_CallDlgProcW( HWND hwnd
, UINT msg
, WPARAM wParam
, LPARAM lParam
)
931 proc
= (DLGPROC
)NtUserGetWindowLongPtrW( hwnd
, DWLP_DLGPROC
);
933 proc
= (DLGPROC
)NtUserGetWindowLongW( hwnd
, DWLP_DLGPROC
);
936 if (!(func
= NtUserGetDialogProc( proc
, FALSE
)) &&
937 !(func
= NtUserGetDialogProc( proc
, TRUE
))) return 0;
939 if (func
== WINPROC_PROC16
)
942 ret
= WINPROC_CallProcWtoA( wow_handlers
.call_dialog_proc
,
943 hwnd
, msg
, wParam
, lParam
, &result
, proc
);
944 SetWindowLongPtrW( hwnd
, DWLP_MSGRESULT
, result
);
948 return call_dialog_proc( hwnd
, msg
, wParam
, lParam
, &result
, func
);
952 /***********************************************************************
953 * Window procedures for builtin classes
956 static LRESULT WINAPI
ButtonWndProcA( HWND hwnd
, UINT msg
, WPARAM wParam
, LPARAM lParam
)
958 return wow_handlers
.button_proc( hwnd
, msg
, wParam
, lParam
, FALSE
);
961 static LRESULT WINAPI
ButtonWndProcW( HWND hwnd
, UINT msg
, WPARAM wParam
, LPARAM lParam
)
963 return wow_handlers
.button_proc( hwnd
, msg
, wParam
, lParam
, TRUE
);
966 static LRESULT WINAPI
ComboWndProcA( HWND hwnd
, UINT message
, WPARAM wParam
, LPARAM lParam
)
968 return wow_handlers
.combo_proc( hwnd
, message
, wParam
, lParam
, FALSE
);
971 static LRESULT WINAPI
ComboWndProcW( HWND hwnd
, UINT message
, WPARAM wParam
, LPARAM lParam
)
973 return wow_handlers
.combo_proc( hwnd
, message
, wParam
, lParam
, TRUE
);
976 LRESULT WINAPI
EditWndProcA( HWND hwnd
, UINT msg
, WPARAM wParam
, LPARAM lParam
)
978 return wow_handlers
.edit_proc( hwnd
, msg
, wParam
, lParam
, FALSE
);
981 static LRESULT WINAPI
EditWndProcW( HWND hwnd
, UINT msg
, WPARAM wParam
, LPARAM lParam
)
983 return wow_handlers
.edit_proc( hwnd
, msg
, wParam
, lParam
, TRUE
);
986 static LRESULT WINAPI
ListBoxWndProcA( HWND hwnd
, UINT msg
, WPARAM wParam
, LPARAM lParam
)
988 return wow_handlers
.listbox_proc( hwnd
, msg
, wParam
, lParam
, FALSE
);
991 static LRESULT WINAPI
ListBoxWndProcW( HWND hwnd
, UINT msg
, WPARAM wParam
, LPARAM lParam
)
993 return wow_handlers
.listbox_proc( hwnd
, msg
, wParam
, lParam
, TRUE
);
996 static LRESULT WINAPI
MDIClientWndProcA( HWND hwnd
, UINT msg
, WPARAM wParam
, LPARAM lParam
)
998 return wow_handlers
.mdiclient_proc( hwnd
, msg
, wParam
, lParam
, FALSE
);
1001 static LRESULT WINAPI
MDIClientWndProcW( HWND hwnd
, UINT msg
, WPARAM wParam
, LPARAM lParam
)
1003 return wow_handlers
.mdiclient_proc( hwnd
, msg
, wParam
, lParam
, TRUE
);
1006 static LRESULT WINAPI
ScrollBarWndProcA( HWND hwnd
, UINT msg
, WPARAM wParam
, LPARAM lParam
)
1008 return wow_handlers
.scrollbar_proc( hwnd
, msg
, wParam
, lParam
, FALSE
);
1011 static LRESULT WINAPI
ScrollBarWndProcW( HWND hwnd
, UINT msg
, WPARAM wParam
, LPARAM lParam
)
1013 return wow_handlers
.scrollbar_proc( hwnd
, msg
, wParam
, lParam
, TRUE
);
1016 static LRESULT WINAPI
StaticWndProcA( HWND hwnd
, UINT msg
, WPARAM wParam
, LPARAM lParam
)
1018 return wow_handlers
.static_proc( hwnd
, msg
, wParam
, lParam
, FALSE
);
1021 static LRESULT WINAPI
StaticWndProcW( HWND hwnd
, UINT msg
, WPARAM wParam
, LPARAM lParam
)
1023 return wow_handlers
.static_proc( hwnd
, msg
, wParam
, lParam
, TRUE
);
1026 /**********************************************************************
1027 * UserRegisterWowHandlers (USER32.@)
1029 * NOTE: no attempt has been made to be compatible here,
1030 * the Windows function is most likely completely different.
1032 void WINAPI
UserRegisterWowHandlers( const struct wow_handlers16
*new, struct wow_handlers32
*orig
)
1034 orig
->button_proc
= ButtonWndProc_common
;
1035 orig
->combo_proc
= ComboWndProc_common
;
1036 orig
->edit_proc
= EditWndProc_common
;
1037 orig
->listbox_proc
= ListBoxWndProc_common
;
1038 orig
->mdiclient_proc
= MDIClientWndProc_common
;
1039 orig
->scrollbar_proc
= ScrollBarWndProc_common
;
1040 orig
->static_proc
= StaticWndProc_common
;
1041 orig
->create_window
= WIN_CreateWindowEx
;
1042 orig
->get_win_handle
= WIN_GetFullHandle
;
1043 orig
->alloc_winproc
= WINPROC_AllocProc
;
1044 orig
->get_dialog_info
= DIALOG_get_info
;
1045 orig
->dialog_box_loop
= DIALOG_DoDialogBox
;
1047 wow_handlers
= *new;
1050 struct wow_handlers16 wow_handlers
=
1052 ButtonWndProc_common
,
1053 ComboWndProc_common
,
1055 ListBoxWndProc_common
,
1056 MDIClientWndProc_common
,
1057 ScrollBarWndProc_common
,
1058 StaticWndProc_common
,
1060 NULL
, /* call_window_proc */
1061 NULL
, /* call_dialog_proc */
1064 static const struct user_client_procs client_procsA
=
1066 .pButtonWndProc
= ButtonWndProcA
,
1067 .pComboWndProc
= ComboWndProcA
,
1068 .pDefWindowProc
= DefWindowProcA
,
1069 .pDefDlgProc
= DefDlgProcA
,
1070 .pEditWndProc
= EditWndProcA
,
1071 .pListBoxWndProc
= ListBoxWndProcA
,
1072 .pMDIClientWndProc
= MDIClientWndProcA
,
1073 .pScrollBarWndProc
= ScrollBarWndProcA
,
1074 .pStaticWndProc
= StaticWndProcA
,
1075 .pImeWndProc
= ImeWndProcA
,
1078 static const struct user_client_procs client_procsW
=
1080 .pButtonWndProc
= ButtonWndProcW
,
1081 .pComboWndProc
= ComboWndProcW
,
1082 .pDefWindowProc
= DefWindowProcW
,
1083 .pDefDlgProc
= DefDlgProcW
,
1084 .pEditWndProc
= EditWndProcW
,
1085 .pListBoxWndProc
= ListBoxWndProcW
,
1086 .pMDIClientWndProc
= MDIClientWndProcW
,
1087 .pScrollBarWndProc
= ScrollBarWndProcW
,
1088 .pStaticWndProc
= StaticWndProcW
,
1089 .pImeWndProc
= ImeWndProcW
,
1090 .pDesktopWndProc
= DesktopWndProc
,
1091 .pIconTitleWndProc
= IconTitleWndProc
,
1092 .pPopupMenuWndProc
= PopupMenuWndProc
,
1093 .pMessageWndProc
= MessageWndProc
,
1096 void winproc_init(void)
1098 NtUserInitializeClientPfnArrays( &client_procsA
, &client_procsW
, NULL
, user32_module
);