Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

新增功能:如根目录没有对应的启动脚本,执行默认命令 #54

Closed
wants to merge 7 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,7 @@ __pycache__/*
/Release/*
/x64/*
/.vs/*
/.vscode/*
/build/*

/.tasks
Expand Down
192 changes: 71 additions & 121 deletions PyStand.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,6 @@
#include <string.h>
#include <winbase.h>
#include <wincon.h>

#include "PyStand.h"

#ifdef _MSC_VER
Expand Down Expand Up @@ -70,14 +69,21 @@ PyStand::PyStand(const char *runtime)
//---------------------------------------------------------------------
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;
// 计算输入字符串的长度
int len = (int)strlen(text);
// 创建一个空的宽字符字符串
std::wstring wide;
// 根据输入的字符串长度计算转换后的宽字符字符串的长度
int require = MultiByteToWideChar(CP_ACP, 0, text, len, NULL, 0);
// 如果转换后的宽字符字符串长度大于0
if (require > 0) {
// 调整宽字符字符串的大小为转换后的长度
wide.resize(require);
// 将输入的ANSI字符串转换为Unicode字符串
MultiByteToWideChar(CP_ACP, 0, text, len, &wide[0], require);
}
// 返回转换后的Unicode字符串
return wide;
}


Expand Down Expand Up @@ -108,9 +114,7 @@ bool PyStand::CheckEnviron(const wchar_t *rtp)

// 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
Expand Down Expand Up @@ -163,10 +167,6 @@ bool PyStand::CheckEnviron(const wchar_t *rtp)
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);
Expand Down Expand Up @@ -221,29 +221,29 @@ bool PyStand::LoadPython()
//---------------------------------------------------------------------
int PyStand::RunString(const wchar_t *script)
{
if (_Py_Main == NULL) {
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);
for (i = 1; i < (int)_argv.size(); i++) {
_py_argv.push_back(_argv[i]);
}
// finalize arguments
_py_args.resize(0);
for (i = 0; i < (int)_py_argv.size(); i++) {
_py_args.push_back((wchar_t*)_py_argv[i].c_str());
}
hr = _Py_Main((int)_py_args.size(), &_py_args[0]);
return hr;
if (_Py_Main == NULL) {
return -1;
}
int hr = 0;
int i;
_py_argv.resize(0);
// 初始化参数
_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);
for (i = 1; i < (int)_argv.size(); i++) {
_py_argv.push_back(_argv[i]);
}
// 终止参数
_py_args.resize(0);
for (i = 0; i < (int)_py_argv.size(); i++) {
_py_args.push_back((wchar_t*)_py_argv[i].c_str());
}
hr = _Py_Main((int)_py_args.size(), &_py_args[0]);
return hr;
}


Expand All @@ -253,19 +253,11 @@ int PyStand::RunString(const wchar_t *script)
int PyStand::RunString(const char *script)
{
std::wstring text = Ansi2Unicode(script);
return RunString(text.c_str());
return RunString(text);
}



//---------------------------------------------------------------------
// static init script
//---------------------------------------------------------------------
#ifndef PYSTAND_STATIC_NAME
#define PYSTAND_STATIC_NAME "_pystand_static.int"
#endif


//---------------------------------------------------------------------
// LoadScript()
//---------------------------------------------------------------------
Expand Down Expand Up @@ -301,79 +293,59 @@ int PyStand::DetectScript()
}
}
if (_script.size() == 0) {
std::wstring msg = L"Can't find either of:\r\n";
for (int j = 0; j < (int)scripts.size(); j++) {
msg += scripts[j] + L"\r\n";
// No default script found, try import the app and run it.
std::wstring app;
app = _home + L"\\app";
if (PathFileExistsW(app.c_str())) {
_script = app;
}else{
std::wstring msg = L"Can't find either of:\r\n";
for (int j = 0; j < (int)scripts.size(); j++) {
msg += scripts[j] + L"\r\n";
}
msg += app + L"\r\n";
MessageBoxW(NULL, msg.c_str(), L"ERROR", MB_OK);
return -1;
}
MessageBoxW(NULL, msg.c_str(), L"ERROR", MB_OK);
return -1;

}
}
SetEnvironmentVariableW(L"PYSTAND_SCRIPT", _script.c_str());
return 0;
}



//---------------------------------------------------------------------
// init script
//---------------------------------------------------------------------
const char *init_script =
"import sys\n"
"import os\n"
"import copy\n"
"import site\n"
"PYSTAND = os.environ['PYSTAND']\n"
"PYSTAND_HOME = os.environ['PYSTAND_HOME']\n"
"PYSTAND_RUNTIME = os.environ['PYSTAND_RUNTIME']\n"
"PYSTAND_SCRIPT = os.environ['PYSTAND_SCRIPT']\n"
"sys.path_origin = [n for n in sys.path]\n"
"sys.PYSTAND = PYSTAND\n"
"sys.PYSTAND_HOME = PYSTAND_HOME\n"
"sys.PYSTAND_SCRIPT = PYSTAND_SCRIPT\n"
"def MessageBox(msg, info = 'Message'):\n"
" import ctypes\n"
" ctypes.windll.user32.MessageBoxW(None, str(msg), str(info), 0)\n"
" return 0\n"
"os.MessageBox = MessageBox\n"
#ifndef PYSTAND_CONSOLE
"try:\n"
" fd = os.open('CONOUT$', os.O_RDWR | os.O_BINARY)\n"
" fp = os.fdopen(fd, 'w')\n"
" sys.stdout = fp\n"
" sys.stderr = fp\n"
" attached = True\n"
"except Exception as e:\n"
" fp = open(os.devnull, 'w')\n"
" sys.stdout = fp\n"
" sys.stderr = fp\n"
" attached = False\n"
#endif
"for n in ['.', 'lib', 'site-packages']:\n"
" test = os.path.abspath(os.path.join(PYSTAND_HOME, n))\n"
" if os.path.exists(test):\n"
" site.addsitedir(test)\n"
"sys.argv = [PYSTAND_SCRIPT] + sys.argv[1:]\n"
"text = open(PYSTAND_SCRIPT, 'rb').read()\n"
"environ = {'__file__': PYSTAND_SCRIPT, '__name__': '__main__'}\n"
"environ['__package__'] = None\n"
#ifndef PYSTAND_CONSOLE
" sys.path.append(test)\n"
"try:\n"
" code = compile(text, PYSTAND_SCRIPT, 'exec')\n"
" exec(code, environ)\n"
"except Exception:\n"
" if attached:\n"
" raise\n"
" import traceback, io\n"
" sio = io.StringIO()\n"
" traceback.print_exc(file = sio)\n"
" os.MessageBox(sio.getvalue(), 'Error')\n"
#else
"code = compile(text, PYSTAND_SCRIPT, 'exec')\n"
"exec(code, environ)\n"
#endif
" from app import run\n"
" run()\n"
"except Exception as e:\n"
" os.MessageBox(str(e), 'Error')\n"
"";



//---------------------------------------------------------------------
// main
//---------------------------------------------------------------------
Expand All @@ -384,37 +356,15 @@ const char *init_script =
//! prebuild: windres resource.rc -o resource.o
//! mode: win
//! int: objs

#ifdef PYSTAND_CONSOLE
int main()
#else
int WINAPI
WinMain(HINSTANCE hInst, HINSTANCE hPrevInst, LPSTR args, int show)
#endif
int WINAPI // 此处为 WINAPI 宏,用于标识这是一个 Win32 API 函数
WinMain(HINSTANCE hInst, HINSTANCE hPrevInst, LPSTR args, int show) // 主程序入口函数,接收实例化程序的句柄 hInst,前一个实例的句柄 hPrevInst,命令行参数 args 和显示状态 show
{
PyStand ps("runtime");
if (ps.DetectScript() != 0) {
return 3;
}
#ifndef PYSTAND_CONSOLE
if (AttachConsole(ATTACH_PARENT_PROCESS)) {
freopen("CONOUT$", "w", stdout);
freopen("CONOUT$", "w", stderr);
int fd = _fileno(stdout);
if (fd >= 0) {
std::string fn = std::to_string(fd);
SetEnvironmentVariableA("PYSTAND_STDOUT", fn.c_str());
}
fd = _fileno(stdin);
if (fd >= 0) {
std::string fn = std::to_string(fd);
SetEnvironmentVariableA("PYSTAND_STDIN", fn.c_str());
}
}
#endif
int hr = ps.RunString(init_script);
// printf("finalize\n");
return hr;
PyStand ps("bin"); // 创建 PyStand 对象 ps,并传入参数 "bin"
// if (ps.DetectScript() != 0) { // 调用 PyStand 对象的 DetectScript 方法,若返回值不为 0
// return 3; // 返回 3
// }

int hr = ps.RunString(init_script); // 调用 PyStand 对象的 RunString 方法,将 init_script 作为参数,并将返回值赋给 hr
// printf("finalize\n"); // 打印字符串 "finalize"
return hr; // 返回 hr
}


3 changes: 1 addition & 2 deletions PyStand.h
Original file line number Diff line number Diff line change
Expand Up @@ -57,5 +57,4 @@ class PyStand
};


#endif

#endif
2 changes: 2 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ Python 独立部署环境。Python 3.5 以后,Windows 下面都有一个 Embed
- 自动加载 `PyStand.exe` 同级目录下面 `runtime` 子目录内的 Embedded Python。
- 自动启动 `PyStand.exe` 同级目录下面的 `PyStand.int` 程序(Python 代码)。
- 如果改名,会加载对应名称的 `.int` 文件,比如改为 `MyDemo.exe` 就会加载 `MyDemo.int`。
- 如果根目录没有int/py/pyw脚本且存在app目录,会自动导入`app`模块且执行`run`函数
- 窗口程序,无 Console,但是如果在 cmd.exe 内运行,可以看到 print 的内容。
- 会自动添加 `PyStand.exe` 同级目录下的 `site-packages` 目录,库可以放到里面。

Expand All @@ -22,6 +23,7 @@ Python 独立部署环境。Python 3.5 以后,Windows 下面都有一个 Embed
- 下载 Python Embedded 版本,放到 `PyStand.exe` 所在目录的 runtime 子目录内。
- 注意 Python Embedded 如果是 32 位,PyStand 配置 CMake 时也需要指明 `-A Win32`。
- 在 `PyStand.exe` 所在目录创建 Python 源代码 PyStand.int。
- 如果你不希望脚本存在根目录,那么必须存在一个叫`app`的包,且包内必须存在`run()`函数用来启动程式
- 双击 `PyStand.exe` 就会运行 `PyStand.int` 里的代码。
- 可以编译成命令行版方便调试,CMake 的时候加 `-DPYSTAND_CONSOLE=ON` 即可。

Expand Down