gdi32/tests: Mark tests failing randomly on Windows as flaky.
[wine.git] / dlls / user32 / winproc.c
blob6cd41b514351ffec50a5e18718c8462da35189dc
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 void dispatch_win_proc_params( struct win_proc_params *params )
717 DPI_AWARENESS_CONTEXT context = SetThreadDpiAwarenessContext( params->dpi_awareness );
719 if (!params->ansi)
721 if (params->procW == WINPROC_PROC16)
722 WINPROC_CallProcWtoA( wow_handlers.call_window_proc, params->hwnd, params->msg, params->wparam,
723 params->lparam, params->result, params->func );
724 else if (!params->ansi_dst)
725 call_window_proc( params->hwnd, params->msg, params->wparam, params->lparam,
726 params->result, params->procW );
727 else
728 WINPROC_CallProcWtoA( call_window_proc, params->hwnd, params->msg, params->wparam,
729 params->lparam, params->result, params->procA );
731 else
733 if (params->procA == WINPROC_PROC16)
734 wow_handlers.call_window_proc( params->hwnd, params->msg, params->wparam, params->lparam,
735 params->result, params->func );
736 else if (!params->ansi_dst)
737 WINPROC_CallProcAtoW( call_window_proc, params->hwnd, params->msg, params->wparam,
738 params->lparam, params->result, params->procW, params->mapping );
739 else
740 call_window_proc( params->hwnd, params->msg, params->wparam, params->lparam,
741 params->result, params->procA );
744 SetThreadDpiAwarenessContext( context );
747 /* make sure that there is space for 'size' bytes in buffer, growing it if needed */
748 static inline void *get_buffer_space( void **buffer, size_t size, size_t prev_size )
750 if (prev_size < size)
751 *buffer = HeapAlloc( GetProcessHeap(), 0, size );
752 return *buffer;
755 /* check whether a combobox expects strings or ids in CB_ADDSTRING/CB_INSERTSTRING */
756 static inline BOOL combobox_has_strings( HWND hwnd )
758 DWORD style = GetWindowLongA( hwnd, GWL_STYLE );
759 return (!(style & (CBS_OWNERDRAWFIXED | CBS_OWNERDRAWVARIABLE)) || (style & CBS_HASSTRINGS));
762 /* check whether a listbox expects strings or ids in LB_ADDSTRING/LB_INSERTSTRING */
763 static inline BOOL listbox_has_strings( HWND hwnd )
765 DWORD style = GetWindowLongA( hwnd, GWL_STYLE );
766 return (!(style & (LBS_OWNERDRAWFIXED | LBS_OWNERDRAWVARIABLE)) || (style & LBS_HASSTRINGS));
769 /* unpack a potentially 64-bit pointer, returning 0 when truncated */
770 static inline void *unpack_ptr( ULONGLONG ptr64 )
772 if ((ULONG_PTR)ptr64 != ptr64) return 0;
773 return (void *)(ULONG_PTR)ptr64;
776 /* convert a server handle to a generic handle */
777 static inline HANDLE unpack_handle( UINT handle )
779 return (HANDLE)(INT_PTR)(int)handle;
782 /* make sure that the buffer contains a valid null-terminated Unicode string */
783 static inline BOOL check_string( LPCWSTR str, size_t size )
785 for (size /= sizeof(WCHAR); size; size--, str++)
786 if (!*str) return TRUE;
787 return FALSE;
790 /***********************************************************************
791 * unpack_message
793 * Unpack a message received from another process.
795 static BOOL unpack_message( HWND hwnd, UINT message, WPARAM *wparam, LPARAM *lparam,
796 void **buffer, size_t size )
798 size_t minsize = 0, prev_size = size;
799 union packed_structs *ps = *buffer;
801 switch(message)
803 case WM_NCCREATE:
804 case WM_CREATE:
806 CREATESTRUCTW cs;
807 WCHAR *str = (WCHAR *)(&ps->cs + 1);
808 if (size < sizeof(ps->cs)) return FALSE;
809 size -= sizeof(ps->cs);
810 cs.lpCreateParams = unpack_ptr( ps->cs.lpCreateParams );
811 cs.hInstance = unpack_ptr( ps->cs.hInstance );
812 cs.hMenu = unpack_handle( ps->cs.hMenu );
813 cs.hwndParent = unpack_handle( ps->cs.hwndParent );
814 cs.cy = ps->cs.cy;
815 cs.cx = ps->cs.cx;
816 cs.y = ps->cs.y;
817 cs.x = ps->cs.x;
818 cs.style = ps->cs.style;
819 cs.dwExStyle = ps->cs.dwExStyle;
820 cs.lpszName = unpack_ptr( ps->cs.lpszName );
821 cs.lpszClass = unpack_ptr( ps->cs.lpszClass );
822 if (ps->cs.lpszName >> 16)
824 if (!check_string( str, size )) return FALSE;
825 cs.lpszName = str;
826 size -= (lstrlenW(str) + 1) * sizeof(WCHAR);
827 str += lstrlenW(str) + 1;
829 if (ps->cs.lpszClass >> 16)
831 if (!check_string( str, size )) return FALSE;
832 cs.lpszClass = str;
834 memcpy( &ps->cs, &cs, sizeof(cs) );
835 break;
837 case WM_GETTEXT:
838 case WM_ASKCBFORMATNAME:
839 if (!get_buffer_space( buffer, (*wparam * sizeof(WCHAR)), size )) return FALSE;
840 break;
841 case WM_WININICHANGE:
842 if (!*lparam) return TRUE;
843 /* fall through */
844 case WM_SETTEXT:
845 case WM_DEVMODECHANGE:
846 case CB_DIR:
847 case LB_DIR:
848 case LB_ADDFILE:
849 case EM_REPLACESEL:
850 if (!check_string( *buffer, size )) return FALSE;
851 break;
852 case WM_GETMINMAXINFO:
853 minsize = sizeof(MINMAXINFO);
854 break;
855 case WM_DRAWITEM:
857 DRAWITEMSTRUCT dis;
858 if (size < sizeof(ps->dis)) return FALSE;
859 dis.CtlType = ps->dis.CtlType;
860 dis.CtlID = ps->dis.CtlID;
861 dis.itemID = ps->dis.itemID;
862 dis.itemAction = ps->dis.itemAction;
863 dis.itemState = ps->dis.itemState;
864 dis.hwndItem = unpack_handle( ps->dis.hwndItem );
865 dis.hDC = unpack_handle( ps->dis.hDC );
866 dis.rcItem = ps->dis.rcItem;
867 dis.itemData = (ULONG_PTR)unpack_ptr( ps->dis.itemData );
868 memcpy( &ps->dis, &dis, sizeof(dis) );
869 break;
871 case WM_MEASUREITEM:
873 MEASUREITEMSTRUCT mis;
874 if (size < sizeof(ps->mis)) return FALSE;
875 mis.CtlType = ps->mis.CtlType;
876 mis.CtlID = ps->mis.CtlID;
877 mis.itemID = ps->mis.itemID;
878 mis.itemWidth = ps->mis.itemWidth;
879 mis.itemHeight = ps->mis.itemHeight;
880 mis.itemData = (ULONG_PTR)unpack_ptr( ps->mis.itemData );
881 memcpy( &ps->mis, &mis, sizeof(mis) );
882 break;
884 case WM_DELETEITEM:
886 DELETEITEMSTRUCT dls;
887 if (size < sizeof(ps->dls)) return FALSE;
888 dls.CtlType = ps->dls.CtlType;
889 dls.CtlID = ps->dls.CtlID;
890 dls.itemID = ps->dls.itemID;
891 dls.hwndItem = unpack_handle( ps->dls.hwndItem );
892 dls.itemData = (ULONG_PTR)unpack_ptr( ps->dls.itemData );
893 memcpy( &ps->dls, &dls, sizeof(dls) );
894 break;
896 case WM_COMPAREITEM:
898 COMPAREITEMSTRUCT cis;
899 if (size < sizeof(ps->cis)) return FALSE;
900 cis.CtlType = ps->cis.CtlType;
901 cis.CtlID = ps->cis.CtlID;
902 cis.hwndItem = unpack_handle( ps->cis.hwndItem );
903 cis.itemID1 = ps->cis.itemID1;
904 cis.itemData1 = (ULONG_PTR)unpack_ptr( ps->cis.itemData1 );
905 cis.itemID2 = ps->cis.itemID2;
906 cis.itemData2 = (ULONG_PTR)unpack_ptr( ps->cis.itemData2 );
907 cis.dwLocaleId = ps->cis.dwLocaleId;
908 memcpy( &ps->cis, &cis, sizeof(cis) );
909 break;
911 case WM_WINDOWPOSCHANGING:
912 case WM_WINDOWPOSCHANGED:
914 WINDOWPOS wp;
915 if (size < sizeof(ps->wp)) return FALSE;
916 wp.hwnd = unpack_handle( ps->wp.hwnd );
917 wp.hwndInsertAfter = unpack_handle( ps->wp.hwndInsertAfter );
918 wp.x = ps->wp.x;
919 wp.y = ps->wp.y;
920 wp.cx = ps->wp.cx;
921 wp.cy = ps->wp.cy;
922 wp.flags = ps->wp.flags;
923 memcpy( &ps->wp, &wp, sizeof(wp) );
924 break;
926 case WM_COPYDATA:
928 COPYDATASTRUCT cds;
929 if (size < sizeof(ps->cds)) return FALSE;
930 cds.dwData = (ULONG_PTR)unpack_ptr( ps->cds.dwData );
931 if (ps->cds.lpData)
933 cds.cbData = ps->cds.cbData;
934 cds.lpData = &ps->cds + 1;
935 minsize = sizeof(ps->cds) + cds.cbData;
937 else
939 cds.cbData = 0;
940 cds.lpData = 0;
942 memcpy( &ps->cds, &cds, sizeof(cds) );
943 break;
945 case WM_NOTIFY:
946 /* WM_NOTIFY cannot be sent across processes (MSDN) */
947 return FALSE;
948 case WM_HELP:
950 HELPINFO hi;
951 if (size < sizeof(ps->hi)) return FALSE;
952 hi.cbSize = sizeof(hi);
953 hi.iContextType = ps->hi.iContextType;
954 hi.iCtrlId = ps->hi.iCtrlId;
955 hi.hItemHandle = unpack_handle( ps->hi.hItemHandle );
956 hi.dwContextId = (ULONG_PTR)unpack_ptr( ps->hi.dwContextId );
957 hi.MousePos = ps->hi.MousePos;
958 memcpy( &ps->hi, &hi, sizeof(hi) );
959 break;
961 case WM_STYLECHANGING:
962 case WM_STYLECHANGED:
963 minsize = sizeof(STYLESTRUCT);
964 break;
965 case WM_NCCALCSIZE:
966 if (!*wparam) minsize = sizeof(RECT);
967 else
969 NCCALCSIZE_PARAMS ncp;
970 WINDOWPOS wp;
971 if (size < sizeof(ps->ncp)) return FALSE;
972 ncp.rgrc[0] = ps->ncp.rgrc[0];
973 ncp.rgrc[1] = ps->ncp.rgrc[1];
974 ncp.rgrc[2] = ps->ncp.rgrc[2];
975 wp.hwnd = unpack_handle( ps->ncp.hwnd );
976 wp.hwndInsertAfter = unpack_handle( ps->ncp.hwndInsertAfter );
977 wp.x = ps->ncp.x;
978 wp.y = ps->ncp.y;
979 wp.cx = ps->ncp.cx;
980 wp.cy = ps->ncp.cy;
981 wp.flags = ps->ncp.flags;
982 ncp.lppos = (WINDOWPOS *)((NCCALCSIZE_PARAMS *)&ps->ncp + 1);
983 memcpy( &ps->ncp, &ncp, sizeof(ncp) );
984 *ncp.lppos = wp;
986 break;
987 case WM_GETDLGCODE:
988 if (*lparam)
990 MSG msg;
991 if (size < sizeof(ps->msg)) return FALSE;
992 msg.hwnd = unpack_handle( ps->msg.hwnd );
993 msg.message = ps->msg.message;
994 msg.wParam = (ULONG_PTR)unpack_ptr( ps->msg.wParam );
995 msg.lParam = (ULONG_PTR)unpack_ptr( ps->msg.lParam );
996 msg.time = ps->msg.time;
997 msg.pt = ps->msg.pt;
998 memcpy( &ps->msg, &msg, sizeof(msg) );
999 break;
1001 return TRUE;
1002 case SBM_SETSCROLLINFO:
1003 minsize = sizeof(SCROLLINFO);
1004 break;
1005 case SBM_GETSCROLLINFO:
1006 if (!get_buffer_space( buffer, sizeof(SCROLLINFO), size )) return FALSE;
1007 break;
1008 case SBM_GETSCROLLBARINFO:
1009 if (!get_buffer_space( buffer, sizeof(SCROLLBARINFO), size )) return FALSE;
1010 break;
1011 case EM_GETSEL:
1012 case SBM_GETRANGE:
1013 case CB_GETEDITSEL:
1014 if (*wparam || *lparam)
1016 if (!get_buffer_space( buffer, 2*sizeof(DWORD), size )) return FALSE;
1017 if (*wparam) *wparam = (WPARAM)*buffer;
1018 if (*lparam) *lparam = (LPARAM)((DWORD *)*buffer + 1);
1020 return TRUE;
1021 case EM_GETRECT:
1022 case LB_GETITEMRECT:
1023 case CB_GETDROPPEDCONTROLRECT:
1024 if (!get_buffer_space( buffer, sizeof(RECT), size )) return FALSE;
1025 break;
1026 case EM_SETRECT:
1027 case EM_SETRECTNP:
1028 minsize = sizeof(RECT);
1029 break;
1030 case EM_GETLINE:
1032 WORD len;
1033 if (size < sizeof(WORD)) return FALSE;
1034 len = *(WORD *)*buffer;
1035 if (!get_buffer_space( buffer, (len + 1) * sizeof(WCHAR), size )) return FALSE;
1036 *lparam = (LPARAM)*buffer + sizeof(WORD); /* don't erase WORD at start of buffer */
1037 return TRUE;
1039 case EM_SETTABSTOPS:
1040 case LB_SETTABSTOPS:
1041 if (!*wparam) return TRUE;
1042 minsize = *wparam * sizeof(UINT);
1043 break;
1044 case CB_ADDSTRING:
1045 case CB_INSERTSTRING:
1046 case CB_FINDSTRING:
1047 case CB_FINDSTRINGEXACT:
1048 case CB_SELECTSTRING:
1049 case LB_ADDSTRING:
1050 case LB_INSERTSTRING:
1051 case LB_FINDSTRING:
1052 case LB_FINDSTRINGEXACT:
1053 case LB_SELECTSTRING:
1054 if (!*buffer) return TRUE;
1055 if (!check_string( *buffer, size )) return FALSE;
1056 break;
1057 case CB_GETLBTEXT:
1059 size = sizeof(ULONG_PTR);
1060 if (combobox_has_strings( hwnd ))
1061 size = (SendMessageW( hwnd, CB_GETLBTEXTLEN, *wparam, 0 ) + 1) * sizeof(WCHAR);
1062 if (!get_buffer_space( buffer, size, prev_size )) return FALSE;
1063 break;
1065 case LB_GETTEXT:
1067 size = sizeof(ULONG_PTR);
1068 if (listbox_has_strings( hwnd ))
1069 size = (SendMessageW( hwnd, LB_GETTEXTLEN, *wparam, 0 ) + 1) * sizeof(WCHAR);
1070 if (!get_buffer_space( buffer, size, prev_size )) return FALSE;
1071 break;
1073 case LB_GETSELITEMS:
1074 if (!get_buffer_space( buffer, *wparam * sizeof(UINT), size )) return FALSE;
1075 break;
1076 case WM_NEXTMENU:
1078 MDINEXTMENU mnm;
1079 if (size < sizeof(ps->mnm)) return FALSE;
1080 mnm.hmenuIn = unpack_handle( ps->mnm.hmenuIn );
1081 mnm.hmenuNext = unpack_handle( ps->mnm.hmenuNext );
1082 mnm.hwndNext = unpack_handle( ps->mnm.hwndNext );
1083 memcpy( &ps->mnm, &mnm, sizeof(mnm) );
1084 break;
1086 case WM_SIZING:
1087 case WM_MOVING:
1088 minsize = sizeof(RECT);
1089 if (!get_buffer_space( buffer, sizeof(RECT), size )) return FALSE;
1090 break;
1091 case WM_MDICREATE:
1093 MDICREATESTRUCTW mcs;
1094 WCHAR *str = (WCHAR *)(&ps->mcs + 1);
1095 if (size < sizeof(ps->mcs)) return FALSE;
1096 size -= sizeof(ps->mcs);
1098 mcs.szClass = unpack_ptr( ps->mcs.szClass );
1099 mcs.szTitle = unpack_ptr( ps->mcs.szTitle );
1100 mcs.hOwner = unpack_ptr( ps->mcs.hOwner );
1101 mcs.x = ps->mcs.x;
1102 mcs.y = ps->mcs.y;
1103 mcs.cx = ps->mcs.cx;
1104 mcs.cy = ps->mcs.cy;
1105 mcs.style = ps->mcs.style;
1106 mcs.lParam = (LPARAM)unpack_ptr( ps->mcs.lParam );
1107 if (ps->mcs.szClass >> 16)
1109 if (!check_string( str, size )) return FALSE;
1110 mcs.szClass = str;
1111 size -= (lstrlenW(str) + 1) * sizeof(WCHAR);
1112 str += lstrlenW(str) + 1;
1114 if (ps->mcs.szTitle >> 16)
1116 if (!check_string( str, size )) return FALSE;
1117 mcs.szTitle = str;
1119 memcpy( &ps->mcs, &mcs, sizeof(mcs) );
1120 break;
1122 case WM_MDIGETACTIVE:
1123 if (!*lparam) return TRUE;
1124 if (!get_buffer_space( buffer, sizeof(BOOL), size )) return FALSE;
1125 break;
1126 case WM_DEVICECHANGE:
1127 if (!(*wparam & 0x8000)) return TRUE;
1128 minsize = sizeof(DEV_BROADCAST_HDR);
1129 break;
1130 case WM_NCPAINT:
1131 if (*wparam <= 1) return TRUE;
1132 FIXME( "WM_NCPAINT hdc unpacking not supported\n" );
1133 return FALSE;
1134 case WM_PAINT:
1135 if (!*wparam) return TRUE;
1136 /* fall through */
1138 /* these contain an HFONT */
1139 case WM_SETFONT:
1140 case WM_GETFONT:
1141 /* these contain an HDC */
1142 case WM_ERASEBKGND:
1143 case WM_ICONERASEBKGND:
1144 case WM_CTLCOLORMSGBOX:
1145 case WM_CTLCOLOREDIT:
1146 case WM_CTLCOLORLISTBOX:
1147 case WM_CTLCOLORBTN:
1148 case WM_CTLCOLORDLG:
1149 case WM_CTLCOLORSCROLLBAR:
1150 case WM_CTLCOLORSTATIC:
1151 case WM_PRINT:
1152 case WM_PRINTCLIENT:
1153 /* these contain an HGLOBAL */
1154 case WM_PAINTCLIPBOARD:
1155 case WM_SIZECLIPBOARD:
1156 /* these contain HICON */
1157 case WM_GETICON:
1158 case WM_SETICON:
1159 case WM_QUERYDRAGICON:
1160 case WM_QUERYPARKICON:
1161 /* these contain pointers */
1162 case WM_DROPOBJECT:
1163 case WM_QUERYDROPOBJECT:
1164 case WM_DRAGLOOP:
1165 case WM_DRAGSELECT:
1166 case WM_DRAGMOVE:
1167 FIXME( "msg %x (%s) not supported yet\n", message, SPY_GetMsgName(message, hwnd) );
1168 return FALSE;
1170 default:
1171 return TRUE; /* message doesn't need any unpacking */
1174 /* default exit for most messages: check minsize and store buffer in lparam */
1175 if (size < minsize) return FALSE;
1176 *lparam = (LPARAM)*buffer;
1177 return TRUE;
1180 BOOL WINAPI User32CallWindowProc( struct win_proc_params *params, ULONG size )
1182 LRESULT result, *result_ptr = params->result;
1183 params->result = &result;
1185 if (params->needs_unpack)
1187 char stack_buffer[128];
1188 void *buffer;
1190 if (size > sizeof(*params))
1192 size -= sizeof(*params);
1193 buffer = params + 1;
1195 else
1197 size = sizeof(stack_buffer);
1198 buffer = stack_buffer;
1200 if (!unpack_message( params->hwnd, params->msg, &params->wparam,
1201 &params->lparam, &buffer, size ))
1202 return 0;
1204 dispatch_win_proc_params( params );
1206 NtUserMessageCall( params->hwnd, params->msg, params->wparam, params->lparam,
1207 (void *)result, NtUserWinProcResult, FALSE );
1208 if (buffer != stack_buffer && buffer != params + 1)
1209 HeapFree( GetProcessHeap(), 0, buffer );
1211 else
1213 dispatch_win_proc_params( params );
1214 if (result_ptr)
1216 *result_ptr = result;
1217 return TRUE;
1219 NtCallbackReturn( &result, sizeof(result), TRUE );
1221 return TRUE;
1224 BOOL WINAPI User32CallSendAsyncCallback( const struct send_async_params *params, ULONG size )
1226 params->callback( params->hwnd, params->msg, params->data, params->result );
1227 return TRUE;
1230 /**********************************************************************
1231 * CallWindowProcA (USER32.@)
1233 * The CallWindowProc() function invokes the windows procedure _func_,
1234 * with _hwnd_ as the target window, the message specified by _msg_, and
1235 * the message parameters _wParam_ and _lParam_.
1237 * Some kinds of argument conversion may be done, I'm not sure what.
1239 * CallWindowProc() may be used for windows subclassing. Use
1240 * SetWindowLong() to set a new windows procedure for windows of the
1241 * subclass, and handle subclassed messages in the new windows
1242 * procedure. The new windows procedure may then use CallWindowProc()
1243 * with _func_ set to the parent class's windows procedure to dispatch
1244 * the message to the superclass.
1246 * RETURNS
1248 * The return value is message dependent.
1250 * CONFORMANCE
1252 * ECMA-234, Win32
1254 LRESULT WINAPI CallWindowProcA( WNDPROC func, HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam )
1256 struct win_proc_params params;
1257 LRESULT result;
1259 params.func = func;
1260 params.result = &result;
1261 if (!NtUserMessageCall( hwnd, msg, wParam, lParam, &params, NtUserCallWindowProc, TRUE ))
1262 return 0;
1263 dispatch_win_proc_params( &params );
1264 return result;
1268 /**********************************************************************
1269 * CallWindowProcW (USER32.@)
1271 * See CallWindowProcA.
1273 LRESULT WINAPI CallWindowProcW( WNDPROC func, HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam )
1275 struct win_proc_params params;
1276 LRESULT result;
1278 params.func = func;
1279 params.result = &result;
1280 if (!NtUserMessageCall( hwnd, msg, wParam, lParam, &params, NtUserCallWindowProc, FALSE ))
1281 return 0;
1282 dispatch_win_proc_params( &params );
1283 return result;
1287 /**********************************************************************
1288 * WINPROC_CallDlgProcA
1290 INT_PTR WINPROC_CallDlgProcA( HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam )
1292 DLGPROC func, proc;
1293 LRESULT result;
1295 #ifdef _WIN64
1296 proc = (DLGPROC)NtUserGetWindowLongPtrA( hwnd, DWLP_DLGPROC );
1297 #else
1298 proc = (DLGPROC)NtUserGetWindowLongA( hwnd, DWLP_DLGPROC );
1299 #endif
1300 if (!proc) return 0;
1301 if (!(func = NtUserGetDialogProc( proc, TRUE )) &&
1302 !(func = NtUserGetDialogProc( proc, FALSE ))) return 0;
1304 if (func == WINPROC_PROC16)
1306 INT_PTR ret;
1307 ret = wow_handlers.call_dialog_proc( hwnd, msg, wParam, lParam, &result, proc );
1308 SetWindowLongPtrW( hwnd, DWLP_MSGRESULT, result );
1309 return ret;
1312 return call_dialog_proc( hwnd, msg, wParam, lParam, &result, func );
1316 /**********************************************************************
1317 * WINPROC_CallDlgProcW
1319 INT_PTR WINPROC_CallDlgProcW( HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam )
1321 DLGPROC func, proc;
1322 LRESULT result;
1324 #ifdef _WIN64
1325 proc = (DLGPROC)NtUserGetWindowLongPtrW( hwnd, DWLP_DLGPROC );
1326 #else
1327 proc = (DLGPROC)NtUserGetWindowLongW( hwnd, DWLP_DLGPROC );
1328 #endif
1329 if (!proc) return 0;
1330 if (!(func = NtUserGetDialogProc( proc, FALSE )) &&
1331 !(func = NtUserGetDialogProc( proc, TRUE ))) return 0;
1333 if (func == WINPROC_PROC16)
1335 INT_PTR ret;
1336 ret = WINPROC_CallProcWtoA( wow_handlers.call_dialog_proc,
1337 hwnd, msg, wParam, lParam, &result, proc );
1338 SetWindowLongPtrW( hwnd, DWLP_MSGRESULT, result );
1339 return ret;
1342 return call_dialog_proc( hwnd, msg, wParam, lParam, &result, func );
1346 /***********************************************************************
1347 * Window procedures for builtin classes
1350 static LRESULT WINAPI ButtonWndProcA( HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam )
1352 return wow_handlers.button_proc( hwnd, msg, wParam, lParam, FALSE );
1355 static LRESULT WINAPI ButtonWndProcW( HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam )
1357 return wow_handlers.button_proc( hwnd, msg, wParam, lParam, TRUE );
1360 static LRESULT WINAPI ComboWndProcA( HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam )
1362 return wow_handlers.combo_proc( hwnd, message, wParam, lParam, FALSE );
1365 static LRESULT WINAPI ComboWndProcW( HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam )
1367 return wow_handlers.combo_proc( hwnd, message, wParam, lParam, TRUE );
1370 LRESULT WINAPI EditWndProcA( HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam )
1372 return wow_handlers.edit_proc( hwnd, msg, wParam, lParam, FALSE );
1375 static LRESULT WINAPI EditWndProcW( HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam )
1377 return wow_handlers.edit_proc( hwnd, msg, wParam, lParam, TRUE );
1380 static LRESULT WINAPI ListBoxWndProcA( HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam )
1382 return wow_handlers.listbox_proc( hwnd, msg, wParam, lParam, FALSE );
1385 static LRESULT WINAPI ListBoxWndProcW( HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam )
1387 return wow_handlers.listbox_proc( hwnd, msg, wParam, lParam, TRUE );
1390 static LRESULT WINAPI MDIClientWndProcA( HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam )
1392 return wow_handlers.mdiclient_proc( hwnd, msg, wParam, lParam, FALSE );
1395 static LRESULT WINAPI MDIClientWndProcW( HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam )
1397 return wow_handlers.mdiclient_proc( hwnd, msg, wParam, lParam, TRUE );
1400 static LRESULT WINAPI ScrollBarWndProcA( HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam )
1402 return wow_handlers.scrollbar_proc( hwnd, msg, wParam, lParam, FALSE );
1405 static LRESULT WINAPI ScrollBarWndProcW( HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam )
1407 return wow_handlers.scrollbar_proc( hwnd, msg, wParam, lParam, TRUE );
1410 static LRESULT WINAPI StaticWndProcA( HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam )
1412 return wow_handlers.static_proc( hwnd, msg, wParam, lParam, FALSE );
1415 static LRESULT WINAPI StaticWndProcW( HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam )
1417 return wow_handlers.static_proc( hwnd, msg, wParam, lParam, TRUE );
1420 /**********************************************************************
1421 * UserRegisterWowHandlers (USER32.@)
1423 * NOTE: no attempt has been made to be compatible here,
1424 * the Windows function is most likely completely different.
1426 void WINAPI UserRegisterWowHandlers( const struct wow_handlers16 *new, struct wow_handlers32 *orig )
1428 orig->button_proc = ButtonWndProc_common;
1429 orig->combo_proc = ComboWndProc_common;
1430 orig->edit_proc = EditWndProc_common;
1431 orig->listbox_proc = ListBoxWndProc_common;
1432 orig->mdiclient_proc = MDIClientWndProc_common;
1433 orig->scrollbar_proc = ScrollBarWndProc_common;
1434 orig->static_proc = StaticWndProc_common;
1435 orig->create_window = WIN_CreateWindowEx;
1436 orig->get_win_handle = WIN_GetFullHandle;
1437 orig->alloc_winproc = WINPROC_AllocProc;
1438 orig->get_dialog_info = DIALOG_get_info;
1439 orig->dialog_box_loop = DIALOG_DoDialogBox;
1441 wow_handlers = *new;
1444 struct wow_handlers16 wow_handlers =
1446 ButtonWndProc_common,
1447 ComboWndProc_common,
1448 EditWndProc_common,
1449 ListBoxWndProc_common,
1450 MDIClientWndProc_common,
1451 ScrollBarWndProc_common,
1452 StaticWndProc_common,
1453 WIN_CreateWindowEx,
1454 NULL, /* call_window_proc */
1455 NULL, /* call_dialog_proc */
1458 static const struct user_client_procs client_procsA =
1460 .pButtonWndProc = ButtonWndProcA,
1461 .pComboWndProc = ComboWndProcA,
1462 .pDefWindowProc = DefWindowProcA,
1463 .pDefDlgProc = DefDlgProcA,
1464 .pEditWndProc = EditWndProcA,
1465 .pListBoxWndProc = ListBoxWndProcA,
1466 .pMDIClientWndProc = MDIClientWndProcA,
1467 .pScrollBarWndProc = ScrollBarWndProcA,
1468 .pStaticWndProc = StaticWndProcA,
1469 .pImeWndProc = ImeWndProcA,
1472 static const struct user_client_procs client_procsW =
1474 .pButtonWndProc = ButtonWndProcW,
1475 .pComboWndProc = ComboWndProcW,
1476 .pDefWindowProc = DefWindowProcW,
1477 .pDefDlgProc = DefDlgProcW,
1478 .pEditWndProc = EditWndProcW,
1479 .pListBoxWndProc = ListBoxWndProcW,
1480 .pMDIClientWndProc = MDIClientWndProcW,
1481 .pScrollBarWndProc = ScrollBarWndProcW,
1482 .pStaticWndProc = StaticWndProcW,
1483 .pImeWndProc = ImeWndProcW,
1484 .pDesktopWndProc = DesktopWndProc,
1485 .pIconTitleWndProc = IconTitleWndProc,
1486 .pPopupMenuWndProc = PopupMenuWndProc,
1487 .pMessageWndProc = MessageWndProc,
1490 void winproc_init(void)
1492 NtUserInitializeClientPfnArrays( &client_procsA, &client_procsW, NULL, user32_module );