2 * Message queues related functions
4 * Copyright 1993, 1994 Alexandre Julliard
15 #define MAX_QUEUE_SIZE 120 /* Max. size of a message queue */
17 static HQUEUE hFirstQueue
= 0;
18 static HQUEUE hmemSysMsgQueue
= 0;
19 static HQUEUE hDoomedQueue
= 0;
20 static MESSAGEQUEUE
*sysMsgQueue
= NULL
;
22 /***********************************************************************
23 * QUEUE_GetDoomedQueue/QUEUE_SetDoomedQueue
25 HQUEUE
QUEUE_GetDoomedQueue()
29 void QUEUE_SetDoomedQueue(HQUEUE hQueue
)
31 hDoomedQueue
= hQueue
;
34 /***********************************************************************
37 void QUEUE_DumpQueue( HQUEUE hQueue
)
41 if (!(pq
= (MESSAGEQUEUE
*) GlobalLock16( hQueue
)) ||
42 GlobalSize16(hQueue
) < sizeof(MESSAGEQUEUE
)+pq
->queueSize
*sizeof(QMSG
))
44 fprintf( stderr
, "%04x is not a queue handle\n", hQueue
);
49 "next: %12.4x Intertask SendMessage:\n"
50 "hTask: %11.4x ----------------------\n"
51 "msgSize: %9.4x hWnd: %10.4x\n"
52 "msgCount: %8.4x msg: %11.4x\n"
53 "msgNext: %9.4x wParam: %8.4x\n"
54 "msgFree: %9.4x lParam: %8.8x\n"
55 "qSize: %11.4x lRet: %10.8x\n"
56 "wWinVer: %9.4x ISMH: %10.4x\n"
57 "paints: %10.4x hSendTask: %5.4x\n"
58 "timers: %10.4x hPrevSend: %5.4x\n"
62 pq
->next
, pq
->hTask
, pq
->msgSize
, pq
->hWnd
,
63 pq
->msgCount
, pq
->msg
, pq
->nextMessage
, pq
->wParam
,
64 pq
->nextFreeMessage
, (unsigned)pq
->lParam
, pq
->queueSize
,
65 (unsigned)pq
->SendMessageReturn
, pq
->wWinVersion
, pq
->InSendMessageHandle
,
66 pq
->wPaintCount
, pq
->hSendingTask
, pq
->wTimerCount
,
67 pq
->hPrevSendingTask
, pq
->wakeBits
, pq
->wakeMask
, pq
->hCurHook
);
71 /***********************************************************************
74 void QUEUE_WalkQueues(void)
76 HQUEUE hQueue
= hFirstQueue
;
78 fprintf( stderr
, "Queue Size Msgs Task\n" );
81 MESSAGEQUEUE
*queue
= (MESSAGEQUEUE
*)GlobalLock16( hQueue
);
84 fprintf( stderr
, "*** Bad queue handle %04x\n", hQueue
);
87 fprintf( stderr
, "%04x %5d %4d %04x %s\n",
88 hQueue
, queue
->msgSize
, queue
->msgCount
, queue
->hTask
,
89 MODULE_GetModuleName( GetExePtr(queue
->hTask
) ) );
92 fprintf( stderr
, "\n" );
96 /***********************************************************************
97 * QUEUE_CreateMsgQueue
99 * Creates a message queue. Doesn't link it into queue list!
101 static HQUEUE
QUEUE_CreateMsgQueue( int size
)
104 MESSAGEQUEUE
* msgQueue
;
106 TDB
*pTask
= (TDB
*)GlobalLock16( GetCurrentTask() );
108 dprintf_msg(stddeb
,"Creating message queue...\n");
110 queueSize
= sizeof(MESSAGEQUEUE
) + size
* sizeof(QMSG
);
111 if (!(hQueue
= GlobalAlloc16( GMEM_FIXED
| GMEM_ZEROINIT
, queueSize
)))
113 msgQueue
= (MESSAGEQUEUE
*) GlobalLock16( hQueue
);
114 msgQueue
->msgSize
= sizeof(QMSG
);
115 msgQueue
->queueSize
= size
;
116 msgQueue
->wWinVersion
= pTask
? pTask
->version
: 0;
117 GlobalUnlock16( hQueue
);
122 /***********************************************************************
123 * QUEUE_DeleteMsgQueue
125 * Unlinks and deletes a message queue.
127 BOOL
QUEUE_DeleteMsgQueue( HQUEUE hQueue
)
129 MESSAGEQUEUE
* msgQueue
= (MESSAGEQUEUE
*)GlobalLock16(hQueue
);
132 dprintf_msg(stddeb
,"Deleting message queue %04x\n", hQueue
);
134 if (!hQueue
|| !msgQueue
)
136 dprintf_msg(stddeb
,"DeleteMsgQueue: invalid argument.\n");
140 pPrev
= &hFirstQueue
;
141 while (*pPrev
&& (*pPrev
!= hQueue
))
143 MESSAGEQUEUE
*msgQ
= (MESSAGEQUEUE
*)GlobalLock16(*pPrev
);
146 if (*pPrev
) *pPrev
= msgQueue
->next
;
147 GlobalFree16( hQueue
);
152 /***********************************************************************
153 * QUEUE_CreateSysMsgQueue
155 * Create the system message queue, and set the double-click speed.
156 * Must be called only once.
158 BOOL
QUEUE_CreateSysMsgQueue( int size
)
160 if (size
> MAX_QUEUE_SIZE
) size
= MAX_QUEUE_SIZE
;
161 else if (size
<= 0) size
= 1;
162 if (!(hmemSysMsgQueue
= QUEUE_CreateMsgQueue( size
))) return FALSE
;
163 sysMsgQueue
= (MESSAGEQUEUE
*) GlobalLock16( hmemSysMsgQueue
);
168 /***********************************************************************
171 MESSAGEQUEUE
*QUEUE_GetSysQueue(void)
177 /***********************************************************************
180 * See "Windows Internals", p.449
182 void QUEUE_SetWakeBit( MESSAGEQUEUE
*queue
, WORD bit
)
184 queue
->changeBits
|= bit
;
185 queue
->wakeBits
|= bit
;
186 if (queue
->wakeMask
& bit
)
189 PostEvent( queue
->hTask
);
194 /***********************************************************************
197 * See "Windows Internals", p.447
199 void QUEUE_WaitBits( WORD bits
)
205 if (!(queue
= (MESSAGEQUEUE
*)GlobalLock16( GetTaskQueue(0) ))) return;
206 if (queue
->changeBits
& bits
)
208 /* One of the bits is set; we can return */
212 if (queue
->wakeBits
& QS_SENDMESSAGE
)
214 /* Process the sent message immediately */
215 QUEUE_ReceiveMessage( queue
);
217 queue
->wakeMask
= bits
| QS_SENDMESSAGE
;
223 /***********************************************************************
224 * QUEUE_ReceiveMessage
226 * This routine is called when a sent message is waiting for the queue.
228 void QUEUE_ReceiveMessage( MESSAGEQUEUE
*queue
)
230 MESSAGEQUEUE
*senderQ
;
237 printf( "ReceiveMessage\n" );
238 if (!(queue
->wakeBits
& QS_SENDMESSAGE
)) return;
239 if (!(senderQ
= (MESSAGEQUEUE
*)GlobalLock16( queue
->hSendingTask
))) return;
241 /* Remove sending queue from the list */
242 queue
->InSendMessageHandle
= queue
->hSendingTask
;
243 queue
->hSendingTask
= senderQ
->hPrevSendingTask
;
244 senderQ
->hPrevSendingTask
= 0;
245 if (!queue
->hSendingTask
) queue
->wakeBits
&= ~QS_SENDMESSAGE
;
247 /* Get the parameters from the sending task */
248 hwnd
= senderQ
->hWnd
;
250 wParam
= senderQ
->wParam
;
251 lParam
= senderQ
->lParam
;
253 QUEUE_SetWakeBit( senderQ
, QS_SMPARAMSFREE
);
255 printf( "ReceiveMessage: calling wnd proc %04x %04x %04x %08x\n",
256 hwnd
, msg
, wParam
, lParam
);
258 /* Call the window procedure */
259 /* FIXME: should we use CallWindowProc here? */
260 if (IsWindow( hwnd
)) result
= SendMessage16( hwnd
, msg
, wParam
, lParam
);
262 printf( "ReceiveMessage: wnd proc %04x %04x %04x %08x ret = %08x\n",
263 hwnd
, msg
, wParam
, lParam
, result
);
265 /* Return the result to the sender task */
266 ReplyMessage( result
);
270 /***********************************************************************
273 * Add a message to the queue. Return FALSE if queue is full.
275 BOOL
QUEUE_AddMsg( HQUEUE hQueue
, MSG
* msg
, DWORD extraInfo
)
278 MESSAGEQUEUE
*msgQueue
;
280 if (!(msgQueue
= (MESSAGEQUEUE
*)GlobalLock16( hQueue
))) return FALSE
;
281 pos
= msgQueue
->nextFreeMessage
;
283 /* Check if queue is full */
284 if ((pos
== msgQueue
->nextMessage
) && (msgQueue
->msgCount
> 0))
286 fprintf(stderr
,"MSG_AddMsg // queue is full !\n");
291 msgQueue
->messages
[pos
].msg
= *msg
;
292 msgQueue
->messages
[pos
].extraInfo
= extraInfo
;
293 if (pos
< msgQueue
->queueSize
-1) pos
++;
295 msgQueue
->nextFreeMessage
= pos
;
296 msgQueue
->msgCount
++;
297 QUEUE_SetWakeBit( msgQueue
, QS_POSTMESSAGE
);
302 /***********************************************************************
305 * Find a message matching the given parameters. Return -1 if none available.
307 int QUEUE_FindMsg( MESSAGEQUEUE
* msgQueue
, HWND hwnd
, int first
, int last
)
309 int i
, pos
= msgQueue
->nextMessage
;
311 dprintf_msg(stddeb
,"QUEUE_FindMsg: hwnd=%04x pos=%d\n", hwnd
, pos
);
313 if (!msgQueue
->msgCount
) return -1;
314 if (!hwnd
&& !first
&& !last
) return pos
;
316 for (i
= 0; i
< msgQueue
->msgCount
; i
++)
318 MSG
* msg
= &msgQueue
->messages
[pos
].msg
;
320 if (!hwnd
|| (msg
->hwnd
== hwnd
))
322 if (!first
&& !last
) return pos
;
323 if ((msg
->message
>= first
) && (msg
->message
<= last
)) return pos
;
325 if (pos
< msgQueue
->queueSize
-1) pos
++;
332 /***********************************************************************
335 * Remove a message from the queue (pos must be a valid position).
337 void QUEUE_RemoveMsg( MESSAGEQUEUE
* msgQueue
, int pos
)
339 if (pos
>= msgQueue
->nextMessage
)
341 for ( ; pos
> msgQueue
->nextMessage
; pos
--)
342 msgQueue
->messages
[pos
] = msgQueue
->messages
[pos
-1];
343 msgQueue
->nextMessage
++;
344 if (msgQueue
->nextMessage
>= msgQueue
->queueSize
)
345 msgQueue
->nextMessage
= 0;
349 for ( ; pos
< msgQueue
->nextFreeMessage
; pos
++)
350 msgQueue
->messages
[pos
] = msgQueue
->messages
[pos
+1];
351 if (msgQueue
->nextFreeMessage
) msgQueue
->nextFreeMessage
--;
352 else msgQueue
->nextFreeMessage
= msgQueue
->queueSize
-1;
354 msgQueue
->msgCount
--;
355 if (!msgQueue
->msgCount
) msgQueue
->wakeBits
&= ~QS_POSTMESSAGE
;
359 /***********************************************************************
362 * Wake a queue upon reception of a hardware event.
364 static void QUEUE_WakeSomeone( UINT message
)
369 MESSAGEQUEUE
*queue
= NULL
;
371 if ((message
>= WM_KEYFIRST
) && (message
<= WM_KEYLAST
)) wakeBit
= QS_KEY
;
372 else wakeBit
= (message
== WM_MOUSEMOVE
) ? QS_MOUSEMOVE
: QS_MOUSEBUTTON
;
374 if (!(hwnd
= GetSysModalWindow()))
376 hwnd
= (wakeBit
== QS_KEY
) ? GetFocus() : GetCapture();
377 if (!hwnd
) hwnd
= GetActiveWindow();
381 WND
*wndPtr
= WIN_FindWndPtr( hwnd
);
382 if (wndPtr
) queue
= (MESSAGEQUEUE
*)GlobalLock16( wndPtr
->hmemTaskQ
);
386 hQueue
= hFirstQueue
;
389 queue
= GlobalLock16( hQueue
);
390 if (queue
->wakeBits
& wakeBit
) break;
391 hQueue
= queue
->next
;
394 if (!queue
) printf( "WakeSomeone: no one found\n" );
395 if (queue
) QUEUE_SetWakeBit( queue
, wakeBit
);
399 /***********************************************************************
402 * Add an event to the system message queue.
403 * Note: the position is relative to the desktop window.
405 void hardware_event( WORD message
, WORD wParam
, LONG lParam
,
406 int xPos
, int yPos
, DWORD time
, DWORD extraInfo
)
411 if (!sysMsgQueue
) return;
412 pos
= sysMsgQueue
->nextFreeMessage
;
414 /* Merge with previous event if possible */
416 if ((message
== WM_MOUSEMOVE
) && sysMsgQueue
->msgCount
)
419 else pos
= sysMsgQueue
->queueSize
- 1;
420 msg
= &sysMsgQueue
->messages
[pos
].msg
;
421 if ((msg
->message
== message
) && (msg
->wParam
== wParam
))
422 sysMsgQueue
->msgCount
--; /* Merge events */
424 pos
= sysMsgQueue
->nextFreeMessage
; /* Don't merge */
427 /* Check if queue is full */
429 if ((pos
== sysMsgQueue
->nextMessage
) && sysMsgQueue
->msgCount
)
431 /* Queue is full, beep (but not on every mouse motion...) */
432 if (message
!= WM_MOUSEMOVE
) MessageBeep(0);
438 msg
= &sysMsgQueue
->messages
[pos
].msg
;
440 msg
->message
= message
;
441 msg
->wParam
= wParam
;
442 msg
->lParam
= lParam
;
444 msg
->pt
.x
= xPos
& 0xffff;
445 msg
->pt
.y
= yPos
& 0xffff;
446 sysMsgQueue
->messages
[pos
].extraInfo
= extraInfo
;
447 if (pos
< sysMsgQueue
->queueSize
- 1) pos
++;
449 sysMsgQueue
->nextFreeMessage
= pos
;
450 sysMsgQueue
->msgCount
++;
451 QUEUE_WakeSomeone( message
);
455 /***********************************************************************
458 HTASK
QUEUE_GetQueueTask( HQUEUE hQueue
)
460 MESSAGEQUEUE
*queue
= GlobalLock16( hQueue
);
461 return (queue
) ? queue
->hTask
: 0 ;
465 /***********************************************************************
466 * QUEUE_IncPaintCount
468 void QUEUE_IncPaintCount( HQUEUE hQueue
)
472 if (!(queue
= (MESSAGEQUEUE
*)GlobalLock16( hQueue
))) return;
473 queue
->wPaintCount
++;
474 QUEUE_SetWakeBit( queue
, QS_PAINT
);
478 /***********************************************************************
479 * QUEUE_DecPaintCount
481 void QUEUE_DecPaintCount( HQUEUE hQueue
)
485 if (!(queue
= (MESSAGEQUEUE
*)GlobalLock16( hQueue
))) return;
486 queue
->wPaintCount
--;
487 if (!queue
->wPaintCount
) queue
->wakeBits
&= ~QS_PAINT
;
491 /***********************************************************************
492 * QUEUE_IncTimerCount
494 void QUEUE_IncTimerCount( HQUEUE hQueue
)
498 if (!(queue
= (MESSAGEQUEUE
*)GlobalLock16( hQueue
))) return;
499 queue
->wTimerCount
++;
500 QUEUE_SetWakeBit( queue
, QS_TIMER
);
504 /***********************************************************************
505 * QUEUE_DecTimerCount
507 void QUEUE_DecTimerCount( HQUEUE hQueue
)
511 if (!(queue
= (MESSAGEQUEUE
*)GlobalLock16( hQueue
))) return;
512 queue
->wTimerCount
--;
513 if (!queue
->wTimerCount
) queue
->wakeBits
&= ~QS_TIMER
;
517 /***********************************************************************
518 * PostQuitMessage (USER.6)
520 void PostQuitMessage( INT exitCode
)
524 if (!(queue
= (MESSAGEQUEUE
*)GlobalLock16( GetTaskQueue(0) ))) return;
525 queue
->wPostQMsg
= TRUE
;
526 queue
->wExitCode
= (WORD
)exitCode
;
530 /***********************************************************************
531 * GetWindowTask (USER.224)
533 HTASK
GetWindowTask( HWND hwnd
)
535 WND
*wndPtr
= WIN_FindWndPtr( hwnd
);
537 if (!wndPtr
) return 0;
538 return QUEUE_GetQueueTask( wndPtr
->hmemTaskQ
);
542 /***********************************************************************
543 * SetMessageQueue (USER.266)
545 BOOL
SetMessageQueue( int size
)
547 HQUEUE hQueue
, hNewQueue
;
548 MESSAGEQUEUE
*queuePtr
;
550 dprintf_msg(stddeb
,"SetMessageQueue: task %04x size %i\n", GetCurrentTask(), size
);
552 if ((size
> MAX_QUEUE_SIZE
) || (size
<= 0)) return TRUE
;
554 if( !(hNewQueue
= QUEUE_CreateMsgQueue( size
)))
556 dprintf_msg(stddeb
,"SetMessageQueue: failed!\n");
560 /* Free the old message queue */
561 if ((hQueue
= GetTaskQueue(0)) != 0) QUEUE_DeleteMsgQueue( hQueue
);
563 /* Link new queue into list */
564 queuePtr
= (MESSAGEQUEUE
*)GlobalLock16( hNewQueue
);
565 queuePtr
->hTask
= GetCurrentTask();
566 queuePtr
->next
= hFirstQueue
;
567 hFirstQueue
= hNewQueue
;
569 SetTaskQueue( 0, hNewQueue
);
574 /***********************************************************************
575 * GetQueueStatus (USER.334)
577 DWORD
GetQueueStatus( UINT flags
)
582 if (!(queue
= (MESSAGEQUEUE
*)GlobalLock16( GetTaskQueue(0) ))) return 0;
583 ret
= MAKELONG( queue
->changeBits
, queue
->wakeBits
);
584 queue
->changeBits
= 0;
585 return ret
& MAKELONG( flags
, flags
);
589 /***********************************************************************
590 * GetInputState (USER.335)
596 if (!(queue
= (MESSAGEQUEUE
*)GlobalLock16( GetTaskQueue(0) ))) return FALSE
;
597 return queue
->wakeBits
& (QS_KEY
| QS_MOUSEBUTTON
);
601 /***********************************************************************
602 * GetMessagePos (USER.119)
604 DWORD
GetMessagePos(void)
608 if (!(queue
= (MESSAGEQUEUE
*)GlobalLock16( GetTaskQueue(0) ))) return 0;
609 return queue
->GetMessagePosVal
;
613 /***********************************************************************
614 * GetMessageTime (USER.120)
616 LONG
GetMessageTime(void)
620 if (!(queue
= (MESSAGEQUEUE
*)GlobalLock16( GetTaskQueue(0) ))) return 0;
621 return queue
->GetMessageTimeVal
;
625 /***********************************************************************
626 * GetMessageExtraInfo (USER.288)
628 LONG
GetMessageExtraInfo(void)
632 if (!(queue
= (MESSAGEQUEUE
*)GlobalLock16( GetTaskQueue(0) ))) return 0;
633 return queue
->GetMessageExtraInfoVal
;