win32u: Use user message packing for WM_NCCALCSIZE.
[wine.git] / dlls / user32 / winproc.c
blob1f9b42d0c06faadcb0b732637c18ab55e3253d10
1 /*
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
22 #include "user_private.h"
23 #include "controls.h"
24 #include "dbt.h"
25 #include "wine/asm.h"
26 #include "wine/debug.h"
28 WINE_DEFAULT_DEBUG_CHANNEL(msg);
29 WINE_DECLARE_DEBUG_CHANNEL(relay);
31 union packed_structs
33 struct packed_CREATESTRUCTW cs;
34 struct packed_DRAWITEMSTRUCT dis;
35 struct packed_MEASUREITEMSTRUCT mis;
36 struct packed_DELETEITEMSTRUCT dls;
37 struct packed_COMPAREITEMSTRUCT cis;
38 struct packed_WINDOWPOS wp;
39 struct packed_COPYDATASTRUCT cds;
40 struct packed_HELPINFO hi;
41 struct packed_NCCALCSIZE_PARAMS ncp;
42 struct packed_MSG msg;
43 struct packed_MDINEXTMENU mnm;
44 struct packed_MDICREATESTRUCTW mcs;
47 static inline void *get_buffer( void *static_buffer, size_t size, size_t need )
49 if (size >= need) return static_buffer;
50 return HeapAlloc( GetProcessHeap(), 0, need );
53 static inline void free_buffer( void *static_buffer, void *buffer )
55 if (buffer != static_buffer) HeapFree( GetProcessHeap(), 0, buffer );
58 #ifdef __i386__
59 /* Some window procedures modify registers they shouldn't, or are not
60 * properly declared stdcall; so we need a small assembly wrapper to
61 * call them. */
62 extern LRESULT WINPROC_wrapper( WNDPROC proc, HWND hwnd, UINT msg,
63 WPARAM wParam, LPARAM lParam );
64 __ASM_GLOBAL_FUNC( WINPROC_wrapper,
65 "pushl %ebp\n\t"
66 __ASM_CFI(".cfi_adjust_cfa_offset 4\n\t")
67 __ASM_CFI(".cfi_rel_offset %ebp,0\n\t")
68 "movl %esp,%ebp\n\t"
69 __ASM_CFI(".cfi_def_cfa_register %ebp\n\t")
70 "pushl %edi\n\t"
71 __ASM_CFI(".cfi_rel_offset %edi,-4\n\t")
72 "pushl %esi\n\t"
73 __ASM_CFI(".cfi_rel_offset %esi,-8\n\t")
74 "pushl %ebx\n\t"
75 __ASM_CFI(".cfi_rel_offset %ebx,-12\n\t")
76 /* TreePad X Enterprise assumes that edi is < 0x80000000 in WM_TIMER messages */
77 "xorl %edi,%edi\n\t"
78 "subl $12,%esp\n\t"
79 "pushl 24(%ebp)\n\t"
80 "pushl 20(%ebp)\n\t"
81 "pushl 16(%ebp)\n\t"
82 "pushl 12(%ebp)\n\t"
83 "movl 8(%ebp),%eax\n\t"
84 "call *%eax\n\t"
85 "leal -12(%ebp),%esp\n\t"
86 "popl %ebx\n\t"
87 __ASM_CFI(".cfi_same_value %ebx\n\t")
88 "popl %esi\n\t"
89 __ASM_CFI(".cfi_same_value %esi\n\t")
90 "popl %edi\n\t"
91 __ASM_CFI(".cfi_same_value %edi\n\t")
92 "leave\n\t"
93 __ASM_CFI(".cfi_def_cfa %esp,4\n\t")
94 __ASM_CFI(".cfi_same_value %ebp\n\t")
95 "ret" )
96 #else
97 static inline LRESULT WINPROC_wrapper( WNDPROC proc, HWND hwnd, UINT msg,
98 WPARAM wParam, LPARAM lParam )
100 return proc( hwnd, msg, wParam, lParam );
102 #endif /* __i386__ */
104 static WPARAM map_wparam_char_WtoA( WPARAM wParam, DWORD len )
106 WCHAR wch = wParam;
107 BYTE ch[2];
108 DWORD cp = get_input_codepage();
110 len = WideCharToMultiByte( cp, 0, &wch, 1, (LPSTR)ch, len, NULL, NULL );
111 if (len == 2)
112 return MAKEWPARAM( (ch[0] << 8) | ch[1], HIWORD(wParam) );
113 else
114 return MAKEWPARAM( ch[0], HIWORD(wParam) );
117 /* call a 32-bit window procedure */
118 static LRESULT call_window_proc( HWND hwnd, UINT msg, WPARAM wp, LPARAM lp, LRESULT *result, void *arg )
120 WNDPROC proc = arg;
122 TRACE_(relay)( "\1Call window proc %p (hwnd=%p,msg=%s,wp=%08Ix,lp=%08Ix)\n",
123 proc, hwnd, SPY_GetMsgName(msg, hwnd), wp, lp );
125 *result = WINPROC_wrapper( proc, hwnd, msg, wp, lp );
127 TRACE_(relay)( "\1Ret window proc %p (hwnd=%p,msg=%s,wp=%08Ix,lp=%08Ix) retval=%08Ix\n",
128 proc, hwnd, SPY_GetMsgName(msg, hwnd), wp, lp, *result );
129 return *result;
132 /* call a 32-bit dialog procedure */
133 static LRESULT call_dialog_proc( HWND hwnd, UINT msg, WPARAM wp, LPARAM lp, LRESULT *result, void *arg )
135 DPI_AWARENESS_CONTEXT context;
136 WNDPROC proc = arg;
137 LRESULT ret;
139 hwnd = WIN_GetFullHandle( hwnd );
140 TRACE_(relay)( "\1Call dialog proc %p (hwnd=%p,msg=%s,wp=%08Ix,lp=%08Ix)\n",
141 proc, hwnd, SPY_GetMsgName(msg, hwnd), wp, lp );
143 context = SetThreadDpiAwarenessContext( GetWindowDpiAwarenessContext( hwnd ));
144 ret = WINPROC_wrapper( proc, hwnd, msg, wp, lp );
145 *result = GetWindowLongPtrW( hwnd, DWLP_MSGRESULT );
146 SetThreadDpiAwarenessContext( context );
148 TRACE_(relay)( "\1Ret dialog proc %p (hwnd=%p,msg=%s,wp=%08Ix,lp=%08Ix) retval=%08Ix result=%08Ix\n",
149 proc, hwnd, SPY_GetMsgName(msg, hwnd), wp, lp, ret, *result );
150 return ret;
154 /**********************************************************************
155 * WINPROC_AllocProc
157 * Allocate a window procedure for a window or class.
159 * Note that allocated winprocs are never freed; the idea is that even if an app creates a
160 * lot of windows, it will usually only have a limited number of window procedures, so the
161 * array won't grow too large, and this way we avoid the need to track allocations per window.
163 static WNDPROC WINPROC_AllocProc( WNDPROC func, BOOL unicode )
165 return (WNDPROC)NtUserCallTwoParam( (UINT_PTR)func, !unicode, NtUserAllocWinProc );
169 /**********************************************************************
170 * WINPROC_TestLBForStr
172 * Return TRUE if the lparam is a string
174 static inline BOOL WINPROC_TestLBForStr( HWND hwnd, UINT msg )
176 DWORD style = GetWindowLongA( hwnd, GWL_STYLE );
177 if (msg <= CB_MSGMAX)
178 return (!(style & (CBS_OWNERDRAWFIXED | CBS_OWNERDRAWVARIABLE)) || (style & CBS_HASSTRINGS));
179 else
180 return (!(style & (LBS_OWNERDRAWFIXED | LBS_OWNERDRAWVARIABLE)) || (style & LBS_HASSTRINGS));
185 /**********************************************************************
186 * WINPROC_CallProcAtoW
188 * Call a window procedure, translating args from Ansi to Unicode.
190 LRESULT WINPROC_CallProcAtoW( winproc_callback_t callback, HWND hwnd, UINT msg, WPARAM wParam,
191 LPARAM lParam, LRESULT *result, void *arg, enum wm_char_mapping mapping )
193 LRESULT ret = 0;
195 TRACE_(msg)("(hwnd=%p,msg=%s,wp=%08Ix,lp=%08Ix)\n",
196 hwnd, SPY_GetMsgName(msg, hwnd), wParam, lParam);
198 switch(msg)
200 case WM_NCCREATE:
201 case WM_CREATE:
203 WCHAR *ptr, buffer[512];
204 CREATESTRUCTA *csA = (CREATESTRUCTA *)lParam;
205 CREATESTRUCTW csW = *(CREATESTRUCTW *)csA;
206 MDICREATESTRUCTW mdi_cs;
207 DWORD name_lenA = 0, name_lenW = 0, class_lenA = 0, class_lenW = 0;
209 if (!IS_INTRESOURCE(csA->lpszClass))
211 class_lenA = strlen(csA->lpszClass) + 1;
212 RtlMultiByteToUnicodeSize( &class_lenW, csA->lpszClass, class_lenA );
214 if (!IS_INTRESOURCE(csA->lpszName))
216 name_lenA = strlen(csA->lpszName) + 1;
217 RtlMultiByteToUnicodeSize( &name_lenW, csA->lpszName, name_lenA );
220 if (!(ptr = get_buffer( buffer, sizeof(buffer), class_lenW + name_lenW ))) break;
222 if (class_lenW)
224 csW.lpszClass = ptr;
225 RtlMultiByteToUnicodeN( ptr, class_lenW, NULL, csA->lpszClass, class_lenA );
227 if (name_lenW)
229 csW.lpszName = ptr + class_lenW/sizeof(WCHAR);
230 RtlMultiByteToUnicodeN( ptr + class_lenW/sizeof(WCHAR), name_lenW, NULL,
231 csA->lpszName, name_lenA );
234 if (GetWindowLongW(hwnd, GWL_EXSTYLE) & WS_EX_MDICHILD)
236 mdi_cs = *(MDICREATESTRUCTW *)csA->lpCreateParams;
237 mdi_cs.szTitle = csW.lpszName;
238 mdi_cs.szClass = csW.lpszClass;
239 csW.lpCreateParams = &mdi_cs;
242 ret = callback( hwnd, msg, wParam, (LPARAM)&csW, result, arg );
243 free_buffer( buffer, ptr );
245 break;
247 case WM_MDICREATE:
249 WCHAR *ptr, buffer[512];
250 DWORD title_lenA = 0, title_lenW = 0, class_lenA = 0, class_lenW = 0;
251 MDICREATESTRUCTA *csA = (MDICREATESTRUCTA *)lParam;
252 MDICREATESTRUCTW csW;
254 memcpy( &csW, csA, sizeof(csW) );
256 if (!IS_INTRESOURCE(csA->szTitle))
258 title_lenA = strlen(csA->szTitle) + 1;
259 RtlMultiByteToUnicodeSize( &title_lenW, csA->szTitle, title_lenA );
261 if (!IS_INTRESOURCE(csA->szClass))
263 class_lenA = strlen(csA->szClass) + 1;
264 RtlMultiByteToUnicodeSize( &class_lenW, csA->szClass, class_lenA );
267 if (!(ptr = get_buffer( buffer, sizeof(buffer), title_lenW + class_lenW ))) break;
269 if (title_lenW)
271 csW.szTitle = ptr;
272 RtlMultiByteToUnicodeN( ptr, title_lenW, NULL, csA->szTitle, title_lenA );
274 if (class_lenW)
276 csW.szClass = ptr + title_lenW/sizeof(WCHAR);
277 RtlMultiByteToUnicodeN( ptr + title_lenW/sizeof(WCHAR), class_lenW, NULL,
278 csA->szClass, class_lenA );
280 ret = callback( hwnd, msg, wParam, (LPARAM)&csW, result, arg );
281 free_buffer( buffer, ptr );
283 break;
285 case WM_GETTEXT:
286 case WM_ASKCBFORMATNAME:
288 WCHAR *ptr, buffer[512];
289 LPSTR str = (LPSTR)lParam;
290 DWORD len = wParam * sizeof(WCHAR);
292 if (!(ptr = get_buffer( buffer, sizeof(buffer), len ))) break;
293 ret = callback( hwnd, msg, wParam, (LPARAM)ptr, result, arg );
294 if (wParam)
296 len = 0;
297 if (*result)
298 RtlUnicodeToMultiByteN( str, wParam - 1, &len, ptr, ret * sizeof(WCHAR) );
299 str[len] = 0;
300 *result = len;
302 free_buffer( buffer, ptr );
304 break;
306 case LB_ADDSTRING:
307 case LB_INSERTSTRING:
308 case LB_FINDSTRING:
309 case LB_FINDSTRINGEXACT:
310 case LB_SELECTSTRING:
311 case CB_ADDSTRING:
312 case CB_INSERTSTRING:
313 case CB_FINDSTRING:
314 case CB_FINDSTRINGEXACT:
315 case CB_SELECTSTRING:
316 if (!lParam || !WINPROC_TestLBForStr( hwnd, msg ))
318 ret = callback( hwnd, msg, wParam, lParam, result, arg );
319 break;
321 /* fall through */
322 case WM_SETTEXT:
323 case WM_WININICHANGE:
324 case WM_DEVMODECHANGE:
325 case CB_DIR:
326 case LB_DIR:
327 case LB_ADDFILE:
328 case EM_REPLACESEL:
329 if (!lParam) ret = callback( hwnd, msg, wParam, lParam, result, arg );
330 else
332 WCHAR *ptr, buffer[512];
333 LPCSTR strA = (LPCSTR)lParam;
334 DWORD lenW, lenA = strlen(strA) + 1;
336 RtlMultiByteToUnicodeSize( &lenW, strA, lenA );
337 if ((ptr = get_buffer( buffer, sizeof(buffer), lenW )))
339 RtlMultiByteToUnicodeN( ptr, lenW, NULL, strA, lenA );
340 ret = callback( hwnd, msg, wParam, (LPARAM)ptr, result, arg );
341 free_buffer( buffer, ptr );
344 break;
346 case LB_GETTEXT:
347 case CB_GETLBTEXT:
348 if (lParam && WINPROC_TestLBForStr( hwnd, msg ))
350 WCHAR buffer[512]; /* FIXME: fixed sized buffer */
352 ret = callback( hwnd, msg, wParam, (LPARAM)buffer, result, arg );
353 if (*result >= 0)
355 DWORD len;
356 RtlUnicodeToMultiByteN( (LPSTR)lParam, 512 * 3, &len,
357 buffer, (lstrlenW(buffer) + 1) * sizeof(WCHAR) );
358 *result = len - 1;
361 else ret = callback( hwnd, msg, wParam, lParam, result, arg );
362 break;
364 case EM_GETLINE:
366 WCHAR *ptr, buffer[512];
367 WORD len = *(WORD *)lParam;
369 if (!(ptr = get_buffer( buffer, sizeof(buffer), len * sizeof(WCHAR) ))) break;
370 *((WORD *)ptr) = len; /* store the length */
371 ret = callback( hwnd, msg, wParam, (LPARAM)ptr, result, arg );
372 if (*result)
374 DWORD reslen;
375 RtlUnicodeToMultiByteN( (LPSTR)lParam, len, &reslen, ptr, *result * sizeof(WCHAR) );
376 if (reslen < len) ((LPSTR)lParam)[reslen] = 0;
377 *result = reslen;
379 free_buffer( buffer, ptr );
381 break;
383 case WM_GETDLGCODE:
384 if (lParam)
386 MSG newmsg = *(MSG *)lParam;
387 if (map_wparam_AtoW( newmsg.message, &newmsg.wParam, WMCHAR_MAP_NOMAPPING ))
388 ret = callback( hwnd, msg, wParam, (LPARAM)&newmsg, result, arg );
390 else ret = callback( hwnd, msg, wParam, lParam, result, arg );
391 break;
393 case WM_CHARTOITEM:
394 case WM_MENUCHAR:
395 case WM_CHAR:
396 case WM_DEADCHAR:
397 case WM_SYSCHAR:
398 case WM_SYSDEADCHAR:
399 case EM_SETPASSWORDCHAR:
400 case WM_IME_CHAR:
401 if (map_wparam_AtoW( msg, &wParam, mapping ))
402 ret = callback( hwnd, msg, wParam, lParam, result, arg );
403 break;
405 case WM_GETTEXTLENGTH:
406 case CB_GETLBTEXTLEN:
407 case LB_GETTEXTLEN:
408 ret = callback( hwnd, msg, wParam, lParam, result, arg );
409 if (*result >= 0)
411 WCHAR *ptr, buffer[512];
412 LRESULT tmp;
413 DWORD len = *result + 1;
414 /* Determine respective GETTEXT message */
415 UINT msgGetText = (msg == WM_GETTEXTLENGTH) ? WM_GETTEXT :
416 ((msg == CB_GETLBTEXTLEN) ? CB_GETLBTEXT : LB_GETTEXT);
417 /* wParam differs between the messages */
418 WPARAM wp = (msg == WM_GETTEXTLENGTH) ? len : wParam;
420 if (!(ptr = get_buffer( buffer, sizeof(buffer), len * sizeof(WCHAR) ))) break;
422 if (callback == call_window_proc) /* FIXME: hack */
423 callback( hwnd, msgGetText, wp, (LPARAM)ptr, &tmp, arg );
424 else
425 tmp = SendMessageW( hwnd, msgGetText, wp, (LPARAM)ptr );
426 RtlUnicodeToMultiByteSize( &len, ptr, tmp * sizeof(WCHAR) );
427 *result = len;
428 free_buffer( buffer, ptr );
430 break;
432 case WM_PAINTCLIPBOARD:
433 case WM_SIZECLIPBOARD:
434 FIXME_(msg)( "message %s (0x%x) needs translation, please report\n",
435 SPY_GetMsgName(msg, hwnd), msg );
436 break;
438 default:
439 ret = callback( hwnd, msg, wParam, lParam, result, arg );
440 break;
442 return ret;
446 /**********************************************************************
447 * WINPROC_CallProcWtoA
449 * Call a window procedure, translating args from Unicode to Ansi.
451 static LRESULT WINPROC_CallProcWtoA( winproc_callback_t callback, HWND hwnd, UINT msg, WPARAM wParam,
452 LPARAM lParam, LRESULT *result, void *arg )
454 LRESULT ret = 0;
456 TRACE_(msg)("(hwnd=%p,msg=%s,wp=%08Ix,lp=%08Ix)\n",
457 hwnd, SPY_GetMsgName(msg, hwnd), wParam, lParam);
459 switch(msg)
461 case WM_NCCREATE:
462 case WM_CREATE:
464 char buffer[1024], *cls;
465 CREATESTRUCTW *csW = (CREATESTRUCTW *)lParam;
466 CREATESTRUCTA csA = *(CREATESTRUCTA *)csW;
467 MDICREATESTRUCTA mdi_cs;
468 DWORD name_lenA = 0, name_lenW = 0, class_lenA = 0, class_lenW = 0;
469 char int_name_buf[4];
471 if (!IS_INTRESOURCE(csW->lpszClass))
473 class_lenW = (lstrlenW(csW->lpszClass) + 1) * sizeof(WCHAR);
474 RtlUnicodeToMultiByteSize(&class_lenA, csW->lpszClass, class_lenW);
476 if (!IS_INTRESOURCE(csW->lpszName))
478 /* resource ID string is a special case */
479 if (csW->lpszName[0] == 0xffff)
481 int_name_buf[0] = 0xff;
482 int_name_buf[1] = csW->lpszName[1];
483 int_name_buf[2] = csW->lpszName[1] >> 8;
484 int_name_buf[3] = 0;
485 csA.lpszName = int_name_buf;
487 else
489 name_lenW = (lstrlenW(csW->lpszName) + 1) * sizeof(WCHAR);
490 RtlUnicodeToMultiByteSize(&name_lenA, csW->lpszName, name_lenW);
494 if (!(cls = get_buffer( buffer, sizeof(buffer), class_lenA + name_lenA ))) break;
496 if (class_lenA)
498 RtlUnicodeToMultiByteN(cls, class_lenA, NULL, csW->lpszClass, class_lenW);
499 csA.lpszClass = cls;
501 if (name_lenA)
503 char *name = cls + class_lenA;
504 RtlUnicodeToMultiByteN(name, name_lenA, NULL, csW->lpszName, name_lenW);
505 csA.lpszName = name;
508 if (GetWindowLongW(hwnd, GWL_EXSTYLE) & WS_EX_MDICHILD)
510 mdi_cs = *(MDICREATESTRUCTA *)csW->lpCreateParams;
511 mdi_cs.szTitle = csA.lpszName;
512 mdi_cs.szClass = csA.lpszClass;
513 csA.lpCreateParams = &mdi_cs;
516 ret = callback( hwnd, msg, wParam, (LPARAM)&csA, result, arg );
517 free_buffer( buffer, cls );
519 break;
521 case WM_GETTEXT:
522 case WM_ASKCBFORMATNAME:
524 char *ptr, buffer[512];
525 DWORD len = wParam * 2;
527 if (!(ptr = get_buffer( buffer, sizeof(buffer), len ))) break;
528 ret = callback( hwnd, msg, wParam, (LPARAM)ptr, result, arg );
529 if (len)
531 if (*result)
533 RtlMultiByteToUnicodeN( (LPWSTR)lParam, wParam*sizeof(WCHAR), &len, ptr, ret + 1 );
534 *result = len/sizeof(WCHAR) - 1; /* do not count terminating null */
536 ((LPWSTR)lParam)[*result] = 0;
538 free_buffer( buffer, ptr );
540 break;
542 case LB_ADDSTRING:
543 case LB_INSERTSTRING:
544 case LB_FINDSTRING:
545 case LB_FINDSTRINGEXACT:
546 case LB_SELECTSTRING:
547 case CB_ADDSTRING:
548 case CB_INSERTSTRING:
549 case CB_FINDSTRING:
550 case CB_FINDSTRINGEXACT:
551 case CB_SELECTSTRING:
552 if (!lParam || !WINPROC_TestLBForStr( hwnd, msg ))
554 ret = callback( hwnd, msg, wParam, lParam, result, arg );
555 break;
557 /* fall through */
558 case WM_SETTEXT:
559 case WM_WININICHANGE:
560 case WM_DEVMODECHANGE:
561 case CB_DIR:
562 case LB_DIR:
563 case LB_ADDFILE:
564 case EM_REPLACESEL:
565 if (!lParam) ret = callback( hwnd, msg, wParam, lParam, result, arg );
566 else
568 char *ptr, buffer[512];
569 LPCWSTR strW = (LPCWSTR)lParam;
570 DWORD lenA, lenW = (lstrlenW(strW) + 1) * sizeof(WCHAR);
572 RtlUnicodeToMultiByteSize( &lenA, strW, lenW );
573 if ((ptr = get_buffer( buffer, sizeof(buffer), lenA )))
575 RtlUnicodeToMultiByteN( ptr, lenA, NULL, strW, lenW );
576 ret = callback( hwnd, msg, wParam, (LPARAM)ptr, result, arg );
577 free_buffer( buffer, ptr );
580 break;
582 case WM_MDICREATE:
584 char *ptr, buffer[1024];
585 DWORD title_lenA = 0, title_lenW = 0, class_lenA = 0, class_lenW = 0;
586 MDICREATESTRUCTW *csW = (MDICREATESTRUCTW *)lParam;
587 MDICREATESTRUCTA csA;
589 memcpy( &csA, csW, sizeof(csA) );
591 if (!IS_INTRESOURCE(csW->szTitle))
593 title_lenW = (lstrlenW(csW->szTitle) + 1) * sizeof(WCHAR);
594 RtlUnicodeToMultiByteSize( &title_lenA, csW->szTitle, title_lenW );
596 if (!IS_INTRESOURCE(csW->szClass))
598 class_lenW = (lstrlenW(csW->szClass) + 1) * sizeof(WCHAR);
599 RtlUnicodeToMultiByteSize( &class_lenA, csW->szClass, class_lenW );
602 if (!(ptr = get_buffer( buffer, sizeof(buffer), title_lenA + class_lenA ))) break;
604 if (title_lenA)
606 RtlUnicodeToMultiByteN( ptr, title_lenA, NULL, csW->szTitle, title_lenW );
607 csA.szTitle = ptr;
609 if (class_lenA)
611 RtlUnicodeToMultiByteN( ptr + title_lenA, class_lenA, NULL, csW->szClass, class_lenW );
612 csA.szClass = ptr + title_lenA;
614 ret = callback( hwnd, msg, wParam, (LPARAM)&csA, result, arg );
615 free_buffer( buffer, ptr );
617 break;
619 case LB_GETTEXT:
620 case CB_GETLBTEXT:
621 if (lParam && WINPROC_TestLBForStr( hwnd, msg ))
623 char buffer[512]; /* FIXME: fixed sized buffer */
625 ret = callback( hwnd, msg, wParam, (LPARAM)buffer, result, arg );
626 if (*result >= 0)
628 DWORD len;
629 RtlMultiByteToUnicodeN( (LPWSTR)lParam, 512 * 3, &len, buffer, strlen(buffer) + 1 );
630 *result = len / sizeof(WCHAR) - 1;
633 else ret = callback( hwnd, msg, wParam, lParam, result, arg );
634 break;
636 case EM_GETLINE:
638 char *ptr, buffer[512];
639 WORD len = *(WORD *)lParam;
641 if (!(ptr = get_buffer( buffer, sizeof(buffer), len * 2 ))) break;
642 *((WORD *)ptr) = len * 2; /* store the length */
643 ret = callback( hwnd, msg, wParam, (LPARAM)ptr, result, arg );
644 if (*result)
646 DWORD reslen;
647 RtlMultiByteToUnicodeN( (LPWSTR)lParam, len*sizeof(WCHAR), &reslen, ptr, *result );
648 *result = reslen / sizeof(WCHAR);
649 if (*result < len) ((LPWSTR)lParam)[*result] = 0;
651 free_buffer( buffer, ptr );
653 break;
655 case WM_GETDLGCODE:
656 if (lParam)
658 MSG newmsg = *(MSG *)lParam;
659 switch(newmsg.message)
661 case WM_CHAR:
662 case WM_DEADCHAR:
663 case WM_SYSCHAR:
664 case WM_SYSDEADCHAR:
665 newmsg.wParam = map_wparam_char_WtoA( newmsg.wParam, 1 );
666 break;
667 case WM_IME_CHAR:
668 newmsg.wParam = map_wparam_char_WtoA( newmsg.wParam, 2 );
669 break;
671 ret = callback( hwnd, msg, wParam, (LPARAM)&newmsg, result, arg );
673 else ret = callback( hwnd, msg, wParam, lParam, result, arg );
674 break;
676 case WM_CHAR:
678 WCHAR wch = wParam;
679 char ch[2];
680 DWORD cp = get_input_codepage();
681 DWORD len = WideCharToMultiByte( cp, 0, &wch, 1, ch, 2, NULL, NULL );
682 ret = callback( hwnd, msg, (BYTE)ch[0], lParam, result, arg );
683 if (len == 2) ret = callback( hwnd, msg, (BYTE)ch[1], lParam, result, arg );
685 break;
687 case WM_CHARTOITEM:
688 case WM_MENUCHAR:
689 case WM_DEADCHAR:
690 case WM_SYSCHAR:
691 case WM_SYSDEADCHAR:
692 case EM_SETPASSWORDCHAR:
693 ret = callback( hwnd, msg, map_wparam_char_WtoA(wParam,1), lParam, result, arg );
694 break;
696 case WM_IME_CHAR:
697 ret = callback( hwnd, msg, map_wparam_char_WtoA(wParam,2), lParam, result, arg );
698 break;
700 case WM_PAINTCLIPBOARD:
701 case WM_SIZECLIPBOARD:
702 FIXME_(msg)( "message %s (%04x) needs translation, please report\n",
703 SPY_GetMsgName(msg, hwnd), msg );
704 break;
706 default:
707 ret = callback( hwnd, msg, wParam, lParam, result, arg );
708 break;
711 return ret;
715 LRESULT dispatch_win_proc_params( struct win_proc_params *params )
717 DPI_AWARENESS_CONTEXT context = SetThreadDpiAwarenessContext( params->dpi_awareness );
718 LRESULT result = 0;
720 if (!params->ansi)
722 if (params->procW == WINPROC_PROC16)
723 WINPROC_CallProcWtoA( wow_handlers.call_window_proc, params->hwnd, params->msg, params->wparam,
724 params->lparam, &result, params->func );
725 else if (!params->ansi_dst)
726 call_window_proc( params->hwnd, params->msg, params->wparam, params->lparam,
727 &result, params->procW );
728 else
729 WINPROC_CallProcWtoA( call_window_proc, params->hwnd, params->msg, params->wparam,
730 params->lparam, &result, params->procA );
732 else
734 if (params->procA == WINPROC_PROC16)
735 wow_handlers.call_window_proc( params->hwnd, params->msg, params->wparam, params->lparam,
736 &result, params->func );
737 else if (!params->ansi_dst)
738 WINPROC_CallProcAtoW( call_window_proc, params->hwnd, params->msg, params->wparam,
739 params->lparam, &result, params->procW, params->mapping );
740 else
741 call_window_proc( params->hwnd, params->msg, params->wparam, params->lparam,
742 &result, params->procA );
745 SetThreadDpiAwarenessContext( context );
746 return result;
749 /* make sure that there is space for 'size' bytes in buffer, growing it if needed */
750 static inline void *get_buffer_space( void **buffer, size_t size, size_t prev_size )
752 if (prev_size < size)
753 *buffer = HeapAlloc( GetProcessHeap(), 0, size );
754 return *buffer;
757 /* check whether a combobox expects strings or ids in CB_ADDSTRING/CB_INSERTSTRING */
758 static inline BOOL combobox_has_strings( HWND hwnd )
760 DWORD style = GetWindowLongA( hwnd, GWL_STYLE );
761 return (!(style & (CBS_OWNERDRAWFIXED | CBS_OWNERDRAWVARIABLE)) || (style & CBS_HASSTRINGS));
764 /* check whether a listbox expects strings or ids in LB_ADDSTRING/LB_INSERTSTRING */
765 static inline BOOL listbox_has_strings( HWND hwnd )
767 DWORD style = GetWindowLongA( hwnd, GWL_STYLE );
768 return (!(style & (LBS_OWNERDRAWFIXED | LBS_OWNERDRAWVARIABLE)) || (style & LBS_HASSTRINGS));
771 /* unpack a potentially 64-bit pointer, returning 0 when truncated */
772 static inline void *unpack_ptr( ULONGLONG ptr64 )
774 if ((ULONG_PTR)ptr64 != ptr64) return 0;
775 return (void *)(ULONG_PTR)ptr64;
778 /* convert a server handle to a generic handle */
779 static inline HANDLE unpack_handle( UINT handle )
781 return (HANDLE)(INT_PTR)(int)handle;
784 /* make sure that the buffer contains a valid null-terminated Unicode string */
785 static inline BOOL check_string( LPCWSTR str, size_t size )
787 for (size /= sizeof(WCHAR); size; size--, str++)
788 if (!*str) return TRUE;
789 return FALSE;
792 static size_t string_size( const void *str, BOOL ansi )
794 return ansi ? strlen( str ) + 1 : (wcslen( str ) + 1) * sizeof(WCHAR);
797 /***********************************************************************
798 * unpack_message
800 * Unpack a message received from another process.
802 BOOL unpack_message( HWND hwnd, UINT message, WPARAM *wparam, LPARAM *lparam,
803 void **buffer, size_t size, BOOL ansi )
805 size_t minsize = 0, prev_size = size;
806 union packed_structs *ps = *buffer;
808 switch(message)
810 case WM_NCCREATE:
811 case WM_CREATE:
813 CREATESTRUCTA *cs = *buffer;
814 char *str = (char *)(cs + 1);
816 if (!IS_INTRESOURCE(cs->lpszName))
818 cs->lpszName = str;
819 str += string_size( str, ansi );
821 if (!IS_INTRESOURCE(cs->lpszClass))
823 cs->lpszClass = str;
825 break;
827 case WM_NCCALCSIZE:
828 if (*wparam)
830 NCCALCSIZE_PARAMS *ncp = *buffer;
831 ncp->lppos = (WINDOWPOS *)((NCCALCSIZE_PARAMS *)ncp + 1);
833 break;
834 case WM_GETTEXT:
835 case WM_ASKCBFORMATNAME:
836 if (!get_buffer_space( buffer, (*wparam * sizeof(WCHAR)), size )) return FALSE;
837 break;
838 case WM_WININICHANGE:
839 if (!*lparam) return TRUE;
840 /* fall through */
841 case WM_SETTEXT:
842 case WM_DEVMODECHANGE:
843 case CB_DIR:
844 case LB_DIR:
845 case LB_ADDFILE:
846 case EM_REPLACESEL:
847 if (!check_string( *buffer, size )) return FALSE;
848 break;
849 case WM_GETMINMAXINFO:
850 minsize = sizeof(MINMAXINFO);
851 break;
852 case WM_DRAWITEM:
854 DRAWITEMSTRUCT dis;
855 if (size < sizeof(ps->dis)) return FALSE;
856 dis.CtlType = ps->dis.CtlType;
857 dis.CtlID = ps->dis.CtlID;
858 dis.itemID = ps->dis.itemID;
859 dis.itemAction = ps->dis.itemAction;
860 dis.itemState = ps->dis.itemState;
861 dis.hwndItem = unpack_handle( ps->dis.hwndItem );
862 dis.hDC = unpack_handle( ps->dis.hDC );
863 dis.rcItem = ps->dis.rcItem;
864 dis.itemData = (ULONG_PTR)unpack_ptr( ps->dis.itemData );
865 memcpy( *buffer, &dis, sizeof(dis) );
866 break;
868 case WM_MEASUREITEM:
870 MEASUREITEMSTRUCT mis;
871 if (size < sizeof(ps->mis)) return FALSE;
872 mis.CtlType = ps->mis.CtlType;
873 mis.CtlID = ps->mis.CtlID;
874 mis.itemID = ps->mis.itemID;
875 mis.itemWidth = ps->mis.itemWidth;
876 mis.itemHeight = ps->mis.itemHeight;
877 mis.itemData = (ULONG_PTR)unpack_ptr( ps->mis.itemData );
878 memcpy( *buffer, &mis, sizeof(mis) );
879 break;
881 case WM_DELETEITEM:
883 DELETEITEMSTRUCT dls;
884 if (size < sizeof(ps->dls)) return FALSE;
885 dls.CtlType = ps->dls.CtlType;
886 dls.CtlID = ps->dls.CtlID;
887 dls.itemID = ps->dls.itemID;
888 dls.hwndItem = unpack_handle( ps->dls.hwndItem );
889 dls.itemData = (ULONG_PTR)unpack_ptr( ps->dls.itemData );
890 memcpy( *buffer, &dls, sizeof(dls) );
891 break;
893 case WM_COMPAREITEM:
895 COMPAREITEMSTRUCT cis;
896 if (size < sizeof(ps->cis)) return FALSE;
897 cis.CtlType = ps->cis.CtlType;
898 cis.CtlID = ps->cis.CtlID;
899 cis.hwndItem = unpack_handle( ps->cis.hwndItem );
900 cis.itemID1 = ps->cis.itemID1;
901 cis.itemData1 = (ULONG_PTR)unpack_ptr( ps->cis.itemData1 );
902 cis.itemID2 = ps->cis.itemID2;
903 cis.itemData2 = (ULONG_PTR)unpack_ptr( ps->cis.itemData2 );
904 cis.dwLocaleId = ps->cis.dwLocaleId;
905 memcpy( *buffer, &cis, sizeof(cis) );
906 break;
908 case WM_WINDOWPOSCHANGING:
909 case WM_WINDOWPOSCHANGED:
911 WINDOWPOS wp;
912 if (size < sizeof(ps->wp)) return FALSE;
913 wp.hwnd = unpack_handle( ps->wp.hwnd );
914 wp.hwndInsertAfter = unpack_handle( ps->wp.hwndInsertAfter );
915 wp.x = ps->wp.x;
916 wp.y = ps->wp.y;
917 wp.cx = ps->wp.cx;
918 wp.cy = ps->wp.cy;
919 wp.flags = ps->wp.flags;
920 memcpy( *buffer, &wp, sizeof(wp) );
921 break;
923 case WM_COPYDATA:
925 COPYDATASTRUCT cds;
926 if (size < sizeof(ps->cds)) return FALSE;
927 cds.dwData = (ULONG_PTR)unpack_ptr( ps->cds.dwData );
928 if (ps->cds.lpData)
930 cds.cbData = ps->cds.cbData;
931 cds.lpData = &ps->cds + 1;
932 minsize = sizeof(ps->cds) + cds.cbData;
934 else
936 cds.cbData = 0;
937 cds.lpData = 0;
939 memcpy( &ps->cds, &cds, sizeof(cds) );
940 break;
942 case WM_NOTIFY:
943 /* WM_NOTIFY cannot be sent across processes (MSDN) */
944 return FALSE;
945 case WM_HELP:
947 HELPINFO hi;
948 if (size < sizeof(ps->hi)) return FALSE;
949 hi.cbSize = sizeof(hi);
950 hi.iContextType = ps->hi.iContextType;
951 hi.iCtrlId = ps->hi.iCtrlId;
952 hi.hItemHandle = unpack_handle( ps->hi.hItemHandle );
953 hi.dwContextId = (ULONG_PTR)unpack_ptr( ps->hi.dwContextId );
954 hi.MousePos = ps->hi.MousePos;
955 memcpy( &ps->hi, &hi, sizeof(hi) );
956 break;
958 case WM_STYLECHANGING:
959 case WM_STYLECHANGED:
960 minsize = sizeof(STYLESTRUCT);
961 break;
962 case WM_GETDLGCODE:
963 if (*lparam)
965 MSG msg;
966 if (size < sizeof(ps->msg)) return FALSE;
967 msg.hwnd = unpack_handle( ps->msg.hwnd );
968 msg.message = ps->msg.message;
969 msg.wParam = (ULONG_PTR)unpack_ptr( ps->msg.wParam );
970 msg.lParam = (ULONG_PTR)unpack_ptr( ps->msg.lParam );
971 msg.time = ps->msg.time;
972 msg.pt = ps->msg.pt;
973 memcpy( &ps->msg, &msg, sizeof(msg) );
974 break;
976 return TRUE;
977 case SBM_SETSCROLLINFO:
978 minsize = sizeof(SCROLLINFO);
979 break;
980 case SBM_GETSCROLLINFO:
981 if (!get_buffer_space( buffer, sizeof(SCROLLINFO), size )) return FALSE;
982 break;
983 case SBM_GETSCROLLBARINFO:
984 if (!get_buffer_space( buffer, sizeof(SCROLLBARINFO), size )) return FALSE;
985 break;
986 case EM_GETSEL:
987 case SBM_GETRANGE:
988 case CB_GETEDITSEL:
989 if (*wparam || *lparam)
991 if (!get_buffer_space( buffer, 2*sizeof(DWORD), size )) return FALSE;
992 if (*wparam) *wparam = (WPARAM)*buffer;
993 if (*lparam) *lparam = (LPARAM)((DWORD *)*buffer + 1);
995 return TRUE;
996 case EM_GETRECT:
997 case LB_GETITEMRECT:
998 case CB_GETDROPPEDCONTROLRECT:
999 if (!get_buffer_space( buffer, sizeof(RECT), size )) return FALSE;
1000 break;
1001 case EM_SETRECT:
1002 case EM_SETRECTNP:
1003 minsize = sizeof(RECT);
1004 break;
1005 case EM_GETLINE:
1007 WORD len;
1008 if (size < sizeof(WORD)) return FALSE;
1009 len = *(WORD *)*buffer;
1010 if (!get_buffer_space( buffer, (len + 1) * sizeof(WCHAR), size )) return FALSE;
1011 *lparam = (LPARAM)*buffer + sizeof(WORD); /* don't erase WORD at start of buffer */
1012 return TRUE;
1014 case EM_SETTABSTOPS:
1015 case LB_SETTABSTOPS:
1016 if (!*wparam) return TRUE;
1017 minsize = *wparam * sizeof(UINT);
1018 break;
1019 case CB_ADDSTRING:
1020 case CB_INSERTSTRING:
1021 case CB_FINDSTRING:
1022 case CB_FINDSTRINGEXACT:
1023 case CB_SELECTSTRING:
1024 case LB_ADDSTRING:
1025 case LB_INSERTSTRING:
1026 case LB_FINDSTRING:
1027 case LB_FINDSTRINGEXACT:
1028 case LB_SELECTSTRING:
1029 if (!*buffer) return TRUE;
1030 if (!check_string( *buffer, size )) return FALSE;
1031 break;
1032 case CB_GETLBTEXT:
1034 size = sizeof(ULONG_PTR);
1035 if (combobox_has_strings( hwnd ))
1036 size = (SendMessageW( hwnd, CB_GETLBTEXTLEN, *wparam, 0 ) + 1) * sizeof(WCHAR);
1037 if (!get_buffer_space( buffer, size, prev_size )) return FALSE;
1038 break;
1040 case LB_GETTEXT:
1042 size = sizeof(ULONG_PTR);
1043 if (listbox_has_strings( hwnd ))
1044 size = (SendMessageW( hwnd, LB_GETTEXTLEN, *wparam, 0 ) + 1) * sizeof(WCHAR);
1045 if (!get_buffer_space( buffer, size, prev_size )) return FALSE;
1046 break;
1048 case LB_GETSELITEMS:
1049 if (!get_buffer_space( buffer, *wparam * sizeof(UINT), size )) return FALSE;
1050 break;
1051 case WM_NEXTMENU:
1053 MDINEXTMENU mnm;
1054 if (size < sizeof(ps->mnm)) return FALSE;
1055 mnm.hmenuIn = unpack_handle( ps->mnm.hmenuIn );
1056 mnm.hmenuNext = unpack_handle( ps->mnm.hmenuNext );
1057 mnm.hwndNext = unpack_handle( ps->mnm.hwndNext );
1058 memcpy( *buffer, &mnm, sizeof(mnm) );
1059 break;
1061 case WM_SIZING:
1062 case WM_MOVING:
1063 minsize = sizeof(RECT);
1064 if (!get_buffer_space( buffer, sizeof(RECT), size )) return FALSE;
1065 break;
1066 case WM_MDICREATE:
1068 MDICREATESTRUCTW mcs;
1069 WCHAR *str = (WCHAR *)(&ps->mcs + 1);
1070 if (size < sizeof(ps->mcs)) return FALSE;
1071 size -= sizeof(ps->mcs);
1073 mcs.szClass = unpack_ptr( ps->mcs.szClass );
1074 mcs.szTitle = unpack_ptr( ps->mcs.szTitle );
1075 mcs.hOwner = unpack_ptr( ps->mcs.hOwner );
1076 mcs.x = ps->mcs.x;
1077 mcs.y = ps->mcs.y;
1078 mcs.cx = ps->mcs.cx;
1079 mcs.cy = ps->mcs.cy;
1080 mcs.style = ps->mcs.style;
1081 mcs.lParam = (LPARAM)unpack_ptr( ps->mcs.lParam );
1082 if (ps->mcs.szClass >> 16)
1084 if (!check_string( str, size )) return FALSE;
1085 mcs.szClass = str;
1086 size -= (lstrlenW(str) + 1) * sizeof(WCHAR);
1087 str += lstrlenW(str) + 1;
1089 if (ps->mcs.szTitle >> 16)
1091 if (!check_string( str, size )) return FALSE;
1092 mcs.szTitle = str;
1094 memcpy( *buffer, &mcs, sizeof(mcs) );
1095 break;
1097 case WM_MDIGETACTIVE:
1098 if (!*lparam) return TRUE;
1099 if (!get_buffer_space( buffer, sizeof(BOOL), size )) return FALSE;
1100 break;
1101 case WM_DEVICECHANGE:
1102 if (!(*wparam & 0x8000)) return TRUE;
1103 minsize = sizeof(DEV_BROADCAST_HDR);
1104 break;
1105 case WM_NCPAINT:
1106 if (*wparam <= 1) return TRUE;
1107 FIXME( "WM_NCPAINT hdc unpacking not supported\n" );
1108 return FALSE;
1109 case WM_PAINT:
1110 if (!*wparam) return TRUE;
1111 /* fall through */
1113 /* these contain an HFONT */
1114 case WM_SETFONT:
1115 case WM_GETFONT:
1116 /* these contain an HDC */
1117 case WM_ERASEBKGND:
1118 case WM_ICONERASEBKGND:
1119 case WM_CTLCOLORMSGBOX:
1120 case WM_CTLCOLOREDIT:
1121 case WM_CTLCOLORLISTBOX:
1122 case WM_CTLCOLORBTN:
1123 case WM_CTLCOLORDLG:
1124 case WM_CTLCOLORSCROLLBAR:
1125 case WM_CTLCOLORSTATIC:
1126 case WM_PRINT:
1127 case WM_PRINTCLIENT:
1128 /* these contain an HGLOBAL */
1129 case WM_PAINTCLIPBOARD:
1130 case WM_SIZECLIPBOARD:
1131 /* these contain HICON */
1132 case WM_GETICON:
1133 case WM_SETICON:
1134 case WM_QUERYDRAGICON:
1135 case WM_QUERYPARKICON:
1136 /* these contain pointers */
1137 case WM_DROPOBJECT:
1138 case WM_QUERYDROPOBJECT:
1139 case WM_DRAGLOOP:
1140 case WM_DRAGSELECT:
1141 case WM_DRAGMOVE:
1142 FIXME( "msg %x (%s) not supported yet\n", message, SPY_GetMsgName(message, hwnd) );
1143 return FALSE;
1145 default:
1146 return TRUE; /* message doesn't need any unpacking */
1149 /* default exit for most messages: check minsize and store buffer in lparam */
1150 if (size < minsize) return FALSE;
1151 *lparam = (LPARAM)*buffer;
1152 return TRUE;
1155 BOOL WINAPI User32CallWindowProc( struct win_proc_params *params, ULONG size )
1157 LRESULT result;
1159 if (params->needs_unpack)
1161 char stack_buffer[128];
1162 size_t msg_size = size - sizeof(*params);
1163 void *buffer;
1165 if (size > sizeof(*params))
1167 size -= sizeof(*params);
1168 buffer = params + 1;
1170 else
1172 size = sizeof(stack_buffer);
1173 buffer = stack_buffer;
1175 if (!unpack_message( params->hwnd, params->msg, &params->wparam,
1176 &params->lparam, &buffer, size, params->ansi ))
1177 return 0;
1179 result = dispatch_win_proc_params( params );
1181 switch (params->msg)
1183 case WM_NCCREATE:
1184 case WM_CREATE:
1185 case WM_NCCALCSIZE:
1187 LRESULT *result_ptr = (LRESULT *)buffer - 1;
1188 *result_ptr = result;
1189 return NtCallbackReturn( result_ptr, sizeof(*result_ptr) + msg_size, TRUE );
1193 NtUserMessageCall( params->hwnd, params->msg, params->wparam, params->lparam,
1194 (void *)result, NtUserWinProcResult, FALSE );
1195 if (buffer != stack_buffer && buffer != params + 1)
1196 HeapFree( GetProcessHeap(), 0, buffer );
1198 else
1200 result = dispatch_win_proc_params( params );
1202 return NtCallbackReturn( &result, sizeof(result), TRUE );
1205 BOOL WINAPI User32CallSendAsyncCallback( const struct send_async_params *params, ULONG size )
1207 params->callback( params->hwnd, params->msg, params->data, params->result );
1208 return TRUE;
1211 /**********************************************************************
1212 * CallWindowProcA (USER32.@)
1214 * The CallWindowProc() function invokes the windows procedure _func_,
1215 * with _hwnd_ as the target window, the message specified by _msg_, and
1216 * the message parameters _wParam_ and _lParam_.
1218 * Some kinds of argument conversion may be done, I'm not sure what.
1220 * CallWindowProc() may be used for windows subclassing. Use
1221 * SetWindowLong() to set a new windows procedure for windows of the
1222 * subclass, and handle subclassed messages in the new windows
1223 * procedure. The new windows procedure may then use CallWindowProc()
1224 * with _func_ set to the parent class's windows procedure to dispatch
1225 * the message to the superclass.
1227 * RETURNS
1229 * The return value is message dependent.
1231 * CONFORMANCE
1233 * ECMA-234, Win32
1235 LRESULT WINAPI CallWindowProcA( WNDPROC func, HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam )
1237 struct win_proc_params params;
1239 params.func = func;
1240 if (!NtUserMessageCall( hwnd, msg, wParam, lParam, &params, NtUserCallWindowProc, TRUE ))
1241 return 0;
1242 return dispatch_win_proc_params( &params );
1246 /**********************************************************************
1247 * CallWindowProcW (USER32.@)
1249 * See CallWindowProcA.
1251 LRESULT WINAPI CallWindowProcW( WNDPROC func, HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam )
1253 struct win_proc_params params;
1255 params.func = func;
1256 if (!NtUserMessageCall( hwnd, msg, wParam, lParam, &params, NtUserCallWindowProc, FALSE ))
1257 return 0;
1258 return dispatch_win_proc_params( &params );
1262 /**********************************************************************
1263 * WINPROC_CallDlgProcA
1265 INT_PTR WINPROC_CallDlgProcA( HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam )
1267 DLGPROC func, proc;
1268 LRESULT result;
1270 #ifdef _WIN64
1271 proc = (DLGPROC)NtUserGetWindowLongPtrA( hwnd, DWLP_DLGPROC );
1272 #else
1273 proc = (DLGPROC)NtUserGetWindowLongA( hwnd, DWLP_DLGPROC );
1274 #endif
1275 if (!proc) return 0;
1276 if (!(func = NtUserGetDialogProc( proc, TRUE )) &&
1277 !(func = NtUserGetDialogProc( proc, FALSE ))) return 0;
1279 if (func == WINPROC_PROC16)
1281 INT_PTR ret;
1282 ret = wow_handlers.call_dialog_proc( hwnd, msg, wParam, lParam, &result, proc );
1283 SetWindowLongPtrW( hwnd, DWLP_MSGRESULT, result );
1284 return ret;
1287 return call_dialog_proc( hwnd, msg, wParam, lParam, &result, func );
1291 /**********************************************************************
1292 * WINPROC_CallDlgProcW
1294 INT_PTR WINPROC_CallDlgProcW( HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam )
1296 DLGPROC func, proc;
1297 LRESULT result;
1299 #ifdef _WIN64
1300 proc = (DLGPROC)NtUserGetWindowLongPtrW( hwnd, DWLP_DLGPROC );
1301 #else
1302 proc = (DLGPROC)NtUserGetWindowLongW( hwnd, DWLP_DLGPROC );
1303 #endif
1304 if (!proc) return 0;
1305 if (!(func = NtUserGetDialogProc( proc, FALSE )) &&
1306 !(func = NtUserGetDialogProc( proc, TRUE ))) return 0;
1308 if (func == WINPROC_PROC16)
1310 INT_PTR ret;
1311 ret = WINPROC_CallProcWtoA( wow_handlers.call_dialog_proc,
1312 hwnd, msg, wParam, lParam, &result, proc );
1313 SetWindowLongPtrW( hwnd, DWLP_MSGRESULT, result );
1314 return ret;
1317 return call_dialog_proc( hwnd, msg, wParam, lParam, &result, func );
1321 /***********************************************************************
1322 * Window procedures for builtin classes
1325 static LRESULT WINAPI ButtonWndProcA( HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam )
1327 return wow_handlers.button_proc( hwnd, msg, wParam, lParam, FALSE );
1330 static LRESULT WINAPI ButtonWndProcW( HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam )
1332 return wow_handlers.button_proc( hwnd, msg, wParam, lParam, TRUE );
1335 static LRESULT WINAPI ComboWndProcA( HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam )
1337 return wow_handlers.combo_proc( hwnd, message, wParam, lParam, FALSE );
1340 static LRESULT WINAPI ComboWndProcW( HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam )
1342 return wow_handlers.combo_proc( hwnd, message, wParam, lParam, TRUE );
1345 LRESULT WINAPI EditWndProcA( HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam )
1347 return wow_handlers.edit_proc( hwnd, msg, wParam, lParam, FALSE );
1350 static LRESULT WINAPI EditWndProcW( HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam )
1352 return wow_handlers.edit_proc( hwnd, msg, wParam, lParam, TRUE );
1355 static LRESULT WINAPI ListBoxWndProcA( HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam )
1357 return wow_handlers.listbox_proc( hwnd, msg, wParam, lParam, FALSE );
1360 static LRESULT WINAPI ListBoxWndProcW( HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam )
1362 return wow_handlers.listbox_proc( hwnd, msg, wParam, lParam, TRUE );
1365 static LRESULT WINAPI MDIClientWndProcA( HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam )
1367 return wow_handlers.mdiclient_proc( hwnd, msg, wParam, lParam, FALSE );
1370 static LRESULT WINAPI MDIClientWndProcW( HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam )
1372 return wow_handlers.mdiclient_proc( hwnd, msg, wParam, lParam, TRUE );
1375 static LRESULT WINAPI ScrollBarWndProcA( HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam )
1377 return wow_handlers.scrollbar_proc( hwnd, msg, wParam, lParam, FALSE );
1380 static LRESULT WINAPI ScrollBarWndProcW( HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam )
1382 return wow_handlers.scrollbar_proc( hwnd, msg, wParam, lParam, TRUE );
1385 static LRESULT WINAPI StaticWndProcA( HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam )
1387 return wow_handlers.static_proc( hwnd, msg, wParam, lParam, FALSE );
1390 static LRESULT WINAPI StaticWndProcW( HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam )
1392 return wow_handlers.static_proc( hwnd, msg, wParam, lParam, TRUE );
1395 /**********************************************************************
1396 * UserRegisterWowHandlers (USER32.@)
1398 * NOTE: no attempt has been made to be compatible here,
1399 * the Windows function is most likely completely different.
1401 void WINAPI UserRegisterWowHandlers( const struct wow_handlers16 *new, struct wow_handlers32 *orig )
1403 orig->button_proc = ButtonWndProc_common;
1404 orig->combo_proc = ComboWndProc_common;
1405 orig->edit_proc = EditWndProc_common;
1406 orig->listbox_proc = ListBoxWndProc_common;
1407 orig->mdiclient_proc = MDIClientWndProc_common;
1408 orig->scrollbar_proc = ScrollBarWndProc_common;
1409 orig->static_proc = StaticWndProc_common;
1410 orig->create_window = WIN_CreateWindowEx;
1411 orig->get_win_handle = WIN_GetFullHandle;
1412 orig->alloc_winproc = WINPROC_AllocProc;
1413 orig->get_dialog_info = DIALOG_get_info;
1414 orig->dialog_box_loop = DIALOG_DoDialogBox;
1416 wow_handlers = *new;
1419 struct wow_handlers16 wow_handlers =
1421 ButtonWndProc_common,
1422 ComboWndProc_common,
1423 EditWndProc_common,
1424 ListBoxWndProc_common,
1425 MDIClientWndProc_common,
1426 ScrollBarWndProc_common,
1427 StaticWndProc_common,
1428 WIN_CreateWindowEx,
1429 NULL, /* call_window_proc */
1430 NULL, /* call_dialog_proc */
1433 static const struct user_client_procs client_procsA =
1435 .pButtonWndProc = ButtonWndProcA,
1436 .pComboWndProc = ComboWndProcA,
1437 .pDefWindowProc = DefWindowProcA,
1438 .pDefDlgProc = DefDlgProcA,
1439 .pEditWndProc = EditWndProcA,
1440 .pListBoxWndProc = ListBoxWndProcA,
1441 .pMDIClientWndProc = MDIClientWndProcA,
1442 .pScrollBarWndProc = ScrollBarWndProcA,
1443 .pStaticWndProc = StaticWndProcA,
1444 .pImeWndProc = ImeWndProcA,
1447 static const struct user_client_procs client_procsW =
1449 .pButtonWndProc = ButtonWndProcW,
1450 .pComboWndProc = ComboWndProcW,
1451 .pDefWindowProc = DefWindowProcW,
1452 .pDefDlgProc = DefDlgProcW,
1453 .pEditWndProc = EditWndProcW,
1454 .pListBoxWndProc = ListBoxWndProcW,
1455 .pMDIClientWndProc = MDIClientWndProcW,
1456 .pScrollBarWndProc = ScrollBarWndProcW,
1457 .pStaticWndProc = StaticWndProcW,
1458 .pImeWndProc = ImeWndProcW,
1459 .pDesktopWndProc = DesktopWndProc,
1460 .pIconTitleWndProc = IconTitleWndProc,
1461 .pPopupMenuWndProc = PopupMenuWndProc,
1462 .pMessageWndProc = MessageWndProc,
1465 void winproc_init(void)
1467 NtUserInitializeClientPfnArrays( &client_procsA, &client_procsW, NULL, user32_module );