2
//Copyright (c) 2007 Michael Curran <mick@kulgan.net>
3
//This file is covered by the GNU General Public Licence
4
//See the file Copying for details.
2
This file is a part of the NVDA project.
3
URL: http://www.nvda-project.org/
4
Copyright 2006-2010 NVDA contributers.
5
This program is free software: you can redistribute it and/or modify
6
it under the terms of the GNU General Public License version 2.0, as published by
7
the Free Software Foundation.
8
This program is distributed in the hope that it will be useful,
9
but WITHOUT ANY WARRANTY; without even the implied warranty of
10
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
11
This license can be found at:
12
http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
17
#define WIN32_LEAN_AND_MEAN
9
18
#include <windows.h>
10
19
#include <objbase.h>
21
#include "nvdaControllerInternal.h"
12
23
#include "nvdaHelperRemote.h"
13
25
#include "IA2Support.h"
15
27
typedef ULONG(*LPFNDLLCANUNLOADNOW)();
36
50
#define IAccessible2ProxyIID IID_IAccessible2
38
52
IID _ia2PSClsidBackups[ARRAYSIZE(ia2Iids)]={0};
39
BOOL isIA2Installed=FALSE;
53
bool isIA2Installed=FALSE;
40
54
HINSTANCE IA2DllHandle=0;
41
55
DWORD IA2RegCooky=0;
42
BOOL isIA2Initialized=FALSE;
56
HANDLE IA2UIThreadHandle=NULL;
57
DWORD IA2UIThreadID=0;
58
HANDLE IA2UIThreadUninstalledEvent=NULL;
59
UINT wm_uninstallIA2Support=0;
60
bool isIA2Initialized=FALSE;
44
BOOL installIA2Support() {
62
bool installIA2Support() {
45
63
LPFNGETCLASSOBJECT IA2Dll_DllGetClassObject;
48
if(isIA2Installed) return TRUE;
66
if(isIA2Installed) return FALSE;
49
67
if((IA2DllHandle=CoLoadLibrary(IA2DllPath,FALSE))==NULL) {
50
fprintf(stderr,"Error loading IAccessible2 proxy dll\n");
68
LOG_ERROR(L"CoLoadLibrary failed");
53
71
IA2Dll_DllGetClassObject=(LPFNGETCLASSOBJECT)GetProcAddress(static_cast<HMODULE>(IA2DllHandle),"DllGetClassObject");
54
assert(IA2Dll_DllGetClassObject); //IAccessible2 proxy dll must have this function
72
nhAssert(IA2Dll_DllGetClassObject); //IAccessible2 proxy dll must have this function
55
73
IUnknown* ia2ClassObjPunk=NULL;
56
74
if((res=IA2Dll_DllGetClassObject(IAccessible2ProxyIID,IID_IUnknown,(LPVOID*)&ia2ClassObjPunk))!=S_OK) {
57
fprintf(stderr,"Error calling DllGetClassObject, code %d\n",res);
75
LOG_ERROR(L"Error calling DllGetClassObject, code "<<res);
58
76
CoFreeLibrary(IA2DllHandle);
62
80
if((res=CoRegisterClassObject(IAccessible2ProxyIID,ia2ClassObjPunk,CLSCTX_INPROC_SERVER,REGCLS_MULTIPLEUSE,(LPDWORD)&IA2RegCooky))!=S_OK) {
63
fprintf(stderr,"Error registering class object, code %d\n",res);
81
LOG_DEBUGWARNING(L"Error registering class object, code "<<res);
64
82
ia2ClassObjPunk->Release();
65
83
CoFreeLibrary(IA2DllHandle);
69
87
ia2ClassObjPunk->Release();
70
for(i=0;i<ARRAYSIZE(ia2Iids);i++) {
88
for(i=0;i<ARRAYSIZE(ia2Iids);++i) {
71
89
CoGetPSClsid(ia2Iids[i],&(_ia2PSClsidBackups[i]));
72
90
CoRegisterPSClsid(ia2Iids[i],IAccessible2ProxyIID);
78
BOOL uninstallIA2Support() {
96
bool uninstallIA2Support() {
80
98
LPFNDLLCANUNLOADNOW IA2Dll_DllCanUnloadNow;
82
for(i=0;i<ARRAYSIZE(ia2Iids);i++) {
83
CoRegisterPSClsid(ia2Iids[i],_ia2PSClsidBackups[i]);
85
CoRevokeClassObject(IA2RegCooky);
86
IA2Dll_DllCanUnloadNow=(LPFNDLLCANUNLOADNOW)GetProcAddress(static_cast<HMODULE>(IA2DllHandle),"DllCanUnloadNow");
87
assert(IA2Dll_DllCanUnloadNow); //IAccessible2 proxy dll must have this function
88
if(IA2Dll_DllCanUnloadNow()==S_OK) {
89
CoFreeLibrary(IA2DllHandle);
101
for(i=0;i<ARRAYSIZE(ia2Iids);++i) {
102
CoRegisterPSClsid(ia2Iids[i],_ia2PSClsidBackups[i]);
104
CoRevokeClassObject(IA2RegCooky);
105
IA2Dll_DllCanUnloadNow=(LPFNDLLCANUNLOADNOW)GetProcAddress(static_cast<HMODULE>(IA2DllHandle),"DllCanUnloadNow");
106
nhAssert(IA2Dll_DllCanUnloadNow); //IAccessible2 proxy dll must have this function
107
if(IA2Dll_DllCanUnloadNow()==S_OK) {
108
CoFreeLibrary(IA2DllHandle);
111
isIA2Installed=FALSE;
97
BOOL IA2Support_initialize() {
98
assert(!isIA2Initialized);
115
bool IA2Support_initialize() {
116
nhAssert(!isIA2Initialized);
99
117
wsprintf(IA2DllPath,L"%s\\IAccessible2Proxy.dll",dllDirectory);
100
118
isIA2Initialized=TRUE;
105
BOOL IA2Support_terminate() {
106
assert(isIA2Initialized);
107
uninstallIA2Support();
122
void CALLBACK IA2Support_winEventProcHook(HWINEVENTHOOK hookID, DWORD eventID, HWND hwnd, long objectID, long childID, DWORD threadID, DWORD time) {
123
if (eventID != EVENT_SYSTEM_FOREGROUND && eventID != EVENT_OBJECT_FOCUS)
125
if (installIA2Support()) {
126
IA2UIThreadHandle=OpenThread(SYNCHRONIZE,false,threadID);
127
IA2UIThreadID=threadID;
128
// IA2 support successfully installed, so this hook isn't needed anymore.
129
unregisterWinEventHook(IA2Support_winEventProcHook);
133
LRESULT CALLBACK IA2Support_uninstallerHook(int code, WPARAM wParam, LPARAM lParam) {
134
MSG* pmsg=(MSG*)lParam;
135
if(pmsg->message==wm_uninstallIA2Support) {
136
uninstallIA2Support();
137
SetEvent(IA2UIThreadUninstalledEvent);
111
142
void IA2Support_inProcess_initialize() {
145
// Try to install IA2 support on focus/foreground changes.
146
// This hook will be unregistered by the callback once IA2 support is successfully installed.
147
registerWinEventHook(IA2Support_winEventProcHook);
115
150
void IA2Support_inProcess_terminate() {
116
uninstallIA2Support();
151
// This will do nothing if the hook isn't registered.
152
unregisterWinEventHook(IA2Support_winEventProcHook);
153
if(!isIA2Installed||!IA2UIThreadHandle) {
156
//Check if the UI thread is still alive, if not there's nothing for us to do
157
if(WaitForSingleObject(IA2UIThreadHandle,0)==0) {
160
//Instruct the UI thread to uninstall IA2
161
IA2UIThreadUninstalledEvent=CreateEvent(NULL,true,false,NULL);
162
registerWindowsHook(WH_GETMESSAGE,IA2Support_uninstallerHook);
163
wm_uninstallIA2Support=RegisterWindowMessage(L"wm_uninstallIA2Support");
164
PostThreadMessage(IA2UIThreadID,wm_uninstallIA2Support,0,0);
165
HANDLE waitHandles[2]={IA2UIThreadUninstalledEvent,IA2UIThreadHandle};
166
int res=WaitForMultipleObjects(2,waitHandles,false,10000);
167
if(res!=WAIT_OBJECT_0&&res!=WAIT_OBJECT_0+1) {
168
LOG_DEBUGWARNING(L"WaitForMultipleObjects returned "<<res);
170
unregisterWindowsHook(WH_GETMESSAGE,IA2Support_uninstallerHook);
171
CloseHandle(IA2UIThreadUninstalledEvent);
172
CloseHandle(IA2UIThreadHandle);