2024-08-07 14:14:04 +08:00
|
|
|
|
|
2024-05-01 14:59:50 +08:00
|
|
|
|
#include "PyStand.h"
|
|
|
|
|
|
2024-10-09 00:09:15 +08:00
|
|
|
|
#include <iomanip>
|
|
|
|
|
#include <sstream>
|
|
|
|
|
#include <chrono>
|
|
|
|
|
#include <ctime>
|
|
|
|
|
|
2024-05-01 14:59:50 +08:00
|
|
|
|
//---------------------------------------------------------------------
|
|
|
|
|
// dtor
|
|
|
|
|
//---------------------------------------------------------------------
|
|
|
|
|
PyStand::~PyStand()
|
|
|
|
|
{
|
|
|
|
|
FreeLibrary(_hDLL);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//---------------------------------------------------------------------
|
|
|
|
|
// ctor
|
|
|
|
|
//---------------------------------------------------------------------
|
|
|
|
|
PyStand::PyStand(const wchar_t *runtime)
|
|
|
|
|
{
|
|
|
|
|
_hDLL = NULL;
|
|
|
|
|
_Py_Main = NULL;
|
2024-05-01 17:28:43 +08:00
|
|
|
|
if (CheckEnviron(runtime) == false)
|
|
|
|
|
{
|
2024-05-01 14:59:50 +08:00
|
|
|
|
exit(1);
|
|
|
|
|
}
|
2024-05-01 17:28:43 +08:00
|
|
|
|
if (LoadPython() == false)
|
|
|
|
|
{
|
2024-05-01 14:59:50 +08:00
|
|
|
|
exit(2);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//---------------------------------------------------------------------
|
2024-05-01 17:28:43 +08:00
|
|
|
|
// init: _args, _argv, _cwd, _pystand, _home, _runtime,
|
2024-05-01 14:59:50 +08:00
|
|
|
|
//---------------------------------------------------------------------
|
|
|
|
|
bool PyStand::CheckEnviron(const wchar_t *rtp)
|
|
|
|
|
{
|
|
|
|
|
// init: _args, _argv
|
|
|
|
|
LPWSTR *argvw;
|
|
|
|
|
int argc;
|
|
|
|
|
_args = GetCommandLineW();
|
|
|
|
|
argvw = CommandLineToArgvW(_args.c_str(), &argc);
|
2024-05-01 17:28:43 +08:00
|
|
|
|
if (argvw == NULL)
|
|
|
|
|
{
|
2024-05-01 14:59:50 +08:00
|
|
|
|
MessageBoxA(NULL, "Error in CommandLineToArgvW()", "ERROR", MB_OK);
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
_argv.resize(argc);
|
2024-05-01 17:28:43 +08:00
|
|
|
|
for (int i = 0; i < argc; i++)
|
|
|
|
|
{
|
2024-05-01 14:59:50 +08:00
|
|
|
|
_argv[i] = argvw[i];
|
|
|
|
|
}
|
|
|
|
|
LocalFree(argvw);
|
|
|
|
|
|
|
|
|
|
// init: _cwd (current working directory)
|
|
|
|
|
wchar_t path[MAX_PATH + 10];
|
|
|
|
|
GetCurrentDirectoryW(MAX_PATH + 1, path);
|
|
|
|
|
_cwd = path;
|
|
|
|
|
|
|
|
|
|
// init: _pystand (full path of PyStand.exe)
|
|
|
|
|
GetModuleFileNameW(NULL, path, MAX_PATH + 1);
|
|
|
|
|
#if 0
|
|
|
|
|
wsprintf(path, L"e:\\github\\tools\\pystand\\pystand.exe");
|
|
|
|
|
#endif
|
|
|
|
|
_pystand = path;
|
|
|
|
|
|
|
|
|
|
// init: _home
|
|
|
|
|
int size = (int)wcslen(path);
|
2024-05-01 17:28:43 +08:00
|
|
|
|
for (; size > 0; size--)
|
|
|
|
|
{
|
|
|
|
|
if (path[size - 1] == L'/')
|
|
|
|
|
break;
|
|
|
|
|
if (path[size - 1] == L'\\')
|
|
|
|
|
break;
|
2024-05-01 14:59:50 +08:00
|
|
|
|
}
|
|
|
|
|
path[size] = 0;
|
|
|
|
|
SetCurrentDirectoryW(path);
|
|
|
|
|
GetCurrentDirectoryW(MAX_PATH + 1, path);
|
|
|
|
|
_home = path;
|
|
|
|
|
SetCurrentDirectoryW(_cwd.c_str());
|
|
|
|
|
|
|
|
|
|
// init: _runtime (embedded python directory)
|
|
|
|
|
bool abspath = false;
|
2024-05-01 17:28:43 +08:00
|
|
|
|
if (wcslen(rtp) >= 3)
|
|
|
|
|
{
|
|
|
|
|
if (rtp[1] == L':')
|
|
|
|
|
{
|
2024-05-01 14:59:50 +08:00
|
|
|
|
if (rtp[2] == L'/' || rtp[2] == L'\\')
|
|
|
|
|
abspath = true;
|
|
|
|
|
}
|
|
|
|
|
}
|
2024-05-01 17:28:43 +08:00
|
|
|
|
if (abspath == false)
|
|
|
|
|
{
|
2024-05-01 14:59:50 +08:00
|
|
|
|
_runtime = _home + L"\\" + rtp;
|
|
|
|
|
}
|
2024-05-01 17:28:43 +08:00
|
|
|
|
else
|
|
|
|
|
{
|
2024-05-01 14:59:50 +08:00
|
|
|
|
_runtime = rtp;
|
|
|
|
|
}
|
|
|
|
|
GetFullPathNameW(_runtime.c_str(), MAX_PATH + 1, path, NULL);
|
|
|
|
|
_runtime = path;
|
|
|
|
|
|
|
|
|
|
// check home
|
|
|
|
|
std::wstring check = _runtime;
|
2024-05-01 17:28:43 +08:00
|
|
|
|
if (!PathFileExistsW(check.c_str()))
|
|
|
|
|
{
|
2024-05-01 14:59:50 +08:00
|
|
|
|
std::wstring msg = L"Missing embedded Python3 in:\n" + check;
|
|
|
|
|
MessageBoxW(NULL, msg.c_str(), L"ERROR", MB_OK);
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// check python3.dll
|
|
|
|
|
std::wstring check2 = _runtime + L"\\python3.dll";
|
2024-05-01 17:28:43 +08:00
|
|
|
|
if (!PathFileExistsW(check2.c_str()))
|
|
|
|
|
{
|
2024-05-01 14:59:50 +08:00
|
|
|
|
std::wstring msg = L"Missing python3.dll in:\r\n" + check;
|
|
|
|
|
MessageBoxW(NULL, msg.c_str(), L"ERROR", MB_OK);
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// setup environment
|
|
|
|
|
SetEnvironmentVariableW(L"PYSTAND", _pystand.c_str());
|
|
|
|
|
SetEnvironmentVariableW(L"PYSTAND_HOME", _home.c_str());
|
|
|
|
|
SetEnvironmentVariableW(L"PYSTAND_RUNTIME", _runtime.c_str());
|
|
|
|
|
|
|
|
|
|
// unnecessary to init PYSTAND_SCRIPT here.
|
|
|
|
|
#if 0
|
|
|
|
|
SetEnvironmentVariableW(L"PYSTAND_SCRIPT", _script.c_str());
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
#if 0
|
|
|
|
|
wprintf(L"%s - %s\n", _pystand.c_str(), path);
|
|
|
|
|
MessageBoxW(NULL, _pystand.c_str(), _home.c_str(), MB_OK);
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//---------------------------------------------------------------------
|
|
|
|
|
// load python
|
|
|
|
|
//---------------------------------------------------------------------
|
|
|
|
|
bool PyStand::LoadPython()
|
|
|
|
|
{
|
|
|
|
|
std::wstring runtime = _runtime;
|
|
|
|
|
std::wstring previous;
|
|
|
|
|
|
|
|
|
|
// save current directory
|
|
|
|
|
wchar_t path[MAX_PATH + 10];
|
|
|
|
|
GetCurrentDirectoryW(MAX_PATH + 1, path);
|
|
|
|
|
previous = path;
|
|
|
|
|
|
|
|
|
|
// python dll must be load under "runtime"
|
|
|
|
|
SetCurrentDirectoryW(runtime.c_str());
|
|
|
|
|
// LoadLibrary
|
|
|
|
|
_hDLL = (HINSTANCE)LoadLibraryA("python3.dll");
|
2024-05-01 17:28:43 +08:00
|
|
|
|
if (_hDLL)
|
|
|
|
|
{
|
2024-05-01 14:59:50 +08:00
|
|
|
|
_Py_Main = (t_Py_Main)GetProcAddress(_hDLL, "Py_Main");
|
2024-05-01 17:28:43 +08:00
|
|
|
|
}
|
2024-05-01 14:59:50 +08:00
|
|
|
|
|
|
|
|
|
// restore director
|
|
|
|
|
SetCurrentDirectoryW(previous.c_str());
|
|
|
|
|
|
2024-05-01 17:28:43 +08:00
|
|
|
|
if (_hDLL == NULL)
|
|
|
|
|
{
|
2024-05-01 14:59:50 +08:00
|
|
|
|
std::wstring msg = L"Cannot load python3.dll from:\r\n" + runtime;
|
|
|
|
|
MessageBoxW(NULL, msg.c_str(), L"ERROR", MB_OK);
|
|
|
|
|
return false;
|
|
|
|
|
}
|
2024-05-01 17:28:43 +08:00
|
|
|
|
else if (_Py_Main == NULL)
|
|
|
|
|
{
|
2024-05-01 14:59:50 +08:00
|
|
|
|
std::wstring msg = L"Cannot find Py_Main() in:\r\n";
|
|
|
|
|
msg += runtime + L"\\python3.dll";
|
|
|
|
|
MessageBoxW(NULL, msg.c_str(), L"ERROR", MB_OK);
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//---------------------------------------------------------------------
|
|
|
|
|
// run string
|
|
|
|
|
//---------------------------------------------------------------------
|
|
|
|
|
int PyStand::RunString(const wchar_t *script)
|
|
|
|
|
{
|
2024-05-01 17:28:43 +08:00
|
|
|
|
if (_Py_Main == NULL)
|
|
|
|
|
{
|
2024-05-01 14:59:50 +08:00
|
|
|
|
return -1;
|
|
|
|
|
}
|
|
|
|
|
int hr = 0;
|
|
|
|
|
int i;
|
|
|
|
|
_py_argv.resize(0);
|
|
|
|
|
// init arguments
|
|
|
|
|
_py_argv.push_back(_argv[0]);
|
|
|
|
|
_py_argv.push_back(L"-I");
|
|
|
|
|
_py_argv.push_back(L"-s");
|
|
|
|
|
_py_argv.push_back(L"-S");
|
|
|
|
|
_py_argv.push_back(L"-c");
|
|
|
|
|
_py_argv.push_back(script);
|
2024-05-01 17:28:43 +08:00
|
|
|
|
for (i = 1; i < (int)_argv.size(); i++)
|
|
|
|
|
{
|
2024-05-01 14:59:50 +08:00
|
|
|
|
_py_argv.push_back(_argv[i]);
|
|
|
|
|
}
|
|
|
|
|
// finalize arguments
|
|
|
|
|
_py_args.resize(0);
|
2024-05-01 17:28:43 +08:00
|
|
|
|
for (i = 0; i < (int)_py_argv.size(); i++)
|
|
|
|
|
{
|
|
|
|
|
_py_args.push_back((wchar_t *)_py_argv[i].c_str());
|
2024-05-01 14:59:50 +08:00
|
|
|
|
}
|
|
|
|
|
hr = _Py_Main((int)_py_args.size(), &_py_args[0]);
|
|
|
|
|
return hr;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//---------------------------------------------------------------------
|
|
|
|
|
// LoadScript()
|
|
|
|
|
//---------------------------------------------------------------------
|
|
|
|
|
int PyStand::DetectScript()
|
|
|
|
|
{
|
|
|
|
|
// init: _script (init script like PyStand.int or PyStand.py)
|
|
|
|
|
int size = (int)_pystand.size() - 1;
|
2024-05-01 17:28:43 +08:00
|
|
|
|
for (; size >= 0; size--)
|
|
|
|
|
{
|
|
|
|
|
if (_pystand[size] == L'.')
|
|
|
|
|
break;
|
2024-05-01 14:59:50 +08:00
|
|
|
|
}
|
2024-05-01 17:28:43 +08:00
|
|
|
|
if (size < 0)
|
|
|
|
|
size = (int)_pystand.size();
|
2024-05-01 14:59:50 +08:00
|
|
|
|
std::wstring main = _pystand.substr(0, size);
|
2024-05-01 17:28:43 +08:00
|
|
|
|
std::vector<const wchar_t *> exts;
|
2024-05-01 14:59:50 +08:00
|
|
|
|
std::vector<std::wstring> scripts;
|
|
|
|
|
_script.clear();
|
2024-05-01 17:12:05 +08:00
|
|
|
|
|
2024-05-01 14:59:50 +08:00
|
|
|
|
std::wstring test;
|
2024-05-01 17:28:43 +08:00
|
|
|
|
test = _home + L"\\LunaTranslator\\LunaTranslator_main.py";
|
|
|
|
|
if (PathFileExistsW(test.c_str()))
|
|
|
|
|
{
|
2024-05-01 14:59:50 +08:00
|
|
|
|
_script = test;
|
|
|
|
|
}
|
2024-05-01 17:28:43 +08:00
|
|
|
|
if (_script.empty())
|
|
|
|
|
{
|
|
|
|
|
std::wstring msg = L"Can't find :\r\n" + test;
|
|
|
|
|
MessageBoxW(NULL, msg.c_str(), L"ERROR", MB_OK);
|
|
|
|
|
return -1;
|
2024-05-01 14:59:50 +08:00
|
|
|
|
}
|
|
|
|
|
SetEnvironmentVariableW(L"PYSTAND_SCRIPT", _script.c_str());
|
2024-07-18 16:34:41 +08:00
|
|
|
|
|
2024-05-01 19:34:32 +08:00
|
|
|
|
std::vector<wchar_t> buffer(MAX_PATH);
|
|
|
|
|
GetModuleFileNameW(GetModuleHandle(0), buffer.data(), MAX_PATH);
|
|
|
|
|
SetEnvironmentVariableW(L"LUNA_EXE_NAME", buffer.data());
|
2024-07-18 16:34:41 +08:00
|
|
|
|
|
2024-05-01 14:59:50 +08:00
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//---------------------------------------------------------------------
|
|
|
|
|
// init script
|
|
|
|
|
//---------------------------------------------------------------------
|
2024-05-01 17:28:43 +08:00
|
|
|
|
const auto init_script =
|
2024-10-09 00:09:15 +08:00
|
|
|
|
LR"(
|
|
|
|
|
import sys
|
|
|
|
|
import os
|
|
|
|
|
PYSTAND = os.environ['PYSTAND']
|
|
|
|
|
PYSTAND_HOME = os.environ['PYSTAND_HOME']
|
|
|
|
|
PYSTAND_RUNTIME = os.environ['PYSTAND_RUNTIME']
|
|
|
|
|
PYSTAND_SCRIPT = os.environ['PYSTAND_SCRIPT']
|
|
|
|
|
sys.path_origin = [n for n in sys.path]
|
|
|
|
|
sys.PYSTAND = PYSTAND
|
|
|
|
|
sys.PYSTAND_HOME = PYSTAND_HOME
|
|
|
|
|
sys.PYSTAND_SCRIPT = PYSTAND_SCRIPT
|
|
|
|
|
def MessageBox(msg, info = 'Message'):
|
|
|
|
|
import ctypes
|
|
|
|
|
ctypes.windll.user32.MessageBoxW(None, str(msg), str(info), 0)
|
|
|
|
|
return 0
|
|
|
|
|
os.MessageBox = MessageBox
|
|
|
|
|
sys.stdout=sys.stderr
|
|
|
|
|
)"
|
2024-05-06 19:37:31 +08:00
|
|
|
|
#ifndef PYSTAND_CONSOLE
|
2024-10-09 00:09:15 +08:00
|
|
|
|
LR"(
|
|
|
|
|
try:
|
|
|
|
|
fd = os.open('CONOUT$', os.O_RDWR | os.O_BINARY)
|
|
|
|
|
fp = os.fdopen(fd, 'w')
|
|
|
|
|
sys.stdout = fp
|
|
|
|
|
sys.stderr = fp
|
|
|
|
|
attached = True
|
|
|
|
|
except Exception as e:
|
2024-10-29 15:53:11 +08:00
|
|
|
|
try:
|
|
|
|
|
fp = open(os.devnull, 'w', errors='ignore') # sometimes FileNotFound Error: [Errno 2]No such file or directory: 'nul'
|
|
|
|
|
sys.stdout = fp
|
|
|
|
|
sys.stderr = fp
|
|
|
|
|
attached = False
|
|
|
|
|
except:
|
|
|
|
|
pass
|
2024-10-09 00:09:15 +08:00
|
|
|
|
)"
|
2024-05-06 19:37:31 +08:00
|
|
|
|
#endif
|
2024-10-09 00:09:15 +08:00
|
|
|
|
LR"(
|
|
|
|
|
sys.argv = [PYSTAND_SCRIPT] + sys.argv[1:]
|
|
|
|
|
text = open(PYSTAND_SCRIPT, 'rb').read()
|
|
|
|
|
environ = {'__file__': PYSTAND_SCRIPT, '__name__': '__main__'}
|
|
|
|
|
environ['__package__'] = None
|
|
|
|
|
)"
|
2024-05-01 14:59:50 +08:00
|
|
|
|
#ifndef PYSTAND_CONSOLE
|
2024-10-09 00:09:15 +08:00
|
|
|
|
LR"(
|
|
|
|
|
try:
|
|
|
|
|
code = compile(text, PYSTAND_SCRIPT, 'exec')
|
|
|
|
|
exec(code, environ)
|
|
|
|
|
except Exception:
|
|
|
|
|
if attached:
|
|
|
|
|
raise
|
|
|
|
|
import traceback, io
|
|
|
|
|
sio = io.StringIO()
|
|
|
|
|
traceback.print_exc(file = sio)
|
|
|
|
|
os.MessageBox(sio.getvalue(), 'Error')
|
|
|
|
|
)"
|
2024-05-01 14:59:50 +08:00
|
|
|
|
#else
|
2024-10-09 00:09:15 +08:00
|
|
|
|
LR"(
|
|
|
|
|
code = compile(text, PYSTAND_SCRIPT, 'exec')
|
|
|
|
|
exec(code, environ)
|
|
|
|
|
)"
|
2024-05-01 14:59:50 +08:00
|
|
|
|
#endif
|
2024-05-01 17:28:43 +08:00
|
|
|
|
"";
|
2024-05-01 14:59:50 +08:00
|
|
|
|
|
|
|
|
|
//---------------------------------------------------------------------
|
|
|
|
|
// main
|
|
|
|
|
//---------------------------------------------------------------------
|
|
|
|
|
|
|
|
|
|
//! flag: -static
|
2024-05-01 17:28:43 +08:00
|
|
|
|
//! src:
|
2024-05-01 14:59:50 +08:00
|
|
|
|
//! link: stdc++, shlwapi, resource.o
|
|
|
|
|
//! prebuild: windres resource.rc -o resource.o
|
|
|
|
|
//! mode: win
|
|
|
|
|
//! int: objs
|
|
|
|
|
|
|
|
|
|
int main()
|
|
|
|
|
{
|
2024-08-07 14:14:04 +08:00
|
|
|
|
{
|
|
|
|
|
// 当更新进行时,禁止启动
|
|
|
|
|
AutoHandle hMutex = CreateMutex(NULL, FALSE, L"LUNA_UPDATER_SINGLE");
|
|
|
|
|
if (GetLastError() == ERROR_ALREADY_EXISTS)
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
2024-07-18 16:34:41 +08:00
|
|
|
|
auto __handle = AutoHandle(CreateMutexA(&allAccess, FALSE, "LUNA_UPDATER_BLOCK"));
|
2024-05-01 17:12:05 +08:00
|
|
|
|
PyStand ps(L"LunaTranslator\\runtime");
|
2024-05-01 17:28:43 +08:00
|
|
|
|
if (ps.DetectScript() != 0)
|
|
|
|
|
{
|
2024-05-01 14:59:50 +08:00
|
|
|
|
return 3;
|
|
|
|
|
}
|
|
|
|
|
#ifndef PYSTAND_CONSOLE
|
2024-10-09 00:09:15 +08:00
|
|
|
|
// winmain下的stderr没有任何卵用,对于崩溃时的stderr根本显示不出来,所以还是用控制台来保存log吧。
|
2024-05-01 17:28:43 +08:00
|
|
|
|
if (AttachConsole(ATTACH_PARENT_PROCESS))
|
|
|
|
|
{
|
2024-05-01 14:59:50 +08:00
|
|
|
|
freopen("CONOUT$", "w", stdout);
|
|
|
|
|
freopen("CONOUT$", "w", stderr);
|
|
|
|
|
int fd = _fileno(stdout);
|
2024-05-01 17:28:43 +08:00
|
|
|
|
if (fd >= 0)
|
|
|
|
|
{
|
2024-05-01 14:59:50 +08:00
|
|
|
|
std::string fn = std::to_string(fd);
|
|
|
|
|
SetEnvironmentVariableA("PYSTAND_STDOUT", fn.c_str());
|
|
|
|
|
}
|
|
|
|
|
fd = _fileno(stdin);
|
2024-05-01 17:28:43 +08:00
|
|
|
|
if (fd >= 0)
|
|
|
|
|
{
|
2024-05-01 14:59:50 +08:00
|
|
|
|
std::string fn = std::to_string(fd);
|
|
|
|
|
SetEnvironmentVariableA("PYSTAND_STDIN", fn.c_str());
|
|
|
|
|
}
|
|
|
|
|
}
|
2024-10-09 00:09:15 +08:00
|
|
|
|
#else
|
2024-10-09 01:23:01 +08:00
|
|
|
|
SetConsoleOutputCP(CP_UTF8);
|
|
|
|
|
auto getCurrentTimestamp = []
|
2024-10-09 00:09:15 +08:00
|
|
|
|
{
|
2024-10-09 01:23:01 +08:00
|
|
|
|
auto now = std::chrono::system_clock::now();
|
|
|
|
|
std::time_t now_time_t = std::chrono::system_clock::to_time_t(now);
|
|
|
|
|
std::tm now_tm = *std::localtime(&now_time_t);
|
|
|
|
|
std::ostringstream oss;
|
|
|
|
|
oss << std::put_time(&now_tm, "log_%Y-%m-%d-%H-%M-%S.txt");
|
|
|
|
|
return oss.str();
|
|
|
|
|
};
|
|
|
|
|
auto curr = getCurrentTimestamp();
|
|
|
|
|
freopen(curr.c_str(), "a", stderr);
|
2024-05-01 14:59:50 +08:00
|
|
|
|
#endif
|
|
|
|
|
int hr = ps.RunString(init_script);
|
|
|
|
|
return hr;
|
|
|
|
|
}
|
2024-10-09 00:09:15 +08:00
|
|
|
|
|
|
|
|
|
int WINAPI
|
|
|
|
|
WinMain(HINSTANCE hInst, HINSTANCE hPrevInst, LPSTR args, int show)
|
|
|
|
|
{
|
|
|
|
|
return main();
|
|
|
|
|
}
|