1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* vim: set ts=8 sts=2 et sw=2 tw=80: */
3 /* This Source Code Form is subject to the terms of the Mozilla Public
4  * License, v. 2.0. If a copy of the MPL was not distributed with this
5  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
6 
7 #include "LazyInstantiator.h"
8 
9 #include "MainThreadUtils.h"
10 #include "mozilla/a11y/LocalAccessible.h"
11 #include "mozilla/a11y/AccessibleHandler.h"
12 #include "mozilla/a11y/Compatibility.h"
13 #include "mozilla/a11y/Platform.h"
14 #include "mozilla/Assertions.h"
15 #include "mozilla/mscom/ProcessRuntime.h"
16 #include "mozilla/mscom/Registration.h"
17 #include "mozilla/UniquePtr.h"
18 #include "mozilla/WinHeaderOnlyUtils.h"
19 #include "MsaaRootAccessible.h"
20 #include "nsAccessibilityService.h"
21 #include "nsWindowsHelpers.h"
22 #include "nsCOMPtr.h"
23 #include "nsIFile.h"
24 #include "nsXPCOM.h"
25 #include "WinUtils.h"
26 #include "prenv.h"
27 
28 #include <oaidl.h>
29 
30 #if !defined(STATE_SYSTEM_NORMAL)
31 #  define STATE_SYSTEM_NORMAL (0)
32 #endif  // !defined(STATE_SYSTEM_NORMAL)
33 
34 #define DLL_BLOCKLIST_ENTRY(name, ...) {L##name, __VA_ARGS__},
35 #define DLL_BLOCKLIST_STRING_TYPE const wchar_t*
36 #include "mozilla/WindowsDllBlocklistA11yDefs.h"
37 
38 namespace mozilla {
39 namespace a11y {
40 
41 static const wchar_t kLazyInstantiatorProp[] =
42     L"mozilla::a11y::LazyInstantiator";
43 
44 /* static */
GetRootAccessible(HWND aHwnd)45 already_AddRefed<IAccessible> LazyInstantiator::GetRootAccessible(HWND aHwnd) {
46   // There must only be one LazyInstantiator per HWND.
47   // To track this, we set the kLazyInstantiatorProp on the HWND with a pointer
48   // to an existing instance. We only create a new LazyInstatiator if that prop
49   // has not already been set.
50   LazyInstantiator* existingInstantiator = reinterpret_cast<LazyInstantiator*>(
51       ::GetProp(aHwnd, kLazyInstantiatorProp));
52 
53   RefPtr<IAccessible> result;
54   if (existingInstantiator) {
55     // Temporarily disable blind aggregation until we know that we have been
56     // marshaled. See EnableBlindAggregation for more information.
57     existingInstantiator->mAllowBlindAggregation = false;
58     result = existingInstantiator;
59     return result.forget();
60   }
61 
62   // At this time we only want to check whether the acc service is running; We
63   // don't actually want to create the acc service yet.
64   if (!GetAccService()) {
65     // a11y is not running yet, there are no existing LazyInstantiators for this
66     // HWND, so create a new one and return it as a surrogate for the root
67     // accessible.
68     result = new LazyInstantiator(aHwnd);
69     return result.forget();
70   }
71 
72   // a11y is running, so we just resolve the real root accessible.
73   a11y::LocalAccessible* rootAcc =
74       widget::WinUtils::GetRootAccessibleForHWND(aHwnd);
75   if (!rootAcc) {
76     return nullptr;
77   }
78 
79   if (!rootAcc->IsRoot()) {
80     // rootAcc might represent a popup as opposed to a true root accessible.
81     // In that case we just use the regular LocalAccessible::GetNativeInterface.
82     rootAcc->GetNativeInterface(getter_AddRefs(result));
83     return result.forget();
84   }
85 
86   auto msaaRoot =
87       static_cast<MsaaRootAccessible*>(MsaaAccessible::GetFrom(rootAcc));
88   // Subtle: msaaRoot might still be wrapped by a LazyInstantiator, but we
89   // don't need LazyInstantiator's capabilities anymore (since a11y is already
90   // running). We can bypass LazyInstantiator by retrieving the internal
91   // unknown (which is not wrapped by the LazyInstantiator) and then querying
92   // that for IID_IAccessible.
93   RefPtr<IUnknown> punk(msaaRoot->GetInternalUnknown());
94 
95   MOZ_ASSERT(punk);
96   if (!punk) {
97     return nullptr;
98   }
99 
100   punk->QueryInterface(IID_IAccessible, getter_AddRefs(result));
101   return result.forget();
102 }
103 
104 /**
105  * When marshaling an interface, COM makes a whole bunch of QueryInterface
106  * calls to determine what kind of marshaling the interface supports. We need
107  * to handle those queries without instantiating a11y, so we temporarily
108  * disable passing through of QueryInterface calls to a11y. Once we know that
109  * COM is finished marshaling, we call EnableBlindAggregation to re-enable
110  * QueryInterface passthrough.
111  */
112 /* static */
EnableBlindAggregation(HWND aHwnd)113 void LazyInstantiator::EnableBlindAggregation(HWND aHwnd) {
114   LazyInstantiator* existingInstantiator = reinterpret_cast<LazyInstantiator*>(
115       ::GetProp(aHwnd, kLazyInstantiatorProp));
116 
117   if (!existingInstantiator) {
118     return;
119   }
120 
121   existingInstantiator->mAllowBlindAggregation = true;
122 }
123 
LazyInstantiator(HWND aHwnd)124 LazyInstantiator::LazyInstantiator(HWND aHwnd)
125     : mHwnd(aHwnd),
126       mAllowBlindAggregation(false),
127       mWeakMsaaRoot(nullptr),
128       mWeakAccessible(nullptr),
129       mWeakDispatch(nullptr) {
130   MOZ_ASSERT(aHwnd);
131   // Assign ourselves as the designated LazyInstantiator for aHwnd
132   DebugOnly<BOOL> setPropOk =
133       ::SetProp(aHwnd, kLazyInstantiatorProp, reinterpret_cast<HANDLE>(this));
134   MOZ_ASSERT(setPropOk);
135 }
136 
~LazyInstantiator()137 LazyInstantiator::~LazyInstantiator() {
138   if (mRealRootUnk) {
139     // Disconnect ourselves from the root accessible.
140     RefPtr<IUnknown> dummy(mWeakMsaaRoot->Aggregate(nullptr));
141   }
142 
143   ClearProp();
144 }
145 
ClearProp()146 void LazyInstantiator::ClearProp() {
147   // Remove ourselves as the designated LazyInstantiator for mHwnd
148   DebugOnly<HANDLE> removedProp = ::RemoveProp(mHwnd, kLazyInstantiatorProp);
149   MOZ_ASSERT(!removedProp ||
150              reinterpret_cast<LazyInstantiator*>(removedProp.value) == this);
151 }
152 
153 /**
154  * Given the remote client's thread ID, resolve its process ID.
155  */
156 DWORD
GetClientPid(const DWORD aClientTid)157 LazyInstantiator::GetClientPid(const DWORD aClientTid) {
158   nsAutoHandle callingThread(
159       ::OpenThread(THREAD_QUERY_LIMITED_INFORMATION, FALSE, aClientTid));
160   if (!callingThread) {
161     return 0;
162   }
163 
164   return ::GetProcessIdOfThread(callingThread);
165 }
166 
167 /**
168  * This is the blocklist for known "bad" remote clients that instantiate a11y.
169  */
170 static const char* gBlockedRemoteClients[] = {
171     "tbnotifier.exe",  // Ask.com Toolbar, bug 1453876
172     "flow.exe",        // Conexant Flow causes performance issues, bug 1569712
173     "rtop_bg.exe",     // ByteFence Anti-Malware, bug 1713383
174 };
175 
176 /**
177  * Check for the presence of any known "bad" injected DLLs that may be trying
178  * to instantiate a11y.
179  *
180  * @return true to block a11y instantiation, otherwise false to continue
181  */
IsBlockedInjection()182 bool LazyInstantiator::IsBlockedInjection() {
183   // Check debugging options see if we should disable the blocklist.
184   if (PR_GetEnv("MOZ_DISABLE_ACCESSIBLE_BLOCKLIST")) {
185     return false;
186   }
187 
188   if (Compatibility::HasKnownNonUiaConsumer()) {
189     // If we already see a known AT, don't block a11y instantiation
190     return false;
191   }
192 
193   for (size_t index = 0, len = ArrayLength(gBlockedInprocDlls); index < len;
194        ++index) {
195     const DllBlockInfo& blockedDll = gBlockedInprocDlls[index];
196     HMODULE module = ::GetModuleHandleW(blockedDll.mName);
197     if (!module) {
198       // This dll isn't loaded.
199       continue;
200     }
201 
202     LauncherResult<ModuleVersion> version = GetModuleVersion(module);
203     return version.isOk() && blockedDll.IsVersionBlocked(version.unwrap());
204   }
205 
206   return false;
207 }
208 
209 /**
210  * Given a remote client's thread ID, determine whether we should proceed with
211  * a11y instantiation. This is where telemetry should be gathered and any
212  * potential blocking of unwanted a11y clients should occur.
213  *
214  * @return true if we should instantiate a11y
215  */
ShouldInstantiate(const DWORD aClientTid)216 bool LazyInstantiator::ShouldInstantiate(const DWORD aClientTid) {
217   if (!aClientTid) {
218     // aClientTid == 0 implies that this is either an in-process call, or else
219     // we failed to retrieve information about the remote caller.
220     // We should always default to instantiating a11y in this case, provided
221     // that we don't see any known bad injected DLLs.
222     return !IsBlockedInjection();
223   }
224 
225   a11y::SetInstantiator(GetClientPid(aClientTid));
226 
227   nsCOMPtr<nsIFile> clientExe;
228   if (!a11y::GetInstantiator(getter_AddRefs(clientExe))) {
229     return true;
230   }
231 
232   nsresult rv;
233   if (!PR_GetEnv("MOZ_DISABLE_ACCESSIBLE_BLOCKLIST")) {
234     // Debugging option is not present, so check blocklist.
235     nsAutoString leafName;
236     rv = clientExe->GetLeafName(leafName);
237     if (NS_SUCCEEDED(rv)) {
238       for (size_t i = 0, len = ArrayLength(gBlockedRemoteClients); i < len;
239            ++i) {
240         if (leafName.EqualsIgnoreCase(gBlockedRemoteClients[i])) {
241           // If client exe is in our blocklist, do not instantiate.
242           return false;
243         }
244       }
245     }
246   }
247 
248   return true;
249 }
250 
ResolveMsaaRoot()251 MsaaRootAccessible* LazyInstantiator::ResolveMsaaRoot() {
252   LocalAccessible* acc = widget::WinUtils::GetRootAccessibleForHWND(mHwnd);
253   if (!acc || !acc->IsRoot()) {
254     return nullptr;
255   }
256 
257   RefPtr<IAccessible> ia;
258   acc->GetNativeInterface(getter_AddRefs(ia));
259   return static_cast<MsaaRootAccessible*>(ia.get());
260 }
261 
262 /**
263  * With COM aggregation, the aggregated inner object usually delegates its
264  * reference counting to the outer object. In other words, we would expect
265  * mRealRootUnk to delegate its AddRef() and Release() to this LazyInstantiator.
266  *
267  * This scheme will not work in our case because the RootAccessibleWrap is
268  * cycle-collected!
269  *
270  * Instead, once a LazyInstantiator aggregates a RootAccessibleWrap, we transfer
271  * our strong references into mRealRootUnk. Any future calls to AddRef or
272  * Release now operate on mRealRootUnk instead of our intrinsic reference
273  * count. This is a bit strange, but it is the only way for these objects to
274  * share their reference count in a way that is safe for cycle collection.
275  *
276  * How do we know when it is safe to destroy ourselves? In
277  * LazyInstantiator::Release, we examine the result of mRealRootUnk->Release().
278  * If mRealRootUnk's resulting refcount is 1, then we know that the only
279  * remaining reference to mRealRootUnk is the mRealRootUnk reference itself (and
280  * thus nobody else holds references to either this or mRealRootUnk). Therefore
281  * we may now delete ourselves.
282  */
TransplantRefCnt()283 void LazyInstantiator::TransplantRefCnt() {
284   MOZ_ASSERT(mRefCnt > 0);
285   MOZ_ASSERT(mRealRootUnk);
286 
287   while (mRefCnt > 0) {
288     mRealRootUnk.get()->AddRef();
289     --mRefCnt;
290   }
291 }
292 
293 HRESULT
MaybeResolveRoot()294 LazyInstantiator::MaybeResolveRoot() {
295   MOZ_ASSERT(NS_IsMainThread());
296   if (mWeakAccessible) {
297     return S_OK;
298   }
299 
300   if (GetAccService() ||
301       ShouldInstantiate(mscom::ProcessRuntime::GetClientThreadId())) {
302     mWeakMsaaRoot = ResolveMsaaRoot();
303     if (!mWeakMsaaRoot) {
304       return E_POINTER;
305     }
306 
307     // Wrap ourselves around the root accessible wrap
308     mRealRootUnk = mWeakMsaaRoot->Aggregate(static_cast<IAccessible*>(this));
309     if (!mRealRootUnk) {
310       return E_FAIL;
311     }
312 
313     // Move our strong references into the root accessible (see the comments
314     // above TransplantRefCnt for explanation).
315     TransplantRefCnt();
316 
317     // Now obtain mWeakAccessible which we use to forward our incoming calls
318     // to the real accesssible.
319     HRESULT hr =
320         mRealRootUnk->QueryInterface(IID_IAccessible, (void**)&mWeakAccessible);
321     if (FAILED(hr)) {
322       return hr;
323     }
324 
325     // mWeakAccessible is weak, so don't hold a strong ref
326     mWeakAccessible->Release();
327 
328     // Now that a11y is running, we don't need to remain registered with our
329     // HWND anymore.
330     ClearProp();
331 
332     return S_OK;
333   }
334 
335   // If we don't want a real root, let's resolve a fake one.
336 
337   const WPARAM flags = 0xFFFFFFFFUL;
338   // Synthesize a WM_GETOBJECT request to obtain a system-implemented
339   // IAccessible object from DefWindowProc
340   LRESULT lresult = ::DefWindowProc(mHwnd, WM_GETOBJECT, flags,
341                                     static_cast<LPARAM>(OBJID_CLIENT));
342 
343   HRESULT hr = ObjectFromLresult(lresult, IID_IAccessible, flags,
344                                  getter_AddRefs(mRealRootUnk));
345   if (FAILED(hr)) {
346     return hr;
347   }
348 
349   if (!mRealRootUnk) {
350     return E_NOTIMPL;
351   }
352 
353   hr = mRealRootUnk->QueryInterface(IID_IAccessible, (void**)&mWeakAccessible);
354   if (FAILED(hr)) {
355     return hr;
356   }
357 
358   // mWeakAccessible is weak, so don't hold a strong ref
359   mWeakAccessible->Release();
360 
361   return S_OK;
362 }
363 
364 #define RESOLVE_ROOT                 \
365   {                                  \
366     HRESULT hr = MaybeResolveRoot(); \
367     if (FAILED(hr)) {                \
368       return hr;                     \
369     }                                \
370   }
371 
372 IMPL_IUNKNOWN_QUERY_HEAD(LazyInstantiator)
373 IMPL_IUNKNOWN_QUERY_IFACE_AMBIGIOUS(IUnknown, IAccessible)
374 IMPL_IUNKNOWN_QUERY_IFACE(IAccessible)
375 IMPL_IUNKNOWN_QUERY_IFACE(IDispatch)
376 IMPL_IUNKNOWN_QUERY_IFACE(IServiceProvider)
377 // See EnableBlindAggregation for comments.
378 if (!mAllowBlindAggregation) {
379   return E_NOINTERFACE;
380 }
381 
382 if (aIID == IID_IAccIdentity) {
383   return E_NOINTERFACE;
384 }
385 // If the client queries for an interface that LazyInstantiator does not
386 // intrinsically support, then we must resolve the root accessible and pass
387 // on the QueryInterface call to mRealRootUnk.
388 RESOLVE_ROOT
IMPL_IUNKNOWN_QUERY_TAIL_AGGREGATED(mRealRootUnk)389 IMPL_IUNKNOWN_QUERY_TAIL_AGGREGATED(mRealRootUnk)
390 
391 ULONG
392 LazyInstantiator::AddRef() {
393   // Always delegate refcounting to mRealRootUnk when it exists
394   if (mRealRootUnk) {
395     return mRealRootUnk.get()->AddRef();
396   }
397 
398   return ++mRefCnt;
399 }
400 
401 ULONG
Release()402 LazyInstantiator::Release() {
403   ULONG result;
404 
405   // Always delegate refcounting to mRealRootUnk when it exists
406   if (mRealRootUnk) {
407     result = mRealRootUnk.get()->Release();
408     if (result == 1) {
409       // mRealRootUnk is the only strong reference left, so nothing else holds
410       // a strong reference to us. Drop result to zero so that we destroy
411       // ourselves (See the comments above LazyInstantiator::TransplantRefCnt
412       // for more info).
413       --result;
414     }
415   } else {
416     result = --mRefCnt;
417   }
418 
419   if (!result) {
420     delete this;
421   }
422   return result;
423 }
424 
425 /**
426  * Create a standard IDispatch implementation. mStdDispatch will translate any
427  * IDispatch::Invoke calls into real IAccessible calls.
428  */
429 HRESULT
ResolveDispatch()430 LazyInstantiator::ResolveDispatch() {
431   if (mWeakDispatch) {
432     return S_OK;
433   }
434 
435   // The IAccessible typelib is embedded in oleacc.dll's resources.
436   auto typelib = mscom::RegisterTypelib(
437       L"oleacc.dll", mscom::RegistrationFlags::eUseSystemDirectory);
438   if (!typelib) {
439     return E_UNEXPECTED;
440   }
441 
442   // Extract IAccessible's type info
443   RefPtr<ITypeInfo> accTypeInfo;
444   HRESULT hr =
445       typelib->GetTypeInfoForGuid(IID_IAccessible, getter_AddRefs(accTypeInfo));
446   if (FAILED(hr)) {
447     return hr;
448   }
449 
450   // Now create the standard IDispatch for IAccessible
451   hr = ::CreateStdDispatch(static_cast<IAccessible*>(this),
452                            static_cast<IAccessible*>(this), accTypeInfo,
453                            getter_AddRefs(mStdDispatch));
454   if (FAILED(hr)) {
455     return hr;
456   }
457 
458   hr = mStdDispatch->QueryInterface(IID_IDispatch, (void**)&mWeakDispatch);
459   if (FAILED(hr)) {
460     return hr;
461   }
462 
463   // WEAK reference
464   mWeakDispatch->Release();
465   return S_OK;
466 }
467 
468 #define RESOLVE_IDISPATCH           \
469   {                                 \
470     HRESULT hr = ResolveDispatch(); \
471     if (FAILED(hr)) {               \
472       return hr;                    \
473     }                               \
474   }
475 
476 /**
477  * The remaining methods implement IDispatch, IAccessible, and IServiceProvider,
478  * lazily resolving the real a11y objects and passing the call through.
479  */
480 
481 HRESULT
GetTypeInfoCount(UINT * pctinfo)482 LazyInstantiator::GetTypeInfoCount(UINT* pctinfo) {
483   RESOLVE_IDISPATCH;
484   return mWeakDispatch->GetTypeInfoCount(pctinfo);
485 }
486 
487 HRESULT
GetTypeInfo(UINT iTInfo,LCID lcid,ITypeInfo ** ppTInfo)488 LazyInstantiator::GetTypeInfo(UINT iTInfo, LCID lcid, ITypeInfo** ppTInfo) {
489   RESOLVE_IDISPATCH;
490   return mWeakDispatch->GetTypeInfo(iTInfo, lcid, ppTInfo);
491 }
492 
493 HRESULT
GetIDsOfNames(REFIID riid,LPOLESTR * rgszNames,UINT cNames,LCID lcid,DISPID * rgDispId)494 LazyInstantiator::GetIDsOfNames(REFIID riid, LPOLESTR* rgszNames, UINT cNames,
495                                 LCID lcid, DISPID* rgDispId) {
496   RESOLVE_IDISPATCH;
497   return mWeakDispatch->GetIDsOfNames(riid, rgszNames, cNames, lcid, rgDispId);
498 }
499 
500 HRESULT
Invoke(DISPID dispIdMember,REFIID riid,LCID lcid,WORD wFlags,DISPPARAMS * pDispParams,VARIANT * pVarResult,EXCEPINFO * pExcepInfo,UINT * puArgErr)501 LazyInstantiator::Invoke(DISPID dispIdMember, REFIID riid, LCID lcid,
502                          WORD wFlags, DISPPARAMS* pDispParams,
503                          VARIANT* pVarResult, EXCEPINFO* pExcepInfo,
504                          UINT* puArgErr) {
505   RESOLVE_IDISPATCH;
506   return mWeakDispatch->Invoke(dispIdMember, riid, lcid, wFlags, pDispParams,
507                                pVarResult, pExcepInfo, puArgErr);
508 }
509 
510 HRESULT
get_accParent(IDispatch ** ppdispParent)511 LazyInstantiator::get_accParent(IDispatch** ppdispParent) {
512   if (!mWeakAccessible) {
513     // If we'd resolve the root right now this would be the codepath we'd end
514     // up in anyway. So we might as well return it here.
515     return ::AccessibleObjectFromWindow(mHwnd, OBJID_WINDOW, IID_IAccessible,
516                                         (void**)ppdispParent);
517   }
518   RESOLVE_ROOT;
519   return mWeakAccessible->get_accParent(ppdispParent);
520 }
521 
522 HRESULT
get_accChildCount(long * pcountChildren)523 LazyInstantiator::get_accChildCount(long* pcountChildren) {
524   if (!pcountChildren) {
525     return E_INVALIDARG;
526   }
527 
528   RESOLVE_ROOT;
529   return mWeakAccessible->get_accChildCount(pcountChildren);
530 }
531 
532 HRESULT
get_accChild(VARIANT varChild,IDispatch ** ppdispChild)533 LazyInstantiator::get_accChild(VARIANT varChild, IDispatch** ppdispChild) {
534   if (!ppdispChild) {
535     return E_INVALIDARG;
536   }
537 
538   if (V_VT(&varChild) == VT_I4 && V_I4(&varChild) == CHILDID_SELF) {
539     RefPtr<IDispatch> disp(this);
540     disp.forget(ppdispChild);
541     return S_OK;
542   }
543 
544   RESOLVE_ROOT;
545   return mWeakAccessible->get_accChild(varChild, ppdispChild);
546 }
547 
548 HRESULT
get_accName(VARIANT varChild,BSTR * pszName)549 LazyInstantiator::get_accName(VARIANT varChild, BSTR* pszName) {
550   if (!pszName) {
551     return E_INVALIDARG;
552   }
553 
554   RESOLVE_ROOT;
555   return mWeakAccessible->get_accName(varChild, pszName);
556 }
557 
558 HRESULT
get_accValue(VARIANT varChild,BSTR * pszValue)559 LazyInstantiator::get_accValue(VARIANT varChild, BSTR* pszValue) {
560   if (!pszValue) {
561     return E_INVALIDARG;
562   }
563 
564   RESOLVE_ROOT;
565   return mWeakAccessible->get_accValue(varChild, pszValue);
566 }
567 
568 HRESULT
get_accDescription(VARIANT varChild,BSTR * pszDescription)569 LazyInstantiator::get_accDescription(VARIANT varChild, BSTR* pszDescription) {
570   if (!pszDescription) {
571     return E_INVALIDARG;
572   }
573 
574   RESOLVE_ROOT;
575   return mWeakAccessible->get_accDescription(varChild, pszDescription);
576 }
577 
578 HRESULT
get_accRole(VARIANT varChild,VARIANT * pvarRole)579 LazyInstantiator::get_accRole(VARIANT varChild, VARIANT* pvarRole) {
580   if (!pvarRole) {
581     return E_INVALIDARG;
582   }
583 
584   if (V_VT(&varChild) == VT_I4 && V_I4(&varChild) == CHILDID_SELF) {
585     V_VT(pvarRole) = VT_I4;
586     V_I4(pvarRole) = ROLE_SYSTEM_APPLICATION;
587     return S_OK;
588   }
589 
590   RESOLVE_ROOT;
591   return mWeakAccessible->get_accRole(varChild, pvarRole);
592 }
593 
594 HRESULT
get_accState(VARIANT varChild,VARIANT * pvarState)595 LazyInstantiator::get_accState(VARIANT varChild, VARIANT* pvarState) {
596   if (!pvarState) {
597     return E_INVALIDARG;
598   }
599 
600   RESOLVE_ROOT;
601   return mWeakAccessible->get_accState(varChild, pvarState);
602 }
603 
604 HRESULT
get_accHelp(VARIANT varChild,BSTR * pszHelp)605 LazyInstantiator::get_accHelp(VARIANT varChild, BSTR* pszHelp) {
606   return E_NOTIMPL;
607 }
608 
609 HRESULT
get_accHelpTopic(BSTR * pszHelpFile,VARIANT varChild,long * pidTopic)610 LazyInstantiator::get_accHelpTopic(BSTR* pszHelpFile, VARIANT varChild,
611                                    long* pidTopic) {
612   return E_NOTIMPL;
613 }
614 
615 HRESULT
get_accKeyboardShortcut(VARIANT varChild,BSTR * pszKeyboardShortcut)616 LazyInstantiator::get_accKeyboardShortcut(VARIANT varChild,
617                                           BSTR* pszKeyboardShortcut) {
618   if (!pszKeyboardShortcut) {
619     return E_INVALIDARG;
620   }
621 
622   RESOLVE_ROOT;
623   return mWeakAccessible->get_accKeyboardShortcut(varChild,
624                                                   pszKeyboardShortcut);
625 }
626 
627 HRESULT
get_accFocus(VARIANT * pvarChild)628 LazyInstantiator::get_accFocus(VARIANT* pvarChild) {
629   if (!pvarChild) {
630     return E_INVALIDARG;
631   }
632 
633   RESOLVE_ROOT;
634   return mWeakAccessible->get_accFocus(pvarChild);
635 }
636 
637 HRESULT
get_accSelection(VARIANT * pvarChildren)638 LazyInstantiator::get_accSelection(VARIANT* pvarChildren) {
639   if (!pvarChildren) {
640     return E_INVALIDARG;
641   }
642 
643   RESOLVE_ROOT;
644   return mWeakAccessible->get_accSelection(pvarChildren);
645 }
646 
647 HRESULT
get_accDefaultAction(VARIANT varChild,BSTR * pszDefaultAction)648 LazyInstantiator::get_accDefaultAction(VARIANT varChild,
649                                        BSTR* pszDefaultAction) {
650   if (!pszDefaultAction) {
651     return E_INVALIDARG;
652   }
653 
654   RESOLVE_ROOT;
655   return mWeakAccessible->get_accDefaultAction(varChild, pszDefaultAction);
656 }
657 
658 HRESULT
accSelect(long flagsSelect,VARIANT varChild)659 LazyInstantiator::accSelect(long flagsSelect, VARIANT varChild) {
660   RESOLVE_ROOT;
661   return mWeakAccessible->accSelect(flagsSelect, varChild);
662 }
663 
664 HRESULT
accLocation(long * pxLeft,long * pyTop,long * pcxWidth,long * pcyHeight,VARIANT varChild)665 LazyInstantiator::accLocation(long* pxLeft, long* pyTop, long* pcxWidth,
666                               long* pcyHeight, VARIANT varChild) {
667   RESOLVE_ROOT;
668   return mWeakAccessible->accLocation(pxLeft, pyTop, pcxWidth, pcyHeight,
669                                       varChild);
670 }
671 
672 HRESULT
accNavigate(long navDir,VARIANT varStart,VARIANT * pvarEndUpAt)673 LazyInstantiator::accNavigate(long navDir, VARIANT varStart,
674                               VARIANT* pvarEndUpAt) {
675   if (!pvarEndUpAt) {
676     return E_INVALIDARG;
677   }
678 
679   RESOLVE_ROOT;
680   return mWeakAccessible->accNavigate(navDir, varStart, pvarEndUpAt);
681 }
682 
683 HRESULT
accHitTest(long xLeft,long yTop,VARIANT * pvarChild)684 LazyInstantiator::accHitTest(long xLeft, long yTop, VARIANT* pvarChild) {
685   if (!pvarChild) {
686     return E_INVALIDARG;
687   }
688 
689   RESOLVE_ROOT;
690   return mWeakAccessible->accHitTest(xLeft, yTop, pvarChild);
691 }
692 
693 HRESULT
accDoDefaultAction(VARIANT varChild)694 LazyInstantiator::accDoDefaultAction(VARIANT varChild) {
695   RESOLVE_ROOT;
696   return mWeakAccessible->accDoDefaultAction(varChild);
697 }
698 
699 HRESULT
put_accName(VARIANT varChild,BSTR szName)700 LazyInstantiator::put_accName(VARIANT varChild, BSTR szName) {
701   return E_NOTIMPL;
702 }
703 
704 HRESULT
put_accValue(VARIANT varChild,BSTR szValue)705 LazyInstantiator::put_accValue(VARIANT varChild, BSTR szValue) {
706   return E_NOTIMPL;
707 }
708 
709 HRESULT
QueryService(REFGUID aServiceId,REFIID aServiceIid,void ** aOutInterface)710 LazyInstantiator::QueryService(REFGUID aServiceId, REFIID aServiceIid,
711                                void** aOutInterface) {
712   if (!aOutInterface) {
713     return E_INVALIDARG;
714   }
715 
716   for (const GUID& unsupportedService : kUnsupportedServices) {
717     if (aServiceId == unsupportedService) {
718       return E_NOINTERFACE;
719     }
720   }
721 
722   *aOutInterface = nullptr;
723 
724   RESOLVE_ROOT;
725 
726   RefPtr<IServiceProvider> servProv;
727   HRESULT hr = mRealRootUnk->QueryInterface(IID_IServiceProvider,
728                                             getter_AddRefs(servProv));
729   if (FAILED(hr)) {
730     return hr;
731   }
732 
733   return servProv->QueryService(aServiceId, aServiceIid, aOutInterface);
734 }
735 
736 }  // namespace a11y
737 }  // namespace mozilla
738