Work on getting windows running

This commit is contained in:
Kovid Goyal 2019-09-03 14:26:26 +05:30
parent 994befe846
commit be471a8cbe
No known key found for this signature in database
GPG Key ID: 06BC317B515ACE7C
6 changed files with 167 additions and 164 deletions

View File

@ -28,6 +28,7 @@ dlls = [
# 'WebSockets', # 'WebSockets',
# 'WebView', # 'WebView',
'Positioning', 'Positioning',
'PositioningQuick',
'Sensors', 'Sensors',
'Sql', 'Sql',
'Svg', 'Svg',
@ -178,10 +179,11 @@ def build_c_extensions(ext_dir):
def run_tests(path_to_calibre_debug, cwd_on_failure): def run_tests(path_to_calibre_debug, cwd_on_failure):
if run(path_to_calibre_debug, '--test-build') != 0: ret = run(path_to_calibre_debug, '--test-build')
if ret != 0:
os.chdir(cwd_on_failure) os.chdir(cwd_on_failure)
print( print(
'running calibre build tests failed with:', path_to_calibre_debug, file=sys.stderr) 'running calibre build tests failed with return code:', ret, 'and exe:', path_to_calibre_debug, file=sys.stderr)
run_shell() run_shell()
raise SystemExit('running calibre build tests failed') raise SystemExit('running calibre build tests failed')

View File

@ -103,7 +103,7 @@ class Env(object):
self.py_ver = '.'.join(map(str, python_major_minor_version())) self.py_ver = '.'.join(map(str, python_major_minor_version()))
self.lib_dir = j(self.app_base, 'Lib') self.lib_dir = j(self.app_base, 'Lib')
self.pylib = j(self.app_base, 'pylib.zip') self.pylib = j(self.app_base, 'pylib.zip')
self.dll_dir = j(self.app_base, 'DLLs') self.dll_dir = j(self.app_base, 'bin')
self.portable_base = j(d(self.base), 'Calibre Portable') self.portable_base = j(d(self.base), 'Calibre Portable')
self.obj_dir = j(build_dir, 'launcher') self.obj_dir = j(build_dir, 'launcher')
self.installer_dir = j(build_dir, 'wix') self.installer_dir = j(build_dir, 'wix')
@ -165,10 +165,11 @@ def freeze(env, ext_dir):
printf('Adding Qt...') printf('Adding Qt...')
for x in QT_DLLS: for x in QT_DLLS:
copybin(os.path.join(QT_PREFIX, 'bin', x + '.dll')) copybin(os.path.join(QT_PREFIX, 'bin', x + '.dll'))
copybin(os.path.join(QT_PREFIX, 'bin', 'QtWebEngineProcess.exe'))
for x in 'libGLESv2 libEGL'.split(): for x in 'libGLESv2 libEGL'.split():
copybin(os.path.join(QT_PREFIX, 'bin', x + '.dll')) copybin(os.path.join(QT_PREFIX, 'bin', x + '.dll'))
plugdir = j(QT_PREFIX, 'plugins') plugdir = j(QT_PREFIX, 'plugins')
tdir = j(env.app_base, 'qt_plugins') tdir = j(env.app_base, 'plugins')
for d in QT_PLUGINS: for d in QT_PLUGINS:
imfd = os.path.join(plugdir, d) imfd = os.path.join(plugdir, d)
tg = os.path.join(tdir, d) tg = os.path.join(tdir, d)
@ -178,6 +179,9 @@ def freeze(env, ext_dir):
for f in walk(tdir): for f in walk(tdir):
if not f.lower().endswith('.dll'): if not f.lower().endswith('.dll'):
os.remove(f) os.remove(f)
for data_file in os.listdir(j(QT_PREFIX, 'resources')):
shutil.copy2(j(QT_PREFIX, 'resources', data_file), j(env.app_base, 'resources'))
shutil.copytree(j(QT_PREFIX, 'translations'), j(env.app_base, 'translations'))
printf('Adding python...') printf('Adding python...')
@ -205,6 +209,12 @@ def freeze(env, ext_dir):
for x in {x for x in os.listdir(pyqt) if x.endswith('.pyd')}: for x in {x for x in os.listdir(pyqt) if x.endswith('.pyd')}:
if x.partition('.')[0] not in PYQT_MODULES and x != 'sip.pyd': if x.partition('.')[0] not in PYQT_MODULES and x != 'sip.pyd':
os.remove(j(pyqt, x)) os.remove(j(pyqt, x))
with open(j(pyqt, '__init__.py') , 'r+b') as f:
raw = f.read()
nraw = raw.replace(b'def find_qt():', b'def find_qt():\n return # disabled for calibre')
if nraw == raw:
raise Exception('Failed to patch PyQt to disable dll directory manipulation')
f.seek(0), f.truncate(), f.write(nraw)
printf('Adding calibre sources...') printf('Adding calibre sources...')
for x in glob.glob(j(CALIBRE_DIR, 'src', '*')): for x in glob.glob(j(CALIBRE_DIR, 'src', '*')):
@ -636,8 +646,8 @@ def archive_lib_dir(env):
shutil.rmtree(env.lib_dir) shutil.rmtree(env.lib_dir)
def copy_crt(env): def copy_crt_and_d3d(env):
printf('Copying CRT...') printf('Copying CRT and D3D...')
plat = ('x64' if is64bit else 'x86') plat = ('x64' if is64bit else 'x86')
for key, val in worker_env.items(): for key, val in worker_env.items():
if 'COMNTOOLS' in key.upper(): if 'COMNTOOLS' in key.upper():
@ -653,17 +663,27 @@ def copy_crt(env):
'ucrt', 'DLLs', plat) 'ucrt', 'DLLs', plat)
if not os.path.exists(sdk_path): if not os.path.exists(sdk_path):
raise SystemExit('Windows 10 Universal CRT redistributable not found at: %r' % sdk_path) raise SystemExit('Windows 10 Universal CRT redistributable not found at: %r' % sdk_path)
for dll in glob.glob(os.path.join(sdk_path, '*.dll')): d3d_path = os.path.join(
worker_env['WINDOWSSDKDIR'], 'Redist', 'D3D', plat)
if not os.path.exists(d3d_path):
raise SystemExit('Windows 10 D3D redistributable not found at: %r' % d3d_path)
def copy_dll(dll):
shutil.copy2(dll, env.dll_dir) shutil.copy2(dll, env.dll_dir)
os.chmod(os.path.join(env.dll_dir, b(dll)), stat.S_IRWXU) os.chmod(os.path.join(env.dll_dir, b(dll)), stat.S_IRWXU)
for dll in glob.glob(os.path.join(d3d_path, '*.dll')):
if os.path.basename(dll).lower().startswith('d3dcompiler_'):
copy_dll(dll)
for dll in glob.glob(os.path.join(sdk_path, '*.dll')):
copy_dll(dll)
for dll in glob.glob(os.path.join(vc_path, '*.dll')): for dll in glob.glob(os.path.join(vc_path, '*.dll')):
bname = os.path.basename(dll) bname = os.path.basename(dll)
if not bname.startswith('vccorlib') and not bname.startswith('concrt'): if not bname.startswith('vccorlib') and not bname.startswith('concrt'):
# Those two DLLs are not required vccorlib is for the CORE CLR # Those two DLLs are not required vccorlib is for the CORE CLR
# I think concrt is the concurrency runtime for C++ which I believe # I think concrt is the concurrency runtime for C++ which I believe
# nothing in calibre currently uses # nothing in calibre currently uses
shutil.copy(dll, env.dll_dir) copy_dll(dll)
os.chmod(os.path.join(env.dll_dir, bname), stat.S_IRWXU)
def sign_executables(env): def sign_executables(env):
@ -685,7 +705,7 @@ def main():
build_utils(env) build_utils(env)
freeze(env, ext_dir) freeze(env, ext_dir)
embed_manifests(env) embed_manifests(env)
copy_crt(env) copy_crt_and_d3d(env)
archive_lib_dir(env) archive_lib_dir(env)
if not args.skip_tests: if not args.skip_tests:
run_tests(os.path.join(env.base, 'calibre-debug.exe'), env.base) run_tests(os.path.join(env.base, 'calibre-debug.exe'), env.base)

View File

@ -53,18 +53,22 @@ static int show_last_error(wchar_t *preamble) {
} }
typedef int (__cdecl *ENTRYPROC)(const char*, const char*, const char*, int); typedef int (__cdecl *ENTRYPROC)(const char*, const char*, const char*, int);
typedef void (__cdecl *SIMPLEPRINT)(const wchar_t*);
typedef BOOL (*SETDEFAULTDIRS)(DWORD);
static ENTRYPROC entrypoint = NULL;
static SIMPLEPRINT simple_print = NULL;
static HMODULE dll = 0;
static ENTRYPROC load_launcher_dll() { static void
wchar_t buf[MAX_PATH]; // Cannot use a zero initializer for the array as it generates an implicit call to memset() load_launcher_dll() {
static wchar_t buf[MAX_PATH]; // Cannot use a zero initializer for the array as it generates an implicit call to memset()
wchar_t *dll_point = NULL; wchar_t *dll_point = NULL;
int i = 0; int i = 0;
DWORD sz = 0; DWORD sz = 0;
HMODULE dll = 0;
ENTRYPROC entrypoint = NULL;
if ((sz = GetModuleFileNameW(NULL, buf, MAX_PATH)) >= MAX_PATH - 30) { if ((sz = GetModuleFileNameW(NULL, buf, MAX_PATH)) >= MAX_PATH - 30) {
show_error(L"Installation directory path too long", L"", 1); show_error(L"Installation directory path too long", L"", 1);
return NULL; return;
} }
while (sz > 0) { while (sz > 0) {
@ -73,33 +77,36 @@ static ENTRYPROC load_launcher_dll() {
} }
if (dll_point == NULL) { if (dll_point == NULL) {
show_error(L"Executable path has no path separators", L"", 1); show_error(L"Executable path has no path separators", L"", 1);
return NULL; return;
} }
wsprintf(dll_point, L"%s\0\0", L"app\\DLLs"); wsprintf(dll_point, L"%s\0\0", L"app\\bin");
// Restrict the directories from which DLLs can be loaded
SETDEFAULTDIRS SetDefaultDllDirectories = (SETDEFAULTDIRS)GetProcAddress(GetModuleHandleW(L"kernel32.dll"), "SetDefaultDllDirectories");
if (SetDefaultDllDirectories) SetDefaultDllDirectories(LOAD_LIBRARY_SEARCH_DEFAULT_DIRS);
if (SetDllDirectoryW(buf) == 0) { if (SetDllDirectoryW(buf) == 0) {
show_last_error(L"Failed to set DLL directory"); show_last_error(L"Failed to set DLL directory");
return NULL; return;
} }
// Have to load ucrtbase manually first, otherwise loading fails on systems where the // Have to load ucrtbase manually first, otherwise loading fails on systems where the
// Universal CRT is not installed. // Universal CRT is not installed.
if (!LoadLibraryW(L"ucrtbase.dll")) { if (!LoadLibraryW(L"ucrtbase.dll")) {
show_last_error(L"Unable to find ucrtbase.dll. You should install all Windows updates on your computer to get this file."); show_last_error(L"Unable to find ucrtbase.dll. You should install all Windows updates on your computer to get this file.");
return NULL; return;
} }
if (!(dll = LoadLibraryW(L"calibre-launcher.dll"))) { if (!(dll = LoadLibraryW(L"calibre-launcher.dll"))) {
show_last_error(L"Failed to load: calibre-launcher.dll"); show_last_error(L"Failed to load: calibre-launcher.dll");
return NULL; return;
} }
if (!(entrypoint = (ENTRYPROC) GetProcAddress(dll, "execute_python_entrypoint"))) { if (!(entrypoint = (ENTRYPROC) GetProcAddress(dll, "execute_python_entrypoint"))) {
show_last_error(L"Failed to get the calibre-launcher dll entry point"); show_last_error(L"Failed to get the calibre-launcher dll entry point");
return NULL; return;
} }
return entrypoint; simple_print = (SIMPLEPRINT) GetProcAddress(dll, "simple_print");
} }
int __stdcall start_here() { int __stdcall start_here() {
int ret = 0; int ret = 0;
ENTRYPROC entrypoint = load_launcher_dll(); load_launcher_dll();
if (entrypoint) { if (entrypoint) {
#ifdef GUI_APP #ifdef GUI_APP
// This should really be returning the value set in the WM_QUIT message, but I cannot be bothered figuring out how to get that. // This should really be returning the value set in the WM_QUIT message, but I cannot be bothered figuring out how to get that.
@ -108,6 +115,10 @@ int __stdcall start_here() {
ret = entrypoint(BASENAME, MODULE, FUNCTION, 0); ret = entrypoint(BASENAME, MODULE, FUNCTION, 0);
#endif #endif
} else ret = 1; } else ret = 1;
if (dll != 0) {
FreeLibrary(dll);
dll = 0;
}
ExitProcess(ret); ExitProcess(ret);
return ret; return ret;
} }

View File

@ -9,6 +9,7 @@ import sys
import os import os
import imp import imp
class PydImporter(object): class PydImporter(object):
__slots__ = ('items', 'description') __slots__ = ('items', 'description')
@ -19,7 +20,7 @@ class PydImporter(object):
def find_module(self, fullname, path=None): def find_module(self, fullname, path=None):
if self.items is None: if self.items is None:
dlls_dir = os.path.join(sys.app_dir, 'app', 'DLLs') dlls_dir = os.path.join(sys.app_dir, 'app', 'bin')
items = self.items = {} items = self.items = {}
for x in os.listdir(dlls_dir): for x in os.listdir(dlls_dir):
lx = x.lower() lx = x.lower()
@ -34,13 +35,19 @@ class PydImporter(object):
try: try:
path = self.items[fullname.lower()] path = self.items[fullname.lower()]
except KeyError: except KeyError:
raise ImportError('The native code module %s seems to have disappeared from self.items' % fullname) raise ImportError(
'The native code module %s seems to have disappeared from self.items'
% fullname
)
package, name = fullname.rpartition(b'.')[::2] package, name = fullname.rpartition(b'.')[::2]
m = imp.load_module(fullname, None, path, self.description) # This inserts the module into sys.modules itself m = imp.load_module(
fullname, None, path, self.description
) # This inserts the module into sys.modules itself
m.__loader__ = self m.__loader__ = self
m.__package__ = package or None m.__package__ = package or None
return m return m
def abs__file__(): def abs__file__():
"""Set all module __file__ attribute to an absolute path""" """Set all module __file__ attribute to an absolute path"""
for m in sys.modules.values(): for m in sys.modules.values():
@ -51,6 +58,7 @@ def abs__file__():
except AttributeError: except AttributeError:
continue continue
def aliasmbcs(): def aliasmbcs():
import locale, codecs import locale, codecs
enc = locale.getdefaultlocale()[1] enc = locale.getdefaultlocale()[1]
@ -62,21 +70,24 @@ def aliasmbcs():
encodings._cache[enc] = encodings._unknown encodings._cache[enc] = encodings._unknown
encodings.aliases.aliases[enc] = 'mbcs' encodings.aliases.aliases[enc] = 'mbcs'
def add_calibre_vars(): def add_calibre_vars():
sys.new_app_layout = 1 sys.new_app_layout = 1
sys.resources_location = os.path.join(sys.app_dir, 'app', 'resources') sys.resources_location = os.path.join(sys.app_dir, 'app', 'resources')
sys.extensions_location = os.path.join(sys.app_dir, 'app', 'DLLs') sys.extensions_location = os.path.join(sys.app_dir, 'app', 'bin')
dv = os.environ.get('CALIBRE_DEVELOP_FROM', None) dv = os.environ.get('CALIBRE_DEVELOP_FROM', None)
if dv and os.path.exists(dv): if dv and os.path.exists(dv):
sys.path.insert(0, os.path.abspath(dv)) sys.path.insert(0, os.path.abspath(dv))
def run_entry_point(): def run_entry_point():
bname, mod, func = sys.calibre_basename, sys.calibre_module, sys.calibre_function bname, mod, func = sys.calibre_basename, sys.calibre_module, sys.calibre_function
sys.argv[0] = bname + '.exe' sys.argv[0] = bname + '.exe'
pmod = __import__(mod, fromlist=[1], level=0) pmod = __import__(mod, fromlist=[1], level=0)
return getattr(pmod, func)() return getattr(pmod, func)()
def main(): def main():
sys.frozen = 'windows_exe' sys.frozen = 'windows_exe'
sys.setdefaultencoding('utf-8') sys.setdefaultencoding('utf-8')
@ -86,8 +97,10 @@ def main():
sys.path_importer_cache.clear() sys.path_importer_cache.clear()
import linecache import linecache
def fake_getline(filename, lineno, module_globals=None): def fake_getline(filename, lineno, module_globals=None):
return '' return ''
linecache.orig_getline = linecache.getline linecache.orig_getline = linecache.getline
linecache.getline = fake_getline linecache.getline = fake_getline
@ -95,7 +108,7 @@ def main():
add_calibre_vars() add_calibre_vars()
# Needed for pywintypes to be able to load its DLL # Needed to bypass meaningless check in pywintypes.py
sys.path.append(os.path.join(sys.app_dir, 'app', 'DLLs')) sys.path.append(os.path.join(sys.app_dir, 'app', 'bin'))
return run_entry_point() return run_entry_point()

View File

@ -16,6 +16,7 @@
#include <io.h> #include <io.h>
#include <fcntl.h> #include <fcntl.h>
#define arraysz(x) (sizeof((x))/sizeof((x)[0]))
static int GUI_APP = 0; static int GUI_APP = 0;
static char python_dll[] = PYDLL; static char python_dll[] = PYDLL;
@ -25,29 +26,16 @@ void set_gui_app(int yes) { GUI_APP = yes; }
int calibre_show_python_error(const wchar_t *preamble, int code); int calibre_show_python_error(const wchar_t *preamble, int code);
static int _show_error(const wchar_t *preamble, const wchar_t *msg, const int code) { static int _show_error(const wchar_t *preamble, const wchar_t *msg, const int code) {
wchar_t *buf; static wchar_t buf[4096];
char *cbuf;
buf = (wchar_t*)LocalAlloc(LMEM_ZEROINIT, sizeof(wchar_t)*
(wcslen(msg) + wcslen(preamble) + 80));
_snwprintf_s(buf, fwprintf(stderr, L"%s\r\n %s (Error Code: %d)\r\n", preamble, msg, code);
LocalSize(buf) / sizeof(wchar_t), _TRUNCATE, fflush(stderr);
L"%s\r\n %s (Error Code: %d)\r\n",
preamble, msg, code);
if (GUI_APP) { if (GUI_APP) {
_snwprintf_s(buf, arraysz(buf), _TRUNCATE, L"%s\r\n %s (Error Code: %d)\r\n", preamble, msg, code);
MessageBeep(MB_ICONERROR); MessageBeep(MB_ICONERROR);
MessageBox(NULL, buf, NULL, MB_OK|MB_ICONERROR); MessageBox(NULL, buf, NULL, MB_OK|MB_ICONERROR);
} }
else {
cbuf = (char*) calloc(10+(wcslen(buf)*4), sizeof(char));
if (cbuf) {
if (WideCharToMultiByte(CP_UTF8, 0, buf, -1, cbuf, (int)(10+(wcslen(buf)*4)), NULL, NULL) != 0) printf_s(cbuf);
free(cbuf);
}
}
LocalFree(buf);
return code; return code;
} }
@ -83,72 +71,72 @@ int show_last_error(wchar_t *preamble) {
return ret; return ret;
} }
char* get_app_dir() { static char app_dir[MAX_PATH] = {0};
char *buf, *buf2, *buf3; static wchar_t dll_dir[MAX_PATH] = {0};
static wchar_t qt_prefix_dir[MAX_PATH] = {0};
static char program_name[MAX_PATH] = {0};
static wchar_t w_program_name[MAX_PATH] = {0};
static wchar_t w_app_dir[MAX_PATH] = {0};
#if PY_VERSION_MAJOR >= 3
static wchar_t python_path[MAX_PATH] = {0};
#else
static char python_path[MAX_PATH] = {0};
#endif
static void
get_app_dir(void) {
char drive[4] = "\0\0\0"; char drive[4] = "\0\0\0";
DWORD sz; errno_t err; DWORD sz; errno_t err;
char buf[MAX_PATH] = {0};
buf = (char*)calloc(MAX_PATH, sizeof(char)); sz = GetModuleFileNameA(NULL, program_name, MAX_PATH);
buf2 = (char*)calloc(MAX_PATH, sizeof(char));
buf3 = (char*)calloc(MAX_PATH, sizeof(char));
if (!buf || !buf2 || !buf3) ExitProcess(_show_error(L"Out of memory", L"", 1));
sz = GetModuleFileNameA(NULL, buf, MAX_PATH);
if (sz >= MAX_PATH-1) ExitProcess(_show_error(L"Installation directory path too long", L"", 1)); if (sz >= MAX_PATH-1) ExitProcess(_show_error(L"Installation directory path too long", L"", 1));
err = _splitpath_s(buf, drive, 4, buf2, MAX_PATH, NULL, 0, NULL, 0); err = _splitpath_s(program_name, drive, 4, buf, MAX_PATH, NULL, 0, NULL, 0);
if (err != 0) ExitProcess(show_last_error_crt(L"Failed to find application directory")); if (err != 0) ExitProcess(show_last_error_crt(L"Failed to find application directory"));
_snprintf_s(buf3, MAX_PATH, _TRUNCATE, "%s%s", drive, buf2); _snprintf_s(app_dir, MAX_PATH, _TRUNCATE, "%s%s", drive, buf);
free(buf); free(buf2);
return buf3;
} }
wchar_t* get_app_dirw() { static void
wchar_t *buf, *buf2, *buf3; get_app_dirw(void) {
wchar_t buf[MAX_PATH] = {0};
wchar_t drive[4] = L"\0\0\0"; wchar_t drive[4] = L"\0\0\0";
DWORD sz; errno_t err; DWORD sz; errno_t err;
buf = (wchar_t*)calloc(MAX_PATH, sizeof(wchar_t)); sz = GetModuleFileNameW(NULL, w_program_name, MAX_PATH);
buf2 = (wchar_t*)calloc(MAX_PATH, sizeof(wchar_t));
buf3 = (wchar_t*)calloc(MAX_PATH, sizeof(wchar_t));
if (!buf || !buf2 || !buf3) ExitProcess(_show_error(L"Out of memory", L"", 1));
sz = GetModuleFileNameW(NULL, buf, MAX_PATH);
if (sz >= MAX_PATH-1) ExitProcess(_show_error(L"Installation directory path too long", L"", 1)); if (sz >= MAX_PATH-1) ExitProcess(_show_error(L"Installation directory path too long", L"", 1));
err = _wsplitpath_s(buf, drive, 4, buf2, MAX_PATH, NULL, 0, NULL, 0); err = _wsplitpath_s(w_program_name, drive, 4, buf, MAX_PATH, NULL, 0, NULL, 0);
if (err != 0) ExitProcess(show_last_error_crt(L"Failed to find application directory")); if (err != 0) ExitProcess(show_last_error_crt(L"Failed to find application directory"));
_snwprintf_s(buf3, MAX_PATH, _TRUNCATE, L"%s%s", drive, buf2); _snwprintf_s(w_app_dir, MAX_PATH, _TRUNCATE, L"%s%s", drive, buf);
free(buf); free(buf2);
return buf3;
} }
static void
get_install_locations(void) {
get_app_dir();
get_app_dirw();
_snwprintf_s(qt_prefix_dir, MAX_PATH-1, _TRUNCATE, L"%s\\app", w_app_dir);
_wputenv_s(L"CALIBRE_QT_PREFIX", qt_prefix_dir);
_snwprintf_s(dll_dir, MAX_PATH-1, _TRUNCATE, L"%s\\app\\bin", w_app_dir);
#if PY_VERSION_MAJOR >= 3
_snwprintf_s(python_path, MAX_PATH-1, _TRUNCATE, L"%s\\app\\pylib.zip", w_app_dir);
#else
_snprintf_s(python_path, MAX_PATH-1, _TRUNCATE, "%s\\app\\pylib.zip", app_dir);
#endif
void load_python_dll() { }
char *app_dir, *dll_dir, *qt_plugin_dir;
size_t l;
app_dir = get_app_dir(); static void
l = strlen(app_dir)+25; load_python_dll() {
dll_dir = (char*) calloc(l, sizeof(char)); get_install_locations();
qt_plugin_dir = (char*) calloc(l, sizeof(char));
if (!dll_dir || !qt_plugin_dir) ExitProcess(_show_error(L"Out of memory", L"", 1));
_snprintf_s(dll_dir, l, _TRUNCATE, "%s\\app\\DLLs", app_dir);
_snprintf_s(qt_plugin_dir, l, _TRUNCATE, "%s\\app\\qt_plugins", app_dir);
free(app_dir);
_putenv_s("QT_PLUGIN_PATH", qt_plugin_dir);
if (!SetDllDirectoryA(dll_dir)) ExitProcess(show_last_error(L"Failed to set DLL directory."));
if (FAILED(__HrLoadAllImportsForDll(python_dll))) if (FAILED(__HrLoadAllImportsForDll(python_dll)))
ExitProcess(_show_error(L"Failed to delay load the python dll", L"", 1)); ExitProcess(_show_error(L"Failed to delay load the python dll", L"", 1));
} }
static char program_name[MAX_PATH]; const static wchar_t out_of_memory[] = L"Out of memory";
static char python_home[MAX_PATH];
static wchar_t out_of_memory[] = L"Out of memory"; static void
setup_stream(const char *name, const char *errors, UINT cp) {
void setup_stream(const char *name, const char *errors, UINT cp) {
PyObject *stream; PyObject *stream;
char *buf = (char *)calloc(100, sizeof(char)); char buf[128] = {0};
if (!buf) ExitProcess(_show_error(out_of_memory, L"", 1));
if (cp == CP_UTF8) _snprintf_s(buf, 100, _TRUNCATE, "%s", "utf-8"); if (cp == CP_UTF8) _snprintf_s(buf, 100, _TRUNCATE, "%s", "utf-8");
else if (cp == CP_UTF7) _snprintf_s(buf, 100, _TRUNCATE, "%s", "utf-7"); else if (cp == CP_UTF7) _snprintf_s(buf, 100, _TRUNCATE, "%s", "utf-7");
@ -158,9 +146,6 @@ void setup_stream(const char *name, const char *errors, UINT cp) {
if (!PyFile_SetEncodingAndErrors(stream, buf, (char*)errors)) if (!PyFile_SetEncodingAndErrors(stream, buf, (char*)errors))
ExitProcess(calibre_show_python_error(L"Failed to set stream encoding", 1)); ExitProcess(calibre_show_python_error(L"Failed to set stream encoding", 1));
free(buf);
} }
UINT UINT
@ -187,30 +172,12 @@ setup_streams() {
UINT UINT
initialize_interpreter(const char *basename, const char *module, const char *function) { initialize_interpreter(const char *basename, const char *module, const char *function) {
DWORD sz; char *buf, *path; HMODULE dll; DWORD sz; HMODULE dll;
int *flag, i, argc; int *flag, i, argc;
wchar_t *app_dir, **wargv; wchar_t **wargv;
PyObject *argv, *v; PyObject *argv, *v;
char *dummy_argv[1] = {""}; char *dummy_argv[1] = {""};
buf = (char*)calloc(MAX_PATH, sizeof(char));
path = (char*)calloc(MAX_PATH, sizeof(char));
if (!buf || !path) ExitProcess(_show_error(L"Out of memory", L"", 1));
sz = GetModuleFileNameA(NULL, buf, MAX_PATH);
if (sz >= MAX_PATH-1) ExitProcess(_show_error(L"Installation directory path too long", L"", 1));
_snprintf_s(program_name, MAX_PATH, _TRUNCATE, "%s", buf);
free(buf);
buf = get_app_dir();
buf[strlen(buf)-1] = '\0';
_snprintf_s(python_home, MAX_PATH, _TRUNCATE, "%s", buf);
_snprintf_s(path, MAX_PATH, _TRUNCATE, "%s\\app\\pylib.zip", buf);
free(buf);
dll = GetModuleHandleA(python_dll); dll = GetModuleHandleA(python_dll);
if (!dll) ExitProcess(show_last_error(L"Failed to get python dll handle")); if (!dll) ExitProcess(show_last_error(L"Failed to get python dll handle"));
flag = (int*)GetProcAddress(dll, "Py_OptimizeFlag"); flag = (int*)GetProcAddress(dll, "Py_OptimizeFlag");
@ -238,8 +205,13 @@ initialize_interpreter(const char *basename, const char *module, const char *fun
if (!flag) ExitProcess(_show_error(L"Failed to get debug flag", L"", 1)); if (!flag) ExitProcess(_show_error(L"Failed to get debug flag", L"", 1));
//*flag = 1; //*flag = 1;
#if PY_VERSION_MAJOR >= 3
Py_SetProgramName(w_program_name);
Py_SetPythonHome(w_app_dir);
#else
Py_SetProgramName(program_name); Py_SetProgramName(program_name);
Py_SetPythonHome(python_home); Py_SetPythonHome(app_dir);
#endif
//printf("Path before Py_Initialize(): %s\r\n\n", Py_GetPath()); //printf("Path before Py_Initialize(): %s\r\n\n", Py_GetPath());
Py_Initialize(); Py_Initialize();
@ -247,11 +219,10 @@ initialize_interpreter(const char *basename, const char *module, const char *fun
PySys_SetArgv(1, dummy_argv); PySys_SetArgv(1, dummy_argv);
//printf("Path after Py_Initialize(): %s\r\n\n", Py_GetPath()); //printf("Path after Py_Initialize(): %s\r\n\n", Py_GetPath());
PySys_SetPath(path); PySys_SetPath(python_path);
//printf("Path set by me: %s\r\n\n", path); //printf("Path set by me: %s\r\n\n", path);
PySys_SetObject("gui_app", PyBool_FromLong((long)GUI_APP)); PySys_SetObject("gui_app", PyBool_FromLong((long)GUI_APP));
app_dir = get_app_dirw(); PySys_SetObject("app_dir", PyUnicode_FromWideChar(w_app_dir, wcslen(w_app_dir)));
PySys_SetObject("app_dir", PyUnicode_FromWideChar(app_dir, wcslen(app_dir)));
PySys_SetObject("calibre_basename", PyBytes_FromString(basename)); PySys_SetObject("calibre_basename", PyBytes_FromString(basename));
PySys_SetObject("calibre_module", PyBytes_FromString(module)); PySys_SetObject("calibre_module", PyBytes_FromString(module));
@ -271,22 +242,21 @@ initialize_interpreter(const char *basename, const char *module, const char *fun
} }
wchar_t* pyobject_to_wchar(PyObject *o) { static const wchar_t*
PyUnicodeObject *t; pyobject_to_wchar(PyObject *o) {
PyObject *t = NULL;
size_t s; size_t s;
wchar_t *ans; static wchar_t ans[4096];
if (!PyUnicode_Check(o)) { if (!PyUnicode_Check(o)) {
t = (PyUnicodeObject*)PyUnicode_FromEncodedObject(o, NULL, "replace"); t = PyUnicode_FromEncodedObject(o, NULL, "replace");
if (t == NULL) return NULL; if (t == NULL) return NULL;
} else t = (PyUnicodeObject*)o; }
s = PyUnicode_AsWideChar(t ? t : o, ans, arraysz(ans)-1);
s = 2*PyUnicode_GET_SIZE(t) +1; Py_XDECREF(t);
ans = (wchar_t*)calloc(s, sizeof(wchar_t)); if (s >= 0) ans[s] = 0;
if (ans == NULL) return NULL; else ans[s] = 0;
s = PyUnicode_AsWideChar(t, ans, s-1);
ans[s] = L'\0';
return ans; return ans;
} }
@ -315,7 +285,7 @@ int handle_sysexit(PyObject *e) {
int calibre_show_python_error(const wchar_t *preamble, int code) { int calibre_show_python_error(const wchar_t *preamble, int code) {
PyObject *exc, *val, *tb, *str, **system_exit; PyObject *exc, *val, *tb, *str, **system_exit;
HMODULE dll; HMODULE dll;
int ret, issysexit = 0; wchar_t *i; int ret, issysexit = 0; const wchar_t *i;
if (!PyErr_Occurred()) return code; if (!PyErr_Occurred()) return code;
dll = GetModuleHandleA(python_dll); dll = GetModuleHandleA(python_dll);
@ -340,7 +310,6 @@ int calibre_show_python_error(const wchar_t *preamble, int code) {
} }
i = pyobject_to_wchar(str); i = pyobject_to_wchar(str);
ret = _show_error(preamble, (i==NULL)?out_of_memory:i, code); ret = _show_error(preamble, (i==NULL)?out_of_memory:i, code);
if (i) free(i);
if (tb != NULL) { if (tb != NULL) {
PyErr_Restore(exc, val, tb); PyErr_Restore(exc, val, tb);
PyErr_Print(); PyErr_Print();
@ -373,6 +342,10 @@ null_invalid_parameter_handler(
// to return errors instead of aborting the program. So get the windows CRT // to return errors instead of aborting the program. So get the windows CRT
// to do that. // to do that.
} }
__declspec(dllexport) int __cdecl
simple_print(const wchar_t *msg) {
wprintf(L"%s", msg); fflush(stdout);
}
__declspec(dllexport) int __cdecl __declspec(dllexport) int __cdecl
execute_python_entrypoint(const char *basename, const char *module, const char *function, int is_gui_app) { execute_python_entrypoint(const char *basename, const char *module, const char *function, int is_gui_app) {
@ -398,51 +371,35 @@ execute_python_entrypoint(const char *basename, const char *module, const char *
if (site == NULL) if (site == NULL)
ret = calibre_show_python_error(L"Failed to import site module", 1); ret = calibre_show_python_error(L"Failed to import site module", 1);
else { else {
Py_XINCREF(site); Py_INCREF(site);
main = PyObject_GetAttrString(site, "main"); main = PyObject_GetAttrString(site, "main");
if (main == NULL || !PyCallable_Check(main)) if (main == NULL || !PyCallable_Check(main))
ret = calibre_show_python_error(L"site module has no main function", 1); ret = calibre_show_python_error(L"site module has no main function", 1);
else { else {
Py_XINCREF(main); Py_INCREF(main);
res = PyObject_CallObject(main, NULL); res = PyObject_CallObject(main, NULL);
if (res == NULL) if (res == NULL)
ret = calibre_show_python_error(L"Python function terminated unexpectedly", 1); ret = calibre_show_python_error(L"Python function terminated unexpectedly", 1);
else { else {
#if PY_VERSION_MAJOR < 3
if (PyInt_Check(res)) {
ret = PyInt_AS_LONG(res);
}
#else
if (PyLong_Check(res)) {
ret = PyLong_AsLong(res);
}
#endif
Py_DECREF(res);
} }
} }
} }
PyErr_Clear(); PyErr_Clear();
Py_Finalize(); Py_Finalize();
if (code_page != CP_UTF8) SetConsoleOutputCP(code_page); if (code_page != CP_UTF8) SetConsoleOutputCP(code_page);
/* printf("111111111111 returning: %d\r\n", ret); */
//printf("11111 Returning: %d\r\n", ret);
return ret; return ret;
} }
wchar_t* get_temp_filename(const wchar_t *prefix) {
DWORD dwRetVal;
UINT uRetVal;
wchar_t *szTempName;
wchar_t lpPathBuffer[MAX_PATH];
szTempName = (wchar_t *)LocalAlloc(LMEM_ZEROINIT, sizeof(wchar_t)*MAX_PATH);
dwRetVal = GetTempPath(MAX_PATH, lpPathBuffer);
if (dwRetVal > MAX_PATH || (dwRetVal == 0)) {
ExitProcess(show_last_error(L"Failed to get temp path."));
}
uRetVal = GetTempFileName(lpPathBuffer, // directory for tmp files
prefix, // temp file name prefix
0, // create unique name
szTempName); // buffer for name
if (uRetVal == 0) {
ExitProcess(show_last_error(L"Failed to get temp file name"));
}
return szTempName;
}

View File

@ -194,7 +194,7 @@ def sanitize_path():
needed_paths.append(p) needed_paths.append(p)
executables.remove(x) executables.remove(x)
sw = os.environ['SW'] sw = os.environ['SW']
paths = r'{0}\private\python\DLLs {0}\private\python\Lib\site-packages\pywin32_system32 {0}\bin {0}\qt\bin C:\Windows\System32'.format( paths = r'{0}\private\python\bin {0}\private\python\Lib\site-packages\pywin32_system32 {0}\bin {0}\qt\bin C:\Windows\System32'.format(
sw sw
).split() + needed_paths ).split() + needed_paths
os.environ['PATH'] = os.pathsep.join(paths) os.environ['PATH'] = os.pathsep.join(paths)