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
23 #define WIN32_NO_STATUS
24 #include "user_private.h"
27 #include "wine/server.h"
28 #include "wine/debug.h"
29 #include "wine/exception.h"
31 WINE_DEFAULT_DEBUG_CHANNEL(msg
);
34 /* pack a pointer into a 32/64 portable format */
35 static inline ULONGLONG
pack_ptr( const void *ptr
)
37 return (ULONG_PTR
)ptr
;
40 /* unpack a potentially 64-bit pointer, returning 0 when truncated */
41 static inline void *unpack_ptr( ULONGLONG ptr64
)
43 if ((ULONG_PTR
)ptr64
!= ptr64
) return 0;
44 return (void *)(ULONG_PTR
)ptr64
;
47 static struct wm_char_mapping_data
*get_wmchar_data(void)
49 return (struct wm_char_mapping_data
*)(UINT_PTR
)NtUserGetThreadInfo()->wmchar_data
;
52 /* check for pending WM_CHAR message with DBCS trailing byte */
53 static inline BOOL
get_pending_wmchar( MSG
*msg
, UINT first
, UINT last
, BOOL remove
)
55 struct wm_char_mapping_data
*data
= get_wmchar_data();
57 if (!data
|| !data
->get_msg
.message
) return FALSE
;
58 if ((first
|| last
) && (first
> WM_CHAR
|| last
< WM_CHAR
)) return FALSE
;
59 if (!msg
) return FALSE
;
61 if (remove
) data
->get_msg
.message
= 0;
66 /***********************************************************************
69 * Window procedure for "Message" windows (HWND_MESSAGE parent).
71 LRESULT WINAPI
MessageWndProc( HWND hwnd
, UINT message
, WPARAM wParam
, LPARAM lParam
)
73 if (message
== WM_NCCREATE
) return TRUE
;
74 return 0; /* all other messages are ignored */
78 DWORD
get_input_codepage( void )
82 HKL hkl
= NtUserGetKeyboardLayout( 0 );
84 ret
= GetLocaleInfoW( LOWORD(hkl
), LOCALE_IDEFAULTANSICODEPAGE
| LOCALE_RETURN_NUMBER
,
85 (WCHAR
*)&cp
, sizeof(cp
) / sizeof(WCHAR
) );
86 if (!ret
) cp
= CP_ACP
;
90 /***********************************************************************
93 * Convert the wparam of an ASCII message to Unicode.
95 BOOL
map_wparam_AtoW( UINT message
, WPARAM
*wparam
, enum wm_char_mapping mapping
)
105 /* WM_CHAR is magic: a DBCS char can be sent/posted as two consecutive WM_CHAR
106 * messages, in which case the first char is stored, and the conversion
107 * to Unicode only takes place once the second char is sent/posted.
109 if (mapping
!= WMCHAR_MAP_NOMAPPING
)
111 struct wm_char_mapping_data
*data
= get_wmchar_data();
112 BYTE low
= LOBYTE(*wparam
);
113 cp
= get_input_codepage();
118 ch
[1] = HIBYTE(*wparam
);
119 MultiByteToWideChar( cp
, 0, ch
, 2, wch
, 2 );
120 TRACE( "map %02x,%02x -> %04x mapping %u\n", (BYTE
)ch
[0], (BYTE
)ch
[1], wch
[0], mapping
);
121 if (data
) data
->lead_byte
[mapping
] = 0;
123 else if (data
&& data
->lead_byte
[mapping
])
125 ch
[0] = data
->lead_byte
[mapping
];
127 MultiByteToWideChar( cp
, 0, ch
, 2, wch
, 2 );
128 TRACE( "map stored %02x,%02x -> %04x mapping %u\n", (BYTE
)ch
[0], (BYTE
)ch
[1], wch
[0], mapping
);
129 data
->lead_byte
[mapping
] = 0;
131 else if (!IsDBCSLeadByte( low
))
134 MultiByteToWideChar( cp
, 0, ch
, 1, wch
, 2 );
135 TRACE( "map %02x -> %04x\n", (BYTE
)ch
[0], wch
[0] );
136 if (data
) data
->lead_byte
[mapping
] = 0;
138 else /* store it and wait for trail byte */
142 if (!(data
= HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(*data
) )))
144 NtUserGetThreadInfo()->wmchar_data
= (UINT_PTR
)data
;
146 TRACE( "storing lead byte %02x mapping %u\n", low
, mapping
);
147 data
->lead_byte
[mapping
] = low
;
150 *wparam
= MAKEWPARAM(wch
[0], wch
[1]);
153 /* else fall through */
155 case EM_SETPASSWORDCHAR
:
160 cp
= get_input_codepage();
161 ch
[0] = LOBYTE(*wparam
);
162 ch
[1] = HIBYTE(*wparam
);
163 MultiByteToWideChar( cp
, 0, ch
, 2, wch
, 2 );
164 *wparam
= MAKEWPARAM(wch
[0], wch
[1]);
167 cp
= get_input_codepage();
168 ch
[0] = HIBYTE(*wparam
);
169 ch
[1] = LOBYTE(*wparam
);
170 if (ch
[0]) MultiByteToWideChar( cp
, 0, ch
, 2, wch
, 2 );
171 else MultiByteToWideChar( cp
, 0, ch
+ 1, 1, wch
, 1 );
172 *wparam
= MAKEWPARAM(wch
[0], HIWORD(*wparam
));
179 /***********************************************************************
182 * Convert the wparam of a Unicode message to ASCII.
184 static void map_wparam_WtoA( MSG
*msg
, BOOL remove
)
194 if (!HIWORD(msg
->wParam
))
196 cp
= get_input_codepage();
197 wch
[0] = LOWORD(msg
->wParam
);
199 len
= WideCharToMultiByte( cp
, 0, wch
, 1, (LPSTR
)ch
, 2, NULL
, NULL
);
200 if (len
== 2) /* DBCS char */
202 struct wm_char_mapping_data
*data
= get_wmchar_data();
205 if (!(data
= HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(*data
) ))) return;
206 NtUserGetThreadInfo()->wmchar_data
= (UINT_PTR
)data
;
210 data
->get_msg
= *msg
;
211 data
->get_msg
.wParam
= ch
[1];
217 /* else fall through */
219 case EM_SETPASSWORDCHAR
:
224 cp
= get_input_codepage();
225 wch
[0] = LOWORD(msg
->wParam
);
226 wch
[1] = HIWORD(msg
->wParam
);
228 WideCharToMultiByte( cp
, 0, wch
, 2, (LPSTR
)ch
, 4, NULL
, NULL
);
229 msg
->wParam
= MAKEWPARAM( ch
[0] | (ch
[1] << 8), 0 );
232 cp
= get_input_codepage();
233 wch
[0] = LOWORD(msg
->wParam
);
235 len
= WideCharToMultiByte( cp
, 0, wch
, 1, (LPSTR
)ch
, 2, NULL
, NULL
);
237 msg
->wParam
= MAKEWPARAM( (ch
[0] << 8) | ch
[1], HIWORD(msg
->wParam
) );
239 msg
->wParam
= MAKEWPARAM( ch
[0], HIWORD(msg
->wParam
) );
245 /* since the WM_DDE_ACK response to a WM_DDE_EXECUTE message should contain the handle
246 * to the memory handle, we keep track (in the server side) of all pairs of handle
247 * used (the client passes its value and the content of the memory handle), and
248 * the server stored both values (the client, and the local one, created after the
249 * content). When a ACK message is generated, the list of pair is searched for a
250 * matching pair, so that the client memory handle can be returned.
257 static struct DDE_pair
* dde_pairs
;
258 static int dde_num_alloc
;
259 static int dde_num_used
;
261 static CRITICAL_SECTION dde_crst
;
262 static CRITICAL_SECTION_DEBUG critsect_debug
=
265 { &critsect_debug
.ProcessLocksList
, &critsect_debug
.ProcessLocksList
},
266 0, 0, { (DWORD_PTR
)(__FILE__
": dde_crst") }
268 static CRITICAL_SECTION dde_crst
= { &critsect_debug
, -1, 0, 0, 0, 0 };
270 static BOOL
dde_add_pair(HGLOBAL chm
, HGLOBAL shm
)
275 EnterCriticalSection(&dde_crst
);
277 /* now remember the pair of hMem on both sides */
278 if (dde_num_used
== dde_num_alloc
)
280 struct DDE_pair
* tmp
;
282 tmp
= HeapReAlloc( GetProcessHeap(), 0, dde_pairs
,
283 (dde_num_alloc
+ GROWBY
) * sizeof(struct DDE_pair
));
285 tmp
= HeapAlloc( GetProcessHeap(), 0,
286 (dde_num_alloc
+ GROWBY
) * sizeof(struct DDE_pair
));
290 LeaveCriticalSection(&dde_crst
);
294 /* zero out newly allocated part */
295 memset(&dde_pairs
[dde_num_alloc
], 0, GROWBY
* sizeof(struct DDE_pair
));
296 dde_num_alloc
+= GROWBY
;
299 for (i
= 0; i
< dde_num_alloc
; i
++)
301 if (dde_pairs
[i
].server_hMem
== 0)
303 dde_pairs
[i
].client_hMem
= chm
;
304 dde_pairs
[i
].server_hMem
= shm
;
309 LeaveCriticalSection(&dde_crst
);
313 static HGLOBAL
dde_get_pair(HGLOBAL shm
)
318 EnterCriticalSection(&dde_crst
);
319 for (i
= 0; i
< dde_num_alloc
; i
++)
321 if (dde_pairs
[i
].server_hMem
== shm
)
324 dde_pairs
[i
].server_hMem
= 0;
326 ret
= dde_pairs
[i
].client_hMem
;
330 LeaveCriticalSection(&dde_crst
);
334 /***********************************************************************
339 BOOL
post_dde_message( HWND hwnd
, UINT msg
, WPARAM wparam
, LPARAM lparam
, DWORD dest_tid
, DWORD type
)
349 if (!UnpackDDElParam( msg
, lparam
, &uiLo
, &uiHi
))
355 /* DDE messages which don't require packing are:
364 /* uiHi should contain a hMem from WM_DDE_EXECUTE */
365 HGLOBAL h
= dde_get_pair( (HANDLE
)uiHi
);
368 hpack
= pack_ptr( h
);
369 /* send back the value of h on the other side */
371 size
= sizeof(hpack
);
373 TRACE( "send dde-ack %Ix %08Ix => %p\n", uiLo
, uiHi
, h
);
378 /* uiHi should contain either an atom or 0 */
379 TRACE( "send dde-ack %Ix atom=%Ix\n", uiLo
, uiHi
);
380 lp
= MAKELONG( uiLo
, uiHi
);
388 size
= GlobalSize( (HGLOBAL
)uiLo
) ;
389 if ((msg
== WM_DDE_ADVISE
&& size
< sizeof(DDEADVISE
)) ||
390 (msg
== WM_DDE_DATA
&& size
< FIELD_OFFSET(DDEDATA
, Value
)) ||
391 (msg
== WM_DDE_POKE
&& size
< FIELD_OFFSET(DDEPOKE
, Value
)))
394 else if (msg
!= WM_DDE_DATA
) return FALSE
;
399 if ((ptr
= GlobalLock( (HGLOBAL
)uiLo
) ))
401 DDEDATA
*dde_data
= ptr
;
402 TRACE("unused %d, fResponse %d, fRelease %d, fDeferUpd %d, fAckReq %d, cfFormat %d\n",
403 dde_data
->unused
, dde_data
->fResponse
, dde_data
->fRelease
,
404 dde_data
->reserved
, dde_data
->fAckReq
, dde_data
->cfFormat
);
405 hunlock
= (HGLOBAL
)uiLo
;
408 TRACE( "send ddepack %u %Ix\n", size
, uiHi
);
413 if ((ptr
= GlobalLock( (HGLOBAL
)lparam
) ))
415 size
= GlobalSize( (HGLOBAL
)lparam
);
416 /* so that the other side can send it back on ACK */
418 hunlock
= (HGLOBAL
)lparam
;
423 SERVER_START_REQ( send_message
)
428 req
->win
= wine_server_user_handle( hwnd
);
430 req
->wparam
= wparam
;
432 req
->timeout
= TIMEOUT_INFINITE
;
433 if (size
) wine_server_add_data( req
, ptr
, size
);
434 if ((res
= wine_server_call( req
)))
436 if (res
== STATUS_INVALID_PARAMETER
)
437 /* FIXME: find a STATUS_ value for this one */
438 SetLastError( ERROR_INVALID_THREAD_ID
);
440 SetLastError( RtlNtStatusToDosError(res
) );
443 FreeDDElParam( msg
, lparam
);
446 if (hunlock
) GlobalUnlock(hunlock
);
451 /***********************************************************************
454 * Unpack a posted DDE message received from another process.
456 BOOL
unpack_dde_message( HWND hwnd
, UINT message
, WPARAM
*wparam
, LPARAM
*lparam
,
457 const void *buffer
, size_t size
)
469 /* hMem is being passed */
470 if (size
!= sizeof(hpack
)) return FALSE
;
472 memcpy( &hpack
, buffer
, size
);
473 hMem
= unpack_ptr( hpack
);
474 uiHi
= (UINT_PTR
)hMem
;
475 TRACE("recv dde-ack %Ix mem=%Ix[%Ix]\n", uiLo
, uiHi
, GlobalSize( hMem
));
479 uiLo
= LOWORD( *lparam
);
480 uiHi
= HIWORD( *lparam
);
481 TRACE("recv dde-ack %Ix atom=%Ix\n", uiLo
, uiHi
);
483 *lparam
= PackDDElParam( WM_DDE_ACK
, uiLo
, uiHi
);
488 if (!size
&& message
!= WM_DDE_DATA
) return FALSE
;
492 if (!(hMem
= GlobalAlloc( GMEM_MOVEABLE
|GMEM_DDESHARE
, size
)))
494 if ((ptr
= GlobalLock( hMem
)))
496 memcpy( ptr
, buffer
, size
);
497 GlobalUnlock( hMem
);
505 uiLo
= (UINT_PTR
)hMem
;
507 *lparam
= PackDDElParam( message
, uiLo
, uiHi
);
512 if (!(hMem
= GlobalAlloc( GMEM_MOVEABLE
|GMEM_DDESHARE
, size
))) return FALSE
;
513 if ((ptr
= GlobalLock( hMem
)))
515 memcpy( ptr
, buffer
, size
);
516 GlobalUnlock( hMem
);
517 TRACE( "exec: pairing c=%08Ix s=%p\n", *lparam
, hMem
);
518 if (!dde_add_pair( (HGLOBAL
)*lparam
, hMem
))
530 *lparam
= (LPARAM
)hMem
;
536 /***********************************************************************
537 * SendMessageTimeoutW (USER32.@)
539 LRESULT WINAPI
SendMessageTimeoutW( HWND hwnd
, UINT msg
, WPARAM wparam
, LPARAM lparam
,
540 UINT flags
, UINT timeout
, PDWORD_PTR res_ptr
)
542 struct send_message_timeout_params params
= { .flags
= flags
, .timeout
= timeout
};
545 res
= NtUserMessageCall( hwnd
, msg
, wparam
, lparam
, ¶ms
, NtUserSendMessageTimeout
, FALSE
);
546 if (res_ptr
) *res_ptr
= res
;
547 return params
.result
;
550 /***********************************************************************
551 * SendMessageTimeoutA (USER32.@)
553 LRESULT WINAPI
SendMessageTimeoutA( HWND hwnd
, UINT msg
, WPARAM wparam
, LPARAM lparam
,
554 UINT flags
, UINT timeout
, PDWORD_PTR res_ptr
)
556 struct send_message_timeout_params params
= { .flags
= flags
, .timeout
= timeout
};
559 if (msg
!= WM_CHAR
|| WIN_IsCurrentThread( hwnd
))
561 res
= NtUserMessageCall( hwnd
, msg
, wparam
, lparam
, ¶ms
,
562 NtUserSendMessageTimeout
, TRUE
);
564 else if (map_wparam_AtoW( msg
, &wparam
, WMCHAR_MAP_SENDMESSAGE
))
566 res
= NtUserMessageCall( hwnd
, msg
, wparam
, lparam
, ¶ms
,
567 NtUserSendMessageTimeout
, FALSE
);
570 if (res_ptr
) *res_ptr
= res
;
571 return params
.result
;
575 static LRESULT
dispatch_send_message( struct win_proc_params
*params
, WPARAM wparam
, LPARAM lparam
)
577 struct ntuser_thread_info
*thread_info
= NtUserGetThreadInfo();
578 INPUT_MESSAGE_SOURCE prev_source
= thread_info
->msg_source
;
581 static const INPUT_MESSAGE_SOURCE msg_source_unavailable
= { IMDT_UNAVAILABLE
, IMO_UNAVAILABLE
};
583 /* params may contain arguments modified by wow, use original parameters instead */
584 params
->wparam
= wparam
;
585 params
->lparam
= lparam
;
587 thread_info
->recursion_count
++;
589 params
->result
= &retval
;
590 thread_info
->msg_source
= msg_source_unavailable
;
591 SPY_EnterMessage( SPY_SENDMESSAGE
, params
->hwnd
, params
->msg
, params
->wparam
, params
->lparam
);
593 dispatch_win_proc_params( params
);
595 SPY_ExitMessage( SPY_RESULT_OK
, params
->hwnd
, params
->msg
, retval
, params
->wparam
, params
->lparam
);
596 thread_info
->msg_source
= prev_source
;
597 thread_info
->recursion_count
--;
602 /***********************************************************************
603 * SendMessageW (USER32.@)
605 LRESULT WINAPI
SendMessageW( HWND hwnd
, UINT msg
, WPARAM wparam
, LPARAM lparam
)
607 struct win_proc_params params
;
611 retval
= NtUserMessageCall( hwnd
, msg
, wparam
, lparam
, ¶ms
, NtUserSendMessage
, FALSE
);
612 if (params
.hwnd
) retval
= dispatch_send_message( ¶ms
, wparam
, lparam
);
617 /***********************************************************************
618 * SendMessageA (USER32.@)
620 LRESULT WINAPI
SendMessageA( HWND hwnd
, UINT msg
, WPARAM wparam
, LPARAM lparam
)
622 struct win_proc_params params
;
625 if (msg
== WM_CHAR
&& !WIN_IsCurrentThread( hwnd
))
627 if (!map_wparam_AtoW( msg
, &wparam
, WMCHAR_MAP_SENDMESSAGE
))
629 return NtUserMessageCall( hwnd
, msg
, wparam
, lparam
, NULL
, NtUserSendMessage
, FALSE
);
633 retval
= NtUserMessageCall( hwnd
, msg
, wparam
, lparam
, ¶ms
, NtUserSendMessage
, TRUE
);
634 if (params
.hwnd
) retval
= dispatch_send_message( ¶ms
, wparam
, lparam
);
639 /***********************************************************************
640 * SendNotifyMessageA (USER32.@)
642 BOOL WINAPI
SendNotifyMessageA( HWND hwnd
, UINT msg
, WPARAM wparam
, LPARAM lparam
)
644 if (!WIN_IsCurrentThread( hwnd
) && !map_wparam_AtoW( msg
, &wparam
, WMCHAR_MAP_SENDMESSAGE
))
647 return NtUserMessageCall( hwnd
, msg
, wparam
, lparam
, 0, NtUserSendNotifyMessage
, TRUE
);
651 /***********************************************************************
652 * SendNotifyMessageW (USER32.@)
654 BOOL WINAPI
SendNotifyMessageW( HWND hwnd
, UINT msg
, WPARAM wparam
, LPARAM lparam
)
656 return NtUserMessageCall( hwnd
, msg
, wparam
, lparam
, 0, NtUserSendNotifyMessage
, FALSE
);
660 /***********************************************************************
661 * SendMessageCallbackA (USER32.@)
663 BOOL WINAPI
SendMessageCallbackA( HWND hwnd
, UINT msg
, WPARAM wparam
, LPARAM lparam
,
664 SENDASYNCPROC callback
, ULONG_PTR data
)
666 struct send_message_callback_params params
= { .callback
= callback
, .data
= data
};
668 if (!WIN_IsCurrentThread( hwnd
) && !map_wparam_AtoW( msg
, &wparam
, WMCHAR_MAP_SENDMESSAGE
))
671 return NtUserMessageCall( hwnd
, msg
, wparam
, lparam
, ¶ms
, NtUserSendMessageCallback
, TRUE
);
675 /***********************************************************************
676 * SendMessageCallbackW (USER32.@)
678 BOOL WINAPI
SendMessageCallbackW( HWND hwnd
, UINT msg
, WPARAM wparam
, LPARAM lparam
,
679 SENDASYNCPROC callback
, ULONG_PTR data
)
681 struct send_message_callback_params params
= { .callback
= callback
, .data
= data
};
682 return NtUserMessageCall( hwnd
, msg
, wparam
, lparam
, ¶ms
, NtUserSendMessageCallback
, FALSE
);
686 /***********************************************************************
687 * ReplyMessage (USER32.@)
689 BOOL WINAPI
ReplyMessage( LRESULT result
)
691 return NtUserReplyMessage( result
);
695 /***********************************************************************
696 * InSendMessage (USER32.@)
698 BOOL WINAPI
InSendMessage(void)
700 return (InSendMessageEx( NULL
) & (ISMEX_SEND
| ISMEX_NOTIFY
| ISMEX_CALLBACK
)) != 0;
704 /***********************************************************************
705 * InSendMessageEx (USER32.@)
707 DWORD WINAPI
InSendMessageEx( LPVOID reserved
)
709 return NtUserGetThreadInfo()->receive_flags
;
713 /***********************************************************************
714 * PostMessageA (USER32.@)
716 BOOL WINAPI
PostMessageA( HWND hwnd
, UINT msg
, WPARAM wparam
, LPARAM lparam
)
718 if (!map_wparam_AtoW( msg
, &wparam
, WMCHAR_MAP_POSTMESSAGE
)) return TRUE
;
719 return PostMessageW( hwnd
, msg
, wparam
, lparam
);
723 /***********************************************************************
724 * PostMessageW (USER32.@)
726 BOOL WINAPI
PostMessageW( HWND hwnd
, UINT msg
, WPARAM wparam
, LPARAM lparam
)
728 return NtUserPostMessage( hwnd
, msg
, wparam
, lparam
);
732 /**********************************************************************
733 * PostThreadMessageA (USER32.@)
735 BOOL WINAPI
PostThreadMessageA( DWORD thread
, UINT msg
, WPARAM wparam
, LPARAM lparam
)
737 if (!map_wparam_AtoW( msg
, &wparam
, WMCHAR_MAP_POSTMESSAGE
)) return TRUE
;
738 return NtUserPostThreadMessage( thread
, msg
, wparam
, lparam
);
742 /***********************************************************************
743 * PostQuitMessage (USER32.@)
745 * Posts a quit message to the current thread's message queue.
748 * exit_code [I] Exit code to return from message loop.
754 * This function is not the same as calling:
755 *|PostThreadMessage(GetCurrentThreadId(), WM_QUIT, exit_code, 0);
756 * It instead sets a flag in the message queue that signals it to generate
757 * a WM_QUIT message when there are no other pending sent or posted messages
760 void WINAPI
PostQuitMessage( INT exit_code
)
762 SERVER_START_REQ( post_quit_message
)
764 req
->exit_code
= exit_code
;
765 wine_server_call( req
);
770 /***********************************************************************
771 * PeekMessageW (USER32.@)
773 BOOL WINAPI DECLSPEC_HOTPATCH
PeekMessageW( MSG
*msg_out
, HWND hwnd
, UINT first
, UINT last
, UINT flags
)
775 return NtUserPeekMessage( msg_out
, hwnd
, first
, last
, flags
);
779 /***********************************************************************
780 * PeekMessageA (USER32.@)
782 BOOL WINAPI DECLSPEC_HOTPATCH
PeekMessageA( MSG
*msg
, HWND hwnd
, UINT first
, UINT last
, UINT flags
)
784 if (get_pending_wmchar( msg
, first
, last
, (flags
& PM_REMOVE
) )) return TRUE
;
785 if (!PeekMessageW( msg
, hwnd
, first
, last
, flags
)) return FALSE
;
786 map_wparam_WtoA( msg
, (flags
& PM_REMOVE
) );
791 /***********************************************************************
792 * GetMessageW (USER32.@)
794 BOOL WINAPI DECLSPEC_HOTPATCH
GetMessageW( MSG
*msg
, HWND hwnd
, UINT first
, UINT last
)
796 return NtUserGetMessage( msg
, hwnd
, first
, last
);
800 /***********************************************************************
801 * GetMessageA (USER32.@)
803 BOOL WINAPI DECLSPEC_HOTPATCH
GetMessageA( MSG
*msg
, HWND hwnd
, UINT first
, UINT last
)
805 if (get_pending_wmchar( msg
, first
, last
, TRUE
)) return TRUE
;
806 if (GetMessageW( msg
, hwnd
, first
, last
) < 0) return -1;
807 map_wparam_WtoA( msg
, TRUE
);
808 return (msg
->message
!= WM_QUIT
);
812 /***********************************************************************
813 * IsDialogMessageA (USER32.@)
814 * IsDialogMessage (USER32.@)
816 BOOL WINAPI
IsDialogMessageA( HWND hwndDlg
, LPMSG pmsg
)
819 map_wparam_AtoW( msg
.message
, &msg
.wParam
, WMCHAR_MAP_NOMAPPING
);
820 return IsDialogMessageW( hwndDlg
, &msg
);
824 /***********************************************************************
825 * TranslateMessage (USER32.@)
827 * Implementation of TranslateMessage.
829 * TranslateMessage translates virtual-key messages into character-messages,
831 * WM_KEYDOWN/WM_KEYUP combinations produce a WM_CHAR or WM_DEADCHAR message.
832 * ditto replacing WM_* with WM_SYS*
833 * This produces WM_CHAR messages only for keys mapped to ASCII characters
834 * by the keyboard driver.
836 * If the message is WM_KEYDOWN, WM_KEYUP, WM_SYSKEYDOWN, or WM_SYSKEYUP, the
837 * return value is nonzero, regardless of the translation.
840 BOOL WINAPI
TranslateMessage( const MSG
*msg
)
842 return NtUserTranslateMessage( msg
, 0 );
846 static LRESULT
dispatch_message( const MSG
*msg
, BOOL ansi
)
848 struct win_proc_params params
;
851 if (!NtUserMessageCall( msg
->hwnd
, msg
->message
, msg
->wParam
, msg
->lParam
,
852 ¶ms
, NtUserGetDispatchParams
, ansi
)) return 0;
853 params
.result
= &retval
;
855 SPY_EnterMessage( SPY_DISPATCHMESSAGE
, msg
->hwnd
, msg
->message
, msg
->wParam
, msg
->lParam
);
856 dispatch_win_proc_params( ¶ms
);
857 SPY_ExitMessage( SPY_RESULT_OK
, msg
->hwnd
, msg
->message
, retval
, msg
->wParam
, msg
->lParam
);
862 /***********************************************************************
863 * DispatchMessageA (USER32.@)
865 * See DispatchMessageW.
867 LRESULT WINAPI DECLSPEC_HOTPATCH
DispatchMessageA( const MSG
* msg
)
871 /* Process timer messages */
872 if (msg
->lParam
&& msg
->message
== WM_TIMER
)
876 retval
= CallWindowProcA( (WNDPROC
)msg
->lParam
, msg
->hwnd
,
877 msg
->message
, msg
->wParam
, GetTickCount() );
887 /* whenever possible, avoid using NtUserDispatchMessage to make the call unwindable */
888 if (msg
->message
!= WM_SYSTIMER
&& msg
->message
!= WM_PAINT
)
889 return dispatch_message( msg
, TRUE
);
891 return NtUserDispatchMessage( msg
);
895 /***********************************************************************
896 * DispatchMessageW (USER32.@) Process a message
898 * Process the message specified in the structure *_msg_.
900 * If the lpMsg parameter points to a WM_TIMER message and the
901 * parameter of the WM_TIMER message is not NULL, the lParam parameter
902 * points to the function that is called instead of the window
903 * procedure. The function stored in lParam (timer callback) is protected
904 * from causing page-faults.
906 * The message must be valid.
910 * DispatchMessage() returns the result of the window procedure invoked.
917 LRESULT WINAPI DECLSPEC_HOTPATCH
DispatchMessageW( const MSG
* msg
)
921 /* Process timer messages */
922 if ((msg
->message
== WM_TIMER
) || (msg
->message
== WM_SYSTIMER
))
928 retval
= CallWindowProcW( (WNDPROC
)msg
->lParam
, msg
->hwnd
,
929 msg
->message
, msg
->wParam
, GetTickCount() );
940 /* whenever possible, avoid using NtUserDispatchMessage to make the call unwindable */
941 if (msg
->message
!= WM_SYSTIMER
&& msg
->message
!= WM_PAINT
)
942 return dispatch_message( msg
, FALSE
);
944 return NtUserDispatchMessage( msg
);
948 /***********************************************************************
949 * GetMessagePos (USER.119)
950 * GetMessagePos (USER32.@)
952 * The GetMessagePos() function returns a long value representing a
953 * cursor position, in screen coordinates, when the last message
954 * retrieved by the GetMessage() function occurs. The x-coordinate is
955 * in the low-order word of the return value, the y-coordinate is in
956 * the high-order word. The application can use the MAKEPOINT()
957 * macro to obtain a POINT structure from the return value.
959 * For the current cursor position, use GetCursorPos().
963 * Cursor position of last message on success, zero on failure.
970 DWORD WINAPI
GetMessagePos(void)
972 return NtUserGetThreadInfo()->message_pos
;
976 /***********************************************************************
977 * GetMessageTime (USER.120)
978 * GetMessageTime (USER32.@)
980 * GetMessageTime() returns the message time for the last message
981 * retrieved by the function. The time is measured in milliseconds with
982 * the same offset as GetTickCount().
984 * Since the tick count wraps, this is only useful for moderately short
985 * relative time comparisons.
989 * Time of last message on success, zero on failure.
991 LONG WINAPI
GetMessageTime(void)
993 return NtUserGetThreadInfo()->message_time
;
997 /***********************************************************************
998 * GetMessageExtraInfo (USER.288)
999 * GetMessageExtraInfo (USER32.@)
1001 LPARAM WINAPI
GetMessageExtraInfo(void)
1003 return NtUserGetThreadInfo()->message_extra
;
1007 /***********************************************************************
1008 * SetMessageExtraInfo (USER32.@)
1010 LPARAM WINAPI
SetMessageExtraInfo(LPARAM lParam
)
1012 struct ntuser_thread_info
*thread_info
= NtUserGetThreadInfo();
1013 LONG old_value
= thread_info
->message_extra
;
1014 thread_info
->message_extra
= lParam
;
1019 /***********************************************************************
1020 * GetCurrentInputMessageSource (USER32.@)
1022 BOOL WINAPI
GetCurrentInputMessageSource( INPUT_MESSAGE_SOURCE
*source
)
1024 *source
= NtUserGetThreadInfo()->msg_source
;
1029 /***********************************************************************
1030 * WaitMessage (USER.112) Suspend thread pending messages
1031 * WaitMessage (USER32.@) Suspend thread pending messages
1033 * WaitMessage() suspends a thread until events appear in the thread's
1036 BOOL WINAPI
WaitMessage(void)
1038 return NtUserMsgWaitForMultipleObjectsEx( 0, NULL
, INFINITE
, QS_ALLINPUT
, 0 ) != WAIT_FAILED
;
1042 /***********************************************************************
1043 * MsgWaitForMultipleObjects (USER32.@)
1045 DWORD WINAPI
MsgWaitForMultipleObjects( DWORD count
, const HANDLE
*handles
,
1046 BOOL wait_all
, DWORD timeout
, DWORD mask
)
1048 return NtUserMsgWaitForMultipleObjectsEx( count
, handles
, timeout
, mask
,
1049 wait_all
? MWMO_WAITALL
: 0 );
1053 /***********************************************************************
1054 * WaitForInputIdle (USER32.@)
1056 DWORD WINAPI
WaitForInputIdle( HANDLE process
, DWORD timeout
)
1058 return NtUserWaitForInputIdle( process
, timeout
, FALSE
);
1062 /***********************************************************************
1063 * RegisterWindowMessageA (USER32.@)
1064 * RegisterWindowMessage (USER.118)
1066 UINT WINAPI
RegisterWindowMessageA( LPCSTR str
)
1068 UINT ret
= GlobalAddAtomA(str
);
1069 TRACE("%s, ret=%x\n", str
, ret
);
1074 /***********************************************************************
1075 * RegisterWindowMessageW (USER32.@)
1077 UINT WINAPI
RegisterWindowMessageW( LPCWSTR str
)
1079 UINT ret
= GlobalAddAtomW(str
);
1080 TRACE("%s ret=%x\n", debugstr_w(str
), ret
);
1084 typedef struct BroadcastParm
1095 static BOOL CALLBACK
bcast_childwindow( HWND hw
, LPARAM lp
)
1097 BroadcastParm
*parm
= (BroadcastParm
*)lp
;
1098 DWORD_PTR retval
= 0;
1101 if (parm
->flags
& BSF_IGNORECURRENTTASK
&& WIN_IsCurrentProcess(hw
))
1103 TRACE("Not telling myself %p\n", hw
);
1107 /* I don't know 100% for sure if this is what Windows does, but it fits the tests */
1108 if (parm
->flags
& BSF_QUERY
)
1110 TRACE("Telling window %p using SendMessageTimeout\n", hw
);
1112 /* Not tested for conflicting flags */
1113 if (parm
->flags
& BSF_FORCEIFHUNG
|| parm
->flags
& BSF_NOHANG
)
1114 lresult
= SendMessageTimeoutW( hw
, parm
->msg
, parm
->wp
, parm
->lp
, SMTO_ABORTIFHUNG
, 2000, &retval
);
1115 else if (parm
->flags
& BSF_NOTIMEOUTIFNOTHUNG
)
1116 lresult
= SendMessageTimeoutW( hw
, parm
->msg
, parm
->wp
, parm
->lp
, SMTO_NOTIMEOUTIFNOTHUNG
, 2000, &retval
);
1118 lresult
= SendMessageTimeoutW( hw
, parm
->msg
, parm
->wp
, parm
->lp
, SMTO_NORMAL
, 2000, &retval
);
1120 if (!lresult
&& GetLastError() == ERROR_TIMEOUT
)
1122 WARN("Timed out!\n");
1123 if (!(parm
->flags
& BSF_FORCEIFHUNG
))
1126 if (retval
== BROADCAST_QUERY_DENY
)
1132 parm
->success
= FALSE
;
1135 else if (parm
->flags
& BSF_POSTMESSAGE
)
1137 TRACE("Telling window %p using PostMessage\n", hw
);
1138 PostMessageW( hw
, parm
->msg
, parm
->wp
, parm
->lp
);
1142 TRACE("Telling window %p using SendNotifyMessage\n", hw
);
1143 SendNotifyMessageW( hw
, parm
->msg
, parm
->wp
, parm
->lp
);
1149 static BOOL CALLBACK
bcast_desktop( LPWSTR desktop
, LPARAM lp
)
1153 BroadcastParm
*parm
= (BroadcastParm
*)lp
;
1155 TRACE("desktop: %s\n", debugstr_w( desktop
));
1157 hdesktop
= open_winstation_desktop( parm
->winsta
, desktop
, 0, FALSE
, DESKTOP_ENUMERATE
|DESKTOP_WRITEOBJECTS
|STANDARD_RIGHTS_WRITE
);
1160 FIXME("Could not open desktop %s\n", debugstr_w(desktop
));
1164 ret
= EnumDesktopWindows( hdesktop
, bcast_childwindow
, lp
);
1165 NtUserCloseDesktop( hdesktop
);
1166 TRACE("-->%d\n", ret
);
1167 return parm
->success
;
1170 static BOOL CALLBACK
bcast_winsta( LPWSTR winsta
, LPARAM lp
)
1173 HWINSTA hwinsta
= OpenWindowStationW( winsta
, FALSE
, WINSTA_ENUMDESKTOPS
);
1174 TRACE("hwinsta: %p/%s/%08lx\n", hwinsta
, debugstr_w( winsta
), GetLastError());
1177 ((BroadcastParm
*)lp
)->winsta
= hwinsta
;
1178 ret
= EnumDesktopsW( hwinsta
, bcast_desktop
, lp
);
1179 NtUserCloseWindowStation( hwinsta
);
1180 TRACE("-->%d\n", ret
);
1184 /***********************************************************************
1185 * BroadcastSystemMessageA (USER32.@)
1186 * BroadcastSystemMessage (USER32.@)
1188 LONG WINAPI
BroadcastSystemMessageA( DWORD flags
, LPDWORD recipients
, UINT msg
, WPARAM wp
, LPARAM lp
)
1190 return BroadcastSystemMessageExA( flags
, recipients
, msg
, wp
, lp
, NULL
);
1194 /***********************************************************************
1195 * BroadcastSystemMessageW (USER32.@)
1197 LONG WINAPI
BroadcastSystemMessageW( DWORD flags
, LPDWORD recipients
, UINT msg
, WPARAM wp
, LPARAM lp
)
1199 return BroadcastSystemMessageExW( flags
, recipients
, msg
, wp
, lp
, NULL
);
1202 /***********************************************************************
1203 * BroadcastSystemMessageExA (USER32.@)
1205 LONG WINAPI
BroadcastSystemMessageExA( DWORD flags
, LPDWORD recipients
, UINT msg
, WPARAM wp
, LPARAM lp
, PBSMINFO pinfo
)
1207 map_wparam_AtoW( msg
, &wp
, WMCHAR_MAP_NOMAPPING
);
1208 return BroadcastSystemMessageExW( flags
, recipients
, msg
, wp
, lp
, NULL
);
1212 /***********************************************************************
1213 * BroadcastSystemMessageExW (USER32.@)
1215 LONG WINAPI
BroadcastSystemMessageExW( DWORD flags
, LPDWORD recipients
, UINT msg
, WPARAM wp
, LPARAM lp
, PBSMINFO pinfo
)
1218 DWORD recips
= BSM_ALLCOMPONENTS
;
1220 static const DWORD all_flags
= ( BSF_QUERY
| BSF_IGNORECURRENTTASK
| BSF_FLUSHDISK
| BSF_NOHANG
1221 | BSF_POSTMESSAGE
| BSF_FORCEIFHUNG
| BSF_NOTIMEOUTIFNOTHUNG
1222 | BSF_ALLOWSFW
| BSF_SENDNOTIFYMESSAGE
| BSF_RETURNHDESK
| BSF_LUID
);
1224 TRACE("Flags: %08lx, recipients: %p(0x%lx), msg: %04x, wparam: %08Ix, lparam: %08Ix\n", flags
, recipients
,
1225 (recipients
? *recipients
: recips
), msg
, wp
, lp
);
1227 if (flags
& ~all_flags
)
1229 SetLastError(ERROR_INVALID_PARAMETER
);
1234 recipients
= &recips
;
1236 if ( pinfo
&& flags
& BSF_QUERY
)
1237 FIXME("Not returning PBSMINFO information yet\n");
1240 parm
.recipients
= recipients
;
1244 parm
.success
= TRUE
;
1246 if (*recipients
& BSM_ALLDESKTOPS
|| *recipients
== BSM_ALLCOMPONENTS
)
1247 ret
= EnumWindowStationsW(bcast_winsta
, (LONG_PTR
)&parm
);
1248 else if (*recipients
& BSM_APPLICATIONS
)
1250 EnumWindows(bcast_childwindow
, (LONG_PTR
)&parm
);
1254 FIXME("Recipients %08lx not supported!\n", *recipients
);
1259 /***********************************************************************
1260 * SetMessageQueue (USER32.@)
1262 BOOL WINAPI
SetMessageQueue( INT size
)
1264 /* now obsolete the message queue will be expanded dynamically as necessary */
1269 /***********************************************************************
1270 * MessageBeep (USER32.@)
1272 BOOL WINAPI
MessageBeep( UINT i
)
1274 return NtUserMessageBeep( i
);
1278 /******************************************************************
1279 * SetTimer (USER32.@)
1281 UINT_PTR WINAPI
SetTimer( HWND hwnd
, UINT_PTR id
, UINT timeout
, TIMERPROC proc
)
1283 return NtUserSetTimer( hwnd
, id
, timeout
, proc
, TIMERV_DEFAULT_COALESCING
);
1287 /******************************************************************
1288 * SetSystemTimer (USER32.@)
1290 UINT_PTR WINAPI
SetSystemTimer( HWND hwnd
, UINT_PTR id
, UINT timeout
, void *unknown
)
1292 if (unknown
) FIXME( "ignoring unknown parameter %p\n", unknown
);
1294 return NtUserSetSystemTimer( hwnd
, id
, timeout
);
1298 /***********************************************************************
1299 * KillSystemTimer (USER32.@)
1301 BOOL WINAPI
KillSystemTimer( HWND hwnd
, UINT_PTR id
)
1303 return NtUserKillSystemTimer( hwnd
, id
);
1307 /**********************************************************************
1308 * IsGUIThread (USER32.@)
1310 BOOL WINAPI
IsGUIThread( BOOL convert
)
1312 FIXME( "%u: stub\n", convert
);
1317 /******************************************************************
1318 * IsHungAppWindow (USER32.@)
1321 BOOL WINAPI
IsHungAppWindow( HWND hWnd
)
1325 SERVER_START_REQ( is_window_hung
)
1327 req
->win
= wine_server_user_handle( hWnd
);
1328 ret
= !wine_server_call_err( req
) && reply
->is_hung
;
1334 /******************************************************************
1335 * ChangeWindowMessageFilter (USER32.@)
1337 BOOL WINAPI
ChangeWindowMessageFilter( UINT message
, DWORD flag
)
1339 FIXME( "%x %08lx\n", message
, flag
);
1343 /******************************************************************
1344 * ChangeWindowMessageFilterEx (USER32.@)
1346 BOOL WINAPI
ChangeWindowMessageFilterEx( HWND hwnd
, UINT message
, DWORD action
, CHANGEFILTERSTRUCT
*changefilter
)
1348 FIXME( "%p %x %ld %p\n", hwnd
, message
, action
, changefilter
);