This commit is contained in:
恍兮惚兮 2024-05-01 17:12:05 +08:00
parent 5234c555e7
commit 69b03bcb43
4 changed files with 133 additions and 192 deletions

View File

@ -1,5 +1,5 @@
{ {
"version": "v2.47.1", "version": "v2.48.0",
"themes": { "themes": {
"dark": [ "dark": [
{ {

View File

@ -4,10 +4,8 @@ import builtins
x86 = int(sys.argv[1]) if len(sys.argv) > 1 else 0 x86 = int(sys.argv[1]) if len(sys.argv) > 1 else 0
if x86: if x86:
downlevel = r"C:\Windows\SysWOW64\downlevel" downlevel = r"C:\Windows\SysWOW64\downlevel"
src = py37Pathlocal = (
os.environ["LOCALAPPDATA"] + r"\Programs\Python\Python37-32" + "\\" runtime = r"..\build\LunaTranslator_x86\LunaTranslator\runtime"
)
tgt = r"..\build\LunaTranslator_x86\LunaTranslator\runtime"
targetdir = r"..\build\LunaTranslator_x86" targetdir = r"..\build\LunaTranslator_x86"
launch = r"..\plugins\builds\_x86" launch = r"..\plugins\builds\_x86"
baddll = "DLL64" baddll = "DLL64"
@ -21,33 +19,17 @@ else:
baddll = "DLL32" baddll = "DLL32"
gooddll = "DLL64" gooddll = "DLL64"
launch = r"..\plugins\builds\_x64" launch = r"..\plugins\builds\_x64"
tgt = r"..\build\LunaTranslator\LunaTranslator\runtime" runtime = r"..\build\LunaTranslator\LunaTranslator\runtime"
targetdir = r"..\build\LunaTranslator" targetdir = r"..\build\LunaTranslator"
downlevel = r"C:\Windows\system32\downlevel" downlevel = r"C:\Windows\system32\downlevel"
src = py37Pathlocal = (
os.environ["LOCALAPPDATA"] + r"\Programs\Python\Python37" + "\\"
)
py37Path = "C:\\hostedtoolcache\\windows\\Python\\3.7.9\\x64\\python.exe" py37Path = "C:\\hostedtoolcache\\windows\\Python\\3.7.9\\x64\\python.exe"
py37Pathlocal = os.environ["LOCALAPPDATA"] + r"\Programs\Python\Python37\python.exe" py37Pathlocal = os.environ["LOCALAPPDATA"] + r"\Programs\Python\Python37\python.exe"
webviewappendix = r"Lib\site-packages\webviewpy\platform\win32\x64\webview.dll" webviewappendix = r"Lib\site-packages\webviewpy\platform\win32\x64\webview.dll"
if os.path.exists(py37Path) == False: if os.path.exists(py37Path) == False:
py37Path = py37Pathlocal py37Path = py37Pathlocal
py37Pathwebview = os.path.join(os.path.dirname(py37Path), webviewappendix) py37Path = os.path.dirname(py37Path)
py37Pathwebview = os.path.join(py37Path, webviewappendix)
saveopen = builtins.open
def __open(*arg, **kwarg):
if len(arg) > 1:
mode = arg[1]
else:
mode = ""
if "b" not in mode:
kwarg["encoding"] = "utf8"
return saveopen(*arg, **kwarg)
builtins.open = __open
def get_import_table(file_path): def get_import_table(file_path):
@ -61,6 +43,18 @@ def get_import_table(file_path):
def get_dependencies(filename): def get_dependencies(filename):
saveopen = builtins.open
def __open(*arg, **kwarg):
if len(arg) > 1:
mode = arg[1]
else:
mode = ""
if "b" not in mode:
kwarg["encoding"] = "utf8"
return saveopen(*arg, **kwarg)
builtins.open = __open
finder = modulefinder.ModuleFinder() finder = modulefinder.ModuleFinder()
finder.run_script(filename) finder.run_script(filename)
@ -69,11 +63,12 @@ def get_dependencies(filename):
for name, module in finder.modules.items(): for name, module in finder.modules.items():
if module.__file__ is not None: if module.__file__ is not None:
dependencies.append(module.__file__) dependencies.append(module.__file__)
builtins.open = saveopen
return dependencies return dependencies
def copycheck(src, tgt): def copycheck(src, tgt):
print(src, tgt, os.path.exists(src))
if not os.path.exists(src): if not os.path.exists(src):
return return
if src.lower().endswith("_ssl.pyd"): if src.lower().endswith("_ssl.pyd"):
@ -131,104 +126,121 @@ for dependency in all_dependencies:
if dependency.startswith("./"): if dependency.startswith("./"):
continue continue
print(dependency) print(dependency)
end = dependency[len(src) :] end = dependency[len(py37Path) + 1 :]
if end.lower().startswith("lib"): if end.lower().startswith("lib"):
end = end[4:] end = end[4:]
if end.lower().startswith("site-packages"): if end.lower().startswith("site-packages"):
end = end[len("site-packages") + 1 :] end = end[len("site-packages") + 1 :]
elif end.lower().startswith("dlls"): elif end.lower().startswith("dlls"):
end = end[5:] end = end[5:]
tgtreal = os.path.dirname(os.path.join(tgt, end)) print(end)
tgtreal = os.path.join(runtime, os.path.dirname(end))
copycheck(dependency, tgtreal) copycheck(dependency, tgtreal)
with open(os.path.join(tgt, "python37._pth"), "w") as ff: with open(os.path.join(runtime, "python37._pth"), "w") as ff:
ff.write(".\n..") ff.write(".\n..")
copycheck(os.path.join(src, "python3.dll"), tgt) copycheck(os.path.join(py37Path, "python3.dll"), runtime)
copycheck(os.path.join(src, "python37.dll"), tgt) copycheck(os.path.join(py37Path, "python37.dll"), runtime)
copycheck(os.path.join(src, "Dlls/sqlite3.dll"), tgt) copycheck(os.path.join(py37Path, "Dlls/sqlite3.dll"), runtime)
copycheck(os.path.join(src, "Lib/encodings"), os.path.join(tgt)) copycheck(os.path.join(py37Path, "Lib/encodings"), runtime)
copycheck(rf"{downlevel}\ucrtbase.dll", tgt) copycheck(rf"{downlevel}\ucrtbase.dll", runtime)
copycheck( copycheck(
os.path.join(src, "Lib/site-packages/PyQt5/Qt5/bin/vcruntime140.dll"), os.path.join(py37Path, "Lib/site-packages/PyQt5/Qt5/bin/vcruntime140.dll"),
os.path.join(tgt), os.path.join(runtime),
) )
copycheck( copycheck(
os.path.join(src, "Lib/site-packages/PyQt5/Qt5/bin/vcruntime140_1.dll"), os.path.join(py37Path, "Lib/site-packages/PyQt5/Qt5/bin/vcruntime140_1.dll"),
os.path.join(tgt), os.path.join(runtime),
) )
copycheck( copycheck(
os.path.join(src, "Lib/site-packages/PyQt5/Qt5/bin/msvcp140.dll"), os.path.join(tgt) os.path.join(py37Path, "Lib/site-packages/PyQt5/Qt5/bin/msvcp140.dll"),
os.path.join(runtime),
) )
copycheck( copycheck(
os.path.join(src, "Lib/site-packages/PyQt5/Qt5/bin/Qt5/msvcp140_1.dll"), os.path.join(py37Path, "Lib/site-packages/PyQt5/Qt5/bin/msvcp140_1.dll"),
os.path.join(tgt), os.path.join(runtime),
) )
for _ in os.listdir(os.path.join(src, "Lib/site-packages/PyQt5")): for _ in os.listdir(os.path.join(py37Path, "Lib/site-packages/PyQt5")):
if _.startswith("sip"): if _.startswith("sip"):
copycheck( copycheck(
os.path.join(src, "Lib/site-packages/PyQt5", _), os.path.join(tgt, "PyQt5") os.path.join(py37Path, "Lib/site-packages/PyQt5", _),
os.path.join(runtime, "PyQt5"),
) )
copycheck( copycheck(
os.path.join(src, "Lib/site-packages/PyQt5/Qt5/bin/Qt5Core.dll"), os.path.join(py37Path, "Lib/site-packages/PyQt5/Qt5/bin/Qt5Core.dll"),
os.path.join(tgt, "PyQt5/Qt5/bin"), os.path.join(runtime, "PyQt5/Qt5/bin"),
) )
copycheck( copycheck(
os.path.join(src, "Lib/site-packages/PyQt5/Qt5/bin/Qt5Gui.dll"), os.path.join(py37Path, "Lib/site-packages/PyQt5/Qt5/bin/Qt5Gui.dll"),
os.path.join(tgt, "PyQt5/Qt5/bin"), os.path.join(runtime, "PyQt5/Qt5/bin"),
) )
copycheck( copycheck(
os.path.join(src, "Lib/site-packages/PyQt5/Qt5/bin/Qt5Widgets.dll"), os.path.join(py37Path, "Lib/site-packages/PyQt5/Qt5/bin/Qt5Widgets.dll"),
os.path.join(tgt, "PyQt5/Qt5/bin"), os.path.join(runtime, "PyQt5/Qt5/bin"),
) )
copycheck( copycheck(
os.path.join(src, "Lib/site-packages/PyQt5/Qt5/plugins/imageformats"), os.path.join(py37Path, "Lib/site-packages/PyQt5/Qt5/plugins/imageformats"),
os.path.join(tgt, "PyQt5/Qt5/plugins"), os.path.join(runtime, "PyQt5/Qt5/plugins"),
)
copycheck(
os.path.join(src, "Lib/site-packages/PyQt5/Qt5/plugins/platforms/qoffscreen.dll"),
os.path.join(tgt, "PyQt5/Qt5/plugins/platforms"),
)
copycheck(
os.path.join(src, "Lib/site-packages/PyQt5/Qt5/plugins/platforms/qwindows.dll"),
os.path.join(tgt, "PyQt5/Qt5/plugins/platforms"),
) )
copycheck( copycheck(
os.path.join( os.path.join(
src, "Lib/site-packages/PyQt5/Qt5/plugins/styles/qwindowsvistastyle.dll" py37Path, "Lib/site-packages/PyQt5/Qt5/plugins/platforms/qoffscreen.dll"
), ),
os.path.join(tgt, "PyQt5/Qt5/plugins/styles"), os.path.join(runtime, "PyQt5/Qt5/plugins/platforms"),
)
copycheck(
os.path.join(
py37Path, "Lib/site-packages/PyQt5/Qt5/plugins/platforms/qwindows.dll"
),
os.path.join(runtime, "PyQt5/Qt5/plugins/platforms"),
)
copycheck(
os.path.join(
py37Path, "Lib/site-packages/PyQt5/Qt5/plugins/styles/qwindowsvistastyle.dll"
),
os.path.join(runtime, "PyQt5/Qt5/plugins/styles"),
) )
collect = [] collect = []
for _dir, _, fs in os.walk(targetdir): for _dir, _, fs in os.walk(targetdir):
for f in fs: for f in fs:
collect.append(os.path.join(_dir, f)) collect.append(os.path.join(_dir, f))
for src in collect: for f in collect:
if src.endswith(".pyc") or src.endswith("Thumbs.db"): if f.endswith(".pyc") or f.endswith("Thumbs.db"):
os.remove(f) os.remove(f)
elif f.endswith(".exe") or f.endswith(".pyd") or f.endswith(".dll"):
elif src.lower().endswith(".pyd") or src.lower().endswith(".dll"): try:
pe = pefile.PE(f)
if src.endswith("QtWidgets.pyd"): import_table = pe.DIRECTORY_ENTRY_IMPORT
imports = [ imports = []
for entry in import_table:
if entry.dll.decode("utf-8").lower().startswith("api"):
imports.append(entry.dll.decode("utf-8"))
pe.close()
except:
continue
if f.endswith("Magpie.Core.exe"):
continue
if f.endswith("QtWidgets.pyd"):
imports += [
"api-ms-win-crt-runtime-l1-1-0.dll", "api-ms-win-crt-runtime-l1-1-0.dll",
"api-ms-win-crt-heap-l1-1-0.dll", "api-ms-win-crt-heap-l1-1-0.dll",
] ]
else: # pefile好像有bug仅对于QtWidgets.pyd这个文件只能读取到导入了Qt5Widgets.dll
imports = get_import_table(src) print(f, imports)
print(src, imports)
if len(imports) == 0: if len(imports) == 0:
continue continue
with open(src, "rb") as ff: with open(f, "rb") as ff:
bs = bytearray(ff.read()) bs = bytearray(ff.read())
for _dll in imports: for _dll in imports:
if _dll.lower().startswith("api-ms-win-core"): if _dll.lower().startswith("api-ms-win-core"):
@ -236,13 +248,13 @@ for src in collect:
_target = "kernel32.dll" _target = "kernel32.dll"
elif _dll.lower().startswith("api-ms-win-crt"): elif _dll.lower().startswith("api-ms-win-crt"):
_target = "ucrtbase.dll" _target = "ucrtbase.dll"
else:
continue
_dll = _dll.encode() _dll = _dll.encode()
_target = _target.encode() _target = _target.encode()
idx = bs.find(_dll) idx = bs.find(_dll)
# print(len(bs))
bs[idx : idx + len(_dll)] = _target + b"\0" * (len(_dll) - len(_target)) bs[idx : idx + len(_dll)] = _target + b"\0" * (len(_dll) - len(_target))
with open(os.path.join(tgt, os.path.basename(src)), "wb") as ff: # print(len(bs))
with open(f, "wb") as ff:
ff.write(bs) ff.write(bs)
target = os.path.basename(targetdir) target = os.path.basename(targetdir)

View File

@ -47,40 +47,6 @@ PyStand::PyStand(const wchar_t *runtime)
} }
} }
//---------------------------------------------------------------------
// ctor for ansi
//---------------------------------------------------------------------
PyStand::PyStand(const char *runtime)
{
_hDLL = NULL;
_Py_Main = NULL;
std::wstring rtp = Ansi2Unicode(runtime);
if (CheckEnviron(rtp.c_str()) == false) {
exit(1);
}
if (LoadPython() == false) {
exit(2);
}
}
//---------------------------------------------------------------------
// char to wchar_t
//---------------------------------------------------------------------
std::wstring PyStand::Ansi2Unicode(const char *text)
{
int len = (int)strlen(text);
std::wstring wide;
int require = MultiByteToWideChar(CP_ACP, 0, text, len, NULL, 0);
if (require > 0) {
wide.resize(require);
MultiByteToWideChar(CP_ACP, 0, text, len, &wide[0], require);
}
return wide;
}
//--------------------------------------------------------------------- //---------------------------------------------------------------------
// init: _args, _argv, _cwd, _pystand, _home, _runtime, // init: _args, _argv, _cwd, _pystand, _home, _runtime,
//--------------------------------------------------------------------- //---------------------------------------------------------------------
@ -247,25 +213,6 @@ int PyStand::RunString(const wchar_t *script)
} }
//---------------------------------------------------------------------
// run ansi string
//---------------------------------------------------------------------
int PyStand::RunString(const char *script)
{
std::wstring text = Ansi2Unicode(script);
return RunString(text.c_str());
}
//---------------------------------------------------------------------
// static init script
//---------------------------------------------------------------------
#ifndef PYSTAND_STATIC_NAME
#define PYSTAND_STATIC_NAME "LunaTranslator\\LunaTranslator_main.py"
#endif
//--------------------------------------------------------------------- //---------------------------------------------------------------------
// LoadScript() // LoadScript()
//--------------------------------------------------------------------- //---------------------------------------------------------------------
@ -281,33 +228,20 @@ int PyStand::DetectScript()
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();
#if !(PYSTAND_DISABLE_STATIC)
std::wstring test; std::wstring test;
test = _home + L"\\" + Ansi2Unicode(PYSTAND_STATIC_NAME); test = _home + L"LunaTranslator\\LunaTranslator_main.py";
if (PathFileExistsW(test.c_str())) { if (PathFileExistsW(test.c_str())) {
_script = test; _script = test;
} }
#endif
if (_script.empty()) { if (_script.empty()) {
exts.push_back(L".int");
exts.push_back(L".py");
exts.push_back(L".pyw");
for (int i = 0; i < (int)exts.size(); i++) {
std::wstring test = main + exts[i];
scripts.push_back(test);
if (PathFileExistsW(test.c_str())) {
_script = test;
break;
}
}
if (_script.size() == 0) {
std::wstring msg = L"Can't find either of:\r\n"; std::wstring msg = L"Can't find either of:\r\n";
for (int j = 0; j < (int)scripts.size(); j++) { for (int j = 0; j < (int)scripts.size(); j++) {
msg += scripts[j] + L"\r\n"; msg += scripts[j] + L"\r\n";
} }
MessageBoxW(NULL, msg.c_str(), L"ERROR", MB_OK); MessageBoxW(NULL, msg.c_str(), L"ERROR", MB_OK);
return -1; return -1;
}
} }
SetEnvironmentVariableW(L"PYSTAND_SCRIPT", _script.c_str()); SetEnvironmentVariableW(L"PYSTAND_SCRIPT", _script.c_str());
return 0; return 0;
@ -317,53 +251,53 @@ int PyStand::DetectScript()
//--------------------------------------------------------------------- //---------------------------------------------------------------------
// init script // init script
//--------------------------------------------------------------------- //---------------------------------------------------------------------
const char *init_script = const auto init_script =
"import sys\n" L"import sys\n"
"import os\n" L"import os\n"
"PYSTAND = os.environ['PYSTAND']\n" L"PYSTAND = os.environ['PYSTAND']\n"
"PYSTAND_HOME = os.environ['PYSTAND_HOME']\n" L"PYSTAND_HOME = os.environ['PYSTAND_HOME']\n"
"PYSTAND_RUNTIME = os.environ['PYSTAND_RUNTIME']\n" L"PYSTAND_RUNTIME = os.environ['PYSTAND_RUNTIME']\n"
"PYSTAND_SCRIPT = os.environ['PYSTAND_SCRIPT']\n" L"PYSTAND_SCRIPT = os.environ['PYSTAND_SCRIPT']\n"
"sys.path_origin = [n for n in sys.path]\n" L"sys.path_origin = [n for n in sys.path]\n"
"sys.PYSTAND = PYSTAND\n" L"sys.PYSTAND = PYSTAND\n"
"sys.PYSTAND_HOME = PYSTAND_HOME\n" L"sys.PYSTAND_HOME = PYSTAND_HOME\n"
"sys.PYSTAND_SCRIPT = PYSTAND_SCRIPT\n" L"sys.PYSTAND_SCRIPT = PYSTAND_SCRIPT\n"
"def MessageBox(msg, info = 'Message'):\n" L"def MessageBox(msg, info = 'Message'):\n"
" import ctypes\n" L" import ctypes\n"
" ctypes.windll.user32.MessageBoxW(None, str(msg), str(info), 0)\n" L" ctypes.windll.user32.MessageBoxW(None, str(msg), str(info), 0)\n"
" return 0\n" L" return 0\n"
"os.MessageBox = MessageBox\n" L"os.MessageBox = MessageBox\n"
#ifndef PYSTAND_CONSOLE #ifndef PYSTAND_CONSOLE
"try:\n" L"try:\n"
" fd = os.open('CONOUT$', os.O_RDWR | os.O_BINARY)\n" L" fd = os.open('CONOUT$', os.O_RDWR | os.O_BINARY)\n"
" fp = os.fdopen(fd, 'w')\n" L" fp = os.fdopen(fd, 'w')\n"
" sys.stdout = fp\n" L" sys.stdout = fp\n"
" sys.stderr = fp\n" L" sys.stderr = fp\n"
" attached = True\n" L" attached = True\n"
"except Exception as e:\n" L"except Exception as e:\n"
" fp = open(os.devnull, 'w')\n" L" fp = open(os.devnull, 'w')\n"
" sys.stdout = fp\n" L" sys.stdout = fp\n"
" sys.stderr = fp\n" L" sys.stderr = fp\n"
" attached = False\n" L" attached = False\n"
#endif #endif
"sys.argv = [PYSTAND_SCRIPT] + sys.argv[1:]\n" L"sys.argv = [PYSTAND_SCRIPT] + sys.argv[1:]\n"
"text = open(PYSTAND_SCRIPT, 'rb').read()\n" L"text = open(PYSTAND_SCRIPT, 'rb').read()\n"
"environ = {'__file__': PYSTAND_SCRIPT, '__name__': '__main__'}\n" L"environ = {'__file__': PYSTAND_SCRIPT, '__name__': '__main__'}\n"
"environ['__package__'] = None\n" L"environ['__package__'] = None\n"
#ifndef PYSTAND_CONSOLE #ifndef PYSTAND_CONSOLE
"try:\n" L"try:\n"
" code = compile(text, PYSTAND_SCRIPT, 'exec')\n" L" code = compile(text, PYSTAND_SCRIPT, 'exec')\n"
" exec(code, environ)\n" L" exec(code, environ)\n"
"except Exception:\n" L"except Exception:\n"
" if attached:\n" L" if attached:\n"
" raise\n" L" raise\n"
" import traceback, io\n" L" import traceback, io\n"
" sio = io.StringIO()\n" L" sio = io.StringIO()\n"
" traceback.print_exc(file = sio)\n" L" traceback.print_exc(file = sio)\n"
" os.MessageBox(sio.getvalue(), 'Error')\n" L" os.MessageBox(sio.getvalue(), 'Error')\n"
#else #else
"code = compile(text, PYSTAND_SCRIPT, 'exec')\n" L"code = compile(text, PYSTAND_SCRIPT, 'exec')\n"
"exec(code, environ)\n" L"exec(code, environ)\n"
#endif #endif
""; "";
@ -386,7 +320,7 @@ int WINAPI
WinMain(HINSTANCE hInst, HINSTANCE hPrevInst, LPSTR args, int show) WinMain(HINSTANCE hInst, HINSTANCE hPrevInst, LPSTR args, int show)
#endif #endif
{ {
PyStand ps("LunaTranslator\\runtime"); PyStand ps(L"LunaTranslator\\runtime");
if (ps.DetectScript() != 0) { if (ps.DetectScript() != 0) {
return 3; return 3;
} }

View File

@ -24,16 +24,11 @@ class PyStand
public: public:
virtual ~PyStand(); virtual ~PyStand();
PyStand(const wchar_t *runtime); PyStand(const wchar_t *runtime);
PyStand(const char *runtime);
public: public:
std::wstring Ansi2Unicode(const char *text);
int RunString(const wchar_t *script); int RunString(const wchar_t *script);
int RunString(const char *script);
int DetectScript(); int DetectScript();
protected: protected:
bool CheckEnviron(const wchar_t *rtp); bool CheckEnviron(const wchar_t *rtp);
bool LoadPython(); bool LoadPython();