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 thread_info
->msg_source
= msg_source_unavailable
;
590 SPY_EnterMessage( SPY_SENDMESSAGE
, params
->hwnd
, params
->msg
, params
->wparam
, params
->lparam
);
592 retval
= dispatch_win_proc_params( params
);
594 SPY_ExitMessage( SPY_RESULT_OK
, params
->hwnd
, params
->msg
, retval
, params
->wparam
, params
->lparam
);
595 thread_info
->msg_source
= prev_source
;
596 thread_info
->recursion_count
--;
601 /***********************************************************************
602 * SendMessageW (USER32.@)
604 LRESULT WINAPI
SendMessageW( HWND hwnd
, UINT msg
, WPARAM wparam
, LPARAM lparam
)
606 struct win_proc_params params
;
610 retval
= NtUserMessageCall( hwnd
, msg
, wparam
, lparam
, ¶ms
, NtUserSendMessage
, FALSE
);
611 if (params
.hwnd
) retval
= dispatch_send_message( ¶ms
, wparam
, lparam
);
616 /***********************************************************************
617 * SendMessageA (USER32.@)
619 LRESULT WINAPI
SendMessageA( HWND hwnd
, UINT msg
, WPARAM wparam
, LPARAM lparam
)
621 struct win_proc_params params
;
624 if (msg
== WM_CHAR
&& !WIN_IsCurrentThread( hwnd
))
626 if (!map_wparam_AtoW( msg
, &wparam
, WMCHAR_MAP_SENDMESSAGE
))
628 return NtUserMessageCall( hwnd
, msg
, wparam
, lparam
, NULL
, NtUserSendMessage
, FALSE
);
632 retval
= NtUserMessageCall( hwnd
, msg
, wparam
, lparam
, ¶ms
, NtUserSendMessage
, TRUE
);
633 if (params
.hwnd
) retval
= dispatch_send_message( ¶ms
, wparam
, lparam
);
638 /***********************************************************************
639 * SendNotifyMessageA (USER32.@)
641 BOOL WINAPI
SendNotifyMessageA( HWND hwnd
, UINT msg
, WPARAM wparam
, LPARAM lparam
)
643 if (!WIN_IsCurrentThread( hwnd
) && !map_wparam_AtoW( msg
, &wparam
, WMCHAR_MAP_SENDMESSAGE
))
646 return NtUserMessageCall( hwnd
, msg
, wparam
, lparam
, 0, NtUserSendNotifyMessage
, TRUE
);
650 /***********************************************************************
651 * SendNotifyMessageW (USER32.@)
653 BOOL WINAPI
SendNotifyMessageW( HWND hwnd
, UINT msg
, WPARAM wparam
, LPARAM lparam
)
655 return NtUserMessageCall( hwnd
, msg
, wparam
, lparam
, 0, NtUserSendNotifyMessage
, FALSE
);
659 /***********************************************************************
660 * SendMessageCallbackA (USER32.@)
662 BOOL WINAPI
SendMessageCallbackA( HWND hwnd
, UINT msg
, WPARAM wparam
, LPARAM lparam
,
663 SENDASYNCPROC callback
, ULONG_PTR data
)
665 struct send_message_callback_params params
= { .callback
= callback
, .data
= data
};
667 if (!WIN_IsCurrentThread( hwnd
) && !map_wparam_AtoW( msg
, &wparam
, WMCHAR_MAP_SENDMESSAGE
))
670 return NtUserMessageCall( hwnd
, msg
, wparam
, lparam
, ¶ms
, NtUserSendMessageCallback
, TRUE
);
674 /***********************************************************************
675 * SendMessageCallbackW (USER32.@)
677 BOOL WINAPI
SendMessageCallbackW( HWND hwnd
, UINT msg
, WPARAM wparam
, LPARAM lparam
,
678 SENDASYNCPROC callback
, ULONG_PTR data
)
680 struct send_message_callback_params params
= { .callback
= callback
, .data
= data
};
681 return NtUserMessageCall( hwnd
, msg
, wparam
, lparam
, ¶ms
, NtUserSendMessageCallback
, FALSE
);
685 /***********************************************************************
686 * ReplyMessage (USER32.@)
688 BOOL WINAPI
ReplyMessage( LRESULT result
)
690 return NtUserReplyMessage( result
);
694 /***********************************************************************
695 * InSendMessage (USER32.@)
697 BOOL WINAPI
InSendMessage(void)
699 return (InSendMessageEx( NULL
) & (ISMEX_SEND
| ISMEX_NOTIFY
| ISMEX_CALLBACK
)) != 0;
703 /***********************************************************************
704 * InSendMessageEx (USER32.@)
706 DWORD WINAPI
InSendMessageEx( LPVOID reserved
)
708 return NtUserGetThreadInfo()->receive_flags
;
712 /***********************************************************************
713 * PostMessageA (USER32.@)
715 BOOL WINAPI
PostMessageA( HWND hwnd
, UINT msg
, WPARAM wparam
, LPARAM lparam
)
717 if (!map_wparam_AtoW( msg
, &wparam
, WMCHAR_MAP_POSTMESSAGE
)) return TRUE
;
718 return PostMessageW( hwnd
, msg
, wparam
, lparam
);
722 /***********************************************************************
723 * PostMessageW (USER32.@)
725 BOOL WINAPI
PostMessageW( HWND hwnd
, UINT msg
, WPARAM wparam
, LPARAM lparam
)
727 return NtUserPostMessage( hwnd
, msg
, wparam
, lparam
);
731 /**********************************************************************
732 * PostThreadMessageA (USER32.@)
734 BOOL WINAPI
PostThreadMessageA( DWORD thread
, UINT msg
, WPARAM wparam
, LPARAM lparam
)
736 if (!map_wparam_AtoW( msg
, &wparam
, WMCHAR_MAP_POSTMESSAGE
)) return TRUE
;
737 return NtUserPostThreadMessage( thread
, msg
, wparam
, lparam
);
741 /***********************************************************************
742 * PostQuitMessage (USER32.@)
744 * Posts a quit message to the current thread's message queue.
747 * exit_code [I] Exit code to return from message loop.
753 * This function is not the same as calling:
754 *|PostThreadMessage(GetCurrentThreadId(), WM_QUIT, exit_code, 0);
755 * It instead sets a flag in the message queue that signals it to generate
756 * a WM_QUIT message when there are no other pending sent or posted messages
759 void WINAPI
PostQuitMessage( INT exit_code
)
761 SERVER_START_REQ( post_quit_message
)
763 req
->exit_code
= exit_code
;
764 wine_server_call( req
);
769 /***********************************************************************
770 * PeekMessageW (USER32.@)
772 BOOL WINAPI DECLSPEC_HOTPATCH
PeekMessageW( MSG
*msg_out
, HWND hwnd
, UINT first
, UINT last
, UINT flags
)
774 return NtUserPeekMessage( msg_out
, hwnd
, first
, last
, flags
);
778 /***********************************************************************
779 * PeekMessageA (USER32.@)
781 BOOL WINAPI DECLSPEC_HOTPATCH
PeekMessageA( MSG
*msg
, HWND hwnd
, UINT first
, UINT last
, UINT flags
)
783 if (get_pending_wmchar( msg
, first
, last
, (flags
& PM_REMOVE
) )) return TRUE
;
784 if (!PeekMessageW( msg
, hwnd
, first
, last
, flags
)) return FALSE
;
785 map_wparam_WtoA( msg
, (flags
& PM_REMOVE
) );
790 /***********************************************************************
791 * GetMessageW (USER32.@)
793 BOOL WINAPI DECLSPEC_HOTPATCH
GetMessageW( MSG
*msg
, HWND hwnd
, UINT first
, UINT last
)
795 return NtUserGetMessage( msg
, hwnd
, first
, last
);
799 /***********************************************************************
800 * GetMessageA (USER32.@)
802 BOOL WINAPI DECLSPEC_HOTPATCH
GetMessageA( MSG
*msg
, HWND hwnd
, UINT first
, UINT last
)
804 if (get_pending_wmchar( msg
, first
, last
, TRUE
)) return TRUE
;
805 if (GetMessageW( msg
, hwnd
, first
, last
) < 0) return -1;
806 map_wparam_WtoA( msg
, TRUE
);
807 return (msg
->message
!= WM_QUIT
);
810 static BOOL
is_cjk(void)
812 int lang_id
= PRIMARYLANGID(GetUserDefaultLangID());
814 if (lang_id
== LANG_CHINESE
|| lang_id
== LANG_JAPANESE
|| lang_id
== LANG_KOREAN
)
819 /***********************************************************************
820 * IsDialogMessageA (USER32.@)
821 * IsDialogMessage (USER32.@)
823 BOOL WINAPI
IsDialogMessageA( HWND hwndDlg
, LPMSG pmsg
)
825 enum wm_char_mapping mapping
;
828 mapping
= is_cjk() ? WMCHAR_MAP_ISDIALOGMESSAGE
: WMCHAR_MAP_NOMAPPING
;
829 if (!map_wparam_AtoW( msg
.message
, &msg
.wParam
, mapping
))
831 return IsDialogMessageW( hwndDlg
, &msg
);
835 /***********************************************************************
836 * TranslateMessage (USER32.@)
838 * Implementation of TranslateMessage.
840 * TranslateMessage translates virtual-key messages into character-messages,
842 * WM_KEYDOWN/WM_KEYUP combinations produce a WM_CHAR or WM_DEADCHAR message.
843 * ditto replacing WM_* with WM_SYS*
844 * This produces WM_CHAR messages only for keys mapped to ASCII characters
845 * by the keyboard driver.
847 * If the message is WM_KEYDOWN, WM_KEYUP, WM_SYSKEYDOWN, or WM_SYSKEYUP, the
848 * return value is nonzero, regardless of the translation.
851 BOOL WINAPI
TranslateMessage( const MSG
*msg
)
853 return NtUserTranslateMessage( msg
, 0 );
857 static LRESULT
dispatch_message( const MSG
*msg
, BOOL ansi
)
859 struct win_proc_params params
;
862 if (!NtUserMessageCall( msg
->hwnd
, msg
->message
, msg
->wParam
, msg
->lParam
,
863 ¶ms
, NtUserGetDispatchParams
, ansi
)) return 0;
865 SPY_EnterMessage( SPY_DISPATCHMESSAGE
, msg
->hwnd
, msg
->message
, msg
->wParam
, msg
->lParam
);
866 retval
= dispatch_win_proc_params( ¶ms
);
867 SPY_ExitMessage( SPY_RESULT_OK
, msg
->hwnd
, msg
->message
, retval
, msg
->wParam
, msg
->lParam
);
872 /***********************************************************************
873 * DispatchMessageA (USER32.@)
875 * See DispatchMessageW.
877 LRESULT WINAPI DECLSPEC_HOTPATCH
DispatchMessageA( const MSG
* msg
)
881 /* Process timer messages */
882 if (msg
->lParam
&& msg
->message
== WM_TIMER
)
886 retval
= CallWindowProcA( (WNDPROC
)msg
->lParam
, msg
->hwnd
,
887 msg
->message
, msg
->wParam
, GetTickCount() );
897 /* whenever possible, avoid using NtUserDispatchMessage to make the call unwindable */
898 if (msg
->message
!= WM_SYSTIMER
&& msg
->message
!= WM_PAINT
)
899 return dispatch_message( msg
, TRUE
);
901 return NtUserDispatchMessage( msg
);
905 /***********************************************************************
906 * DispatchMessageW (USER32.@) Process a message
908 * Process the message specified in the structure *_msg_.
910 * If the lpMsg parameter points to a WM_TIMER message and the
911 * parameter of the WM_TIMER message is not NULL, the lParam parameter
912 * points to the function that is called instead of the window
913 * procedure. The function stored in lParam (timer callback) is protected
914 * from causing page-faults.
916 * The message must be valid.
920 * DispatchMessage() returns the result of the window procedure invoked.
927 LRESULT WINAPI DECLSPEC_HOTPATCH
DispatchMessageW( const MSG
* msg
)
931 /* Process timer messages */
932 if ((msg
->message
== WM_TIMER
) || (msg
->message
== WM_SYSTIMER
))
938 retval
= CallWindowProcW( (WNDPROC
)msg
->lParam
, msg
->hwnd
,
939 msg
->message
, msg
->wParam
, GetTickCount() );
950 /* whenever possible, avoid using NtUserDispatchMessage to make the call unwindable */
951 if (msg
->message
!= WM_SYSTIMER
&& msg
->message
!= WM_PAINT
)
952 return dispatch_message( msg
, FALSE
);
954 return NtUserDispatchMessage( msg
);
958 /***********************************************************************
959 * GetMessagePos (USER.119)
960 * GetMessagePos (USER32.@)
962 * The GetMessagePos() function returns a long value representing a
963 * cursor position, in screen coordinates, when the last message
964 * retrieved by the GetMessage() function occurs. The x-coordinate is
965 * in the low-order word of the return value, the y-coordinate is in
966 * the high-order word. The application can use the MAKEPOINT()
967 * macro to obtain a POINT structure from the return value.
969 * For the current cursor position, use GetCursorPos().
973 * Cursor position of last message on success, zero on failure.
980 DWORD WINAPI
GetMessagePos(void)
982 return NtUserGetThreadInfo()->message_pos
;
986 /***********************************************************************
987 * GetMessageTime (USER.120)
988 * GetMessageTime (USER32.@)
990 * GetMessageTime() returns the message time for the last message
991 * retrieved by the function. The time is measured in milliseconds with
992 * the same offset as GetTickCount().
994 * Since the tick count wraps, this is only useful for moderately short
995 * relative time comparisons.
999 * Time of last message on success, zero on failure.
1001 LONG WINAPI
GetMessageTime(void)
1003 return NtUserGetThreadInfo()->message_time
;
1007 /***********************************************************************
1008 * GetMessageExtraInfo (USER.288)
1009 * GetMessageExtraInfo (USER32.@)
1011 LPARAM WINAPI
GetMessageExtraInfo(void)
1013 return NtUserGetThreadInfo()->message_extra
;
1017 /***********************************************************************
1018 * SetMessageExtraInfo (USER32.@)
1020 LPARAM WINAPI
SetMessageExtraInfo(LPARAM lParam
)
1022 struct ntuser_thread_info
*thread_info
= NtUserGetThreadInfo();
1023 LONG old_value
= thread_info
->message_extra
;
1024 thread_info
->message_extra
= lParam
;
1029 /***********************************************************************
1030 * GetCurrentInputMessageSource (USER32.@)
1032 BOOL WINAPI
GetCurrentInputMessageSource( INPUT_MESSAGE_SOURCE
*source
)
1034 *source
= NtUserGetThreadInfo()->msg_source
;
1039 /***********************************************************************
1040 * MsgWaitForMultipleObjects (USER32.@)
1042 DWORD WINAPI
MsgWaitForMultipleObjects( DWORD count
, const HANDLE
*handles
,
1043 BOOL wait_all
, DWORD timeout
, DWORD mask
)
1045 return NtUserMsgWaitForMultipleObjectsEx( count
, handles
, timeout
, mask
,
1046 wait_all
? MWMO_WAITALL
: 0 );
1050 /***********************************************************************
1051 * WaitForInputIdle (USER32.@)
1053 DWORD WINAPI
WaitForInputIdle( HANDLE process
, DWORD timeout
)
1055 return NtUserWaitForInputIdle( process
, timeout
, FALSE
);
1059 /***********************************************************************
1060 * RegisterWindowMessageA (USER32.@)
1061 * RegisterWindowMessage (USER.118)
1063 UINT WINAPI
RegisterWindowMessageA( LPCSTR str
)
1065 UINT ret
= GlobalAddAtomA(str
);
1066 TRACE("%s, ret=%x\n", str
, ret
);
1071 /***********************************************************************
1072 * RegisterWindowMessageW (USER32.@)
1074 UINT WINAPI
RegisterWindowMessageW( LPCWSTR str
)
1076 UINT ret
= GlobalAddAtomW(str
);
1077 TRACE("%s ret=%x\n", debugstr_w(str
), ret
);
1081 typedef struct BroadcastParm
1092 static BOOL CALLBACK
bcast_childwindow( HWND hw
, LPARAM lp
)
1094 BroadcastParm
*parm
= (BroadcastParm
*)lp
;
1095 DWORD_PTR retval
= 0;
1098 if (parm
->flags
& BSF_IGNORECURRENTTASK
&& WIN_IsCurrentProcess(hw
))
1100 TRACE("Not telling myself %p\n", hw
);
1104 /* I don't know 100% for sure if this is what Windows does, but it fits the tests */
1105 if (parm
->flags
& BSF_QUERY
)
1107 TRACE("Telling window %p using SendMessageTimeout\n", hw
);
1109 /* Not tested for conflicting flags */
1110 if (parm
->flags
& BSF_FORCEIFHUNG
|| parm
->flags
& BSF_NOHANG
)
1111 lresult
= SendMessageTimeoutW( hw
, parm
->msg
, parm
->wp
, parm
->lp
, SMTO_ABORTIFHUNG
, 2000, &retval
);
1112 else if (parm
->flags
& BSF_NOTIMEOUTIFNOTHUNG
)
1113 lresult
= SendMessageTimeoutW( hw
, parm
->msg
, parm
->wp
, parm
->lp
, SMTO_NOTIMEOUTIFNOTHUNG
, 2000, &retval
);
1115 lresult
= SendMessageTimeoutW( hw
, parm
->msg
, parm
->wp
, parm
->lp
, SMTO_NORMAL
, 2000, &retval
);
1117 if (!lresult
&& GetLastError() == ERROR_TIMEOUT
)
1119 WARN("Timed out!\n");
1120 if (!(parm
->flags
& BSF_FORCEIFHUNG
))
1123 if (retval
== BROADCAST_QUERY_DENY
)
1129 parm
->success
= FALSE
;
1132 else if (parm
->flags
& BSF_POSTMESSAGE
)
1134 TRACE("Telling window %p using PostMessage\n", hw
);
1135 PostMessageW( hw
, parm
->msg
, parm
->wp
, parm
->lp
);
1139 TRACE("Telling window %p using SendNotifyMessage\n", hw
);
1140 SendNotifyMessageW( hw
, parm
->msg
, parm
->wp
, parm
->lp
);
1146 static BOOL CALLBACK
bcast_desktop( LPWSTR desktop
, LPARAM lp
)
1150 BroadcastParm
*parm
= (BroadcastParm
*)lp
;
1152 TRACE("desktop: %s\n", debugstr_w( desktop
));
1154 hdesktop
= open_winstation_desktop( parm
->winsta
, desktop
, 0, FALSE
, DESKTOP_ENUMERATE
|DESKTOP_WRITEOBJECTS
|STANDARD_RIGHTS_WRITE
);
1157 FIXME("Could not open desktop %s\n", debugstr_w(desktop
));
1161 ret
= EnumDesktopWindows( hdesktop
, bcast_childwindow
, lp
);
1162 NtUserCloseDesktop( hdesktop
);
1163 TRACE("-->%d\n", ret
);
1164 return parm
->success
;
1167 static BOOL CALLBACK
bcast_winsta( LPWSTR winsta
, LPARAM lp
)
1170 HWINSTA hwinsta
= OpenWindowStationW( winsta
, FALSE
, WINSTA_ENUMDESKTOPS
);
1171 TRACE("hwinsta: %p/%s/%08lx\n", hwinsta
, debugstr_w( winsta
), GetLastError());
1174 ((BroadcastParm
*)lp
)->winsta
= hwinsta
;
1175 ret
= EnumDesktopsW( hwinsta
, bcast_desktop
, lp
);
1176 NtUserCloseWindowStation( hwinsta
);
1177 TRACE("-->%d\n", ret
);
1181 /***********************************************************************
1182 * BroadcastSystemMessageA (USER32.@)
1183 * BroadcastSystemMessage (USER32.@)
1185 LONG WINAPI
BroadcastSystemMessageA( DWORD flags
, LPDWORD recipients
, UINT msg
, WPARAM wp
, LPARAM lp
)
1187 return BroadcastSystemMessageExA( flags
, recipients
, msg
, wp
, lp
, NULL
);
1191 /***********************************************************************
1192 * BroadcastSystemMessageW (USER32.@)
1194 LONG WINAPI
BroadcastSystemMessageW( DWORD flags
, LPDWORD recipients
, UINT msg
, WPARAM wp
, LPARAM lp
)
1196 return BroadcastSystemMessageExW( flags
, recipients
, msg
, wp
, lp
, NULL
);
1199 /***********************************************************************
1200 * BroadcastSystemMessageExA (USER32.@)
1202 LONG WINAPI
BroadcastSystemMessageExA( DWORD flags
, LPDWORD recipients
, UINT msg
, WPARAM wp
, LPARAM lp
, PBSMINFO pinfo
)
1204 map_wparam_AtoW( msg
, &wp
, WMCHAR_MAP_NOMAPPING
);
1205 return BroadcastSystemMessageExW( flags
, recipients
, msg
, wp
, lp
, pinfo
);
1209 /***********************************************************************
1210 * BroadcastSystemMessageExW (USER32.@)
1212 LONG WINAPI
BroadcastSystemMessageExW( DWORD flags
, LPDWORD recipients
, UINT msg
, WPARAM wp
, LPARAM lp
, PBSMINFO pinfo
)
1215 DWORD recips
= BSM_ALLCOMPONENTS
;
1217 static const DWORD all_flags
= ( BSF_QUERY
| BSF_IGNORECURRENTTASK
| BSF_FLUSHDISK
| BSF_NOHANG
1218 | BSF_POSTMESSAGE
| BSF_FORCEIFHUNG
| BSF_NOTIMEOUTIFNOTHUNG
1219 | BSF_ALLOWSFW
| BSF_SENDNOTIFYMESSAGE
| BSF_RETURNHDESK
| BSF_LUID
);
1221 TRACE("Flags: %08lx, recipients: %p(0x%lx), msg: %04x, wparam: %08Ix, lparam: %08Ix\n", flags
, recipients
,
1222 (recipients
? *recipients
: recips
), msg
, wp
, lp
);
1224 if (flags
& ~all_flags
)
1226 SetLastError(ERROR_INVALID_PARAMETER
);
1231 recipients
= &recips
;
1233 if ( pinfo
&& flags
& BSF_QUERY
)
1234 FIXME("Not returning PBSMINFO information yet\n");
1237 parm
.recipients
= recipients
;
1241 parm
.success
= TRUE
;
1243 if (*recipients
& BSM_ALLDESKTOPS
|| *recipients
== BSM_ALLCOMPONENTS
)
1244 ret
= EnumWindowStationsW(bcast_winsta
, (LONG_PTR
)&parm
);
1245 else if (*recipients
& BSM_APPLICATIONS
)
1247 EnumWindows(bcast_childwindow
, (LONG_PTR
)&parm
);
1251 FIXME("Recipients %08lx not supported!\n", *recipients
);
1256 /***********************************************************************
1257 * SetMessageQueue (USER32.@)
1259 BOOL WINAPI
SetMessageQueue( INT size
)
1261 /* now obsolete the message queue will be expanded dynamically as necessary */
1266 /***********************************************************************
1267 * MessageBeep (USER32.@)
1269 BOOL WINAPI
MessageBeep( UINT i
)
1271 return NtUserMessageBeep( i
);
1275 /******************************************************************
1276 * SetTimer (USER32.@)
1278 UINT_PTR WINAPI
SetTimer( HWND hwnd
, UINT_PTR id
, UINT timeout
, TIMERPROC proc
)
1280 return NtUserSetTimer( hwnd
, id
, timeout
, proc
, TIMERV_DEFAULT_COALESCING
);
1284 /******************************************************************
1285 * SetSystemTimer (USER32.@)
1287 UINT_PTR WINAPI
SetSystemTimer( HWND hwnd
, UINT_PTR id
, UINT timeout
, void *unknown
)
1289 if (unknown
) FIXME( "ignoring unknown parameter %p\n", unknown
);
1291 return NtUserSetSystemTimer( hwnd
, id
, timeout
);
1295 /***********************************************************************
1296 * KillSystemTimer (USER32.@)
1298 BOOL WINAPI
KillSystemTimer( HWND hwnd
, UINT_PTR id
)
1300 return NtUserKillSystemTimer( hwnd
, id
);
1304 /**********************************************************************
1305 * IsGUIThread (USER32.@)
1307 BOOL WINAPI
IsGUIThread( BOOL convert
)
1309 FIXME( "%u: stub\n", convert
);
1314 /******************************************************************
1315 * IsHungAppWindow (USER32.@)
1318 BOOL WINAPI
IsHungAppWindow( HWND hWnd
)
1322 SERVER_START_REQ( is_window_hung
)
1324 req
->win
= wine_server_user_handle( hWnd
);
1325 ret
= !wine_server_call_err( req
) && reply
->is_hung
;
1331 /******************************************************************
1332 * ChangeWindowMessageFilter (USER32.@)
1334 BOOL WINAPI
ChangeWindowMessageFilter( UINT message
, DWORD flag
)
1336 FIXME( "%x %08lx\n", message
, flag
);
1340 /******************************************************************
1341 * ChangeWindowMessageFilterEx (USER32.@)
1343 BOOL WINAPI
ChangeWindowMessageFilterEx( HWND hwnd
, UINT message
, DWORD action
, CHANGEFILTERSTRUCT
*changefilter
)
1345 FIXME( "%p %x %ld %p\n", hwnd
, message
, action
, changefilter
);