source: trunk/src/user32/message.cpp@ 8608

Last change on this file since 8608 was 8608, checked in by sandervl, 23 years ago

SendMessageTimeoutA/W fixes for inter-process/thread message sending

File size: 20.7 KB
Line 
1/* $Id: message.cpp,v 1.3 2002-06-09 10:47:50 sandervl Exp $ */
2/*
3 * Win32 window message APIs for OS/2
4 *
5 * Copyright 1999-2002 Sander van Leeuwen
6 *
7 * Based on Wine Windows code (dlls\user\message.c) 20020122
8 *
9 * Window messaging support
10 *
11 * Copyright 2001 Alexandre Julliard
12 *
13 * Project Odin Software License can be found in LICENSE.TXT
14 *
15 */
16
17#include <odin.h>
18#include <odinwrap.h>
19#include <os2sel.h>
20
21#include <os2win.h>
22#include <misc.h>
23#include <win32wbase.h>
24#include <win.h>
25#include <heapstring.h>
26#include <handlemanager.h>
27#include "oslibutil.h"
28#include "oslibwin.h"
29#include "oslibmsg.h"
30#include "hook.h"
31#include "wndmsg.h"
32
33#define DBG_LOCALLOG DBG_message
34#include "dbglocal.h"
35
36ODINDEBUGCHANNEL(USER32-MESSAGE)
37
38#define WIN_GetFullHandle(a) a
39
40#define is_broadcast(hwnd) (hwnd == HWND_BROADCAST || hwnd == HWND_TOPMOST)
41
42
43enum message_type
44{
45 MSG_ASCII,
46 MSG_UNICODE,
47 MSG_NOTIFY,
48 MSG_CALLBACK_ASCII,
49 MSG_CALLBACK_UNICODE,
50 MSG_OTHER_PROCESS,
51 MSG_POSTED_ASCII,
52 MSG_POSTED_UNICODE
53};
54
55/* structure to group all parameters for sent messages of the various kinds */
56struct send_message_info
57{
58 enum message_type type;
59 HWND hwnd;
60 UINT msg;
61 WPARAM wparam;
62 LPARAM lparam;
63 UINT flags; /* flags for SendMessageTimeout */
64 UINT timeout; /* timeout for SendMessageTimeout */
65 SENDASYNCPROC callback; /* callback function for SendMessageCallback */
66 ULONG_PTR data; /* callback data */
67};
68
69/***********************************************************************
70 * broadcast_message_callback
71 *
72 * Helper callback for broadcasting messages.
73 */
74static BOOL CALLBACK broadcast_message_callback( HWND hwnd, LPARAM lparam )
75{
76 struct send_message_info *info = (struct send_message_info *)lparam;
77 if (!(GetWindowLongW( hwnd, GWL_STYLE ) & (WS_POPUP|WS_CAPTION))) return TRUE;
78 switch(info->type)
79 {
80 case MSG_UNICODE:
81 SendMessageTimeoutW( hwnd, info->msg, info->wparam, info->lparam,
82 info->flags, info->timeout, NULL );
83 break;
84 case MSG_ASCII:
85 SendMessageTimeoutA( hwnd, info->msg, info->wparam, info->lparam,
86 info->flags, info->timeout, NULL );
87 break;
88 case MSG_NOTIFY:
89 SendNotifyMessageW( hwnd, info->msg, info->wparam, info->lparam );
90 break;
91 case MSG_CALLBACK_ASCII:
92 SendMessageCallbackA( hwnd, info->msg, info->wparam, info->lparam,
93 info->callback, info->data );
94 break;
95 case MSG_CALLBACK_UNICODE:
96 SendMessageCallbackW( hwnd, info->msg, info->wparam, info->lparam,
97 info->callback, info->data );
98 break;
99 case MSG_POSTED_ASCII:
100 PostMessageA( hwnd, info->msg, info->wparam, info->lparam );
101 break;
102 case MSG_POSTED_UNICODE:
103 PostMessageW( hwnd, info->msg, info->wparam, info->lparam );
104 break;
105 default:
106 dprintf(("!ERROR!: broadcast_message_callback: bad type %d\n", info->type ));
107 DebugInt3();
108 break;
109 }
110 return TRUE;
111}
112/***********************************************************************
113 * call_window_proc
114 *
115 * Call a window procedure and the corresponding hooks.
116 */
117static LRESULT call_window_proc( HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam, BOOL unicode )
118{
119 LRESULT result;
120 WNDPROC winproc;
121
122 /* first the WH_CALLWNDPROC hook */
123 if (HOOK_IsHooked( WH_CALLWNDPROC ))
124 {
125 CWPSTRUCT cwp;
126 cwp.lParam = lparam;
127 cwp.wParam = wparam;
128 cwp.message = msg;
129 cwp.hwnd = WIN_GetFullHandle( hwnd );
130 if (unicode) HOOK_CallHooksW( WH_CALLWNDPROC, HC_ACTION, 1, (LPARAM)&cwp );
131 else HOOK_CallHooksA( WH_CALLWNDPROC, HC_ACTION, 1, (LPARAM)&cwp );
132 lparam = cwp.lParam;
133 wparam = cwp.wParam;
134 msg = cwp.message;
135 hwnd = cwp.hwnd;
136 }
137
138 /* now call the window procedure */
139 if (unicode)
140 {
141 if (!(winproc = (WNDPROC)GetWindowLongW( hwnd, GWL_WNDPROC ))) return 0;
142 result = CallWindowProcW( winproc, hwnd, msg, wparam, lparam );
143 }
144 else
145 {
146 if (!(winproc = (WNDPROC)GetWindowLongA( hwnd, GWL_WNDPROC ))) return 0;
147 result = CallWindowProcA( winproc, hwnd, msg, wparam, lparam );
148 }
149#ifdef __WIN32OS2__
150 //hittest caching
151 if(msg == WM_NCHITTEST)
152 {
153 Win32BaseWindow *window = Win32BaseWindow::GetWindowFromHandle(hwnd);
154 if(window) {
155 window->setLastHitTestVal(result);
156 RELEASE_WNDOBJ(window);
157 }
158 else DebugInt3();
159 }
160#endif
161
162 /* and finally the WH_CALLWNDPROCRET hook */
163 if (HOOK_IsHooked( WH_CALLWNDPROCRET ))
164 {
165 CWPRETSTRUCT cwp;
166 cwp.lResult = result;
167 cwp.lParam = lparam;
168 cwp.wParam = wparam;
169 cwp.message = msg;
170 cwp.hwnd = WIN_GetFullHandle( hwnd );
171 if (unicode) HOOK_CallHooksW( WH_CALLWNDPROCRET, HC_ACTION, 1, (LPARAM)&cwp );
172 else HOOK_CallHooksA( WH_CALLWNDPROCRET, HC_ACTION, 1, (LPARAM)&cwp );
173 }
174 return result;
175}
176/***********************************************************************
177 * SendMessageTimeoutW (USER32.@)
178 */
179LRESULT WINAPI SendMessageTimeoutW( HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam,
180 UINT flags, UINT timeout, LPDWORD res_ptr )
181{
182 struct send_message_info info;
183 DWORD dest_tid, dest_pid;
184 LRESULT ret, result;
185
186 info.type = MSG_UNICODE;
187 info.hwnd = hwnd;
188 info.msg = msg;
189 info.wparam = wparam;
190 info.lparam = lparam;
191 info.flags = flags;
192 info.timeout = timeout;
193
194 if (is_broadcast(hwnd))
195 {
196 EnumWindows( broadcast_message_callback, (LPARAM)&info );
197 if (res_ptr) *res_ptr = 1;
198 return 1;
199 }
200
201 if (!(dest_tid = GetWindowThreadProcessId( hwnd, &dest_pid ))) return 0;
202
203 if (dest_tid == GetCurrentThreadId())
204 {
205 result = call_window_proc( hwnd, msg, wparam, lparam, TRUE );
206 ret = 1;
207 }
208 else
209 {
210 //otherwise use WinSendMsg to send it to the right process/thread
211 dprintf(("SendMessages (inter-process/thread) %x %x %x %x", Win32ToOS2Handle(hwnd), msg, wparam, lparam));
212 result = OSLibSendMessage(Win32ToOS2Handle(hwnd), msg, wparam, lparam, TRUE);
213 ret = 1;
214 }
215
216 if (ret && res_ptr) *res_ptr = result;
217 return ret;
218}
219
220
221/***********************************************************************
222 * SendMessageTimeoutA (USER32.@)
223 */
224LRESULT WINAPI SendMessageTimeoutA( HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam,
225 UINT flags, UINT timeout, LPDWORD res_ptr )
226{
227 struct send_message_info info;
228 DWORD dest_tid, dest_pid;
229 LRESULT ret, result;
230
231 info.type = MSG_ASCII;
232 info.hwnd = hwnd;
233 info.msg = msg;
234 info.wparam = wparam;
235 info.lparam = lparam;
236 info.flags = flags;
237 info.timeout = timeout;
238
239 if (is_broadcast(hwnd))
240 {
241 EnumWindows( broadcast_message_callback, (LPARAM)&info );
242 if (res_ptr) *res_ptr = 1;
243 return 1;
244 }
245
246 if (!(dest_tid = GetWindowThreadProcessId( hwnd, &dest_pid ))) return 0;
247
248 if (dest_tid == GetCurrentThreadId())
249 {
250 result = call_window_proc( hwnd, msg, wparam, lparam, FALSE );
251 ret = 1;
252 }
253 else
254 {
255 //otherwise use WinSendMsg to send it to the right process/thread
256 dprintf(("SendMessages (inter-process/thread) %x %x %x %x", Win32ToOS2Handle(hwnd), msg, wparam, lparam));
257 result = OSLibSendMessage(Win32ToOS2Handle(hwnd), msg, wparam, lparam, FALSE);
258 ret = 1;
259 }
260 if (ret && res_ptr) *res_ptr = result;
261 return ret;
262}
263//******************************************************************************
264//******************************************************************************
265LRESULT WIN32API SendMessageA(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
266{
267 LRESULT res = 0;
268 DebugPrintMessage(hwnd, msg, wParam, lParam, FALSE, FALSE);
269 SendMessageTimeoutA(hwnd, msg, wParam, lParam, SMTO_NORMAL, INFINITE, (LPDWORD)&res);
270 return res;
271}
272//******************************************************************************
273//******************************************************************************
274LRESULT WIN32API SendMessageW(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
275{
276 LRESULT res = 0;
277 DebugPrintMessage(hwnd, msg, wParam, lParam, TRUE, FALSE);
278 SendMessageTimeoutW(hwnd, msg, wParam, lParam, SMTO_NORMAL, INFINITE, (LPDWORD)&res);
279 return res;
280}
281//******************************************************************************
282//******************************************************************************
283BOOL WIN32API PostMessageA(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
284{
285 Win32BaseWindow *window;
286 HWND hwndOS2;
287
288 struct send_message_info info;
289 DWORD dest_tid;
290
291#if 0
292 if (is_pointer_message( msg ))
293 {
294 SetLastError( ERROR_INVALID_PARAMETER );
295 return FALSE;
296 }
297#endif
298
299 info.type = MSG_POSTED_ASCII;
300 info.hwnd = hwnd;
301 info.msg = msg;
302 info.wparam = wParam;
303 info.lparam = lParam;
304
305 if (is_broadcast(hwnd))
306 {
307 EnumWindows( broadcast_message_callback, (LPARAM)&info );
308 return TRUE;
309 }
310
311 if(hwnd == NULL)
312 return PostThreadMessageA(GetCurrentThreadId(), msg, wParam, lParam);
313
314 window = Win32BaseWindow::GetWindowFromHandle(hwnd);
315 if(!window) {
316 dprintf(("PostMessageA, window %x not found", hwnd));
317 return FALSE;
318 }
319 hwndOS2 = window->getOS2WindowHandle();
320 RELEASE_WNDOBJ(window);
321 DebugPrintMessage(hwnd, msg, wParam, lParam, FALSE, TRUE);
322 return OSLibPostMessage(hwndOS2, msg, wParam, lParam, FALSE);
323}
324//******************************************************************************
325//******************************************************************************
326BOOL WIN32API PostMessageW(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
327{
328 Win32BaseWindow *window;
329 HWND hwndOS2;
330
331 struct send_message_info info;
332 DWORD dest_tid;
333
334 info.type = MSG_POSTED_UNICODE;
335 info.hwnd = hwnd;
336 info.msg = msg;
337 info.wparam = wParam;
338 info.lparam = lParam;
339
340 if (is_broadcast(hwnd))
341 {
342 EnumWindows( broadcast_message_callback, (LPARAM)&info );
343 return TRUE;
344 }
345
346 if(hwnd == NULL)
347 return PostThreadMessageW(GetCurrentThreadId(), msg, wParam, lParam);
348
349 window = Win32BaseWindow::GetWindowFromHandle(hwnd);
350 if(!window) {
351 dprintf(("PostMessageW, window %x not found", hwnd));
352 return FALSE;
353 }
354 hwndOS2 = window->getOS2WindowHandle();
355 RELEASE_WNDOBJ(window);
356 DebugPrintMessage(hwnd, msg, wParam, lParam, TRUE, TRUE);
357 return OSLibPostMessage(hwndOS2, msg, wParam, lParam, TRUE);
358}
359//******************************************************************************
360//******************************************************************************
361BOOL WIN32API PostThreadMessageA( DWORD threadid, UINT msg, WPARAM wParam, LPARAM lParam)
362{
363 return OSLibPostThreadMessage(threadid, msg, wParam, lParam, FALSE);
364}
365//******************************************************************************
366//******************************************************************************
367BOOL WIN32API PostThreadMessageW( DWORD threadid, UINT msg, WPARAM wParam, LPARAM lParam)
368{
369 return OSLibPostThreadMessage(threadid, msg, wParam, lParam, TRUE);
370}
371//******************************************************************************
372//******************************************************************************
373BOOL WIN32API SendNotifyMessageA(HWND hwnd, UINT Msg, WPARAM wParam, LPARAM lParam)
374{
375 DWORD dest_tid;
376
377 dprintf(("USER32: SendNotifyMessageA %x %x %x %x", hwnd, Msg, wParam, lParam));
378
379 if (!(dest_tid = GetWindowThreadProcessId( hwnd, NULL ))) return FALSE;
380
381 if (dest_tid == GetCurrentThreadId())
382 {
383 SendMessageA( hwnd, Msg, wParam, lParam);
384 return TRUE;
385 }
386 //Must not block when window thread != current thread
387 return PostMessageA(hwnd, Msg, wParam, lParam);
388}
389//******************************************************************************
390//******************************************************************************
391BOOL WIN32API SendNotifyMessageW(HWND hwnd, UINT Msg, WPARAM wParam, LPARAM lParam)
392{
393 DWORD dest_tid;
394
395 dprintf(("USER32: SendNotifyMessageW %x %x %x %x", hwnd, Msg, wParam, lParam));
396
397 if (!(dest_tid = GetWindowThreadProcessId( hwnd, NULL ))) return FALSE;
398
399 if (dest_tid == GetCurrentThreadId())
400 {
401 SendMessageW( hwnd, Msg, wParam, lParam);
402 return TRUE;
403 }
404 //Must not block when window thread != current thread
405 return PostMessageW(hwnd, Msg, wParam, lParam);
406}
407/*****************************************************************************
408 * Name : BOOL WIN32API SendMessageCallbackA
409 * Purpose : The SendMessageCallback function sends the specified message to
410 * a window or windows. The function calls the window procedure for
411 * the specified window and returns immediately. After the window
412 * procedure processes the message, the system calls the specified
413 * callback function, passing the result of the message processing
414 * and an application-defined value to the callback function.
415 * Parameters: HWND hwnd handle of destination window
416 * UINT uMsg message to send
417 * WPARAM wParam first message parameter
418 * LPARAM lParam second message parameter
419 * SENDASYNCPROC lpResultCallBack function to receive message value
420 * DWORD dwData value to pass to callback function
421 * Variables :
422 * Result : If the function succeeds, the return value is TRUE.
423 * If the function fails, the return value is FALSE. To get extended
424 * error information, call GetLastError.
425 * Remark :
426 * Status :
427 *
428 * Author : Wine
429 *****************************************************************************/
430
431BOOL WIN32API SendMessageCallbackA(HWND hwnd,
432 UINT uMsg,
433 WPARAM wParam,
434 LPARAM lParam,
435 SENDASYNCPROC lpResultCallBack,
436 DWORD dwData)
437{
438 struct send_message_info info;
439 LRESULT result;
440 DWORD dest_tid;
441
442#if 0
443 if (is_pointer_message(msg))
444 {
445 SetLastError(ERROR_INVALID_PARAMETER);
446 return FALSE;
447 }
448#endif
449
450 dprintf(("USER32:SendMessageCallBackW (%08xh,%08xh,%08xh,%08xh,%08xh,%08x)",
451 hwnd, uMsg, wParam, lParam, lpResultCallBack, dwData));
452
453 info.type = MSG_CALLBACK_ASCII;
454 info.hwnd = hwnd;
455 info.msg = uMsg;
456 info.wparam = wParam;
457 info.lparam = lParam;
458 info.callback = lpResultCallBack;
459 info.data = dwData;
460
461 if (is_broadcast(hwnd))
462 {
463 EnumWindows( broadcast_message_callback, (LPARAM)&info );
464 return TRUE;
465 }
466
467 if (!(dest_tid = GetWindowThreadProcessId( hwnd, NULL ))) return FALSE;
468
469 if (dest_tid == GetCurrentThreadId())
470 {
471 result = call_window_proc( hwnd, uMsg, wParam, lParam, FALSE );
472 lpResultCallBack( hwnd, uMsg, dwData, result );
473 return TRUE;
474 }
475 else
476 {
477 dprintf(("!WARNING!: callback will not be called" ));
478
479 //otherwise use PostMessage to send it to the right process/thread
480 dprintf(("SendMessageCallbackA (inter-process/thread) %x %x %x %x", hwnd, uMsg, wParam, lParam));
481 PostMessageA(hwnd, uMsg, wParam, lParam);
482 return TRUE;
483 }
484}
485
486
487/*****************************************************************************
488 * Name : BOOL WIN32API SendMessageCallbackW
489 * Purpose : The SendMessageCallback function sends the specified message to
490 * a window or windows. The function calls the window procedure for
491 * the specified window and returns immediately. After the window
492 * procedure processes the message, the system calls the specified
493 * callback function, passing the result of the message processing
494 * and an application-defined value to the callback function.
495 * Parameters: HWND hwnd handle of destination window
496 * UINT uMsg message to send
497 * WPARAM wParam first message parameter
498 * LPARAM lParam second message parameter
499 * SENDASYNCPROC lpResultCallBack function to receive message value
500 * DWORD dwData value to pass to callback function
501 * Variables :
502 * Result : If the function succeeds, the return value is TRUE.
503 * If the function fails, the return value is FALSE. To get extended
504 * error information, call GetLastError.
505 * Remark :
506 * Status :
507 *
508 * Author : Wine
509 *****************************************************************************/
510
511BOOL WIN32API SendMessageCallbackW(HWND hwnd,
512 UINT uMsg,
513 WPARAM wParam,
514 LPARAM lParam,
515 SENDASYNCPROC lpResultCallBack,
516 DWORD dwData)
517{
518 struct send_message_info info;
519 LRESULT result;
520 DWORD dest_tid;
521
522#if 0
523 if (is_pointer_message(msg))
524 {
525 SetLastError(ERROR_INVALID_PARAMETER);
526 return FALSE;
527 }
528#endif
529
530 dprintf(("USER32:SendMessageCallBackW (%08xh,%08xh,%08xh,%08xh,%08xh,%08x)",
531 hwnd, uMsg, wParam, lParam, lpResultCallBack, dwData));
532
533 info.type = MSG_CALLBACK_UNICODE;
534 info.hwnd = hwnd;
535 info.msg = uMsg;
536 info.wparam = wParam;
537 info.lparam = lParam;
538 info.callback = lpResultCallBack;
539 info.data = dwData;
540
541 if (is_broadcast(hwnd))
542 {
543 EnumWindows( broadcast_message_callback, (LPARAM)&info );
544 return TRUE;
545 }
546
547 if (!(dest_tid = GetWindowThreadProcessId( hwnd, NULL ))) return FALSE;
548
549 if (dest_tid == GetCurrentThreadId())
550 {
551 result = call_window_proc( hwnd, uMsg, wParam, lParam, TRUE );
552 lpResultCallBack( hwnd, uMsg, dwData, result );
553 return TRUE;
554 }
555 else
556 {
557 dprintf(("!WARNING!: callback will not be called" ));
558
559 //otherwise use PostMessage to send it to the right process/thread
560 dprintf(("SendMessageCallbackW (inter-process/thread) %x %x %x %x", hwnd, uMsg, wParam, lParam));
561 PostMessageW(hwnd, uMsg, wParam, lParam);
562 return TRUE;
563 }
564}
565/*****************************************************************************
566 * Name : long WIN32API BroadcastSystemMessage
567 * Purpose : The BroadcastSystemMessage function sends a message to the given
568 * recipients. The recipients can be applications, installable
569 * drivers, Windows-based network drivers, system-level device
570 * drivers, or any combination of these system components.
571 * Parameters: DWORD dwFlags,
572 LPDWORD lpdwRecipients,
573 UINT uiMessage,
574 WPARAM wParam,
575 LPARAM lParam
576 * Variables :
577 * Result : If the function succeeds, the return value is a positive value.
578 * If the function is unable to broadcast the message, the return value is -1.
579 * If the dwFlags parameter is BSF_QUERY and at least one recipient returned FALSE to the corresponding message, the return value is zero.
580 * Remark :
581 * Status : UNTESTED STUB
582 *
583 * Author : Patrick Haller [Thu, 1998/02/26 11:55]
584 *****************************************************************************/
585
586long WIN32API BroadcastSystemMessage(DWORD dwFlags,
587 LPDWORD lpdwRecipients,
588 UINT uiMessage,
589 WPARAM wParam,
590 LPARAM lParam)
591{
592 dprintf(("USER32:BroadcastSystemMessage(%08xh,%08xh,%08xh,%08xh,%08x) not implemented.\n",
593 dwFlags,
594 lpdwRecipients,
595 uiMessage,
596 wParam,
597 lParam));
598
599 return (-1);
600}
601#if 0
602//******************************************************************************
603//******************************************************************************
604VOID WIN32API PostQuitMessage( int nExitCode)
605{
606 dprintf(("USER32: PostQuitMessage %d", nExitCode));
607 PostThreadMessageW(GetCurrentThreadId(), WM_QUIT, nExitCode, 0);
608}
609//******************************************************************************
610//******************************************************************************
611#endif
Note: See TracBrowser for help on using the repository browser.