source: trunk/src/user32/oslibmsg.cpp@ 21555

Last change on this file since 21555 was 21555, checked in by dmik, 15 years ago

user32: Make GetQueueStatus() return actual message summary in high word instead of the copy of the low word (WinQueryQueueStatus() API provides this functionality according to my tests, despite unclear docs).

File size: 32.8 KB
Line 
1/* $Id: oslibmsg.cpp,v 1.76 2003-08-22 13:16:44 sandervl Exp $ */
2/*
3 * Window message translation functions for OS/2
4 *
5 *
6 * Copyright 1999 Sander van Leeuwen (sandervl@xs4all.nl)
7 *
8 *
9 * Project Odin Software License can be found in LICENSE.TXT
10 *
11 * TODO: Some messages that are sent to the frame window are directly passed on to the client
12 * -> Get/PeekMessage never gets them as we return a dummy message for non-client windows
13 * (i.e. menu WM_COMMAND messages)
14 *
15 * TODO: Filter translation isn't correct! (for posted messages or messages that don't have
16 * a PM version)
17 *
18 * TODO: Flaw in our message handling; we don't handle posted/sent (by the app)
19 * system messages properly if removed from the queue with PeekMessage.
20 * e.g.
21 * PostMessage(WM_KEYDOWN)
22 * PeekMessage(any, PM_NOREMOVE)
23 * ...
24 * PeekMessage(WM_KEYDOWN, WM_KEYDOWN, PM_REMOVE)
25 *
26 * So what we really need is a complete win to os2 message translation
27 * in Post/SendMessage. Quite a lot of work though...
28 *
29 */
30#define INCL_WIN
31#define INCL_PM
32#define INCL_DOSPROCESS
33#define INCL_WINMESSAGEMGR
34#define INCL_DOSSEMAPHORES
35#define INCL_DOSERRORS
36#include <os2wrap.h>
37#include <odinwrap.h>
38#include <string.h>
39#include <misc.h>
40#include "oslibmsg.h"
41#include <winconst.h>
42#include <win32api.h>
43#include <winuser32.h>
44#include "oslibutil.h"
45#include "timer.h"
46#include <thread.h>
47#include <wprocess.h>
48#include <winnls.h>
49#include "pmwindow.h"
50#include "oslibwin.h"
51#include <win\hook.h>
52#include <winscan.h>
53#include <winkeyboard.h>
54#include "user32api.h"
55
56#define DBG_LOCALLOG DBG_oslibmsg
57#include "dbglocal.h"
58
59
60ODINDEBUGCHANNEL(USER32-OSLIBMSG)
61
62
63
64typedef BOOL (EXPENTRY FNTRANS)(MSG *, QMSG *);
65typedef FNTRANS *PFNTRANS;
66
67typedef struct
68{
69 ULONG msgOS2;
70 ULONG msgWin32;
71// PFNTRANS toOS2;
72// PFNTRANS toWIN32;
73} MSGTRANSTAB, *PMSGTRANSTAB;
74
75//NOTE: Must be ordered by win32 message id!!
76MSGTRANSTAB MsgTransTab[] = {
77 WM_NULL, WINWM_NULL,
78 WM_CREATE, WINWM_CREATE,
79 WM_DESTROY, WINWM_DESTROY,
80 WM_MOVE, WINWM_MOVE, //TODO: Sent directly
81 WM_SIZE, WINWM_SIZE, //TODO: Sent directly
82 WM_ACTIVATE, WINWM_ACTIVATE,
83 WM_SETFOCUS, WINWM_SETFOCUS,
84 WM_SETFOCUS, WINWM_KILLFOCUS,
85 WM_ENABLE, WINWM_ENABLE,
86 WM_PAINT, WINWM_PAINT,
87 WM_CLOSE, WINWM_CLOSE,
88 WM_QUIT, WINWM_QUIT,
89 WM_SHOW, WINWM_SHOWWINDOW,
90
91 WM_HITTEST, WINWM_NCHITTEST,
92
93 //todo: not always right if mouse msg turns out to be for the client window
94 WM_MOUSEMOVE, WINWM_NCMOUSEMOVE,
95 WM_BUTTON1DOWN, WINWM_NCLBUTTONDOWN,
96 WM_BUTTON1UP, WINWM_NCLBUTTONUP,
97 WM_BUTTON1DBLCLK, WINWM_NCLBUTTONDBLCLK,
98 WM_BUTTON2DOWN, WINWM_NCRBUTTONDOWN,
99 WM_BUTTON2UP, WINWM_NCRBUTTONUP,
100 WM_BUTTON2DBLCLK, WINWM_NCRBUTTONDBLCLK,
101 WM_BUTTON3DOWN, WINWM_NCMBUTTONDOWN,
102 WM_BUTTON3UP, WINWM_NCMBUTTONUP,
103 WM_BUTTON3DBLCLK, WINWM_NCMBUTTONDBLCLK,
104
105 //TODO: Needs better translation!
106 WM_CHAR, WINWM_KEYDOWN, //WM_KEYFIRST
107 WM_CHAR, WINWM_KEYUP,
108 WM_CHAR, WINWM_CHAR,
109 WM_CHAR, WINWM_DEADCHAR,
110 WM_CHAR, WINWM_SYSKEYDOWN,
111 WM_CHAR, WINWM_SYSKEYUP,
112 WM_CHAR, WINWM_SYSCHAR,
113 WM_CHAR, WINWM_SYSDEADCHAR,
114 WM_CHAR, WINWM_KEYLAST,
115
116 //
117 WM_TIMER, WINWM_TIMER,
118
119 //
120 //todo: not always right if mouse msg turns out to be for the nonclient window
121 WM_MOUSEMOVE, WINWM_MOUSEMOVE, //WM_MOUSEFIRST
122 WM_BUTTON1DOWN, WINWM_LBUTTONDOWN,
123 WM_BUTTON1UP, WINWM_LBUTTONUP,
124 WM_BUTTON1DBLCLK, WINWM_LBUTTONDBLCLK,
125 WM_BUTTON2DOWN, WINWM_RBUTTONDOWN,
126 WM_BUTTON2UP, WINWM_RBUTTONUP,
127 WM_BUTTON2DBLCLK, WINWM_RBUTTONDBLCLK,
128 WM_BUTTON3DOWN, WINWM_MBUTTONDOWN,
129 WM_BUTTON3UP, WINWM_MBUTTONUP,
130 WM_BUTTON3DBLCLK, WINWM_MBUTTONDBLCLK,
131 WM_VSCROLL, WINWM_MOUSEWHEEL, //WM_MOUSELAST
132 999999999, 999999999,
133};
134#define MAX_MSGTRANSTAB (sizeof(MsgTransTab)/sizeof(MsgTransTab[0]))
135
136//******************************************************************************
137//******************************************************************************
138void WinToOS2MsgTranslate(MSG *winMsg, QMSG *os2Msg, BOOL isUnicode)
139{
140 dprintf(("WinToOS2MsgTranslate not implemented"));
141// memcpy(os2Msg, winMsg, sizeof(MSG));
142// os2Msg->hwnd = Win32ToOS2Handle(winMsg->hwnd);
143// os2Msg->reserved = 0;
144}
145//******************************************************************************
146//TODO: NOT COMPLETE nor 100% CORRECT!!!
147//If both the minimum & maximum message are unknown, the result can be wrong (max > min)!
148//******************************************************************************
149ULONG TranslateWinMsg(ULONG msg, BOOL fMinFilter, BOOL fExactMatch = FALSE)
150{
151 if(msg == 0)
152 return 0;
153
154 if(msg >= WINWM_USER)
155 return msg + WIN32APP_POSTMSG;
156
157 for(int i=0;i<MAX_MSGTRANSTAB;i++)
158 {
159 if(fExactMatch) {
160 if(MsgTransTab[i].msgWin32 == msg)
161 return MsgTransTab[i].msgOS2;
162 }
163 else {
164 if(fMinFilter && MsgTransTab[i].msgWin32 >= msg) {
165 return MsgTransTab[i].msgOS2;
166 }
167 else
168 if(!fMinFilter && MsgTransTab[i].msgWin32 >= msg) {
169 if(MsgTransTab[i].msgWin32 == msg)
170 return MsgTransTab[i].msgOS2;
171 else return MsgTransTab[i-1].msgOS2;
172 }
173 }
174 }
175
176 //not found, get everything
177 dprintf2(("WARNING: TranslateWinMsg: message %x not found", msg));
178 return 0;
179}
180//******************************************************************************
181//******************************************************************************
182void OSLibWinPostQuitMessage(ULONG nExitCode)
183{
184 APIRET rc;
185
186 //NOTE: mp2 must always be zero or else we won't be able to distinguish
187 // between the WM_QUIT sent by us and the one sent by the window list!!
188 rc = WinPostQueueMsg(NULLHANDLE, WM_QUIT, MPFROMLONG(nExitCode), 0);
189 dprintf(("WinPostQueueMsg %d returned %d", nExitCode, rc));
190}
191//******************************************************************************
192//******************************************************************************
193LONG OSLibWinDispatchMsg(MSG *msg, BOOL isUnicode)
194{
195 TEB *teb;
196 QMSG os2msg;
197 LONG rc;
198
199 teb = GetThreadTEB();
200 if(teb == NULL) {
201 DebugInt3();
202 return FALSE;
203 }
204
205 //TODO: What to do if app changed msg? (translate)
206 // WinToOS2MsgTranslate(msg, &qmsg, isUnicode);
207
208 if(!memcmp(msg, &teb->o.odin.winmsg, sizeof(MSG)) || msg->hwnd == 0) {
209 memcpy(&os2msg, &teb->o.odin.os2msg, sizeof(QMSG));
210 teb->o.odin.os2msg.time = -1;
211 teb->o.odin.winmsg.time = -1;
212 if(msg->hwnd) {
213 teb->o.odin.nrOfMsgs = 1;
214 teb->o.odin.msgstate++; //odd -> next call to our PM window handler should dispatch the translated msg
215 memcpy(&teb->o.odin.msg, msg, sizeof(MSG));
216 }
217 if(os2msg.hwnd || os2msg.msg == WM_QUIT) {
218 memset(&teb->o.odin.os2msg, 0, sizeof(teb->o.odin.os2msg));
219 memset(&teb->o.odin.winmsg, 0, sizeof(teb->o.odin.winmsg));
220 return (LONG)WinDispatchMsg(teb->o.odin.hab, &os2msg);
221 }
222 //SvL: Don't dispatch messages sent by PostThreadMessage (correct??)
223 // Or WM_TIMER msgs with no window handle or timer proc
224 return 0;
225
226 }
227 else {//is this allowed?
228// dprintf(("WARNING: OSLibWinDispatchMsg: called with own message!"));
229 return isUnicode ? SendMessageW(msg->hwnd, msg->message, msg->wParam, msg->lParam) :
230 SendMessageA(msg->hwnd, msg->message, msg->wParam, msg->lParam);
231 }
232}
233//******************************************************************************
234// ReturnQueuedWMCHAR:
235//
236// Check for a queued WM_CHAR message (e.g. inserted by TranslateMessage)
237//******************************************************************************
238BOOL ReturnQueuedWMCHAR(LPMSG pMsg, TEB *teb, HWND hwnd, UINT uMsgFilterMin, UINT uMsgFilterMax,
239 BOOL isUnicode, BOOL fRemove)
240{
241 if(teb->o.odin.fTranslated && (!hwnd || hwnd == teb->o.odin.msgWCHAR.hwnd))
242 {
243 dprintf(("Return queued WM_CHAR message hwnd=%x msg=%d wParam=%x lParam=%x", teb->o.odin.msgWCHAR.hwnd, teb->o.odin.msgWCHAR.message, teb->o.odin.msgWCHAR.wParam, teb->o.odin.msgWCHAR.lParam));
244
245 if(uMsgFilterMin) {
246 if(teb->o.odin.msgWCHAR.message < uMsgFilterMin)
247 return FALSE;
248 }
249 if(uMsgFilterMax) {
250 if(teb->o.odin.msgWCHAR.message > uMsgFilterMax)
251 return FALSE;
252 }
253
254 if(fRemove & PM_REMOVE_W) {
255 teb->o.odin.fTranslated = FALSE;
256 teb->o.odin.os2msg.msg = 0;
257 teb->o.odin.os2msg.hwnd = 0;
258 }
259 memcpy(pMsg, &teb->o.odin.msgWCHAR, sizeof(MSG));
260 //After SetFocus(0), all keystrokes are converted in WM_SYS*
261 if(pMsg->message == WINWM_CHAR && fIgnoreKeystrokes) {
262 pMsg->message = WINWM_SYSCHAR;
263 }
264
265 if(!IsWindow(pMsg->hwnd)) {
266 //could be a queued char message for a window that was just destroyed
267 //when that's the case, we ignore it (MFC assertions are triggered by this)
268 teb->o.odin.fTranslated = FALSE;
269 teb->o.odin.os2msg.msg = 0;
270 teb->o.odin.os2msg.hwnd = 0;
271 return FALSE;
272 }
273
274 // @@@PH verify this
275 // if this is a keyup or keydown message, we've got to
276 // call the keyboard hook here
277 // send keyboard messages to the registered hooks
278 if(fRemove & PM_REMOVE_W)
279 {
280 switch (pMsg->message)
281 {
282 case WINWM_KEYDOWN:
283 case WINWM_KEYUP:
284 case WINWM_SYSKEYDOWN:
285 case WINWM_SYSKEYUP:
286 // only supposed to be called upon WM_KEYDOWN
287 // and WM_KEYUP according to docs.
288 if(ProcessKbdHook(pMsg, fRemove))
289 return FALSE;
290 break;
291 }
292 }
293
294 //GetMessageW and PeekMessageW expect the character code in UTF-16
295 //(we save it in ascii format)
296 if(isUnicode && (pMsg->message == WINWM_CHAR || pMsg->message == WINWM_SYSCHAR))
297 {
298 CHAR charA;
299 WCHAR charW;
300
301 charA = pMsg->wParam;
302 MultiByteToWideChar(CP_ACP, 0, &charA, 1, &charW, 1);
303 pMsg->wParam= charW;
304 dprintf(("ReturnQueuedWMCHAR: Convert to Unicode src=%x res=%x", charA, charW));
305 }
306 return TRUE;
307 }
308 return FALSE;
309}
310//******************************************************************************
311//******************************************************************************
312BOOL OSLibWinGetMsg(LPMSG pMsg, HWND hwnd, UINT uMsgFilterMin, UINT uMsgFilterMax,
313 BOOL isUnicode)
314{
315 BOOL rc, eaten;
316 TEB *teb;
317 QMSG os2msg;
318 HWND hwndOS2 = 0;
319 ULONG filtermin, filtermax;
320
321 if(hwnd) {
322 hwndOS2 = Win32ToOS2Handle(hwnd);
323 if(hwndOS2 == NULL) {
324 memset(pMsg, 0, sizeof(MSG));
325 dprintf(("GetMsg: window %x NOT FOUND!", hwnd));
326 SetLastError(ERROR_INVALID_WINDOW_HANDLE_W);
327 return TRUE;
328 }
329 }
330
331 teb = GetThreadTEB();
332 if(teb == NULL) {
333 DebugInt3();
334 return TRUE;
335 }
336
337 //check for a queued WM_CHAR message (e.g. inserted by TranslateMessage)
338 if(ReturnQueuedWMCHAR(pMsg, teb, hwnd, uMsgFilterMin, uMsgFilterMax, isUnicode, PM_REMOVE_W) == TRUE)
339 {
340 return (pMsg->message != WINWM_QUIT);
341 }
342
343continuegetmsg:
344 if(hwnd) {
345 filtermin = TranslateWinMsg(uMsgFilterMin, TRUE);
346 filtermax = TranslateWinMsg(uMsgFilterMax, FALSE);
347 if(filtermin > filtermax) {
348 ULONG tmp = filtermin;
349 filtermin = filtermax;
350 filtermax = tmp;
351 }
352 do {
353 WinWaitMsg(teb->o.odin.hab, filtermin, filtermax);
354 rc = OSLibWinPeekMsg(pMsg, hwnd, uMsgFilterMin, uMsgFilterMax, PM_REMOVE_W, isUnicode);
355 }
356 while(rc == FALSE);
357
358 return (pMsg->message != WINWM_QUIT);
359 }
360 else
361 {
362 filtermin = TranslateWinMsg(uMsgFilterMin, TRUE);
363 filtermax = TranslateWinMsg(uMsgFilterMax, FALSE);
364 if(filtermin > filtermax) {
365 ULONG tmp = filtermin;
366 filtermin = filtermax;
367 filtermax = filtermin;
368 }
369 rc = WinGetMsg(teb->o.odin.hab, &os2msg, 0, filtermin, filtermax);
370 if (os2msg.msg == WM_QUIT && ((ULONG)os2msg.mp2 != 0) ) {
371 // Don't return FALSE when the window list sends us
372 // a WM_QUIT message, improper killing can lead to
373 // application crashes.
374 // In the WM_QUIT handler in pmwindow we send a WM_CLOSE
375 // in this case. When the app calls PostQuitMessage (mp2 == 0),
376 // then we handle it the normal way
377 rc = 1;
378 }
379 }
380 if(OS2ToWinMsgTranslate((PVOID)teb, &os2msg, pMsg, isUnicode, MSG_REMOVE) == FALSE) {
381 //dispatch untranslated message immediately
382 WinDispatchMsg(teb->o.odin.hab, &os2msg);
383 //and get the next one
384 return OSLibWinGetMsg(pMsg, hwnd, uMsgFilterMin, uMsgFilterMax, isUnicode);
385 }
386
387 memcpy(&teb->o.odin.os2msg, &os2msg, sizeof(QMSG));
388 memcpy(&teb->o.odin.winmsg, pMsg, sizeof(MSG));
389
390 // send keyboard messages to the registered hooks
391 switch (pMsg->message)
392 {
393 case WINWM_KEYDOWN:
394 case WINWM_KEYUP:
395 case WINWM_SYSKEYDOWN:
396 case WINWM_SYSKEYUP:
397 // only supposed to be called upon WM_KEYDOWN
398 // and WM_KEYUP according to docs.
399 dprintf(("OSLibWinGetMsg: ProcessKbdHook call"));
400 if(ProcessKbdHook(pMsg, TRUE))
401 goto continuegetmsg;
402 break;
403 case WINWM_IME_CHAR:
404 // prevent from calling wrong DispatchMsg() (DBCS generated WM_CHAR)
405 memset( &teb->o.odin.winmsg, 0, sizeof( MSG ));
406 break;
407 }
408 return rc;
409}
410
411
412//******************************************************************************
413//PeekMessage retrieves only messages associated with the window identified by the
414//hwnd parameter or any of its children as specified by the IsChild function, and within
415//the range of message values given by the uMsgFilterMin and uMsgFilterMax
416//parameters. If hwnd is NULL, PeekMessage retrieves messages for any window that
417//belongs to the current thread making the call. (PeekMessage does not retrieve
418//messages for windows that belong to other threads.) If hwnd is -1, PeekMessage only
419//returns messages with a hwnd value of NULL, as posted by the PostAppMessage
420//function. If uMsgFilterMin and uMsgFilterMax are both zero, PeekMessage returns all
421//available messages (no range filtering is performed).
422//TODO: Not working as specified right now!
423//******************************************************************************
424BOOL OSLibWinPeekMsg(LPMSG pMsg, HWND hwnd, UINT uMsgFilterMin, UINT uMsgFilterMax,
425 DWORD fRemove, BOOL isUnicode)
426{
427 BOOL rc, eaten;
428 TEB *teb;
429 QMSG os2msg;
430 HWND hwndOS2 = 0;
431
432 if(uMsgFilterMin > uMsgFilterMax) {
433 //TODO: is this correct behaviour?
434 dprintf(("!ERROR!: invalid message filter range!!!"));
435 SetLastError(ERROR_INVALID_PARAMETER_W);
436 return FALSE;
437 }
438 if(hwnd && hwnd != -1) {
439 hwndOS2 = Win32ToOS2Handle(hwnd);
440 if(hwndOS2 == NULL) {
441 dprintf(("PeekMsg: window %x NOT FOUND!", hwnd));
442 SetLastError(ERROR_INVALID_WINDOW_HANDLE_W);
443 return FALSE;
444 }
445 }
446
447 teb = GetThreadTEB();
448 if(teb == NULL) {
449 DebugInt3();
450 return FALSE;
451 }
452
453 //check for a queued WM_CHAR message (e.g. inserted by TranslateMessage)
454 if(ReturnQueuedWMCHAR(pMsg, teb, hwnd, uMsgFilterMin, uMsgFilterMax, isUnicode, fRemove) == TRUE)
455 {
456 return TRUE;
457 }
458
459continuepeekmsg:
460 if(uMsgFilterMin && uMsgFilterMax)
461 { //we can't use the PM message filter (since the message nrs aren't similar), so we must
462 //filter each message seperately
463 //to do so, we will translate each win32 message in the filter range and call WinPeekMsg
464 ULONG ulPMFilter;
465
466 for(int i=0;i<uMsgFilterMax-uMsgFilterMin+1;i++)
467 {
468 rc = 0;
469
470 ulPMFilter = TranslateWinMsg(uMsgFilterMin+i, TRUE, TRUE);
471 if(ulPMFilter) {
472 rc = WinPeekMsg(teb->o.odin.hab, &os2msg, hwndOS2, ulPMFilter, ulPMFilter,
473 (fRemove & PM_REMOVE_W) ? PM_REMOVE : PM_NOREMOVE);
474 //Sadly indeed WinPeekMsg sometimes does not filter well!
475 if (rc && (os2msg.msg != ulPMFilter)) {// drop this message
476 dprintf(("WARNING: WinPeekMsg returns %x even though we filter for %x", os2msg.msg, ulPMFilter));
477 rc = 0;
478 }
479 }
480 if(rc) {
481 break;
482 }
483 }
484 }
485 else {
486 rc = WinPeekMsg(teb->o.odin.hab, &os2msg, hwndOS2, 0, 0, (fRemove & PM_REMOVE_W) ? PM_REMOVE : PM_NOREMOVE);
487 }
488 if(rc == FALSE) {
489 return FALSE;
490 }
491
492 // @@@PH
493 // warning - OS2ToWinMsgTranslate might insert additional messages
494 // into the queue
495 if(OS2ToWinMsgTranslate((PVOID)teb, &os2msg, pMsg, isUnicode, (fRemove & PM_REMOVE_W) ? MSG_REMOVE : MSG_NOREMOVE) == FALSE)
496 {
497 //unused PM message; dispatch immediately and grab next one
498 dprintf2(("OSLibWinPeekMsg: Untranslated message; dispatched immediately"));
499 if(!(fRemove & PM_REMOVE_W)) {
500 rc = WinPeekMsg(teb->o.odin.hab, &os2msg, os2msg.hwnd, os2msg.msg,
501 os2msg.msg, PM_REMOVE);
502 }
503 WinDispatchMsg(teb->o.odin.hab, &os2msg);
504 return OSLibWinPeekMsg(pMsg, hwnd, uMsgFilterMin, uMsgFilterMax, fRemove, isUnicode);
505 }
506 //TODO: This is not safe! There's no guarantee this message will be dispatched and it might overwrite a previous message
507 if(fRemove & PM_REMOVE_W) {
508 memcpy(&teb->o.odin.os2msg, &os2msg, sizeof(QMSG));
509 memcpy(&teb->o.odin.winmsg, pMsg, sizeof(MSG));
510 }
511
512 // send keyboard messages to the registered hooks
513 if(fRemove & PM_REMOVE_W) {
514 switch (pMsg->message)
515 {
516 case WINWM_KEYDOWN:
517 case WINWM_KEYUP:
518 case WINWM_SYSKEYDOWN:
519 case WINWM_SYSKEYUP:
520 // only supposed to be called upon WM_KEYDOWN
521 // and WM_KEYUP according to docs.
522 dprintf(("OSLibWinPeekMsg: ProcessKbdHook call"));
523 if(ProcessKbdHook(pMsg, fRemove))
524 goto continuepeekmsg;
525 break;
526 case WINWM_IME_CHAR:
527 // prevent from calling wrong DispatchMsg() (DBCS generated WM_CHAR)
528 memset( &teb->o.odin.winmsg, 0, sizeof( MSG ));
529 break;
530 }
531 }
532
533 return rc;
534}
535//******************************************************************************
536//******************************************************************************
537ULONG OSLibWinQueryMsgTime()
538{
539 return WinQueryMsgTime(GetThreadHAB());
540}
541//******************************************************************************
542//******************************************************************************
543BOOL OSLibWinWaitMessage()
544{
545 return WinWaitMsg(GetThreadHAB(), 0, 0);
546}
547//******************************************************************************
548//TODO: QS_HOTKEY
549//******************************************************************************
550ULONG OSLibWinQueryQueueStatus()
551{
552 ULONG statusOS2, statusWin32 = 0;
553
554 statusOS2 = WinQueryQueueStatus(HWND_DESKTOP);
555
556 // convert the flags since last call (low word)
557
558 if(statusOS2 & QS_KEY)
559 statusWin32 |= QS_KEY_W;
560 if(statusOS2 & QS_MOUSEBUTTON)
561 statusWin32 |= QS_MOUSEBUTTON_W;
562 if(statusOS2 & QS_MOUSEMOVE)
563 statusWin32 |= QS_MOUSEMOVE_W;
564 if(statusOS2 & QS_TIMER)
565 statusWin32 |= QS_TIMER_W;
566 if(statusOS2 & QS_PAINT)
567 statusWin32 |= QS_PAINT_W;
568 if(statusOS2 & QS_POSTMSG)
569 statusWin32 |= QS_POSTMESSAGE_W;
570 if(statusOS2 & QS_SENDMSG)
571 statusWin32 |= QS_SENDMESSAGE_W;
572
573 // convert the summary flags (high word)
574
575 statusOS2 >>= 16;
576
577 if(statusOS2 & QS_KEY)
578 statusWin32 |= QS_KEY_W << 16;
579 if(statusOS2 & QS_MOUSEBUTTON)
580 statusWin32 |= QS_MOUSEBUTTON_W << 16;
581 if(statusOS2 & QS_MOUSEMOVE)
582 statusWin32 |= QS_MOUSEMOVE_W << 16;
583 if(statusOS2 & QS_TIMER)
584 statusWin32 |= QS_TIMER_W << 16;
585 if(statusOS2 & QS_PAINT)
586 statusWin32 |= QS_PAINT_W << 16;
587 if(statusOS2 & QS_POSTMSG)
588 statusWin32 |= QS_POSTMESSAGE_W << 16;
589 if(statusOS2 & QS_SENDMSG)
590 statusWin32 |= QS_SENDMESSAGE_W << 16;
591
592 return statusWin32;
593}
594//******************************************************************************
595//******************************************************************************
596BOOL OSLibWinInSendMessage()
597{
598 return WinInSendMsg(GetThreadHAB());
599}
600//******************************************************************************
601//******************************************************************************
602DWORD OSLibWinGetMessagePos()
603{
604 APIRET rc;
605 POINTL ptl;
606
607 rc = WinQueryMsgPos(GetThreadHAB(), &ptl);
608 if(!rc) {
609 return 0;
610 }
611 //convert to windows coordinates
612 return MAKEULONG(ptl.x,mapScreenY(ptl.y));
613}
614//******************************************************************************
615//******************************************************************************
616LONG OSLibWinGetMessageTime()
617{
618 return (LONG)WinQueryMsgTime(GetThreadHAB());
619}
620//******************************************************************************
621//******************************************************************************
622BOOL OSLibWinReplyMessage(ULONG result)
623{
624 return (BOOL)WinReplyMsg( NULLHANDLE, NULLHANDLE, HMQ_CURRENT, (MRESULT)result);
625}
626
627//******************************************************************************
628
629/**
630 * Send and Post message helper for packing down interprocess and interthread messages.
631 *
632 * @returns Pointer to packet on success. (shared memory)
633 * @returns NULL on failure with SendMessage return code suggestion in *pRc if pRc is set.
634 * @param hwndOdin Odin window handle. (NULL allowed)
635 * @param hwndOS2 OS/2 window handle.
636 * @param msg Message id.
637 * @param wParam Message param.
638 * @param lParam Message param.
639 * @param fUnicode Unicode or ansi indicator.
640 * @param pRc Where to store SendMessage return code. Optional.
641 * @author knut st. osmundsen<bird@anduin.net>
642 */
643void * OSLibPackMessage(HWND hwndOdin, HWND hwndOS2, ULONG msg, ULONG wParam, ULONG lParam, BOOL fUnicode, PULONG pRc)
644{
645 POSTMSG_PACKET * pMsgPacket;
646
647 /*
648 * Pack message by id.
649 */
650 switch (msg)
651 {
652 /*
653 * lParam = PCOPYDATASTRUCT.
654 * Must move this to shared memory together with any
655 * data it's pointing at.
656 *
657 * We put everything into the package that might ease cleanup...
658 * WARNING! Currently there are cleanup hacks which works with acrobat.
659 */
660 case WINWM_COPYDATA:
661 {
662 PCOPYDATASTRUCT_W pOrg = (PCOPYDATASTRUCT_W)lParam;
663 dprintf(("user32::oslibmsg::OSLibPackMessage - WM_COPYDATA: lParam=%#x dwData=%#x cbData=%d lpData=%#x",
664 pOrg, pOrg ? pOrg->dwData : -1, pOrg ? pOrg->cbData : -1, pOrg ? pOrg->lpData : (LPVOID)-1));
665
666 /*
667 * Calc packet size.
668 */
669 unsigned cb = sizeof(POSTMSG_PACKET);
670 if (pOrg)
671 {
672 cb += sizeof(COPYDATASTRUCT_W);
673 if (pOrg->lpData && pOrg->cbData)
674 cb += 16 + pOrg->cbData; //add 16 Bytes for safty and alignment.
675 }
676
677 /*
678 * Allocate packet.
679 */
680 pMsgPacket = (POSTMSG_PACKET *)_smalloc(cb);
681 if (!pMsgPacket)
682 {
683 dprintf(("user32::oslibmsg::OSLibPackMessage - WM_COPYDATA: failed to allocate %d shared bytes for packing", cb));
684 DebugInt3();
685 if (pRc)
686 *pRc = FALSE;
687 //@todo figure out which error to set. This is plain guesswork!
688 SetLastError(ERROR_NOT_ENOUGH_MEMORY_W);
689 break;
690 }
691
692 /*
693 * Initialize packet.
694 */
695 PCOPYDATASTRUCT_W pNew = (PCOPYDATASTRUCT_W)(pMsgPacket + 1);
696 pMsgPacket->wParam = wParam;
697 pMsgPacket->lParam = (LPARAM)pNew;
698 *pNew = *pOrg;
699 if (pNew->cbData && pNew->lpData)
700 {
701 pNew->lpData = (LPVOID)(((unsigned)(pNew + 1) + 15) & ~15); //16byte align for safty.
702 //@todo what about a safe_memcpy?
703 memcpy(pNew->lpData, pOrg->lpData, pNew->cbData);
704 }
705
706 /* done! */
707 dprintf(("user32::oslibmsg::OSLibPackMessage - WM_COPYDATA: Packed down %d bytes at %#x (pMsgPacket)",
708 cb, pMsgPacket));
709 break;
710 }
711
712
713 /*
714 * Default packing
715 */
716 default:
717 {
718 ULONG pid;
719
720 GetWindowThreadProcessId(hwndOdin, &pid);
721
722 //use shared or local memory depending on the target window
723 //(sfree can be used for any heap)
724 if(pid != GetCurrentProcessId()) {
725 pMsgPacket = (POSTMSG_PACKET *)_smalloc(sizeof(POSTMSG_PACKET));
726 }
727 else pMsgPacket = (POSTMSG_PACKET *)malloc(sizeof(POSTMSG_PACKET));
728
729 if (!pMsgPacket)
730 {
731 dprintf(("user32::oslibmsg::OSLibPackMessage - allocated packet structure is NULL"));
732 if (pRc)
733 { // Can't find any better return code than 0 :/
734 *pRc = 0;
735 }
736 DebugInt3();
737 break;
738 }
739 pMsgPacket->wParam = wParam;
740 pMsgPacket->lParam = lParam;
741 }
742
743 }
744
745 return pMsgPacket;
746}
747
748
749/**
750 * Send an inter thread/proces message.
751 *
752 * @returns
753 * @param hwndWin32 Odin window handle.
754 * @param hwndOS2 OS/2 window handle
755 * @param msg Odin message id.
756 * @param wParam Message param.
757 * @param lParam Message param.
758 * @param fUnicode Unicode indicator.
759 */
760ULONG OSLibSendMessage(HWND hwndWin32, HWND hwndOS2, ULONG msg, ULONG wParam, ULONG lParam, BOOL fUnicode)
761{
762 ULONG rc; /* return code on packing failure */
763 void * pvMsgPacket; /* packed message (shared memory) */
764
765 if(GetDesktopWindow() == hwndWin32) {
766 dprintf(("Ignore messages sent to the desktop window"));
767 return TRUE;
768 }
769
770 /*
771 * Call message packer.
772 */
773 pvMsgPacket = OSLibPackMessage(hwndWin32, hwndOS2, msg, wParam, lParam, fUnicode, &rc);
774 if (!pvMsgPacket)
775 {
776 dprintf(("user32::oslibmsg::OSLibSendMessage - Failed to pack message !!"));
777 DebugInt3();
778 return rc;
779 }
780
781 return (ULONG)WinSendMsg(hwndOS2, WIN32APP_POSTMSG+msg, (MPARAM)((fUnicode) ? WIN32MSG_MAGICW : WIN32MSG_MAGICA), pvMsgPacket);
782}
783//******************************************************************************
784//******************************************************************************
785BOOL OSLibSendWinMessage(HWND hwnd, ULONG winmsg, ULONG extra /*= 0*/)
786{
787 if (winmsg == WINWM_MOUSEWHEEL)
788 {
789 return (BOOL)WinSendMsg(Win32ToOS2Handle(hwnd), TranslateWinMsg(winmsg, TRUE),
790 0, MPFROM2SHORT(0, extra < 0 ? SB_LINEDOWN : SB_LINEUP));
791 }
792 return (BOOL)WinSendMsg(Win32ToOS2Handle(hwnd), TranslateWinMsg(winmsg, TRUE), 0, 0);
793}
794//******************************************************************************
795//******************************************************************************
796ULONG OSLibWinBroadcastMsg(ULONG msg, ULONG wParam, ULONG lParam, BOOL fSend)
797{
798 #ifdef DEBUG
799 if (msg == WINWM_COPYDATA)
800 {
801 dprintf(("user32::oslibmsg::OSLibWinBroadcastMsg - WM_COPYDATA will not work outside this process !!!"));
802 DebugInt3();
803 }
804 #endif
805 return WinBroadcastMsg(HWND_DESKTOP, WIN32APP_POSTMSG+msg, (MPARAM)wParam, (MPARAM)lParam,
806 (fSend) ? BMSG_SEND : BMSG_POST);
807}
808
809
810/**
811 * Post a message.
812 *
813 * @returns Success indicator.
814 *
815 * @param hwndWin32 Odin window handle.
816 * @param hwndOS2 OS/2 window handle
817 * @param msg Odin message id.
818 * @param wParam Message param.
819 * @param lParam Message param.
820 * @param fUnicode Unicode indicator.
821 */
822BOOL OSLibPostMessage(HWND hwndWin32, HWND hwndOS2, ULONG msg, ULONG wParam, ULONG lParam, BOOL fUnicode)
823{
824 void * pvMsgPacket; /* packed message (shared memory) */
825
826 if(GetDesktopWindow() == hwndWin32) {
827 dprintf(("Ignore messages posted to the desktop window"));
828 return TRUE;
829 }
830
831 /*
832 * Call message packer.
833 */
834 pvMsgPacket = OSLibPackMessage(hwndWin32, hwndOS2, msg, wParam, lParam, fUnicode, NULL);
835 if (!pvMsgPacket)
836 {
837 dprintf(("user32::oslibmsg::OSLibPostMessage - Failed to pack message !!"));
838 DebugInt3();
839 return FALSE;
840 }
841
842 /*
843 * Post the message.
844 * Signal the receiver for if it's doing MsgWaitForMultipleObjects() at the time.
845 */
846 TEB *teb = GetTEBFromThreadId(GetWindowThreadProcessId(hwndWin32, NULL));
847 BOOL ret = WinPostMsg(hwndOS2,
848 WIN32APP_POSTMSG+msg,
849 (MPARAM)((fUnicode) ? WIN32MSG_MAGICW : WIN32MSG_MAGICA),
850 pvMsgPacket);
851 if (teb && (teb->o.odin.dwWakeMask & QS_POSTMESSAGE_W))
852 {
853 //thread is blocked in MsgWaitForMultipleObjects waiting for
854 //posted messages
855 dprintf(("PostMessage: Wake up thread %x which is blocked in MsgWaitForMultipleObjects", teb->o.odin.threadId));
856 SetEvent(teb->o.odin.hPostMsgEvent);
857 }
858 return ret;
859}
860//******************************************************************************
861//Direct posting of messages that must remain invisible to the win32 app
862//******************************************************************************
863BOOL OSLibPostMessageDirect(HWND hwnd, ULONG msg, ULONG wParam, ULONG lParam)
864{
865 return WinPostMsg(hwnd, msg, (MPARAM)wParam, (MPARAM)lParam);
866}
867//******************************************************************************
868//******************************************************************************
869BOOL OSLibPostThreadMessage(ULONG threadid, UINT msg, WPARAM wParam, LPARAM lParam, BOOL fUnicode)
870{
871 TEB *teb = GetTEBFromThreadId(threadid);
872 POSTMSG_PACKET *packet = (POSTMSG_PACKET *)_smalloc(sizeof(POSTMSG_PACKET));
873 BOOL ret;
874
875 if (NULL == packet)
876 {
877 dprintf(("user32::oslibmsg::OSLibPostMessage - allocated packet structure is NULL"));
878
879 DebugInt3();
880 // PH: we can provide a correct returncode
881 return FALSE;
882 }
883
884 if(teb == NULL) {
885 dprintf(("OSLibPostThreadMessage: thread %x not found!", threadid));
886 return FALSE;
887 }
888 dprintf(("PostThreadMessageA %x %x %x %x -> hmq %x", threadid, msg, wParam, lParam, teb->o.odin.hmq));
889 packet->wParam = wParam;
890 packet->lParam = lParam;
891
892 ret = WinPostQueueMsg((HMQ)teb->o.odin.hmq, WIN32APP_POSTMSG+msg,
893 (MPARAM)((fUnicode) ? WIN32MSG_MAGICW : WIN32MSG_MAGICA),
894 (MPARAM)packet);
895
896 if(ret == FALSE)
897 {
898 SetLastError(ERROR_INVALID_PARAMETER_W);
899 return FALSE;
900 }
901
902 if(teb->o.odin.dwWakeMask & QS_POSTMESSAGE_W) {
903 //thread is blocked in MsgWaitForMultipleObjects waiting for
904 //posted messages
905 dprintf(("PostMessage: Wake up thread %x which is blocked in MsgWaitForMultipleObjects", teb->o.odin.threadId));
906 SetEvent(teb->o.odin.hPostMsgEvent);
907 }
908
909 SetLastError(ERROR_SUCCESS_W);
910 return TRUE;
911}
912//******************************************************************************
913//******************************************************************************
914DWORD GetThreadMessageExtraInfo()
915{
916 TEB *teb;
917
918 teb = GetThreadTEB();
919 if(teb)
920 {
921 return teb->o.odin.dwMsgExtraInfo;
922 }
923 dprintf(("GetThreadMessageExtraInfo: teb == NULL!!"));
924 return 0;
925}
926//******************************************************************************
927//******************************************************************************
928DWORD SetThreadMessageExtraInfo(DWORD lParam)
929{
930 TEB *teb;
931
932 teb = GetThreadTEB();
933 if(teb)
934 {
935 teb->o.odin.dwMsgExtraInfo = lParam;
936 }
937 else dprintf(("SetThreadMessageExtraInfo: teb == NULL!!"));
938 return 0;
939}
940//******************************************************************************
941//******************************************************************************
Note: See TracBrowser for help on using the repository browser.