dxgi: Add IDXGISwapChain2 stubs for D3D11.
[wine.git] / dlls / user32 / winproc.c
blob4525f604beb8897bb50c00297d135354730981e6
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 "ntstatus.h"
23 #define WIN32_NO_STATUS
24 #include "user_private.h"
25 #include "controls.h"
26 #include "dbt.h"
27 #include "wine/asm.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 );
44 #ifdef __i386__
45 /* Some window procedures modify registers they shouldn't, or are not
46 * properly declared stdcall; so we need a small assembly wrapper to
47 * call them. */
48 extern LRESULT WINPROC_wrapper( WNDPROC proc, HWND hwnd, UINT msg,
49 WPARAM wParam, LPARAM lParam );
50 __ASM_GLOBAL_FUNC( WINPROC_wrapper,
51 "pushl %ebp\n\t"
52 __ASM_CFI(".cfi_adjust_cfa_offset 4\n\t")
53 __ASM_CFI(".cfi_rel_offset %ebp,0\n\t")
54 "movl %esp,%ebp\n\t"
55 __ASM_CFI(".cfi_def_cfa_register %ebp\n\t")
56 "pushl %edi\n\t"
57 __ASM_CFI(".cfi_rel_offset %edi,-4\n\t")
58 "pushl %esi\n\t"
59 __ASM_CFI(".cfi_rel_offset %esi,-8\n\t")
60 "pushl %ebx\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 */
63 "xorl %edi,%edi\n\t"
64 "subl $12,%esp\n\t"
65 "pushl 24(%ebp)\n\t"
66 "pushl 20(%ebp)\n\t"
67 "pushl 16(%ebp)\n\t"
68 "pushl 12(%ebp)\n\t"
69 "movl 8(%ebp),%eax\n\t"
70 "call *%eax\n\t"
71 "leal -12(%ebp),%esp\n\t"
72 "popl %ebx\n\t"
73 __ASM_CFI(".cfi_same_value %ebx\n\t")
74 "popl %esi\n\t"
75 __ASM_CFI(".cfi_same_value %esi\n\t")
76 "popl %edi\n\t"
77 __ASM_CFI(".cfi_same_value %edi\n\t")
78 "leave\n\t"
79 __ASM_CFI(".cfi_def_cfa %esp,4\n\t")
80 __ASM_CFI(".cfi_same_value %ebp\n\t")
81 "ret" )
82 #else
83 static inline LRESULT WINPROC_wrapper( WNDPROC proc, HWND hwnd, UINT msg,
84 WPARAM wParam, LPARAM lParam )
86 return proc( hwnd, msg, wParam, lParam );
88 #endif /* __i386__ */
90 static WPARAM map_wparam_char_WtoA( WPARAM wParam, DWORD len )
92 WCHAR wch = wParam;
93 BYTE ch[2];
94 DWORD cp = get_input_codepage();
96 len = WideCharToMultiByte( cp, 0, &wch, 1, (LPSTR)ch, len, NULL, NULL );
97 if (len == 2)
98 return MAKEWPARAM( (ch[0] << 8) | ch[1], HIWORD(wParam) );
99 else
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 )
106 WNDPROC proc = 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 );
115 return *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;
122 WNDPROC proc = arg;
123 LRESULT ret;
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 );
136 return ret;
140 /**********************************************************************
141 * WINPROC_AllocProc
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));
165 else
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 )
179 LRESULT ret = 0;
181 TRACE( "(hwnd=%p,msg=%s,wp=%08Ix,lp=%08Ix)\n", hwnd, SPY_GetMsgName(msg, hwnd), wParam, lParam );
183 switch(msg)
185 case WM_NCCREATE:
186 case WM_CREATE:
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;
207 if (class_lenW)
209 csW.lpszClass = ptr;
210 RtlMultiByteToUnicodeN( ptr, class_lenW, NULL, csA->lpszClass, class_lenA );
212 if (name_lenW)
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 );
230 break;
232 case WM_MDICREATE:
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;
254 if (title_lenW)
256 csW.szTitle = ptr;
257 RtlMultiByteToUnicodeN( ptr, title_lenW, NULL, csA->szTitle, title_lenA );
259 if (class_lenW)
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 );
268 break;
270 case WM_GETTEXT:
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 );
279 if (wParam)
281 len = 0;
282 if (*result)
283 RtlUnicodeToMultiByteN( str, wParam - 1, &len, ptr, ret * sizeof(WCHAR) );
284 str[len] = 0;
285 *result = len;
287 free_buffer( buffer, ptr );
289 break;
291 case LB_ADDSTRING:
292 case LB_INSERTSTRING:
293 case LB_FINDSTRING:
294 case LB_FINDSTRINGEXACT:
295 case LB_SELECTSTRING:
296 case CB_ADDSTRING:
297 case CB_INSERTSTRING:
298 case CB_FINDSTRING:
299 case CB_FINDSTRINGEXACT:
300 case CB_SELECTSTRING:
301 if (!lParam || !WINPROC_TestLBForStr( hwnd, msg ))
303 ret = callback( hwnd, msg, wParam, lParam, result, arg );
304 break;
306 /* fall through */
307 case WM_SETTEXT:
308 case WM_WININICHANGE:
309 case WM_DEVMODECHANGE:
310 case CB_DIR:
311 case LB_DIR:
312 case LB_ADDFILE:
313 case EM_REPLACESEL:
314 if (!lParam) ret = callback( hwnd, msg, wParam, lParam, result, arg );
315 else
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 );
329 break;
331 case LB_GETTEXT:
332 case CB_GETLBTEXT:
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 );
338 if (*result >= 0)
340 DWORD len;
341 RtlUnicodeToMultiByteN( (LPSTR)lParam, 512 * 3, &len,
342 buffer, (lstrlenW(buffer) + 1) * sizeof(WCHAR) );
343 *result = len - 1;
346 else ret = callback( hwnd, msg, wParam, lParam, result, arg );
347 break;
349 case EM_GETLINE:
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 );
357 if (*result)
359 DWORD reslen;
360 RtlUnicodeToMultiByteN( (LPSTR)lParam, len, &reslen, ptr, *result * sizeof(WCHAR) );
361 if (reslen < len) ((LPSTR)lParam)[reslen] = 0;
362 *result = reslen;
364 free_buffer( buffer, ptr );
366 break;
368 case WM_GETDLGCODE:
369 if (lParam)
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 );
376 break;
378 case WM_CHARTOITEM:
379 case WM_MENUCHAR:
380 case WM_CHAR:
381 case WM_DEADCHAR:
382 case WM_SYSCHAR:
383 case WM_SYSDEADCHAR:
384 case EM_SETPASSWORDCHAR:
385 case WM_IME_CHAR:
386 if (map_wparam_AtoW( msg, &wParam, mapping ))
387 ret = callback( hwnd, msg, wParam, lParam, result, arg );
388 break;
390 case WM_GETTEXTLENGTH:
391 case CB_GETLBTEXTLEN:
392 case LB_GETTEXTLEN:
393 ret = callback( hwnd, msg, wParam, lParam, result, arg );
394 if (*result >= 0)
396 WCHAR *ptr, buffer[512];
397 LRESULT tmp;
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 );
409 else
410 tmp = SendMessageW( hwnd, msgGetText, wp, (LPARAM)ptr );
411 RtlUnicodeToMultiByteSize( &len, ptr, tmp * sizeof(WCHAR) );
412 *result = len;
413 free_buffer( buffer, ptr );
415 break;
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 );
421 break;
423 default:
424 ret = callback( hwnd, msg, wParam, lParam, result, arg );
425 break;
427 return ret;
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 )
439 LRESULT ret = 0;
441 TRACE( "(hwnd=%p,msg=%s,wp=%08Ix,lp=%08Ix)\n", hwnd, SPY_GetMsgName(msg, hwnd), wParam, lParam );
443 switch(msg)
445 case WM_NCCREATE:
446 case WM_CREATE:
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;
468 int_name_buf[3] = 0;
469 csA.lpszName = int_name_buf;
471 else
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;
480 if (class_lenA)
482 RtlUnicodeToMultiByteN(cls, class_lenA, NULL, csW->lpszClass, class_lenW);
483 csA.lpszClass = cls;
485 if (name_lenA)
487 char *name = cls + class_lenA;
488 RtlUnicodeToMultiByteN(name, name_lenA, NULL, csW->lpszName, name_lenW);
489 csA.lpszName = name;
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 );
503 break;
505 case WM_GETTEXT:
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 );
513 if (len)
515 if (*result)
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 );
524 break;
526 case LB_ADDSTRING:
527 case LB_INSERTSTRING:
528 case LB_FINDSTRING:
529 case LB_FINDSTRINGEXACT:
530 case LB_SELECTSTRING:
531 case CB_ADDSTRING:
532 case CB_INSERTSTRING:
533 case CB_FINDSTRING:
534 case CB_FINDSTRINGEXACT:
535 case CB_SELECTSTRING:
536 if (!lParam || !WINPROC_TestLBForStr( hwnd, msg ))
538 ret = callback( hwnd, msg, wParam, lParam, result, arg );
539 break;
541 /* fall through */
542 case WM_SETTEXT:
543 case WM_WININICHANGE:
544 case WM_DEVMODECHANGE:
545 case CB_DIR:
546 case LB_DIR:
547 case LB_ADDFILE:
548 case EM_REPLACESEL:
549 if (!lParam) ret = callback( hwnd, msg, wParam, lParam, result, arg );
550 else
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 );
564 break;
566 case WM_MDICREATE:
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;
588 if (title_lenA)
590 RtlUnicodeToMultiByteN( ptr, title_lenA, NULL, csW->szTitle, title_lenW );
591 csA.szTitle = ptr;
593 if (class_lenA)
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 );
601 break;
603 case LB_GETTEXT:
604 case CB_GETLBTEXT:
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 );
610 if (*result >= 0)
612 DWORD len;
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 );
618 break;
620 case EM_GETLINE:
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 );
628 if (*result)
630 DWORD reslen;
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 );
637 break;
639 case WM_GETDLGCODE:
640 if (lParam)
642 MSG newmsg = *(MSG *)lParam;
643 switch(newmsg.message)
645 case WM_CHAR:
646 case WM_DEADCHAR:
647 case WM_SYSCHAR:
648 case WM_SYSDEADCHAR:
649 newmsg.wParam = map_wparam_char_WtoA( newmsg.wParam, 1 );
650 break;
651 case WM_IME_CHAR:
652 newmsg.wParam = map_wparam_char_WtoA( newmsg.wParam, 2 );
653 break;
655 ret = callback( hwnd, msg, wParam, (LPARAM)&newmsg, result, arg );
657 else ret = callback( hwnd, msg, wParam, lParam, result, arg );
658 break;
660 case WM_CHAR:
662 WCHAR wch = wParam;
663 char ch[2];
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 );
669 break;
671 case WM_CHARTOITEM:
672 case WM_MENUCHAR:
673 case WM_DEADCHAR:
674 case WM_SYSCHAR:
675 case WM_SYSDEADCHAR:
676 case EM_SETPASSWORDCHAR:
677 ret = callback( hwnd, msg, map_wparam_char_WtoA(wParam,1), lParam, result, arg );
678 break;
680 case WM_IME_CHAR:
681 ret = callback( hwnd, msg, map_wparam_char_WtoA(wParam,2), lParam, result, arg );
682 break;
684 case WM_PAINTCLIPBOARD:
685 case WM_SIZECLIPBOARD:
686 FIXME( "message %s (%04x) needs translation, please report\n",
687 SPY_GetMsgName(msg, hwnd), msg );
688 break;
690 default:
691 ret = callback( hwnd, msg, wParam, lParam, result, arg );
692 break;
695 return ret;
699 LRESULT dispatch_win_proc_params( struct win_proc_params *params )
701 DPI_AWARENESS_CONTEXT context = SetThreadDpiAwarenessContext( params->dpi_awareness );
702 LRESULT result = 0;
704 if (!params->ansi)
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 );
712 else
713 WINPROC_CallProcWtoA( call_window_proc, params->hwnd, params->msg, params->wparam,
714 params->lparam, &result, params->procA );
716 else
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 );
724 else
725 call_window_proc( params->hwnd, params->msg, params->wparam, params->lparam,
726 &result, params->procA );
729 SetThreadDpiAwarenessContext( context );
730 return result;
733 static size_t string_size( const void *str, BOOL ansi )
735 return ansi ? strlen( str ) + 1 : (wcslen( str ) + 1) * sizeof(WCHAR);
738 /***********************************************************************
739 * unpack_message
741 * Unpack a message received from win32u.
743 void unpack_message( HWND hwnd, UINT message, WPARAM *wparam, LPARAM *lparam, void *buffer, BOOL ansi )
745 switch(message)
747 case WM_NCCREATE:
748 case WM_CREATE:
750 CREATESTRUCTA *cs = buffer;
751 char *str = (char *)(cs + 1);
753 if (!IS_INTRESOURCE(cs->lpszName))
755 cs->lpszName = str;
756 str += string_size( str, ansi );
758 if (!IS_INTRESOURCE(cs->lpszClass))
760 cs->lpszClass = str;
762 break;
764 case WM_NCCALCSIZE:
765 if (*wparam)
767 NCCALCSIZE_PARAMS *ncp = buffer;
768 ncp->lppos = (WINDOWPOS *)((NCCALCSIZE_PARAMS *)ncp + 1);
770 break;
771 case WM_COPYDATA:
773 COPYDATASTRUCT *cds = buffer;
774 if (cds->lpData) cds->lpData = cds + 1;
775 break;
777 case EM_GETSEL:
778 case SBM_GETRANGE:
779 case CB_GETEDITSEL:
781 DWORD *ptr = buffer;
782 *wparam = (WPARAM)ptr++;
783 *lparam = (LPARAM)ptr;
784 return;
786 case WM_MDICREATE:
788 MDICREATESTRUCTA *mcs = buffer;
789 char *str = (char *)(mcs + 1);
791 if (!IS_INTRESOURCE(mcs->szClass))
793 mcs->szClass = str;
794 str += string_size( mcs->szClass, ansi );
796 if (!IS_INTRESOURCE(mcs->szTitle))
798 mcs->szTitle = str;
800 break;
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;
811 void *buffer = NULL;
812 LRESULT result;
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, &params->wparam, &params->lparam,
821 buffer, params->ansi );
824 result = dispatch_win_proc_params( params );
826 if (packed_size)
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.
858 * RETURNS
860 * The return value is message dependent.
862 * CONFORMANCE
864 * ECMA-234, Win32
866 LRESULT WINAPI DECLSPEC_HOTPATCH CallWindowProcA( WNDPROC func, HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam )
868 struct win_proc_params params;
870 params.func = func;
871 if (!NtUserMessageCall( hwnd, msg, wParam, lParam, &params, NtUserCallWindowProc, TRUE ))
872 return 0;
873 return dispatch_win_proc_params( &params );
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;
886 params.func = func;
887 if (!NtUserMessageCall( hwnd, msg, wParam, lParam, &params, NtUserCallWindowProc, FALSE ))
888 return 0;
889 return dispatch_win_proc_params( &params );
893 /**********************************************************************
894 * WINPROC_CallDlgProcA
896 INT_PTR WINPROC_CallDlgProcA( HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam )
898 DLGPROC func, proc;
899 LRESULT result;
901 #ifdef _WIN64
902 proc = (DLGPROC)NtUserGetWindowLongPtrA( hwnd, DWLP_DLGPROC );
903 #else
904 proc = (DLGPROC)NtUserGetWindowLongA( hwnd, DWLP_DLGPROC );
905 #endif
906 if (!proc) return 0;
907 if (!(func = NtUserGetDialogProc( proc, TRUE )) &&
908 !(func = NtUserGetDialogProc( proc, FALSE ))) return 0;
910 if (func == WINPROC_PROC16)
912 INT_PTR ret;
913 ret = wow_handlers.call_dialog_proc( hwnd, msg, wParam, lParam, &result, proc );
914 SetWindowLongPtrW( hwnd, DWLP_MSGRESULT, result );
915 return ret;
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 )
927 DLGPROC func, proc;
928 LRESULT result;
930 #ifdef _WIN64
931 proc = (DLGPROC)NtUserGetWindowLongPtrW( hwnd, DWLP_DLGPROC );
932 #else
933 proc = (DLGPROC)NtUserGetWindowLongW( hwnd, DWLP_DLGPROC );
934 #endif
935 if (!proc) return 0;
936 if (!(func = NtUserGetDialogProc( proc, FALSE )) &&
937 !(func = NtUserGetDialogProc( proc, TRUE ))) return 0;
939 if (func == WINPROC_PROC16)
941 INT_PTR ret;
942 ret = WINPROC_CallProcWtoA( wow_handlers.call_dialog_proc,
943 hwnd, msg, wParam, lParam, &result, proc );
944 SetWindowLongPtrW( hwnd, DWLP_MSGRESULT, result );
945 return ret;
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,
1054 EditWndProc_common,
1055 ListBoxWndProc_common,
1056 MDIClientWndProc_common,
1057 ScrollBarWndProc_common,
1058 StaticWndProc_common,
1059 WIN_CreateWindowEx,
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 );