Skip to content

Commit 258c421

Browse files
authored
Merge 5afa213 into b817b03
2 parents b817b03 + 5afa213 commit 258c421

5 files changed

Lines changed: 70 additions & 9 deletions

File tree

source/UIAHandler/__init__.py

Lines changed: 11 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -814,21 +814,23 @@ def _isUIAWindowHelper(self,hwnd):
814814
and not config.conf['UIA']['useInMSExcelWhenAvailable']
815815
):
816816
return False
817-
# Unless explicitly allowed, all Chromium implementations (including Edge) should not be UIA,
818-
# As their IA2 implementation is still better at the moment.
819-
elif (
820-
windowClass == "Chrome_RenderWidgetHostHWND"
821-
and (
817+
elif windowClass == "Chrome_RenderWidgetHostHWND":
818+
# Unless explicitly allowed, all Chromium implementations (including Edge) should not be UIA,
819+
# As their IA2 implementation is still better at the moment.
820+
# However, in cases where Chromium is running under another logon session,
821+
# the IAccessible2 implementation is unavailable.
822+
hasAccessToIA2 = not appModule.isRunningUnderDifferentLogonSession
823+
if (
822824
AllowUiaInChromium.getConfig() == AllowUiaInChromium.NO
823825
# Disabling is only useful if we can inject in-process (and use our older code)
824826
or (
825827
canUseOlderInProcessApproach
828+
and hasAccessToIA2
826829
and AllowUiaInChromium.getConfig() != AllowUiaInChromium.YES # Users can prefer to use UIA
827830
)
828-
)
829-
):
830-
return False
831-
if windowClass == "ConsoleWindowClass":
831+
):
832+
return False
833+
elif windowClass == "ConsoleWindowClass":
832834
return utils._shouldUseUIAConsole(hwnd)
833835
return bool(res)
834836

source/appModuleHandler.py

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,7 @@
4444
import extensionPoints
4545
from fileUtils import getFileVersionInfo
4646
import globalVars
47+
from systemUtils import getProcessTokenOrigin
4748

4849

4950
_KNOWN_IMPORTERS_T = Union[importlib.machinery.FileFinder, zipimport.zipimporter]
@@ -666,6 +667,21 @@ def _get_isWindowsStoreApp(self):
666667
self.isWindowsStoreApp = False
667668
return self.isWindowsStoreApp
668669

670+
def _get_isRunningUnderDifferentLogonSession(self) -> bool:
671+
"""Returns whether the application for this appModule was started under a different logon session.
672+
This applies to applications started with the Windows runas command
673+
or when choosing "run as a different user" from an application's (shortcut) context menu.
674+
"""
675+
try:
676+
self.isRunningUnderDifferentLogonSession = (
677+
globalVars.appLogonSessionID != 0
678+
and globalVars.appLogonSessionID != getProcessTokenOrigin(self.processHandle)
679+
)
680+
except WindowsError:
681+
log.error(f"Couldn't get logon session ID for {self}", exc_info=True)
682+
self.isRunningUnderDifferentLogonSession = False
683+
return self.isRunningUnderDifferentLogonSession
684+
669685
def _get_appArchitecture(self):
670686
"""Returns the target architecture for the specified app.
671687
This is useful for detecting X86/X64 apps running on ARM64 releases of Windows 10.

source/globalVars.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -70,6 +70,10 @@ class DefaultAppArgs(argparse.Namespace):
7070
"""The process ID of NVDA itself.
7171
"""
7272

73+
appLogonSessionID: int = 0
74+
"""The logon session ID under which NVDA was started.
75+
"""
76+
7377
_allowDeprecatedAPI: bool = True
7478
"""
7579
Used for marking code as deprecated.

source/nvda.pyw

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -77,6 +77,15 @@ import logHandler
7777
from logHandler import log
7878
import winUser
7979
import winKernel
80+
# Avoid a E402 'module level import not at top of file' warning,
81+
# because monkeypatches need to be applied first first
82+
from systemUtils import getProcessTokenOrigin # noqa: E402
83+
84+
try:
85+
globalVars.appLogonSessionID = getProcessTokenOrigin(winKernel.GetCurrentProcess())
86+
except WindowsError:
87+
log.error("Couldn't get NVDAProcessLogonSessionID", exc_info=True)
88+
8089

8190
# Find out if NVDA is running as a Windows Store application
8291
bufLen=ctypes.c_int()

source/systemUtils.py

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,36 @@ def hasUiAccess():
6363
ctypes.windll.kernel32.CloseHandle(token)
6464

6565

66+
TokenOrigin = 17
67+
68+
69+
class TOKEN_ORIGIN(ctypes.Structure):
70+
_fields_ = [("OriginatingLogonSession", ctypes.c_ulonglong)]
71+
72+
73+
def getProcessTokenOrigin(processHandle):
74+
token = ctypes.wintypes.HANDLE()
75+
if not ctypes.windll.advapi32.OpenProcessToken(
76+
processHandle,
77+
winKernel.MAXIMUM_ALLOWED,
78+
ctypes.byref(token)
79+
):
80+
raise ctypes.WinError()
81+
try:
82+
val = TOKEN_ORIGIN()
83+
if not ctypes.windll.advapi32.GetTokenInformation(
84+
token,
85+
TokenOrigin,
86+
ctypes.byref(val),
87+
ctypes.sizeof(val),
88+
ctypes.byref(ctypes.wintypes.DWORD())
89+
):
90+
raise ctypes.WinError()
91+
return val.OriginatingLogonSession
92+
finally:
93+
ctypes.windll.kernel32.CloseHandle(token)
94+
95+
6696
def execElevated(path, params=None, wait=False, handleAlreadyElevated=False):
6797
import subprocess
6898
if params is not None:

0 commit comments

Comments
 (0)