forked from nvaccess/nvda
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Repaired the COM Registration Fixing Tool so it is more effective on …
…64bit Windows (Partial fix of nvaccess#9039). Problems: - The registerServer function called the 32-bit version of regsvr32.exe, even in 64-bit contexts. - The applyRegistryPatch function called the 32-bit version of regedit, even in 64-bit contexts. - The Win7 32-bit run did not take into account 32-bit only systems (no Program Files (x86) folder). Remediation: - Replaced applyRegistryPatch function with two new functions: apply32bitRegistryPatch and apply64bitRegistryPatch. - Replaced registerServer function with register32bitServer and register64bitServer, to make clear what they do. - The new functions don't check 32/64 bitness; they leave that to the caller and log errors on failure. - Updated to more descriptive error logging. - Adjusted the Windows 7 code to use server registration with proper bitness for each DLL. Path remediations: - Moved the OLEACC_REG_FILE_PATH constant to the top of the file with the rest. - Added sysnative path to the list of path constants at the top of the file. - Now use Sysnative in the path for intentional 64bit calls. - Now use System32 in the path for 32-bit calls on either 32-bit or 64-bit systems. - Now use reg.exe's import option to load .reg files instead of regedit.exe. - Now check whether to use "Program Files" or "Program Files (x86)" on Win7. - Removed now unused sysWow64 path constant. Misc: - Added docstring note about 32 and 64 bit functions needing attention if NVDA goes 64-bit in the future. - Converted path constants to uppercase-with-underscore style, and corrected case on some Windows paths. - Moved comments with discussion links into module docstring, and rearranged. - Updated copyright. - In gui/__init__.py: added a recommendation that the user restart the computer, to the completion message.
- Loading branch information
Showing
2 changed files
with
94 additions
and
43 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,81 +1,126 @@ | ||
# A part of NonVisual Desktop Access (NVDA) | ||
# Copyright (C) 2018-2020 NV Access Limited | ||
# Copyright (C) 2018-2021 NV Access Limited, Luke Davis (Open Source Systems, Ltd.) | ||
# This file is covered by the GNU General Public License. | ||
# See the file COPYING for more details. | ||
|
||
"""Utilities to re-register particular system COM interfaces needed by NVDA.""" | ||
"""Utilities to re-register particular system COM interfaces needed by NVDA. | ||
Relevant discussions of DLLs, registry keys, and paths, can be found on these issues: | ||
https://github.com/nvaccess/nvda/issues/2807#issuecomment-320149243 | ||
https://github.com/nvaccess/nvda/issues/9039 | ||
https://github.com/nvaccess/nvda/issues/12560 | ||
""" | ||
|
||
import os | ||
import subprocess | ||
import winVersion | ||
import globalVars | ||
from logHandler import log | ||
|
||
OLEACC_REG_FILE_PATH = os.path.join(globalVars.appDir, "COMRegistrationFixes", "oleaccProxy.reg") | ||
# Particular 64 bit / 32 bit system paths | ||
systemRoot=os.path.expandvars('%SYSTEMROOT%') | ||
system32=os.path.join(systemRoot,'system32') | ||
sysWow64=os.path.join(systemRoot,'syswow64') | ||
systemDrive=os.path.expandvars('%SYSTEMDRIVE%\\') | ||
programFiles=os.path.join(systemDrive,'program files') | ||
programFilesX86=os.path.join(systemDrive,'program files (x86)') | ||
SYSTEM_ROOT = os.path.expandvars("%SYSTEMROOT%") | ||
SYSTEM32 = os.path.join(SYSTEM_ROOT, "System32") | ||
SYSNATIVE = os.path.join(SYSTEM_ROOT, "Sysnative") # Virtual folder for reaching 64-bit exes from 32-bit apps | ||
SYSTEM_DRIVE = os.path.expandvars("%SYSTEMDRIVE%\\") | ||
PROGRAM_FILES = os.path.join(SYSTEM_DRIVE, "Program Files") | ||
PROGRAM_FILES_X86 = os.path.join(SYSTEM_DRIVE, "Program Files (x86)") | ||
|
||
|
||
def registerServer(fileName,wow64=False): | ||
def register32bitServer(fileName: str) -> None: | ||
"""Registers the COM proxy dll with the given file name, using the 32-bit version of regsvr32. | ||
Note: this function is valid while NVDA remains a 32-bit app. Re-evaluate if we move to 64-bit. | ||
@param fileName: the path to the dll | ||
@type fileName: str | ||
""" | ||
Registers the COM proxy dll with the given file name | ||
Using regsvr32. | ||
# Points to the 32-bit version, on Windows 32-bit or 64-bit. | ||
regsvr32 = os.path.join(SYSTEM32, "regsvr32.exe") | ||
try: | ||
subprocess.check_call([regsvr32, "/s", fileName]) | ||
except subprocess.CalledProcessError as e: | ||
log.error(f"Error registering {fileName} in a 32-bit context: {e}") | ||
else: | ||
log.debug(f"Registered {fileName} in a 32-bit context.") | ||
|
||
|
||
def register64bitServer(fileName: str) -> None: | ||
"""Registers the COM proxy dll with the given file name, using the 64-bit version of regsvr64. | ||
Note: this function is valid while NVDA remains a 32-bit app. Re-evaluate if we move to 64-bit. | ||
@param fileName: the path to the dll | ||
@type fileName: str | ||
@param wow64: If true then the 32 bit (wow64) version of regsvr32 will be used. | ||
@type wow64: bool | ||
""" | ||
regsvr32=os.path.join(sysWow64 if wow64 else system32,'regsvr32.exe') | ||
# SysWOW64 provides a virtual directory to allow 32-bit programs to reach 64-bit executables. | ||
regsvr32 = os.path.join(SYSNATIVE, "regsvr32.exe") | ||
try: | ||
subprocess.check_call([regsvr32,'/s',fileName]) | ||
subprocess.check_call([regsvr32, "/s", fileName]) | ||
except subprocess.CalledProcessError as e: | ||
log.error("Error registering %s, %s"%(fileName,e)) | ||
log.error(f"Error registering {fileName} in a 64-bit context: {e}") | ||
else: | ||
log.debug("Registered %s"%fileName) | ||
log.debug(f"Registered {fileName} in a 64-bit context.") | ||
|
||
|
||
def applyRegistryPatch(fileName,wow64=False): | ||
def apply32bitRegistryPatch(fileName: str) -> None: | ||
"""Applies the registry patch with the given file name, using 32-bit regExe. | ||
Note: this function is valid while NVDA remains a 32-bit app. Re-evaluate if we move to 64-bit. | ||
@param fileName: the path to the .reg file | ||
@type fileName: str | ||
""" | ||
Applies the registry patch with the given file name | ||
using regedit. | ||
if not os.path.isfile(fileName): | ||
raise FileNotFoundError(f"Cannot apply 32-bit registry patch: {fileName} not found.") | ||
# On 32-bit systems, reg.exe is in System32. On 64-bit systems, SysWOW64 will redirect to 32-bit version. | ||
regExe = os.path.join(SYSTEM_ROOT, "System32", "reg.exe") | ||
try: | ||
subprocess.check_call([regExe, "import", fileName]) | ||
except subprocess.CalledProcessError as e: | ||
log.error(f"Error applying 32-bit registry patch from {fileName} with {regExe}: {e}") | ||
else: | ||
log.debug(f"Applied 32-bit registry patch from {fileName}") | ||
|
||
|
||
def apply64bitRegistryPatch(fileName: str) -> None: | ||
"""Applies the registry patch with the given file name, using 64-bit regExe. | ||
Note: this function is valid while NVDA remains a 32-bit app. Re-evaluate if we move to 64-bit. | ||
@param fileName: the path to the .reg file | ||
@type fileName: str | ||
""" | ||
if not os.path.isfile(fileName): | ||
raise FileNotFoundError(f"Cannot apply registry patch, {fileName} not found.") | ||
regedit=os.path.join(sysWow64 if wow64 else systemRoot,'regedit.exe') | ||
raise FileNotFoundError(f"Cannot apply 64-bit registry patch: {fileName} not found.") | ||
# On 64-bit systems, SysWOW64 provides 32-bit apps with a virtual directory to reach 64-bit executables. | ||
regExe = os.path.join(SYSNATIVE, "reg.exe") | ||
try: | ||
subprocess.check_call([regedit,'/s',fileName]) | ||
subprocess.check_call([regExe, "import", fileName]) | ||
except subprocess.CalledProcessError as e: | ||
log.error("Error applying registry patch: %s with %s, %s"%(fileName,regedit,e)) | ||
log.error(f"Error applying 64-bit registry patch from {fileName} with {regExe}: {e}") | ||
else: | ||
log.debug("Applied registry patch: %s with %s"%(fileName,regedit)) | ||
log.debug(f"Applied 64-bit registry patch from {fileName}") | ||
|
||
|
||
OLEACC_REG_FILE_PATH = os.path.join(globalVars.appDir, "COMRegistrationFixes", "oleaccProxy.reg") | ||
def fixCOMRegistrations(): | ||
"""Registers most common COM proxies, in case they have accidentally been unregistered or overwritten by | ||
3rd party software installs or uninstalls. | ||
""" | ||
Registers most common COM proxies, in case they had accidentally been unregistered or overwritten by 3rd party software installs/uninstalls. | ||
""" | ||
is64bit=os.environ.get("PROCESSOR_ARCHITEW6432","").endswith('64') | ||
is64bit = os.environ.get("PROCESSOR_ARCHITEW6432", "").endswith("64") | ||
winVer = winVersion.getWinVer() | ||
OSMajorMinor = (winVer.major, winVer.minor) | ||
log.debug("Fixing COM registration for Windows %s.%s, %s"%(OSMajorMinor[0],OSMajorMinor[1],"64 bit" if is64bit else "32 bit")) | ||
# Commands taken from NVDA issue #2807 comment https://github.com/nvaccess/nvda/issues/2807#issuecomment-320149243 | ||
log.debug( | ||
f"Fixing COM registrations for Windows {OSMajorMinor[0]}.{OSMajorMinor[1]}, " | ||
"{} bit.".format("64" if is64bit else "32") | ||
) | ||
# OLEACC (MSAA) proxies | ||
applyRegistryPatch(OLEACC_REG_FILE_PATH) | ||
apply32bitRegistryPatch(OLEACC_REG_FILE_PATH) | ||
if is64bit: | ||
applyRegistryPatch(OLEACC_REG_FILE_PATH, wow64=True) | ||
apply64bitRegistryPatch(OLEACC_REG_FILE_PATH) | ||
# IDispatch and other common OLE interfaces | ||
registerServer(os.path.join(system32,'oleaut32.dll')) | ||
registerServer(os.path.join(system32,'actxprxy.dll')) | ||
register32bitServer(os.path.join(SYSTEM32, "oleaut32.dll")) | ||
register32bitServer(os.path.join(SYSTEM32, "actxprxy.dll")) | ||
if is64bit: | ||
registerServer(os.path.join(sysWow64,'oleaut32.dll'),wow64=True) | ||
registerServer(os.path.join(sysWow64,'actxprxy.dll'),wow64=True) | ||
register64bitServer(os.path.join(SYSTEM32, "oleaut32.dll")) | ||
register64bitServer(os.path.join(SYSTEM32, "actxprxy.dll")) | ||
# IServiceProvider on windows 7 can become unregistered | ||
if OSMajorMinor==(6,1): # Windows 7 | ||
registerServer(os.path.join(programFiles,'Internet Explorer','ieproxy.dll')) | ||
if OSMajorMinor == (6, 1): # Windows 7 | ||
# There was no "Program Files (x86)" in Windows 7 32-bit, so we cover both cases | ||
register32bitServer(os.path.join( | ||
PROGRAM_FILES_X86 if is64bit else PROGRAM_FILES, | ||
"Internet Explorer", "ieproxy.dll" | ||
)) | ||
if is64bit: | ||
registerServer(os.path.join(programFilesX86,'Internet Explorer','ieproxy.dll'),wow64=True) | ||
register64bitServer(os.path.join(PROGRAM_FILES, "Internet Explorer", "ieproxy.dll")) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters