Backed out changeset 0724fde82b2f (bug 1838123) for causing build bustages. CLOSED TREE

This commit is contained in:
Iulian Moraru 2023-07-13 07:35:44 +03:00
Родитель b9171ec2f1
Коммит 1cfd3a3bc7
7 изменённых файлов: 434 добавлений и 125 удалений

Просмотреть файл

@ -8,7 +8,7 @@
#define COMPATIBILITY_MANAGER_H
#include <windows.h>
#include "nsTArray.h"
#include "mozilla/Maybe.h"
#include "nsString.h"
#include <stdint.h>
@ -60,7 +60,9 @@ class Compatibility {
*/
static void Init();
static void GetUiaClientPids(nsTArray<DWORD>& aPids);
static Maybe<bool> OnUIAMessage(WPARAM aWParam, LPARAM aLParam);
static Maybe<DWORD> GetUiaRemotePid() { return sUiaRemotePid; }
/**
* return true if a known, non-UIA a11y consumer is present
@ -110,6 +112,7 @@ class Compatibility {
private:
static uint32_t sConsumers;
static Maybe<DWORD> sUiaRemotePid;
};
} // namespace a11y

Просмотреть файл

@ -7,30 +7,201 @@
#include "Compatibility.h"
#include "mozilla/a11y/Platform.h"
#include "mozilla/ScopeExit.h"
#include "mozilla/Telemetry.h"
#include "mozilla/UniquePtrExtensions.h"
#include "mozilla/WindowsVersion.h"
#include "mozilla/UniquePtr.h"
#include "nsdefs.h"
#include "nspr/prenv.h"
#include "nsIFile.h"
#include "nsTHashMap.h"
#include "nsTHashSet.h"
#include "nsPrintfCString.h"
#include "nsReadableUtils.h"
#include "nsString.h"
#include "nsTHashtable.h"
#include "nsUnicharUtils.h"
#include "nsWindowsHelpers.h"
#include "nsWinUtils.h"
#include "NtUndoc.h"
#if defined(UIA_LOGGING)
# define LOG_ERROR(FuncName) \
{ \
DWORD err = ::GetLastError(); \
nsPrintfCString msg(#FuncName " failed with code %u\n", err); \
::OutputDebugStringA(msg.get()); \
}
#else
# define LOG_ERROR(FuncName)
#endif // defined(UIA_LOGGING)
using namespace mozilla;
struct ByteArrayDeleter {
void operator()(void* aBuf) { delete[] reinterpret_cast<char*>(aBuf); }
};
typedef UniquePtr<OBJECT_DIRECTORY_INFORMATION, ByteArrayDeleter> ObjDirInfoPtr;
// ComparatorFnT returns true to continue searching, or else false to indicate
// search completion.
template <typename ComparatorFnT>
static bool FindNamedObject(const ComparatorFnT& aComparator) {
// We want to enumerate every named kernel object in our session. We do this
// by opening a directory object using a path constructed using the session
// id under which our process resides.
DWORD sessionId;
if (!::ProcessIdToSessionId(::GetCurrentProcessId(), &sessionId)) {
return false;
}
nsAutoString path;
path.AppendPrintf("\\Sessions\\%lu\\BaseNamedObjects", sessionId);
UNICODE_STRING baseNamedObjectsName;
::RtlInitUnicodeString(&baseNamedObjectsName, path.get());
OBJECT_ATTRIBUTES attributes;
InitializeObjectAttributes(&attributes, &baseNamedObjectsName, 0, nullptr,
nullptr);
HANDLE rawBaseNamedObjects;
NTSTATUS ntStatus = ::NtOpenDirectoryObject(
&rawBaseNamedObjects, DIRECTORY_QUERY | DIRECTORY_TRAVERSE, &attributes);
if (!NT_SUCCESS(ntStatus)) {
return false;
}
nsAutoHandle baseNamedObjects(rawBaseNamedObjects);
ULONG context = 0, returnedLen;
ULONG objDirInfoBufLen = 1024 * sizeof(OBJECT_DIRECTORY_INFORMATION);
ObjDirInfoPtr objDirInfo(reinterpret_cast<OBJECT_DIRECTORY_INFORMATION*>(
new char[objDirInfoBufLen]));
// Now query that directory object for every named object that it contains.
BOOL firstCall = TRUE;
do {
ntStatus = ::NtQueryDirectoryObject(baseNamedObjects, objDirInfo.get(),
objDirInfoBufLen, FALSE, firstCall,
&context, &returnedLen);
#if defined(HAVE_64BIT_BUILD)
if (!NT_SUCCESS(ntStatus)) {
return false;
}
#else
if (ntStatus == STATUS_BUFFER_TOO_SMALL) {
// This case only occurs on 32-bit builds running atop WOW64.
// (See https://bugzilla.mozilla.org/show_bug.cgi?id=1423999#c3)
objDirInfo.reset(reinterpret_cast<OBJECT_DIRECTORY_INFORMATION*>(
new char[returnedLen]));
objDirInfoBufLen = returnedLen;
continue;
} else if (!NT_SUCCESS(ntStatus)) {
return false;
}
#endif
// NtQueryDirectoryObject gave us an array of OBJECT_DIRECTORY_INFORMATION
// structures whose final entry is zeroed out.
OBJECT_DIRECTORY_INFORMATION* curDir = objDirInfo.get();
while (curDir->mName.Length && curDir->mTypeName.Length) {
// We use nsDependentSubstring here because UNICODE_STRINGs are not
// guaranteed to be null-terminated.
nsDependentSubstring objName(curDir->mName.Buffer,
curDir->mName.Length / sizeof(wchar_t));
nsDependentSubstring typeName(curDir->mTypeName.Buffer,
curDir->mTypeName.Length / sizeof(wchar_t));
if (!aComparator(objName, typeName)) {
return true;
}
++curDir;
}
firstCall = FALSE;
} while (ntStatus == STATUS_MORE_ENTRIES);
return false;
}
static const char* gBlockedUiaClients[] = {"osk.exe"};
static bool ShouldBlockUIAClient(nsIFile* aClientExe) {
if (PR_GetEnv("MOZ_DISABLE_ACCESSIBLE_BLOCKLIST")) {
return false;
}
nsAutoString leafName;
nsresult rv = aClientExe->GetLeafName(leafName);
if (NS_FAILED(rv)) {
return false;
}
for (size_t index = 0, len = ArrayLength(gBlockedUiaClients); index < len;
++index) {
if (leafName.EqualsIgnoreCase(gBlockedUiaClients[index])) {
return true;
}
}
return false;
}
namespace mozilla {
namespace a11y {
void Compatibility::GetUiaClientPids(nsTArray<DWORD>& aPids) {
if (!::GetModuleHandleW(L"uiautomationcore.dll")) {
// UIAutomationCore isn't loaded, so there is no UIA client.
return;
}
Maybe<DWORD> Compatibility::sUiaRemotePid;
Maybe<bool> Compatibility::OnUIAMessage(WPARAM aWParam, LPARAM aLParam) {
auto clearUiaRemotePid = MakeScopeExit([]() { sUiaRemotePid = Nothing(); });
Telemetry::AutoTimer<Telemetry::A11Y_UIA_DETECTION_TIMING_MS> timer;
// UIA creates a section containing the substring "HOOK_SHMEM_"
constexpr auto kStrHookShmem = u"HOOK_SHMEM_"_ns;
// The section name always ends with this suffix, which is derived from the
// current thread id and the UIA message's WPARAM and LPARAM.
nsAutoString partialSectionSuffix;
partialSectionSuffix.AppendPrintf("_%08lx_%08" PRIxLPTR "_%08zx",
::GetCurrentThreadId(), aLParam, aWParam);
// Find any named Section that matches the naming convention of the UIA shared
// memory.
nsAutoHandle section;
auto comparator = [&](const nsDependentSubstring& aName,
const nsDependentSubstring& aType) -> bool {
if (aType.Equals(u"Section"_ns) && FindInReadable(kStrHookShmem, aName) &&
StringEndsWith(aName, partialSectionSuffix)) {
section.own(::OpenFileMapping(GENERIC_READ, FALSE,
PromiseFlatString(aName).get()));
return false;
}
return true;
};
if (!FindNamedObject(comparator) || !section) {
return Nothing();
}
NTSTATUS ntStatus;
// First we must query for a list of all the open handles in the system.
UniquePtr<std::byte[]> handleInfoBuf;
UniquePtr<char[]> handleInfoBuf;
ULONG handleInfoBufLen = sizeof(SYSTEM_HANDLE_INFORMATION_EX) +
1024 * sizeof(SYSTEM_HANDLE_TABLE_ENTRY_INFO_EX);
@ -40,9 +211,9 @@ void Compatibility::GetUiaClientPids(nsTArray<DWORD>& aPids) {
while (true) {
// These allocations can be hundreds of megabytes on some computers, so
// we should use fallible new here.
handleInfoBuf = MakeUniqueFallible<std::byte[]>(handleInfoBufLen);
handleInfoBuf = MakeUniqueFallible<char[]>(handleInfoBufLen);
if (!handleInfoBuf) {
return;
return Nothing();
}
ntStatus = ::NtQuerySystemInformation(
@ -53,56 +224,121 @@ void Compatibility::GetUiaClientPids(nsTArray<DWORD>& aPids) {
}
if (!NT_SUCCESS(ntStatus)) {
return;
return Nothing();
}
break;
}
const DWORD ourPid = ::GetCurrentProcessId();
Maybe<PVOID> kernelObject;
static Maybe<USHORT> sectionObjTypeIndex;
nsTHashSet<uint32_t> nonSectionObjTypes;
nsTHashMap<nsVoidPtrHashKey, DWORD> objMap;
auto handleInfo =
reinterpret_cast<SYSTEM_HANDLE_INFORMATION_EX*>(handleInfoBuf.get());
for (ULONG index = 0; index < handleInfo->mHandleCount; ++index) {
SYSTEM_HANDLE_TABLE_ENTRY_INFO_EX& curHandle = handleInfo->mHandles[index];
if (curHandle.mPid != ourPid) {
// We're only interested in handles in our own process.
continue;
}
HANDLE handle = reinterpret_cast<HANDLE>(curHandle.mHandle);
// Get the name of the handle.
ULONG objNameBufLen;
ntStatus =
::NtQueryObject(handle, (OBJECT_INFORMATION_CLASS)ObjectNameInformation,
nullptr, 0, &objNameBufLen);
if (ntStatus != STATUS_INFO_LENGTH_MISMATCH) {
// The mapping of the curHandle.mObjectTypeIndex field depends on the
// underlying OS kernel. As we scan through the handle list, we record the
// type indices such that we may use those values to skip over handles that
// refer to non-section objects.
if (sectionObjTypeIndex) {
// If we know the type index for Sections, that's the fastest check...
if (sectionObjTypeIndex.value() != curHandle.mObjectTypeIndex) {
// Not a section
continue;
}
} else if (nonSectionObjTypes.Contains(
static_cast<uint32_t>(curHandle.mObjectTypeIndex))) {
// Otherwise we check whether or not the object type is definitely _not_
// a Section...
continue;
}
auto objNameBuf = MakeUnique<std::byte[]>(objNameBufLen);
ntStatus =
::NtQueryObject(handle, (OBJECT_INFORMATION_CLASS)ObjectNameInformation,
objNameBuf.get(), objNameBufLen, &objNameBufLen);
if (!NT_SUCCESS(ntStatus)) {
continue;
}
auto objNameInfo =
reinterpret_cast<OBJECT_NAME_INFORMATION*>(objNameBuf.get());
if (!objNameInfo->mName.Length) {
continue;
}
nsDependentString objName(objNameInfo->mName.Buffer,
objNameInfo->mName.Length / sizeof(wchar_t));
} else if (ourPid == curHandle.mPid) {
// Otherwise we need to issue some system calls to find out the object
// type corresponding to the current handle's type index.
ULONG objTypeBufLen;
ntStatus = ::NtQueryObject(handle, ObjectTypeInformation, nullptr, 0,
&objTypeBufLen);
if (ntStatus != STATUS_INFO_LENGTH_MISMATCH) {
continue;
}
// UIA creates a named pipe between the client and server processes. Find
// our handle to that pipe (if any).
if (StringBeginsWith(objName, u"\\Device\\NamedPipe\\UIA_PIPE_"_ns)) {
// Get the process id of the remote end. Counter-intuitively, for this
// pipe, we're the client and the remote process is the server.
ULONG pid = 0;
::GetNamedPipeServerProcessId(handle, &pid);
aPids.AppendElement(pid);
auto objTypeBuf = MakeUnique<char[]>(objTypeBufLen);
ntStatus =
::NtQueryObject(handle, ObjectTypeInformation, objTypeBuf.get(),
objTypeBufLen, &objTypeBufLen);
if (!NT_SUCCESS(ntStatus)) {
continue;
}
auto objType =
reinterpret_cast<PUBLIC_OBJECT_TYPE_INFORMATION*>(objTypeBuf.get());
// Now we check whether the object's type name matches "Section"
nsDependentSubstring objTypeName(
objType->TypeName.Buffer, objType->TypeName.Length / sizeof(wchar_t));
if (!objTypeName.Equals(u"Section"_ns)) {
nonSectionObjTypes.Insert(
static_cast<uint32_t>(curHandle.mObjectTypeIndex));
continue;
}
sectionObjTypeIndex = Some(curHandle.mObjectTypeIndex);
}
// At this point we know that curHandle references a Section object.
// Now we can do some actual tests on it.
if (ourPid != curHandle.mPid) {
if (kernelObject && kernelObject.value() == curHandle.mObject) {
// The kernel objects match -- we have found the remote pid!
sUiaRemotePid = Some(curHandle.mPid);
break;
}
// An object that is not ours. Since we do not yet know which kernel
// object we're interested in, we'll save the current object for later.
objMap.InsertOrUpdate(curHandle.mObject, curHandle.mPid);
} else if (handle == section.get()) {
// This is the file mapping that we opened above. We save this mObject
// in order to compare to Section objects opened by other processes.
kernelObject = Some(curHandle.mObject);
}
}
if (!kernelObject) {
return Nothing();
}
if (!sUiaRemotePid) {
// We found kernelObject *after* we saw the remote process's copy. Now we
// must look it up in objMap.
DWORD pid;
if (objMap.Get(kernelObject.value(), &pid)) {
sUiaRemotePid = Some(pid);
}
}
if (!sUiaRemotePid) {
return Nothing();
}
a11y::SetInstantiator(sUiaRemotePid.value());
// Block if necessary
nsCOMPtr<nsIFile> instantiator;
if (a11y::GetInstantiator(getter_AddRefs(instantiator)) &&
ShouldBlockUIAClient(instantiator)) {
return Some(false);
}
return Some(true);
}
} // namespace a11y

Просмотреть файл

@ -39,8 +39,6 @@ namespace a11y {
static const wchar_t kLazyInstantiatorProp[] =
L"mozilla::a11y::LazyInstantiator";
Maybe<bool> LazyInstantiator::sShouldBlockUia;
/* static */
already_AddRefed<IAccessible> LazyInstantiator::GetRootAccessible(HWND aHwnd) {
RefPtr<IAccessible> result;
@ -152,15 +150,16 @@ void LazyInstantiator::ClearProp() {
}
/**
* Get the process id of a remote (out-of-process) MSAA/IA2 client.
* Given the remote client's thread ID, resolve its process ID.
*/
DWORD LazyInstantiator::GetRemoteMsaaClientPid() {
DWORD
LazyInstantiator::GetClientPid(const DWORD aClientTid) {
nsAutoHandle callingThread(
::OpenThread(THREAD_QUERY_LIMITED_INFORMATION, FALSE,
mscom::ProcessRuntime::GetClientThreadId()));
::OpenThread(THREAD_QUERY_LIMITED_INFORMATION, FALSE, aClientTid));
if (!callingThread) {
return 0;
}
return ::GetProcessIdOfThread(callingThread);
}
@ -171,7 +170,6 @@ 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
};
/**
@ -186,6 +184,11 @@ bool LazyInstantiator::IsBlockedInjection() {
return false;
}
if (Compatibility::HasKnownNonUiaConsumer()) {
// If we already see a known AT, don't block a11y instantiation
return false;
}
for (size_t index = 0, len = ArrayLength(gBlockedInprocDlls); index < len;
++index) {
const DllBlockInfo& blockedDll = gBlockedInprocDlls[index];
@ -203,14 +206,30 @@ bool LazyInstantiator::IsBlockedInjection() {
}
/**
* Given a remote client's process ID, determine whether we should proceed with
* Given a remote client's thread 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);
bool LazyInstantiator::ShouldInstantiate(const DWORD aClientTid) {
if (Compatibility::IsA11ySuppressedForClipboardCopy()) {
// Bug 1774285: Windows Suggested Actions (introduced in Windows 11 22H2)
// walks the entire a11y tree using UIA whenever anything is copied to the
// clipboard. This causes an unacceptable hang, particularly when the cache
// is disabled. Don't allow a11y to be instantiated by this.
return false;
}
if (!aClientTid) {
// aClientTid == 0 implies that this is either an in-process call, or else
// we failed to retrieve information about the remote caller.
// We should always default to instantiating a11y in this case, provided
// that we don't see any known bad injected DLLs.
return !IsBlockedInjection();
}
a11y::SetInstantiator(GetClientPid(aClientTid));
nsCOMPtr<nsIFile> clientExe;
if (!a11y::GetInstantiator(getter_AddRefs(clientExe))) {
@ -236,57 +255,6 @@ bool LazyInstantiator::ShouldInstantiate(const DWORD aClientPid) {
return true;
}
/**
* Determine whether we should proceed with a11y instantiation, considering the
* various different types of clients.
*/
bool LazyInstantiator::ShouldInstantiate() {
if (Compatibility::IsA11ySuppressedForClipboardCopy()) {
// Bug 1774285: Windows Suggested Actions (introduced in Windows 11 22H2)
// walks the entire a11y tree using UIA whenever anything is copied to the
// clipboard. This causes an unacceptable hang, particularly when the cache
// is disabled. Don't allow a11y to be instantiated by this.
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)) {
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()) {
@ -346,7 +314,8 @@ LazyInstantiator::MaybeResolveRoot() {
return S_OK;
}
if (GetAccService() || ShouldInstantiate()) {
if (GetAccService() ||
ShouldInstantiate(mscom::ProcessRuntime::GetClientThreadId())) {
mWeakMsaaRoot = ResolveMsaaRoot();
if (!mWeakMsaaRoot) {
return E_POINTER;

Просмотреть файл

@ -8,7 +8,6 @@
#define mozilla_a11y_LazyInstantiator_h
#include "IUnknownImpl.h"
#include "mozilla/Maybe.h"
#include "mozilla/RefPtr.h"
#include "nsString.h"
@ -83,25 +82,14 @@ class LazyInstantiator final : public IAccessible, public IServiceProvider {
STDMETHODIMP QueryService(REFGUID aServiceId, REFIID aServiceIid,
void** aOutInterface) override;
/**
* 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();
bool ShouldInstantiate(const DWORD aClientTid);
DWORD GetRemoteMsaaClientPid();
DWORD GetClientPid(const DWORD aClientTid);
/**
* @return S_OK if we have a valid mRealRoot to invoke methods on
@ -133,7 +121,6 @@ class LazyInstantiator final : public IAccessible, public IServiceProvider {
MsaaRootAccessible* mWeakMsaaRoot;
IAccessible* mWeakAccessible;
IDispatch* mWeakDispatch;
static Maybe<bool> sShouldBlockUia;
};
} // namespace a11y

Просмотреть файл

@ -390,6 +390,79 @@ nsAppShell::~nsAppShell() {
sOutstandingNativeEventCallbacks = 0;
}
#if defined(ACCESSIBILITY)
static ULONG gUiaMsg;
static HHOOK gUiaHook;
static uint32_t gUiaAttempts;
static const uint32_t kMaxUiaAttempts = 5;
static void InitUIADetection();
static LRESULT CALLBACK UiaHookProc(int aCode, WPARAM aWParam, LPARAM aLParam) {
if (aCode < 0) {
return ::CallNextHookEx(nullptr, aCode, aWParam, aLParam);
}
auto cwp = reinterpret_cast<CWPSTRUCT*>(aLParam);
if (gUiaMsg && cwp->message == gUiaMsg) {
if (gUiaAttempts < kMaxUiaAttempts) {
++gUiaAttempts;
Maybe<bool> shouldCallNextHook =
a11y::Compatibility::OnUIAMessage(cwp->wParam, cwp->lParam);
if (shouldCallNextHook.isSome()) {
// We've got an instantiator.
if (!shouldCallNextHook.value()) {
// We're blocking this instantiation. We need to keep this hook set
// so that we can catch any future instantiation attempts.
return 0;
}
// We're allowing the instantiator to proceed, so this hook is no longer
// needed.
if (::UnhookWindowsHookEx(gUiaHook)) {
gUiaHook = nullptr;
}
} else {
// Our hook might be firing after UIA; let's try reinstalling ourselves.
InitUIADetection();
}
} else {
// We've maxed out our attempts. Let's unhook.
if (::UnhookWindowsHookEx(gUiaHook)) {
gUiaHook = nullptr;
}
}
}
return ::CallNextHookEx(nullptr, aCode, aWParam, aLParam);
}
static void InitUIADetection() {
if (gUiaHook) {
// In this case we want to re-hook so that the hook is always called ahead
// of UIA's hook.
if (::UnhookWindowsHookEx(gUiaHook)) {
gUiaHook = nullptr;
}
}
if (!gUiaMsg) {
// This is the message that UIA sends to trigger a command. UIA's
// CallWndProc looks for this message and then handles the request.
// Our hook gets in front of UIA's hook and examines the message first.
gUiaMsg = ::RegisterWindowMessageW(L"HOOKUTIL_MSG");
}
if (!gUiaHook) {
gUiaHook = ::SetWindowsHookEx(WH_CALLWNDPROC, &UiaHookProc, nullptr,
::GetCurrentThreadId());
}
}
#endif // defined(ACCESSIBILITY)
NS_IMETHODIMP
nsAppShell::Observe(nsISupports* aSubject, const char* aTopic,
const char16_t* aData) {
@ -397,6 +470,25 @@ nsAppShell::Observe(nsISupports* aSubject, const char* aTopic,
nsCOMPtr<nsIObserverService> obsServ(
mozilla::services::GetObserverService());
#if defined(ACCESSIBILITY)
if (!strcmp(aTopic, "dll-loaded-main-thread")) {
if (a11y::PlatformDisabledState() != a11y::ePlatformIsDisabled &&
!gUiaHook) {
nsDependentString dllName(aData);
if (StringEndsWith(dllName, u"uiautomationcore.dll"_ns,
nsCaseInsensitiveStringComparator)) {
InitUIADetection();
// Now that we've handled the observer notification, we can remove it
obsServ->RemoveObserver(this, "dll-loaded-main-thread");
}
}
return NS_OK;
}
#endif // defined(ACCESSIBILITY)
if (!strcmp(aTopic, "sessionstore-restoring-on-startup")) {
nsWindow::SetIsRestoringSession(true);
// Now that we've handled the observer notification, we can remove it
@ -488,6 +580,14 @@ nsresult nsAppShell::Init() {
obsServ->AddObserver(this, "sessionstore-restoring-on-startup", false);
obsServ->AddObserver(this, "sessionstore-windows-restored", false);
#if defined(ACCESSIBILITY)
if (::GetModuleHandleW(L"uiautomationcore.dll")) {
InitUIADetection();
} else {
obsServ->AddObserver(this, "dll-loaded-main-thread", false);
}
#endif // defined(ACCESSIBILITY)
}
if (!WinUtils::GetTimezoneName(mTimezoneName)) {
@ -530,6 +630,23 @@ nsAppShell::Run(void) {
return rv;
}
NS_IMETHODIMP
nsAppShell::Exit(void) {
#if defined(ACCESSIBILITY)
if (XRE_IsParentProcess()) {
nsCOMPtr<nsIObserverService> obsServ(
mozilla::services::GetObserverService());
obsServ->RemoveObserver(this, "dll-loaded-main-thread");
if (gUiaHook && ::UnhookWindowsHookEx(gUiaHook)) {
gUiaHook = nullptr;
}
}
#endif // defined(ACCESSIBILITY)
return nsBaseAppShell::Exit();
}
void nsAppShell::DoProcessMoreGeckoEvents() {
// Called by nsBaseAppShell's NativeEventCallback() after it has finished
// processing pending gecko events and there are still gecko events pending

Просмотреть файл

@ -39,6 +39,7 @@ class nsAppShell : public nsBaseAppShell {
protected:
NS_IMETHOD Run() override;
NS_IMETHOD Exit() override;
NS_IMETHOD Observe(nsISupports* aSubject, const char* aTopic,
const char16_t* aData) override;

Просмотреть файл

@ -6132,10 +6132,6 @@ bool nsWindow::ProcessMessageInternal(UINT msg, WPARAM& wParam, LPARAM& lParam,
DispatchInputEvent(&event);
if (sSwitchKeyboardLayout && mLastKeyboardLayout)
ActivateKeyboardLayout(mLastKeyboardLayout, 0);
#ifdef ACCESSIBILITY
a11y::LazyInstantiator::ResetUiaDetectionCache();
#endif
}
}
} break;