From 15443c869ea6bc180524413257c93e54f2daee9d Mon Sep 17 00:00:00 2001 From: Kovid Goyal Date: Wed, 14 Oct 2020 12:47:40 +0530 Subject: [PATCH] Wrap CommandLineToArgvW --- src/calibre/test_build.py | 1 + src/calibre/utils/windows/winutil.cpp | 20 ++++++++++++++++++++ src/calibre/utils/winreg/default_programs.py | 20 ++------------------ 3 files changed, 23 insertions(+), 18 deletions(-) diff --git a/src/calibre/test_build.py b/src/calibre/test_build.py index b2a6c328e2..cce8541144 100644 --- a/src/calibre/test_build.py +++ b/src/calibre/test_build.py @@ -250,6 +250,7 @@ class BuildTest(unittest.TestCase): m = winutil.create_mutex("test-mutex", False) self.assertRaises(OSError, winutil.create_mutex, 'test-mutex', False) m.close() + self.assertEqual(winutil.parse_cmdline('"c:\\test exe.exe" "some arg" 2'), ('c:\\test exe.exe', 'some arg', '2')) def test_sqlite(self): import sqlite3 diff --git a/src/calibre/utils/windows/winutil.cpp b/src/calibre/utils/windows/winutil.cpp index 84d42aa0a1..5a4ef5a7d8 100644 --- a/src/calibre/utils/windows/winutil.cpp +++ b/src/calibre/utils/windows/winutil.cpp @@ -800,6 +800,25 @@ create_mutex(PyObject *self, PyObject *args) { return (PyObject*)Handle_create(h); } + +static PyObject* +parse_cmdline(PyObject *self, PyObject *args) { + wchar_raii cmdline; + if (!PyArg_ParseTuple(args, "O&", py_to_wchar_no_none, &cmdline)) return NULL; + int num; + LPWSTR *data = CommandLineToArgvW(cmdline.ptr(), &num); + if (data == NULL) return PyErr_SetFromWindowsErr(0); + PyObject *ans = PyTuple_New(num); + if (!ans) { LocalFree(data); return NULL; } + for (int i = 0; i < num; i++) { + PyObject *temp = PyUnicode_FromWideChar(data[i], -1); + if (!temp) { Py_CLEAR(ans); LocalFree(data); return NULL; } + PyTuple_SET_ITEM(ans, i, temp); + } + LocalFree(data); + return ans; +} + // Icon loading {{{ #pragma pack( push ) #pragma pack( 2 ) @@ -945,6 +964,7 @@ static PyMethodDef winutil_methods[] = { M(load_library, METH_VARARGS), M(load_icons, METH_VARARGS), M(get_icon_for_file, METH_VARARGS), + M(parse_cmdline, METH_VARARGS), {"special_folder_path", winutil_folder_path, METH_VARARGS, "special_folder_path(csidl_id) -> path\n\n" diff --git a/src/calibre/utils/winreg/default_programs.py b/src/calibre/utils/winreg/default_programs.py index 39bc066f9e..26657857d6 100644 --- a/src/calibre/utils/winreg/default_programs.py +++ b/src/calibre/utils/winreg/default_programs.py @@ -5,8 +5,7 @@ __license__ = 'GPL v3' __copyright__ = '2015, Kovid Goyal ' -import os, sys, time, ctypes, traceback -from ctypes.wintypes import HLOCAL, LPCWSTR +import os, sys, time, traceback from threading import Thread import winerror @@ -225,26 +224,11 @@ def get_open_data(base, prog_id): return cmd, k.get(sub_key='DefaultIcon'), k.get_mui_string('FriendlyTypeName') or k.get() -CommandLineToArgvW = ctypes.windll.shell32.CommandLineToArgvW -CommandLineToArgvW.arg_types = [LPCWSTR, ctypes.POINTER(ctypes.c_int)] -CommandLineToArgvW.restype = ctypes.POINTER(LPCWSTR) -LocalFree = ctypes.windll.kernel32.LocalFree -LocalFree.res_type = HLOCAL -LocalFree.arg_types = [HLOCAL] - - def split_commandline(commandline): # CommandLineToArgvW returns path to executable if called with empty string. if not commandline.strip(): return [] - num = ctypes.c_int(0) - result_pointer = CommandLineToArgvW(commandline.lstrip(), ctypes.byref(num)) - if not result_pointer: - raise ctypes.WinError() - result_array_type = LPCWSTR * num.value - result = [arg for arg in result_array_type.from_address(ctypes.addressof(result_pointer.contents))] - LocalFree(result_pointer) - return result + return list(plugins['winutil'][0].parse_cmdline(commandline)) def friendly_app_name(prog_id=None, exe=None):