Our application acts as a COM server, where all automation takes place in one STA apartment (in the main application thread), and some VBS scripts that make long (> 10-minute) calls fail with the error "System call error (80010100) " Some research ( one , two , three ) indicates that this is probably caused by the message queue being full, so when COM tries to call the next method, it cannot.
In case this is important, the application is developed using Embarcadero RAD Studio 2010 (mainly C ++ , smatterings Delphi for some COM classes.)
I thought I would review the thread's message queue at the end of a long COM method call (i.e. before it returns) to see what it contains using GetQueueStatus and PeekMessage . Although it seems that the queue is full, I see some strange behavior, and itโs hard for me to understand why PeekMessage behaves as it is, and thatโs why the queue is full - that is, what it fills.
A slightly long explanation ahead:
Testing thread message queue full
Code like this:
int iMessages = 0; DWORD dwThreadId = GetCurrentThreadId(); while (::PostThreadMessage(dwThreadId, WM_USER, 0, 0)) { iMessages++; } if (GetLastError() == ERROR_NOT_ENOUGH_QUOTA) { String strError = L"Not enough quota, posted " + IntToStr(iMessages) + L" messages";
when launched at the end of a short method called by COM, it can send thousands of messages (say, 9996); at the end of a long method call that causes a script error, it can send a message 0. My conclusion is that the message queue is full really is the cause of the problem. My system has a default message queue limit of 10,000 (see the "Notes" section.)
Calling Application->ProcessMessages() (calls the application message loop until it is empty, for those of you who are not Delphi / C ++ Builder users, this is a pretty normal "get / translate / dispatch", until more messages appear, the "method) solves the problem, and the COM script can successfully invoke the next method. Although it is probably good in this particular situation, calling ProcessMessages() at effectively random points is something that should be avoided - this can lead to re-entry: I would like to know what causes the queue to fill up, if possible.
Examine the contents of the message queue
Using GetQueueStatus to determine which messages are in the queue, shows that there is a timer ( QS_TIMER ), sent messages ( QS_POSTMESSAGE ), "all sent messages" (i.e., others posted, QS_ALLPOSTMESSAGE ) and color messages ( QS_PAINT ).
Here where it gets weird. I am trying to delete selected messages or message types using PeekMessage with PM_REMOVE to both partially remove the queue and count the number of messages of each type.
If I call:
while (::PeekMessage(&oMsg, NULL, 0, 0, PM_REMOVE | PM_NOYIELD | (QS_TIMER << 16)) != 0) {...
I get a little over ten thousand messages, usually 10006 or so. Not all of them are WM_TIMER: several thousand WM_APP + 202, a message that we use internally, which, it seems, is not published (by us) anywhere near such huge quantities. I checked this: it is only sent a few times. There are also several thousand other WM_APP+something messages that we use; this one is probably sent too often.
If I call it:
while (::PeekMessage(&oMsg, NULL, WM_TIMER, WM_TIMER, PM_REMOVE | PM_NOYIELD) != 0) {...
I get about ten messages, all of which are really WM_TIMER. What for? PeekMessage documentation indicates that passing QS_TIMER <16 should only process timer messages, but it generates significantly more messages, many of which are not timers at all.
Finally, if you instead call the third variation:
while (::PeekMessage(&oMsg, NULL, WM_APP+202, WM_APP+202, PM_REMOVE | PM_NOYIELD) != 0) {...
which filters directly for a custom message that the first line of code returns thousands, I get seventeen messages.
I reproduced all this several times - none of them work.
So:
- Why does the first PeekMessage call remove more than just timers (compared to the second call)? Curiosity, really.
- Why does the first PeekMessage call delete several thousand WM_APP + 202 messages (which we define and use and do not send many of them), but if I instead name the third option, which directly filters this message, I get 17?
- If I get such different results for the same message, how do I find out what has filled the queue and what is the best way to avoid it?
- Or, to avoid all of the above: can I completely ignore all this, and then how should I work with a full message queue when COM is going to try to use the method?
I am puzzled and quite able to make an elementary mistake - he went to the stage of considering something puzzling where you do it. Any help for a COM problem or explanation of the behavior of the message will be greatly appreciated, including "You made a basic mistake X, golly, which was stupid with you").