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
);
198 len
= WideCharToMultiByte( cp
, 0, wch
, 1, (LPSTR
)ch
, 2, NULL
, NULL
);
199 if (len
== 2) /* DBCS char */
201 struct wm_char_mapping_data
*data
= get_wmchar_data();
204 if (!(data
= HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(*data
) ))) return;
205 NtUserGetThreadInfo()->wmchar_data
= (UINT_PTR
)data
;
209 data
->get_msg
= *msg
;
210 data
->get_msg
.wParam
= ch
[1];
216 /* else fall through */
218 case EM_SETPASSWORDCHAR
:
223 cp
= get_input_codepage();
224 wch
[0] = LOWORD(msg
->wParam
);
225 wch
[1] = HIWORD(msg
->wParam
);
226 len
= WideCharToMultiByte( cp
, 0, wch
, 2, (LPSTR
)ch
, 4, NULL
, NULL
);
227 for (msg
->wParam
= i
= 0; i
< len
; i
++) msg
->wParam
|= ch
[i
] << (8 * i
);
230 cp
= get_input_codepage();
231 wch
[0] = LOWORD(msg
->wParam
);
232 len
= WideCharToMultiByte( cp
, 0, wch
, 1, (LPSTR
)ch
, 2, NULL
, NULL
);
234 msg
->wParam
= MAKEWPARAM( (ch
[0] << 8) | ch
[1], HIWORD(msg
->wParam
) );
236 msg
->wParam
= MAKEWPARAM( ch
[0], HIWORD(msg
->wParam
) );
242 /* since the WM_DDE_ACK response to a WM_DDE_EXECUTE message should contain the handle
243 * to the memory handle, we keep track (in the server side) of all pairs of handle
244 * used (the client passes its value and the content of the memory handle), and
245 * the server stored both values (the client, and the local one, created after the
246 * content). When a ACK message is generated, the list of pair is searched for a
247 * matching pair, so that the client memory handle can be returned.
254 static struct DDE_pair
* dde_pairs
;
255 static int dde_num_alloc
;
256 static int dde_num_used
;
258 static CRITICAL_SECTION dde_crst
;
259 static CRITICAL_SECTION_DEBUG critsect_debug
=
262 { &critsect_debug
.ProcessLocksList
, &critsect_debug
.ProcessLocksList
},
263 0, 0, { (DWORD_PTR
)(__FILE__
": dde_crst") }
265 static CRITICAL_SECTION dde_crst
= { &critsect_debug
, -1, 0, 0, 0, 0 };
267 static BOOL
dde_add_pair(HGLOBAL chm
, HGLOBAL shm
)
272 EnterCriticalSection(&dde_crst
);
274 /* now remember the pair of hMem on both sides */
275 if (dde_num_used
== dde_num_alloc
)
277 struct DDE_pair
* tmp
;
279 tmp
= HeapReAlloc( GetProcessHeap(), 0, dde_pairs
,
280 (dde_num_alloc
+ GROWBY
) * sizeof(struct DDE_pair
));
282 tmp
= HeapAlloc( GetProcessHeap(), 0,
283 (dde_num_alloc
+ GROWBY
) * sizeof(struct DDE_pair
));
287 LeaveCriticalSection(&dde_crst
);
291 /* zero out newly allocated part */
292 memset(&dde_pairs
[dde_num_alloc
], 0, GROWBY
* sizeof(struct DDE_pair
));
293 dde_num_alloc
+= GROWBY
;
296 for (i
= 0; i
< dde_num_alloc
; i
++)
298 if (dde_pairs
[i
].server_hMem
== 0)
300 dde_pairs
[i
].client_hMem
= chm
;
301 dde_pairs
[i
].server_hMem
= shm
;
306 LeaveCriticalSection(&dde_crst
);
310 static HGLOBAL
dde_get_pair(HGLOBAL shm
)
315 EnterCriticalSection(&dde_crst
);
316 for (i
= 0; i
< dde_num_alloc
; i
++)
318 if (dde_pairs
[i
].server_hMem
== shm
)
321 dde_pairs
[i
].server_hMem
= 0;
323 ret
= dde_pairs
[i
].client_hMem
;
327 LeaveCriticalSection(&dde_crst
);
331 /***********************************************************************
336 NTSTATUS
post_dde_message( HWND hwnd
, UINT msg
, WPARAM wparam
, LPARAM lparam
, DWORD dest_tid
, DWORD type
)
346 if (!UnpackDDElParam( msg
, lparam
, &uiLo
, &uiHi
))
347 return STATUS_INVALID_PARAMETER
;
352 /* DDE messages which don't require packing are:
361 /* uiHi should contain a hMem from WM_DDE_EXECUTE */
362 HGLOBAL h
= dde_get_pair( (HANDLE
)uiHi
);
365 hpack
= pack_ptr( h
);
366 /* send back the value of h on the other side */
368 size
= sizeof(hpack
);
370 TRACE( "send dde-ack %Ix %08Ix => %p\n", uiLo
, uiHi
, h
);
375 /* uiHi should contain either an atom or 0 */
376 TRACE( "send dde-ack %Ix atom=%Ix\n", uiLo
, uiHi
);
377 lp
= MAKELONG( uiLo
, uiHi
);
385 size
= GlobalSize( (HGLOBAL
)uiLo
) ;
386 if ((msg
== WM_DDE_ADVISE
&& size
< sizeof(DDEADVISE
)) ||
387 (msg
== WM_DDE_DATA
&& size
< FIELD_OFFSET(DDEDATA
, Value
)) ||
388 (msg
== WM_DDE_POKE
&& size
< FIELD_OFFSET(DDEPOKE
, Value
)))
389 return STATUS_INVALID_PARAMETER
;
391 else if (msg
!= WM_DDE_DATA
) return STATUS_INVALID_PARAMETER
;
396 if ((ptr
= GlobalLock( (HGLOBAL
)uiLo
) ))
398 DDEDATA
*dde_data
= ptr
;
399 TRACE("unused %d, fResponse %d, fRelease %d, fDeferUpd %d, fAckReq %d, cfFormat %d\n",
400 dde_data
->unused
, dde_data
->fResponse
, dde_data
->fRelease
,
401 dde_data
->reserved
, dde_data
->fAckReq
, dde_data
->cfFormat
);
402 hunlock
= (HGLOBAL
)uiLo
;
405 TRACE( "send ddepack %u %Ix\n", size
, uiHi
);
410 if ((ptr
= GlobalLock( (HGLOBAL
)lparam
) ))
412 size
= GlobalSize( (HGLOBAL
)lparam
);
413 /* so that the other side can send it back on ACK */
415 hunlock
= (HGLOBAL
)lparam
;
420 SERVER_START_REQ( send_message
)
425 req
->win
= wine_server_user_handle( hwnd
);
427 req
->wparam
= wparam
;
429 req
->timeout
= TIMEOUT_INFINITE
;
430 if (size
) wine_server_add_data( req
, ptr
, size
);
431 if (!(res
= wine_server_call( req
))) FreeDDElParam( msg
, lparam
);
434 if (hunlock
) GlobalUnlock(hunlock
);
439 /***********************************************************************
442 * Unpack a posted DDE message received from another process.
444 BOOL
unpack_dde_message( HWND hwnd
, UINT message
, WPARAM
*wparam
, LPARAM
*lparam
,
445 const void *buffer
, size_t size
)
457 /* hMem is being passed */
458 if (size
!= sizeof(hpack
)) return FALSE
;
460 memcpy( &hpack
, buffer
, size
);
461 hMem
= unpack_ptr( hpack
);
462 uiHi
= (UINT_PTR
)hMem
;
463 TRACE("recv dde-ack %Ix mem=%Ix[%Ix]\n", uiLo
, uiHi
, GlobalSize( hMem
));
467 uiLo
= LOWORD( *lparam
);
468 uiHi
= HIWORD( *lparam
);
469 TRACE("recv dde-ack %Ix atom=%Ix\n", uiLo
, uiHi
);
471 *lparam
= PackDDElParam( WM_DDE_ACK
, uiLo
, uiHi
);
476 if (!size
&& message
!= WM_DDE_DATA
) return FALSE
;
480 if (!(hMem
= GlobalAlloc( GMEM_MOVEABLE
|GMEM_DDESHARE
, size
)))
482 if ((ptr
= GlobalLock( hMem
)))
484 memcpy( ptr
, buffer
, size
);
485 GlobalUnlock( hMem
);
493 uiLo
= (UINT_PTR
)hMem
;
495 *lparam
= PackDDElParam( message
, uiLo
, uiHi
);
500 if (!(hMem
= GlobalAlloc( GMEM_MOVEABLE
|GMEM_DDESHARE
, size
))) return FALSE
;
501 if ((ptr
= GlobalLock( hMem
)))
503 memcpy( ptr
, buffer
, size
);
504 GlobalUnlock( hMem
);
505 TRACE( "exec: pairing c=%08Ix s=%p\n", *lparam
, hMem
);
506 if (!dde_add_pair( (HGLOBAL
)*lparam
, hMem
))
518 *lparam
= (LPARAM
)hMem
;
524 /***********************************************************************
525 * SendMessageTimeoutW (USER32.@)
527 LRESULT WINAPI
SendMessageTimeoutW( HWND hwnd
, UINT msg
, WPARAM wparam
, LPARAM lparam
,
528 UINT flags
, UINT timeout
, PDWORD_PTR res_ptr
)
530 struct send_message_timeout_params params
= { .flags
= flags
, .timeout
= timeout
};
533 res
= NtUserMessageCall( hwnd
, msg
, wparam
, lparam
, ¶ms
, NtUserSendMessageTimeout
, FALSE
);
534 if (res_ptr
) *res_ptr
= res
;
535 return params
.result
;
538 /***********************************************************************
539 * SendMessageTimeoutA (USER32.@)
541 LRESULT WINAPI
SendMessageTimeoutA( HWND hwnd
, UINT msg
, WPARAM wparam
, LPARAM lparam
,
542 UINT flags
, UINT timeout
, PDWORD_PTR res_ptr
)
544 struct send_message_timeout_params params
= { .flags
= flags
, .timeout
= timeout
};
547 if (msg
!= WM_CHAR
|| WIN_IsCurrentThread( hwnd
))
549 res
= NtUserMessageCall( hwnd
, msg
, wparam
, lparam
, ¶ms
,
550 NtUserSendMessageTimeout
, TRUE
);
552 else if (map_wparam_AtoW( msg
, &wparam
, WMCHAR_MAP_SENDMESSAGE
))
554 res
= NtUserMessageCall( hwnd
, msg
, wparam
, lparam
, ¶ms
,
555 NtUserSendMessageTimeout
, FALSE
);
558 if (res_ptr
) *res_ptr
= res
;
559 return params
.result
;
563 static LRESULT
dispatch_send_message( struct win_proc_params
*params
, WPARAM wparam
, LPARAM lparam
)
565 struct ntuser_thread_info
*thread_info
= NtUserGetThreadInfo();
566 INPUT_MESSAGE_SOURCE prev_source
= thread_info
->msg_source
;
569 static const INPUT_MESSAGE_SOURCE msg_source_unavailable
= { IMDT_UNAVAILABLE
, IMO_UNAVAILABLE
};
571 /* params may contain arguments modified by wow, use original parameters instead */
572 params
->wparam
= wparam
;
573 params
->lparam
= lparam
;
575 thread_info
->recursion_count
++;
577 thread_info
->msg_source
= msg_source_unavailable
;
578 SPY_EnterMessage( SPY_SENDMESSAGE
, params
->hwnd
, params
->msg
, params
->wparam
, params
->lparam
);
580 retval
= dispatch_win_proc_params( params
);
582 SPY_ExitMessage( SPY_RESULT_OK
, params
->hwnd
, params
->msg
, retval
, params
->wparam
, params
->lparam
);
583 thread_info
->msg_source
= prev_source
;
584 thread_info
->recursion_count
--;
589 /***********************************************************************
590 * SendMessageW (USER32.@)
592 LRESULT WINAPI
SendMessageW( HWND hwnd
, UINT msg
, WPARAM wparam
, LPARAM lparam
)
594 struct win_proc_params params
;
598 retval
= NtUserMessageCall( hwnd
, msg
, wparam
, lparam
, ¶ms
, NtUserSendMessage
, FALSE
);
599 if (params
.hwnd
) retval
= dispatch_send_message( ¶ms
, wparam
, lparam
);
604 /***********************************************************************
605 * SendMessageA (USER32.@)
607 LRESULT WINAPI
SendMessageA( HWND hwnd
, UINT msg
, WPARAM wparam
, LPARAM lparam
)
609 struct win_proc_params params
;
612 if (msg
== WM_CHAR
&& !WIN_IsCurrentThread( hwnd
))
614 if (!map_wparam_AtoW( msg
, &wparam
, WMCHAR_MAP_SENDMESSAGE
))
616 return NtUserMessageCall( hwnd
, msg
, wparam
, lparam
, NULL
, NtUserSendMessage
, FALSE
);
620 retval
= NtUserMessageCall( hwnd
, msg
, wparam
, lparam
, ¶ms
, NtUserSendMessage
, TRUE
);
621 if (params
.hwnd
) retval
= dispatch_send_message( ¶ms
, wparam
, lparam
);
626 /***********************************************************************
627 * SendNotifyMessageA (USER32.@)
629 BOOL WINAPI
SendNotifyMessageA( HWND hwnd
, UINT msg
, WPARAM wparam
, LPARAM lparam
)
631 if (!WIN_IsCurrentThread( hwnd
) && !map_wparam_AtoW( msg
, &wparam
, WMCHAR_MAP_SENDMESSAGE
))
634 return NtUserMessageCall( hwnd
, msg
, wparam
, lparam
, 0, NtUserSendNotifyMessage
, TRUE
);
638 /***********************************************************************
639 * SendNotifyMessageW (USER32.@)
641 BOOL WINAPI
SendNotifyMessageW( HWND hwnd
, UINT msg
, WPARAM wparam
, LPARAM lparam
)
643 return NtUserMessageCall( hwnd
, msg
, wparam
, lparam
, 0, NtUserSendNotifyMessage
, FALSE
);
647 /***********************************************************************
648 * SendMessageCallbackA (USER32.@)
650 BOOL WINAPI
SendMessageCallbackA( HWND hwnd
, UINT msg
, WPARAM wparam
, LPARAM lparam
,
651 SENDASYNCPROC callback
, ULONG_PTR data
)
653 struct send_message_callback_params params
= { .callback
= callback
, .data
= data
};
655 if (!WIN_IsCurrentThread( hwnd
) && !map_wparam_AtoW( msg
, &wparam
, WMCHAR_MAP_SENDMESSAGE
))
658 return NtUserMessageCall( hwnd
, msg
, wparam
, lparam
, ¶ms
, NtUserSendMessageCallback
, TRUE
);
662 /***********************************************************************
663 * SendMessageCallbackW (USER32.@)
665 BOOL WINAPI
SendMessageCallbackW( HWND hwnd
, UINT msg
, WPARAM wparam
, LPARAM lparam
,
666 SENDASYNCPROC callback
, ULONG_PTR data
)
668 struct send_message_callback_params params
= { .callback
= callback
, .data
= data
};
669 return NtUserMessageCall( hwnd
, msg
, wparam
, lparam
, ¶ms
, NtUserSendMessageCallback
, FALSE
);
673 /***********************************************************************
674 * ReplyMessage (USER32.@)
676 BOOL WINAPI
ReplyMessage( LRESULT result
)
678 return NtUserReplyMessage( result
);
682 /***********************************************************************
683 * InSendMessage (USER32.@)
685 BOOL WINAPI
InSendMessage(void)
687 return (InSendMessageEx( NULL
) & (ISMEX_SEND
| ISMEX_NOTIFY
| ISMEX_CALLBACK
)) != 0;
691 /***********************************************************************
692 * InSendMessageEx (USER32.@)
694 DWORD WINAPI
InSendMessageEx( LPVOID reserved
)
696 return NtUserGetThreadInfo()->receive_flags
;
700 /***********************************************************************
701 * PostMessageA (USER32.@)
703 BOOL WINAPI
PostMessageA( HWND hwnd
, UINT msg
, WPARAM wparam
, LPARAM lparam
)
705 if (!map_wparam_AtoW( msg
, &wparam
, WMCHAR_MAP_POSTMESSAGE
)) return TRUE
;
706 return PostMessageW( hwnd
, msg
, wparam
, lparam
);
710 /***********************************************************************
711 * PostMessageW (USER32.@)
713 BOOL WINAPI
PostMessageW( HWND hwnd
, UINT msg
, WPARAM wparam
, LPARAM lparam
)
715 return NtUserPostMessage( hwnd
, msg
, wparam
, lparam
);
719 /**********************************************************************
720 * PostThreadMessageA (USER32.@)
722 BOOL WINAPI
PostThreadMessageA( DWORD thread
, UINT msg
, WPARAM wparam
, LPARAM lparam
)
724 if (!map_wparam_AtoW( msg
, &wparam
, WMCHAR_MAP_POSTMESSAGE
)) return TRUE
;
725 return NtUserPostThreadMessage( thread
, msg
, wparam
, lparam
);
729 /***********************************************************************
730 * PostQuitMessage (USER32.@)
732 * Posts a quit message to the current thread's message queue.
735 * exit_code [I] Exit code to return from message loop.
741 * This function is not the same as calling:
742 *|PostThreadMessage(GetCurrentThreadId(), WM_QUIT, exit_code, 0);
743 * It instead sets a flag in the message queue that signals it to generate
744 * a WM_QUIT message when there are no other pending sent or posted messages
747 void WINAPI
PostQuitMessage( INT exit_code
)
749 SERVER_START_REQ( post_quit_message
)
751 req
->exit_code
= exit_code
;
752 wine_server_call( req
);
757 /***********************************************************************
758 * PeekMessageW (USER32.@)
760 BOOL WINAPI DECLSPEC_HOTPATCH
PeekMessageW( MSG
*msg_out
, HWND hwnd
, UINT first
, UINT last
, UINT flags
)
762 return NtUserPeekMessage( msg_out
, hwnd
, first
, last
, flags
);
766 /***********************************************************************
767 * PeekMessageA (USER32.@)
769 BOOL WINAPI DECLSPEC_HOTPATCH
PeekMessageA( MSG
*msg
, HWND hwnd
, UINT first
, UINT last
, UINT flags
)
771 if (get_pending_wmchar( msg
, first
, last
, (flags
& PM_REMOVE
) )) return TRUE
;
772 if (!PeekMessageW( msg
, hwnd
, first
, last
, flags
)) return FALSE
;
773 map_wparam_WtoA( msg
, (flags
& PM_REMOVE
) );
778 /***********************************************************************
779 * GetMessageW (USER32.@)
781 BOOL WINAPI DECLSPEC_HOTPATCH
GetMessageW( MSG
*msg
, HWND hwnd
, UINT first
, UINT last
)
783 return NtUserGetMessage( msg
, hwnd
, first
, last
);
787 /***********************************************************************
788 * GetMessageA (USER32.@)
790 BOOL WINAPI DECLSPEC_HOTPATCH
GetMessageA( MSG
*msg
, HWND hwnd
, UINT first
, UINT last
)
792 if (get_pending_wmchar( msg
, first
, last
, TRUE
)) return TRUE
;
793 if (GetMessageW( msg
, hwnd
, first
, last
) < 0) return -1;
794 map_wparam_WtoA( msg
, TRUE
);
795 return (msg
->message
!= WM_QUIT
);
798 static BOOL
is_cjk(void)
800 int lang_id
= PRIMARYLANGID(GetUserDefaultLangID());
802 if (lang_id
== LANG_CHINESE
|| lang_id
== LANG_JAPANESE
|| lang_id
== LANG_KOREAN
)
807 /***********************************************************************
808 * IsDialogMessageA (USER32.@)
809 * IsDialogMessage (USER32.@)
811 BOOL WINAPI
IsDialogMessageA( HWND hwndDlg
, LPMSG pmsg
)
813 enum wm_char_mapping mapping
;
816 mapping
= is_cjk() ? WMCHAR_MAP_ISDIALOGMESSAGE
: WMCHAR_MAP_NOMAPPING
;
817 if (!map_wparam_AtoW( msg
.message
, &msg
.wParam
, mapping
))
819 return IsDialogMessageW( hwndDlg
, &msg
);
823 /***********************************************************************
824 * TranslateMessage (USER32.@)
826 * Implementation of TranslateMessage.
828 * TranslateMessage translates virtual-key messages into character-messages,
830 * WM_KEYDOWN/WM_KEYUP combinations produce a WM_CHAR or WM_DEADCHAR message.
831 * ditto replacing WM_* with WM_SYS*
832 * This produces WM_CHAR messages only for keys mapped to ASCII characters
833 * by the keyboard driver.
835 * If the message is WM_KEYDOWN, WM_KEYUP, WM_SYSKEYDOWN, or WM_SYSKEYUP, the
836 * return value is nonzero, regardless of the translation.
839 BOOL WINAPI
TranslateMessage( const MSG
*msg
)
841 return NtUserTranslateMessage( msg
, 0 );
845 static LRESULT
dispatch_message( const MSG
*msg
, BOOL ansi
)
847 struct win_proc_params params
;
850 if (!NtUserMessageCall( msg
->hwnd
, msg
->message
, msg
->wParam
, msg
->lParam
,
851 ¶ms
, NtUserGetDispatchParams
, ansi
)) return 0;
853 SPY_EnterMessage( SPY_DISPATCHMESSAGE
, msg
->hwnd
, msg
->message
, msg
->wParam
, msg
->lParam
);
854 retval
= dispatch_win_proc_params( ¶ms
);
855 SPY_ExitMessage( SPY_RESULT_OK
, msg
->hwnd
, msg
->message
, retval
, msg
->wParam
, msg
->lParam
);
860 /***********************************************************************
861 * DispatchMessageA (USER32.@)
863 * See DispatchMessageW.
865 LRESULT WINAPI DECLSPEC_HOTPATCH
DispatchMessageA( const MSG
* msg
)
869 /* Process timer messages */
870 if (msg
->lParam
&& msg
->message
== WM_TIMER
)
874 retval
= CallWindowProcA( (WNDPROC
)msg
->lParam
, msg
->hwnd
,
875 msg
->message
, msg
->wParam
, GetTickCount() );
885 /* whenever possible, avoid using NtUserDispatchMessage to make the call unwindable */
886 if (msg
->message
!= WM_SYSTIMER
&& msg
->message
!= WM_PAINT
)
887 return dispatch_message( msg
, TRUE
);
889 return NtUserDispatchMessage( msg
);
893 /***********************************************************************
894 * DispatchMessageW (USER32.@) Process a message
896 * Process the message specified in the structure *_msg_.
898 * If the lpMsg parameter points to a WM_TIMER message and the
899 * parameter of the WM_TIMER message is not NULL, the lParam parameter
900 * points to the function that is called instead of the window
901 * procedure. The function stored in lParam (timer callback) is protected
902 * from causing page-faults.
904 * The message must be valid.
908 * DispatchMessage() returns the result of the window procedure invoked.
915 LRESULT WINAPI DECLSPEC_HOTPATCH
DispatchMessageW( const MSG
* msg
)
919 /* Process timer messages */
920 if ((msg
->message
== WM_TIMER
) || (msg
->message
== WM_SYSTIMER
))
926 retval
= CallWindowProcW( (WNDPROC
)msg
->lParam
, msg
->hwnd
,
927 msg
->message
, msg
->wParam
, GetTickCount() );
938 /* whenever possible, avoid using NtUserDispatchMessage to make the call unwindable */
939 if (msg
->message
!= WM_SYSTIMER
&& msg
->message
!= WM_PAINT
)
940 return dispatch_message( msg
, FALSE
);
942 return NtUserDispatchMessage( msg
);
946 /***********************************************************************
947 * GetMessagePos (USER.119)
948 * GetMessagePos (USER32.@)
950 * The GetMessagePos() function returns a long value representing a
951 * cursor position, in screen coordinates, when the last message
952 * retrieved by the GetMessage() function occurs. The x-coordinate is
953 * in the low-order word of the return value, the y-coordinate is in
954 * the high-order word. The application can use the MAKEPOINT()
955 * macro to obtain a POINT structure from the return value.
957 * For the current cursor position, use GetCursorPos().
961 * Cursor position of last message on success, zero on failure.
968 DWORD WINAPI
GetMessagePos(void)
970 return NtUserGetThreadInfo()->message_pos
;
974 /***********************************************************************
975 * GetMessageTime (USER.120)
976 * GetMessageTime (USER32.@)
978 * GetMessageTime() returns the message time for the last message
979 * retrieved by the function. The time is measured in milliseconds with
980 * the same offset as GetTickCount().
982 * Since the tick count wraps, this is only useful for moderately short
983 * relative time comparisons.
987 * Time of last message on success, zero on failure.
989 LONG WINAPI
GetMessageTime(void)
991 return NtUserGetThreadInfo()->message_time
;
995 /***********************************************************************
996 * GetMessageExtraInfo (USER.288)
997 * GetMessageExtraInfo (USER32.@)
999 LPARAM WINAPI
GetMessageExtraInfo(void)
1001 return NtUserGetThreadInfo()->message_extra
;
1005 /***********************************************************************
1006 * SetMessageExtraInfo (USER32.@)
1008 LPARAM WINAPI
SetMessageExtraInfo(LPARAM lParam
)
1010 struct ntuser_thread_info
*thread_info
= NtUserGetThreadInfo();
1011 LONG old_value
= thread_info
->message_extra
;
1012 thread_info
->message_extra
= lParam
;
1017 /***********************************************************************
1018 * GetCurrentInputMessageSource (USER32.@)
1020 BOOL WINAPI
GetCurrentInputMessageSource( INPUT_MESSAGE_SOURCE
*source
)
1022 *source
= NtUserGetThreadInfo()->msg_source
;
1027 /***********************************************************************
1028 * MsgWaitForMultipleObjects (USER32.@)
1030 DWORD WINAPI
MsgWaitForMultipleObjects( DWORD count
, const HANDLE
*handles
,
1031 BOOL wait_all
, DWORD timeout
, DWORD mask
)
1033 return NtUserMsgWaitForMultipleObjectsEx( count
, handles
, timeout
, mask
,
1034 wait_all
? MWMO_WAITALL
: 0 );
1038 /***********************************************************************
1039 * WaitForInputIdle (USER32.@)
1041 DWORD WINAPI
WaitForInputIdle( HANDLE process
, DWORD timeout
)
1043 return NtUserWaitForInputIdle( process
, timeout
, FALSE
);
1047 /***********************************************************************
1048 * RegisterWindowMessageA (USER32.@)
1049 * RegisterWindowMessage (USER.118)
1051 UINT WINAPI
RegisterWindowMessageA( LPCSTR str
)
1053 UINT ret
= GlobalAddAtomA(str
);
1054 TRACE("%s, ret=%x\n", str
, ret
);
1059 /***********************************************************************
1060 * RegisterWindowMessageW (USER32.@)
1062 UINT WINAPI
RegisterWindowMessageW( LPCWSTR str
)
1064 UINT ret
= GlobalAddAtomW(str
);
1065 TRACE("%s ret=%x\n", debugstr_w(str
), ret
);
1069 typedef struct BroadcastParm
1080 static BOOL CALLBACK
bcast_childwindow( HWND hw
, LPARAM lp
)
1082 BroadcastParm
*parm
= (BroadcastParm
*)lp
;
1083 DWORD_PTR retval
= 0;
1086 if (parm
->flags
& BSF_IGNORECURRENTTASK
&& WIN_IsCurrentProcess(hw
))
1088 TRACE("Not telling myself %p\n", hw
);
1092 /* I don't know 100% for sure if this is what Windows does, but it fits the tests */
1093 if (parm
->flags
& BSF_QUERY
)
1095 TRACE("Telling window %p using SendMessageTimeout\n", hw
);
1097 /* Not tested for conflicting flags */
1098 if (parm
->flags
& BSF_FORCEIFHUNG
|| parm
->flags
& BSF_NOHANG
)
1099 lresult
= SendMessageTimeoutW( hw
, parm
->msg
, parm
->wp
, parm
->lp
, SMTO_ABORTIFHUNG
, 2000, &retval
);
1100 else if (parm
->flags
& BSF_NOTIMEOUTIFNOTHUNG
)
1101 lresult
= SendMessageTimeoutW( hw
, parm
->msg
, parm
->wp
, parm
->lp
, SMTO_NOTIMEOUTIFNOTHUNG
, 2000, &retval
);
1103 lresult
= SendMessageTimeoutW( hw
, parm
->msg
, parm
->wp
, parm
->lp
, SMTO_NORMAL
, 2000, &retval
);
1105 if (!lresult
&& GetLastError() == ERROR_TIMEOUT
)
1107 WARN("Timed out!\n");
1108 if (!(parm
->flags
& BSF_FORCEIFHUNG
))
1111 if (retval
== BROADCAST_QUERY_DENY
)
1117 parm
->success
= FALSE
;
1120 else if (parm
->flags
& BSF_POSTMESSAGE
)
1122 TRACE("Telling window %p using PostMessage\n", hw
);
1123 PostMessageW( hw
, parm
->msg
, parm
->wp
, parm
->lp
);
1127 TRACE("Telling window %p using SendNotifyMessage\n", hw
);
1128 SendNotifyMessageW( hw
, parm
->msg
, parm
->wp
, parm
->lp
);
1134 static BOOL CALLBACK
bcast_desktop( LPWSTR desktop
, LPARAM lp
)
1138 BroadcastParm
*parm
= (BroadcastParm
*)lp
;
1140 TRACE("desktop: %s\n", debugstr_w( desktop
));
1142 hdesktop
= open_winstation_desktop( parm
->winsta
, desktop
, 0, FALSE
, DESKTOP_ENUMERATE
|DESKTOP_WRITEOBJECTS
|STANDARD_RIGHTS_WRITE
);
1145 FIXME("Could not open desktop %s\n", debugstr_w(desktop
));
1149 ret
= EnumDesktopWindows( hdesktop
, bcast_childwindow
, lp
);
1150 NtUserCloseDesktop( hdesktop
);
1151 TRACE("-->%d\n", ret
);
1152 return parm
->success
;
1155 static BOOL CALLBACK
bcast_winsta( LPWSTR winsta
, LPARAM lp
)
1158 HWINSTA hwinsta
= OpenWindowStationW( winsta
, FALSE
, WINSTA_ENUMDESKTOPS
);
1159 TRACE("hwinsta: %p/%s/%08lx\n", hwinsta
, debugstr_w( winsta
), GetLastError());
1162 ((BroadcastParm
*)lp
)->winsta
= hwinsta
;
1163 ret
= EnumDesktopsW( hwinsta
, bcast_desktop
, lp
);
1164 NtUserCloseWindowStation( hwinsta
);
1165 TRACE("-->%d\n", ret
);
1169 /***********************************************************************
1170 * BroadcastSystemMessageA (USER32.@)
1171 * BroadcastSystemMessage (USER32.@)
1173 LONG WINAPI
BroadcastSystemMessageA( DWORD flags
, LPDWORD recipients
, UINT msg
, WPARAM wp
, LPARAM lp
)
1175 return BroadcastSystemMessageExA( flags
, recipients
, msg
, wp
, lp
, NULL
);
1179 /***********************************************************************
1180 * BroadcastSystemMessageW (USER32.@)
1182 LONG WINAPI
BroadcastSystemMessageW( DWORD flags
, LPDWORD recipients
, UINT msg
, WPARAM wp
, LPARAM lp
)
1184 return BroadcastSystemMessageExW( flags
, recipients
, msg
, wp
, lp
, NULL
);
1187 /***********************************************************************
1188 * BroadcastSystemMessageExA (USER32.@)
1190 LONG WINAPI
BroadcastSystemMessageExA( DWORD flags
, LPDWORD recipients
, UINT msg
, WPARAM wp
, LPARAM lp
, PBSMINFO pinfo
)
1192 map_wparam_AtoW( msg
, &wp
, WMCHAR_MAP_NOMAPPING
);
1193 return BroadcastSystemMessageExW( flags
, recipients
, msg
, wp
, lp
, pinfo
);
1197 /***********************************************************************
1198 * BroadcastSystemMessageExW (USER32.@)
1200 LONG WINAPI
BroadcastSystemMessageExW( DWORD flags
, LPDWORD recipients
, UINT msg
, WPARAM wp
, LPARAM lp
, PBSMINFO pinfo
)
1203 DWORD recips
= BSM_ALLCOMPONENTS
;
1205 static const DWORD all_flags
= ( BSF_QUERY
| BSF_IGNORECURRENTTASK
| BSF_FLUSHDISK
| BSF_NOHANG
1206 | BSF_POSTMESSAGE
| BSF_FORCEIFHUNG
| BSF_NOTIMEOUTIFNOTHUNG
1207 | BSF_ALLOWSFW
| BSF_SENDNOTIFYMESSAGE
| BSF_RETURNHDESK
| BSF_LUID
);
1209 TRACE("Flags: %08lx, recipients: %p(0x%lx), msg: %04x, wparam: %08Ix, lparam: %08Ix\n", flags
, recipients
,
1210 (recipients
? *recipients
: recips
), msg
, wp
, lp
);
1212 if (flags
& ~all_flags
)
1214 SetLastError(ERROR_INVALID_PARAMETER
);
1219 recipients
= &recips
;
1221 if ( pinfo
&& flags
& BSF_QUERY
)
1222 FIXME("Not returning PBSMINFO information yet\n");
1225 parm
.recipients
= recipients
;
1229 parm
.success
= TRUE
;
1231 if (*recipients
& BSM_ALLDESKTOPS
|| *recipients
== BSM_ALLCOMPONENTS
)
1232 ret
= EnumWindowStationsW(bcast_winsta
, (LONG_PTR
)&parm
);
1233 else if (*recipients
& BSM_APPLICATIONS
)
1235 EnumWindows(bcast_childwindow
, (LONG_PTR
)&parm
);
1239 FIXME("Recipients %08lx not supported!\n", *recipients
);
1244 /***********************************************************************
1245 * SetMessageQueue (USER32.@)
1247 BOOL WINAPI
SetMessageQueue( INT size
)
1249 /* now obsolete the message queue will be expanded dynamically as necessary */
1254 /***********************************************************************
1255 * MessageBeep (USER32.@)
1257 BOOL WINAPI
MessageBeep( UINT i
)
1259 return NtUserMessageBeep( i
);
1263 /******************************************************************
1264 * SetTimer (USER32.@)
1266 UINT_PTR WINAPI
SetTimer( HWND hwnd
, UINT_PTR id
, UINT timeout
, TIMERPROC proc
)
1268 return NtUserSetTimer( hwnd
, id
, timeout
, proc
, TIMERV_DEFAULT_COALESCING
);
1272 /******************************************************************
1273 * SetSystemTimer (USER32.@)
1275 UINT_PTR WINAPI
SetSystemTimer( HWND hwnd
, UINT_PTR id
, UINT timeout
, void *unknown
)
1277 if (unknown
) FIXME( "ignoring unknown parameter %p\n", unknown
);
1279 return NtUserSetSystemTimer( hwnd
, id
, timeout
);
1283 /***********************************************************************
1284 * KillSystemTimer (USER32.@)
1286 BOOL WINAPI
KillSystemTimer( HWND hwnd
, UINT_PTR id
)
1288 return NtUserKillSystemTimer( hwnd
, id
);
1292 /**********************************************************************
1293 * IsGUIThread (USER32.@)
1295 BOOL WINAPI
IsGUIThread( BOOL convert
)
1297 FIXME( "%u: stub\n", convert
);
1302 /******************************************************************
1303 * IsHungAppWindow (USER32.@)
1306 BOOL WINAPI
IsHungAppWindow( HWND hWnd
)
1310 SERVER_START_REQ( is_window_hung
)
1312 req
->win
= wine_server_user_handle( hWnd
);
1313 ret
= !wine_server_call_err( req
) && reply
->is_hung
;
1319 /******************************************************************
1320 * ChangeWindowMessageFilter (USER32.@)
1322 BOOL WINAPI
ChangeWindowMessageFilter( UINT message
, DWORD flag
)
1324 FIXME( "%x %08lx\n", message
, flag
);
1328 /******************************************************************
1329 * ChangeWindowMessageFilterEx (USER32.@)
1331 BOOL WINAPI
ChangeWindowMessageFilterEx( HWND hwnd
, UINT message
, DWORD action
, CHANGEFILTERSTRUCT
*changefilter
)
1333 FIXME( "%p %x %ld %p\n", hwnd
, message
, action
, changefilter
);