调用同步
在处理来自 COM 或操作系统的一个或多个调用时,COM 应用程序必须能够正确处理用户输入。 COM 仅为单线程单元提供调用同步。 多线程单元(包含自由线程线程)在进行调用时(在同一线程上)不会接收调用。 多线程单元无法进行输入同步调用。 多线程单元中的异步调用将转换为同步调用。 对于多线程单元中的任何线程,不调用消息筛选器。 有关线程问题的详细信息,请参阅进程、线程和单元。
进程之间的 COM 调用分为三个类别,具体如下:
-
同步调用
-
COM 中发生的大多数通信都是同步的。 进行同步调用时,调用方会等待回复,然后再继续,并可以在等待时接收传入消息。 COM 进入模式循环来等待回复,从而以受控方式接收和调度其他消息。
-
异步通知
-
发送异步通知时,调用方不会等待回复。 COM 使用 PostMessage 或高级事件发送异步通知,具体取决于平台。 COM 定义 IAdviseSink 的五种异步方法:
注意
COM 正在处理异步调用时,无法进行同步调用。 例如,容器应用程序的 OnDataChange 实现不能包含对 IPersistStorage::Save 的调用。 这些调用是 COM 支持的唯一异步调用。 目前无法创建异步自定义接口。
-
输入同步调用
-
进行输入同步调用时,调用的对象必须在生成控件之前完成调用。 这有助于确保焦点管理正常工作,并适当处理用户输入的数据。 COM 通过 SendMessage 函数进行这些调用,无需进入模式循环。 处理输入同步调用时,调用的对象不得调用任何可能产生控件的函数或方法(包括同步方法)。 以下方法为输入同步方法
- IOleWindow::GetWindow
- IOleInPlaceActiveObject::OnFrameWindowActivate
- IOleInPlaceActiveObject::OnDocWindowActivate
- IOleInPlaceActiveObject::ResizeBorder
- IOleInPlaceUIWindow::GetBorder
- IOleInPlaceUIWindow::RequestBorderSpace
- IOleInPlaceUIWindow::SetBorderSpace
- IOleInPlaceFrame::SetMenu
- IOleInPlaceFrame::SetStatusText
- IOleInPlaceObject::SetObjectRects
为了最大程度地减少异步消息处理可能出现的问题,大多数 COM 方法调用都是同步调用。 使用同步通信,无需特殊代码即可调度和处理传入消息。 当应用程序进行同步方法调用时,COM 将进入模式等待循环,用于处理所需的回复并将传入消息调度给能够处理这些消息的应用程序。
COM 通过分配名为逻辑线程 ID 的标识符来管理方法调用。 当用户选择菜单命令或应用程序启动新的 COM 操作时,会分配一个新命令。 与初始 COM 调用相关的后续调用分配有与初始调用相同的逻辑线程 ID。