Click here to Skip to main content
15,893,814 members
Please Sign up or sign in to vote.
5.00/5 (1 vote)
See more:
I use the thread message queue as my job queue. So there are all WM_USER messages in the queue, each one represent a job.
And I need to know how many jobs are there waiting in the queue.

Thanks, SAKryukov, I learned something from your reply.
Thanks, Philippe Mori, That's a solution, and I likely choose it.
Posted
Updated 20-Jul-11 4:51am
v5

This is not a simple thing to do. Before doing it you should think if you really need it. Usually you don't need to know how many messages are there in the queue. There is no a completely non-intrusive way to know it — maybe because it is never required; and the code based on this knowledge might be incorrect — all messages should be properly processed.

First, before posing this task, bear in mind that not all messages are queued. There are queued messages and nonqueued messages. See http://msdn.microsoft.com/en-us/library/ms644927%28v=VS.85%29.aspx[^]. The mechanism of using both is kind of very cunning. For example, WM_PAINT message goes outside the queue because it optimizes Invalidate requests: if a windows is fully or partially invalidated, the message data is modified to merge ("OR", theory-set disjunction operation) old and new requests to keep no more than on non-handled WM_PAINT message to avoid excessive re-rendering.

Now, the way to check is there is a message of certain type in the message queue, you can use the API PeekMessage, see the code sample here: http://msdn.microsoft.com/en-us/library/ms644928%28v=VS.85%29.aspx[^], the description of the function here: http://msdn.microsoft.com/en-us/library/ms644943(v=VS.85).aspx[^]. See also the article "Why to use PeekMessage": http://msdn.microsoft.com/en-us/library/ms644928(v=VS.85).aspx#3[^].

Now, the trick is: if you use PeekMessage in the UI thread repeatedly, you will pause processing message during this operation, but it will return the same very message until you break the loop unless you remove the message (see the last parameter of the function). But if you remove the message to get to new message every time and ultimately count them all, you would disrupt the normal message processing!

So, what would be the work-around? You could get all messages from the queue using PeekMessage with remove option, learn the results (count/classify them or whatever) and put all the messages in some internal container. You will need them to stick them back in the queue using PostMessage, see http://msdn.microsoft.com/en-us/library/ms644944%28v=VS.85%29.aspx[^].

I still wonder: why would you need all that?

—SA
 
Share this answer
 
Comments
Espen Harlinn 19-Jul-11 17:11pm    
Good reply, my 5
Sergey Alexandrovich Kryukov 19-Jul-11 17:18pm    
Thank you, Espen.
--SA
Liang HL 19-Jul-11 22:04pm    
Thanks, SAKryukov, I learned something from your reply, but I think they are beyond the right answer.
I really don't think it's a good idea to PEEK them all. There may be new messages coming when you are PEEKING or POSTING.
And PEEK OUT of the queue is not acceptable.
Sergey Alexandrovich Kryukov 19-Jul-11 22:47pm    
I agree with your concerns, but... I will be glad to know that I was wrong and there is another method. I simply looked through all APIs related to messages and did not see anything which would return information on all messages without any intrusive operation. As I say, maybe the reason for that is that it is not really required. Could you explain why would you need it?

And you did not convinced me about "right answer". Not giving you the algorithm you wanted does not mean "wrong answer". This is what it is, as far as I can see.
--SA
Philippe Mori 19-Jul-11 22:19pm    
Uses a separate container (uses thread-safe access) for your job queue. Also post a message. That way, you will be able to manage any pending jobs. If you have a message but the container is empty simply ignore it.
A simple solution is simply to have your own counter. Just increment it when adding a job and decrement it when retriving it.

Consider using function like InterlockedIncrement to ensure that your count is not messed up.
 
Share this answer
 
Comments
Sergey Alexandrovich Kryukov 19-Jul-11 22:55pm    
Philippe, I did not understand you at first but now I see this is a right point. I did not pay attention OP is interested in only WM_USER messages each representing a job, so I was trying to address more general problem that it has to be. OP could increment the shared counter when adding a message and decrement when removing it. In this case, interlocked access is a must. My 5.
--SA
Liang HL 20-Jul-11 0:34am    
Thanks Philippe Mori. I think this may be the only solution.
Although some BAD GUY may post a message without increase the counter. :)
Interlocked is good, I always use it, if possible.

Also to SAKryukov, the message queue is quite efficient, that's why I use it.
Philippe Mori 20-Jul-11 8:19am    
While it is true that a BAD GUY could post without incrementing the counter, a good programmer while define a little function to add a message to its queue: void AddJob(/* parameters for the job */) { } and another function to retreive it. Those functions would handle WPARAM and LPARAM as appropriate. And I an added benefit, it would be much easier to refactor the code if we need to.
At last I found some details of windows kernel implement. And actually windows knows the queue length. What a pity.

Windows XP SP2, the message queue is found at offset 0xD0 of _W32THREAD, and looks like:
typedef struct _MSG_QUEUE 
{
PMSG_QUEUE_ENTRY Head;
PMSG_QUEUE_ENTRY Tail;
unsigned long NumberOfMessages;
} MSG_QUEUE;


Each queue entry, in turn, looks like:

typedef struct _MSG_QUEUE_ENTRY {
PMSG_QUEUE_ENTRY pNext;
PMSG_QUEUE_ENTRY pPrev;
struct _MSG 
{ 
unsigned long hWnd; 
unsigned long ulMsg; 
unsigned long wParam; 
unsigned long lParam; 
unsigned long time; // In milliseconds 
POINT pt; // Mouse cursor position 
unsigned long dwUnknown; 
unsigned long dwExtraInfo; 
} Msg;
} MSG_QUEUE_ENTRY, * PMSG_QUEUE_ENTRY;

So for each thread, we can just start at the head of the queue, and keep following pNext until we get to the end, at which point pNext will be NULL.
 
Share this answer
 
v3

This content, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)



CodeProject, 20 Bay Street, 11th Floor Toronto, Ontario, Canada M5J 2N8 +1 (416) 849-8900