diff --git a/source/installer.py b/source/installer.py index 42fc16acd09..325f0e8175e 100644 --- a/source/installer.py +++ b/source/installer.py @@ -135,6 +135,36 @@ def copyUserConfig(destPath): destFilePath=os.path.join(destPath,os.path.relpath(sourceFilePath,sourcePath)) tryCopyFile(sourceFilePath,destFilePath) +def removeOldLibFiles(destPath,rebootOK=False): + """ + Removes library files from previous versions of NVDA. + @param destPath: The path where NVDA is installed. + @ type destPath: string + @param rebootOK: If true then files can be removed on next reboot if trying to do so now fails. + @type rebootOK: boolean + """ + for topDir in ('lib','lib64'): + currentLibPath=os.path.join(destPath,topDir,versionInfo.version) + for parent,subdirs,files in os.walk(os.path.join(destPath,topDir),topdown=False): + if parent==currentLibPath: + # Lib dir for current installation. Don't touch this! + log.debug("Skipping current install lib path: %r"%parent) + continue + for d in subdirs: + path=os.path.join(parent,d) + log.debug("Removing old lib directory: %r"%path) + try: + os.rmdir(path) + except OSError: + log.warning("Failed to remove a directory no longer needed. This can be manually removed after a reboot or the installer will try removing it again next time. Directory: %r"%path) + for f in files: + path=os.path.join(parent,f) + log.debug("Removing old lib file: %r"%path) + try: + tryRemoveFile(path,numRetries=2,rebootOK=rebootOK) + except RetriableFailure: + log.warning("A file no longer needed could not be removed. This can be manually removed after a reboot, or the installer will try again next time. File: %r"%path) + def removeOldProgramFiles(destPath): # #3181: Remove espeak-ng-data\voices except for variants. # Otherwise, there will be duplicates if voices have been moved in this new eSpeak version. @@ -154,14 +184,6 @@ def removeOldProgramFiles(destPath): else: os.remove(fn) - # #7546: Remove old version-specific libs - for topDir in ('lib','lib64'): - for parent,subdirs,files in os.walk(os.path.join(destPath,topDir),topdown=False): - for d in subdirs: - tryRemoveFile(os.path.join(parent,d),numRetries=1,rebootOK=True) - for f in files: - tryRemoveFile(os.path.join(parent,f),numRetries=1,rebootOK=True) - # #4235: mpr.dll is a Windows system dll accidentally included with # earlier versions of NVDA. Its presence causes problems in Windows Vista. fn = os.path.join(destPath, "mpr.dll") @@ -404,6 +426,7 @@ def install(shouldCreateDesktopShortcut=True,shouldRunAtLogon=True): else: raise RuntimeError("No available executable to use as nvda.exe") registerInstallation(installDir,startMenuFolder,shouldCreateDesktopShortcut,shouldRunAtLogon,configInLocalAppData) + removeOldLibFiles(installDir,rebootOK=True) def removeOldLoggedFiles(installPath): datPath=os.path.join(installPath,"uninstall.dat") @@ -432,6 +455,7 @@ def createPortableCopy(destPath,shouldCopyUserConfig=True): tryCopyFile(os.path.join(destPath,"nvda_noUIAccess.exe"),os.path.join(destPath,"nvda.exe")) if shouldCopyUserConfig: copyUserConfig(os.path.join(destPath,'userConfig')) + removeOldLibFiles(destPath,rebootOK=True) def registerEaseOfAccess(installDir): with _winreg.CreateKeyEx(_winreg.HKEY_LOCAL_MACHINE, easeOfAccess.APP_KEY_PATH, 0, diff --git a/source/logHandler.py b/source/logHandler.py index 71c050d9852..ae9db25e834 100755 --- a/source/logHandler.py +++ b/source/logHandler.py @@ -18,6 +18,7 @@ import traceback from types import MethodType, FunctionType import globalVars +import versionInfo ERROR_INVALID_WINDOW_HANDLE = 1400 ERROR_TIMEOUT = 1460 @@ -29,6 +30,7 @@ EVENT_E_ALL_SUBSCRIBERS_FAILED = -2147220991 RPC_E_CALL_REJECTED = -2147418111 RPC_E_DISCONNECTED = -2147417848 +LOAD_WITH_ALTERED_SEARCH_PATH=0x8 def getCodePath(f): """Using a frame object, gets its module path (relative to the current directory).[className.[funcName]] @@ -188,17 +190,19 @@ class RemoteHandler(logging.Handler): def __init__(self): #Load nvdaHelperRemote.dll but with an altered search path so it can pick up other dlls in lib - h=ctypes.windll.kernel32.LoadLibraryExW(os.path.abspath(ur"lib\nvdaHelperRemote.dll"),0,0x8) - self._remoteLib=ctypes.WinDLL("nvdaHelperRemote",handle=h) if h else None + path=os.path.abspath(os.path.join(u"lib",versionInfo.version,u"nvdaHelperRemote.dll")) + h=ctypes.windll.kernel32.LoadLibraryExW(path,0,LOAD_WITH_ALTERED_SEARCH_PATH) + if not h: + raise OSError("Could not load %s"%path) + self._remoteLib=ctypes.WinDLL("nvdaHelperRemote",handle=h) logging.Handler.__init__(self) def emit(self, record): msg = self.format(record) - if self._remoteLib: - try: - self._remoteLib.nvdaControllerInternal_logMessage(record.levelno, ctypes.windll.kernel32.GetCurrentProcessId(), msg) - except WindowsError: - pass + try: + self._remoteLib.nvdaControllerInternal_logMessage(record.levelno, ctypes.windll.kernel32.GetCurrentProcessId(), msg) + except WindowsError: + pass class FileHandler(logging.StreamHandler): diff --git a/source/nvda.pyw b/source/nvda.pyw index 45d2bc8481e..55f0731c19d 100755 --- a/source/nvda.pyw +++ b/source/nvda.pyw @@ -24,6 +24,14 @@ import pythonMonkeyPatches import ctypes import locale import gettext + +#Localization settings +locale.setlocale(locale.LC_ALL,'') +try: + gettext.translation('nvda',localedir='locale',languages=[locale.getlocale()[0]]).install(True) +except: + gettext.install('nvda',unicode=True) + import time import argparse import win32con @@ -51,13 +59,6 @@ class NoConsoleOptionParser(argparse.ArgumentParser): globalVars.startTime=time.time() -#Localization settings -locale.setlocale(locale.LC_ALL,'') -try: - gettext.translation('nvda',localedir='locale',languages=[locale.getlocale()[0]]).install(True) -except: - gettext.install('nvda',unicode=True) - # Check OS version requirements import winVersion if not winVersion.isSupportedOS(): diff --git a/tests/unit/__init__.py b/tests/unit/__init__.py index 7cccd81dc3f..211547b8f27 100644 --- a/tests/unit/__init__.py +++ b/tests/unit/__init__.py @@ -17,6 +17,12 @@ import os import sys +import locale +import gettext +#Localization settings +locale.setlocale(locale.LC_ALL,'') +gettext.install('nvda',unicode=True) + # The path to the unit tests. UNIT_DIR = os.path.dirname(os.path.abspath(__file__)) # The path to the top of the repo.