Delphi 是什么解释了这种奇怪的消息行为(试图处理完整的消息队列,过滤特定的消息)?

Delphi 是什么解释了这种奇怪的消息行为(试图处理完整的消息队列,过滤特定的消息)?,delphi,winapi,com,message-queue,c++builder,Delphi,Winapi,Com,Message Queue,C++builder,我们的应用程序充当COM服务器,其中所有自动化都发生在单个STA单元中(在应用程序的主线程中),一些进行长时间(>10分钟)调用的VBS脚本失败,错误为“System call failed(80010100)”。一些研究(,)表明,这可能是由于消息队列已满,因此当COM试图调用下一个方法时,它无法调用 如果这很重要的话,该应用程序的开发是基于(大多数情况下,对于一些COM类来说,是少量的) 我想我应该在冗长的COM方法调用结束时(即,就在它返回之前)检查线程的消息队列,通过使用and查看它包含

我们的应用程序充当COM服务器,其中所有自动化都发生在单个STA单元中(在应用程序的主线程中),一些进行长时间(>10分钟)调用的VBS脚本失败,错误为“System call failed(80010100)”。一些研究(,)表明,这可能是由于消息队列已满,因此当COM试图调用下一个方法时,它无法调用

如果这很重要的话,该应用程序的开发是基于(大多数情况下,对于一些COM类来说,是少量的)

我想我应该在冗长的COM方法调用结束时(即,就在它返回之前)检查线程的消息队列,通过使用and查看它包含什么。虽然队列似乎已满,但我看到了一些奇怪的行为,我很难弄清楚
PeekMessage
的行为方式,以及队列已满的确切原因,即队列中充满了什么

前面的解释有些冗长:

测试线程的消息队列已满 代码如下:

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";
  // Do something with strError
}
当运行在一个短COM调用方法的末尾时,可以发布数千条(比如,9996条)消息;在导致脚本失败的冗长方法调用结束时,它可以发布0。我的结论是,消息队列已满确实是问题的原因。我的系统(请参阅备注部分。)

调用
Application->ProcessMessages()
(调用应用程序的消息循环直到其为空,对于不是Delphi/C++Builder用户的用户,这是一个相当正常的“get/translate/dispatch直到不再有消息”方法)解决了问题,COM脚本可以成功调用下一个方法。虽然在这种特定情况下可能没有问题,但在有效的随机点中调用
ProcessMessages()
是需要避免的—它可能会导致重新进入。如果可能的话,我想找出是什么原因导致队列已满

检查消息队列的内容 使用来确定队列中的消息类型表明存在计时器(
QS\u timer
)、已发布消息(
QS\u POSTMESSAGE
)、“所有已发布消息”(即其他已发布消息、
QS\u ALLPOSTMESSAGE
)和绘制消息(
QS\u-paint

这就是奇怪的地方。我正在尝试使用with
PM\u remove
删除选定的消息或消息类型,以部分清空队列并计算每种类型消息的数量

如果我打电话:

while (::PeekMessage(&oMsg, NULL, 0, 0, PM_REMOVE | PM_NOYIELD | (QS_TIMER << 16)) != 0) {...

我收到了大约十条信息,它们都是真正的WM_计时器。为什么?PeekMessage文档表明,传递QS_定时器
GetQueueStatus
()接受
QS_xxx
参数,但
PeekMessage
()只接受
PM_QS_xxx
常量

这解释了由
QueueStatus
指示的
WM_TIMER
消息数量与随后由
peek message
()删除的消息数量之间的差异。您的
peek消息(PM\u REMOVE)
调用并没有删除
WM\u TIMER
消息,而是完全删除其他消息

我认为您误解了
PeekMessage
()的文档<代码>PM_QS_POSTMESSAGE被记录为具有以下同等价值:

((QS_POSTMESSAGE | QS_HOTKEY | QS_TIMER) << 16)

((QS|u POSTMESSAGE | QS|u热键| QS|u计时器)你能冻结所有其他线程,这样当你忙着从另一端数东西的时候,它们就不会把东西从一端抽进来了吗reporting@DavidHeffernan:好主意-结果也很有趣!当我冻结其他邮件时,PeekMessage几乎没有提取任何邮件,而且10000多个WM_APP+202从未出现过d、 当我解冻所有其他线程时,下一个COM调用成功完成(我猜其中一个线程是必须运行才能调用下一个方法的内部COM线程?),但是我们所有的线程(在这个过程中有几个未识别的线程)我们坐在WaitForSingleObject或类似的平台上,没有做任何工作,也绝对没有发送消息。令人困惑。类似的问题由Raymond Chen在中讨论。谢谢@Deltics!这解释了为什么我会收到非定时消息。你必须仔细阅读MSDN,不是吗!对其他三个问题有什么想法吗?它们是最重要的…问题首先是好奇,了解它在做什么。我仍然需要找到一个解决原始问题的好方法:/我认为你的其他三个问题中的第一个是过滤问题。QS_TIMER(续…)至于更广泛的问题,在我看来,您的问题的根本原因是消息队列被填满,这表明它可能不是被消息循环“泵送”的。而不是试图找出一种处理症状的方法(一个完整的消息队列)我会首先调查队列为什么会被填满,然后进行处理(防止问题发生)。这是主线程中的STA方法调用,因此主应用程序消息循环不会运行,队列会随着时间的推移而填满。除非(这是我希望弄清楚的)有人向消息队列发送垃圾消息,因此它的填充速度比正常情况下快。但我得到的奇怪结果(即使在您帮助理解第一项之后)让人有点困惑:/
while (::PeekMessage(&oMsg, NULL, WM_APP+202, WM_APP+202, PM_REMOVE | PM_NOYIELD) != 0) {...
((QS_POSTMESSAGE | QS_HOTKEY | QS_TIMER) << 16)