From b271c5ea72f6bc33a914fa511a23958be6ee1113 Mon Sep 17 00:00:00 2001 From: Kovid Goyal Date: Wed, 25 Jan 2012 10:15:18 +0530 Subject: [PATCH] Allow calibre to be run simultaneously in two different user accounts on windows. Fixes #919856 (Python function terminated unexpectedly [Error 5] Access is denied (Error Code: 1)) --- src/calibre/constants.py | 23 +++++++++++++++++++ src/calibre/gui2/main.py | 14 ++++++------ src/calibre/utils/ipc/__init__.py | 37 ++++++++++++++++++++++--------- 3 files changed, 56 insertions(+), 18 deletions(-) diff --git a/src/calibre/constants.py b/src/calibre/constants.py index 0bae1d2c86..902dc057df 100644 --- a/src/calibre/constants.py +++ b/src/calibre/constants.py @@ -161,4 +161,27 @@ def get_version(): v += '*' return v +def get_unicode_windows_env_var(name): + import ctypes + name = unicode(name) + n = ctypes.windll.kernel32.GetEnvironmentVariableW(name, None, 0) + if n == 0: + return None + buf = ctypes.create_unicode_buffer(u'\0'*n) + ctypes.windll.kernel32.GetEnvironmentVariableW(name, buf, n) + return buf.value +def get_windows_username(): + import ctypes + try: + advapi32 = ctypes.windll.advapi32 + GetUserName = getattr(advapi32, u'GetUserNameW') + except AttributeError: + pass + else: + buf = ctypes.create_unicode_buffer(257) + n = ctypes.c_int(257) + if GetUserName(buf, ctypes.byref(n)): + return buf.value + + return get_unicode_windows_env_var(u'USERNAME') diff --git a/src/calibre/gui2/main.py b/src/calibre/gui2/main.py index 9e1b6b4b24..195be03626 100644 --- a/src/calibre/gui2/main.py +++ b/src/calibre/gui2/main.py @@ -10,7 +10,7 @@ from PyQt4.Qt import (QCoreApplication, QIcon, QObject, QTimer, from calibre import prints, plugins, force_unicode from calibre.constants import (iswindows, __appname__, isosx, DEBUG, filesystem_encoding) -from calibre.utils.ipc import ADDRESS, RC +from calibre.utils.ipc import gui_socket_address, RC from calibre.gui2 import (ORG_NAME, APP_UID, initialize_file_icon_provider, Application, choose_dir, error_dialog, question_dialog, gprefs) from calibre.gui2.main_window import option_parser as _option_parser @@ -304,7 +304,7 @@ def cant_start(msg=_('If you are sure it is not running')+', ', if iswindows: what = _('try rebooting your computer.') else: - what = _('try deleting the file')+': '+ADDRESS + what = _('try deleting the file')+': '+ gui_socket_address() info = base%(where, msg, what) error_dialog(None, _('Cannot Start ')+__appname__, @@ -345,14 +345,14 @@ def main(args=sys.argv): return 0 if si: try: - listener = Listener(address=ADDRESS) + listener = Listener(address=gui_socket_address()) except socket.error: if iswindows: cant_start() - if os.path.exists(ADDRESS): - os.remove(ADDRESS) + if os.path.exists(gui_socket_address()): + os.remove(gui_socket_address()) try: - listener = Listener(address=ADDRESS) + listener = Listener(address=gui_socket_address()) except socket.error: cant_start() else: @@ -363,7 +363,7 @@ def main(args=sys.argv): gui_debug=gui_debug) otherinstance = False try: - listener = Listener(address=ADDRESS) + listener = Listener(address=gui_socket_address()) except socket.error: # Good si is correct (on UNIX) otherinstance = True else: diff --git a/src/calibre/utils/ipc/__init__.py b/src/calibre/utils/ipc/__init__.py index 2df13ce7c8..93db2e9fc7 100644 --- a/src/calibre/utils/ipc/__init__.py +++ b/src/calibre/utils/ipc/__init__.py @@ -9,17 +9,32 @@ __docformat__ = 'restructuredtext en' import os from threading import Thread -from calibre.constants import iswindows +from calibre.constants import iswindows, get_windows_username -if iswindows: - ADDRESS = r'\\.\pipe\CalibreGUI' -else: - from tempfile import gettempdir - tmp = gettempdir() - user = os.environ.get('USER', '') - if not user: - user = os.path.basename(os.path.expanduser('~')) - ADDRESS = os.path.join(tmp, user+'-calibre-gui.socket') +ADDRESS = None + +def gui_socket_address(): + global ADDRESS + if ADDRESS is None: + if iswindows: + ADDRESS = r'\\.\pipe\CalibreGUI' + try: + user = get_windows_username() + except: + user = None + if user: + from calibre.utils.filenames import ascii_filename + user = ascii_filename(user).replace(' ', '_') + if user: + ADDRESS += '-' + user[:100] + 'x' + else: + from tempfile import gettempdir + tmp = gettempdir() + user = os.environ.get('USER', '') + if not user: + user = os.path.basename(os.path.expanduser('~')) + ADDRESS = os.path.join(tmp, user+'-calibre-gui.socket') + return ADDRESS class RC(Thread): @@ -32,7 +47,7 @@ class RC(Thread): from multiprocessing.connection import Client self.done = False try: - self.conn = Client(ADDRESS) + self.conn = Client(gui_socket_address()) self.done = True except: if self.print_error: