mirror of
https://github.com/kovidgoyal/calibre.git
synced 2025-07-09 03:04:10 -04:00
Move various win API calls into native code
Faster, more robust. Should fix #1728196
This commit is contained in:
parent
7357c7d7da
commit
b6312f1f12
@ -163,7 +163,7 @@
|
|||||||
"name": "winutil",
|
"name": "winutil",
|
||||||
"only": "windows",
|
"only": "windows",
|
||||||
"sources": "calibre/utils/windows/winutil.c",
|
"sources": "calibre/utils/windows/winutil.c",
|
||||||
"libraries": "shell32 wininet",
|
"libraries": "shell32 wininet advapi32",
|
||||||
"cflags": "/X"
|
"cflags": "/X"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
@ -281,6 +281,10 @@ def get_portable_base():
|
|||||||
|
|
||||||
|
|
||||||
def get_unicode_windows_env_var(name):
|
def get_unicode_windows_env_var(name):
|
||||||
|
winutil = plugins['winutil'][0]
|
||||||
|
getenv = getattr(winutil, 'getenv', None)
|
||||||
|
if getenv is not None:
|
||||||
|
return getenv(unicode(name))
|
||||||
import ctypes
|
import ctypes
|
||||||
name = unicode(name)
|
name = unicode(name)
|
||||||
n = ctypes.windll.kernel32.GetEnvironmentVariableW(name, None, 0)
|
n = ctypes.windll.kernel32.GetEnvironmentVariableW(name, None, 0)
|
||||||
@ -293,19 +297,26 @@ def get_unicode_windows_env_var(name):
|
|||||||
|
|
||||||
def get_windows_username():
|
def get_windows_username():
|
||||||
'''
|
'''
|
||||||
Return the user name of the currently loggen in user as a unicode string.
|
Return the user name of the currently logged in user as a unicode string.
|
||||||
Note that usernames on windows are case insensitive, the case of the value
|
Note that usernames on windows are case insensitive, the case of the value
|
||||||
returned depends on what the user typed into the login box at login time.
|
returned depends on what the user typed into the login box at login time.
|
||||||
'''
|
'''
|
||||||
|
winutil = plugins['winutil'][0]
|
||||||
|
username = getattr(winutil, 'username', None)
|
||||||
|
if username is not None:
|
||||||
|
return username()
|
||||||
import ctypes
|
import ctypes
|
||||||
|
from ctypes import wintypes
|
||||||
try:
|
try:
|
||||||
advapi32 = ctypes.windll.advapi32
|
advapi32 = ctypes.windll.advapi32
|
||||||
GetUserName = getattr(advapi32, u'GetUserNameW')
|
GetUserName = getattr(advapi32, u'GetUserNameW')
|
||||||
|
GetUserName.argtypes = [wintypes.LPWSTR, ctypes.POINTER(wintypes.DWORD)]
|
||||||
|
GetUserName.restype = wintypes.BOOL
|
||||||
except AttributeError:
|
except AttributeError:
|
||||||
pass
|
pass
|
||||||
else:
|
else:
|
||||||
buf = ctypes.create_unicode_buffer(257)
|
buf = ctypes.create_unicode_buffer(257)
|
||||||
n = ctypes.c_int(257)
|
n = wintypes.DWORD(257)
|
||||||
if GetUserName(buf, ctypes.byref(n)):
|
if GetUserName(buf, ctypes.byref(n)):
|
||||||
return buf.value
|
return buf.value
|
||||||
|
|
||||||
@ -313,6 +324,10 @@ def get_windows_username():
|
|||||||
|
|
||||||
|
|
||||||
def get_windows_temp_path():
|
def get_windows_temp_path():
|
||||||
|
winutil = plugins['winutil'][0]
|
||||||
|
temp_path = getattr(winutil, 'temp_path', None)
|
||||||
|
if temp_path is not None:
|
||||||
|
return temp_path()
|
||||||
import ctypes
|
import ctypes
|
||||||
n = ctypes.windll.kernel32.GetTempPathW(0, None)
|
n = ctypes.windll.kernel32.GetTempPathW(0, None)
|
||||||
if n == 0:
|
if n == 0:
|
||||||
@ -324,6 +339,10 @@ def get_windows_temp_path():
|
|||||||
|
|
||||||
|
|
||||||
def get_windows_user_locale_name():
|
def get_windows_user_locale_name():
|
||||||
|
winutil = plugins['winutil'][0]
|
||||||
|
locale_name = getattr(winutil, 'locale_name', None)
|
||||||
|
if locale_name is not None:
|
||||||
|
return locale_name()
|
||||||
import ctypes
|
import ctypes
|
||||||
k32 = ctypes.windll.kernel32
|
k32 = ctypes.windll.kernel32
|
||||||
n = 255
|
n = 255
|
||||||
@ -334,32 +353,17 @@ def get_windows_user_locale_name():
|
|||||||
return u'_'.join(buf.value.split(u'-')[:2])
|
return u'_'.join(buf.value.split(u'-')[:2])
|
||||||
|
|
||||||
|
|
||||||
number_formats = None
|
|
||||||
|
|
||||||
|
|
||||||
def get_windows_number_formats():
|
def get_windows_number_formats():
|
||||||
# This can be changed to use localeconv() once we switch to Visual Studio
|
ans = getattr(get_windows_number_formats, 'ans', None)
|
||||||
# 2015 as localeconv() in that version has unicode variants for all strings.
|
if ans is None:
|
||||||
global number_formats
|
winutil = plugins['winutil'][0]
|
||||||
if number_formats is None:
|
localeconv = getattr(winutil, 'localeconv', None)
|
||||||
import ctypes
|
if localeconv is not None:
|
||||||
from ctypes.wintypes import DWORD
|
d = localeconv()
|
||||||
k32 = ctypes.windll.kernel32
|
thousands_sep, decimal_point = d['thousands_sep'], d['decimal_point']
|
||||||
n = 25
|
else:
|
||||||
buf = ctypes.create_unicode_buffer(u'\0'*n)
|
from locale import localeconv
|
||||||
k32.GetNumberFormatEx.argtypes = [ctypes.c_wchar_p, DWORD, ctypes.c_wchar_p, ctypes.c_void_p, ctypes.c_wchar_p, ctypes.c_int]
|
d = localeconv()
|
||||||
k32.GetNumberFormatEx.restype = ctypes.c_int
|
thousands_sep, decimal_point = d['thousands_sep'].decode('mbcs'), d['decimal_point'].decode('mbcs')
|
||||||
if k32.GetNumberFormatEx(None, 0, u'123456.7', None, buf, n) == 0:
|
ans = get_windows_number_formats.ans = thousands_sep, decimal_point
|
||||||
raise ctypes.WinError()
|
return ans
|
||||||
src = buf.value
|
|
||||||
thousands_sep, decimal_point = u',.'
|
|
||||||
idx = src.find(u'6')
|
|
||||||
if idx > -1 and src[idx+1] != u'7':
|
|
||||||
decimal_point = src[idx+1]
|
|
||||||
src = src[:idx]
|
|
||||||
for c in src:
|
|
||||||
if c not in u'123456':
|
|
||||||
thousands_sep = c
|
|
||||||
break
|
|
||||||
number_formats = (thousands_sep, decimal_point)
|
|
||||||
return number_formats
|
|
||||||
|
@ -121,8 +121,20 @@ class BuildTest(unittest.TestCase):
|
|||||||
def test_winutil(self):
|
def test_winutil(self):
|
||||||
from calibre.constants import plugins
|
from calibre.constants import plugins
|
||||||
winutil = plugins['winutil'][0]
|
winutil = plugins['winutil'][0]
|
||||||
|
|
||||||
|
def au(x, name):
|
||||||
|
self.assertTrue(isinstance(x, unicode), name + '() did not return a unicode string')
|
||||||
for x in winutil.argv():
|
for x in winutil.argv():
|
||||||
self.assertTrue(isinstance(x, unicode), 'argv() not returning unicode string')
|
au(x, 'argv')
|
||||||
|
for x in 'username temp_path locale_name'.split():
|
||||||
|
au(getattr(winutil, x)(), x)
|
||||||
|
d = winutil.localeconv()
|
||||||
|
au(d['thousands_sep'], 'localeconv')
|
||||||
|
au(d['decimal_point'], 'localeconv')
|
||||||
|
for k, v in d.iteritems():
|
||||||
|
au(v, k)
|
||||||
|
for k in os.environ.keys():
|
||||||
|
au(winutil.getenv(unicode(k)), 'getenv-' + k)
|
||||||
|
|
||||||
def test_sqlite(self):
|
def test_sqlite(self):
|
||||||
import sqlite3
|
import sqlite3
|
||||||
|
@ -42,6 +42,8 @@ wherever possible in this module.
|
|||||||
#define UNICODE
|
#define UNICODE
|
||||||
#include <Windows.h>
|
#include <Windows.h>
|
||||||
#include <Wininet.h>
|
#include <Wininet.h>
|
||||||
|
#include <LMcons.h>
|
||||||
|
#include <locale.h>
|
||||||
#include <Python.h>
|
#include <Python.h>
|
||||||
#include <structseq.h>
|
#include <structseq.h>
|
||||||
#include <timefuncs.h>
|
#include <timefuncs.h>
|
||||||
@ -228,6 +230,62 @@ winutil_set_max_stdio(PyObject *self, PyObject *args) {
|
|||||||
Py_RETURN_NONE;
|
Py_RETURN_NONE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static PyObject *
|
||||||
|
winutil_getenv(PyObject *self, PyObject *args) {
|
||||||
|
const wchar_t *q;
|
||||||
|
if (!PyArg_ParseTuple(args, "u", &q)) return NULL;
|
||||||
|
wchar_t *ans = _wgetenv(q);
|
||||||
|
if (ans == NULL) Py_RETURN_NONE;
|
||||||
|
return PyUnicode_FromWideChar(ans, wcslen(ans));
|
||||||
|
}
|
||||||
|
|
||||||
|
static PyObject *
|
||||||
|
winutil_username(PyObject *self) {
|
||||||
|
wchar_t buf[UNLEN + 1] = {0};
|
||||||
|
DWORD sz = sizeof(buf)/sizeof(buf[0]);
|
||||||
|
if (!GetUserName(buf, &sz)) {
|
||||||
|
PyErr_SetFromWindowsErr(0);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
return PyUnicode_FromWideChar(buf, wcslen(buf));
|
||||||
|
}
|
||||||
|
|
||||||
|
static PyObject *
|
||||||
|
winutil_temp_path(PyObject *self) {
|
||||||
|
wchar_t buf[MAX_PATH + 1] = {0};
|
||||||
|
DWORD sz = sizeof(buf)/sizeof(buf[0]);
|
||||||
|
if (!GetTempPath(sz, buf)) {
|
||||||
|
PyErr_SetFromWindowsErr(0);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
return PyUnicode_FromWideChar(buf, wcslen(buf));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static PyObject *
|
||||||
|
winutil_locale_name(PyObject *self) {
|
||||||
|
wchar_t buf[LOCALE_NAME_MAX_LENGTH + 1] = {0};
|
||||||
|
if (!GetUserDefaultLocaleName(buf, sizeof(buf)/sizeof(buf[0]))) {
|
||||||
|
PyErr_SetFromWindowsErr(0);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
return PyUnicode_FromWideChar(buf, wcslen(buf));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static PyObject *
|
||||||
|
winutil_localeconv(PyObject *self) {
|
||||||
|
struct lconv *d = localeconv();
|
||||||
|
#define W(name) #name, d->_W_##name
|
||||||
|
return Py_BuildValue(
|
||||||
|
"{su su su su su su su su}",
|
||||||
|
W(decimal_point), W(thousands_sep), W(int_curr_symbol), W(currency_symbol),
|
||||||
|
W(mon_decimal_point), W(mon_thousands_sep), W(positive_sign), W(negative_sign)
|
||||||
|
);
|
||||||
|
#undef W
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
static PyObject *
|
static PyObject *
|
||||||
winutil_strftime(PyObject *self, PyObject *args)
|
winutil_strftime(PyObject *self, PyObject *args)
|
||||||
{
|
{
|
||||||
@ -381,6 +439,26 @@ be a unicode string. Returns unicode strings."
|
|||||||
"setmaxstdio(num)\n\nSet the maximum number of open file handles."
|
"setmaxstdio(num)\n\nSet the maximum number of open file handles."
|
||||||
},
|
},
|
||||||
|
|
||||||
|
{"getenv", (PyCFunction)winutil_getenv, METH_VARARGS,
|
||||||
|
"getenv(name)\n\nGet the value of the specified env var as a unicode string."
|
||||||
|
},
|
||||||
|
|
||||||
|
{"username", (PyCFunction)winutil_username, METH_NOARGS,
|
||||||
|
"username()\n\nGet the current username as a unicode string."
|
||||||
|
},
|
||||||
|
|
||||||
|
{"temp_path", (PyCFunction)winutil_temp_path, METH_NOARGS,
|
||||||
|
"temp_path()\n\nGet the current temporary dir as a unicode string."
|
||||||
|
},
|
||||||
|
|
||||||
|
{"locale_name", (PyCFunction)winutil_locale_name, METH_NOARGS,
|
||||||
|
"locale_name()\n\nGet the current locale name as a unicode string."
|
||||||
|
},
|
||||||
|
|
||||||
|
{"localeconv", (PyCFunction)winutil_localeconv, METH_NOARGS,
|
||||||
|
"localeconv()\n\nGet the locale conventions as unicode strings."
|
||||||
|
},
|
||||||
|
|
||||||
{NULL, NULL, 0, NULL}
|
{NULL, NULL, 0, NULL}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user