123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714 |
- #include "StdAfx.h"
- #include "ScriptExecutor.h"
- #include <fstream>
- #include <io.h>
- #include <fcntl.h>
- #include "Python.h"
- CScriptExecutor::CScriptExecutor(void)
- {
- m_hWorkThread = NULL;
- m_hWorkEvent = NULL;
- m_hLogThread = NULL;
- m_hLogEvent = NULL;
- m_bStatus = FALSE;
- m_nRunType = 0;
- m_hStdOutRead = NULL;
- m_hStdOutWrite = NULL;
- m_hStdErrorWrite = NULL;
- m_hOldStdOutWrite = NULL;
- memset(m_szScriptPath, 0, MAX_PATH);
- memset(m_szLogPath, 0, MAX_PATH);
- memset(m_szExtraSentence, 0, MAX_PATH);
- memset(&m_si, 0, sizeof(m_si));
- memset(&m_pi, 0, sizeof(m_pi));
- m_si.cb = sizeof(m_si);
- m_bKillProcess = FALSE;
- m_bStopLogExport = FALSE;
- m_dwThreadId = 0;
- m_dwSubprocessId = 0;
- m_bRuned = FALSE;
- }
- CScriptExecutor::~CScriptExecutor(void)
- {
- }
- DWORD CScriptExecutor::_WorkerThread(LPVOID lpParam)
- {
- CScriptExecutor* that = (CScriptExecutor*)lpParam;
- if ( !that )
- {
- printf("Error:参数失效\n");
- return -1;
- }
- if ( that->m_nRunType == EMBEDDED )
- {
- that->RedirectProcessStdout();
- ResumeThread(that->m_hLogThread);
- that->RunEmbeddedScript();
- }
- else if (that->m_nRunType == SUBPROCESS)
- {
- that->RunScripProcess();
- }
- CloseHandle(that->m_hWorkThread);
- that->m_hWorkThread = NULL;
- // 结束日志线程;
- that->m_bStopLogExport = TRUE;
- return 0;
- }
- DWORD CScriptExecutor::_LogExportThread(LPVOID lpParam)
- {
- CScriptExecutor* that = (CScriptExecutor*)lpParam;
- if (!that)
- {
- printf("Error:参数失效\n");
- return -1;
- }
- if (that->m_nRunType == SUBPROCESS)
- {
- DWORD dwRead;
- CHAR chBuf[BUFSIZE] = {0};
- BOOL bSuccess = FALSE;
-
- do
- {
- bSuccess = ReadFile(that->m_hStdOutRead, chBuf, BUFSIZE, &dwRead, NULL);
- if (!bSuccess || dwRead == 0 || !_tcslen(chBuf))
- continue;
- Global::WritePythonLog(that->m_szLogPath, chBuf);
- memset(chBuf, 0, BUFSIZE);
- } while (!that->m_bStopLogExport);
- }
- else if ( that->m_nRunType == EMBEDDED)
- {
- DWORD dwRead;
- CHAR chBuf[BUFSIZE] = {0};
- BOOL bSuccess = FALSE;
- do
- {
- bSuccess = ReadFile(that->m_hStdOutRead, chBuf, BUFSIZE, &dwRead, NULL);
- if (!bSuccess || dwRead == 0 || !_tcslen(chBuf))
- continue;
- Global::WritePythonLog(that->m_szLogPath, chBuf);
- memset(chBuf, 0, BUFSIZE);
- } while (!that->m_bStopLogExport);
- }
- // 关闭线程句柄;
- CloseHandle(that->m_hLogThread);
- that->m_hLogThread = NULL;
- // 结束重定向;
- that->EndSubprocessStdOut();
- return 0;
- }
- int CScriptExecutor::RedirectSubprocessStdout(LPSTARTUPINFO si /*=NULL*/)
- {
- #ifdef _DEBUG
- OutputDebugString("RedirectSubprocessStdout\n");
- #endif
- // Python脚本中,必须使用sys.__stdout__()
- if (m_nRunType == SUBPROCESS)
- {
- SECURITY_ATTRIBUTES sa;
- sa.bInheritHandle = TRUE;
- sa.lpSecurityDescriptor = NULL;
- sa.nLength = sizeof(sa);
- // 创建stdout的管道;
- if (!CreatePipe(&m_hStdOutRead, &m_hStdOutWrite, &sa, 0))
- {
- OutputDebugString("Error:创建stdout管道失败\n");
- return -1;
- }
- // 创建stderr的管道,由于stderr一般就是stdout,直接复制句柄;
- if (!DuplicateHandle(GetCurrentProcess(), m_hStdOutWrite, GetCurrentProcess(), &m_hStdErrorWrite, 0, TRUE, DUPLICATE_SAME_ACCESS))
- {
- OutputDebugString("创建stderr管道失败\n");
- return -2;
- }
- si->dwFlags |= STARTF_USESTDHANDLES;
- // 将子进程的stdout输出到句柄hStdOutWrite;
- si->hStdOutput = m_hStdOutWrite;
- // 将子进程的stderr输出到句柄hStdErrWrite;
- si->hStdError = m_hStdErrorWrite;
- return 0;
- }
- // 异常类型;
- OutputDebugString("Error:异常类型\n");
- return -5;
- }
- int CScriptExecutor::RedirectProcessStdout()
- {
- #ifdef _DEBUG
- OutputDebugString("RedirectProcessStdout\n");
- #endif
- if (m_nRunType == EMBEDDED)
- {
- // 创建stdout的管道;
- if (!CreatePipe(&m_hStdOutRead, &m_hStdOutWrite, NULL, 0))
- {
- printf("Error:创建stdout管道失败\n");
- return -1;
- }
- // 将 C 运行时文件描述符与现有操作系统文件句柄关联;
- int wpfd = _open_osfhandle((intptr_t)m_hStdOutWrite, _O_TEXT);
- // 为stdout分配新文件描述符;
- if (_dup2(wpfd, _fileno(stdout)) != 0)
- {
- printf("Error:dup2调用失败");
- return -2;
- }
- _close(wpfd);
- // 备份进程原始标准输出;
- m_hOldStdOutWrite = GetStdHandle(STD_OUTPUT_HANDLE);
- // 设备进程标准输出,重定向到管道中;
- if (!SetStdHandle(STD_OUTPUT_HANDLE, m_hStdOutWrite))
- {
- printf("Error:重定向失败\n");
- return -3;
- }
- // 设置标准流不使用缓冲,即时写入;
- setvbuf(stdout, NULL, _IONBF, 0);
- return 0;
- }
- // 异常类型;
- printf("Error:异常类型\n");
- return -5;
- }
- 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环境;
- if (!Py_IsInitialized())
- 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;
- }
- m_bRuned = TRUE;
- // 执行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("Error:脚本路径无效\n");
- return -1;
- }
- // 初始化参数;
- ::memset(&m_si, 0, sizeof(m_si));
- ::memset(&m_pi, 0, sizeof(m_pi));
- m_si.cb = sizeof(m_si);
- GetStartupInfo(&m_si);
- // 强制stdion, stdout和stderr完全无缓冲:python -u
- TCHAR szCommandLine[MAX_PATH] = { 0 };
- if (_tcslen(m_szExtraSentence))
- _stprintf_s(szCommandLine, _T("python -W ignore -u %s %s"), m_szScriptPath, m_szExtraSentence);
- else
- _stprintf_s(szCommandLine, _T("python -W ignore -u %s"), m_szScriptPath);
- // 重定向输出;
- RedirectSubprocessStdout(&m_si);
- // 恢复日志线程;
- ResumeThread(m_hLogThread);
- // 启动子进程;
- if (!CreateProcess(
- NULL, // No module name (use command line)
- szCommandLine, // Command line
- NULL, // Process handle not inheritable
- NULL, // Thread handle not inheritable
- TRUE, // Set handle inheritance to TRUE
- 0, // No creation flags
- NULL, // Use parent's environment block
- NULL, // Use parent's starting directory
- &m_si, // Pointer to STARTUPINFO structure
- &m_pi) // Pointer to PROCESS_INFORMATION structure
- )
- {
- printf("Error:创建子进程失败 (%d).\n", GetLastError());
- return -3;
- }
- m_bRuned = TRUE;
- m_dwSubprocessId = m_pi.dwProcessId;
- // 等待进程完成退出.
- WaitForSingleObject(m_pi.hProcess, INFINITE);
- Sleep(5000);
- // 结束日志线程;
- m_bStopLogExport = TRUE;
- // 关闭进程句柄.
- CloseHandle(m_pi.hProcess);
- CloseHandle(m_pi.hThread);
- // 重置;
- memset(&m_si, 0, sizeof(m_si));
- memset(&m_pi, 0, sizeof(m_pi));
- m_si.cb = sizeof(m_si);
- return 0;
- }
- bool CScriptExecutor::StartWorkThread()
- {
- // 创建线程;
- m_hWorkThread = CreateThread(NULL, 0, _WorkerThread, this, 0, &m_dwThreadId);
- if (!m_hWorkThread)
- {
- printf("Error:创建线程失败\n");
- return false;
- }
- return true;
- }
- bool CScriptExecutor::StartLogThread()
- {
- printf("StartLogThread\n");
- // 创建线程事件:手动控制,无信号状态;
- m_hLogEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
- if (!m_hLogEvent)
- {
- printf("Error:无法为线程创建控制事件\n");
- return false;
- }
- // 创建线程;
- m_hLogThread = CreateThread(NULL, 0, _LogExportThread, this, CREATE_SUSPENDED, NULL);
- if (!m_hLogThread)
- {
- printf("Error:创建线程失败\n");
- CloseHandle(m_hLogEvent);
- m_hLogEvent = NULL;
- return false;
- }
- return true;
- }
- void CScriptExecutor::EndWorkThread()
- {
- // 等待线程结束;
- if (m_hWorkThread)
- {
- // 尝试5次结束行为;
- for (int i = 0; i < 5; i++)
- {
- if (TerminateThread(m_hWorkThread, 0))
- break;
- }
- CloseHandle(m_hWorkThread);
- m_hWorkThread = NULL;
- }
- }
- void CScriptExecutor::EndLogThread()
- {
- // 设置事件有信号;
- if (m_hLogEvent)
- SetEvent(m_hLogEvent);
- // 等待线程结束;
- if (m_hLogThread)
- {
- WaitForSingleObject(m_hLogThread, INFINITE);
- CloseHandle(m_hLogThread);
- m_hLogThread = NULL;
- }
- // 关闭句柄;
- if (m_hLogEvent)
- CloseHandle(m_hLogEvent);
- m_hLogEvent = NULL;
- }
- void CScriptExecutor::EndThread(HANDLE hThread, HANDLE hEvent)
- {
- // 设置事件有信号;
- if (hEvent)
- SetEvent(hEvent);
- // 等待线程结束;
- if (hThread)
- {
- WaitForSingleObject(hThread, INFINITE);
- CloseHandle(hThread);
- hThread = NULL;
- }
- // 关闭句柄;
- if (hEvent)
- CloseHandle(hEvent);
- hEvent = NULL;
- }
- BOOL CScriptExecutor::EndSubprocess()
- {
- BOOL ret = false;
- if (m_pi.hProcess)
- {
- // 尝试5次结束;
- for (int i = 0; i < 5; i++)
- {
- if ( (ret = TerminateProcess(m_pi.hProcess, 0)) )
- break;
- }
- }
- return ret;
- }
- void CScriptExecutor::EndProcessStdOut()
- {
- OutputDebugString("--------------EndProcessStdOut----------------\n");
- #if 0 // 恢复失败,代码有问题
- // 恢复标准输出(嵌入进程脚本);
- if ( m_nRunType == EMBEDDED && m_hOldStdOutWrite)
- {
- int fn = _fileno(stdout);
- // 恢复进程默认标准输出;
- int fd = _open_osfhandle((intptr_t)m_hOldStdOutWrite, _O_RDWR);
- if ( _dup2(fd, _fileno(stdout)) == 0)
- {
- _close(fd);
- // 设置标准输出;
- SetStdHandle(STD_OUTPUT_HANDLE, m_hOldStdOutWrite);
- m_hOldStdOutWrite = NULL;
- // 设置标准流不使用缓冲,即时写入;
- setvbuf(stdout, NULL, _IONBF, 0);
- }
- else
- {
- printf("Error:_dup2分配文件描述符失败\n");
- }
- }
- #endif
- // 关闭重定向句柄;
- if (m_hStdErrorWrite)
- CloseHandle(m_hStdErrorWrite);
- m_hStdErrorWrite = NULL;
- // 只有子进程方式才关闭句柄;
- if ( m_hStdOutWrite)
- CloseHandle(m_hStdOutWrite);
- m_hStdOutWrite = NULL;
- if (m_hStdOutRead)
- CloseHandle(m_hStdOutRead);
- m_hStdOutRead = NULL;
- }
- void CScriptExecutor::EndSubprocessStdOut()
- {
- OutputDebugString("--------------EndSubprocessStdOut----------------\n");
- // 关闭重定向句柄;
- if (m_hStdErrorWrite)
- CloseHandle(m_hStdErrorWrite);
- m_hStdErrorWrite = NULL;
- // 只有子进程方式才关闭句柄;
- if ( m_hStdOutWrite)
- CloseHandle(m_hStdOutWrite);
- m_hStdOutWrite = NULL;
- if (m_hStdOutRead)
- CloseHandle(m_hStdOutRead);
- m_hStdOutRead = NULL;
- }
- void CScriptExecutor::InitScript(std::string strScript, std::string strLogPath, std::string strScriptCmd, int nRunType /*= PY_RUN_TYPE::EMBEDDED*/)
- {
- // 判断脚本是否存在;
- if (!PathFileExists(strScript.c_str()))
- {
- printf("Error:脚本文件不存在\n");
- return;
- }
- // 判断日志文件路径是否可创建;
- if (!PathFileExists(strLogPath.c_str()))
- {
- // 创建路径;
- if (!Global::MKDIR(strLogPath.c_str()))
- {
- printf("Error:创建目录失败\n");
- return;
- }
- // 创建文件;
- std::ofstream flog(strLogPath.c_str());
- if ( flog.bad() )
- {
- printf("Error:创建文件失败\n");
- return;
- }
- flog.close();
- }
- // 赋值参数;
- m_bRuned = FALSE;
- m_nRunType = nRunType;
- m_dwThreadId = m_dwSubprocessId = 0;
- _tcscpy_s(m_szScriptPath, strScript.c_str());
- _tcscpy_s(m_szLogPath, strLogPath.c_str());
- _tcscpy_s(m_szExtraSentence, strScriptCmd.c_str());
- }
- bool CScriptExecutor::StartScript()
- {
- if (StartWorkThread())
- {
- // 开启日志导出线程;
- if (!StartLogThread())
- {
- printf("Error:日志导出线程创建出错\n");
- }
- Sleep(100);
- return true;
- }
- // 异常类型;
- printf("Error:异常类型脚本\n");
- return false;
- }
- void CScriptExecutor::StopScript()
- {
- // 如果是子进程运行脚本,停止线程时kill进程;
- if (m_nRunType == SUBPROCESS)
- EndSubprocess();
- // 结束线程;
- EndWorkThread();
- }
- bool CScriptExecutor::IsScriptOver()
- {
- int i = 10;
- while (!m_bRuned)
- {
- Sleep(300);
- if ( --i == 0 )
- break;
- }
- if (m_nRunType == EMBEDDED)
- {
- if ( m_hWorkThread == NULL )
- return true;
- }
- else if (m_nRunType == SUBPROCESS)
- {
- if ( m_pi.hProcess == NULL && m_hWorkThread == NULL )
- return true;
- }
- return false;
- }
|