如何解决如何在线程之间传递IUIAutomationElement
我正在用C ++(使用node-addon-api)编写一个Node.js本机插件,以与Microsofts UIAutomation API进行交互。我正在尝试收听Focus Events,包装引起事件的iuiAutomationElement
并将包装的元素传递给javascript。
我可以附加一个事件侦听器(在此示例后为 Handling Focus Events ),该侦听器可以成功接收焦点事件和iuiAutomationElement
。但是,所有UIAutomation事件侦听器都在单独的线程中运行
在UI自动化事件处理程序中进行UI自动化调用是安全的,因为始终在非UI线程上调用事件处理程序。 (请参阅: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",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);
我尝试过的事情
-
El
和passedEl
具有相同的内存地址,因此我相信在非主线程停止时iuiAutomationElement
无效。 -
callback.NonBlockingCall
与其他变量(int
,string
,自定义类)完美配合
我的问题是在线程之间传递iuiAutomationElement
的正确方法是什么?
根据我所读的内容,我需要阻止Microsoft在非主线程停止时回收该对象。我相信要做到这一点,我需要获取并存储对该对象的引用,但是没有找到有关该对象的任何文档。
解决方法
为了使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
的线程拥有该对象及其内存。为了将其传递给另一个线程,您需要增加引用计数,否则线程将在停止时释放对象/内存。
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。