Skip to content

Commit 2a20df3

Browse files
authored
Merge e3c0a75 into 8b1b943
2 parents 8b1b943 + e3c0a75 commit 2a20df3

2 files changed

Lines changed: 78 additions & 62 deletions

File tree

nvdaHelper/remote/IA2Support.cpp

Lines changed: 66 additions & 60 deletions
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,6 @@ This license can be found at:
2626
#include "dllmain.h"
2727
#include "inProcess.h"
2828
#include <remote/nvdaInProcUtils.h>
29-
#include "COMProxyRegistration.h"
3029
#include "IA2Support.h"
3130
#include <atlcomcli.h>
3231
#include "textFromIAccessible.h"
@@ -38,71 +37,77 @@ using namespace std;
3837
// Used in isSuspendableProcess.
3938
LONG WINAPI GetCurrentApplicationUserModelId(UINT32* pBufSize,PWSTR buf);
4039

41-
bool isIA2Installed=FALSE;
42-
COMProxyRegistration_t* IA2ProxyRegistration;
43-
COMProxyRegistration_t* ISimpleDOMProxyRegistration;
44-
HANDLE IA2UIThreadHandle=NULL;
45-
DWORD IA2UIThreadID=0;
46-
HANDLE IA2UIThreadUninstalledEvent=NULL;
47-
UINT wm_uninstallIA2Support=0;
48-
bool isIA2Initialized=FALSE;
40+
41+
UINT wm_uninstallIA2Support = RegisterWindowMessage(L"wm_uninstallIA2Support");
4942
bool isIA2SupportDisabled=false;
5043

51-
bool installIA2Support() {
52-
if(isIA2Installed) return FALSE;
44+
map<DWORD, IA2InstallData> IA2InstallMap;
45+
46+
pair<map<DWORD, IA2InstallData>::iterator, bool> installIA2Support(DWORD threadID) {
47+
if (IA2InstallMap.find(threadID) != IA2InstallMap.end()) {
48+
return {IA2InstallMap.end(), false};
49+
}
5350
APTTYPE appType;
5451
APTTYPEQUALIFIER aptQualifier;
5552
HRESULT res;
5653
if((res=CoGetApartmentType(&appType,&aptQualifier))!=S_OK) {
5754
if(res!=CO_E_NOTINITIALIZED) {
5855
LOG_ERROR(L"Error getting apartment type, code "<<res);
5956
}
60-
return false;
57+
return {IA2InstallMap.end(), false};
6158
}
62-
IA2ProxyRegistration=registerCOMProxy(L"IAccessible2Proxy.dll");
63-
if(!IA2ProxyRegistration) {
64-
LOG_ERROR(L"Error registering IAccessible2 proxy");
59+
IA2InstallData data{};
60+
data.IA2ProxyRegistration = registerCOMProxy(L"IAccessible2Proxy.dll");
61+
if (!data.IA2ProxyRegistration) {
62+
LOG_ERROR(L"Error registering IAccessible2 proxy for thread " << threadID);
6563
}
66-
ISimpleDOMProxyRegistration=registerCOMProxy(L"ISimpleDOM.dll");
67-
if(!ISimpleDOMProxyRegistration) {
68-
LOG_ERROR(L"Error registering ISimpleDOM proxy");
64+
data.ISimpleDOMProxyRegistration = registerCOMProxy(L"ISimpleDOM.dll");
65+
if (!data.ISimpleDOMProxyRegistration) {
66+
LOG_ERROR(L"Error registering ISimpleDOM proxy for thread " << threadID);
6967
}
70-
isIA2Installed=TRUE;
71-
return isIA2Installed;
68+
return IA2InstallMap.insert(make_pair(threadID, data));
7269
}
7370

74-
bool uninstallIA2Support() {
75-
if(!isIA2Installed) return false;
76-
if(ISimpleDOMProxyRegistration&&!unregisterCOMProxy(ISimpleDOMProxyRegistration)) {
77-
LOG_ERROR(L"Error unregistering ISimpleDOM proxy");
71+
bool uninstallIA2Support(DWORD threadID) {
72+
auto it = IA2InstallMap.find(threadID);
73+
if (it == IA2InstallMap.end()) {
74+
return false;
75+
}
76+
auto& data = it->second;
77+
if (data.ISimpleDOMProxyRegistration && !unregisterCOMProxy(data.ISimpleDOMProxyRegistration)) {
78+
LOG_ERROR(L"Error unregistering ISimpleDOM proxy for thread " << threadID);
7879
} else {
79-
ISimpleDOMProxyRegistration=nullptr;
80+
data.ISimpleDOMProxyRegistration = nullptr;
8081
}
81-
if(IA2ProxyRegistration&&!unregisterCOMProxy(IA2ProxyRegistration)) {
82-
LOG_ERROR(L"Error unregistering IAccessible2 proxy");
82+
if (data.IA2ProxyRegistration && !unregisterCOMProxy(data.IA2ProxyRegistration)) {
83+
LOG_ERROR(L"Error unregistering IAccessible2 proxy for thread " << threadID);
8384
} else {
84-
IA2ProxyRegistration=nullptr;
85+
data.IA2ProxyRegistration = nullptr;
8586
}
86-
isIA2Installed=FALSE;
87-
return TRUE;
87+
return true;
8888
}
8989

9090
void CALLBACK IA2Support_winEventProcHook(HWINEVENTHOOK hookID, DWORD eventID, HWND hwnd, long objectID, long childID, DWORD threadID, DWORD time) {
91-
if (eventID != EVENT_SYSTEM_FOREGROUND && eventID != EVENT_OBJECT_FOCUS)
91+
if (eventID != EVENT_SYSTEM_FOREGROUND && eventID != EVENT_OBJECT_FOCUS) {
9292
return;
93-
if (installIA2Support()) {
94-
IA2UIThreadHandle=OpenThread(SYNCHRONIZE,false,threadID);
95-
IA2UIThreadID=threadID;
96-
// IA2 support successfully installed, so this hook isn't needed anymore.
97-
unregisterWinEventHook(IA2Support_winEventProcHook);
93+
}
94+
auto installRes = installIA2Support(threadID);
95+
if (installRes.second) {
96+
auto& data = installRes.first->second;
97+
data.uiThreadHandle = OpenThread(SYNCHRONIZE, false, threadID);
9898
}
9999
}
100100

101101
LRESULT CALLBACK IA2Support_uninstallerHook(int code, WPARAM wParam, LPARAM lParam) {
102102
MSG* pmsg=(MSG*)lParam;
103103
if(pmsg->message==wm_uninstallIA2Support) {
104-
uninstallIA2Support();
105-
SetEvent(IA2UIThreadUninstalledEvent);
104+
auto threadId = GetCurrentThreadId();
105+
uninstallIA2Support(threadId);
106+
auto it = IA2InstallMap.find(threadId);
107+
if (it != IA2InstallMap.end()) {
108+
auto& data = it->second;
109+
SetEvent(data.uiThreadUninstalledEvent);
110+
}
106111
}
107112
return 0;
108113
}
@@ -146,8 +151,9 @@ bool isAppContainerProcess() {
146151
}
147152

148153
void IA2Support_inProcess_initialize() {
149-
if (isIA2Installed||isIA2SupportDisabled)
154+
if (IA2InstallMap.size() > 0 || isIA2SupportDisabled) {
150155
return;
156+
}
151157
// #5417: disable IAccessible2 support for suspendable processes to work around a deadlock in NVDAHelperRemote (specifically seen in Win10 searchUI)
152158
isIA2SupportDisabled = isSuspendableProcess();
153159
if(isIA2SupportDisabled) {
@@ -162,37 +168,37 @@ void IA2Support_inProcess_initialize() {
162168
return;
163169
}
164170
// Try to install IA2 support on focus/foreground changes.
165-
// This hook will be unregistered by the callback once IA2 support is successfully installed.
166171
registerWinEventHook(IA2Support_winEventProcHook);
167172
}
168173

169174
void IA2Support_inProcess_terminate() {
170175
// This will do nothing if the hook isn't registered.
171176
unregisterWinEventHook(IA2Support_winEventProcHook);
172-
if(!isIA2Installed||!IA2UIThreadHandle) {
173-
return;
174-
}
175-
//Check if the UI thread is still alive, if not there's nothing for us to do
176-
if(WaitForSingleObject(IA2UIThreadHandle,0)==0) {
177-
return;
178-
}
179-
//Instruct the UI thread to uninstall IA2
180-
IA2UIThreadUninstalledEvent = CreateEvent(NULL, true, false, NULL);
181-
if (IA2UIThreadUninstalledEvent == 0){
182-
// unable to create the event, can't continue
177+
if (IA2InstallMap.size() == 0) {
183178
return;
184179
}
185-
registerWindowsHook(WH_GETMESSAGE,IA2Support_uninstallerHook);
186-
wm_uninstallIA2Support=RegisterWindowMessage(L"wm_uninstallIA2Support");
187-
PostThreadMessage(IA2UIThreadID,wm_uninstallIA2Support,0,0);
188-
HANDLE waitHandles[2]={IA2UIThreadUninstalledEvent,IA2UIThreadHandle};
189-
int res=WaitForMultipleObjects(2,waitHandles,false,10000);
190-
if(res!=WAIT_OBJECT_0&&res!=WAIT_OBJECT_0+1) {
191-
LOG_DEBUGWARNING(L"WaitForMultipleObjects returned "<<res);
180+
registerWindowsHook(WH_GETMESSAGE, IA2Support_uninstallerHook);
181+
for (auto& [threadId, data] : IA2InstallMap) {
182+
//Check if the UI thread is still alive, if not there's nothing for us to do
183+
if (WaitForSingleObject(data.uiThreadHandle, 0) == 0) {
184+
continue;
185+
}
186+
//Instruct the UI thread to uninstall IA2
187+
data.uiThreadUninstalledEvent = CreateEvent(NULL, true, false, NULL);
188+
if (data.uiThreadUninstalledEvent == 0) {
189+
// unable to create the event, can't continue
190+
continue;
191+
}
192+
PostThreadMessage(threadId, wm_uninstallIA2Support, 0, 0);
193+
HANDLE waitHandles[2] = {data.uiThreadUninstalledEvent, data.uiThreadHandle};
194+
int res = WaitForMultipleObjects(2, waitHandles, false, 10000);
195+
if (res != WAIT_OBJECT_0 && res != WAIT_OBJECT_0 + 1) {
196+
LOG_DEBUGWARNING(L"WaitForMultipleObjects returned "<<res);
197+
}
198+
CloseHandle(data.uiThreadUninstalledEvent);
199+
CloseHandle(data.uiThreadHandle);
192200
}
193201
unregisterWindowsHook(WH_GETMESSAGE,IA2Support_uninstallerHook);
194-
CloseHandle(IA2UIThreadUninstalledEvent);
195-
CloseHandle(IA2UIThreadHandle);
196202
}
197203

198204
const long FINDCONTENTDESCENDANT_FIRST=0;

nvdaHelper/remote/IA2Support.h

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -18,8 +18,18 @@ This license can be found at:
1818
#ifndef IA2SUPPORT_H
1919
#define IA2SUPPORT_H
2020

21-
bool installIA2Support();
22-
bool uninstallIA2Support();
21+
#include <map>
22+
#include "COMProxyRegistration.h"
23+
24+
struct IA2InstallData {
25+
COMProxyRegistration_t* IA2ProxyRegistration;
26+
COMProxyRegistration_t* ISimpleDOMProxyRegistration;
27+
HANDLE uiThreadHandle;
28+
HANDLE uiThreadUninstalledEvent;
29+
};
30+
31+
std::pair<std::map<DWORD, IA2InstallData>::iterator, bool> installIA2Support(DWORD threadID);
32+
bool uninstallIA2Support(DWORD threadID);
2333

2434
//Private functions
2535
void IA2Support_inProcess_initialize();

0 commit comments

Comments
 (0)