Update PyStand.cpp

This commit is contained in:
恍兮惚兮 2024-05-01 17:28:43 +08:00
parent 69b03bcb43
commit 69d4695e23

View File

@ -1,6 +1,6 @@
//===================================================================== //=====================================================================
// //
// PyStand.cpp - // PyStand.cpp -
// //
// Created by skywind on 2022/02/03 // Created by skywind on 2022/02/03
// Last Modified: 2023/03/17 20:06 // Last Modified: 2023/03/17 20:06
@ -22,7 +22,6 @@
#pragma comment(lib, "shlwapi.lib") #pragma comment(lib, "shlwapi.lib")
#endif #endif
//--------------------------------------------------------------------- //---------------------------------------------------------------------
// dtor // dtor
//--------------------------------------------------------------------- //---------------------------------------------------------------------
@ -31,7 +30,6 @@ PyStand::~PyStand()
FreeLibrary(_hDLL); FreeLibrary(_hDLL);
} }
//--------------------------------------------------------------------- //---------------------------------------------------------------------
// ctor // ctor
//--------------------------------------------------------------------- //---------------------------------------------------------------------
@ -39,16 +37,18 @@ PyStand::PyStand(const wchar_t *runtime)
{ {
_hDLL = NULL; _hDLL = NULL;
_Py_Main = NULL; _Py_Main = NULL;
if (CheckEnviron(runtime) == false) { if (CheckEnviron(runtime) == false)
{
exit(1); exit(1);
} }
if (LoadPython() == false) { if (LoadPython() == false)
{
exit(2); exit(2);
} }
} }
//--------------------------------------------------------------------- //---------------------------------------------------------------------
// init: _args, _argv, _cwd, _pystand, _home, _runtime, // init: _args, _argv, _cwd, _pystand, _home, _runtime,
//--------------------------------------------------------------------- //---------------------------------------------------------------------
bool PyStand::CheckEnviron(const wchar_t *rtp) bool PyStand::CheckEnviron(const wchar_t *rtp)
{ {
@ -57,12 +57,14 @@ bool PyStand::CheckEnviron(const wchar_t *rtp)
int argc; int argc;
_args = GetCommandLineW(); _args = GetCommandLineW();
argvw = CommandLineToArgvW(_args.c_str(), &argc); argvw = CommandLineToArgvW(_args.c_str(), &argc);
if (argvw == NULL) { if (argvw == NULL)
{
MessageBoxA(NULL, "Error in CommandLineToArgvW()", "ERROR", MB_OK); MessageBoxA(NULL, "Error in CommandLineToArgvW()", "ERROR", MB_OK);
return false; return false;
} }
_argv.resize(argc); _argv.resize(argc);
for (int i = 0; i < argc; i++) { for (int i = 0; i < argc; i++)
{
_argv[i] = argvw[i]; _argv[i] = argvw[i];
} }
LocalFree(argvw); LocalFree(argvw);
@ -81,9 +83,12 @@ bool PyStand::CheckEnviron(const wchar_t *rtp)
// init: _home // init: _home
int size = (int)wcslen(path); int size = (int)wcslen(path);
for (; size > 0; size--) { for (; size > 0; size--)
if (path[size - 1] == L'/') break; {
if (path[size - 1] == L'\\') break; if (path[size - 1] == L'/')
break;
if (path[size - 1] == L'\\')
break;
} }
path[size] = 0; path[size] = 0;
SetCurrentDirectoryW(path); SetCurrentDirectoryW(path);
@ -93,16 +98,20 @@ bool PyStand::CheckEnviron(const wchar_t *rtp)
// init: _runtime (embedded python directory) // init: _runtime (embedded python directory)
bool abspath = false; bool abspath = false;
if (wcslen(rtp) >= 3) { if (wcslen(rtp) >= 3)
if (rtp[1] == L':') { {
if (rtp[1] == L':')
{
if (rtp[2] == L'/' || rtp[2] == L'\\') if (rtp[2] == L'/' || rtp[2] == L'\\')
abspath = true; abspath = true;
} }
} }
if (abspath == false) { if (abspath == false)
{
_runtime = _home + L"\\" + rtp; _runtime = _home + L"\\" + rtp;
} }
else { else
{
_runtime = rtp; _runtime = rtp;
} }
GetFullPathNameW(_runtime.c_str(), MAX_PATH + 1, path, NULL); GetFullPathNameW(_runtime.c_str(), MAX_PATH + 1, path, NULL);
@ -110,7 +119,8 @@ bool PyStand::CheckEnviron(const wchar_t *rtp)
// check home // check home
std::wstring check = _runtime; std::wstring check = _runtime;
if (!PathFileExistsW(check.c_str())) { if (!PathFileExistsW(check.c_str()))
{
std::wstring msg = L"Missing embedded Python3 in:\n" + check; std::wstring msg = L"Missing embedded Python3 in:\n" + check;
MessageBoxW(NULL, msg.c_str(), L"ERROR", MB_OK); MessageBoxW(NULL, msg.c_str(), L"ERROR", MB_OK);
return false; return false;
@ -118,7 +128,8 @@ bool PyStand::CheckEnviron(const wchar_t *rtp)
// check python3.dll // check python3.dll
std::wstring check2 = _runtime + L"\\python3.dll"; std::wstring check2 = _runtime + L"\\python3.dll";
if (!PathFileExistsW(check2.c_str())) { if (!PathFileExistsW(check2.c_str()))
{
std::wstring msg = L"Missing python3.dll in:\r\n" + check; std::wstring msg = L"Missing python3.dll in:\r\n" + check;
MessageBoxW(NULL, msg.c_str(), L"ERROR", MB_OK); MessageBoxW(NULL, msg.c_str(), L"ERROR", MB_OK);
return false; return false;
@ -142,7 +153,6 @@ bool PyStand::CheckEnviron(const wchar_t *rtp)
return true; return true;
} }
//--------------------------------------------------------------------- //---------------------------------------------------------------------
// load python // load python
//--------------------------------------------------------------------- //---------------------------------------------------------------------
@ -160,19 +170,22 @@ bool PyStand::LoadPython()
SetCurrentDirectoryW(runtime.c_str()); SetCurrentDirectoryW(runtime.c_str());
// LoadLibrary // LoadLibrary
_hDLL = (HINSTANCE)LoadLibraryA("python3.dll"); _hDLL = (HINSTANCE)LoadLibraryA("python3.dll");
if (_hDLL) { if (_hDLL)
{
_Py_Main = (t_Py_Main)GetProcAddress(_hDLL, "Py_Main"); _Py_Main = (t_Py_Main)GetProcAddress(_hDLL, "Py_Main");
} }
// restore director // restore director
SetCurrentDirectoryW(previous.c_str()); SetCurrentDirectoryW(previous.c_str());
if (_hDLL == NULL) { if (_hDLL == NULL)
{
std::wstring msg = L"Cannot load python3.dll from:\r\n" + runtime; std::wstring msg = L"Cannot load python3.dll from:\r\n" + runtime;
MessageBoxW(NULL, msg.c_str(), L"ERROR", MB_OK); MessageBoxW(NULL, msg.c_str(), L"ERROR", MB_OK);
return false; return false;
} }
else if (_Py_Main == NULL) { else if (_Py_Main == NULL)
{
std::wstring msg = L"Cannot find Py_Main() in:\r\n"; std::wstring msg = L"Cannot find Py_Main() in:\r\n";
msg += runtime + L"\\python3.dll"; msg += runtime + L"\\python3.dll";
MessageBoxW(NULL, msg.c_str(), L"ERROR", MB_OK); MessageBoxW(NULL, msg.c_str(), L"ERROR", MB_OK);
@ -181,13 +194,13 @@ bool PyStand::LoadPython()
return true; return true;
} }
//--------------------------------------------------------------------- //---------------------------------------------------------------------
// run string // run string
//--------------------------------------------------------------------- //---------------------------------------------------------------------
int PyStand::RunString(const wchar_t *script) int PyStand::RunString(const wchar_t *script)
{ {
if (_Py_Main == NULL) { if (_Py_Main == NULL)
{
return -1; return -1;
} }
int hr = 0; int hr = 0;
@ -200,19 +213,20 @@ int PyStand::RunString(const wchar_t *script)
_py_argv.push_back(L"-S"); _py_argv.push_back(L"-S");
_py_argv.push_back(L"-c"); _py_argv.push_back(L"-c");
_py_argv.push_back(script); _py_argv.push_back(script);
for (i = 1; i < (int)_argv.size(); i++) { for (i = 1; i < (int)_argv.size(); i++)
{
_py_argv.push_back(_argv[i]); _py_argv.push_back(_argv[i]);
} }
// finalize arguments // finalize arguments
_py_args.resize(0); _py_args.resize(0);
for (i = 0; i < (int)_py_argv.size(); i++) { for (i = 0; i < (int)_py_argv.size(); i++)
_py_args.push_back((wchar_t*)_py_argv[i].c_str()); {
_py_args.push_back((wchar_t *)_py_argv[i].c_str());
} }
hr = _Py_Main((int)_py_args.size(), &_py_args[0]); hr = _Py_Main((int)_py_args.size(), &_py_args[0]);
return hr; return hr;
} }
//--------------------------------------------------------------------- //---------------------------------------------------------------------
// LoadScript() // LoadScript()
//--------------------------------------------------------------------- //---------------------------------------------------------------------
@ -220,94 +234,93 @@ int PyStand::DetectScript()
{ {
// init: _script (init script like PyStand.int or PyStand.py) // init: _script (init script like PyStand.int or PyStand.py)
int size = (int)_pystand.size() - 1; int size = (int)_pystand.size() - 1;
for (; size >= 0; size--) { for (; size >= 0; size--)
if (_pystand[size] == L'.') break; {
if (_pystand[size] == L'.')
break;
} }
if (size < 0) size = (int)_pystand.size(); if (size < 0)
size = (int)_pystand.size();
std::wstring main = _pystand.substr(0, size); std::wstring main = _pystand.substr(0, size);
std::vector<const wchar_t*> exts; std::vector<const wchar_t *> exts;
std::vector<std::wstring> scripts; std::vector<std::wstring> scripts;
_script.clear(); _script.clear();
std::wstring test; std::wstring test;
test = _home + L"LunaTranslator\\LunaTranslator_main.py"; test = _home + L"\\LunaTranslator\\LunaTranslator_main.py";
if (PathFileExistsW(test.c_str())) { if (PathFileExistsW(test.c_str()))
{
_script = test; _script = test;
} }
if (_script.empty())
if (_script.empty()) { {
std::wstring msg = L"Can't find either of:\r\n"; std::wstring msg = L"Can't find :\r\n" + test;
for (int j = 0; j < (int)scripts.size(); j++) { MessageBoxW(NULL, msg.c_str(), L"ERROR", MB_OK);
msg += scripts[j] + L"\r\n"; return -1;
}
MessageBoxW(NULL, msg.c_str(), L"ERROR", MB_OK);
return -1;
} }
SetEnvironmentVariableW(L"PYSTAND_SCRIPT", _script.c_str()); SetEnvironmentVariableW(L"PYSTAND_SCRIPT", _script.c_str());
return 0; return 0;
} }
//--------------------------------------------------------------------- //---------------------------------------------------------------------
// init script // init script
//--------------------------------------------------------------------- //---------------------------------------------------------------------
const auto init_script = const auto init_script =
L"import sys\n" L"import sys\n"
L"import os\n" L"import os\n"
L"PYSTAND = os.environ['PYSTAND']\n" L"PYSTAND = os.environ['PYSTAND']\n"
L"PYSTAND_HOME = os.environ['PYSTAND_HOME']\n" L"PYSTAND_HOME = os.environ['PYSTAND_HOME']\n"
L"PYSTAND_RUNTIME = os.environ['PYSTAND_RUNTIME']\n" L"PYSTAND_RUNTIME = os.environ['PYSTAND_RUNTIME']\n"
L"PYSTAND_SCRIPT = os.environ['PYSTAND_SCRIPT']\n" L"PYSTAND_SCRIPT = os.environ['PYSTAND_SCRIPT']\n"
L"sys.path_origin = [n for n in sys.path]\n" L"sys.path_origin = [n for n in sys.path]\n"
L"sys.PYSTAND = PYSTAND\n" L"sys.PYSTAND = PYSTAND\n"
L"sys.PYSTAND_HOME = PYSTAND_HOME\n" L"sys.PYSTAND_HOME = PYSTAND_HOME\n"
L"sys.PYSTAND_SCRIPT = PYSTAND_SCRIPT\n" L"sys.PYSTAND_SCRIPT = PYSTAND_SCRIPT\n"
L"def MessageBox(msg, info = 'Message'):\n" L"def MessageBox(msg, info = 'Message'):\n"
L" import ctypes\n" L" import ctypes\n"
L" ctypes.windll.user32.MessageBoxW(None, str(msg), str(info), 0)\n" L" ctypes.windll.user32.MessageBoxW(None, str(msg), str(info), 0)\n"
L" return 0\n" L" return 0\n"
L"os.MessageBox = MessageBox\n" L"os.MessageBox = MessageBox\n"
#ifndef PYSTAND_CONSOLE #ifndef PYSTAND_CONSOLE
L"try:\n" L"try:\n"
L" fd = os.open('CONOUT$', os.O_RDWR | os.O_BINARY)\n" L" fd = os.open('CONOUT$', os.O_RDWR | os.O_BINARY)\n"
L" fp = os.fdopen(fd, 'w')\n" L" fp = os.fdopen(fd, 'w')\n"
L" sys.stdout = fp\n" L" sys.stdout = fp\n"
L" sys.stderr = fp\n" L" sys.stderr = fp\n"
L" attached = True\n" L" attached = True\n"
L"except Exception as e:\n" L"except Exception as e:\n"
L" fp = open(os.devnull, 'w')\n" L" fp = open(os.devnull, 'w')\n"
L" sys.stdout = fp\n" L" sys.stdout = fp\n"
L" sys.stderr = fp\n" L" sys.stderr = fp\n"
L" attached = False\n" L" attached = False\n"
#endif #endif
L"sys.argv = [PYSTAND_SCRIPT] + sys.argv[1:]\n" L"sys.argv = [PYSTAND_SCRIPT] + sys.argv[1:]\n"
L"text = open(PYSTAND_SCRIPT, 'rb').read()\n" L"text = open(PYSTAND_SCRIPT, 'rb').read()\n"
L"environ = {'__file__': PYSTAND_SCRIPT, '__name__': '__main__'}\n" L"environ = {'__file__': PYSTAND_SCRIPT, '__name__': '__main__'}\n"
L"environ['__package__'] = None\n" L"environ['__package__'] = None\n"
#ifndef PYSTAND_CONSOLE #ifndef PYSTAND_CONSOLE
L"try:\n" L"try:\n"
L" code = compile(text, PYSTAND_SCRIPT, 'exec')\n" L" code = compile(text, PYSTAND_SCRIPT, 'exec')\n"
L" exec(code, environ)\n" L" exec(code, environ)\n"
L"except Exception:\n" L"except Exception:\n"
L" if attached:\n" L" if attached:\n"
L" raise\n" L" raise\n"
L" import traceback, io\n" L" import traceback, io\n"
L" sio = io.StringIO()\n" L" sio = io.StringIO()\n"
L" traceback.print_exc(file = sio)\n" L" traceback.print_exc(file = sio)\n"
L" os.MessageBox(sio.getvalue(), 'Error')\n" L" os.MessageBox(sio.getvalue(), 'Error')\n"
#else #else
L"code = compile(text, PYSTAND_SCRIPT, 'exec')\n" L"code = compile(text, PYSTAND_SCRIPT, 'exec')\n"
L"exec(code, environ)\n" L"exec(code, environ)\n"
#endif #endif
""; "";
//--------------------------------------------------------------------- //---------------------------------------------------------------------
// main // main
//--------------------------------------------------------------------- //---------------------------------------------------------------------
//! flag: -static //! flag: -static
//! src: //! src:
//! link: stdc++, shlwapi, resource.o //! link: stdc++, shlwapi, resource.o
//! prebuild: windres resource.rc -o resource.o //! prebuild: windres resource.rc -o resource.o
//! mode: win //! mode: win
@ -316,25 +329,29 @@ L"exec(code, environ)\n"
#ifdef PYSTAND_CONSOLE #ifdef PYSTAND_CONSOLE
int main() int main()
#else #else
int WINAPI int WINAPI
WinMain(HINSTANCE hInst, HINSTANCE hPrevInst, LPSTR args, int show) WinMain(HINSTANCE hInst, HINSTANCE hPrevInst, LPSTR args, int show)
#endif #endif
{ {
PyStand ps(L"LunaTranslator\\runtime"); PyStand ps(L"LunaTranslator\\runtime");
if (ps.DetectScript() != 0) { if (ps.DetectScript() != 0)
{
return 3; return 3;
} }
#ifndef PYSTAND_CONSOLE #ifndef PYSTAND_CONSOLE
if (AttachConsole(ATTACH_PARENT_PROCESS)) { if (AttachConsole(ATTACH_PARENT_PROCESS))
{
freopen("CONOUT$", "w", stdout); freopen("CONOUT$", "w", stdout);
freopen("CONOUT$", "w", stderr); freopen("CONOUT$", "w", stderr);
int fd = _fileno(stdout); int fd = _fileno(stdout);
if (fd >= 0) { if (fd >= 0)
{
std::string fn = std::to_string(fd); std::string fn = std::to_string(fd);
SetEnvironmentVariableA("PYSTAND_STDOUT", fn.c_str()); SetEnvironmentVariableA("PYSTAND_STDOUT", fn.c_str());
} }
fd = _fileno(stdin); fd = _fileno(stdin);
if (fd >= 0) { if (fd >= 0)
{
std::string fn = std::to_string(fd); std::string fn = std::to_string(fd);
SetEnvironmentVariableA("PYSTAND_STDIN", fn.c_str()); SetEnvironmentVariableA("PYSTAND_STDIN", fn.c_str());
} }
@ -344,5 +361,3 @@ WinMain(HINSTANCE hInst, HINSTANCE hPrevInst, LPSTR args, int show)
// printf("finalize\n"); // printf("finalize\n");
return hr; return hr;
} }