Make setting of app uids on windows more robust

This commit is contained in:
Kovid Goyal 2017-09-21 12:54:08 +05:30
parent ae098550e9
commit 2b3608cc1a
No known key found for this signature in database
GPG Key ID: 06BC317B515ACE7C
5 changed files with 48 additions and 26 deletions

View File

@ -39,9 +39,9 @@ isworker = 'CALIBRE_WORKER' in os.environ or 'CALIBRE_SIMPLE_WORKER' in os.envir
if isworker: if isworker:
os.environ.pop('CALIBRE_FORCE_ANSI', None) os.environ.pop('CALIBRE_FORCE_ANSI', None)
FAKE_PROTOCOL, FAKE_HOST = 'https', 'calibre-internal.invalid' FAKE_PROTOCOL, FAKE_HOST = 'https', 'calibre-internal.invalid'
VIEWER_APP_UID = 'com.calibre-ebook.viewer' VIEWER_APP_UID = u'com.calibre-ebook.viewer'
EDITOR_APP_UID = 'com.calibre-ebook.edit-book' EDITOR_APP_UID = u'com.calibre-ebook.edit-book'
MAIN_APP_UID = 'com.calibre-ebook.main-gui' MAIN_APP_UID = u'com.calibre-ebook.main-gui'
try: try:
preferred_encoding = locale.getpreferredencoding() preferred_encoding = locale.getpreferredencoding()
codecs.lookup(preferred_encoding) codecs.lookup(preferred_encoding)

View File

@ -11,7 +11,7 @@ from PyQt5.Qt import (
QDesktopServices, QFileDialog, QFileIconProvider, QSettings, QIcon, QStringListModel, QDesktopServices, QFileDialog, QFileIconProvider, QSettings, QIcon, QStringListModel,
QApplication, QDialog, QUrl, QFont, QFontDatabase, QLocale, QFontInfo) QApplication, QDialog, QUrl, QFont, QFontDatabase, QLocale, QFontInfo)
from calibre import prints from calibre import prints, as_unicode
from calibre.constants import (islinux, iswindows, isbsd, isfrozen, isosx, is_running_from_develop, from calibre.constants import (islinux, iswindows, isbsd, isfrozen, isosx, is_running_from_develop,
plugins, config_dir, filesystem_encoding, isxp, DEBUG, __version__, __appname__ as APP_UID) plugins, config_dir, filesystem_encoding, isxp, DEBUG, __version__, __appname__ as APP_UID)
from calibre.ptempfile import base_dir from calibre.ptempfile import base_dir
@ -1286,3 +1286,39 @@ def secure_web_page(qwebpage_or_qwebsettings):
empty_model = QStringListModel(['']) empty_model = QStringListModel([''])
empty_index = empty_model.index(0) empty_index = empty_model.index(0)
def get_app_uid():
import ctypes
from ctypes import wintypes
lpBuffer = wintypes.LPWSTR()
try:
AppUserModelID = ctypes.windll.shell32.GetCurrentProcessExplicitAppUserModelID
except Exception: # Vista has no app uids
return
AppUserModelID.argtypes = [wintypes.LPWSTR]
AppUserModelID.restype = wintypes.HRESULT
try:
AppUserModelID(ctypes.cast(ctypes.byref(lpBuffer), wintypes.LPWSTR))
except Exception:
return
appid = lpBuffer.value
ctypes.windll.ole32.CoTaskMemFree(lpBuffer)
return appid
def set_app_uid(val):
import ctypes
from ctypes import wintypes
try:
AppUserModelID = ctypes.windll.shell32.SetCurrentProcessExplicitAppUserModelID
except Exception: # Vista has no app uids
return False
AppUserModelID.argtypes = [wintypes.LPCWSTR]
AppUserModelID.restype = wintypes.HRESULT
try:
AppUserModelID(unicode(val))
except Exception as err:
prints(u'Failed to set app uid with error:', as_unicode(err))
return False
return True

View File

@ -15,12 +15,12 @@ from PyQt5.Qt import QCoreApplication, QIcon, QObject, QTimer
from calibre import force_unicode, plugins, prints from calibre import force_unicode, plugins, prints
from calibre.constants import ( from calibre.constants import (
DEBUG, __appname__, filesystem_encoding, get_portable_base, islinux, isosx, DEBUG, MAIN_APP_UID, __appname__, filesystem_encoding, get_portable_base,
iswindows, MAIN_APP_UID islinux, isosx, iswindows
) )
from calibre.gui2 import ( from calibre.gui2 import (
Application, choose_dir, error_dialog, gprefs, initialize_file_icon_provider, Application, choose_dir, error_dialog, gprefs, initialize_file_icon_provider,
question_dialog, setup_gui_option_parser question_dialog, set_app_uid, setup_gui_option_parser
) )
from calibre.gui2.main_window import option_parser as _option_parser from calibre.gui2.main_window import option_parser as _option_parser
from calibre.gui2.splash_screen import SplashScreen from calibre.gui2.splash_screen import SplashScreen
@ -522,11 +522,7 @@ def main(args=sys.argv):
# Ensure that all ebook editor instances are grouped together in the task # Ensure that all ebook editor instances are grouped together in the task
# bar. This prevents them from being grouped with viewer process when # bar. This prevents them from being grouped with viewer process when
# launched from within calibre, as both use calibre-parallel.exe # launched from within calibre, as both use calibre-parallel.exe
import ctypes set_app_uid(MAIN_APP_UID)
try:
ctypes.windll.shell32.SetCurrentProcessExplicitAppUserModelID(MAIN_APP_UID)
except Exception:
pass # Only available on windows 7 and newer
try: try:
app, opts, args = init_qt(args) app, opts, args = init_qt(args)

View File

@ -11,7 +11,7 @@ from PyQt5.Qt import QIcon
from calibre.constants import EDITOR_APP_UID, islinux, iswindows from calibre.constants import EDITOR_APP_UID, islinux, iswindows
from calibre.gui2 import ( from calibre.gui2 import (
Application, decouple, set_gui_prefs, setup_gui_option_parser Application, decouple, set_app_uid, set_gui_prefs, setup_gui_option_parser
) )
from calibre.ptempfile import reset_base_dir from calibre.ptempfile import reset_base_dir
from calibre.utils.config import OptionParser from calibre.utils.config import OptionParser
@ -57,13 +57,7 @@ def _run(args, notify=None):
# Ensure that all ebook editor instances are grouped together in the task # Ensure that all ebook editor instances are grouped together in the task
# bar. This prevents them from being grouped with viewer process when # bar. This prevents them from being grouped with viewer process when
# launched from within calibre, as both use calibre-parallel.exe # launched from within calibre, as both use calibre-parallel.exe
import ctypes set_app_uid(EDITOR_APP_UID)
try:
ctypes.windll.shell32.SetCurrentProcessExplicitAppUserModelID(
EDITOR_APP_UID
)
except Exception:
pass # Only available on windows 7 and newer
# The following two lines are needed to prevent circular imports causing # The following two lines are needed to prevent circular imports causing
# errors during initialization of plugins that use the polish container # errors during initialization of plugins that use the polish container

View File

@ -22,7 +22,7 @@ from calibre.customize.ui import available_input_formats
from calibre.ebooks.oeb.iterator.book import EbookIterator from calibre.ebooks.oeb.iterator.book import EbookIterator
from calibre.gui2 import ( from calibre.gui2 import (
Application, choose_files, error_dialog, info_dialog, open_url, Application, choose_files, error_dialog, info_dialog, open_url,
setup_gui_option_parser setup_gui_option_parser, set_app_uid
) )
from calibre.gui2.viewer.toc import TOC from calibre.gui2.viewer.toc import TOC
from calibre.gui2.viewer.ui import Main as MainWindow from calibre.gui2.viewer.ui import Main as MainWindow
@ -1262,11 +1262,7 @@ def main(args=sys.argv):
# Ensure that all ebook editor instances are grouped together in the task # Ensure that all ebook editor instances are grouped together in the task
# bar. This prevents them from being grouped with viewer process when # bar. This prevents them from being grouped with viewer process when
# launched from within calibre, as both use calibre-parallel.exe # launched from within calibre, as both use calibre-parallel.exe
import ctypes set_app_uid(VIEWER_APP_UID)
try:
ctypes.windll.shell32.SetCurrentProcessExplicitAppUserModelID(VIEWER_APP_UID)
except Exception:
pass # Only available on windows 7 and newer
parser = option_parser() parser = option_parser()
opts, args = parser.parse_args(args) opts, args = parser.parse_args(args)