了解线程问题

本主题介绍用于Microsoft UI 自动化客户端实现的常见线程方案,并说明如何避免在客户端错误地使用线程处理时可能出现的问题。

本主题包含以下各节:

UI 自动化和 UI 线程

由于 UI 自动化使用 Windows 消息的方式,当客户端应用程序尝试在 UI 线程上与自己的 UI 进行交互时,可能发生冲突。 这些冲突可导致执行极其缓慢,或者甚至会导致应用程序停止响应。

如果客户端应用程序旨在与桌面上的所有元素(包括自己的 UI)进行交互,则应在单独线程上进行所有的 UI 自动化调用。 这包括查找元素(例如,通过使用 IUIAutomationTreeWalkerIUIAutomationElement::FindAll 方法)和使用控件模式。 此线程不应拥有任何窗口,并且应该是组件对象模型 (COM) 多线程单元 (MTA) 模型线程(一个通过调用 CoInitializeExCOINIT_MULTITHREADED 标志初始化 COM 的线程)。

在 UI 自动化事件处理程序内执行 UI 自动化调用是安全的,因为事件处理程序始终在非 UI 线程上调用。 但是,在订阅可能源自客户端应用程序 UI 的事件时,必须在非 UI 线程(也应是 MTA 线程)上调用 IUIAutomation::AddAutomationEventHandler 或相关方法。 删除同一线程上的事件处理程序。

UI 自动化客户端不应使用多个线程添加或删除事件处理程序。 如果在同一客户端进程中添加或删除另一个事件处理程序,则意外行为可能会导致另一个事件处理程序被添加或删除。

事件处理程序的线程模型

UI 自动化客户端应对实现事件处理程序的线程使用 COM MTA 线程模型。 使用单线程单元 (STA) 模型可能会引发问题,例如阻止客户端从线程中删除事件处理程序。

64 位 Windows 上的 COM 单元相关性

根据 COM 规范,远程对象的生存期由调用 CoCreateInstance 函数创建对象的单元的生存期控制。 当原始单元关闭时,远程对象也会释放。

对于UI 自动化客户端,此 COM 行为可能意味着由 32 位元素使用的远程 32/64 帮助程序(由 UIAutomationCore.dll 创建)的生存期由创建该元素的线程的单元生存期控制。 如果UI 自动化客户端将元素封送到另一个线程,则当原始单元关闭时,该元素可能会失效。 UI 自动化客户端应在使用封送自动化元素时捕获错误来正常处理这些问题。

对于具有 64 位元素的 32 位UI 自动化客户端,可能会出现相同的问题。

概念:

获取 UI 自动化元素

订阅 UI 自动化事件

UI 自动化事件概述

其他资源:

OLE 线程模型的描述和工作