调用同步
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。