From 0f3b2e2329f252fd63fcb5e18b56aea7fcb33f1a Mon Sep 17 00:00:00 2001 From: Kovid Goyal Date: Tue, 11 Jun 2019 12:06:12 +0530 Subject: [PATCH] Dont use win32com for adding to recent docs --- setup/extensions.json | 2 +- setup/test.py | 3 ++ src/calibre/gui2/__init__.py | 8 +--- src/calibre/utils/windows/__init__.py | 0 src/calibre/utils/windows/wintest.py | 28 +++++++++++ src/calibre/utils/windows/winutil.c | 5 ++ src/calibre/utils/windows/winutilpp.cpp | 63 +++++++++++++++++++++++++ 7 files changed, 101 insertions(+), 8 deletions(-) create mode 100644 src/calibre/utils/windows/__init__.py create mode 100644 src/calibre/utils/windows/wintest.py create mode 100644 src/calibre/utils/windows/winutilpp.cpp diff --git a/setup/extensions.json b/setup/extensions.json index b0698d4cec..7c4c54c74c 100644 --- a/setup/extensions.json +++ b/setup/extensions.json @@ -161,7 +161,7 @@ { "name": "winutil", "only": "windows", - "sources": "calibre/utils/windows/winutil.c", + "sources": "calibre/utils/windows/winutil.c calibre/utils/windows/winutilpp.cpp", "libraries": "shell32 wininet advapi32", "cflags": "/X" }, diff --git a/setup/test.py b/setup/test.py index 1c0ac4dfca..6638dda11d 100644 --- a/setup/test.py +++ b/setup/test.py @@ -127,6 +127,9 @@ def find_tests(which_tests=None): a(find_tests()) from calibre.ebooks.compression.palmdoc import find_tests a(find_tests()) + if iswindows: + from calibre.utils.windows.wintest import find_tests + a(find_tests()) a(unittest.defaultTestLoader.loadTestsFromTestCase(TestImports)) if ok('dbcli'): diff --git a/src/calibre/gui2/__init__.py b/src/calibre/gui2/__init__.py index 340a6e7dff..4346657c3f 100644 --- a/src/calibre/gui2/__init__.py +++ b/src/calibre/gui2/__init__.py @@ -1380,11 +1380,5 @@ def set_app_uid(val): def add_to_recent_docs(path): - from win32com.shell import shell, shellcon - path = unicode_type(path) app_id = get_app_uid() - if app_id is None: - shell.SHAddToRecentDocs(shellcon.SHARD_PATHW, path) - else: - item = shell.SHCreateItemFromParsingName(path, None, shell.IID_IShellItem) - shell.SHAddToRecentDocs(shellcon.SHARD_APPIDINFO, (item, app_id)) + plugins['winutil'][0].add_to_recent_docs(unicode_type(path), app_id) diff --git a/src/calibre/utils/windows/__init__.py b/src/calibre/utils/windows/__init__.py new file mode 100644 index 0000000000..e69de29bb2 diff --git a/src/calibre/utils/windows/wintest.py b/src/calibre/utils/windows/wintest.py new file mode 100644 index 0000000000..8ac5ed25c0 --- /dev/null +++ b/src/calibre/utils/windows/wintest.py @@ -0,0 +1,28 @@ +#!/usr/bin/env python2 +# vim:fileencoding=utf-8 +# License: GPL v3 Copyright: 2019, Kovid Goyal + +from __future__ import absolute_import, division, print_function, unicode_literals + +import os +import unittest +from polyglot.builtins import unicode_type + + +class TestWinutil(unittest.TestCase): + + def setUp(self): + from calibre.constants import plugins + self.winutil = plugins['winutil'][0] + + def tearDown(self): + del self.winutil + + def test_add_to_recent_docs(self): + path = unicode_type(os.path.abspath(__file__)) + self.winutil.add_to_recent_docs(path, None) + self.winutil.add_to_recent_docs(path, 'some-app-uid') + + +def find_tests(): + return unittest.defaultTestLoader.loadTestsFromTestCase(TestWinutil) diff --git a/src/calibre/utils/windows/winutil.c b/src/calibre/utils/windows/winutil.c index 4e5ce9f706..add7c03010 100644 --- a/src/calibre/utils/windows/winutil.c +++ b/src/calibre/utils/windows/winutil.c @@ -375,6 +375,7 @@ winutil_strftime(PyObject *self, PyObject *args) } static char winutil_doc[] = "Defines utility methods to interface with windows."; +extern PyObject *add_to_recent_docs(PyObject *self, PyObject *args); static PyMethodDef winutil_methods[] = { {"special_folder_path", winutil_folder_path, METH_VARARGS, @@ -442,6 +443,10 @@ be a unicode string. Returns unicode strings." "move_file()\n\nRename the specified file." }, + {"add_to_recent_docs", (PyCFunction)add_to_recent_docs, METH_VARARGS, + "add_to_recent_docs()\n\nAdd a path to the recent documents list" + }, + {NULL, NULL, 0, NULL} }; diff --git a/src/calibre/utils/windows/winutilpp.cpp b/src/calibre/utils/windows/winutilpp.cpp new file mode 100644 index 0000000000..dd150227a8 --- /dev/null +++ b/src/calibre/utils/windows/winutilpp.cpp @@ -0,0 +1,63 @@ +/* + * winutil.cpp + * Copyright (C) 2019 Kovid Goyal + * + * Distributed under terms of the GPL3 license. + */ + + +#define UNICODE +#include +#include +#include +#include // for CComPtr +#include + +static inline int +py_to_wchar(PyObject *obj, wchar_t **output) { + if (!PyUnicode_Check(obj)) { + if (obj == Py_None) { *output = NULL; return 1; } + PyErr_SetString(PyExc_TypeError, "unicode object expected"); + return 0; + } +#if PY_MAJOR_VERSION < 3 + *output = PyUnicode_AS_UNICODE(obj); +#else + *output = PyUnicode_AsWideCharString(obj, NULL); +#endif + return 1; +} + +static inline void +free_wchar_buffer(wchar_t **buf) { +#if PY_MAJOR_VERSION >= 3 + PyMem_Free(*buf); +#endif + *buf = NULL; +} + + +extern "C" { + +PyObject * +add_to_recent_docs(PyObject *self, PyObject *args) { + wchar_t *path, *app_id; + if (!PyArg_ParseTuple(args, "O&O&", py_to_wchar, &path, py_to_wchar, &app_id)) return NULL; + if (app_id) { + CComPtr item; + HRESULT hr = SHCreateItemFromParsingName(path, NULL, IID_PPV_ARGS(&item)); + if (SUCCEEDED(hr)) { + SHARDAPPIDINFO info; + info.psi = item; + info.pszAppID = app_id; + SHAddToRecentDocs(SHARD_APPIDINFO, &info); + } + } else { + SHAddToRecentDocs(SHARD_PATHW, path); + } + free_wchar_buffer(&path); free_wchar_buffer(&app_id); + Py_RETURN_NONE; +} + + +}