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
25 #define NONAMELESSUNION
26 #define NONAMELESSSTRUCT
28 #define WIN32_NO_STATUS
40 #include "wine/server.h"
41 #include "user_private.h"
44 #include "wine/debug.h"
45 #include "wine/exception.h"
47 WINE_DEFAULT_DEBUG_CHANNEL(msg
);
50 /* pack a pointer into a 32/64 portable format */
51 static inline ULONGLONG
pack_ptr( const void *ptr
)
53 return (ULONG_PTR
)ptr
;
56 /* unpack a potentially 64-bit pointer, returning 0 when truncated */
57 static inline void *unpack_ptr( ULONGLONG ptr64
)
59 if ((ULONG_PTR
)ptr64
!= ptr64
) return 0;
60 return (void *)(ULONG_PTR
)ptr64
;
63 static struct wm_char_mapping_data
*get_wmchar_data(void)
65 return (struct wm_char_mapping_data
*)(UINT_PTR
)NtUserGetThreadInfo()->wmchar_data
;
68 /* check for pending WM_CHAR message with DBCS trailing byte */
69 static inline BOOL
get_pending_wmchar( MSG
*msg
, UINT first
, UINT last
, BOOL remove
)
71 struct wm_char_mapping_data
*data
= get_wmchar_data();
73 if (!data
|| !data
->get_msg
.message
) return FALSE
;
74 if ((first
|| last
) && (first
> WM_CHAR
|| last
< WM_CHAR
)) return FALSE
;
75 if (!msg
) return FALSE
;
77 if (remove
) data
->get_msg
.message
= 0;
82 /***********************************************************************
85 * Window procedure for "Message" windows (HWND_MESSAGE parent).
87 LRESULT WINAPI
MessageWndProc( HWND hwnd
, UINT message
, WPARAM wParam
, LPARAM lParam
)
89 if (message
== WM_NCCREATE
) return TRUE
;
90 return 0; /* all other messages are ignored */
94 DWORD
get_input_codepage( void )
98 HKL hkl
= NtUserGetKeyboardLayout( 0 );
100 ret
= GetLocaleInfoW( LOWORD(hkl
), LOCALE_IDEFAULTANSICODEPAGE
| LOCALE_RETURN_NUMBER
,
101 (WCHAR
*)&cp
, sizeof(cp
) / sizeof(WCHAR
) );
102 if (!ret
) cp
= CP_ACP
;
106 /***********************************************************************
109 * Convert the wparam of an ASCII message to Unicode.
111 BOOL
map_wparam_AtoW( UINT message
, WPARAM
*wparam
, enum wm_char_mapping mapping
)
121 /* WM_CHAR is magic: a DBCS char can be sent/posted as two consecutive WM_CHAR
122 * messages, in which case the first char is stored, and the conversion
123 * to Unicode only takes place once the second char is sent/posted.
125 if (mapping
!= WMCHAR_MAP_NOMAPPING
)
127 struct wm_char_mapping_data
*data
= get_wmchar_data();
128 BYTE low
= LOBYTE(*wparam
);
129 cp
= get_input_codepage();
134 ch
[1] = HIBYTE(*wparam
);
135 MultiByteToWideChar( cp
, 0, ch
, 2, wch
, 2 );
136 TRACE( "map %02x,%02x -> %04x mapping %u\n", (BYTE
)ch
[0], (BYTE
)ch
[1], wch
[0], mapping
);
137 if (data
) data
->lead_byte
[mapping
] = 0;
139 else if (data
&& data
->lead_byte
[mapping
])
141 ch
[0] = data
->lead_byte
[mapping
];
143 MultiByteToWideChar( cp
, 0, ch
, 2, wch
, 2 );
144 TRACE( "map stored %02x,%02x -> %04x mapping %u\n", (BYTE
)ch
[0], (BYTE
)ch
[1], wch
[0], mapping
);
145 data
->lead_byte
[mapping
] = 0;
147 else if (!IsDBCSLeadByte( low
))
150 MultiByteToWideChar( cp
, 0, ch
, 1, wch
, 2 );
151 TRACE( "map %02x -> %04x\n", (BYTE
)ch
[0], wch
[0] );
152 if (data
) data
->lead_byte
[mapping
] = 0;
154 else /* store it and wait for trail byte */
158 if (!(data
= HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(*data
) )))
160 NtUserGetThreadInfo()->wmchar_data
= (UINT_PTR
)data
;
162 TRACE( "storing lead byte %02x mapping %u\n", low
, mapping
);
163 data
->lead_byte
[mapping
] = low
;
166 *wparam
= MAKEWPARAM(wch
[0], wch
[1]);
169 /* else fall through */
171 case EM_SETPASSWORDCHAR
:
176 cp
= get_input_codepage();
177 ch
[0] = LOBYTE(*wparam
);
178 ch
[1] = HIBYTE(*wparam
);
179 MultiByteToWideChar( cp
, 0, ch
, 2, wch
, 2 );
180 *wparam
= MAKEWPARAM(wch
[0], wch
[1]);
183 cp
= get_input_codepage();
184 ch
[0] = HIBYTE(*wparam
);
185 ch
[1] = LOBYTE(*wparam
);
186 if (ch
[0]) MultiByteToWideChar( cp
, 0, ch
, 2, wch
, 2 );
187 else MultiByteToWideChar( cp
, 0, ch
+ 1, 1, wch
, 1 );
188 *wparam
= MAKEWPARAM(wch
[0], HIWORD(*wparam
));
195 /***********************************************************************
198 * Convert the wparam of a Unicode message to ASCII.
200 static void map_wparam_WtoA( MSG
*msg
, BOOL remove
)
210 if (!HIWORD(msg
->wParam
))
212 cp
= get_input_codepage();
213 wch
[0] = LOWORD(msg
->wParam
);
215 len
= WideCharToMultiByte( cp
, 0, wch
, 1, (LPSTR
)ch
, 2, NULL
, NULL
);
216 if (len
== 2) /* DBCS char */
218 struct wm_char_mapping_data
*data
= get_wmchar_data();
221 if (!(data
= HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(*data
) ))) return;
222 NtUserGetThreadInfo()->wmchar_data
= (UINT_PTR
)data
;
226 data
->get_msg
= *msg
;
227 data
->get_msg
.wParam
= ch
[1];
233 /* else fall through */
235 case EM_SETPASSWORDCHAR
:
240 cp
= get_input_codepage();
241 wch
[0] = LOWORD(msg
->wParam
);
242 wch
[1] = HIWORD(msg
->wParam
);
244 WideCharToMultiByte( cp
, 0, wch
, 2, (LPSTR
)ch
, 4, NULL
, NULL
);
245 msg
->wParam
= MAKEWPARAM( ch
[0] | (ch
[1] << 8), 0 );
248 cp
= get_input_codepage();
249 wch
[0] = LOWORD(msg
->wParam
);
251 len
= WideCharToMultiByte( cp
, 0, wch
, 1, (LPSTR
)ch
, 2, NULL
, NULL
);
253 msg
->wParam
= MAKEWPARAM( (ch
[0] << 8) | ch
[1], HIWORD(msg
->wParam
) );
255 msg
->wParam
= MAKEWPARAM( ch
[0], HIWORD(msg
->wParam
) );
261 /* since the WM_DDE_ACK response to a WM_DDE_EXECUTE message should contain the handle
262 * to the memory handle, we keep track (in the server side) of all pairs of handle
263 * used (the client passes its value and the content of the memory handle), and
264 * the server stored both values (the client, and the local one, created after the
265 * content). When a ACK message is generated, the list of pair is searched for a
266 * matching pair, so that the client memory handle can be returned.
273 static struct DDE_pair
* dde_pairs
;
274 static int dde_num_alloc
;
275 static int dde_num_used
;
277 static CRITICAL_SECTION dde_crst
;
278 static CRITICAL_SECTION_DEBUG critsect_debug
=
281 { &critsect_debug
.ProcessLocksList
, &critsect_debug
.ProcessLocksList
},
282 0, 0, { (DWORD_PTR
)(__FILE__
": dde_crst") }
284 static CRITICAL_SECTION dde_crst
= { &critsect_debug
, -1, 0, 0, 0, 0 };
286 static BOOL
dde_add_pair(HGLOBAL chm
, HGLOBAL shm
)
291 EnterCriticalSection(&dde_crst
);
293 /* now remember the pair of hMem on both sides */
294 if (dde_num_used
== dde_num_alloc
)
296 struct DDE_pair
* tmp
;
298 tmp
= HeapReAlloc( GetProcessHeap(), 0, dde_pairs
,
299 (dde_num_alloc
+ GROWBY
) * sizeof(struct DDE_pair
));
301 tmp
= HeapAlloc( GetProcessHeap(), 0,
302 (dde_num_alloc
+ GROWBY
) * sizeof(struct DDE_pair
));
306 LeaveCriticalSection(&dde_crst
);
310 /* zero out newly allocated part */
311 memset(&dde_pairs
[dde_num_alloc
], 0, GROWBY
* sizeof(struct DDE_pair
));
312 dde_num_alloc
+= GROWBY
;
315 for (i
= 0; i
< dde_num_alloc
; i
++)
317 if (dde_pairs
[i
].server_hMem
== 0)
319 dde_pairs
[i
].client_hMem
= chm
;
320 dde_pairs
[i
].server_hMem
= shm
;
325 LeaveCriticalSection(&dde_crst
);
329 static HGLOBAL
dde_get_pair(HGLOBAL shm
)
334 EnterCriticalSection(&dde_crst
);
335 for (i
= 0; i
< dde_num_alloc
; i
++)
337 if (dde_pairs
[i
].server_hMem
== shm
)
340 dde_pairs
[i
].server_hMem
= 0;
342 ret
= dde_pairs
[i
].client_hMem
;
346 LeaveCriticalSection(&dde_crst
);
350 /***********************************************************************
355 BOOL
post_dde_message( HWND hwnd
, UINT msg
, WPARAM wparam
, LPARAM lparam
, DWORD dest_tid
, DWORD type
)
365 if (!UnpackDDElParam( msg
, lparam
, &uiLo
, &uiHi
))
371 /* DDE messages which don't require packing are:
380 /* uiHi should contain a hMem from WM_DDE_EXECUTE */
381 HGLOBAL h
= dde_get_pair( (HANDLE
)uiHi
);
384 hpack
= pack_ptr( h
);
385 /* send back the value of h on the other side */
387 size
= sizeof(hpack
);
389 TRACE( "send dde-ack %Ix %08Ix => %p\n", uiLo
, uiHi
, h
);
394 /* uiHi should contain either an atom or 0 */
395 TRACE( "send dde-ack %Ix atom=%Ix\n", uiLo
, uiHi
);
396 lp
= MAKELONG( uiLo
, uiHi
);
404 size
= GlobalSize( (HGLOBAL
)uiLo
) ;
405 if ((msg
== WM_DDE_ADVISE
&& size
< sizeof(DDEADVISE
)) ||
406 (msg
== WM_DDE_DATA
&& size
< FIELD_OFFSET(DDEDATA
, Value
)) ||
407 (msg
== WM_DDE_POKE
&& size
< FIELD_OFFSET(DDEPOKE
, Value
)))
410 else if (msg
!= WM_DDE_DATA
) return FALSE
;
415 if ((ptr
= GlobalLock( (HGLOBAL
)uiLo
) ))
417 DDEDATA
*dde_data
= ptr
;
418 TRACE("unused %d, fResponse %d, fRelease %d, fDeferUpd %d, fAckReq %d, cfFormat %d\n",
419 dde_data
->unused
, dde_data
->fResponse
, dde_data
->fRelease
,
420 dde_data
->reserved
, dde_data
->fAckReq
, dde_data
->cfFormat
);
421 hunlock
= (HGLOBAL
)uiLo
;
424 TRACE( "send ddepack %u %Ix\n", size
, uiHi
);
429 if ((ptr
= GlobalLock( (HGLOBAL
)lparam
) ))
431 size
= GlobalSize( (HGLOBAL
)lparam
);
432 /* so that the other side can send it back on ACK */
434 hunlock
= (HGLOBAL
)lparam
;
439 SERVER_START_REQ( send_message
)
444 req
->win
= wine_server_user_handle( hwnd
);
446 req
->wparam
= wparam
;
448 req
->timeout
= TIMEOUT_INFINITE
;
449 if (size
) wine_server_add_data( req
, ptr
, size
);
450 if ((res
= wine_server_call( req
)))
452 if (res
== STATUS_INVALID_PARAMETER
)
453 /* FIXME: find a STATUS_ value for this one */
454 SetLastError( ERROR_INVALID_THREAD_ID
);
456 SetLastError( RtlNtStatusToDosError(res
) );
459 FreeDDElParam( msg
, lparam
);
462 if (hunlock
) GlobalUnlock(hunlock
);
467 /***********************************************************************
470 * Unpack a posted DDE message received from another process.
472 BOOL
unpack_dde_message( HWND hwnd
, UINT message
, WPARAM
*wparam
, LPARAM
*lparam
,
473 const void *buffer
, size_t size
)
485 /* hMem is being passed */
486 if (size
!= sizeof(hpack
)) return FALSE
;
488 memcpy( &hpack
, buffer
, size
);
489 hMem
= unpack_ptr( hpack
);
490 uiHi
= (UINT_PTR
)hMem
;
491 TRACE("recv dde-ack %Ix mem=%Ix[%Ix]\n", uiLo
, uiHi
, GlobalSize( hMem
));
495 uiLo
= LOWORD( *lparam
);
496 uiHi
= HIWORD( *lparam
);
497 TRACE("recv dde-ack %Ix atom=%Ix\n", uiLo
, uiHi
);
499 *lparam
= PackDDElParam( WM_DDE_ACK
, uiLo
, uiHi
);
504 if (!size
&& message
!= WM_DDE_DATA
) return FALSE
;
508 if (!(hMem
= GlobalAlloc( GMEM_MOVEABLE
|GMEM_DDESHARE
, size
)))
510 if ((ptr
= GlobalLock( hMem
)))
512 memcpy( ptr
, buffer
, size
);
513 GlobalUnlock( hMem
);
521 uiLo
= (UINT_PTR
)hMem
;
523 *lparam
= PackDDElParam( message
, uiLo
, uiHi
);
528 if (!(hMem
= GlobalAlloc( GMEM_MOVEABLE
|GMEM_DDESHARE
, size
))) return FALSE
;
529 if ((ptr
= GlobalLock( hMem
)))
531 memcpy( ptr
, buffer
, size
);
532 GlobalUnlock( hMem
);
533 TRACE( "exec: pairing c=%08Ix s=%p\n", *lparam
, hMem
);
534 if (!dde_add_pair( (HGLOBAL
)*lparam
, hMem
))
546 *lparam
= (LPARAM
)hMem
;
552 /***********************************************************************
553 * SendMessageTimeoutW (USER32.@)
555 LRESULT WINAPI
SendMessageTimeoutW( HWND hwnd
, UINT msg
, WPARAM wparam
, LPARAM lparam
,
556 UINT flags
, UINT timeout
, PDWORD_PTR res_ptr
)
558 struct send_message_timeout_params params
= { .flags
= flags
, .timeout
= timeout
};
561 res
= NtUserMessageCall( hwnd
, msg
, wparam
, lparam
, ¶ms
, NtUserSendMessageTimeout
, FALSE
);
562 if (res_ptr
) *res_ptr
= res
;
563 return params
.result
;
566 /***********************************************************************
567 * SendMessageTimeoutA (USER32.@)
569 LRESULT WINAPI
SendMessageTimeoutA( HWND hwnd
, UINT msg
, WPARAM wparam
, LPARAM lparam
,
570 UINT flags
, UINT timeout
, PDWORD_PTR res_ptr
)
572 struct send_message_timeout_params params
= { .flags
= flags
, .timeout
= timeout
};
575 if (msg
!= WM_CHAR
|| WIN_IsCurrentThread( hwnd
))
577 res
= NtUserMessageCall( hwnd
, msg
, wparam
, lparam
, ¶ms
,
578 NtUserSendMessageTimeout
, TRUE
);
580 else if (map_wparam_AtoW( msg
, &wparam
, WMCHAR_MAP_SENDMESSAGE
))
582 res
= NtUserMessageCall( hwnd
, msg
, wparam
, lparam
, ¶ms
,
583 NtUserSendMessageTimeout
, FALSE
);
586 if (res_ptr
) *res_ptr
= res
;
587 return params
.result
;
591 static LRESULT
dispatch_send_message( struct win_proc_params
*params
)
593 struct ntuser_thread_info
*thread_info
= NtUserGetThreadInfo();
594 INPUT_MESSAGE_SOURCE prev_source
= thread_info
->msg_source
;
597 static const INPUT_MESSAGE_SOURCE msg_source_unavailable
= { IMDT_UNAVAILABLE
, IMO_UNAVAILABLE
};
599 thread_info
->recursion_count
++;
601 params
->result
= &retval
;
602 thread_info
->msg_source
= msg_source_unavailable
;
603 SPY_EnterMessage( SPY_SENDMESSAGE
, params
->hwnd
, params
->msg
, params
->wparam
, params
->lparam
);
605 dispatch_win_proc_params( params
);
607 SPY_ExitMessage( SPY_RESULT_OK
, params
->hwnd
, params
->msg
, retval
, params
->wparam
, params
->lparam
);
608 thread_info
->msg_source
= prev_source
;
609 thread_info
->recursion_count
--;
614 /***********************************************************************
615 * SendMessageW (USER32.@)
617 LRESULT WINAPI
SendMessageW( HWND hwnd
, UINT msg
, WPARAM wparam
, LPARAM lparam
)
619 struct win_proc_params params
;
623 retval
= NtUserMessageCall( hwnd
, msg
, wparam
, lparam
, ¶ms
, NtUserSendMessage
, FALSE
);
624 if (params
.hwnd
) retval
= dispatch_send_message( ¶ms
);
629 /***********************************************************************
630 * SendMessageA (USER32.@)
632 LRESULT WINAPI
SendMessageA( HWND hwnd
, UINT msg
, WPARAM wparam
, LPARAM lparam
)
634 struct win_proc_params params
;
637 if (msg
== WM_CHAR
&& !WIN_IsCurrentThread( hwnd
))
639 if (!map_wparam_AtoW( msg
, &wparam
, WMCHAR_MAP_SENDMESSAGE
))
641 return NtUserMessageCall( hwnd
, msg
, wparam
, lparam
, NULL
, NtUserSendMessage
, FALSE
);
645 retval
= NtUserMessageCall( hwnd
, msg
, wparam
, lparam
, ¶ms
, NtUserSendMessage
, TRUE
);
646 if (params
.hwnd
) retval
= dispatch_send_message( ¶ms
);
651 /***********************************************************************
652 * SendNotifyMessageA (USER32.@)
654 BOOL WINAPI
SendNotifyMessageA( HWND hwnd
, UINT msg
, WPARAM wparam
, LPARAM lparam
)
656 if (!WIN_IsCurrentThread( hwnd
) && !map_wparam_AtoW( msg
, &wparam
, WMCHAR_MAP_SENDMESSAGE
))
659 return NtUserMessageCall( hwnd
, msg
, wparam
, lparam
, 0, NtUserSendNotifyMessage
, TRUE
);
663 /***********************************************************************
664 * SendNotifyMessageW (USER32.@)
666 BOOL WINAPI
SendNotifyMessageW( HWND hwnd
, UINT msg
, WPARAM wparam
, LPARAM lparam
)
668 return NtUserMessageCall( hwnd
, msg
, wparam
, lparam
, 0, NtUserSendNotifyMessage
, FALSE
);
672 /***********************************************************************
673 * SendMessageCallbackA (USER32.@)
675 BOOL WINAPI
SendMessageCallbackA( HWND hwnd
, UINT msg
, WPARAM wparam
, LPARAM lparam
,
676 SENDASYNCPROC callback
, ULONG_PTR data
)
678 struct send_message_callback_params params
= { .callback
= callback
, .data
= data
};
680 if (!WIN_IsCurrentThread( hwnd
) && !map_wparam_AtoW( msg
, &wparam
, WMCHAR_MAP_SENDMESSAGE
))
683 return NtUserMessageCall( hwnd
, msg
, wparam
, lparam
, ¶ms
, NtUserSendMessageCallback
, TRUE
);
687 /***********************************************************************
688 * SendMessageCallbackW (USER32.@)
690 BOOL WINAPI
SendMessageCallbackW( HWND hwnd
, UINT msg
, WPARAM wparam
, LPARAM lparam
,
691 SENDASYNCPROC callback
, ULONG_PTR data
)
693 struct send_message_callback_params params
= { .callback
= callback
, .data
= data
};
694 return NtUserMessageCall( hwnd
, msg
, wparam
, lparam
, ¶ms
, NtUserSendMessageCallback
, FALSE
);
698 /***********************************************************************
699 * ReplyMessage (USER32.@)
701 BOOL WINAPI
ReplyMessage( LRESULT result
)
703 return NtUserReplyMessage( result
, NULL
);
707 /***********************************************************************
708 * InSendMessage (USER32.@)
710 BOOL WINAPI
InSendMessage(void)
712 return (InSendMessageEx( NULL
) & (ISMEX_SEND
| ISMEX_NOTIFY
| ISMEX_CALLBACK
)) != 0;
716 /***********************************************************************
717 * InSendMessageEx (USER32.@)
719 DWORD WINAPI
InSendMessageEx( LPVOID reserved
)
721 return NtUserGetThreadInfo()->receive_flags
;
725 /***********************************************************************
726 * PostMessageA (USER32.@)
728 BOOL WINAPI
PostMessageA( HWND hwnd
, UINT msg
, WPARAM wparam
, LPARAM lparam
)
730 if (!map_wparam_AtoW( msg
, &wparam
, WMCHAR_MAP_POSTMESSAGE
)) return TRUE
;
731 return PostMessageW( hwnd
, msg
, wparam
, lparam
);
735 /***********************************************************************
736 * PostMessageW (USER32.@)
738 BOOL WINAPI
PostMessageW( HWND hwnd
, UINT msg
, WPARAM wparam
, LPARAM lparam
)
740 return NtUserPostMessage( hwnd
, msg
, wparam
, lparam
);
744 /**********************************************************************
745 * PostThreadMessageA (USER32.@)
747 BOOL WINAPI
PostThreadMessageA( DWORD thread
, UINT msg
, WPARAM wparam
, LPARAM lparam
)
749 if (!map_wparam_AtoW( msg
, &wparam
, WMCHAR_MAP_POSTMESSAGE
)) return TRUE
;
750 return NtUserPostThreadMessage( thread
, msg
, wparam
, lparam
);
754 /***********************************************************************
755 * PostQuitMessage (USER32.@)
757 * Posts a quit message to the current thread's message queue.
760 * exit_code [I] Exit code to return from message loop.
766 * This function is not the same as calling:
767 *|PostThreadMessage(GetCurrentThreadId(), WM_QUIT, exit_code, 0);
768 * It instead sets a flag in the message queue that signals it to generate
769 * a WM_QUIT message when there are no other pending sent or posted messages
772 void WINAPI
PostQuitMessage( INT exit_code
)
774 SERVER_START_REQ( post_quit_message
)
776 req
->exit_code
= exit_code
;
777 wine_server_call( req
);
782 /***********************************************************************
783 * PeekMessageW (USER32.@)
785 BOOL WINAPI DECLSPEC_HOTPATCH
PeekMessageW( MSG
*msg_out
, HWND hwnd
, UINT first
, UINT last
, UINT flags
)
787 return NtUserPeekMessage( msg_out
, hwnd
, first
, last
, flags
);
791 /***********************************************************************
792 * PeekMessageA (USER32.@)
794 BOOL WINAPI DECLSPEC_HOTPATCH
PeekMessageA( MSG
*msg
, HWND hwnd
, UINT first
, UINT last
, UINT flags
)
796 if (get_pending_wmchar( msg
, first
, last
, (flags
& PM_REMOVE
) )) return TRUE
;
797 if (!PeekMessageW( msg
, hwnd
, first
, last
, flags
)) return FALSE
;
798 map_wparam_WtoA( msg
, (flags
& PM_REMOVE
) );
803 /***********************************************************************
804 * GetMessageW (USER32.@)
806 BOOL WINAPI DECLSPEC_HOTPATCH
GetMessageW( MSG
*msg
, HWND hwnd
, UINT first
, UINT last
)
808 return NtUserGetMessage( msg
, hwnd
, first
, last
);
812 /***********************************************************************
813 * GetMessageA (USER32.@)
815 BOOL WINAPI DECLSPEC_HOTPATCH
GetMessageA( MSG
*msg
, HWND hwnd
, UINT first
, UINT last
)
817 if (get_pending_wmchar( msg
, first
, last
, TRUE
)) return TRUE
;
818 if (GetMessageW( msg
, hwnd
, first
, last
) < 0) return -1;
819 map_wparam_WtoA( msg
, TRUE
);
820 return (msg
->message
!= WM_QUIT
);
824 /***********************************************************************
825 * IsDialogMessageA (USER32.@)
826 * IsDialogMessage (USER32.@)
828 BOOL WINAPI
IsDialogMessageA( HWND hwndDlg
, LPMSG pmsg
)
831 map_wparam_AtoW( msg
.message
, &msg
.wParam
, WMCHAR_MAP_NOMAPPING
);
832 return IsDialogMessageW( hwndDlg
, &msg
);
836 /***********************************************************************
837 * TranslateMessage (USER32.@)
839 * Implementation of TranslateMessage.
841 * TranslateMessage translates virtual-key messages into character-messages,
843 * WM_KEYDOWN/WM_KEYUP combinations produce a WM_CHAR or WM_DEADCHAR message.
844 * ditto replacing WM_* with WM_SYS*
845 * This produces WM_CHAR messages only for keys mapped to ASCII characters
846 * by the keyboard driver.
848 * If the message is WM_KEYDOWN, WM_KEYUP, WM_SYSKEYDOWN, or WM_SYSKEYUP, the
849 * return value is nonzero, regardless of the translation.
852 BOOL WINAPI
TranslateMessage( const MSG
*msg
)
854 return NtUserTranslateMessage( msg
, 0 );
858 static LRESULT
dispatch_message( const MSG
*msg
, BOOL ansi
)
860 struct win_proc_params params
;
863 if (!NtUserMessageCall( msg
->hwnd
, msg
->message
, msg
->wParam
, msg
->lParam
,
864 ¶ms
, NtUserGetDispatchParams
, ansi
)) return 0;
865 params
.result
= &retval
;
867 SPY_EnterMessage( SPY_DISPATCHMESSAGE
, msg
->hwnd
, msg
->message
, msg
->wParam
, msg
->lParam
);
868 dispatch_win_proc_params( ¶ms
);
869 SPY_ExitMessage( SPY_RESULT_OK
, msg
->hwnd
, msg
->message
, retval
, msg
->wParam
, msg
->lParam
);
874 /***********************************************************************
875 * DispatchMessageA (USER32.@)
877 * See DispatchMessageW.
879 LRESULT WINAPI DECLSPEC_HOTPATCH
DispatchMessageA( const MSG
* msg
)
883 /* Process timer messages */
884 if (msg
->lParam
&& msg
->message
== WM_TIMER
)
888 retval
= CallWindowProcA( (WNDPROC
)msg
->lParam
, msg
->hwnd
,
889 msg
->message
, msg
->wParam
, GetTickCount() );
899 /* whenever possible, avoid using NtUserDispatchMessage to make the call unwindable */
900 if (msg
->message
!= WM_SYSTIMER
&& msg
->message
!= WM_PAINT
)
901 return dispatch_message( msg
, TRUE
);
903 return NtUserDispatchMessage( msg
);
907 /***********************************************************************
908 * DispatchMessageW (USER32.@) Process a message
910 * Process the message specified in the structure *_msg_.
912 * If the lpMsg parameter points to a WM_TIMER message and the
913 * parameter of the WM_TIMER message is not NULL, the lParam parameter
914 * points to the function that is called instead of the window
915 * procedure. The function stored in lParam (timer callback) is protected
916 * from causing page-faults.
918 * The message must be valid.
922 * DispatchMessage() returns the result of the window procedure invoked.
929 LRESULT WINAPI DECLSPEC_HOTPATCH
DispatchMessageW( const MSG
* msg
)
933 /* Process timer messages */
934 if ((msg
->message
== WM_TIMER
) || (msg
->message
== WM_SYSTIMER
))
940 retval
= CallWindowProcW( (WNDPROC
)msg
->lParam
, msg
->hwnd
,
941 msg
->message
, msg
->wParam
, GetTickCount() );
952 /* whenever possible, avoid using NtUserDispatchMessage to make the call unwindable */
953 if (msg
->message
!= WM_SYSTIMER
&& msg
->message
!= WM_PAINT
)
954 return dispatch_message( msg
, FALSE
);
956 return NtUserDispatchMessage( msg
);
960 /***********************************************************************
961 * GetMessagePos (USER.119)
962 * GetMessagePos (USER32.@)
964 * The GetMessagePos() function returns a long value representing a
965 * cursor position, in screen coordinates, when the last message
966 * retrieved by the GetMessage() function occurs. The x-coordinate is
967 * in the low-order word of the return value, the y-coordinate is in
968 * the high-order word. The application can use the MAKEPOINT()
969 * macro to obtain a POINT structure from the return value.
971 * For the current cursor position, use GetCursorPos().
975 * Cursor position of last message on success, zero on failure.
982 DWORD WINAPI
GetMessagePos(void)
984 return NtUserGetThreadInfo()->message_pos
;
988 /***********************************************************************
989 * GetMessageTime (USER.120)
990 * GetMessageTime (USER32.@)
992 * GetMessageTime() returns the message time for the last message
993 * retrieved by the function. The time is measured in milliseconds with
994 * the same offset as GetTickCount().
996 * Since the tick count wraps, this is only useful for moderately short
997 * relative time comparisons.
1001 * Time of last message on success, zero on failure.
1003 LONG WINAPI
GetMessageTime(void)
1005 return NtUserGetThreadInfo()->message_time
;
1009 /***********************************************************************
1010 * GetMessageExtraInfo (USER.288)
1011 * GetMessageExtraInfo (USER32.@)
1013 LPARAM WINAPI
GetMessageExtraInfo(void)
1015 return NtUserGetThreadInfo()->message_extra
;
1019 /***********************************************************************
1020 * SetMessageExtraInfo (USER32.@)
1022 LPARAM WINAPI
SetMessageExtraInfo(LPARAM lParam
)
1024 struct ntuser_thread_info
*thread_info
= NtUserGetThreadInfo();
1025 LONG old_value
= thread_info
->message_extra
;
1026 thread_info
->message_extra
= lParam
;
1031 /***********************************************************************
1032 * GetCurrentInputMessageSource (USER32.@)
1034 BOOL WINAPI
GetCurrentInputMessageSource( INPUT_MESSAGE_SOURCE
*source
)
1036 *source
= NtUserGetThreadInfo()->msg_source
;
1041 /***********************************************************************
1042 * WaitMessage (USER.112) Suspend thread pending messages
1043 * WaitMessage (USER32.@) Suspend thread pending messages
1045 * WaitMessage() suspends a thread until events appear in the thread's
1048 BOOL WINAPI
WaitMessage(void)
1050 return NtUserMsgWaitForMultipleObjectsEx( 0, NULL
, INFINITE
, QS_ALLINPUT
, 0 ) != WAIT_FAILED
;
1054 /***********************************************************************
1055 * MsgWaitForMultipleObjects (USER32.@)
1057 DWORD WINAPI
MsgWaitForMultipleObjects( DWORD count
, const HANDLE
*handles
,
1058 BOOL wait_all
, DWORD timeout
, DWORD mask
)
1060 return NtUserMsgWaitForMultipleObjectsEx( count
, handles
, timeout
, mask
,
1061 wait_all
? MWMO_WAITALL
: 0 );
1065 /***********************************************************************
1066 * WaitForInputIdle (USER32.@)
1068 DWORD WINAPI
WaitForInputIdle( HANDLE process
, DWORD timeout
)
1070 return NtUserWaitForInputIdle( process
, timeout
, FALSE
);
1074 /***********************************************************************
1075 * RegisterWindowMessageA (USER32.@)
1076 * RegisterWindowMessage (USER.118)
1078 UINT WINAPI
RegisterWindowMessageA( LPCSTR str
)
1080 UINT ret
= GlobalAddAtomA(str
);
1081 TRACE("%s, ret=%x\n", str
, ret
);
1086 /***********************************************************************
1087 * RegisterWindowMessageW (USER32.@)
1089 UINT WINAPI
RegisterWindowMessageW( LPCWSTR str
)
1091 UINT ret
= GlobalAddAtomW(str
);
1092 TRACE("%s ret=%x\n", debugstr_w(str
), ret
);
1096 typedef struct BroadcastParm
1107 static BOOL CALLBACK
bcast_childwindow( HWND hw
, LPARAM lp
)
1109 BroadcastParm
*parm
= (BroadcastParm
*)lp
;
1110 DWORD_PTR retval
= 0;
1113 if (parm
->flags
& BSF_IGNORECURRENTTASK
&& WIN_IsCurrentProcess(hw
))
1115 TRACE("Not telling myself %p\n", hw
);
1119 /* I don't know 100% for sure if this is what Windows does, but it fits the tests */
1120 if (parm
->flags
& BSF_QUERY
)
1122 TRACE("Telling window %p using SendMessageTimeout\n", hw
);
1124 /* Not tested for conflicting flags */
1125 if (parm
->flags
& BSF_FORCEIFHUNG
|| parm
->flags
& BSF_NOHANG
)
1126 lresult
= SendMessageTimeoutW( hw
, parm
->msg
, parm
->wp
, parm
->lp
, SMTO_ABORTIFHUNG
, 2000, &retval
);
1127 else if (parm
->flags
& BSF_NOTIMEOUTIFNOTHUNG
)
1128 lresult
= SendMessageTimeoutW( hw
, parm
->msg
, parm
->wp
, parm
->lp
, SMTO_NOTIMEOUTIFNOTHUNG
, 2000, &retval
);
1130 lresult
= SendMessageTimeoutW( hw
, parm
->msg
, parm
->wp
, parm
->lp
, SMTO_NORMAL
, 2000, &retval
);
1132 if (!lresult
&& GetLastError() == ERROR_TIMEOUT
)
1134 WARN("Timed out!\n");
1135 if (!(parm
->flags
& BSF_FORCEIFHUNG
))
1138 if (retval
== BROADCAST_QUERY_DENY
)
1144 parm
->success
= FALSE
;
1147 else if (parm
->flags
& BSF_POSTMESSAGE
)
1149 TRACE("Telling window %p using PostMessage\n", hw
);
1150 PostMessageW( hw
, parm
->msg
, parm
->wp
, parm
->lp
);
1154 TRACE("Telling window %p using SendNotifyMessage\n", hw
);
1155 SendNotifyMessageW( hw
, parm
->msg
, parm
->wp
, parm
->lp
);
1161 static BOOL CALLBACK
bcast_desktop( LPWSTR desktop
, LPARAM lp
)
1165 BroadcastParm
*parm
= (BroadcastParm
*)lp
;
1167 TRACE("desktop: %s\n", debugstr_w( desktop
));
1169 hdesktop
= open_winstation_desktop( parm
->winsta
, desktop
, 0, FALSE
, DESKTOP_ENUMERATE
|DESKTOP_WRITEOBJECTS
|STANDARD_RIGHTS_WRITE
);
1172 FIXME("Could not open desktop %s\n", debugstr_w(desktop
));
1176 ret
= EnumDesktopWindows( hdesktop
, bcast_childwindow
, lp
);
1177 NtUserCloseDesktop( hdesktop
);
1178 TRACE("-->%d\n", ret
);
1179 return parm
->success
;
1182 static BOOL CALLBACK
bcast_winsta( LPWSTR winsta
, LPARAM lp
)
1185 HWINSTA hwinsta
= OpenWindowStationW( winsta
, FALSE
, WINSTA_ENUMDESKTOPS
);
1186 TRACE("hwinsta: %p/%s/%08lx\n", hwinsta
, debugstr_w( winsta
), GetLastError());
1189 ((BroadcastParm
*)lp
)->winsta
= hwinsta
;
1190 ret
= EnumDesktopsW( hwinsta
, bcast_desktop
, lp
);
1191 NtUserCloseWindowStation( hwinsta
);
1192 TRACE("-->%d\n", ret
);
1196 /***********************************************************************
1197 * BroadcastSystemMessageA (USER32.@)
1198 * BroadcastSystemMessage (USER32.@)
1200 LONG WINAPI
BroadcastSystemMessageA( DWORD flags
, LPDWORD recipients
, UINT msg
, WPARAM wp
, LPARAM lp
)
1202 return BroadcastSystemMessageExA( flags
, recipients
, msg
, wp
, lp
, NULL
);
1206 /***********************************************************************
1207 * BroadcastSystemMessageW (USER32.@)
1209 LONG WINAPI
BroadcastSystemMessageW( DWORD flags
, LPDWORD recipients
, UINT msg
, WPARAM wp
, LPARAM lp
)
1211 return BroadcastSystemMessageExW( flags
, recipients
, msg
, wp
, lp
, NULL
);
1214 /***********************************************************************
1215 * BroadcastSystemMessageExA (USER32.@)
1217 LONG WINAPI
BroadcastSystemMessageExA( DWORD flags
, LPDWORD recipients
, UINT msg
, WPARAM wp
, LPARAM lp
, PBSMINFO pinfo
)
1219 map_wparam_AtoW( msg
, &wp
, WMCHAR_MAP_NOMAPPING
);
1220 return BroadcastSystemMessageExW( flags
, recipients
, msg
, wp
, lp
, NULL
);
1224 /***********************************************************************
1225 * BroadcastSystemMessageExW (USER32.@)
1227 LONG WINAPI
BroadcastSystemMessageExW( DWORD flags
, LPDWORD recipients
, UINT msg
, WPARAM wp
, LPARAM lp
, PBSMINFO pinfo
)
1230 DWORD recips
= BSM_ALLCOMPONENTS
;
1232 static const DWORD all_flags
= ( BSF_QUERY
| BSF_IGNORECURRENTTASK
| BSF_FLUSHDISK
| BSF_NOHANG
1233 | BSF_POSTMESSAGE
| BSF_FORCEIFHUNG
| BSF_NOTIMEOUTIFNOTHUNG
1234 | BSF_ALLOWSFW
| BSF_SENDNOTIFYMESSAGE
| BSF_RETURNHDESK
| BSF_LUID
);
1236 TRACE("Flags: %08lx, recipients: %p(0x%lx), msg: %04x, wparam: %08Ix, lparam: %08Ix\n", flags
, recipients
,
1237 (recipients
? *recipients
: recips
), msg
, wp
, lp
);
1239 if (flags
& ~all_flags
)
1241 SetLastError(ERROR_INVALID_PARAMETER
);
1246 recipients
= &recips
;
1248 if ( pinfo
&& flags
& BSF_QUERY
)
1249 FIXME("Not returning PBSMINFO information yet\n");
1252 parm
.recipients
= recipients
;
1256 parm
.success
= TRUE
;
1258 if (*recipients
& BSM_ALLDESKTOPS
|| *recipients
== BSM_ALLCOMPONENTS
)
1259 ret
= EnumWindowStationsW(bcast_winsta
, (LONG_PTR
)&parm
);
1260 else if (*recipients
& BSM_APPLICATIONS
)
1262 EnumWindows(bcast_childwindow
, (LONG_PTR
)&parm
);
1266 FIXME("Recipients %08lx not supported!\n", *recipients
);
1271 /***********************************************************************
1272 * SetMessageQueue (USER32.@)
1274 BOOL WINAPI
SetMessageQueue( INT size
)
1276 /* now obsolete the message queue will be expanded dynamically as necessary */
1281 /***********************************************************************
1282 * MessageBeep (USER32.@)
1284 BOOL WINAPI
MessageBeep( UINT i
)
1286 return NtUserMessageBeep( i
);
1290 /******************************************************************
1291 * SetTimer (USER32.@)
1293 UINT_PTR WINAPI
SetTimer( HWND hwnd
, UINT_PTR id
, UINT timeout
, TIMERPROC proc
)
1295 return NtUserSetTimer( hwnd
, id
, timeout
, proc
, TIMERV_DEFAULT_COALESCING
);
1299 /******************************************************************
1300 * SetSystemTimer (USER32.@)
1302 UINT_PTR WINAPI
SetSystemTimer( HWND hwnd
, UINT_PTR id
, UINT timeout
, void *unknown
)
1304 if (unknown
) FIXME( "ignoring unknown parameter %p\n", unknown
);
1306 return NtUserSetSystemTimer( hwnd
, id
, timeout
);
1310 /***********************************************************************
1311 * KillSystemTimer (USER32.@)
1313 BOOL WINAPI
KillSystemTimer( HWND hwnd
, UINT_PTR id
)
1315 return NtUserKillSystemTimer( hwnd
, id
);
1319 /**********************************************************************
1320 * IsGUIThread (USER32.@)
1322 BOOL WINAPI
IsGUIThread( BOOL convert
)
1324 FIXME( "%u: stub\n", convert
);
1329 /******************************************************************
1330 * IsHungAppWindow (USER32.@)
1333 BOOL WINAPI
IsHungAppWindow( HWND hWnd
)
1337 SERVER_START_REQ( is_window_hung
)
1339 req
->win
= wine_server_user_handle( hWnd
);
1340 ret
= !wine_server_call_err( req
) && reply
->is_hung
;
1346 /******************************************************************
1347 * ChangeWindowMessageFilter (USER32.@)
1349 BOOL WINAPI
ChangeWindowMessageFilter( UINT message
, DWORD flag
)
1351 FIXME( "%x %08lx\n", message
, flag
);
1355 /******************************************************************
1356 * ChangeWindowMessageFilterEx (USER32.@)
1358 BOOL WINAPI
ChangeWindowMessageFilterEx( HWND hwnd
, UINT message
, DWORD action
, CHANGEFILTERSTRUCT
*changefilter
)
1360 FIXME( "%p %x %ld %p\n", hwnd
, message
, action
, changefilter
);