Quellcodebibliothek Statistik Leitseite products/Sources/formale Sprachen/C/Firefox/accessible/windows/msaa/   (Browser von der Mozilla Stiftung Version 136.0.1©)  Datei vom 10.2.2025 mit Größe 24 kB image not shown  

Quelle  LazyInstantiator.cpp   Sprache: C

 
/* -*- 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/. */


#include "LazyInstantiator.h"

#include "MainThreadUtils.h"
#include "mozilla/a11y/LocalAccessible.h"
#include "mozilla/a11y/Compatibility.h"
#include "mozilla/a11y/Platform.h"
#include "mozilla/Assertions.h"
#include "mozilla/mscom/ProcessRuntime.h"
#include "mozilla/StaticPrefs_accessibility.h"
#include "mozilla/UniquePtr.h"
#include "mozilla/WinHeaderOnlyUtils.h"
#include "MsaaRootAccessible.h"
#include "nsAccessibilityService.h"
#include "nsWindowsHelpers.h"
#include "nsCOMPtr.h"
#include "nsIFile.h"
#include "nsXPCOM.h"
#include "WinUtils.h"
#include "prenv.h"

#include <oaidl.h>

#if !defined(STATE_SYSTEM_NORMAL)
#  define STATE_SYSTEM_NORMAL (0)
#endif  // !defined(STATE_SYSTEM_NORMAL)

#define DLL_BLOCKLIST_ENTRY(name, ...) {L##name, __VA_ARGS__},
#define DLL_BLOCKLIST_STRING_TYPE const wchar_t*
#include "mozilla/WindowsDllBlocklistA11yDefs.h"

namespace mozilla {
namespace a11y {

static const wchar_t kLazyInstantiatorProp[] =
    L"mozilla::a11y::LazyInstantiator";

Maybe<bool> LazyInstantiator::sShouldBlockUia;

template <class T>
already_AddRefed<T> LazyInstantiator::GetRoot(HWND aHwnd) {
  RefPtr<T> result;
  // At this time we only want to check whether the acc service is running. We
  // don't actually want to create the acc service yet.
  if (!GetAccService()) {
    // There must only be one LazyInstantiator per HWND.
    // To track this, we set the kLazyInstantiatorProp on the HWND with a
    // pointer to an existing instance. We only create a new LazyInstatiator if
    // that prop has not already been set.
    LazyInstantiator* existingInstantiator =
        reinterpret_cast<LazyInstantiator*>(
            ::GetProp(aHwnd, kLazyInstantiatorProp));

    if (existingInstantiator) {
      // Temporarily disable blind aggregation until we know that we have been
      // marshaled. See EnableBlindAggregation for more information.
      existingInstantiator->mAllowBlindAggregation = false;
      result = existingInstantiator;
      return result.forget();
    }

    // a11y is not running yet, there are no existing LazyInstantiators for this
    // HWND, so create a new one and return it as a surrogate for the root
    // accessible.
    result = new LazyInstantiator(aHwnd);
    return result.forget();
  }

  // a11y is running, so we just resolve the real root accessible.
  a11y::LocalAccessible* rootAcc =
      widget::WinUtils::GetRootAccessibleForHWND(aHwnd);
  if (!rootAcc) {
    return nullptr;
  }

  if (!rootAcc->IsRoot()) {
    // rootAcc might represent a popup as opposed to a true root accessible.
    // In that case we just use the regular LocalAccessible::GetNativeInterface.
    result = MsaaAccessible::GetFrom(rootAcc);
    return result.forget();
  }

  auto msaaRoot =
      static_cast<MsaaRootAccessible*>(MsaaAccessible::GetFrom(rootAcc));
  // Subtle: msaaRoot might still be wrapped by a LazyInstantiator, but we
  // don't need LazyInstantiator's capabilities anymore (since a11y is already
  // running). We can bypass LazyInstantiator by retrieving the internal
  // unknown (which is not wrapped by the LazyInstantiator) and then querying
  // that for the interface we want.
  RefPtr<IUnknown> punk(msaaRoot->GetInternalUnknown());

  MOZ_ASSERT(punk);
  if (!punk) {
    return nullptr;
  }

  punk->QueryInterface(__uuidof(T), getter_AddRefs(result));
  return result.forget();
}

/* static */
already_AddRefed<IAccessible> LazyInstantiator::GetRootAccessible(HWND aHwnd) {
  return GetRoot<IAccessible>(aHwnd);
}

/* static */
already_AddRefed<IRawElementProviderSimple> LazyInstantiator::GetRootUia(
    HWND aHwnd) {
  if (!StaticPrefs::accessibility_uia_enable()) {
    return nullptr;
  }
  return GetRoot<IRawElementProviderSimple>(aHwnd);
}

/**
 * When marshaling an interface, COM makes a whole bunch of QueryInterface
 * calls to determine what kind of marshaling the interface supports. We need
 * to handle those queries without instantiating a11y, so we temporarily
 * disable passing through of QueryInterface calls to a11y. Once we know that
 * COM is finished marshaling, we call EnableBlindAggregation to re-enable
 * QueryInterface passthrough.
 */

/* static */
void LazyInstantiator::EnableBlindAggregation(HWND aHwnd) {
  if (GetAccService()) {
    // The accessibility service is already running. That means that
    // LazyInstantiator::GetRootAccessible returned the real MsaaRootAccessible,
    // rather than returning a LazyInstantiator with blind aggregation disabled.
    // Thus, we have nothing to do here.
    return;
  }

  LazyInstantiator* existingInstantiator = reinterpret_cast<LazyInstantiator*>(
      ::GetProp(aHwnd, kLazyInstantiatorProp));

  if (!existingInstantiator) {
    return;
  }

  existingInstantiator->mAllowBlindAggregation = true;
}

LazyInstantiator::LazyInstantiator(HWND aHwnd)
    : mHwnd(aHwnd),
      mAllowBlindAggregation(false),
      mWeakMsaaRoot(nullptr),
      mWeakAccessible(nullptr),
      mWeakDispatch(nullptr),
      mWeakUia(nullptr) {
  MOZ_ASSERT(aHwnd);
  // Assign ourselves as the designated LazyInstantiator for aHwnd
  DebugOnly<BOOL> setPropOk =
      ::SetProp(aHwnd, kLazyInstantiatorProp, reinterpret_cast<HANDLE>(this));
  MOZ_ASSERT(setPropOk);
}

LazyInstantiator::~LazyInstantiator() {
  if (mRealRootUnk) {
    // Disconnect ourselves from the root accessible.
    RefPtr<IUnknown> dummy(mWeakMsaaRoot->Aggregate(nullptr));
  }

  ClearProp();
}

void LazyInstantiator::ClearProp() {
  // Remove ourselves as the designated LazyInstantiator for mHwnd
  DebugOnly<HANDLE> removedProp = ::RemoveProp(mHwnd, kLazyInstantiatorProp);
  MOZ_ASSERT(!removedProp ||
             reinterpret_cast<LazyInstantiator*>(removedProp.value) == this);
}

/**
 * Get the process id of a remote (out-of-process) MSAA/IA2 client.
 */

DWORD LazyInstantiator::GetRemoteMsaaClientPid() {
  nsAutoHandle callingThread(
      ::OpenThread(THREAD_QUERY_LIMITED_INFORMATION, FALSE,
                   mscom::ProcessRuntime::GetClientThreadId()));
  if (!callingThread) {
    return 0;
  }
  return ::GetProcessIdOfThread(callingThread);
}

/**
 * This is the blocklist for known "bad" remote clients that instantiate a11y.
 */

static const char* gBlockedRemoteClients[] = {
    "tbnotifier.exe",  // Ask.com Toolbar, bug 1453876
    "flow.exe",        // Conexant Flow causes performance issues, bug 1569712
    "rtop_bg.exe",     // ByteFence Anti-Malware, bug 1713383
    "osk.exe",         // Windows On-Screen Keyboard, bug 1424505
};

/**
 * Check for the presence of any known "bad" injected DLLs that may be trying
 * to instantiate a11y.
 *
 * @return true to block a11y instantiation, otherwise false to continue
 */

bool LazyInstantiator::IsBlockedInjection() {
  // Check debugging options see if we should disable the blocklist.
  if (PR_GetEnv("MOZ_DISABLE_ACCESSIBLE_BLOCKLIST")) {
    return false;
  }

  for (size_t index = 0, len = std::size(gBlockedInprocDlls); index < len;
       ++index) {
    const DllBlockInfo& blockedDll = gBlockedInprocDlls[index];
    HMODULE module = ::GetModuleHandleW(blockedDll.mName);
    if (!module) {
      // This dll isn't loaded.
      continue;
    }

    LauncherResult<ModuleVersion> version = GetModuleVersion(module);
    return version.isOk() && blockedDll.IsVersionBlocked(version.unwrap());
  }

  return false;
}

/**
 * Given a remote client's process ID, determine whether we should proceed with
 * a11y instantiation. This is where telemetry should be gathered and any
 * potential blocking of unwanted a11y clients should occur.
 *
 * @return true if we should instantiate a11y
 */

bool LazyInstantiator::ShouldInstantiate(const DWORD aClientPid) {
  a11y::SetInstantiator(aClientPid);

  nsCOMPtr<nsIFile> clientExe;
  if (!a11y::GetInstantiator(getter_AddRefs(clientExe))) {
    return true;
  }

  nsresult rv;
  if (!PR_GetEnv("MOZ_DISABLE_ACCESSIBLE_BLOCKLIST")) {
    // Debugging option is not present, so check blocklist.
    nsAutoString leafName;
    rv = clientExe->GetLeafName(leafName);
    if (NS_SUCCEEDED(rv)) {
      for (size_t i = 0, len = std::size(gBlockedRemoteClients); i < len; ++i) {
        if (leafName.EqualsIgnoreCase(gBlockedRemoteClients[i])) {
          // If client exe is in our blocklist, do not instantiate.
          return false;
        }
      }
    }
  }

  return true;
}

/**
 * Determine whether we should proceed with a11y instantiation, considering the
 * various different types of clients.
 */

bool LazyInstantiator::ShouldInstantiate() {
  if (Compatibility::IsA11ySuppressed()) {
    return false;
  }
  if (DWORD pid = GetRemoteMsaaClientPid()) {
    return ShouldInstantiate(pid);
  }
  if (Compatibility::HasKnownNonUiaConsumer()) {
    // We detected a known in-process client.
    return true;
  }
  // UIA client detection can be expensive, so we cache the result. See the
  // header comment for ResetUiaDetectionCache() for details.
  if (sShouldBlockUia.isNothing()) {
    // Unlike MSAA, we can't tell which specific UIA client is querying us right
    // now. We can only determine which clients have tried querying us.
    // Therefore, we must check all of them.
    AutoTArray<DWORD, 1> uiaPids;
    Compatibility::GetUiaClientPids(uiaPids);
    if (uiaPids.IsEmpty()) {
      // No UIA clients, so don't block UIA. However, we might block for
      // non-UIA clients below.
      sShouldBlockUia = Some(false);
    } else {
      for (const DWORD pid : uiaPids) {
        if (ShouldInstantiate(pid)) {
          sShouldBlockUia = Some(false);
          return true;
        }
      }
      // We didn't return in the loop above, so there are only blocked UIA
      // clients.
      sShouldBlockUia = Some(true);
    }
  }
  if (*sShouldBlockUia) {
    return false;
  }
  if (IsBlockedInjection()) {
    return false;
  }
  return true;
}

MsaaRootAccessible* LazyInstantiator::ResolveMsaaRoot() {
  LocalAccessible* acc = widget::WinUtils::GetRootAccessibleForHWND(mHwnd);
  if (!acc || !acc->IsRoot()) {
    return nullptr;
  }

  RefPtr<IAccessible> ia;
  acc->GetNativeInterface(getter_AddRefs(ia));
  return static_cast<MsaaRootAccessible*>(ia.get());
}

/**
 * With COM aggregation, the aggregated inner object usually delegates its
 * reference counting to the outer object. In other words, we would expect
 * mRealRootUnk to delegate its AddRef() and Release() to this LazyInstantiator.
 *
 * This scheme will not work in our case because the RootAccessibleWrap is
 * cycle-collected!
 *
 * Instead, once a LazyInstantiator aggregates a RootAccessibleWrap, we transfer
 * our strong references into mRealRootUnk. Any future calls to AddRef or
 * Release now operate on mRealRootUnk instead of our intrinsic reference
 * count. This is a bit strange, but it is the only way for these objects to
 * share their reference count in a way that is safe for cycle collection.
 *
 * How do we know when it is safe to destroy ourselves? In
 * LazyInstantiator::Release, we examine the result of mRealRootUnk->Release().
 * If mRealRootUnk's resulting refcount is 1, then we know that the only
 * remaining reference to mRealRootUnk is the mRealRootUnk reference itself (and
 * thus nobody else holds references to either this or mRealRootUnk). Therefore
 * we may now delete ourselves.
 */

void LazyInstantiator::TransplantRefCnt() {
  MOZ_ASSERT(mRefCnt > 0);
  MOZ_ASSERT(mRealRootUnk);

  while (mRefCnt > 0) {
    mRealRootUnk.get()->AddRef();
    --mRefCnt;
  }
}

HRESULT
LazyInstantiator::MaybeResolveRoot() {
  if (!NS_IsMainThread()) {
    MOZ_ASSERT_UNREACHABLE("Called on a background thread!");
    // Bug 1814780: This should never happen, since a caller should only be able
    // to get this via AccessibleObjectFromWindow/AccessibleObjectFromEvent or
    // WM_GETOBJECT/ObjectFromLresult, which should marshal any calls on
    // a background thread to the main thread. Nevertheless, Windows sometimes
    // calls QueryInterface from a background thread! To avoid crashes, fail
    // gracefully here.
    return RPC_E_WRONG_THREAD;
  }

  if (mWeakAccessible) {
    return S_OK;
  }

  if (GetAccService() || ShouldInstantiate()) {
    mWeakMsaaRoot = ResolveMsaaRoot();
    if (!mWeakMsaaRoot) {
      return E_POINTER;
    }

    // Wrap ourselves around the root accessible wrap
    mRealRootUnk = mWeakMsaaRoot->Aggregate(static_cast<IAccessible*>(this));
    if (!mRealRootUnk) {
      return E_FAIL;
    }

    // Move our strong references into the root accessible (see the comments
    // above TransplantRefCnt for explanation).
    TransplantRefCnt();

    // Now obtain mWeakAccessible which we use to forward our incoming calls
    // to the real accesssible.
    HRESULT hr =
        mRealRootUnk->QueryInterface(IID_IAccessible, (void**)&mWeakAccessible);
    if (FAILED(hr)) {
      return hr;
    }
    // mWeakAccessible is weak, so don't hold a strong ref
    mWeakAccessible->Release();
    if (StaticPrefs::accessibility_uia_enable()) {
      hr = mRealRootUnk->QueryInterface(IID_IRawElementProviderSimple,
                                        (void**)&mWeakUia);
      if (FAILED(hr)) {
        return hr;
      }
      mWeakUia->Release();
    }

    // Now that a11y is running, we don't need to remain registered with our
    // HWND anymore.
    ClearProp();

    return S_OK;
  }

  return E_FAIL;
}

#define RESOLVE_ROOT                 \
  {                                  \
    HRESULT hr = MaybeResolveRoot(); \
    if (FAILED(hr)) {                \
      return hr;                     \
    }                                \
  }

IMPL_IUNKNOWN_QUERY_HEAD(LazyInstantiator)
IMPL_IUNKNOWN_QUERY_IFACE_AMBIGIOUS(IUnknown, IAccessible)
IMPL_IUNKNOWN_QUERY_IFACE(IAccessible)
IMPL_IUNKNOWN_QUERY_IFACE(IDispatch)
IMPL_IUNKNOWN_QUERY_IFACE(IServiceProvider)
if (StaticPrefs::accessibility_uia_enable()) {
  IMPL_IUNKNOWN_QUERY_IFACE(IRawElementProviderSimple)
}
// See EnableBlindAggregation for comments.
if (!mAllowBlindAggregation) {
  return E_NOINTERFACE;
}

if (aIID == IID_IAccIdentity) {
  return E_NOINTERFACE;
}
// If the client queries for an interface that LazyInstantiator does not
// intrinsically support, then we must resolve the root accessible and pass
// on the QueryInterface call to mRealRootUnk.
RESOLVE_ROOT
IMPL_IUNKNOWN_QUERY_TAIL_AGGREGATED(mRealRootUnk)

ULONG
LazyInstantiator::AddRef() {
  // Always delegate refcounting to mRealRootUnk when it exists
  if (mRealRootUnk) {
    return mRealRootUnk.get()->AddRef();
  }

  return ++mRefCnt;
}

ULONG
LazyInstantiator::Release() {
  ULONG result;

  // Always delegate refcounting to mRealRootUnk when it exists
  if (mRealRootUnk) {
    result = mRealRootUnk.get()->Release();
    if (result == 1) {
      // mRealRootUnk is the only strong reference left, so nothing else holds
      // a strong reference to us. Drop result to zero so that we destroy
      // ourselves (See the comments above LazyInstantiator::TransplantRefCnt
      // for more info).
      --result;
    }
  } else {
    result = --mRefCnt;
  }

  if (!result) {
    delete this;
  }
  return result;
}

/**
 * Create a standard IDispatch implementation. mStdDispatch will translate any
 * IDispatch::Invoke calls into real IAccessible calls.
 */

HRESULT
LazyInstantiator::ResolveDispatch() {
  if (mWeakDispatch) {
    return S_OK;
  }

  // Extract IAccessible's type info
  RefPtr<ITypeInfo> accTypeInfo = MsaaAccessible::GetTI(LOCALE_USER_DEFAULT);
  if (!accTypeInfo) {
    return E_UNEXPECTED;
  }

  // Now create the standard IDispatch for IAccessible
  HRESULT hr = ::CreateStdDispatch(static_cast<IAccessible*>(this),
                                   static_cast<IAccessible*>(this), accTypeInfo,
                                   getter_AddRefs(mStdDispatch));
  if (FAILED(hr)) {
    return hr;
  }

  hr = mStdDispatch->QueryInterface(IID_IDispatch, (void**)&mWeakDispatch);
  if (FAILED(hr)) {
    return hr;
  }

  // WEAK reference
  mWeakDispatch->Release();
  return S_OK;
}

#define RESOLVE_IDISPATCH           \
  {                                 \
    HRESULT hr = ResolveDispatch(); \
    if (FAILED(hr)) {               \
      return hr;                    \
    }                               \
  }

/**
 * The remaining methods implement IDispatch, IAccessible, and IServiceProvider,
 * lazily resolving the real a11y objects and passing the call through.
 */


HRESULT
LazyInstantiator::GetTypeInfoCount(UINT* pctinfo) {
  RESOLVE_IDISPATCH;
  return mWeakDispatch->GetTypeInfoCount(pctinfo);
}

HRESULT
LazyInstantiator::GetTypeInfo(UINT iTInfo, LCID lcid, ITypeInfo** ppTInfo) {
  RESOLVE_IDISPATCH;
  return mWeakDispatch->GetTypeInfo(iTInfo, lcid, ppTInfo);
}

HRESULT
LazyInstantiator::GetIDsOfNames(REFIID riid, LPOLESTR* rgszNames, UINT cNames,
                                LCID lcid, DISPID* rgDispId) {
  RESOLVE_IDISPATCH;
  return mWeakDispatch->GetIDsOfNames(riid, rgszNames, cNames, lcid, rgDispId);
}

HRESULT
LazyInstantiator::Invoke(DISPID dispIdMember, REFIID riid, LCID lcid,
                         WORD wFlags, DISPPARAMS* pDispParams,
                         VARIANT* pVarResult, EXCEPINFO* pExcepInfo,
                         UINT* puArgErr) {
  RESOLVE_IDISPATCH;
  return mWeakDispatch->Invoke(dispIdMember, riid, lcid, wFlags, pDispParams,
                               pVarResult, pExcepInfo, puArgErr);
}

HRESULT
LazyInstantiator::get_accParent(IDispatch** ppdispParent) {
  if (!mWeakAccessible) {
    // If we'd resolve the root right now this would be the codepath we'd end
    // up in anyway. So we might as well return it here.
    return ::CreateStdAccessibleObject(mHwnd, OBJID_WINDOW, IID_IAccessible,
                                       (void**)ppdispParent);
  }
  RESOLVE_ROOT;
  return mWeakAccessible->get_accParent(ppdispParent);
}

HRESULT
LazyInstantiator::get_accChildCount(long* pcountChildren) {
  if (!pcountChildren) {
    return E_INVALIDARG;
  }

  RESOLVE_ROOT;
  return mWeakAccessible->get_accChildCount(pcountChildren);
}

HRESULT
LazyInstantiator::get_accChild(VARIANT varChild, IDispatch** ppdispChild) {
  if (!ppdispChild) {
    return E_INVALIDARG;
  }

  if (V_VT(&varChild) == VT_I4 && V_I4(&varChild) == CHILDID_SELF) {
    RefPtr<IDispatch> disp(this);
    disp.forget(ppdispChild);
    return S_OK;
  }

  RESOLVE_ROOT;
  return mWeakAccessible->get_accChild(varChild, ppdispChild);
}

HRESULT
LazyInstantiator::get_accName(VARIANT varChild, BSTR* pszName) {
  if (!pszName) {
    return E_INVALIDARG;
  }

  RESOLVE_ROOT;
  return mWeakAccessible->get_accName(varChild, pszName);
}

HRESULT
LazyInstantiator::get_accValue(VARIANT varChild, BSTR* pszValue) {
  if (!pszValue) {
    return E_INVALIDARG;
  }

  RESOLVE_ROOT;
  return mWeakAccessible->get_accValue(varChild, pszValue);
}

HRESULT
LazyInstantiator::get_accDescription(VARIANT varChild, BSTR* pszDescription) {
  if (!pszDescription) {
    return E_INVALIDARG;
  }

  RESOLVE_ROOT;
  return mWeakAccessible->get_accDescription(varChild, pszDescription);
}

HRESULT
LazyInstantiator::get_accRole(VARIANT varChild, VARIANT* pvarRole) {
  if (!pvarRole) {
    return E_INVALIDARG;
  }

  if (V_VT(&varChild) == VT_I4 && V_I4(&varChild) == CHILDID_SELF) {
    V_VT(pvarRole) = VT_I4;
    V_I4(pvarRole) = ROLE_SYSTEM_APPLICATION;
    return S_OK;
  }

  RESOLVE_ROOT;
  return mWeakAccessible->get_accRole(varChild, pvarRole);
}

HRESULT
LazyInstantiator::get_accState(VARIANT varChild, VARIANT* pvarState) {
  if (!pvarState) {
    return E_INVALIDARG;
  }

  RESOLVE_ROOT;
  return mWeakAccessible->get_accState(varChild, pvarState);
}

HRESULT
LazyInstantiator::get_accHelp(VARIANT varChild, BSTR* pszHelp) {
  return E_NOTIMPL;
}

HRESULT
LazyInstantiator::get_accHelpTopic(BSTR* pszHelpFile, VARIANT varChild,
                                   long* pidTopic) {
  return E_NOTIMPL;
}

HRESULT
LazyInstantiator::get_accKeyboardShortcut(VARIANT varChild,
                                          BSTR* pszKeyboardShortcut) {
  if (!pszKeyboardShortcut) {
    return E_INVALIDARG;
  }

  RESOLVE_ROOT;
  return mWeakAccessible->get_accKeyboardShortcut(varChild,
                                                  pszKeyboardShortcut);
}

HRESULT
LazyInstantiator::get_accFocus(VARIANT* pvarChild) {
  if (!pvarChild) {
    return E_INVALIDARG;
  }

  RESOLVE_ROOT;
  return mWeakAccessible->get_accFocus(pvarChild);
}

HRESULT
LazyInstantiator::get_accSelection(VARIANT* pvarChildren) {
  if (!pvarChildren) {
    return E_INVALIDARG;
  }

  RESOLVE_ROOT;
  return mWeakAccessible->get_accSelection(pvarChildren);
}

HRESULT
LazyInstantiator::get_accDefaultAction(VARIANT varChild,
                                       BSTR* pszDefaultAction) {
  if (!pszDefaultAction) {
    return E_INVALIDARG;
  }

  RESOLVE_ROOT;
  return mWeakAccessible->get_accDefaultAction(varChild, pszDefaultAction);
}

HRESULT
LazyInstantiator::accSelect(long flagsSelect, VARIANT varChild) {
  RESOLVE_ROOT;
  return mWeakAccessible->accSelect(flagsSelect, varChild);
}

HRESULT
LazyInstantiator::accLocation(long* pxLeft, long* pyTop, long* pcxWidth,
                              long* pcyHeight, VARIANT varChild) {
  RESOLVE_ROOT;
  return mWeakAccessible->accLocation(pxLeft, pyTop, pcxWidth, pcyHeight,
                                      varChild);
}

HRESULT
LazyInstantiator::accNavigate(long navDir, VARIANT varStart,
                              VARIANT* pvarEndUpAt) {
  if (!pvarEndUpAt) {
    return E_INVALIDARG;
  }

  RESOLVE_ROOT;
  return mWeakAccessible->accNavigate(navDir, varStart, pvarEndUpAt);
}

HRESULT
LazyInstantiator::accHitTest(long xLeft, long yTop, VARIANT* pvarChild) {
  if (!pvarChild) {
    return E_INVALIDARG;
  }

  RESOLVE_ROOT;
  return mWeakAccessible->accHitTest(xLeft, yTop, pvarChild);
}

HRESULT
LazyInstantiator::accDoDefaultAction(VARIANT varChild) {
  RESOLVE_ROOT;
  return mWeakAccessible->accDoDefaultAction(varChild);
}

HRESULT
LazyInstantiator::put_accName(VARIANT varChild, BSTR szName) {
  return E_NOTIMPL;
}

HRESULT
LazyInstantiator::put_accValue(VARIANT varChild, BSTR szValue) {
  return E_NOTIMPL;
}

static const GUID kUnsupportedServices[] = {
    // clang-format off
  // Unknown, queried by Windows on devices with touch screens or similar devices
  // connected.
  {0x33f139ee, 0xe509, 0x47f7, {0xbf, 0x39, 0x83, 0x76, 0x44, 0xf7, 0x45, 0x76}},
  // Unknown, queried by Windows
  {0xFDA075CF, 0x7C8B, 0x498C, { 0xB5, 0x14, 0xA9, 0xCB, 0x52, 0x1B, 0xBF, 0xB4 }},
  // Unknown, queried by Windows
  {0x8EDAA462, 0x21F4, 0x4C87, { 0xA0, 0x12, 0xB3, 0xCD, 0xA3, 0xAB, 0x01, 0xFC }},
  // Unknown, queried by Windows
  {0xacd46652, 0x829d, 0x41cb, { 0xa5, 0xfc, 0x17, 0xac, 0xf4, 0x36, 0x61, 0xac }},
  // SID_IsUIAutomationObject (undocumented), queried by Windows
  {0xb96fdb85, 0x7204, 0x4724, { 0x84, 0x2b, 0xc7, 0x05, 0x9d, 0xed, 0xb9, 0xd0 }},
  // IIS_IsOleaccProxy (undocumented), queried by Windows
  {0x902697FA, 0x80E4, 0x4560, {0x80, 0x2A, 0xA1, 0x3F, 0x22, 0xA6, 0x47, 0x09}},
  // IID_IHTMLElement, queried by JAWS
  {0x3050F1FF, 0x98B5, 0x11CF, {0xBB, 0x82, 0x00, 0xAA, 0x00, 0xBD, 0xCE, 0x0B}}
    // clang-format on
};

HRESULT
LazyInstantiator::QueryService(REFGUID aServiceId, REFIID aServiceIid,
                               void** aOutInterface) {
  if (!aOutInterface) {
    return E_INVALIDARG;
  }

  for (const GUID& unsupportedService : kUnsupportedServices) {
    if (aServiceId == unsupportedService) {
      return E_NOINTERFACE;
    }
  }

  *aOutInterface = nullptr;

  RESOLVE_ROOT;

  RefPtr<IServiceProvider> servProv;
  HRESULT hr = mRealRootUnk->QueryInterface(IID_IServiceProvider,
                                            getter_AddRefs(servProv));
  if (FAILED(hr)) {
    return hr;
  }

  return servProv->QueryService(aServiceId, aServiceIid, aOutInterface);
}

STDMETHODIMP
LazyInstantiator::get_ProviderOptions(
    __RPC__out enum ProviderOptions* aOptions) {
  // This method is called before a UIA connection is fully established and thus
  // before we can detect the client. We must not call RESOLVE_ROOT here because
  // this might turn out to be a client we want to block.
  if (!aOptions) {
    return E_INVALIDARG;
  }
  *aOptions = uiaRawElmProvider::kProviderOptions;
  return S_OK;
}

STDMETHODIMP
LazyInstantiator::GetPatternProvider(
    PATTERNID aPatternId, __RPC__deref_out_opt IUnknown** aPatternProvider) {
  RESOLVE_ROOT;
  return mWeakUia->GetPatternProvider(aPatternId, aPatternProvider);
}

STDMETHODIMP
LazyInstantiator::GetPropertyValue(PROPERTYID aPropertyId,
                                   __RPC__out VARIANT* aPropertyValue) {
  RESOLVE_ROOT;
  return mWeakUia->GetPropertyValue(aPropertyId, aPropertyValue);
}

STDMETHODIMP
LazyInstantiator::get_HostRawElementProvider(
    __RPC__deref_out_opt IRawElementProviderSimple** aRawElmProvider) {
  // This method is called before a UIA connection is fully established and thus
  // before we can detect the client. We must not call RESOLVE_ROOT here because
  // this might turn out to be a client we want to block.
  if (!aRawElmProvider) {
    return E_INVALIDARG;
  }
  *aRawElmProvider = nullptr;
  return UiaHostProviderFromHwnd(mHwnd, aRawElmProvider);
}

}  // namespace a11y
}  // namespace mozilla

Messung V0.5
C=93 H=98 G=95

¤ Dauer der Verarbeitung: 0.29 Sekunden  (vorverarbeitet)  ¤

*© Formatika GbR, Deutschland






Wurzel

Suchen

Beweissystem der NASA

Beweissystem Isabelle

NIST Cobol Testsuite

Cephes Mathematical Library

Wiener Entwicklungsmethode

Haftungshinweis

Die Informationen auf dieser Webseite wurden nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit, noch Qualität der bereit gestellten Informationen zugesichert.

Bemerkung:

Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.