|
@@ -0,0 +1,291 @@
|
|
|
|
+#include "StdAfx.h"
|
|
|
|
+#include "ScriptExecutor.h"
|
|
|
|
+
|
|
|
|
+CScriptExecutor::CScriptExecutor(void)
|
|
|
|
+{
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+CScriptExecutor::~CScriptExecutor(void)
|
|
|
|
+{
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+DWORD __stdcall CScriptExecutor::_WorkerThread(LPVOID lpParam)
|
|
|
|
+{
|
|
|
|
+ return 0;
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+int CScriptExecutor::RedirectStdout(STARTUPINFO &si)
|
|
|
|
+{
|
|
|
|
+ SECURITY_ATTRIBUTES sa;
|
|
|
|
+ sa.bInheritHandle = TRUE;
|
|
|
|
+ sa.lpSecurityDescriptor = NULL;
|
|
|
|
+ sa.nLength = sizeof(sa);
|
|
|
|
+
|
|
|
|
+ // 创建stdout的管道;
|
|
|
|
+ if (!CreatePipe(&m_hStdOutRead, &m_hStdOutWrite, &sa, 0))
|
|
|
|
+ {
|
|
|
|
+ printf("Error:创建stdout管道失败\n");
|
|
|
|
+ return -1;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ // 创建stderr的管道,由于stderr一般就是stdout,直接复制句柄;
|
|
|
|
+ if (!DuplicateHandle(GetCurrentProcess(), m_hStdOutWrite, GetCurrentProcess(), &m_hStdErrorWrite, 0, TRUE, DUPLICATE_SAME_ACCESS))
|
|
|
|
+ {
|
|
|
|
+ printf("创建stderr管道失败\n");
|
|
|
|
+ return -2;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ si.dwFlags |= STARTF_USESTDHANDLES;
|
|
|
|
+ // 将子进程的stdout输出到句柄hStdOutWrite;
|
|
|
|
+ si.hStdOutput = m_hStdOutWrite;
|
|
|
|
+ // 将子进程的stderr输出到句柄hStdErrWrite;
|
|
|
|
+ si.hStdError = m_hStdErrorWrite;
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+void CScriptExecutor::CatchPythonException()
|
|
|
|
+{
|
|
|
|
+ if (!Py_IsInitialized())
|
|
|
|
+ {
|
|
|
|
+ printf("Error:未初始化Python环境\n");
|
|
|
|
+ return;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ if (!PyErr_Occurred())
|
|
|
|
+ {
|
|
|
|
+ printf("Error:没有异常产生\n");
|
|
|
|
+ return;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ // 捕获异常;
|
|
|
|
+ const char* pszErrMsg = NULL;
|
|
|
|
+ TCHAR* pszTraceback = NULL;
|
|
|
|
+
|
|
|
|
+ PyObject* pPyType = NULL;
|
|
|
|
+ PyObject* pPyValue = NULL;
|
|
|
|
+ PyObject* pPyTraceback = NULL;
|
|
|
|
+ // 非控制台,使用PyErr_Fetch捕获异常;
|
|
|
|
+ PyErr_Fetch(&pPyType, &pPyValue, &pPyTraceback);
|
|
|
|
+ PyErr_NormalizeException(&pPyType, &pPyValue, &pPyTraceback); // 可有可无,不影响获取异常;
|
|
|
|
+ if (pPyValue)
|
|
|
|
+ {
|
|
|
|
+ PyObject* pPyStr = PyObject_Str(pPyValue);
|
|
|
|
+ if (PyString_Check(pPyStr))
|
|
|
|
+ {
|
|
|
|
+ pszErrMsg = PyString_AsString(pPyStr);
|
|
|
|
+ if (pszErrMsg)
|
|
|
|
+ printf("Error Info=>%s\n", pszErrMsg);
|
|
|
|
+
|
|
|
|
+ if (pPyTraceback)
|
|
|
|
+ {
|
|
|
|
+ PyObject* pPyTraceModule = PyImport_ImportModule("traceback");
|
|
|
|
+ if (!pPyTraceModule)
|
|
|
|
+ {
|
|
|
|
+ printf("Error:导入traceback模块失败\n");
|
|
|
|
+ return;
|
|
|
|
+ }
|
|
|
|
+#if 1
|
|
|
|
+ PyObject* pPyModuleDict = PyModule_GetDict(pPyTraceModule);
|
|
|
|
+ if (pPyModuleDict)
|
|
|
|
+ {
|
|
|
|
+ PyObject* pPyFunc = PyDict_GetItemString(pPyModuleDict, "format_exception");
|
|
|
|
+ if (!pPyFunc || !PyCallable_Check(pPyFunc))
|
|
|
|
+ {
|
|
|
|
+ printf("Error:加载format_exception失败\n");
|
|
|
|
+ return;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ PyObject* pErroList = PyObject_CallFunctionObjArgs(pPyFunc, pPyType, pPyValue, pPyTraceback, NULL);
|
|
|
|
+ if (pErroList)
|
|
|
|
+ {
|
|
|
|
+ int nSize = PyList_Size(pErroList);
|
|
|
|
+ for (int i = 0; i < nSize; i++)
|
|
|
|
+ {
|
|
|
|
+ pszErrMsg = PyString_AsString(PyList_GetItem(pErroList, i));
|
|
|
|
+ printf("%s", pszErrMsg);
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ Py_DECREF(pErroList);
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ Py_XDECREF(pPyTraceModule);
|
|
|
|
+#else // 不细分Item;
|
|
|
|
+ PyObject* pPyFunc = PyObject_GetAttrString(pPyTraceModule, "format_exception");
|
|
|
|
+ if (!pPyFunc || !PyCallable_Check(pPyFunc))
|
|
|
|
+ {
|
|
|
|
+ printf("Error:加载format_exception失败\n");
|
|
|
|
+ return;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ PyObject* pPyResult = PyObject_CallFunctionObjArgs(pPyFunc, pPyType, pPyValue, pPyTraceback, NULL);
|
|
|
|
+ pPyStr = PyObject_Str(pPyResult);
|
|
|
|
+ pszErrMsg = PyString_AsString(pPyStr);
|
|
|
|
+ if (pszErrMsg)
|
|
|
|
+ printf("%s\n", pszErrMsg);
|
|
|
|
+
|
|
|
|
+ Py_DECREF(pPyResult);
|
|
|
|
+ Py_XDECREF(pPyTraceModule);
|
|
|
|
+#endif
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ Py_XDECREF(pPyType);
|
|
|
|
+ Py_XDECREF(pPyValue);
|
|
|
|
+ Py_XDECREF(pPyTraceback);
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+int CScriptExecutor::RunEmbeddedScript()
|
|
|
|
+{
|
|
|
|
+ // 参数有效性判断;
|
|
|
|
+ if (!PathFileExists(m_szScriptPath))
|
|
|
|
+ {
|
|
|
|
+ printf("Error:脚本文件不存在\n");
|
|
|
|
+ return -1;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ // 初始化Python环境;
|
|
|
|
+ Py_Initialize();
|
|
|
|
+ if (!Py_IsInitialized())
|
|
|
|
+ {
|
|
|
|
+ printf("Error:初始化Python环境失败\n");
|
|
|
|
+ return -2;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ // 解析脚本路径和脚本名称;
|
|
|
|
+ std::string scriptdir;
|
|
|
|
+ TCHAR szDrive[_MAX_DRIVE] = { 0 };
|
|
|
|
+ TCHAR szDir[_MAX_DIR] = { 0 };
|
|
|
|
+ TCHAR szExt[_MAX_EXT] = { 0 };
|
|
|
|
+ TCHAR szFilename[_MAX_FNAME] = { 0 };
|
|
|
|
+ TCHAR szScriptDir[MAX_PATH] = { 0 };
|
|
|
|
+ _tsplitpath_s(m_szScriptPath, szDrive, szDir, szFilename, szExt);
|
|
|
|
+ _stprintf_s(szScriptDir, _T("%s%s"), szDrive, szDir);
|
|
|
|
+ // 缓存一份路径;
|
|
|
|
+ scriptdir = szScriptDir;
|
|
|
|
+ // 将'\'转换成'/', Python才设置运行目录成功;
|
|
|
|
+ int len = _tcslen(szScriptDir);
|
|
|
|
+ for (int i = 0; i < len; i++)
|
|
|
|
+ {
|
|
|
|
+ if (szScriptDir[i] == '\\')
|
|
|
|
+ szScriptDir[i] = '/';
|
|
|
|
+ }
|
|
|
|
+ //szScriptDir[len-1] = '\0';
|
|
|
|
+
|
|
|
|
+ TCHAR szExecuteDir[MAX_PATH] = { 0 };
|
|
|
|
+ _stprintf_s(szExecuteDir, _T("sys.path.append(\"%s\")"), szScriptDir);
|
|
|
|
+ // 添加系统模块,并指定当前脚本路径为运行路径;
|
|
|
|
+ PyRun_SimpleString("import sys");
|
|
|
|
+ PyRun_SimpleString(szExecuteDir);
|
|
|
|
+ // 运行额外的语句,一般用于传递命令行参数;
|
|
|
|
+ if (_tcslen(m_szExtraSentence))
|
|
|
|
+ PyRun_SimpleString(m_szExtraSentence);
|
|
|
|
+
|
|
|
|
+ // 注意:脚本名称尽量不要与系统目录其他py文件相同;
|
|
|
|
+ // 导入脚本,以脚本名称为模块名加载;
|
|
|
|
+ PyObject* pModuleObj = PyImport_ImportModule(szFilename);
|
|
|
|
+ if (!pModuleObj)
|
|
|
|
+ {
|
|
|
|
+ printf("Error:加载脚本模块失败\n");
|
|
|
|
+ Py_Finalize();
|
|
|
|
+ return -3;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ // 获取脚本的主函数名称(规定所有脚本的主函数名为main)
|
|
|
|
+ // 加载函数:注意,如果目录下有同名的脚本文件,可能会加载失败;
|
|
|
|
+ PyObject* pFunction = PyObject_GetAttrString(pModuleObj, "main");
|
|
|
|
+ if (!pFunction || !PyCallable_Check(pFunction))
|
|
|
|
+ {
|
|
|
|
+ printf("Error:加载函数失败\n");
|
|
|
|
+ Py_Finalize();
|
|
|
|
+ return -4;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ // 执行main函数;
|
|
|
|
+ PyObject* pResult = PyObject_CallObject(pFunction, NULL);
|
|
|
|
+ if (!pResult)
|
|
|
|
+ {
|
|
|
|
+ printf("Error:执行函数失败\n");
|
|
|
|
+ CatchPythonException();
|
|
|
|
+ Py_Finalize();
|
|
|
|
+ return -5;
|
|
|
|
+ }
|
|
|
|
+ Py_DECREF(pResult);
|
|
|
|
+
|
|
|
|
+ Py_Finalize();
|
|
|
|
+
|
|
|
|
+ return 0;
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+int CScriptExecutor::RunScripProcess()
|
|
|
|
+{
|
|
|
|
+ if (!PathFileExists(m_szScriptPath))
|
|
|
|
+ {
|
|
|
|
+ printf("参数无效\n");
|
|
|
|
+ return -1;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ // 获取Python27进程目录;
|
|
|
|
+ TCHAR szPython27Dir[MAX_PATH] = { 0 };
|
|
|
|
+ TCHAR szPython27Exe[MAX_PATH] = { 0 };
|
|
|
|
+ if (!Python27Dir(szPython27Dir, MAX_PATH))
|
|
|
|
+ {
|
|
|
|
+ printf("获取Python27目录失败\n");
|
|
|
|
+ return -2;
|
|
|
|
+ }
|
|
|
|
+ _stprintf_s(szPython27Exe, _T("%spython.exe"), szPython27Dir);
|
|
|
|
+
|
|
|
|
+ STARTUPINFO si;
|
|
|
|
+ ::memset(&si, 0, sizeof(si));
|
|
|
|
+ si.cb = sizeof(si);
|
|
|
|
+
|
|
|
|
+ PROCESS_INFORMATION pi;
|
|
|
|
+ ::memset(&pi, 0, sizeof(pi));
|
|
|
|
+
|
|
|
|
+ TCHAR szCommandLine[MAX_PATH] = { 0 };
|
|
|
|
+ if (_tcslen(m_szExtraSentence))
|
|
|
|
+ _stprintf_s(szCommandLine, _T("python -W ignore %s %s"), m_szScriptPath, m_szExtraSentence);
|
|
|
|
+ else
|
|
|
|
+ _stprintf_s(szCommandLine, _T("python -W ignore %s"), m_szScriptPath);
|
|
|
|
+
|
|
|
|
+ // 启动子进程;
|
|
|
|
+ if (!CreateProcess(
|
|
|
|
+ NULL, // No module name (use command line)
|
|
|
|
+ szCommandLine, // Command line
|
|
|
|
+ NULL, // Process handle not inheritable
|
|
|
|
+ NULL, // Thread handle not inheritable
|
|
|
|
+ FALSE, // Set handle inheritance to TRUE
|
|
|
|
+ 0, // No creation flags
|
|
|
|
+ NULL, // Use parent's environment block
|
|
|
|
+ NULL, // Use parent's starting directory
|
|
|
|
+ &si, // Pointer to STARTUPINFO structure
|
|
|
|
+ &pi) // Pointer to PROCESS_INFORMATION structure
|
|
|
|
+ )
|
|
|
|
+ {
|
|
|
|
+ printf("CreateProcess failed (%d).\n", GetLastError());
|
|
|
|
+ return -3;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ // Wait until child process exits.
|
|
|
|
+ WaitForSingleObject(pi.hProcess, INFINITE);
|
|
|
|
+
|
|
|
|
+ // Close process and thread handles.
|
|
|
|
+ CloseHandle(pi.hProcess);
|
|
|
|
+ CloseHandle(pi.hThread);
|
|
|
|
+
|
|
|
|
+ return 0;
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+void CScriptExecutor::InitScript(std::string strScript, std::string strLogPath, std::string strScriptCmd, int nRunType)
|
|
|
|
+{
|
|
|
|
+
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+bool CScriptExecutor::StartScript()
|
|
|
|
+{
|
|
|
|
+ return false;
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+bool CScriptExecutor::StopScript()
|
|
|
|
+{
|
|
|
|
+ return false;
|
|
|
|
+}
|