2 * Window messaging support
4 * Copyright 2001 Alexandre Julliard
5 * Copyright 2008 Maarten Lankhorst
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
29 #define WIN32_NO_STATUS
30 #include "win32u_private.h"
31 #include "ntuser_private.h"
36 #include "wine/server.h"
37 #include "wine/debug.h"
39 WINE_DEFAULT_DEBUG_CHANNEL(msg
);
40 WINE_DECLARE_DEBUG_CHANNEL(key
);
41 WINE_DECLARE_DEBUG_CHANNEL(relay
);
43 #define MAX_WINPROC_RECURSION 64
45 #define WM_NCMOUSEFIRST WM_NCMOUSEMOVE
46 #define WM_NCMOUSELAST (WM_NCMOUSEFIRST+(WM_MOUSELAST-WM_MOUSEFIRST))
48 #define MAX_PACK_COUNT 4
50 /* info about the message currently being received by the current thread */
51 struct received_message_info
55 UINT flags
; /* InSendMessageEx return flags */
57 struct received_message_info
*prev
;
60 #define MSG_CLIENT_MESSAGE 0xff
62 struct packed_hook_extra_info
69 /* the structures are unpacked on top of the packed ones, so make sure they fit */
70 C_ASSERT( sizeof(struct packed_CREATESTRUCTW
) >= sizeof(CREATESTRUCTW
) );
71 C_ASSERT( sizeof(struct packed_DRAWITEMSTRUCT
) >= sizeof(DRAWITEMSTRUCT
) );
72 C_ASSERT( sizeof(struct packed_MEASUREITEMSTRUCT
) >= sizeof(MEASUREITEMSTRUCT
) );
73 C_ASSERT( sizeof(struct packed_DELETEITEMSTRUCT
) >= sizeof(DELETEITEMSTRUCT
) );
74 C_ASSERT( sizeof(struct packed_COMPAREITEMSTRUCT
) >= sizeof(COMPAREITEMSTRUCT
) );
75 C_ASSERT( sizeof(struct packed_WINDOWPOS
) >= sizeof(WINDOWPOS
) );
76 C_ASSERT( sizeof(struct packed_COPYDATASTRUCT
) >= sizeof(COPYDATASTRUCT
) );
77 C_ASSERT( sizeof(struct packed_HELPINFO
) >= sizeof(HELPINFO
) );
78 C_ASSERT( sizeof(struct packed_NCCALCSIZE_PARAMS
) >= sizeof(NCCALCSIZE_PARAMS
) + sizeof(WINDOWPOS
) );
79 C_ASSERT( sizeof(struct packed_MSG
) >= sizeof(MSG
) );
80 C_ASSERT( sizeof(struct packed_MDINEXTMENU
) >= sizeof(MDINEXTMENU
) );
81 C_ASSERT( sizeof(struct packed_MDICREATESTRUCTW
) >= sizeof(MDICREATESTRUCTW
) );
82 C_ASSERT( sizeof(struct packed_hook_extra_info
) >= sizeof(struct hook_extra_info
) );
86 struct packed_CREATESTRUCTW cs
;
87 struct packed_DRAWITEMSTRUCT dis
;
88 struct packed_MEASUREITEMSTRUCT mis
;
89 struct packed_DELETEITEMSTRUCT dls
;
90 struct packed_COMPAREITEMSTRUCT cis
;
91 struct packed_WINDOWPOS wp
;
92 struct packed_COPYDATASTRUCT cds
;
93 struct packed_HELPINFO hi
;
94 struct packed_NCCALCSIZE_PARAMS ncp
;
95 struct packed_MSG msg
;
96 struct packed_MDINEXTMENU mnm
;
97 struct packed_MDICREATESTRUCTW mcs
;
98 struct packed_hook_extra_info hook
;
101 /* description of the data fields that need to be packed along with a sent message */
102 struct packed_message
104 union packed_structs ps
;
106 const void *data
[MAX_PACK_COUNT
];
107 size_t size
[MAX_PACK_COUNT
];
110 /* structure to group all parameters for sent messages of the various kinds */
111 struct send_message_info
113 enum message_type type
;
119 UINT flags
; /* flags for SendMessageTimeout */
120 UINT timeout
; /* timeout for SendMessageTimeout */
121 SENDASYNCPROC callback
; /* callback function for SendMessageCallback */
122 ULONG_PTR data
; /* callback data */
123 enum wm_char_mapping wm_char
;
124 struct win_proc_params
*params
;
127 static const INPUT_MESSAGE_SOURCE msg_source_unavailable
= { IMDT_UNAVAILABLE
, IMO_UNAVAILABLE
};
129 /* flag for messages that contain pointers */
130 /* 32 messages per entry, messages 0..31 map to bits 0..31 */
132 #define SET(msg) (1 << ((msg) & 31))
134 static const unsigned int message_pointer_flags
[] =
137 SET(WM_CREATE
) | SET(WM_SETTEXT
) | SET(WM_GETTEXT
) |
138 SET(WM_WININICHANGE
) | SET(WM_DEVMODECHANGE
),
140 SET(WM_GETMINMAXINFO
) | SET(WM_DRAWITEM
) | SET(WM_MEASUREITEM
) | SET(WM_DELETEITEM
) |
143 SET(WM_WINDOWPOSCHANGING
) | SET(WM_WINDOWPOSCHANGED
) | SET(WM_COPYDATA
) | SET(WM_HELP
),
145 SET(WM_STYLECHANGING
) | SET(WM_STYLECHANGED
),
147 SET(WM_NCCREATE
) | SET(WM_NCCALCSIZE
) | SET(WM_GETDLGCODE
),
149 SET(EM_GETSEL
) | SET(EM_GETRECT
) | SET(EM_SETRECT
) | SET(EM_SETRECTNP
),
151 SET(EM_REPLACESEL
) | SET(EM_GETLINE
) | SET(EM_SETTABSTOPS
),
153 SET(SBM_GETRANGE
) | SET(SBM_SETSCROLLINFO
) | SET(SBM_GETSCROLLINFO
) | SET(SBM_GETSCROLLBARINFO
),
159 SET(CB_GETEDITSEL
) | SET(CB_ADDSTRING
) | SET(CB_DIR
) | SET(CB_GETLBTEXT
) |
160 SET(CB_INSERTSTRING
) | SET(CB_FINDSTRING
) | SET(CB_SELECTSTRING
) |
161 SET(CB_GETDROPPEDCONTROLRECT
) | SET(CB_FINDSTRINGEXACT
),
165 SET(LB_ADDSTRING
) | SET(LB_INSERTSTRING
) | SET(LB_GETTEXT
) | SET(LB_SELECTSTRING
) |
166 SET(LB_DIR
) | SET(LB_FINDSTRING
) |
167 SET(LB_GETSELITEMS
) | SET(LB_SETTABSTOPS
) | SET(LB_ADDFILE
) | SET(LB_GETITEMRECT
),
169 SET(LB_FINDSTRINGEXACT
),
175 SET(WM_NEXTMENU
) | SET(WM_SIZING
) | SET(WM_MOVING
) | SET(WM_DEVICECHANGE
),
177 SET(WM_MDICREATE
) | SET(WM_MDIGETACTIVE
) | SET(WM_DROPOBJECT
) |
178 SET(WM_QUERYDROPOBJECT
) | SET(WM_DRAGLOOP
) | SET(WM_DRAGSELECT
) | SET(WM_DRAGMOVE
),
192 SET(WM_ASKCBFORMATNAME
)
195 /* check whether a given message type includes pointers */
196 static inline BOOL
is_pointer_message( UINT message
, WPARAM wparam
)
198 if (message
>= 8*sizeof(message_pointer_flags
)) return FALSE
;
199 if (message
== WM_DEVICECHANGE
&& !(wparam
& 0x8000)) return FALSE
;
200 return (message_pointer_flags
[message
/ 32] & SET(message
)) != 0;
205 static BOOL
init_win_proc_params( struct win_proc_params
*params
, HWND hwnd
, UINT msg
,
206 WPARAM wparam
, LPARAM lparam
, BOOL ansi
)
208 if (!params
->func
) return FALSE
;
210 user_check_not_lock();
212 params
->hwnd
= get_full_window_handle( hwnd
);
214 params
->wparam
= wparam
;
215 params
->lparam
= lparam
;
216 params
->ansi
= params
->ansi_dst
= ansi
;
217 params
->needs_unpack
= FALSE
;
218 params
->mapping
= WMCHAR_MAP_CALLWINDOWPROC
;
219 params
->dpi_awareness
= get_window_dpi_awareness_context( params
->hwnd
);
220 get_winproc_params( params
, TRUE
);
224 static BOOL
init_window_call_params( struct win_proc_params
*params
, HWND hwnd
, UINT msg
, WPARAM wParam
,
225 LPARAM lParam
, LRESULT
*result
, BOOL ansi
,
226 enum wm_char_mapping mapping
)
231 user_check_not_lock();
233 if (!(win
= get_win_ptr( hwnd
))) return FALSE
;
234 if (win
== WND_OTHER_PROCESS
|| win
== WND_DESKTOP
) return FALSE
;
235 if (win
->tid
!= GetCurrentThreadId())
237 release_win_ptr( win
);
240 params
->func
= win
->winproc
;
241 params
->ansi_dst
= !(win
->flags
& WIN_ISUNICODE
);
242 is_dialog
= win
->dlgInfo
!= NULL
;
243 release_win_ptr( win
);
245 params
->hwnd
= get_full_window_handle( hwnd
);
247 params
->wparam
= wParam
;
248 params
->lparam
= lParam
;
249 params
->result
= result
;
251 params
->needs_unpack
= FALSE
;
252 params
->mapping
= mapping
;
253 params
->dpi_awareness
= get_window_dpi_awareness_context( params
->hwnd
);
254 get_winproc_params( params
, !is_dialog
);
258 static BOOL
dispatch_win_proc_params( struct win_proc_params
*params
, size_t size
)
260 struct ntuser_thread_info
*thread_info
= NtUserGetThreadInfo();
264 if (thread_info
->recursion_count
> MAX_WINPROC_RECURSION
) return FALSE
;
265 thread_info
->recursion_count
++;
267 KeUserModeCallback( NtUserCallWinProc
, params
, size
, &ret_ptr
, &ret_len
);
268 if (ret_len
== sizeof(*params
->result
)) *params
->result
= *(LRESULT
*)ret_ptr
;
270 thread_info
->recursion_count
--;
274 /* add a data field to a packed message */
275 static inline void push_data( struct packed_message
*data
, const void *ptr
, size_t size
)
277 data
->data
[data
->count
] = ptr
;
278 data
->size
[data
->count
] = size
;
282 /* pack a pointer into a 32/64 portable format */
283 static inline ULONGLONG
pack_ptr( const void *ptr
)
285 return (ULONG_PTR
)ptr
;
288 /* unpack a potentially 64-bit pointer, returning 0 when truncated */
289 static inline void *unpack_ptr( ULONGLONG ptr64
)
291 if ((ULONG_PTR
)ptr64
!= ptr64
) return 0;
292 return (void *)(ULONG_PTR
)ptr64
;
295 /* add a string to a packed message */
296 static inline void push_string( struct packed_message
*data
, LPCWSTR str
)
298 push_data( data
, str
, (lstrlenW(str
) + 1) * sizeof(WCHAR
) );
301 /* check whether a combobox expects strings or ids in CB_ADDSTRING/CB_INSERTSTRING */
302 static inline BOOL
combobox_has_strings( HWND hwnd
)
304 DWORD style
= get_window_long( hwnd
, GWL_STYLE
);
305 return (!(style
& (CBS_OWNERDRAWFIXED
| CBS_OWNERDRAWVARIABLE
)) || (style
& CBS_HASSTRINGS
));
308 /* check whether a listbox expects strings or ids in LB_ADDSTRING/LB_INSERTSTRING */
309 static inline BOOL
listbox_has_strings( HWND hwnd
)
311 DWORD style
= get_window_long( hwnd
, GWL_STYLE
);
312 return (!(style
& (LBS_OWNERDRAWFIXED
| LBS_OWNERDRAWVARIABLE
)) || (style
& LBS_HASSTRINGS
));
315 /* check whether message is in the range of keyboard messages */
316 static inline BOOL
is_keyboard_message( UINT message
)
318 return (message
>= WM_KEYFIRST
&& message
<= WM_KEYLAST
);
321 /* check whether message is in the range of mouse messages */
322 static inline BOOL
is_mouse_message( UINT message
)
324 return ((message
>= WM_NCMOUSEFIRST
&& message
<= WM_NCMOUSELAST
) ||
325 (message
>= WM_MOUSEFIRST
&& message
<= WM_MOUSELAST
));
328 /* check whether message matches the specified hwnd filter */
329 static inline BOOL
check_hwnd_filter( const MSG
*msg
, HWND hwnd_filter
)
331 if (!hwnd_filter
|| hwnd_filter
== get_desktop_window()) return TRUE
;
332 return (msg
->hwnd
== hwnd_filter
|| is_child( hwnd_filter
, msg
->hwnd
));
335 /***********************************************************************
338 * Unpack a message received from another process.
340 static BOOL
unpack_message( HWND hwnd
, UINT message
, WPARAM
*wparam
, LPARAM
*lparam
,
341 void **buffer
, size_t size
)
344 union packed_structs
*ps
= *buffer
;
348 case WM_WINE_SETWINDOWPOS
:
351 if (size
< sizeof(ps
->wp
)) return FALSE
;
352 wp
.hwnd
= wine_server_ptr_handle( ps
->wp
.hwnd
);
353 wp
.hwndInsertAfter
= wine_server_ptr_handle( ps
->wp
.hwndInsertAfter
);
358 wp
.flags
= ps
->wp
.flags
;
359 memcpy( ps
, &wp
, sizeof(wp
) );
362 case WM_WINE_KEYBOARD_LL_HOOK
:
363 case WM_WINE_MOUSE_LL_HOOK
:
365 struct hook_extra_info h_extra
;
366 minsize
= sizeof(ps
->hook
) +
367 (message
== WM_WINE_KEYBOARD_LL_HOOK
? sizeof(KBDLLHOOKSTRUCT
)
368 : sizeof(MSLLHOOKSTRUCT
));
369 if (size
< minsize
) return FALSE
;
370 h_extra
.handle
= wine_server_ptr_handle( ps
->hook
.handle
);
371 h_extra
.lparam
= (LPARAM
)(&ps
->hook
+ 1);
372 memcpy( &ps
->hook
, &h_extra
, sizeof(h_extra
) );
376 return TRUE
; /* message doesn't need any unpacking */
379 /* default exit for most messages: check minsize and store buffer in lparam */
380 if (size
< minsize
) return FALSE
;
381 *lparam
= (LPARAM
)*buffer
;
385 /***********************************************************************
388 * Pack a message for sending to another process.
389 * Return the size of the data we expect in the message reply.
390 * Set data->count to -1 if there is an error.
392 static size_t pack_message( HWND hwnd
, UINT message
, WPARAM wparam
, LPARAM lparam
,
393 struct packed_message
*data
)
401 CREATESTRUCTW
*cs
= (CREATESTRUCTW
*)lparam
;
402 data
->ps
.cs
.lpCreateParams
= pack_ptr( cs
->lpCreateParams
);
403 data
->ps
.cs
.hInstance
= pack_ptr( cs
->hInstance
);
404 data
->ps
.cs
.hMenu
= wine_server_user_handle( cs
->hMenu
);
405 data
->ps
.cs
.hwndParent
= wine_server_user_handle( cs
->hwndParent
);
406 data
->ps
.cs
.cy
= cs
->cy
;
407 data
->ps
.cs
.cx
= cs
->cx
;
408 data
->ps
.cs
.y
= cs
->y
;
409 data
->ps
.cs
.x
= cs
->x
;
410 data
->ps
.cs
.style
= cs
->style
;
411 data
->ps
.cs
.dwExStyle
= cs
->dwExStyle
;
412 data
->ps
.cs
.lpszName
= pack_ptr( cs
->lpszName
);
413 data
->ps
.cs
.lpszClass
= pack_ptr( cs
->lpszClass
);
414 push_data( data
, &data
->ps
.cs
, sizeof(data
->ps
.cs
) );
415 if (!IS_INTRESOURCE(cs
->lpszName
)) push_string( data
, cs
->lpszName
);
416 if (!IS_INTRESOURCE(cs
->lpszClass
)) push_string( data
, cs
->lpszClass
);
417 return sizeof(data
->ps
.cs
);
420 case WM_ASKCBFORMATNAME
:
421 return wparam
* sizeof(WCHAR
);
422 case WM_WININICHANGE
:
423 if (lparam
) push_string(data
, (LPWSTR
)lparam
);
426 case WM_DEVMODECHANGE
:
431 push_string( data
, (LPWSTR
)lparam
);
433 case WM_GETMINMAXINFO
:
434 push_data( data
, (MINMAXINFO
*)lparam
, sizeof(MINMAXINFO
) );
435 return sizeof(MINMAXINFO
);
438 DRAWITEMSTRUCT
*dis
= (DRAWITEMSTRUCT
*)lparam
;
439 data
->ps
.dis
.CtlType
= dis
->CtlType
;
440 data
->ps
.dis
.CtlID
= dis
->CtlID
;
441 data
->ps
.dis
.itemID
= dis
->itemID
;
442 data
->ps
.dis
.itemAction
= dis
->itemAction
;
443 data
->ps
.dis
.itemState
= dis
->itemState
;
444 data
->ps
.dis
.hwndItem
= wine_server_user_handle( dis
->hwndItem
);
445 data
->ps
.dis
.hDC
= wine_server_user_handle( dis
->hDC
); /* FIXME */
446 data
->ps
.dis
.rcItem
= dis
->rcItem
;
447 data
->ps
.dis
.itemData
= dis
->itemData
;
448 push_data( data
, &data
->ps
.dis
, sizeof(data
->ps
.dis
) );
453 MEASUREITEMSTRUCT
*mis
= (MEASUREITEMSTRUCT
*)lparam
;
454 data
->ps
.mis
.CtlType
= mis
->CtlType
;
455 data
->ps
.mis
.CtlID
= mis
->CtlID
;
456 data
->ps
.mis
.itemID
= mis
->itemID
;
457 data
->ps
.mis
.itemWidth
= mis
->itemWidth
;
458 data
->ps
.mis
.itemHeight
= mis
->itemHeight
;
459 data
->ps
.mis
.itemData
= mis
->itemData
;
460 push_data( data
, &data
->ps
.mis
, sizeof(data
->ps
.mis
) );
461 return sizeof(data
->ps
.mis
);
465 DELETEITEMSTRUCT
*dls
= (DELETEITEMSTRUCT
*)lparam
;
466 data
->ps
.dls
.CtlType
= dls
->CtlType
;
467 data
->ps
.dls
.CtlID
= dls
->CtlID
;
468 data
->ps
.dls
.itemID
= dls
->itemID
;
469 data
->ps
.dls
.hwndItem
= wine_server_user_handle( dls
->hwndItem
);
470 data
->ps
.dls
.itemData
= dls
->itemData
;
471 push_data( data
, &data
->ps
.dls
, sizeof(data
->ps
.dls
) );
476 COMPAREITEMSTRUCT
*cis
= (COMPAREITEMSTRUCT
*)lparam
;
477 data
->ps
.cis
.CtlType
= cis
->CtlType
;
478 data
->ps
.cis
.CtlID
= cis
->CtlID
;
479 data
->ps
.cis
.hwndItem
= wine_server_user_handle( cis
->hwndItem
);
480 data
->ps
.cis
.itemID1
= cis
->itemID1
;
481 data
->ps
.cis
.itemData1
= cis
->itemData1
;
482 data
->ps
.cis
.itemID2
= cis
->itemID2
;
483 data
->ps
.cis
.itemData2
= cis
->itemData2
;
484 data
->ps
.cis
.dwLocaleId
= cis
->dwLocaleId
;
485 push_data( data
, &data
->ps
.cis
, sizeof(data
->ps
.cis
) );
488 case WM_WINE_SETWINDOWPOS
:
489 case WM_WINDOWPOSCHANGING
:
490 case WM_WINDOWPOSCHANGED
:
492 WINDOWPOS
*wp
= (WINDOWPOS
*)lparam
;
493 data
->ps
.wp
.hwnd
= wine_server_user_handle( wp
->hwnd
);
494 data
->ps
.wp
.hwndInsertAfter
= wine_server_user_handle( wp
->hwndInsertAfter
);
495 data
->ps
.wp
.x
= wp
->x
;
496 data
->ps
.wp
.y
= wp
->y
;
497 data
->ps
.wp
.cx
= wp
->cx
;
498 data
->ps
.wp
.cy
= wp
->cy
;
499 data
->ps
.wp
.flags
= wp
->flags
;
500 push_data( data
, &data
->ps
.wp
, sizeof(data
->ps
.wp
) );
501 return sizeof(data
->ps
.wp
);
505 COPYDATASTRUCT
*cds
= (COPYDATASTRUCT
*)lparam
;
506 data
->ps
.cds
.cbData
= cds
->cbData
;
507 data
->ps
.cds
.dwData
= cds
->dwData
;
508 data
->ps
.cds
.lpData
= pack_ptr( cds
->lpData
);
509 push_data( data
, &data
->ps
.cds
, sizeof(data
->ps
.cds
) );
510 if (cds
->lpData
) push_data( data
, cds
->lpData
, cds
->cbData
);
514 /* WM_NOTIFY cannot be sent across processes (MSDN) */
519 HELPINFO
*hi
= (HELPINFO
*)lparam
;
520 data
->ps
.hi
.iContextType
= hi
->iContextType
;
521 data
->ps
.hi
.iCtrlId
= hi
->iCtrlId
;
522 data
->ps
.hi
.hItemHandle
= wine_server_user_handle( hi
->hItemHandle
);
523 data
->ps
.hi
.dwContextId
= hi
->dwContextId
;
524 data
->ps
.hi
.MousePos
= hi
->MousePos
;
525 push_data( data
, &data
->ps
.hi
, sizeof(data
->ps
.hi
) );
528 case WM_STYLECHANGING
:
529 case WM_STYLECHANGED
:
530 push_data( data
, (STYLESTRUCT
*)lparam
, sizeof(STYLESTRUCT
) );
535 push_data( data
, (RECT
*)lparam
, sizeof(RECT
) );
540 NCCALCSIZE_PARAMS
*ncp
= (NCCALCSIZE_PARAMS
*)lparam
;
541 data
->ps
.ncp
.rgrc
[0] = ncp
->rgrc
[0];
542 data
->ps
.ncp
.rgrc
[1] = ncp
->rgrc
[1];
543 data
->ps
.ncp
.rgrc
[2] = ncp
->rgrc
[2];
544 data
->ps
.ncp
.hwnd
= wine_server_user_handle( ncp
->lppos
->hwnd
);
545 data
->ps
.ncp
.hwndInsertAfter
= wine_server_user_handle( ncp
->lppos
->hwndInsertAfter
);
546 data
->ps
.ncp
.x
= ncp
->lppos
->x
;
547 data
->ps
.ncp
.y
= ncp
->lppos
->y
;
548 data
->ps
.ncp
.cx
= ncp
->lppos
->cx
;
549 data
->ps
.ncp
.cy
= ncp
->lppos
->cy
;
550 data
->ps
.ncp
.flags
= ncp
->lppos
->flags
;
551 push_data( data
, &data
->ps
.ncp
, sizeof(data
->ps
.ncp
) );
552 return sizeof(data
->ps
.ncp
);
557 MSG
*msg
= (MSG
*)lparam
;
558 data
->ps
.msg
.hwnd
= wine_server_user_handle( msg
->hwnd
);
559 data
->ps
.msg
.message
= msg
->message
;
560 data
->ps
.msg
.wParam
= msg
->wParam
;
561 data
->ps
.msg
.lParam
= msg
->lParam
;
562 data
->ps
.msg
.time
= msg
->time
;
563 data
->ps
.msg
.pt
= msg
->pt
;
564 push_data( data
, &data
->ps
.msg
, sizeof(data
->ps
.msg
) );
565 return sizeof(data
->ps
.msg
);
568 case SBM_SETSCROLLINFO
:
569 push_data( data
, (SCROLLINFO
*)lparam
, sizeof(SCROLLINFO
) );
571 case SBM_GETSCROLLINFO
:
572 push_data( data
, (SCROLLINFO
*)lparam
, sizeof(SCROLLINFO
) );
573 return sizeof(SCROLLINFO
);
574 case SBM_GETSCROLLBARINFO
:
576 const SCROLLBARINFO
*info
= (const SCROLLBARINFO
*)lparam
;
577 size_t size
= min( info
->cbSize
, sizeof(SCROLLBARINFO
) );
578 push_data( data
, info
, size
);
586 if (wparam
) size
+= sizeof(DWORD
);
587 if (lparam
) size
+= sizeof(DWORD
);
592 case CB_GETDROPPEDCONTROLRECT
:
596 push_data( data
, (RECT
*)lparam
, sizeof(RECT
) );
600 WORD
*pw
= (WORD
*)lparam
;
601 push_data( data
, pw
, sizeof(*pw
) );
602 return *pw
* sizeof(WCHAR
);
606 if (wparam
) push_data( data
, (UINT
*)lparam
, sizeof(UINT
) * wparam
);
609 case CB_INSERTSTRING
:
611 case CB_FINDSTRINGEXACT
:
612 case CB_SELECTSTRING
:
613 if (combobox_has_strings( hwnd
)) push_string( data
, (LPWSTR
)lparam
);
616 if (!combobox_has_strings( hwnd
)) return sizeof(ULONG_PTR
);
617 return (send_message( hwnd
, CB_GETLBTEXTLEN
, wparam
, 0 ) + 1) * sizeof(WCHAR
);
619 case LB_INSERTSTRING
:
621 case LB_FINDSTRINGEXACT
:
622 case LB_SELECTSTRING
:
623 if (listbox_has_strings( hwnd
)) push_string( data
, (LPWSTR
)lparam
);
626 if (!listbox_has_strings( hwnd
)) return sizeof(ULONG_PTR
);
627 return (send_message( hwnd
, LB_GETTEXTLEN
, wparam
, 0 ) + 1) * sizeof(WCHAR
);
629 return wparam
* sizeof(UINT
);
632 MDINEXTMENU
*mnm
= (MDINEXTMENU
*)lparam
;
633 data
->ps
.mnm
.hmenuIn
= wine_server_user_handle( mnm
->hmenuIn
);
634 data
->ps
.mnm
.hmenuNext
= wine_server_user_handle( mnm
->hmenuNext
);
635 data
->ps
.mnm
.hwndNext
= wine_server_user_handle( mnm
->hwndNext
);
636 push_data( data
, &data
->ps
.mnm
, sizeof(data
->ps
.mnm
) );
637 return sizeof(data
->ps
.mnm
);
641 push_data( data
, (RECT
*)lparam
, sizeof(RECT
) );
645 MDICREATESTRUCTW
*mcs
= (MDICREATESTRUCTW
*)lparam
;
646 data
->ps
.mcs
.szClass
= pack_ptr( mcs
->szClass
);
647 data
->ps
.mcs
.szTitle
= pack_ptr( mcs
->szTitle
);
648 data
->ps
.mcs
.hOwner
= pack_ptr( mcs
->hOwner
);
649 data
->ps
.mcs
.x
= mcs
->x
;
650 data
->ps
.mcs
.y
= mcs
->y
;
651 data
->ps
.mcs
.cx
= mcs
->cx
;
652 data
->ps
.mcs
.cy
= mcs
->cy
;
653 data
->ps
.mcs
.style
= mcs
->style
;
654 data
->ps
.mcs
.lParam
= mcs
->lParam
;
655 push_data( data
, &data
->ps
.mcs
, sizeof(data
->ps
.mcs
) );
656 if (!IS_INTRESOURCE(mcs
->szClass
)) push_string( data
, mcs
->szClass
);
657 if (!IS_INTRESOURCE(mcs
->szTitle
)) push_string( data
, mcs
->szTitle
);
658 return sizeof(data
->ps
.mcs
);
660 case WM_MDIGETACTIVE
:
661 if (lparam
) return sizeof(BOOL
);
663 case WM_DEVICECHANGE
:
665 DEV_BROADCAST_HDR
*header
= (DEV_BROADCAST_HDR
*)lparam
;
666 if ((wparam
& 0x8000) && header
) push_data( data
, header
, header
->dbch_size
);
669 case WM_WINE_KEYBOARD_LL_HOOK
:
671 struct hook_extra_info
*h_extra
= (struct hook_extra_info
*)lparam
;
672 data
->ps
.hook
.handle
= wine_server_user_handle( h_extra
->handle
);
673 push_data( data
, &data
->ps
.hook
, sizeof(data
->ps
.hook
) );
674 push_data( data
, (LPVOID
)h_extra
->lparam
, sizeof(KBDLLHOOKSTRUCT
) );
677 case WM_WINE_MOUSE_LL_HOOK
:
679 struct hook_extra_info
*h_extra
= (struct hook_extra_info
*)lparam
;
680 data
->ps
.hook
.handle
= wine_server_user_handle( h_extra
->handle
);
681 push_data( data
, &data
->ps
.hook
, sizeof(data
->ps
.hook
) );
682 push_data( data
, (LPVOID
)h_extra
->lparam
, sizeof(MSLLHOOKSTRUCT
) );
686 if (wparam
<= 1) return 0;
687 FIXME( "WM_NCPAINT hdc packing not supported yet\n" );
691 if (!wparam
) return 0;
694 /* these contain an HFONT */
697 /* these contain an HDC */
699 case WM_ICONERASEBKGND
:
700 case WM_CTLCOLORMSGBOX
:
701 case WM_CTLCOLOREDIT
:
702 case WM_CTLCOLORLISTBOX
:
705 case WM_CTLCOLORSCROLLBAR
:
706 case WM_CTLCOLORSTATIC
:
709 /* these contain an HGLOBAL */
710 case WM_PAINTCLIPBOARD
:
711 case WM_SIZECLIPBOARD
:
712 /* these contain HICON */
715 case WM_QUERYDRAGICON
:
716 case WM_QUERYPARKICON
:
717 /* these contain pointers */
719 case WM_QUERYDROPOBJECT
:
723 FIXME( "msg %x (%s) not supported yet\n", message
, debugstr_msg_name(message
, hwnd
) );
730 /***********************************************************************
733 * Pack a reply to a message for sending to another process.
735 static void pack_reply( HWND hwnd
, UINT message
, WPARAM wparam
, LPARAM lparam
,
736 LRESULT res
, struct packed_message
*data
)
744 CREATESTRUCTW
*cs
= (CREATESTRUCTW
*)lparam
;
745 data
->ps
.cs
.lpCreateParams
= (ULONG_PTR
)cs
->lpCreateParams
;
746 data
->ps
.cs
.hInstance
= (ULONG_PTR
)cs
->hInstance
;
747 data
->ps
.cs
.hMenu
= wine_server_user_handle( cs
->hMenu
);
748 data
->ps
.cs
.hwndParent
= wine_server_user_handle( cs
->hwndParent
);
749 data
->ps
.cs
.cy
= cs
->cy
;
750 data
->ps
.cs
.cx
= cs
->cx
;
751 data
->ps
.cs
.y
= cs
->y
;
752 data
->ps
.cs
.x
= cs
->x
;
753 data
->ps
.cs
.style
= cs
->style
;
754 data
->ps
.cs
.dwExStyle
= cs
->dwExStyle
;
755 data
->ps
.cs
.lpszName
= (ULONG_PTR
)cs
->lpszName
;
756 data
->ps
.cs
.lpszClass
= (ULONG_PTR
)cs
->lpszClass
;
757 push_data( data
, &data
->ps
.cs
, sizeof(data
->ps
.cs
) );
763 push_data( data
, (WCHAR
*)lparam
, (res
+ 1) * sizeof(WCHAR
) );
765 case WM_GETMINMAXINFO
:
766 push_data( data
, (MINMAXINFO
*)lparam
, sizeof(MINMAXINFO
) );
770 MEASUREITEMSTRUCT
*mis
= (MEASUREITEMSTRUCT
*)lparam
;
771 data
->ps
.mis
.CtlType
= mis
->CtlType
;
772 data
->ps
.mis
.CtlID
= mis
->CtlID
;
773 data
->ps
.mis
.itemID
= mis
->itemID
;
774 data
->ps
.mis
.itemWidth
= mis
->itemWidth
;
775 data
->ps
.mis
.itemHeight
= mis
->itemHeight
;
776 data
->ps
.mis
.itemData
= mis
->itemData
;
777 push_data( data
, &data
->ps
.mis
, sizeof(data
->ps
.mis
) );
780 case WM_WINDOWPOSCHANGING
:
781 case WM_WINDOWPOSCHANGED
:
783 WINDOWPOS
*wp
= (WINDOWPOS
*)lparam
;
784 data
->ps
.wp
.hwnd
= wine_server_user_handle( wp
->hwnd
);
785 data
->ps
.wp
.hwndInsertAfter
= wine_server_user_handle( wp
->hwndInsertAfter
);
786 data
->ps
.wp
.x
= wp
->x
;
787 data
->ps
.wp
.y
= wp
->y
;
788 data
->ps
.wp
.cx
= wp
->cx
;
789 data
->ps
.wp
.cy
= wp
->cy
;
790 data
->ps
.wp
.flags
= wp
->flags
;
791 push_data( data
, &data
->ps
.wp
, sizeof(data
->ps
.wp
) );
797 MSG
*msg
= (MSG
*)lparam
;
798 data
->ps
.msg
.hwnd
= wine_server_user_handle( msg
->hwnd
);
799 data
->ps
.msg
.message
= msg
->message
;
800 data
->ps
.msg
.wParam
= msg
->wParam
;
801 data
->ps
.msg
.lParam
= msg
->lParam
;
802 data
->ps
.msg
.time
= msg
->time
;
803 data
->ps
.msg
.pt
= msg
->pt
;
804 push_data( data
, &data
->ps
.msg
, sizeof(data
->ps
.msg
) );
807 case SBM_GETSCROLLINFO
:
808 push_data( data
, (SCROLLINFO
*)lparam
, sizeof(SCROLLINFO
) );
812 case CB_GETDROPPEDCONTROLRECT
:
815 push_data( data
, (RECT
*)lparam
, sizeof(RECT
) );
819 WORD
*ptr
= (WORD
*)lparam
;
820 push_data( data
, ptr
, ptr
[-1] * sizeof(WCHAR
) );
824 push_data( data
, (UINT
*)lparam
, wparam
* sizeof(UINT
) );
826 case WM_MDIGETACTIVE
:
827 if (lparam
) push_data( data
, (BOOL
*)lparam
, sizeof(BOOL
) );
831 push_data( data
, (RECT
*)lparam
, sizeof(RECT
) );
834 NCCALCSIZE_PARAMS
*ncp
= (NCCALCSIZE_PARAMS
*)lparam
;
835 data
->ps
.ncp
.rgrc
[0] = ncp
->rgrc
[0];
836 data
->ps
.ncp
.rgrc
[1] = ncp
->rgrc
[1];
837 data
->ps
.ncp
.rgrc
[2] = ncp
->rgrc
[2];
838 data
->ps
.ncp
.hwnd
= wine_server_user_handle( ncp
->lppos
->hwnd
);
839 data
->ps
.ncp
.hwndInsertAfter
= wine_server_user_handle( ncp
->lppos
->hwndInsertAfter
);
840 data
->ps
.ncp
.x
= ncp
->lppos
->x
;
841 data
->ps
.ncp
.y
= ncp
->lppos
->y
;
842 data
->ps
.ncp
.cx
= ncp
->lppos
->cx
;
843 data
->ps
.ncp
.cy
= ncp
->lppos
->cy
;
844 data
->ps
.ncp
.flags
= ncp
->lppos
->flags
;
845 push_data( data
, &data
->ps
.ncp
, sizeof(data
->ps
.ncp
) );
851 if (wparam
) push_data( data
, (DWORD
*)wparam
, sizeof(DWORD
) );
852 if (lparam
) push_data( data
, (DWORD
*)lparam
, sizeof(DWORD
) );
856 MDINEXTMENU
*mnm
= (MDINEXTMENU
*)lparam
;
857 data
->ps
.mnm
.hmenuIn
= wine_server_user_handle( mnm
->hmenuIn
);
858 data
->ps
.mnm
.hmenuNext
= wine_server_user_handle( mnm
->hmenuNext
);
859 data
->ps
.mnm
.hwndNext
= wine_server_user_handle( mnm
->hwndNext
);
860 push_data( data
, &data
->ps
.mnm
, sizeof(data
->ps
.mnm
) );
865 MDICREATESTRUCTW
*mcs
= (MDICREATESTRUCTW
*)lparam
;
866 data
->ps
.mcs
.szClass
= pack_ptr( mcs
->szClass
);
867 data
->ps
.mcs
.szTitle
= pack_ptr( mcs
->szTitle
);
868 data
->ps
.mcs
.hOwner
= pack_ptr( mcs
->hOwner
);
869 data
->ps
.mcs
.x
= mcs
->x
;
870 data
->ps
.mcs
.y
= mcs
->y
;
871 data
->ps
.mcs
.cx
= mcs
->cx
;
872 data
->ps
.mcs
.cy
= mcs
->cy
;
873 data
->ps
.mcs
.style
= mcs
->style
;
874 data
->ps
.mcs
.lParam
= mcs
->lParam
;
875 push_data( data
, &data
->ps
.mcs
, sizeof(data
->ps
.mcs
) );
878 case WM_ASKCBFORMATNAME
:
879 push_data( data
, (WCHAR
*)lparam
, (lstrlenW((WCHAR
*)lparam
) + 1) * sizeof(WCHAR
) );
884 /***********************************************************************
887 * Unpack a message reply received from another process.
889 static void unpack_reply( HWND hwnd
, UINT message
, WPARAM wparam
, LPARAM lparam
,
890 void *buffer
, size_t size
)
892 union packed_structs
*ps
= buffer
;
898 if (size
>= sizeof(ps
->cs
))
900 CREATESTRUCTW
*cs
= (CREATESTRUCTW
*)lparam
;
901 cs
->lpCreateParams
= unpack_ptr( ps
->cs
.lpCreateParams
);
902 cs
->hInstance
= unpack_ptr( ps
->cs
.hInstance
);
903 cs
->hMenu
= wine_server_ptr_handle( ps
->cs
.hMenu
);
904 cs
->hwndParent
= wine_server_ptr_handle( ps
->cs
.hwndParent
);
909 cs
->style
= ps
->cs
.style
;
910 cs
->dwExStyle
= ps
->cs
.dwExStyle
;
911 /* don't allow changing name and class pointers */
915 case WM_ASKCBFORMATNAME
:
916 memcpy( (WCHAR
*)lparam
, buffer
, min( wparam
*sizeof(WCHAR
), size
));
918 case WM_GETMINMAXINFO
:
919 memcpy( (MINMAXINFO
*)lparam
, buffer
, min( sizeof(MINMAXINFO
), size
));
922 if (size
>= sizeof(ps
->mis
))
924 MEASUREITEMSTRUCT
*mis
= (MEASUREITEMSTRUCT
*)lparam
;
925 mis
->CtlType
= ps
->mis
.CtlType
;
926 mis
->CtlID
= ps
->mis
.CtlID
;
927 mis
->itemID
= ps
->mis
.itemID
;
928 mis
->itemWidth
= ps
->mis
.itemWidth
;
929 mis
->itemHeight
= ps
->mis
.itemHeight
;
930 mis
->itemData
= (ULONG_PTR
)unpack_ptr( ps
->mis
.itemData
);
933 case WM_WINDOWPOSCHANGING
:
934 case WM_WINDOWPOSCHANGED
:
935 if (size
>= sizeof(ps
->wp
))
937 WINDOWPOS
*wp
= (WINDOWPOS
*)lparam
;
938 wp
->hwnd
= wine_server_ptr_handle( ps
->wp
.hwnd
);
939 wp
->hwndInsertAfter
= wine_server_ptr_handle( ps
->wp
.hwndInsertAfter
);
944 wp
->flags
= ps
->wp
.flags
;
948 if (lparam
&& size
>= sizeof(ps
->msg
))
950 MSG
*msg
= (MSG
*)lparam
;
951 msg
->hwnd
= wine_server_ptr_handle( ps
->msg
.hwnd
);
952 msg
->message
= ps
->msg
.message
;
953 msg
->wParam
= (ULONG_PTR
)unpack_ptr( ps
->msg
.wParam
);
954 msg
->lParam
= (ULONG_PTR
)unpack_ptr( ps
->msg
.lParam
);
955 msg
->time
= ps
->msg
.time
;
956 msg
->pt
= ps
->msg
.pt
;
959 case SBM_GETSCROLLINFO
:
960 memcpy( (SCROLLINFO
*)lparam
, buffer
, min( sizeof(SCROLLINFO
), size
));
962 case SBM_GETSCROLLBARINFO
:
963 memcpy( (SCROLLBARINFO
*)lparam
, buffer
, min( sizeof(SCROLLBARINFO
), size
));
966 case CB_GETDROPPEDCONTROLRECT
:
970 memcpy( (RECT
*)lparam
, buffer
, min( sizeof(RECT
), size
));
973 size
= min( size
, (size_t)*(WORD
*)lparam
);
974 memcpy( (WCHAR
*)lparam
, buffer
, size
);
977 memcpy( (UINT
*)lparam
, buffer
, min( wparam
*sizeof(UINT
), size
));
981 memcpy( (WCHAR
*)lparam
, buffer
, size
);
984 if (size
>= sizeof(ps
->mnm
))
986 MDINEXTMENU
*mnm
= (MDINEXTMENU
*)lparam
;
987 mnm
->hmenuIn
= wine_server_ptr_handle( ps
->mnm
.hmenuIn
);
988 mnm
->hmenuNext
= wine_server_ptr_handle( ps
->mnm
.hmenuNext
);
989 mnm
->hwndNext
= wine_server_ptr_handle( ps
->mnm
.hwndNext
);
992 case WM_MDIGETACTIVE
:
993 if (lparam
) memcpy( (BOOL
*)lparam
, buffer
, min( sizeof(BOOL
), size
));
997 memcpy( (RECT
*)lparam
, buffer
, min( sizeof(RECT
), size
));
998 else if (size
>= sizeof(ps
->ncp
))
1000 NCCALCSIZE_PARAMS
*ncp
= (NCCALCSIZE_PARAMS
*)lparam
;
1001 ncp
->rgrc
[0] = ps
->ncp
.rgrc
[0];
1002 ncp
->rgrc
[1] = ps
->ncp
.rgrc
[1];
1003 ncp
->rgrc
[2] = ps
->ncp
.rgrc
[2];
1004 ncp
->lppos
->hwnd
= wine_server_ptr_handle( ps
->ncp
.hwnd
);
1005 ncp
->lppos
->hwndInsertAfter
= wine_server_ptr_handle( ps
->ncp
.hwndInsertAfter
);
1006 ncp
->lppos
->x
= ps
->ncp
.x
;
1007 ncp
->lppos
->y
= ps
->ncp
.y
;
1008 ncp
->lppos
->cx
= ps
->ncp
.cx
;
1009 ncp
->lppos
->cy
= ps
->ncp
.cy
;
1010 ncp
->lppos
->flags
= ps
->ncp
.flags
;
1018 memcpy( (DWORD
*)wparam
, buffer
, min( sizeof(DWORD
), size
));
1019 if (size
<= sizeof(DWORD
)) break;
1020 size
-= sizeof(DWORD
);
1021 buffer
= (DWORD
*)buffer
+ 1;
1023 if (lparam
) memcpy( (DWORD
*)lparam
, buffer
, min( sizeof(DWORD
), size
));
1026 if (size
>= sizeof(ps
->mcs
))
1028 MDICREATESTRUCTW
*mcs
= (MDICREATESTRUCTW
*)lparam
;
1029 mcs
->hOwner
= unpack_ptr( ps
->mcs
.hOwner
);
1032 mcs
->cx
= ps
->mcs
.cx
;
1033 mcs
->cy
= ps
->mcs
.cy
;
1034 mcs
->style
= ps
->mcs
.style
;
1035 mcs
->lParam
= (LPARAM
)unpack_ptr( ps
->mcs
.lParam
);
1036 /* don't allow changing class and title pointers */
1040 ERR( "should not happen: unexpected message %x\n", message
);
1045 /***********************************************************************
1048 * Copy a message reply received from client.
1050 static void copy_reply( LRESULT result
, HWND hwnd
, UINT message
, WPARAM wparam
, LPARAM lparam
,
1051 WPARAM wparam_src
, LPARAM lparam_src
)
1053 size_t copy_size
= 0;
1060 CREATESTRUCTW
*dst
= (CREATESTRUCTW
*)lparam
;
1061 CREATESTRUCTW
*src
= (CREATESTRUCTW
*)lparam_src
;
1062 dst
->lpCreateParams
= src
->lpCreateParams
;
1063 dst
->hInstance
= src
->hInstance
;
1064 dst
->hMenu
= src
->hMenu
;
1065 dst
->hwndParent
= src
->hwndParent
;
1070 dst
->style
= src
->style
;
1071 dst
->dwExStyle
= src
->dwExStyle
;
1072 /* don't allow changing name and class pointers */
1078 copy_size
= (result
+ 1) * sizeof(WCHAR
);
1080 case WM_GETMINMAXINFO
:
1081 copy_size
= sizeof(MINMAXINFO
);
1083 case WM_MEASUREITEM
:
1084 copy_size
= sizeof(MEASUREITEMSTRUCT
);
1086 case WM_WINDOWPOSCHANGING
:
1087 case WM_WINDOWPOSCHANGED
:
1088 copy_size
= sizeof(WINDOWPOS
);
1090 case WM_STYLECHANGING
:
1091 copy_size
= sizeof(STYLESTRUCT
);
1094 if (lparam
) copy_size
= sizeof(MSG
);
1096 case SBM_GETSCROLLINFO
:
1097 copy_size
= sizeof(SCROLLINFO
);
1099 case SBM_GETSCROLLBARINFO
:
1100 copy_size
= sizeof(SCROLLBARINFO
);
1103 case LB_GETITEMRECT
:
1104 case CB_GETDROPPEDCONTROLRECT
:
1107 copy_size
= sizeof(RECT
);
1111 WORD
*ptr
= (WORD
*)lparam
;
1112 copy_size
= ptr
[-1] * sizeof(WCHAR
);
1115 case LB_GETSELITEMS
:
1116 copy_size
= wparam
* sizeof(UINT
);
1118 case WM_MDIGETACTIVE
:
1119 if (lparam
) copy_size
= sizeof(BOOL
);
1124 NCCALCSIZE_PARAMS
*dst
= (NCCALCSIZE_PARAMS
*)lparam
;
1125 NCCALCSIZE_PARAMS
*src
= (NCCALCSIZE_PARAMS
*)lparam_src
;
1126 dst
->rgrc
[0] = src
->rgrc
[0];
1127 dst
->rgrc
[1] = src
->rgrc
[1];
1128 dst
->rgrc
[2] = src
->rgrc
[2];
1129 *dst
->lppos
= *src
->lppos
;
1132 copy_size
= sizeof(RECT
);
1137 if (wparam
) *(DWORD
*)wparam
= *(DWORD
*)wparam_src
;
1138 if (lparam
) copy_size
= sizeof(DWORD
);
1141 copy_size
= sizeof(MDINEXTMENU
);
1144 copy_size
= sizeof(MDICREATESTRUCTW
);
1146 case WM_ASKCBFORMATNAME
:
1147 copy_size
= (lstrlenW((WCHAR
*)lparam
) + 1) * sizeof(WCHAR
);
1153 if (copy_size
) memcpy( (void *)lparam
, (void *)lparam_src
, copy_size
);
1156 /***********************************************************************
1159 * Send a reply to a sent message.
1161 static void reply_message( struct received_message_info
*info
, LRESULT result
, MSG
*msg
)
1163 struct packed_message data
;
1164 int i
, replied
= info
->flags
& ISMEX_REPLIED
;
1165 BOOL remove
= msg
!= NULL
;
1167 if (info
->flags
& ISMEX_NOTIFY
) return; /* notify messages don't get replies */
1168 if (!remove
&& replied
) return; /* replied already */
1170 memset( &data
, 0, sizeof(data
) );
1171 info
->flags
|= ISMEX_REPLIED
;
1172 if (info
== get_user_thread_info()->receive_info
)
1173 NtUserGetThreadInfo()->receive_flags
= info
->flags
;
1175 if (info
->type
== MSG_OTHER_PROCESS
&& !replied
)
1177 if (!msg
) msg
= &info
->msg
;
1178 pack_reply( msg
->hwnd
, msg
->message
, msg
->wParam
, msg
->lParam
, result
, &data
);
1181 SERVER_START_REQ( reply_message
)
1183 req
->result
= result
;
1184 req
->remove
= remove
;
1185 for (i
= 0; i
< data
.count
; i
++) wine_server_add_data( req
, data
.data
[i
], data
.size
[i
] );
1186 wine_server_call( req
);
1191 /***********************************************************************
1192 * reply_message_result
1194 * Send a reply to a sent message and update thread receive info.
1196 BOOL
reply_message_result( LRESULT result
)
1198 struct user_thread_info
*thread_info
= get_user_thread_info();
1199 struct received_message_info
*info
= thread_info
->receive_info
;
1201 while (info
&& info
->type
== MSG_CLIENT_MESSAGE
) info
= info
->prev
;
1202 if (!info
) return FALSE
;
1203 reply_message( info
, result
, NULL
);
1207 /***********************************************************************
1208 * reply_winproc_result
1210 * Send a reply to a sent message and update thread receive info.
1212 static BOOL
reply_winproc_result( LRESULT result
, HWND hwnd
, UINT message
, WPARAM wparam
, LPARAM lparam
)
1214 struct user_thread_info
*thread_info
= get_user_thread_info();
1215 struct received_message_info
*info
= thread_info
->receive_info
;
1218 if (!info
) return FALSE
;
1220 if (info
->type
== MSG_CLIENT_MESSAGE
)
1222 copy_reply( result
, hwnd
, message
, info
->msg
.wParam
, info
->msg
.lParam
, wparam
, lparam
);
1223 info
->result
= result
;
1228 msg
.message
= message
;
1229 msg
.wParam
= wparam
;
1230 msg
.lParam
= lparam
;
1231 reply_message( info
, result
, &msg
);
1233 thread_info
->receive_info
= info
->prev
;
1234 thread_info
->client_info
.receive_flags
= info
->prev
? info
->prev
->flags
: ISMEX_NOSEND
;
1238 /***********************************************************************
1239 * handle_internal_message
1241 * Handle an internal Wine message instead of calling the window proc.
1243 static LRESULT
handle_internal_message( HWND hwnd
, UINT msg
, WPARAM wparam
, LPARAM lparam
)
1247 case WM_WINE_DESTROYWINDOW
:
1248 return destroy_window( hwnd
);
1249 case WM_WINE_SETWINDOWPOS
:
1250 if (is_desktop_window( hwnd
)) return 0;
1251 return set_window_pos( (WINDOWPOS
*)lparam
, 0, 0 );
1252 case WM_WINE_SHOWWINDOW
:
1253 if (is_desktop_window( hwnd
)) return 0;
1254 return NtUserShowWindow( hwnd
, wparam
);
1255 case WM_WINE_SETPARENT
:
1256 if (is_desktop_window( hwnd
)) return 0;
1257 return HandleToUlong( NtUserSetParent( hwnd
, UlongToHandle(wparam
) ));
1258 case WM_WINE_SETWINDOWLONG
:
1259 return set_window_long( hwnd
, (short)LOWORD(wparam
), HIWORD(wparam
), lparam
, FALSE
);
1260 case WM_WINE_SETSTYLE
:
1261 if (is_desktop_window( hwnd
)) return 0;
1262 return set_window_style( hwnd
, wparam
, lparam
);
1263 case WM_WINE_SETACTIVEWINDOW
:
1264 if (!wparam
&& NtUserGetForegroundWindow() == hwnd
) return 0;
1265 return (LRESULT
)NtUserSetActiveWindow( (HWND
)wparam
);
1266 case WM_WINE_KEYBOARD_LL_HOOK
:
1267 case WM_WINE_MOUSE_LL_HOOK
:
1269 struct hook_extra_info
*h_extra
= (struct hook_extra_info
*)lparam
;
1271 return call_current_hook( h_extra
->handle
, HC_ACTION
, wparam
, h_extra
->lparam
);
1273 case WM_WINE_CLIPCURSOR
:
1277 get_clip_cursor( &rect
);
1278 return user_driver
->pClipCursor( &rect
);
1280 return user_driver
->pClipCursor( NULL
);
1281 case WM_WINE_UPDATEWINDOWSTATE
:
1282 update_window_state( hwnd
);
1285 if (msg
>= WM_WINE_FIRST_DRIVER_MSG
&& msg
<= WM_WINE_LAST_DRIVER_MSG
)
1286 return user_driver
->pWindowMessage( hwnd
, msg
, wparam
, lparam
);
1287 FIXME( "unknown internal message %x\n", msg
);
1292 /**********************************************************************
1293 * NtUserGetGUIThreadInfo (win32u.@)
1295 BOOL WINAPI
NtUserGetGUIThreadInfo( DWORD id
, GUITHREADINFO
*info
)
1299 if (info
->cbSize
!= sizeof(*info
))
1301 RtlSetLastWin32Error( ERROR_INVALID_PARAMETER
);
1305 SERVER_START_REQ( get_thread_input
)
1308 if ((ret
= !wine_server_call_err( req
)))
1311 info
->hwndActive
= wine_server_ptr_handle( reply
->active
);
1312 info
->hwndFocus
= wine_server_ptr_handle( reply
->focus
);
1313 info
->hwndCapture
= wine_server_ptr_handle( reply
->capture
);
1314 info
->hwndMenuOwner
= wine_server_ptr_handle( reply
->menu_owner
);
1315 info
->hwndMoveSize
= wine_server_ptr_handle( reply
->move_size
);
1316 info
->hwndCaret
= wine_server_ptr_handle( reply
->caret
);
1317 info
->rcCaret
.left
= reply
->rect
.left
;
1318 info
->rcCaret
.top
= reply
->rect
.top
;
1319 info
->rcCaret
.right
= reply
->rect
.right
;
1320 info
->rcCaret
.bottom
= reply
->rect
.bottom
;
1321 if (reply
->menu_owner
) info
->flags
|= GUI_INMENUMODE
;
1322 if (reply
->move_size
) info
->flags
|= GUI_INMOVESIZE
;
1323 if (reply
->caret
) info
->flags
|= GUI_CARETBLINKING
;
1330 /***********************************************************************
1333 * Call a window procedure and the corresponding hooks.
1335 static LRESULT
call_window_proc( HWND hwnd
, UINT msg
, WPARAM wparam
, LPARAM lparam
,
1336 BOOL unicode
, BOOL same_thread
, enum wm_char_mapping mapping
,
1337 BOOL needs_unpack
, void *buffer
, size_t size
)
1339 struct win_proc_params p
, *params
= &p
;
1342 CWPRETSTRUCT cwpret
;
1344 if (msg
& 0x80000000)
1345 return handle_internal_message( hwnd
, msg
, wparam
, lparam
);
1347 if (!needs_unpack
) size
= 0;
1348 if (!is_current_thread_window( hwnd
)) return 0;
1349 if (size
&& !(params
= malloc( sizeof(*params
) + size
))) return 0;
1350 if (!init_window_call_params( params
, hwnd
, msg
, wparam
, lparam
, &result
, !unicode
, mapping
))
1352 if (params
!= &p
) free( params
);
1358 params
->needs_unpack
= TRUE
;
1359 params
->ansi
= FALSE
;
1360 if (size
) memcpy( params
+ 1, buffer
, size
);
1363 /* first the WH_CALLWNDPROC hook */
1364 cwp
.lParam
= lparam
;
1365 cwp
.wParam
= wparam
;
1367 cwp
.hwnd
= params
->hwnd
;
1368 call_hooks( WH_CALLWNDPROC
, HC_ACTION
, same_thread
, (LPARAM
)&cwp
, sizeof(cwp
) );
1370 dispatch_win_proc_params( params
, sizeof(*params
) + size
);
1371 if (params
!= &p
) free( params
);
1373 /* and finally the WH_CALLWNDPROCRET hook */
1374 cwpret
.lResult
= result
;
1375 cwpret
.lParam
= lparam
;
1376 cwpret
.wParam
= wparam
;
1377 cwpret
.message
= msg
;
1378 cwpret
.hwnd
= params
->hwnd
;
1379 call_hooks( WH_CALLWNDPROCRET
, HC_ACTION
, same_thread
, (LPARAM
)&cwpret
, sizeof(cwpret
) );
1383 /***********************************************************************
1384 * call_sendmsg_callback
1386 * Call the callback function of SendMessageCallback.
1388 static inline void call_sendmsg_callback( SENDASYNCPROC callback
, HWND hwnd
, UINT msg
,
1389 ULONG_PTR data
, LRESULT result
)
1391 struct send_async_params params
;
1395 if (!callback
) return;
1397 params
.callback
= callback
;
1401 params
.result
= result
;
1403 TRACE_(relay
)( "\1Call message callback %p (hwnd=%p,msg=%s,data=%08lx,result=%08lx)\n",
1404 callback
, hwnd
, debugstr_msg_name( msg
, hwnd
), data
, result
);
1406 KeUserModeCallback( NtUserCallSendAsyncCallback
, ¶ms
, sizeof(params
), &ret_ptr
, &ret_len
);
1408 TRACE_(relay
)( "\1Ret message callback %p (hwnd=%p,msg=%s,data=%08lx,result=%08lx)\n",
1409 callback
, hwnd
, debugstr_msg_name( msg
, hwnd
), data
, result
);
1412 /***********************************************************************
1413 * accept_hardware_message
1415 * Tell the server we have passed the message to the app
1416 * (even though we may end up dropping it later on)
1418 static void accept_hardware_message( UINT hw_id
)
1420 SERVER_START_REQ( accept_hardware_message
)
1423 if (wine_server_call( req
))
1424 FIXME("Failed to reply to MSG_HARDWARE message. Message may not be removed from queue.\n");
1429 /***********************************************************************
1430 * send_parent_notify
1432 * Send a WM_PARENTNOTIFY to all ancestors of the given window, unless
1433 * the window has the WS_EX_NOPARENTNOTIFY style.
1435 static void send_parent_notify( HWND hwnd
, WORD event
, WORD idChild
, POINT pt
)
1437 /* pt has to be in the client coordinates of the parent window */
1438 map_window_points( 0, hwnd
, &pt
, 1, get_thread_dpi() );
1443 if (!(get_window_long( hwnd
, GWL_STYLE
) & WS_CHILD
)) break;
1444 if (get_window_long( hwnd
, GWL_EXSTYLE
) & WS_EX_NOPARENTNOTIFY
) break;
1445 if (!(parent
= get_parent( hwnd
))) break;
1446 if (parent
== get_desktop_window()) break;
1447 map_window_points( hwnd
, parent
, &pt
, 1, get_thread_dpi() );
1449 send_message( hwnd
, WM_PARENTNOTIFY
,
1450 MAKEWPARAM( event
, idChild
), MAKELPARAM( pt
.x
, pt
.y
) );
1454 /***********************************************************************
1455 * process_keyboard_message
1457 * returns TRUE if the contents of 'msg' should be passed to the application
1459 static BOOL
process_keyboard_message( MSG
*msg
, UINT hw_id
, HWND hwnd_filter
,
1460 UINT first
, UINT last
, BOOL remove
)
1464 if (msg
->message
== WM_KEYDOWN
|| msg
->message
== WM_SYSKEYDOWN
||
1465 msg
->message
== WM_KEYUP
|| msg
->message
== WM_SYSKEYUP
)
1466 switch (msg
->wParam
)
1468 case VK_LSHIFT
: case VK_RSHIFT
:
1469 msg
->wParam
= VK_SHIFT
;
1471 case VK_LCONTROL
: case VK_RCONTROL
:
1472 msg
->wParam
= VK_CONTROL
;
1474 case VK_LMENU
: case VK_RMENU
:
1475 msg
->wParam
= VK_MENU
;
1479 /* FIXME: is this really the right place for this hook? */
1480 event
.message
= msg
->message
;
1481 event
.hwnd
= msg
->hwnd
;
1482 event
.time
= msg
->time
;
1483 event
.paramL
= (msg
->wParam
& 0xFF) | (HIWORD(msg
->lParam
) << 8);
1484 event
.paramH
= msg
->lParam
& 0x7FFF;
1485 if (HIWORD(msg
->lParam
) & 0x0100) event
.paramH
|= 0x8000; /* special_key - bit */
1486 call_hooks( WH_JOURNALRECORD
, HC_ACTION
, 0, (LPARAM
)&event
, sizeof(event
) );
1488 /* check message filters */
1489 if (msg
->message
< first
|| msg
->message
> last
) return FALSE
;
1490 if (!check_hwnd_filter( msg
, hwnd_filter
)) return FALSE
;
1494 if((msg
->message
== WM_KEYDOWN
) &&
1495 (msg
->hwnd
!= get_desktop_window()))
1497 /* Handle F1 key by sending out WM_HELP message */
1498 if (msg
->wParam
== VK_F1
)
1500 NtUserPostMessage( msg
->hwnd
, WM_KEYF1
, 0, 0 );
1502 else if(msg
->wParam
>= VK_BROWSER_BACK
&&
1503 msg
->wParam
<= VK_LAUNCH_APP2
)
1505 /* FIXME: Process keystate */
1506 send_message( msg
->hwnd
, WM_APPCOMMAND
, (WPARAM
)msg
->hwnd
,
1507 MAKELPARAM(0, (FAPPCOMMAND_KEY
| (msg
->wParam
- VK_BROWSER_BACK
+ 1))) );
1510 else if (msg
->message
== WM_KEYUP
)
1512 /* Handle VK_APPS key by posting a WM_CONTEXTMENU message */
1513 if (msg
->wParam
== VK_APPS
&& !is_menu_active())
1514 NtUserPostMessage( msg
->hwnd
, WM_CONTEXTMENU
, (WPARAM
)msg
->hwnd
, -1 );
1518 if (call_hooks( WH_KEYBOARD
, remove
? HC_ACTION
: HC_NOREMOVE
,
1519 LOWORD(msg
->wParam
), msg
->lParam
, 0 ))
1521 /* skip this message */
1522 call_hooks( WH_CBT
, HCBT_KEYSKIPPED
, LOWORD(msg
->wParam
), msg
->lParam
, 0 );
1523 accept_hardware_message( hw_id
);
1526 if (remove
) accept_hardware_message( hw_id
);
1527 msg
->pt
= point_phys_to_win_dpi( msg
->hwnd
, msg
->pt
);
1529 if (remove
&& msg
->message
== WM_KEYDOWN
)
1530 if (ImmProcessKey( msg
->hwnd
, NtUserGetKeyboardLayout(0), msg
->wParam
, msg
->lParam
, 0 ))
1531 msg
->wParam
= VK_PROCESSKEY
;
1536 /***********************************************************************
1537 * process_mouse_message
1539 * returns TRUE if the contents of 'msg' should be passed to the application
1541 static BOOL
process_mouse_message( MSG
*msg
, UINT hw_id
, ULONG_PTR extra_info
, HWND hwnd_filter
,
1542 UINT first
, UINT last
, BOOL remove
)
1551 MOUSEHOOKSTRUCTEX hook
;
1555 /* find the window to dispatch this mouse message to */
1557 info
.cbSize
= sizeof(info
);
1558 NtUserGetGUIThreadInfo( GetCurrentThreadId(), &info
);
1559 if (info
.hwndCapture
)
1562 msg
->hwnd
= info
.hwndCapture
;
1566 HWND orig
= msg
->hwnd
;
1568 msg
->hwnd
= window_from_point( msg
->hwnd
, msg
->pt
, &hittest
);
1569 if (!msg
->hwnd
) /* As a heuristic, try the next window if it's the owner of orig */
1571 HWND next
= get_window_relative( orig
, GW_HWNDNEXT
);
1573 if (next
&& get_window_relative( orig
, GW_OWNER
) == next
&&
1574 is_current_thread_window( next
))
1575 msg
->hwnd
= window_from_point( next
, msg
->pt
, &hittest
);
1579 if (!msg
->hwnd
|| !is_current_thread_window( msg
->hwnd
))
1581 accept_hardware_message( hw_id
);
1585 msg
->pt
= point_phys_to_win_dpi( msg
->hwnd
, msg
->pt
);
1586 SetThreadDpiAwarenessContext( get_window_dpi_awareness_context( msg
->hwnd
));
1588 /* FIXME: is this really the right place for this hook? */
1589 event
.message
= msg
->message
;
1590 event
.time
= msg
->time
;
1591 event
.hwnd
= msg
->hwnd
;
1592 event
.paramL
= msg
->pt
.x
;
1593 event
.paramH
= msg
->pt
.y
;
1594 call_hooks( WH_JOURNALRECORD
, HC_ACTION
, 0, (LPARAM
)&event
, sizeof(event
) );
1596 if (!check_hwnd_filter( msg
, hwnd_filter
)) return FALSE
;
1599 message
= msg
->message
;
1600 wparam
= msg
->wParam
;
1601 /* Note: windows has no concept of a non-client wheel message */
1602 if (message
!= WM_MOUSEWHEEL
)
1604 if (hittest
!= HTCLIENT
)
1606 message
+= WM_NCMOUSEMOVE
- WM_MOUSEMOVE
;
1611 /* coordinates don't get translated while tracking a menu */
1612 /* FIXME: should differentiate popups and top-level menus */
1613 if (!(info
.flags
& GUI_INMENUMODE
))
1614 screen_to_client( msg
->hwnd
, &pt
);
1617 msg
->lParam
= MAKELONG( pt
.x
, pt
.y
);
1619 /* translate double clicks */
1621 if (msg
->message
== WM_LBUTTONDOWN
||
1622 msg
->message
== WM_RBUTTONDOWN
||
1623 msg
->message
== WM_MBUTTONDOWN
||
1624 msg
->message
== WM_XBUTTONDOWN
)
1626 BOOL update
= remove
;
1628 /* translate double clicks -
1629 * note that ...MOUSEMOVEs can slip in between
1630 * ...BUTTONDOWN and ...BUTTONDBLCLK messages */
1632 if ((info
.flags
& (GUI_INMENUMODE
|GUI_INMOVESIZE
)) ||
1633 hittest
!= HTCLIENT
||
1634 (get_class_long( msg
->hwnd
, GCL_STYLE
, FALSE
) & CS_DBLCLKS
))
1636 if ((msg
->message
== clk_msg
.message
) &&
1637 (msg
->hwnd
== clk_msg
.hwnd
) &&
1638 (msg
->wParam
== clk_msg
.wParam
) &&
1639 (msg
->time
- clk_msg
.time
< NtUserGetDoubleClickTime()) &&
1640 (abs(msg
->pt
.x
- clk_msg
.pt
.x
) < get_system_metrics( SM_CXDOUBLECLK
) / 2) &&
1641 (abs(msg
->pt
.y
- clk_msg
.pt
.y
) < get_system_metrics( SM_CYDOUBLECLK
) / 2))
1643 message
+= (WM_LBUTTONDBLCLK
- WM_LBUTTONDOWN
);
1646 clk_msg
.message
= 0; /* clear the double click conditions */
1651 if (message
< first
|| message
> last
) return FALSE
;
1652 /* update static double click conditions */
1653 if (update
) clk_msg
= *msg
;
1657 if (message
< first
|| message
> last
) return FALSE
;
1659 msg
->wParam
= wparam
;
1661 /* message is accepted now (but may still get dropped) */
1664 hook
.hwnd
= msg
->hwnd
;
1665 hook
.wHitTestCode
= hittest
;
1666 hook
.dwExtraInfo
= extra_info
;
1667 hook
.mouseData
= msg
->wParam
;
1668 if (call_hooks( WH_MOUSE
, remove
? HC_ACTION
: HC_NOREMOVE
, message
, (LPARAM
)&hook
, sizeof(hook
) ))
1671 hook
.hwnd
= msg
->hwnd
;
1672 hook
.wHitTestCode
= hittest
;
1673 hook
.dwExtraInfo
= extra_info
;
1674 hook
.mouseData
= msg
->wParam
;
1675 call_hooks( WH_CBT
, HCBT_CLICKSKIPPED
, message
, (LPARAM
)&hook
, sizeof(hook
) );
1676 accept_hardware_message( hw_id
);
1680 if ((hittest
== HTERROR
) || (hittest
== HTNOWHERE
))
1682 send_message( msg
->hwnd
, WM_SETCURSOR
, (WPARAM
)msg
->hwnd
, MAKELONG( hittest
, msg
->message
));
1683 accept_hardware_message( hw_id
);
1687 if (remove
) accept_hardware_message( hw_id
);
1689 if (!remove
|| info
.hwndCapture
)
1691 msg
->message
= message
;
1697 if (msg
->message
== WM_LBUTTONDOWN
||
1698 msg
->message
== WM_RBUTTONDOWN
||
1699 msg
->message
== WM_MBUTTONDOWN
||
1700 msg
->message
== WM_XBUTTONDOWN
)
1702 /* Send the WM_PARENTNOTIFY,
1703 * note that even for double/nonclient clicks
1704 * notification message is still WM_L/M/RBUTTONDOWN.
1706 send_parent_notify( msg
->hwnd
, msg
->message
, 0, msg
->pt
);
1708 /* Activate the window if needed */
1710 if (msg
->hwnd
!= info
.hwndActive
)
1712 HWND hwndTop
= NtUserGetAncestor( msg
->hwnd
, GA_ROOT
);
1714 if ((get_window_long( hwndTop
, GWL_STYLE
) & (WS_POPUP
|WS_CHILD
)) != WS_CHILD
)
1716 LONG ret
= send_message( msg
->hwnd
, WM_MOUSEACTIVATE
, (WPARAM
)hwndTop
,
1717 MAKELONG( hittest
, msg
->message
) );
1720 case MA_NOACTIVATEANDEAT
:
1725 case MA_ACTIVATEANDEAT
:
1730 if (!set_foreground_window( hwndTop
, TRUE
)) eat_msg
= TRUE
;
1733 WARN( "unknown WM_MOUSEACTIVATE code %d\n", ret
);
1740 /* send the WM_SETCURSOR message */
1742 /* Windows sends the normal mouse message as the message parameter
1743 in the WM_SETCURSOR message even if it's non-client mouse message */
1744 send_message( msg
->hwnd
, WM_SETCURSOR
, (WPARAM
)msg
->hwnd
, MAKELONG( hittest
, msg
->message
));
1746 msg
->message
= message
;
1750 /***********************************************************************
1751 * process_hardware_message
1753 * Process a hardware message; return TRUE if message should be passed on to the app
1755 static BOOL
process_hardware_message( MSG
*msg
, UINT hw_id
, const struct hardware_msg_data
*msg_data
,
1756 HWND hwnd_filter
, UINT first
, UINT last
, BOOL remove
)
1758 struct ntuser_thread_info
*thread_info
= NtUserGetThreadInfo();
1759 DPI_AWARENESS_CONTEXT context
;
1762 thread_info
->msg_source
.deviceType
= msg_data
->source
.device
;
1763 thread_info
->msg_source
.originId
= msg_data
->source
.origin
;
1765 /* hardware messages are always in physical coords */
1766 context
= SetThreadDpiAwarenessContext( DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE
);
1768 if (msg
->message
== WM_INPUT
|| msg
->message
== WM_INPUT_DEVICE_CHANGE
)
1769 ret
= process_rawinput_message( msg
, hw_id
, msg_data
);
1770 else if (is_keyboard_message( msg
->message
))
1771 ret
= process_keyboard_message( msg
, hw_id
, hwnd_filter
, first
, last
, remove
);
1772 else if (is_mouse_message( msg
->message
))
1773 ret
= process_mouse_message( msg
, hw_id
, msg_data
->info
, hwnd_filter
, first
, last
, remove
);
1775 ERR( "unknown message type %x\n", msg
->message
);
1776 SetThreadDpiAwarenessContext( context
);
1780 /***********************************************************************
1783 * Peek for a message matching the given parameters. Return 0 if none are
1784 * available; -1 on error.
1785 * All pending sent messages are processed before returning.
1787 static int peek_message( MSG
*msg
, HWND hwnd
, UINT first
, UINT last
, UINT flags
, UINT changed_mask
)
1790 struct user_thread_info
*thread_info
= get_user_thread_info();
1791 INPUT_MESSAGE_SOURCE prev_source
= thread_info
->client_info
.msg_source
;
1792 struct received_message_info info
;
1793 unsigned int hw_id
= 0; /* id of previous hardware message */
1795 size_t buffer_size
= 1024;
1797 if (!(buffer
= malloc( buffer_size
))) return -1;
1799 if (!first
&& !last
) last
= ~0;
1800 if (hwnd
== HWND_BROADCAST
) hwnd
= HWND_TOPMOST
;
1806 const message_data_t
*msg_data
= buffer
;
1807 BOOL needs_unpack
= FALSE
;
1809 thread_info
->client_info
.msg_source
= prev_source
;
1811 SERVER_START_REQ( get_message
)
1814 req
->get_win
= wine_server_user_handle( hwnd
);
1815 req
->get_first
= first
;
1816 req
->get_last
= last
;
1818 req
->wake_mask
= changed_mask
& (QS_SENDMESSAGE
| QS_SMRESULT
);
1819 req
->changed_mask
= changed_mask
;
1820 wine_server_set_reply( req
, buffer
, buffer_size
);
1821 if (!(res
= wine_server_call( req
)))
1823 size
= wine_server_reply_size( reply
);
1824 info
.type
= reply
->type
;
1825 info
.msg
.hwnd
= wine_server_ptr_handle( reply
->win
);
1826 info
.msg
.message
= reply
->msg
;
1827 info
.msg
.wParam
= reply
->wparam
;
1828 info
.msg
.lParam
= reply
->lparam
;
1829 info
.msg
.time
= reply
->time
;
1830 info
.msg
.pt
.x
= reply
->x
;
1831 info
.msg
.pt
.y
= reply
->y
;
1833 thread_info
->active_hooks
= reply
->active_hooks
;
1835 else buffer_size
= reply
->total
;
1842 if (res
== STATUS_PENDING
)
1844 thread_info
->wake_mask
= changed_mask
& (QS_SENDMESSAGE
| QS_SMRESULT
);
1845 thread_info
->changed_mask
= changed_mask
;
1848 if (res
!= STATUS_BUFFER_OVERFLOW
)
1850 RtlSetLastWin32Error( RtlNtStatusToDosError(res
) );
1853 if (!(buffer
= malloc( buffer_size
))) return -1;
1857 TRACE( "got type %d msg %x (%s) hwnd %p wp %lx lp %lx\n",
1858 info
.type
, info
.msg
.message
,
1859 (info
.type
== MSG_WINEVENT
) ? "MSG_WINEVENT" : debugstr_msg_name(info
.msg
.message
, info
.msg
.hwnd
),
1860 info
.msg
.hwnd
, info
.msg
.wParam
, info
.msg
.lParam
);
1866 info
.flags
= ISMEX_SEND
;
1869 info
.flags
= ISMEX_NOTIFY
;
1870 if (!unpack_message( info
.msg
.hwnd
, info
.msg
.message
, &info
.msg
.wParam
,
1871 &info
.msg
.lParam
, &buffer
, size
))
1873 needs_unpack
= TRUE
;
1876 info
.flags
= ISMEX_CALLBACK
;
1878 case MSG_CALLBACK_RESULT
:
1879 if (size
>= sizeof(msg_data
->callback
))
1880 call_sendmsg_callback( wine_server_get_ptr(msg_data
->callback
.callback
),
1881 info
.msg
.hwnd
, info
.msg
.message
,
1882 msg_data
->callback
.data
, msg_data
->callback
.result
);
1885 if (size
>= sizeof(msg_data
->winevent
))
1887 struct win_event_hook_params params
;
1891 params
.proc
= wine_server_get_ptr( msg_data
->winevent
.hook_proc
);
1892 size
-= sizeof(msg_data
->winevent
);
1895 size
= min( size
, sizeof(params
.module
) - sizeof(WCHAR
) );
1896 memcpy( params
.module
, &msg_data
->winevent
+ 1, size
);
1898 params
.module
[size
/ sizeof(WCHAR
)] = 0;
1899 size
= FIELD_OFFSET( struct win_event_hook_params
, module
[size
/ sizeof(WCHAR
) + 1] );
1901 params
.handle
= wine_server_ptr_handle( msg_data
->winevent
.hook
);
1902 params
.event
= info
.msg
.message
;
1903 params
.hwnd
= info
.msg
.hwnd
;
1904 params
.object_id
= info
.msg
.wParam
;
1905 params
.child_id
= info
.msg
.lParam
;
1906 params
.tid
= msg_data
->winevent
.tid
;
1907 params
.time
= info
.msg
.time
;
1909 KeUserModeCallback( NtUserCallWinEventHook
, ¶ms
, size
, &ret_ptr
, &ret_len
);
1913 info
.flags
= ISMEX_SEND
;
1915 if (info
.msg
.message
== WH_KEYBOARD_LL
&& size
>= sizeof(msg_data
->hardware
))
1917 KBDLLHOOKSTRUCT hook
;
1919 hook
.vkCode
= LOWORD( info
.msg
.lParam
);
1920 hook
.scanCode
= HIWORD( info
.msg
.lParam
);
1921 hook
.flags
= msg_data
->hardware
.flags
;
1922 hook
.time
= info
.msg
.time
;
1923 hook
.dwExtraInfo
= msg_data
->hardware
.info
;
1924 TRACE( "calling keyboard LL hook vk %x scan %x flags %x time %u info %lx\n",
1925 hook
.vkCode
, hook
.scanCode
, hook
.flags
, hook
.time
, hook
.dwExtraInfo
);
1926 result
= call_hooks( WH_KEYBOARD_LL
, HC_ACTION
, info
.msg
.wParam
,
1927 (LPARAM
)&hook
, sizeof(hook
) );
1929 else if (info
.msg
.message
== WH_MOUSE_LL
&& size
>= sizeof(msg_data
->hardware
))
1931 MSLLHOOKSTRUCT hook
;
1933 hook
.pt
= info
.msg
.pt
;
1934 hook
.mouseData
= info
.msg
.lParam
;
1935 hook
.flags
= msg_data
->hardware
.flags
;
1936 hook
.time
= info
.msg
.time
;
1937 hook
.dwExtraInfo
= msg_data
->hardware
.info
;
1938 TRACE( "calling mouse LL hook pos %d,%d data %x flags %x time %u info %lx\n",
1939 hook
.pt
.x
, hook
.pt
.y
, hook
.mouseData
, hook
.flags
, hook
.time
, hook
.dwExtraInfo
);
1940 result
= call_hooks( WH_MOUSE_LL
, HC_ACTION
, info
.msg
.wParam
,
1941 (LPARAM
)&hook
, sizeof(hook
) );
1943 reply_message( &info
, result
, &info
.msg
);
1945 case MSG_OTHER_PROCESS
:
1946 info
.flags
= ISMEX_SEND
;
1947 if (!unpack_message( info
.msg
.hwnd
, info
.msg
.message
, &info
.msg
.wParam
,
1948 &info
.msg
.lParam
, &buffer
, size
))
1951 reply_message( &info
, 0, &info
.msg
);
1954 needs_unpack
= TRUE
;
1957 if (size
>= sizeof(msg_data
->hardware
))
1959 hw_id
= msg_data
->hardware
.hw_id
;
1960 if (!process_hardware_message( &info
.msg
, hw_id
, &msg_data
->hardware
,
1961 hwnd
, first
, last
, flags
& PM_REMOVE
))
1963 TRACE("dropping msg %x\n", info
.msg
.message
);
1964 continue; /* ignore it */
1967 thread_info
->client_info
.message_pos
= MAKELONG( info
.msg
.pt
.x
, info
.msg
.pt
.y
);
1968 thread_info
->client_info
.message_time
= info
.msg
.time
;
1969 thread_info
->client_info
.message_extra
= msg_data
->hardware
.info
;
1971 call_hooks( WH_GETMESSAGE
, HC_ACTION
, flags
& PM_REMOVE
, (LPARAM
)msg
, sizeof(*msg
) );
1976 if (info
.msg
.message
& 0x80000000) /* internal message */
1978 if (flags
& PM_REMOVE
)
1980 handle_internal_message( info
.msg
.hwnd
, info
.msg
.message
,
1981 info
.msg
.wParam
, info
.msg
.lParam
);
1982 /* if this is a nested call return right away */
1983 if (first
== info
.msg
.message
&& last
== info
.msg
.message
)
1990 peek_message( msg
, info
.msg
.hwnd
, info
.msg
.message
,
1991 info
.msg
.message
, flags
| PM_REMOVE
, changed_mask
);
1994 if (info
.msg
.message
>= WM_DDE_FIRST
&& info
.msg
.message
<= WM_DDE_LAST
)
1996 struct unpack_dde_message_result result
;
1997 struct unpack_dde_message_params
*params
;
2002 len
= FIELD_OFFSET( struct unpack_dde_message_params
, data
[size
] );
2003 if (!(params
= malloc( len
)))
2005 params
->result
= &result
;
2006 params
->hwnd
= info
.msg
.hwnd
;
2007 params
->message
= info
.msg
.message
;
2008 params
->wparam
= info
.msg
.wParam
;
2009 params
->lparam
= info
.msg
.lParam
;
2010 if (size
) memcpy( params
->data
, buffer
, size
);
2011 ret
= KeUserModeCallback( NtUserUnpackDDEMessage
, params
, len
, &ret_ptr
, &len
);
2012 if (len
== sizeof(result
)) result
= *(struct unpack_dde_message_result
*)ret_ptr
;
2014 if (!ret
) continue; /* ignore it */
2015 info
.msg
.wParam
= result
.wparam
;
2016 info
.msg
.lParam
= result
.lparam
;
2019 msg
->pt
= point_phys_to_win_dpi( info
.msg
.hwnd
, info
.msg
.pt
);
2020 thread_info
->client_info
.message_pos
= MAKELONG( msg
->pt
.x
, msg
->pt
.y
);
2021 thread_info
->client_info
.message_time
= info
.msg
.time
;
2022 thread_info
->client_info
.message_extra
= 0;
2023 thread_info
->client_info
.msg_source
= msg_source_unavailable
;
2025 call_hooks( WH_GETMESSAGE
, HC_ACTION
, flags
& PM_REMOVE
, (LPARAM
)msg
, sizeof(*msg
) );
2029 /* if we get here, we have a sent message; call the window procedure */
2030 info
.prev
= thread_info
->receive_info
;
2031 thread_info
->receive_info
= &info
;
2032 thread_info
->client_info
.msg_source
= msg_source_unavailable
;
2033 thread_info
->client_info
.receive_flags
= info
.flags
;
2034 result
= call_window_proc( info
.msg
.hwnd
, info
.msg
.message
, info
.msg
.wParam
,
2035 info
.msg
.lParam
, (info
.type
!= MSG_ASCII
), FALSE
,
2036 WMCHAR_MAP_RECVMESSAGE
, needs_unpack
, buffer
, size
);
2037 if (thread_info
->receive_info
== &info
)
2038 reply_winproc_result( result
, info
.msg
.hwnd
, info
.msg
.message
,
2039 info
.msg
.wParam
, info
.msg
.lParam
);
2041 /* if some PM_QS* flags were specified, only handle sent messages from now on */
2042 if (HIWORD(flags
) && !changed_mask
) flags
= PM_QS_SENDMESSAGE
| LOWORD(flags
);
2046 /***********************************************************************
2047 * process_sent_messages
2049 * Process all pending sent messages.
2051 static void process_sent_messages(void)
2054 peek_message( &msg
, 0, 0, 0, PM_REMOVE
| PM_QS_SENDMESSAGE
, 0 );
2057 /***********************************************************************
2058 * get_server_queue_handle
2060 * Get a handle to the server message queue for the current thread.
2062 static HANDLE
get_server_queue_handle(void)
2064 struct user_thread_info
*thread_info
= get_user_thread_info();
2067 if (!(ret
= thread_info
->server_queue
))
2069 SERVER_START_REQ( get_msg_queue
)
2071 wine_server_call( req
);
2072 ret
= wine_server_ptr_handle( reply
->handle
);
2075 thread_info
->server_queue
= ret
;
2076 if (!ret
) ERR( "Cannot get server thread queue\n" );
2081 /* check for driver events if we detect that the app is not properly consuming messages */
2082 static inline void check_for_driver_events( UINT msg
)
2084 if (get_user_thread_info()->message_count
> 200)
2086 LARGE_INTEGER zero
= { .QuadPart
= 0 };
2087 flush_window_surfaces( FALSE
);
2088 user_driver
->pMsgWaitForMultipleObjectsEx( 0, NULL
, &zero
, QS_ALLINPUT
, 0 );
2090 else if (msg
== WM_TIMER
|| msg
== WM_SYSTIMER
)
2092 /* driver events should have priority over timers, so make sure we'll check for them soon */
2093 get_user_thread_info()->message_count
+= 100;
2095 else get_user_thread_info()->message_count
++;
2098 /* helper for kernel32->ntdll timeout format conversion */
2099 static inline LARGE_INTEGER
*get_nt_timeout( LARGE_INTEGER
*time
, DWORD timeout
)
2101 if (timeout
== INFINITE
) return NULL
;
2102 time
->QuadPart
= (ULONGLONG
)timeout
* -10000;
2106 /* wait for message or signaled handle */
2107 static DWORD
wait_message( DWORD count
, const HANDLE
*handles
, DWORD timeout
, DWORD mask
, DWORD flags
)
2114 if (enable_thunk_lock
)
2115 lock
= KeUserModeCallback( NtUserThunkLock
, NULL
, 0, &ret_ptr
, &ret_len
);
2117 ret
= user_driver
->pMsgWaitForMultipleObjectsEx( count
, handles
, get_nt_timeout( &time
, timeout
),
2119 if (HIWORD(ret
)) /* is it an error code? */
2121 RtlSetLastWin32Error( RtlNtStatusToDosError(ret
) );
2124 if (ret
== WAIT_TIMEOUT
&& !count
&& !timeout
) NtYieldExecution();
2125 if ((mask
& QS_INPUT
) == QS_INPUT
) get_user_thread_info()->message_count
= 0;
2127 if (enable_thunk_lock
)
2128 KeUserModeCallback( NtUserThunkLock
, &lock
, sizeof(lock
), &ret_ptr
, &ret_len
);
2133 /***********************************************************************
2136 * Wait for multiple objects including the server queue, with specific queue masks.
2138 static DWORD
wait_objects( DWORD count
, const HANDLE
*handles
, DWORD timeout
,
2139 DWORD wake_mask
, DWORD changed_mask
, DWORD flags
)
2141 struct user_thread_info
*thread_info
= get_user_thread_info();
2144 assert( count
); /* we must have at least the server queue */
2146 flush_window_surfaces( TRUE
);
2148 if (thread_info
->wake_mask
!= wake_mask
|| thread_info
->changed_mask
!= changed_mask
)
2150 SERVER_START_REQ( set_queue_mask
)
2152 req
->wake_mask
= wake_mask
;
2153 req
->changed_mask
= changed_mask
;
2155 wine_server_call( req
);
2158 thread_info
->wake_mask
= wake_mask
;
2159 thread_info
->changed_mask
= changed_mask
;
2162 ret
= wait_message( count
, handles
, timeout
, changed_mask
, flags
);
2164 if (ret
!= WAIT_TIMEOUT
) thread_info
->wake_mask
= thread_info
->changed_mask
= 0;
2168 static HANDLE
normalize_std_handle( HANDLE handle
)
2170 if (handle
== (HANDLE
)STD_INPUT_HANDLE
)
2171 return NtCurrentTeb()->Peb
->ProcessParameters
->hStdInput
;
2172 if (handle
== (HANDLE
)STD_OUTPUT_HANDLE
)
2173 return NtCurrentTeb()->Peb
->ProcessParameters
->hStdOutput
;
2174 if (handle
== (HANDLE
)STD_ERROR_HANDLE
)
2175 return NtCurrentTeb()->Peb
->ProcessParameters
->hStdError
;
2180 /***********************************************************************
2181 * NtUserMsgWaitForMultipleObjectsEx (win32u.@)
2183 DWORD WINAPI
NtUserMsgWaitForMultipleObjectsEx( DWORD count
, const HANDLE
*handles
,
2184 DWORD timeout
, DWORD mask
, DWORD flags
)
2186 HANDLE wait_handles
[MAXIMUM_WAIT_OBJECTS
];
2189 if (count
> MAXIMUM_WAIT_OBJECTS
-1)
2191 RtlSetLastWin32Error( ERROR_INVALID_PARAMETER
);
2195 /* add the queue to the handle list */
2196 for (i
= 0; i
< count
; i
++) wait_handles
[i
] = normalize_std_handle( handles
[i
] );
2197 wait_handles
[count
] = get_server_queue_handle();
2199 return wait_objects( count
+1, wait_handles
, timeout
,
2200 (flags
& MWMO_INPUTAVAILABLE
) ? mask
: 0, mask
, flags
);
2203 /***********************************************************************
2204 * NtUserWaitForInputIdle (win32u.@)
2206 DWORD WINAPI
NtUserWaitForInputIdle( HANDLE process
, DWORD timeout
, BOOL wow
)
2208 DWORD start_time
, elapsed
, ret
;
2211 handles
[0] = process
;
2212 SERVER_START_REQ( get_process_idle_event
)
2214 req
->handle
= wine_server_obj_handle( process
);
2215 wine_server_call_err( req
);
2216 handles
[1] = wine_server_ptr_handle( reply
->event
);
2219 if (!handles
[1]) return WAIT_FAILED
; /* no event to wait on */
2221 start_time
= NtGetTickCount();
2224 TRACE("waiting for %p\n", handles
[1] );
2228 ret
= NtUserMsgWaitForMultipleObjectsEx( 2, handles
, timeout
- elapsed
, QS_SENDMESSAGE
, 0 );
2233 case WAIT_OBJECT_0
+2:
2234 process_sent_messages();
2238 TRACE("timeout or error\n");
2241 TRACE("finished\n");
2244 if (timeout
!= INFINITE
)
2246 elapsed
= NtGetTickCount() - start_time
;
2247 if (elapsed
> timeout
)
2252 return WAIT_TIMEOUT
;
2255 /***********************************************************************
2256 * NtUserPeekMessage (win32u.@)
2258 BOOL WINAPI
NtUserPeekMessage( MSG
*msg_out
, HWND hwnd
, UINT first
, UINT last
, UINT flags
)
2263 user_check_not_lock();
2264 check_for_driver_events( 0 );
2266 ret
= peek_message( &msg
, hwnd
, first
, last
, flags
, 0 );
2267 if (ret
< 0) return FALSE
;
2271 flush_window_surfaces( TRUE
);
2272 ret
= wait_message( 0, NULL
, 0, QS_ALLINPUT
, 0 );
2273 /* if we received driver events, check again for a pending message */
2274 if (ret
== WAIT_TIMEOUT
|| peek_message( &msg
, hwnd
, first
, last
, flags
, 0 ) <= 0) return FALSE
;
2277 check_for_driver_events( msg
.message
);
2279 /* copy back our internal safe copy of message data to msg_out.
2280 * msg_out is a variable from the *program*, so it can't be used
2281 * internally as it can get "corrupted" by our use of SendMessage()
2282 * (back to the program) inside the message handling itself. */
2285 RtlSetLastWin32Error( ERROR_NOACCESS
);
2292 /***********************************************************************
2293 * NtUserGetMessage (win32u.@)
2295 BOOL WINAPI
NtUserGetMessage( MSG
*msg
, HWND hwnd
, UINT first
, UINT last
)
2297 HANDLE server_queue
= get_server_queue_handle();
2298 unsigned int mask
= QS_POSTMESSAGE
| QS_SENDMESSAGE
; /* Always selected */
2301 user_check_not_lock();
2302 check_for_driver_events( 0 );
2306 if ((first
<= WM_KEYLAST
) && (last
>= WM_KEYFIRST
)) mask
|= QS_KEY
;
2307 if ( ((first
<= WM_MOUSELAST
) && (last
>= WM_MOUSEFIRST
)) ||
2308 ((first
<= WM_NCMOUSELAST
) && (last
>= WM_NCMOUSEFIRST
)) ) mask
|= QS_MOUSE
;
2309 if ((first
<= WM_TIMER
) && (last
>= WM_TIMER
)) mask
|= QS_TIMER
;
2310 if ((first
<= WM_SYSTIMER
) && (last
>= WM_SYSTIMER
)) mask
|= QS_TIMER
;
2311 if ((first
<= WM_PAINT
) && (last
>= WM_PAINT
)) mask
|= QS_PAINT
;
2313 else mask
= QS_ALLINPUT
;
2315 while (!(ret
= peek_message( msg
, hwnd
, first
, last
, PM_REMOVE
| (mask
<< 16), mask
)))
2317 wait_objects( 1, &server_queue
, INFINITE
, mask
& (QS_SENDMESSAGE
| QS_SMRESULT
), mask
, 0 );
2319 if (ret
< 0) return -1;
2321 check_for_driver_events( msg
->message
);
2323 return msg
->message
!= WM_QUIT
;
2326 /***********************************************************************
2327 * put_message_in_queue
2329 * Put a sent message into the destination queue.
2330 * For inter-process message, reply_size is set to expected size of reply data.
2332 static BOOL
put_message_in_queue( const struct send_message_info
*info
, size_t *reply_size
)
2334 struct packed_message data
;
2335 message_data_t msg_data
;
2338 timeout_t timeout
= TIMEOUT_INFINITE
;
2340 /* Check for INFINITE timeout for compatibility with Win9x,
2341 * although Windows >= NT does not do so
2343 if (info
->type
!= MSG_NOTIFY
&&
2344 info
->type
!= MSG_CALLBACK
&&
2345 info
->type
!= MSG_POSTED
&&
2347 info
->timeout
!= INFINITE
)
2349 /* timeout is signed despite the prototype */
2350 timeout
= (timeout_t
)max( 0, (int)info
->timeout
) * -10000;
2353 memset( &data
, 0, sizeof(data
) );
2354 if (info
->type
== MSG_OTHER_PROCESS
|| info
->type
== MSG_NOTIFY
)
2356 *reply_size
= pack_message( info
->hwnd
, info
->msg
, info
->wparam
, info
->lparam
, &data
);
2357 if (data
.count
== -1)
2359 WARN( "cannot pack message %x\n", info
->msg
);
2363 else if (info
->type
== MSG_CALLBACK
)
2365 msg_data
.callback
.callback
= wine_server_client_ptr( info
->callback
);
2366 msg_data
.callback
.data
= info
->data
;
2367 msg_data
.callback
.result
= 0;
2368 data
.data
[0] = &msg_data
;
2369 data
.size
[0] = sizeof(msg_data
.callback
);
2372 else if (info
->type
== MSG_POSTED
&& info
->msg
>= WM_DDE_FIRST
&& info
->msg
<= WM_DDE_LAST
)
2374 struct post_dde_message_params params
;
2378 params
.hwnd
= info
->hwnd
;
2379 params
.msg
= info
->msg
;
2380 params
.wparam
= info
->wparam
;
2381 params
.lparam
= info
->lparam
;
2382 params
.dest_tid
= info
->dest_tid
;
2383 params
.type
= info
->type
;
2384 return KeUserModeCallback( NtUserPostDDEMessage
, ¶ms
, sizeof(params
), &ret_ptr
, &ret_len
);
2387 SERVER_START_REQ( send_message
)
2389 req
->id
= info
->dest_tid
;
2390 req
->type
= info
->type
;
2392 req
->win
= wine_server_user_handle( info
->hwnd
);
2393 req
->msg
= info
->msg
;
2394 req
->wparam
= info
->wparam
;
2395 req
->lparam
= info
->lparam
;
2396 req
->timeout
= timeout
;
2398 if (info
->flags
& SMTO_ABORTIFHUNG
) req
->flags
|= SEND_MSG_ABORT_IF_HUNG
;
2399 for (i
= 0; i
< data
.count
; i
++) wine_server_add_data( req
, data
.data
[i
], data
.size
[i
] );
2400 if ((res
= wine_server_call( req
)))
2402 if (res
== STATUS_INVALID_PARAMETER
)
2403 /* FIXME: find a STATUS_ value for this one */
2404 RtlSetLastWin32Error( ERROR_INVALID_THREAD_ID
);
2406 RtlSetLastWin32Error( RtlNtStatusToDosError(res
) );
2413 /***********************************************************************
2414 * wait_message_reply
2416 * Wait until a sent message gets replied to.
2418 static void wait_message_reply( UINT flags
)
2420 struct user_thread_info
*thread_info
= get_user_thread_info();
2421 HANDLE server_queue
= get_server_queue_handle();
2422 unsigned int wake_mask
= QS_SMRESULT
| ((flags
& SMTO_BLOCK
) ? 0 : QS_SENDMESSAGE
);
2426 unsigned int wake_bits
= 0;
2428 SERVER_START_REQ( set_queue_mask
)
2430 req
->wake_mask
= wake_mask
;
2431 req
->changed_mask
= wake_mask
;
2433 if (!wine_server_call( req
)) wake_bits
= reply
->wake_bits
& wake_mask
;
2437 thread_info
->wake_mask
= thread_info
->changed_mask
= 0;
2439 if (wake_bits
& QS_SMRESULT
) return; /* got a result */
2440 if (wake_bits
& QS_SENDMESSAGE
)
2442 /* Process the sent message immediately */
2443 process_sent_messages();
2447 wait_message( 1, &server_queue
, INFINITE
, wake_mask
, 0 );
2451 /***********************************************************************
2454 * Retrieve a message reply from the server.
2456 static LRESULT
retrieve_reply( const struct send_message_info
*info
,
2457 size_t reply_size
, LRESULT
*result
)
2460 void *reply_data
= NULL
;
2464 if (!(reply_data
= malloc( reply_size
)))
2466 WARN( "no memory for reply, will be truncated\n" );
2470 SERVER_START_REQ( get_message_reply
)
2473 if (reply_size
) wine_server_set_reply( req
, reply_data
, reply_size
);
2474 if (!(status
= wine_server_call( req
))) *result
= reply
->result
;
2475 reply_size
= wine_server_reply_size( reply
);
2478 if (!status
&& reply_size
)
2479 unpack_reply( info
->hwnd
, info
->msg
, info
->wparam
, info
->lparam
, reply_data
, reply_size
);
2483 TRACE( "hwnd %p msg %x (%s) wp %lx lp %lx got reply %lx (err=%d)\n",
2484 info
->hwnd
, info
->msg
, debugstr_msg_name(info
->msg
, info
->hwnd
), info
->wparam
,
2485 info
->lparam
, *result
, status
);
2487 /* MSDN states that last error is 0 on timeout, but at least NT4 returns ERROR_TIMEOUT */
2488 if (status
) RtlSetLastWin32Error( RtlNtStatusToDosError(status
) );
2492 /***********************************************************************
2493 * send_inter_thread_message
2495 static LRESULT
send_inter_thread_message( const struct send_message_info
*info
, LRESULT
*res_ptr
)
2497 size_t reply_size
= 0;
2499 TRACE( "hwnd %p msg %x (%s) wp %lx lp %lx\n",
2500 info
->hwnd
, info
->msg
, debugstr_msg_name(info
->msg
, info
->hwnd
), info
->wparam
, info
->lparam
);
2502 user_check_not_lock();
2504 if (!put_message_in_queue( info
, &reply_size
)) return 0;
2506 /* there's no reply to wait for on notify/callback messages */
2507 if (info
->type
== MSG_NOTIFY
|| info
->type
== MSG_CALLBACK
) return 1;
2509 wait_message_reply( info
->flags
);
2510 return retrieve_reply( info
, reply_size
, res_ptr
);
2513 /***********************************************************************
2514 * send_internal_message_timeout
2516 * Same as SendMessageTimeoutW but sends the message to a specific thread
2517 * without requiring a window handle. Only works for internal Wine messages.
2519 LRESULT
send_internal_message_timeout( DWORD dest_pid
, DWORD dest_tid
,
2520 UINT msg
, WPARAM wparam
, LPARAM lparam
,
2521 UINT flags
, UINT timeout
, PDWORD_PTR res_ptr
)
2523 LRESULT ret
, result
= 0;
2525 assert( msg
& 0x80000000 ); /* must be an internal Wine message */
2527 if (is_exiting_thread( dest_tid
)) return 0;
2529 if (dest_tid
== GetCurrentThreadId())
2531 result
= handle_internal_message( 0, msg
, wparam
, lparam
);
2536 struct send_message_info info
;
2538 info
.type
= dest_pid
== GetCurrentProcessId() ? MSG_UNICODE
: MSG_OTHER_PROCESS
;
2539 info
.dest_tid
= dest_tid
;
2542 info
.wparam
= wparam
;
2543 info
.lparam
= lparam
;
2545 info
.timeout
= timeout
;
2548 ret
= send_inter_thread_message( &info
, &result
);
2550 if (ret
&& res_ptr
) *res_ptr
= result
;
2554 /***********************************************************************
2555 * send_hardware_message
2557 NTSTATUS
send_hardware_message( HWND hwnd
, const INPUT
*input
, const RAWINPUT
*rawinput
, UINT flags
)
2559 struct user_key_state_info
*key_state_info
= get_user_thread_info()->key_state
;
2560 struct send_message_info info
;
2561 int prev_x
, prev_y
, new_x
, new_y
;
2562 INT counter
= global_key_state_counter
;
2563 USAGE hid_usage_page
, hid_usage
;
2567 info
.type
= MSG_HARDWARE
;
2574 if (input
->type
== INPUT_HARDWARE
&& rawinput
->header
.dwType
== RIM_TYPEHID
)
2576 if (input
->hi
.uMsg
== WM_INPUT_DEVICE_CHANGE
)
2578 hid_usage_page
= ((USAGE
*)rawinput
->data
.hid
.bRawData
)[0];
2579 hid_usage
= ((USAGE
*)rawinput
->data
.hid
.bRawData
)[1];
2581 if (input
->hi
.uMsg
== WM_INPUT
&&
2582 !rawinput_device_get_usages( rawinput
->header
.hDevice
, &hid_usage_page
, &hid_usage
))
2584 WARN( "unable to get HID usages for device %p\n", rawinput
->header
.hDevice
);
2585 return STATUS_INVALID_HANDLE
;
2589 SERVER_START_REQ( send_hardware_message
)
2591 req
->win
= wine_server_user_handle( hwnd
);
2593 req
->input
.type
= input
->type
;
2594 switch (input
->type
)
2597 req
->input
.mouse
.x
= input
->mi
.dx
;
2598 req
->input
.mouse
.y
= input
->mi
.dy
;
2599 req
->input
.mouse
.data
= input
->mi
.mouseData
;
2600 req
->input
.mouse
.flags
= input
->mi
.dwFlags
;
2601 req
->input
.mouse
.time
= input
->mi
.time
;
2602 req
->input
.mouse
.info
= input
->mi
.dwExtraInfo
;
2604 case INPUT_KEYBOARD
:
2605 req
->input
.kbd
.vkey
= input
->ki
.wVk
;
2606 req
->input
.kbd
.scan
= input
->ki
.wScan
;
2607 req
->input
.kbd
.flags
= input
->ki
.dwFlags
;
2608 req
->input
.kbd
.time
= input
->ki
.time
;
2609 req
->input
.kbd
.info
= input
->ki
.dwExtraInfo
;
2611 case INPUT_HARDWARE
:
2612 req
->input
.hw
.msg
= input
->hi
.uMsg
;
2613 req
->input
.hw
.lparam
= MAKELONG( input
->hi
.wParamL
, input
->hi
.wParamH
);
2614 switch (input
->hi
.uMsg
)
2617 case WM_INPUT_DEVICE_CHANGE
:
2618 req
->input
.hw
.rawinput
.type
= rawinput
->header
.dwType
;
2619 switch (rawinput
->header
.dwType
)
2622 req
->input
.hw
.rawinput
.hid
.device
= HandleToUlong( rawinput
->header
.hDevice
);
2623 req
->input
.hw
.rawinput
.hid
.param
= rawinput
->header
.wParam
;
2624 req
->input
.hw
.rawinput
.hid
.usage_page
= hid_usage_page
;
2625 req
->input
.hw
.rawinput
.hid
.usage
= hid_usage
;
2626 req
->input
.hw
.rawinput
.hid
.count
= rawinput
->data
.hid
.dwCount
;
2627 req
->input
.hw
.rawinput
.hid
.length
= rawinput
->data
.hid
.dwSizeHid
;
2628 wine_server_add_data( req
, rawinput
->data
.hid
.bRawData
,
2629 rawinput
->data
.hid
.dwCount
* rawinput
->data
.hid
.dwSizeHid
);
2638 if (key_state_info
) wine_server_set_reply( req
, key_state_info
->state
,
2639 sizeof(key_state_info
->state
) );
2640 ret
= wine_server_call( req
);
2642 prev_x
= reply
->prev_x
;
2643 prev_y
= reply
->prev_y
;
2644 new_x
= reply
->new_x
;
2645 new_y
= reply
->new_y
;
2653 key_state_info
->time
= NtGetTickCount();
2654 key_state_info
->counter
= counter
;
2656 if ((flags
& SEND_HWMSG_INJECTED
) && (prev_x
!= new_x
|| prev_y
!= new_y
))
2657 user_driver
->pSetCursorPos( new_x
, new_y
);
2663 wait_message_reply( 0 );
2664 retrieve_reply( &info
, 0, &ignored
);
2669 /**********************************************************************
2670 * NtUserDispatchMessage (win32u.@)
2672 LRESULT WINAPI
NtUserDispatchMessage( const MSG
*msg
)
2674 struct win_proc_params params
;
2677 /* Process timer messages */
2678 if (msg
->lParam
&& msg
->message
== WM_TIMER
)
2680 params
.func
= (WNDPROC
)msg
->lParam
;
2681 params
.result
= &retval
; /* FIXME */
2682 if (!init_win_proc_params( ¶ms
, msg
->hwnd
, msg
->message
,
2683 msg
->wParam
, NtGetTickCount(), FALSE
))
2685 dispatch_win_proc_params( ¶ms
, sizeof(params
) );
2688 if (msg
->message
== WM_SYSTIMER
)
2690 switch (msg
->wParam
)
2692 case SYSTEM_TIMER_CARET
:
2693 toggle_caret( msg
->hwnd
);
2696 case SYSTEM_TIMER_TRACK_MOUSE
:
2697 update_mouse_tracking_info( msg
->hwnd
);
2702 if (!msg
->hwnd
) return 0;
2704 spy_enter_message( SPY_DISPATCHMESSAGE
, msg
->hwnd
, msg
->message
, msg
->wParam
, msg
->lParam
);
2706 if (init_window_call_params( ¶ms
, msg
->hwnd
, msg
->message
, msg
->wParam
, msg
->lParam
,
2707 &retval
, FALSE
, WMCHAR_MAP_DISPATCHMESSAGE
))
2708 dispatch_win_proc_params( ¶ms
, sizeof(params
) );
2709 else if (!is_window( msg
->hwnd
)) RtlSetLastWin32Error( ERROR_INVALID_WINDOW_HANDLE
);
2710 else RtlSetLastWin32Error( ERROR_MESSAGE_SYNC_ONLY
);
2712 spy_exit_message( SPY_RESULT_OK
, msg
->hwnd
, msg
->message
, retval
, msg
->wParam
, msg
->lParam
);
2714 if (msg
->message
== WM_PAINT
)
2716 /* send a WM_NCPAINT and WM_ERASEBKGND if the non-client area is still invalid */
2717 HRGN hrgn
= NtGdiCreateRectRgn( 0, 0, 0, 0 );
2718 NtUserGetUpdateRgn( msg
->hwnd
, hrgn
, TRUE
);
2719 NtGdiDeleteObjectApp( hrgn
);
2724 static BOOL
is_message_broadcastable( UINT msg
)
2726 return msg
< WM_USER
|| msg
>= 0xc000;
2729 /***********************************************************************
2732 static BOOL
broadcast_message( struct send_message_info
*info
, DWORD_PTR
*res_ptr
)
2736 if (is_message_broadcastable( info
->msg
) &&
2737 (list
= list_window_children( 0, get_desktop_window(), NULL
, 0 )))
2741 for (i
= 0; list
[i
]; i
++)
2743 if (!is_window(list
[i
])) continue;
2744 if ((get_window_long( list
[i
], GWL_STYLE
) & (WS_POPUP
|WS_CHILD
)) == WS_CHILD
)
2750 case MSG_OTHER_PROCESS
:
2751 send_message_timeout( list
[i
], info
->msg
, info
->wparam
, info
->lparam
,
2752 info
->flags
, info
->timeout
, FALSE
);
2755 send_message_timeout( list
[i
], info
->msg
, info
->wparam
, info
->lparam
,
2756 info
->flags
, info
->timeout
, TRUE
);
2759 NtUserMessageCall( list
[i
], info
->msg
, info
->wparam
, info
->lparam
,
2760 0, NtUserSendNotifyMessage
, FALSE
);
2764 struct send_message_callback_params params
=
2765 { .callback
= info
->callback
, .data
= info
->data
};
2766 NtUserMessageCall( list
[i
], info
->msg
, info
->wparam
, info
->lparam
,
2767 ¶ms
, NtUserSendMessageCallback
, FALSE
);
2771 NtUserPostMessage( list
[i
], info
->msg
, info
->wparam
, info
->lparam
);
2774 ERR( "bad type %d\n", info
->type
);
2780 if (res_ptr
) *res_ptr
= 1;
2784 static BOOL
process_packed_message( struct send_message_info
*info
, LRESULT
*res_ptr
, BOOL ansi
)
2786 struct user_thread_info
*thread_info
= get_user_thread_info();
2787 struct received_message_info receive_info
;
2788 struct packed_message data
;
2789 size_t buffer_size
= 0, i
;
2790 void *buffer
= NULL
;
2793 pack_message( info
->hwnd
, info
->msg
, info
->wparam
, info
->lparam
, &data
);
2794 if (data
.count
== -1) return FALSE
;
2796 for (i
= 0; i
< data
.count
; i
++) buffer_size
+= data
.size
[i
];
2797 if (!(buffer
= malloc( buffer_size
))) return FALSE
;
2798 for (ptr
= buffer
, i
= 0; i
< data
.count
; i
++)
2800 memcpy( ptr
, data
.data
[i
], data
.size
[i
] );
2801 ptr
+= data
.size
[i
];
2804 receive_info
.type
= MSG_CLIENT_MESSAGE
;
2805 receive_info
.msg
.hwnd
= info
->hwnd
;
2806 receive_info
.msg
.message
= info
->msg
;
2807 receive_info
.msg
.wParam
= info
->wparam
;
2808 receive_info
.msg
.lParam
= info
->lparam
;
2809 receive_info
.flags
= 0;
2810 receive_info
.prev
= thread_info
->receive_info
;
2811 receive_info
.result
= 0;
2812 thread_info
->receive_info
= &receive_info
;
2814 *res_ptr
= call_window_proc( info
->hwnd
, info
->msg
, info
->wparam
, info
->lparam
,
2815 !ansi
, TRUE
, info
->wm_char
, TRUE
, buffer
, buffer_size
);
2816 if (thread_info
->receive_info
== &receive_info
)
2818 thread_info
->receive_info
= receive_info
.prev
;
2819 *res_ptr
= receive_info
.result
;
2826 /***********************************************************************
2829 * Backend implementation of the various SendMessage functions.
2831 static BOOL
process_message( struct send_message_info
*info
, DWORD_PTR
*res_ptr
, BOOL ansi
)
2833 struct ntuser_thread_info
*thread_info
= NtUserGetThreadInfo();
2834 INPUT_MESSAGE_SOURCE prev_source
= thread_info
->msg_source
;
2839 if (is_broadcast( info
->hwnd
)) return broadcast_message( info
, res_ptr
);
2841 if (!(info
->dest_tid
= get_window_thread( info
->hwnd
, &dest_pid
))) return FALSE
;
2842 if (is_exiting_thread( info
->dest_tid
)) return FALSE
;
2844 if (info
->params
&& info
->dest_tid
== GetCurrentThreadId() &&
2845 !is_hooked( WH_CALLWNDPROC
) && !is_hooked( WH_CALLWNDPROCRET
) &&
2846 thread_info
->recursion_count
<= MAX_WINPROC_RECURSION
)
2848 /* if we're called from client side and need just a simple winproc call,
2849 * just fill dispatch params and let user32 do the rest */
2850 return init_window_call_params( info
->params
, info
->hwnd
, info
->msg
, info
->wparam
, info
->lparam
,
2851 NULL
, ansi
, info
->wm_char
);
2854 thread_info
->msg_source
= msg_source_unavailable
;
2855 spy_enter_message( SPY_SENDMESSAGE
, info
->hwnd
, info
->msg
, info
->wparam
, info
->lparam
);
2857 if (info
->dest_tid
!= GetCurrentThreadId())
2859 if (dest_pid
!= GetCurrentProcessId() && (info
->type
== MSG_ASCII
|| info
->type
== MSG_UNICODE
))
2860 info
->type
= MSG_OTHER_PROCESS
;
2861 ret
= send_inter_thread_message( info
, &result
);
2863 else if (info
->type
!= MSG_OTHER_PROCESS
)
2865 result
= call_window_proc( info
->hwnd
, info
->msg
, info
->wparam
, info
->lparam
,
2866 !ansi
, TRUE
, info
->wm_char
, FALSE
, NULL
, 0 );
2867 if (info
->type
== MSG_CALLBACK
)
2868 call_sendmsg_callback( info
->callback
, info
->hwnd
, info
->msg
, info
->data
, result
);
2873 ret
= process_packed_message( info
, &result
, ansi
);
2876 spy_exit_message( SPY_RESULT_OK
, info
->hwnd
, info
->msg
, result
, info
->wparam
, info
->lparam
);
2877 thread_info
->msg_source
= prev_source
;
2878 if (ret
&& res_ptr
) *res_ptr
= result
;
2882 /***********************************************************************
2883 * NtUserSetTimer (win32u.@)
2885 UINT_PTR WINAPI
NtUserSetTimer( HWND hwnd
, UINT_PTR id
, UINT timeout
, TIMERPROC proc
, ULONG tolerance
)
2888 WNDPROC winproc
= 0;
2890 if (proc
) winproc
= alloc_winproc( (WNDPROC
)proc
, TRUE
);
2892 timeout
= min( max( USER_TIMER_MINIMUM
, timeout
), USER_TIMER_MAXIMUM
);
2894 SERVER_START_REQ( set_win_timer
)
2896 req
->win
= wine_server_user_handle( hwnd
);
2897 req
->msg
= WM_TIMER
;
2899 req
->rate
= timeout
;
2900 req
->lparam
= (ULONG_PTR
)winproc
;
2901 if (!wine_server_call_err( req
))
2904 if (!ret
) ret
= TRUE
;
2910 TRACE( "Added %p %lx %p timeout %d\n", hwnd
, id
, winproc
, timeout
);
2914 /***********************************************************************
2915 * NtUserSetSystemTimer (win32u.@)
2917 UINT_PTR WINAPI
NtUserSetSystemTimer( HWND hwnd
, UINT_PTR id
, UINT timeout
)
2921 TRACE( "window %p, id %#lx, timeout %u\n", hwnd
, id
, timeout
);
2923 timeout
= min( max( USER_TIMER_MINIMUM
, timeout
), USER_TIMER_MAXIMUM
);
2925 SERVER_START_REQ( set_win_timer
)
2927 req
->win
= wine_server_user_handle( hwnd
);
2928 req
->msg
= WM_SYSTIMER
;
2930 req
->rate
= timeout
;
2932 if (!wine_server_call_err( req
))
2935 if (!ret
) ret
= TRUE
;
2944 /***********************************************************************
2945 * NtUserKillTimer (win32u.@)
2947 BOOL WINAPI
NtUserKillTimer( HWND hwnd
, UINT_PTR id
)
2951 SERVER_START_REQ( kill_win_timer
)
2953 req
->win
= wine_server_user_handle( hwnd
);
2954 req
->msg
= WM_TIMER
;
2956 ret
= !wine_server_call_err( req
);
2962 /* see KillSystemTimer */
2963 BOOL
kill_system_timer( HWND hwnd
, UINT_PTR id
)
2967 SERVER_START_REQ( kill_win_timer
)
2969 req
->win
= wine_server_user_handle( hwnd
);
2970 req
->msg
= WM_SYSTIMER
;
2972 ret
= !wine_server_call_err( req
);
2978 static LRESULT
send_window_message( HWND hwnd
, UINT msg
, WPARAM wparam
, LPARAM lparam
,
2979 struct win_proc_params
*client_params
, BOOL ansi
)
2981 struct send_message_info info
;
2984 info
.type
= ansi
? MSG_ASCII
: MSG_UNICODE
;
2987 info
.wparam
= wparam
;
2988 info
.lparam
= lparam
;
2989 info
.flags
= SMTO_NORMAL
;
2991 info
.wm_char
= WMCHAR_MAP_SENDMESSAGETIMEOUT
;
2992 info
.params
= client_params
;
2994 process_message( &info
, &res
, ansi
);
2998 /* see SendMessageTimeoutW */
2999 static LRESULT
send_client_message( HWND hwnd
, UINT msg
, WPARAM wparam
, LPARAM lparam
,
3000 UINT flags
, UINT timeout
, DWORD_PTR
*res_ptr
, BOOL ansi
)
3002 struct send_message_info info
;
3004 info
.type
= ansi
? MSG_ASCII
: MSG_UNICODE
;
3007 info
.wparam
= wparam
;
3008 info
.lparam
= lparam
;
3010 info
.timeout
= timeout
;
3011 info
.wm_char
= WMCHAR_MAP_SENDMESSAGETIMEOUT
;
3014 return process_message( &info
, res_ptr
, ansi
);
3017 LRESULT
send_message_timeout( HWND hwnd
, UINT msg
, WPARAM wparam
, LPARAM lparam
,
3018 UINT flags
, UINT timeout
, BOOL ansi
)
3020 struct send_message_info info
;
3023 if (!is_pointer_message( msg
, wparam
))
3025 send_client_message( hwnd
, msg
, wparam
, lparam
, flags
, timeout
, &res
, ansi
);
3029 info
.type
= MSG_OTHER_PROCESS
;
3032 info
.wparam
= wparam
;
3033 info
.lparam
= lparam
;
3035 info
.timeout
= timeout
;
3036 info
.wm_char
= WMCHAR_MAP_SENDMESSAGETIMEOUT
;
3039 process_message( &info
, &res
, ansi
);
3043 /* see SendMessageW */
3044 LRESULT
send_message( HWND hwnd
, UINT msg
, WPARAM wparam
, LPARAM lparam
)
3046 return send_message_timeout( hwnd
, msg
, wparam
, lparam
, SMTO_NORMAL
, 0, FALSE
);
3049 /* see SendNotifyMessageW */
3050 static BOOL
send_notify_message( HWND hwnd
, UINT msg
, WPARAM wparam
, LPARAM lparam
, BOOL ansi
)
3052 struct send_message_info info
;
3054 if (is_pointer_message( msg
, wparam
))
3056 RtlSetLastWin32Error( ERROR_MESSAGE_SYNC_ONLY
);
3060 info
.type
= MSG_NOTIFY
;
3063 info
.wparam
= wparam
;
3064 info
.lparam
= lparam
;
3066 info
.wm_char
= WMCHAR_MAP_SENDMESSAGETIMEOUT
;
3069 return process_message( &info
, NULL
, ansi
);
3072 /* see SendMessageCallbackW */
3073 static BOOL
send_message_callback( HWND hwnd
, UINT msg
, WPARAM wparam
, LPARAM lparam
,
3074 const struct send_message_callback_params
*params
, BOOL ansi
)
3076 struct send_message_info info
;
3078 if (is_pointer_message( msg
, wparam
))
3080 RtlSetLastWin32Error( ERROR_MESSAGE_SYNC_ONLY
);
3084 info
.type
= MSG_CALLBACK
;
3087 info
.wparam
= wparam
;
3088 info
.lparam
= lparam
;
3089 info
.callback
= params
->callback
;
3090 info
.data
= params
->data
;
3092 info
.wm_char
= WMCHAR_MAP_SENDMESSAGETIMEOUT
;
3095 return process_message( &info
, NULL
, ansi
);
3098 /***********************************************************************
3099 * NtUserPostMessage (win32u.@)
3101 BOOL WINAPI
NtUserPostMessage( HWND hwnd
, UINT msg
, WPARAM wparam
, LPARAM lparam
)
3103 struct send_message_info info
;
3105 if (is_pointer_message( msg
, wparam
))
3107 RtlSetLastWin32Error( ERROR_MESSAGE_SYNC_ONLY
);
3111 TRACE( "hwnd %p msg %x (%s) wp %lx lp %lx\n",
3112 hwnd
, msg
, debugstr_msg_name(msg
, hwnd
), wparam
, lparam
);
3114 info
.type
= MSG_POSTED
;
3117 info
.wparam
= wparam
;
3118 info
.lparam
= lparam
;
3122 if (is_broadcast(hwnd
)) return broadcast_message( &info
, NULL
);
3124 if (!hwnd
) return NtUserPostThreadMessage( GetCurrentThreadId(), msg
, wparam
, lparam
);
3126 if (!(info
.dest_tid
= get_window_thread( hwnd
, NULL
))) return FALSE
;
3128 if (is_exiting_thread( info
.dest_tid
)) return TRUE
;
3130 return put_message_in_queue( &info
, NULL
);
3133 /**********************************************************************
3134 * NtUserPostThreadMessage (win32u.@)
3136 BOOL WINAPI
NtUserPostThreadMessage( DWORD thread
, UINT msg
, WPARAM wparam
, LPARAM lparam
)
3138 struct send_message_info info
;
3140 if (is_pointer_message( msg
, wparam
))
3142 RtlSetLastWin32Error( ERROR_MESSAGE_SYNC_ONLY
);
3145 if (is_exiting_thread( thread
)) return TRUE
;
3147 info
.type
= MSG_POSTED
;
3148 info
.dest_tid
= thread
;
3151 info
.wparam
= wparam
;
3152 info
.lparam
= lparam
;
3155 return put_message_in_queue( &info
, NULL
);
3158 LRESULT WINAPI
NtUserMessageCall( HWND hwnd
, UINT msg
, WPARAM wparam
, LPARAM lparam
,
3159 void *result_info
, DWORD type
, BOOL ansi
)
3163 case NtUserScrollBarWndProc
:
3164 return scroll_bar_window_proc( hwnd
, msg
, wparam
, lparam
, ansi
);
3166 case NtUserPopupMenuWndProc
:
3167 return popup_menu_window_proc( hwnd
, msg
, wparam
, lparam
);
3169 case NtUserDesktopWindowProc
:
3170 return desktop_window_proc( hwnd
, msg
, wparam
, lparam
);
3172 case NtUserDefWindowProc
:
3173 return default_window_proc( hwnd
, msg
, wparam
, lparam
, ansi
);
3175 case NtUserCallWindowProc
:
3176 return init_win_proc_params( (struct win_proc_params
*)result_info
, hwnd
, msg
,
3177 wparam
, lparam
, ansi
);
3179 case NtUserSendMessage
:
3180 return send_window_message( hwnd
, msg
, wparam
, lparam
, result_info
, ansi
);
3182 case NtUserSendMessageTimeout
:
3184 struct send_message_timeout_params
*params
= (void *)result_info
;
3186 params
->result
= send_client_message( hwnd
, msg
, wparam
, lparam
, params
->flags
,
3187 params
->timeout
, &res
, ansi
);
3191 case NtUserSendNotifyMessage
:
3192 return send_notify_message( hwnd
, msg
, wparam
, lparam
, ansi
);
3194 case NtUserSendMessageCallback
:
3195 return send_message_callback( hwnd
, msg
, wparam
, lparam
, result_info
, ansi
);
3197 case NtUserClipboardWindowProc
:
3198 return user_driver
->pClipboardWindowProc( hwnd
, msg
, wparam
, lparam
);
3200 case NtUserWinProcResult
:
3201 return reply_winproc_result( (LRESULT
)result_info
, hwnd
, msg
, wparam
, lparam
);
3203 case NtUserGetDispatchParams
:
3204 if (!hwnd
) return FALSE
;
3205 if (init_window_call_params( result_info
, hwnd
, msg
, wparam
, lparam
,
3206 NULL
, ansi
, WMCHAR_MAP_DISPATCHMESSAGE
))
3208 if (!is_window( hwnd
)) RtlSetLastWin32Error( ERROR_INVALID_WINDOW_HANDLE
);
3209 else RtlSetLastWin32Error( ERROR_MESSAGE_SYNC_ONLY
);
3212 case NtUserSpyEnter
:
3213 spy_enter_message( ansi
, hwnd
, msg
, wparam
, lparam
);
3216 case NtUserSpyGetMsgName
:
3217 lstrcpynA( result_info
, debugstr_msg_name( msg
, hwnd
), wparam
);
3221 spy_exit_message( ansi
, hwnd
, msg
, (LPARAM
)result_info
, wparam
, lparam
);
3225 FIXME( "%p %x %lx %lx %p %x %x\n", hwnd
, msg
, wparam
, lparam
, result_info
, type
, ansi
);
3230 /***********************************************************************
3231 * NtUserTranslateMessage (win32u.@)
3233 BOOL WINAPI
NtUserTranslateMessage( const MSG
*msg
, UINT flags
)
3240 if (flags
) FIXME( "unsupported flags %x\n", flags
);
3242 if (msg
->message
< WM_KEYFIRST
|| msg
->message
> WM_KEYLAST
) return FALSE
;
3243 if (msg
->message
!= WM_KEYDOWN
&& msg
->message
!= WM_SYSKEYDOWN
) return TRUE
;
3245 TRACE_(key
)( "Translating key %s (%04lX), scancode %04x\n",
3246 debugstr_vkey_name( msg
->wParam
), msg
->wParam
, HIWORD(msg
->lParam
) );
3248 switch (msg
->wParam
)
3251 message
= (msg
->message
== WM_KEYDOWN
) ? WM_CHAR
: WM_SYSCHAR
;
3252 TRACE_(key
)( "PostMessageW(%p,%s,%04x,%08x)\n", msg
->hwnd
,
3253 debugstr_msg_name( message
, msg
->hwnd
),
3254 HIWORD(msg
->lParam
), LOWORD(msg
->lParam
) );
3255 NtUserPostMessage( msg
->hwnd
, message
, HIWORD(msg
->lParam
), LOWORD(msg
->lParam
) );
3259 return ImmTranslateMessage( msg
->hwnd
, msg
->message
, msg
->wParam
, msg
->lParam
);
3262 NtUserGetKeyboardState( state
);
3263 len
= NtUserToUnicodeEx( msg
->wParam
, HIWORD(msg
->lParam
), state
, wp
, ARRAY_SIZE(wp
), 0,
3264 NtUserGetKeyboardLayout(0) );
3267 message
= msg
->message
== WM_KEYDOWN
? WM_DEADCHAR
: WM_SYSDEADCHAR
;
3268 TRACE_(key
)( "-1 -> PostMessageW(%p,%s,%04x,%08lx)\n",
3269 msg
->hwnd
, debugstr_msg_name( message
, msg
->hwnd
), wp
[0], msg
->lParam
);
3270 NtUserPostMessage( msg
->hwnd
, message
, wp
[0], msg
->lParam
);
3276 message
= msg
->message
== WM_KEYDOWN
? WM_CHAR
: WM_SYSCHAR
;
3277 TRACE_(key
)( "%d -> PostMessageW(%p,%s,<x>,%08lx) for <x> in %s\n", len
, msg
->hwnd
,
3278 debugstr_msg_name(message
, msg
->hwnd
), msg
->lParam
, debugstr_wn(wp
, len
) );
3279 for (i
= 0; i
< len
; i
++)
3280 NtUserPostMessage( msg
->hwnd
, message
, wp
[i
], msg
->lParam
);