2020-08-22 18:47:58 +05:30

171 lines
5.1 KiB
C

/*
* Copyright 2009 Kovid Goyal
*/
#define UNICODE
#define _WIN32_WINNT 0x0502
#define WINDOWS_LEAN_AND_MEAN
#include <windows.h>
#include <Python.h>
#include <stdio.h>
#include <stdlib.h>
#include <Shellapi.h>
#include <delayimp.h>
#include <io.h>
#include <fcntl.h>
#include "../run-python.h"
static int GUI_APP = 0;
static char python_dll[] = PYDLL;
void set_gui_app(int yes) { GUI_APP = yes; }
static int _show_error(const wchar_t *preamble, const wchar_t *msg, const int code) {
static wchar_t buf[4096];
static char utf8_buf[4096] = {0};
int n = WideCharToMultiByte(CP_UTF8, 0, preamble, -1, utf8_buf, sizeof(utf8_buf) - 1, NULL, NULL);
if (n > 0) fprintf(stderr, "%s\r\n ", utf8_buf);
n = WideCharToMultiByte(CP_UTF8, 0, msg, -1, utf8_buf, sizeof(utf8_buf) - 1, NULL, NULL);
if (n > 0) fprintf(stderr, "%s (Error Code: %d)\r\n ", utf8_buf, code);
fflush(stderr);
if (GUI_APP) {
_snwprintf_s(buf, arraysz(buf), _TRUNCATE, L"%ls\r\n %ls (Error Code: %d)\r\n", preamble, msg, code);
MessageBeep(MB_ICONERROR);
MessageBox(NULL, buf, NULL, MB_OK|MB_ICONERROR);
}
return code;
}
int show_last_error_crt(wchar_t *preamble) {
wchar_t buf[1000];
int err = 0;
_get_errno(&err);
_wcserror_s(buf, 1000, err);
return _show_error(preamble, buf, err);
}
int show_last_error(wchar_t *preamble) {
wchar_t *msg = NULL;
DWORD dw = GetLastError();
int ret;
FormatMessage(
FORMAT_MESSAGE_ALLOCATE_BUFFER |
FORMAT_MESSAGE_FROM_SYSTEM |
FORMAT_MESSAGE_IGNORE_INSERTS,
NULL,
dw,
MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
(LPWSTR)&msg,
0,
NULL );
ret = _show_error(preamble, msg, (int)dw);
if (msg != NULL) LocalFree(msg);
return ret;
}
static wchar_t qt_prefix_dir[MAX_PATH] = {0};
static wchar_t w_program_name[MAX_PATH] = {0};
static void
get_app_dirw(void) {
wchar_t buf[MAX_PATH] = {0};
wchar_t drive[4] = L"\0\0\0";
DWORD sz; errno_t err;
sz = GetModuleFileNameW(NULL, w_program_name, MAX_PATH);
if (sz >= MAX_PATH-1) ExitProcess(_show_error(L"Installation directory path too long", L"", 1));
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"));
_snwprintf_s(interpreter_data.app_dir, MAX_PATH, _TRUNCATE, L"%ls%ls", drive, buf);
}
static void
get_install_locations(void) {
get_app_dirw();
_snwprintf_s(qt_prefix_dir, MAX_PATH-1, _TRUNCATE, L"%ls\\app", interpreter_data.app_dir);
_wputenv_s(L"CALIBRE_QT_PREFIX", qt_prefix_dir);
}
static void
load_python_dll() {
get_install_locations();
if (FAILED(__HrLoadAllImportsForDll(python_dll)))
ExitProcess(_show_error(L"Failed to delay load the python dll", L"", 1));
}
const static wchar_t out_of_memory[] = L"Out of memory";
UINT
setup_streams() {
UINT code_page = GetConsoleOutputCP();
SetConsoleOutputCP(CP_UTF8);
//printf("input cp: %d output cp: %d\r\n", GetConsoleCP(), GetConsoleOutputCP());
return code_page;
}
void redirect_out_stream(FILE *stream) {
FILE *f = NULL;
errno_t err;
err = freopen_s(&f, "NUL", "wt", stream);
if (err != 0) {
ExitProcess(show_last_error_crt(L"Failed to redirect stdout/stderr to NUL. This indicates a corrupted Windows install.\r\n You should contact Microsoft for assistance and/or follow the steps described here:\r\n http://bytes.com/topic/net/answers/264804-compile-error-null-device-missing"));
}
}
static void
null_invalid_parameter_handler(
const wchar_t * expression,
const wchar_t * function,
const wchar_t * file,
unsigned int line,
uintptr_t pReserved
) {
// The python runtime expects various system calls with invalid parameters
// to return errors instead of aborting the program. So get the windows CRT
// to do that.
}
__declspec(dllexport) int __cdecl
simple_print(const wchar_t *msg) {
int n = wprintf(L"%ls", msg); fflush(stdout);
return n;
}
__declspec(dllexport) int __cdecl
execute_python_entrypoint(const wchar_t *basename, const wchar_t *module, const wchar_t *function, int is_gui_app) {
int ret = 0;
// Prevent Windows' idiotic error dialog popups when various win32 api functions fail
SetErrorMode(SEM_FAILCRITICALERRORS | SEM_NOALIGNMENTFAULTEXCEPT | SEM_NOGPFAULTERRORBOX | SEM_NOOPENFILEERRORBOX);
if (is_gui_app) {
// Redirect stdout and stderr to NUL so that python does not fail writing to them
redirect_out_stream(stdout);
redirect_out_stream(stderr);
}
set_gui_app(is_gui_app);
// Disable the invalid parameter handler
_set_invalid_parameter_handler(null_invalid_parameter_handler);
interpreter_data.argv = CommandLineToArgvW(GetCommandLineW(), &interpreter_data.argc);
if (interpreter_data.argv == NULL) ExitProcess(show_last_error(L"Failed to get command line"));
interpreter_data.basename = basename; interpreter_data.module = module; interpreter_data.function = function;
load_python_dll();
pre_initialize_interpreter(is_gui_app);
run_interpreter();
/* printf("111111111111 returning: %d\r\n", ret); */
return ret;
}