c++ - 如何在线程之间传递 IUIAutomationElement

标签 c++ multithreading microsoft-ui-automation node-addon-api

我正在用 C++ 编写一个 Node.js 原生插件(使用 node-addon-api )来与 Microsofts UIAutomation API 交互.我正在尝试收听焦点事件,包装 IUIAutomationElement这导致了事件并将包装的元素传递给javascript。
我可以附加一个成功接收焦点事件和 IUIAutomationElement 的事件监听器(按照 Handling Focus Events 的示例) .但是,所有 UIAutomation 事件监听器都在单独的线程中运行

It is safe to make UI Automation calls in a UI Automation event handler, because the event handler is always called on a non-UI thread. (see: https://docs.microsoft.com/en-us/windows/win32/winauto/uiauto-threading).


例如,这里我将 lambda 函数传递给 IUIAutomation::AddFocusChangedEventHandler 周围的包装器。方法。
this->automation_->SubscribeToFocusChange([callback, this](IUIAutomationElement* el){
    // This code here runs in a non-main thread
    // It gets the correct IUIAutomationElemenet
}
为了通过IUIAutomationElement回到 Javascript 我需要将它传递给主线程。 node-addon-api提供Napi::ThreadSafeFunction这意味着在线程之间传递变量。
Napi::ThreadSafeFunction callback = Napi::ThreadSafeFunction::New(
    env, 
    info[0].As<Napi::Function>(),
    "Callback",
    0,
    1
);

this->automation_->SubscribeToFocusChange([callback, this](IUIAutomationElement* el){
    // Code running in non-main thread
    // el works here 
    callback.BlockingCall(el, [this](Napi::Env env, Napi::Function jsCallback, IUIAutomationElement* passedEl){
       // Code running in main thread
       // passedEl should be the same as el
    }
}
注意:这里info[0]是表示 Javascript 函数的函数参数。
问题是,虽然 el有效,任何功能现在都可以在 passedEl 上运行抛出异常。
例如:
BSTR elControlType;
BSTR passedElcontrolType;

// Following works perfectly
HRESULT hr = this->el->get_CurrentLocalizedControlType(&controlType);

// This throws an exception and stops the program
HRESULT hr = this->passedEl->get_CurrentLocalizedControlType(&controlType);
我试过的
  • ElpassedEl有相同的内存地址,所以我相信 IUIAutomationElement非主线程停止时失效。
  • callback.NonBlockingCall与其他变量完美配合( intstring ,自定义类)

  • 我的问题是传递 IUIAutomationElement 的正确方法是什么?线程之间?
    根据我的阅读,我需要阻止微软在非主线程停止时回收对象。我相信要做到这一点,我需要获取并存储对该对象的引用,但没有找到任何有关如何操作的文档。

    最佳答案

    为了来自 IUIAutomation API 的实例要跨线程传递,您需要保持强引用。 IUIAutomationElement基于 IUnknown所以这可以使用 IUnknown::AddRef 来完成(https://docs.microsoft.com/en-us/windows/win32/api/unknwn/nf-unknwn-iunknown-addref)。
    这添加了对引用计数的引用,这意味着一旦创建它的线程停止并因此停止持有它,该对象就不会失效。
    最终释放对象及其内存也很重要,这可以通过 IUnknown::Release 来完成。 (https://docs.microsoft.com/en-us/windows/win32/api/unknwn/nf-unknwn-iunknown-release)。
    这可以通过制作像 这样的包装器来概括。 std::shared_ptr 这将有助于管理引用,但是我无法弄清楚如何做到这一点。
    TL;DR: 创建 IUIAutomationElement 的线程拥有该对象及其内存。为了将它传递给另一个线程,您需要增加引用计数,否则线程一旦停止就会释放对象/内存。

    关于c++ - 如何在线程之间传递 IUIAutomationElement,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/64644006/

    相关文章:

    c++ - 在 Visual Studio、C++ 中调试时设置默认线程

    c++ - fork() 后子进程中处理 std::thread 终止的正确方法

    c# - UI 自动化是否有任何依赖项?

    c# - 如何使用 Microsoft UI Automation 从 Point 获取文本值?

    c++ - Clang++ 编译器 - python 的模拟

    c++ - 为什么 _beginthread 返回错误 ENOMEM

    iphone - Objective C - 多线程问题

    c# - Windows UIAutomation 获取文件类型

    c++ - 将 Qt 5.3 应用程序移动到 Qt 5.5,10k+ 警告,PRAGMA, '-Winconsistent-missing-override'

    c++ - 为什么模板类的内联静态变量未初始化?