1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
|
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#ifndef mozilla_a11y_LazyInstantiator_h
#define mozilla_a11y_LazyInstantiator_h
#include "IUnknownImpl.h"
#include "mozilla/Maybe.h"
#include "mozilla/RefPtr.h"
#include "nsString.h"
#include <oleacc.h>
#include <uiautomation.h>
class nsIFile;
namespace mozilla {
namespace a11y {
class MsaaRootAccessible;
/**
* LazyInstantiator is an IAccessible that initially acts as a placeholder.
* The a11y service is not actually started until two conditions are met:
*
* (1) A method is called on the LazyInstantiator that would require a11y
* services in order to fulfill; and
* (2) LazyInstantiator::ShouldInstantiate returns true.
*/
class LazyInstantiator final : public IAccessible,
public IServiceProvider,
public IRawElementProviderSimple {
public:
[[nodiscard]] static already_AddRefed<IAccessible> GetRootAccessible(
HWND aHwnd);
[[nodiscard]] static already_AddRefed<IRawElementProviderSimple> GetRootUia(
HWND aHwnd);
static void EnableBlindAggregation(HWND aHwnd);
// IUnknown
STDMETHODIMP QueryInterface(REFIID aIid, void** aOutInterface) override;
STDMETHODIMP_(ULONG) AddRef() override;
STDMETHODIMP_(ULONG) Release() override;
// IDispatch
STDMETHODIMP GetTypeInfoCount(UINT* pctinfo) override;
STDMETHODIMP GetTypeInfo(UINT iTInfo, LCID lcid,
ITypeInfo** ppTInfo) override;
STDMETHODIMP GetIDsOfNames(REFIID riid, LPOLESTR* rgszNames, UINT cNames,
LCID lcid, DISPID* rgDispId) override;
STDMETHODIMP Invoke(DISPID dispIdMember, REFIID riid, LCID lcid, WORD wFlags,
DISPPARAMS* pDispParams, VARIANT* pVarResult,
EXCEPINFO* pExcepInfo, UINT* puArgErr) override;
// IAccessible
STDMETHODIMP get_accParent(IDispatch** ppdispParent) override;
STDMETHODIMP get_accChildCount(long* pcountChildren) override;
STDMETHODIMP get_accChild(VARIANT varChild, IDispatch** ppdispChild) override;
STDMETHODIMP get_accName(VARIANT varChild, BSTR* pszName) override;
STDMETHODIMP get_accValue(VARIANT varChild, BSTR* pszValue) override;
STDMETHODIMP get_accDescription(VARIANT varChild,
BSTR* pszDescription) override;
STDMETHODIMP get_accRole(VARIANT varChild, VARIANT* pvarRole) override;
STDMETHODIMP get_accState(VARIANT varChild, VARIANT* pvarState) override;
STDMETHODIMP get_accHelp(VARIANT varChild, BSTR* pszHelp) override;
STDMETHODIMP get_accHelpTopic(BSTR* pszHelpFile, VARIANT varChild,
long* pidTopic) override;
STDMETHODIMP get_accKeyboardShortcut(VARIANT varChild,
BSTR* pszKeyboardShortcut) override;
STDMETHODIMP get_accFocus(VARIANT* pvarChild) override;
STDMETHODIMP get_accSelection(VARIANT* pvarChildren) override;
STDMETHODIMP get_accDefaultAction(VARIANT varChild,
BSTR* pszDefaultAction) override;
STDMETHODIMP accSelect(long flagsSelect, VARIANT varChild) override;
STDMETHODIMP accLocation(long* pxLeft, long* pyTop, long* pcxWidth,
long* pcyHeight, VARIANT varChild) override;
STDMETHODIMP accNavigate(long navDir, VARIANT varStart,
VARIANT* pvarEndUpAt) override;
STDMETHODIMP accHitTest(long xLeft, long yTop, VARIANT* pvarChild) override;
STDMETHODIMP accDoDefaultAction(VARIANT varChild) override;
STDMETHODIMP put_accName(VARIANT varChild, BSTR szName) override;
STDMETHODIMP put_accValue(VARIANT varChild, BSTR szValue) override;
// IServiceProvider
STDMETHODIMP QueryService(REFGUID aServiceId, REFIID aServiceIid,
void** aOutInterface) override;
// IRawElementProviderSimple
virtual /* [propget] */ HRESULT STDMETHODCALLTYPE get_ProviderOptions(
/* [retval][out] */ __RPC__out enum ProviderOptions* aProviderOptions);
virtual HRESULT STDMETHODCALLTYPE GetPatternProvider(
/* [in] */ PATTERNID aPatternId,
/* [retval][out] */ __RPC__deref_out_opt IUnknown** aPatternProvider);
virtual HRESULT STDMETHODCALLTYPE GetPropertyValue(
/* [in] */ PROPERTYID aPropertyId,
/* [retval][out] */ __RPC__out VARIANT* aPropertyValue);
virtual /* [propget] */ HRESULT STDMETHODCALLTYPE get_HostRawElementProvider(
/* [retval][out] */ __RPC__deref_out_opt IRawElementProviderSimple**
aRawElmProvider);
/**
* We cache the result of UIA detection because it could be expensive if a
* client repeatedly queries us. This function is called to reset that cache
* when one of our windows comes to the foreground. If there is a new UIA
* client that isn't blocked, instantiation will subsequently be allowed. The
* hope is that a user will probably need to switch apps in order to start a
* new client.
*/
static void ResetUiaDetectionCache() { sShouldBlockUia = Nothing(); }
private:
explicit LazyInstantiator(HWND aHwnd);
~LazyInstantiator();
bool IsBlockedInjection();
bool ShouldInstantiate(const DWORD aClientPid);
bool ShouldInstantiate();
DWORD GetRemoteMsaaClientPid();
/**
* @return S_OK if we have a valid mRealRoot to invoke methods on
*/
HRESULT MaybeResolveRoot();
/**
* @return S_OK if we have a valid mWeakDispatch to invoke methods on
*/
HRESULT ResolveDispatch();
MsaaRootAccessible* ResolveMsaaRoot();
void TransplantRefCnt();
void ClearProp();
template <class T>
static already_AddRefed<T> GetRoot(HWND aHwnd);
private:
mozilla::a11y::AutoRefCnt mRefCnt;
HWND mHwnd;
bool mAllowBlindAggregation;
RefPtr<IUnknown> mRealRootUnk;
RefPtr<IUnknown> mStdDispatch;
/**
* mWeakMsaaRoot, mWeakAccessible and mWeakDispatch are weak because they
* are interfaces that come from objects that we aggregate. Aggregated object
* interfaces share refcount methods with ours, so if we were to hold strong
* references to them, we would be holding strong references to ourselves,
* creating a cycle.
*/
MsaaRootAccessible* mWeakMsaaRoot;
IAccessible* mWeakAccessible;
IDispatch* mWeakDispatch;
IRawElementProviderSimple* mWeakUia;
static Maybe<bool> sShouldBlockUia;
};
} // namespace a11y
} // namespace mozilla
#endif // mozilla_a11y_LazyInstantiator_h
|