Get rid of the last use of win32com

This commit is contained in:
Kovid Goyal 2019-06-12 07:07:28 +05:30
parent 9844394258
commit ea74df97ec
No known key found for this signature in database
GPG Key ID: 06BC317B515ACE7C
3 changed files with 93 additions and 40 deletions

View File

@ -2,6 +2,8 @@
# vim:fileencoding=UTF-8:ts=4:sw=4:sta:et:sts=4:ai # vim:fileencoding=UTF-8:ts=4:sw=4:sta:et:sts=4:ai
# License: GPLv3 Copyright: 2010, Kovid Goyal <kovid at kovidgoyal.net> # License: GPLv3 Copyright: 2010, Kovid Goyal <kovid at kovidgoyal.net>
from __future__ import absolute_import, division, print_function, unicode_literals
import errno import errno
import json import json
import numbers import numbers
@ -53,45 +55,26 @@ if iswindows and not isportable:
startup_path = winutil.special_folder_path(winutil.CSIDL_STARTUP) startup_path = winutil.special_folder_path(winutil.CSIDL_STARTUP)
return os.path.join(startup_path, "calibre.lnk") return os.path.join(startup_path, "calibre.lnk")
class Shortcut(object): def create_shortcut(shortcut_path, target, description, *args):
quoted_args = None
if args:
quoted_args = []
for arg in args:
quoted_args.append('"{}"'.format(arg))
quoted_args = ' '.join(quoted_args)
plugins['winutil'][0].manage_shortcut(shortcut_path, target, description, quoted_args)
def __enter__(self): def shortcut_exists_at(shortcut_path, target):
import pythoncom if not os.access(shortcut_path, os.R_OK):
from win32com.shell import shell return False
pythoncom.CoInitialize() name = plugins['winutil'][0].manage_shortcut(shortcut_path, None, None, None)
self.instance = pythoncom.CoCreateInstance(shell.CLSID_ShellLink, None, pythoncom.CLSCTX_INPROC_SERVER, shell.IID_IShellLink) if name is None:
self.persist_file = self.instance.QueryInterface(pythoncom.IID_IPersistFile) return False
return self return os.path.normcase(os.path.abspath(name)) == os.path.normcase(os.path.abspath(target))
def __exit__(self, *a):
import pythoncom
del self.instance
del self.persist_file
pythoncom.CoUninitialize()
def create_at(self, shortcut_path, target, description, *args):
shortcut = self.instance
shortcut.SetPath(target)
shortcut.SetIconLocation(target, 0)
shortcut.SetDescription(description)
if args:
quoted_args = []
for arg in args:
quoted_args.append('"{}"'.format(arg))
shortcut.SetArguments(' '.join(quoted_args))
self.persist_file.Save(shortcut_path, 0)
def exists_at(self, shortcut_path, target):
if not os.access(shortcut_path, os.R_OK):
return False
self.persist_file.Load(shortcut_path)
name = self.instance.GetPath(8)[0]
return os.path.normcase(os.path.abspath(name)) == os.path.normcase(os.path.abspath(get_exe()))
def set_run_at_startup(run_at_startup=True): def set_run_at_startup(run_at_startup=True):
if run_at_startup: if run_at_startup:
with Shortcut() as shortcut: create_shortcut(startup_shortcut_path(), get_exe(), 'calibre - E-book management', '--start-in-tray')
shortcut.create_at(startup_shortcut_path(), get_exe(), 'calibre - E-book management', '--start-in-tray')
else: else:
shortcut_path = startup_shortcut_path() shortcut_path = startup_shortcut_path()
if os.path.exists(shortcut_path): if os.path.exists(shortcut_path):
@ -99,8 +82,7 @@ if iswindows and not isportable:
def is_set_to_run_at_startup(): def is_set_to_run_at_startup():
try: try:
with Shortcut() as shortcut: return shortcut_exists_at(startup_shortcut_path(), get_exe())
return shortcut.exists_at(startup_shortcut_path(), get_exe())
except Exception: except Exception:
import traceback import traceback
traceback.print_exc() traceback.print_exc()

View File

@ -380,6 +380,7 @@ extern PyObject *winutil_file_association(PyObject *self, PyObject *args);
extern PyObject *winutil_friendly_name(PyObject *self, PyObject *args); extern PyObject *winutil_friendly_name(PyObject *self, PyObject *args);
extern PyObject *winutil_notify_associations_changed(PyObject *self, PyObject *args); extern PyObject *winutil_notify_associations_changed(PyObject *self, PyObject *args);
extern PyObject *winutil_move_to_trash(PyObject *self, PyObject *args); extern PyObject *winutil_move_to_trash(PyObject *self, PyObject *args);
extern PyObject *winutil_manage_shortcut(PyObject *self, PyObject *args);
static PyMethodDef winutil_methods[] = { static PyMethodDef winutil_methods[] = {
{"special_folder_path", winutil_folder_path, METH_VARARGS, {"special_folder_path", winutil_folder_path, METH_VARARGS,
@ -467,6 +468,10 @@ be a unicode string. Returns unicode strings."
"move_to_trash()\n\nMove the specified path to trash" "move_to_trash()\n\nMove the specified path to trash"
}, },
{"manage_shortcut", (PyCFunction)winutil_manage_shortcut, METH_VARARGS,
"manage_shortcut()\n\nManage a shortcut"
},
{NULL, NULL, 0, NULL} {NULL, NULL, 0, NULL}
}; };

View File

@ -79,13 +79,15 @@ class wchar_raii { // {{{
wchar_raii() : handle(NULL) {} wchar_raii() : handle(NULL) {}
~wchar_raii() { ~wchar_raii() {
if (handle) {
#if PY_MAJOR_VERSION >= 3 #if PY_MAJOR_VERSION >= 3
PyMem_Free(*handle); PyMem_Free(*handle);
#endif #endif
*handle = NULL; *handle = NULL;
}
} }
wchar_t *ptr() { return *handle; } wchar_t *ptr() { return handle ? *handle : NULL; }
void set_ptr(wchar_t **val) { handle = val; } void set_ptr(wchar_t **val) { handle = val; }
}; // }}} }; // }}}
@ -215,4 +217,68 @@ winutil_move_to_trash(PyObject *self, PyObject *args) {
Py_RETURN_NONE; Py_RETURN_NONE;
} }
PyObject *
winutil_manage_shortcut(PyObject *self, PyObject *args) {
wchar_raii path, target, description, quoted_args;
if (!PyArg_ParseTuple(args, "O&O&O&O&", py_to_wchar, &path, py_to_wchar, &target, py_to_wchar, &description, py_to_wchar, &quoted_args)) return NULL;
if (!path.ptr()) {
PyErr_SetString(PyExc_TypeError, "Path must not be None");
return NULL;
}
scoped_com_initializer com;
if (!com.succeded()) { PyErr_SetString(PyExc_OSError, "Failed to initialize COM"); return NULL; }
CComPtr<IShellLink> shell_link;
if (FAILED(CoCreateInstance(CLSID_ShellLink, nullptr, CLSCTX_INPROC_SERVER, IID_PPV_ARGS(&shell_link)))) {
PyErr_SetString(PyExc_OSError, "Failed to create IShellLink instance");
return NULL;
}
CComPtr<IPersistFile> persist_file;
if (FAILED(shell_link->QueryInterface(IID_PPV_ARGS(&persist_file)))) {
PyErr_SetString(PyExc_OSError, "Failed to create IPersistFile instance");
return NULL;
}
if (!target.ptr()) {
wchar_t buf[2048];
if (FAILED(persist_file->Load(path.ptr(), 0))) Py_RETURN_NONE;
if (FAILED(shell_link->GetPath(buf, sizeof(buf), NULL, 0))) Py_RETURN_NONE;
return Py_BuildValue("u", buf);
}
if (FAILED(shell_link->SetPath(target.ptr()))) {
PyErr_SetString(PyExc_OSError, "Failed to set shortcut target");
return NULL;
}
if (FAILED(shell_link->SetIconLocation(target.ptr(), 0))) {
PyErr_SetString(PyExc_OSError, "Failed to set shortcut icon");
return NULL;
}
if (description.ptr()) {
if (FAILED(shell_link->SetDescription(description.ptr()))) {
PyErr_SetString(PyExc_OSError, "Failed to set shortcut description");
return NULL;
}
}
if (quoted_args.ptr()) {
if (FAILED(shell_link->SetArguments(quoted_args.ptr()))) {
PyErr_SetString(PyExc_OSError, "Failed to set shortcut arguments");
return NULL;
}
}
if (FAILED(persist_file->Save(path.ptr(), FALSE))) {
PyErr_SetString(PyExc_OSError, "Failed to save the shortcut");
return NULL;
}
Py_RETURN_NONE;
}
// end extern "C"
} }