2009-04-19 68 views
11

在Win32 C++应用程序中,我们启动一个消息循环,从队列中提取消息,翻译它们,然后分发它们。最终,每条消息都会到达我们的WndProc,在那里可以处理关联的事件。Win32事件驱动的编程是如何实现的?

我明白那一部分。我不明白的是在两者之间。特别是:

  1. 不同种类的操作系统中断处理程序必须将消息放置在所述的'消息队列'中,但是在该进程地址空间内的这个队列所在的位置?它如何暴露给中断处理程序代码?
  2. “翻译”信息意味着什么?打电话给TranslateMessage()真的有什么用?
  3. 一旦由DispatchMessage()调度,在到达我的WndProc(即操作系统用它做什么)之前,所有地方的消息都会摆动?

如果有人知道上述的答案,请满足我的好奇心。谢谢。

回答

6

操作系统维护一个消息队列,在该消息队列中放置事件(例如来自中断或其他来源)。然后它根据消息将该队列中的消息发送到所有窗口(例如,它不会将密钥消息发送到没有焦点的窗口)。

应用程序可以拥有自己的队列来处理消息。这些队列被创建on request(仅在需要时)。

翻译消息用于创建非“真实”事件的消息。例如,WM_CONTEXTMENU消息由鼠标右键单击或上下文菜单键或shift-F10进行“翻译”。 WM_CHAR从WM_KEYDOWN消息转换而来。当然,还有很多其他的消息是这样翻译的。

消息发布到每个应接收它的窗口。操作系统根据消息的类型决定窗口是否应该接收该消息。大多数消息都由系统等待,即消息不会被发布到另一个窗口,直到它被窗口处理。这对广播消息有很大的影响:如果处理该消息时一个窗口没有返回,则队列为blocked,而其他窗口不再接收消息。

+3

这是错的。只有当问题是关于Win16的时候,那些正确的部分才是正确的,在Win16中,整个操作系统和应用程序在单个线程上被共同操作。 – 2009-08-20 07:55:02

1

不是绝对看好这一点,但我最好的猜测说:

  1. 队列是你与Win32 API调用访问系统对象。它不在你的进程地址空间中。所以中断处理程序可以访问它(可能通过内核的HAL(硬件抽象层))。

  2. 在Win16中,这个调用把一个更大的消息的各个子部分分解成一个整体。所以TranslateMessage会在找到相应的WM_KEYDOWN WM_KEYUP序列时添加WM_KEYPRESS。它还会根据内部设置和消息的时间戳将各种按钮点击消息转变为双击消息。无论它在Win32中仍然如此,我不知道。

  3. DispatchMessage可能是Window消息挂钩处理的地方。所以如果窗口上有一个钩子,它会在这里调用,或者调用GetMessage。我不确定。除此之外,DispatchMessage只是查找与窗口关联的WndProc地址并调用它。没有太多的事情要做。

希望有所帮助。

6

这取决于您的邮件如何发送以及如何处理。

当你调用SendMessage函数,如果目标窗口是由当前线程拥有,呼叫绕过消息队列的窗口和窗口管理器直接调用目标窗口上的WindowProc。如果目标窗口由另一个线程拥有,则窗口管理器有效地调用PostMessage并泵送窗口消息,直到目标窗口从窗口过程返回。

当调用PostMessage的,窗口管理器警消息参数,并插入相应的对象到用于所述目标窗口的消息队列。当它接下来调用GetMessage时,消息将从消息队列中移除。

窗口管理器还注册用于从所述输入装置的原始输入事件(键盘和/或鼠标),并且它对于那些输入事件生成消息。然后,它将这些消息适当插入队列中(输入事件的处理过程很复杂,因为它取决于窗口的消息队列中已存在的消息)。

作为斯蒂芬指出的,刚刚的TranslateMessage平移加速键 - 例如其转换键序列到WM_COMMAND消息。

1

为了解决最后subquestion,已分派消息会去你的WindowProc它已经通过所有的钩子(WH_CALLWNDPROC)

4

不同种类的操作系统中断处理程序的管道后,必须将消息在说:“消息队列',但是这个队列驻留在进程地址空间中的什么地方?它如何暴露给中断处理程序代码?

窗口与线程关联。带窗口的每个线程在进程的地址空间中都有一个线程队列。操作系统在其自己的地址空间中有一个内部队列用于硬件生成的事件。使用事件的细节和其他状态信息(例如,哪个窗口具有焦点),操作系统将硬件事件转换为消息,然后将其置于适当的线程队列中。

发布的消息直接放置在目标窗口的线程队列中。

发送的消息通常直接处理(绕过队列)。

细节变得毛茸茸的。例如,线程队列不仅仅是消息列表 - 它们还保留一些状态信息。某些消息(如WM_PAINT)并未真正排队,但是在查询队列时它是从附加状态信息合成的,并且它是空的。发送到其他线程所拥有的窗口的消息实际上被发送到接收者的队列中,而不是直接处理,但是系统使它看起来像来自呼叫者的观点的常规阻塞发送。如果这可能导致死锁(因为循环发送回原始线程),则会产生欢闹。

杰弗里里希特书有很多(所有?)的血淋淋的细节。我的版本是旧的(高级Windows)。目前的版本似乎被称为Windows via C/C++

操作系统做的工作很多,以便使邮件流出现理性(比较简单)给调用者。

这意味着'翻译'的消息?对TranslateMessage()的调用真的有用吗?

它监视虚拟按键消息,并且当它识别按键/按键组合时,它添加字符消息。如果您不拨打TranslateMessage,则不会收到像WM_CHAR这样的字符消息。

我怀疑它在返回之前直接发送字符消息(而不是发布它们)。我从来没有检查过,但我似乎记得WM_CHAR消息就在WM_KEYUP之前到达。

一旦DispatchMessage()派发,在到达我的WndProc(即操作系统用它做什么)之前,消息摆动的所有地方是什么?

DispatchMessage将消息传递给目标窗口的WndProc。一路上,它的一些钩子可能有机会看到该消息(并可能干扰它)。