// RunPython.cpp : 定义 DLL 应用程序的导出函数。 // #include "stdafx.h" #include "RunPython.h" #include "ScriptExecutor.h" #ifdef _DEBUG #define new DEBUG_NEW #endif // 唯一的应用程序对象 CWinApp theApp; using namespace std; BOOL Python27Dir(LPTSTR lpPython27Dir, int nBufferLen); int _tmain(int argc, TCHAR* argv[], TCHAR* envp[]) { int nRetCode = 0; // 初始化 MFC 并在失败时显示错误 if (!AfxWinInit(::GetModuleHandle(NULL), NULL, ::GetCommandLine(), 0)) { // TODO: 更改错误代码以符合您的需要 _tprintf(_T("错误: MFC 初始化失败\n")); nRetCode = 1; } else { // TODO: 在此处为应用程序的行为编写代码。 CScriptExecutor excutor; excutor.InitScript("E:\\bin\\ScbcCopyKey\\ScbcTest.py", "D:\\SAT\\log.txt", "", EMBEDDED); excutor.StartScript(); Sleep(500); while( !excutor.IsScriptOver() ) Sleep(100); } system("pause"); return nRetCode; } void CatchPythonException() { if ( !Py_IsInitialized() ) { printf("未初始化Python环境\n"); return; } if ( !PyErr_Occurred() ) { printf("没有异常产生\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("导入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("加载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_XDECREF(pPyTraceModule); #else // 不细分Item; PyObject *pPyFunc = PyObject_GetAttrString(pPyTraceModule, "format_exception"); if ( !pPyFunc || !PyCallable_Check(pPyFunc) ) { printf("加载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 } } } } // 从注册表获取 Python27路径; BOOL Python27Dir(LPTSTR lpPython27Dir, int nBufferLen) { HKEY hKey; int ret = RegOpenKeyEx(HKEY_LOCAL_MACHINE, _T("SOFTWARE\\WOW6432Node\\Python\\PythonCore\\2.7\\InstallPath"), 0, KEY_QUERY_VALUE, &hKey); if (ret != ERROR_SUCCESS) return FALSE; //读取KEY DWORD dwType = REG_SZ; //数据类型 DWORD cbData = nBufferLen; ret = RegQueryValueEx(hKey, _T(""), NULL, &dwType, (LPBYTE)lpPython27Dir, &cbData); if (ret != ERROR_SUCCESS) { RegCloseKey(hKey); return FALSE; } RegCloseKey(hKey); return TRUE; } // 运行Python脚本; RUNPYTHON_API int RunPython(LPCTSTR lpScriptFile, LPCTSTR lpExtraSentence) { // 参数有效性判断; if ( !lpScriptFile || !PathFileExists(lpScriptFile) ) return -1; // 初始化Python环境; Py_Initialize(); if ( !Py_IsInitialized() ) 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(lpScriptFile, 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 ( lpExtraSentence ) PyRun_SimpleString(lpExtraSentence); // 注意:脚本名称尽量不要与系统目录其他py文件相同; // 导入脚本,以脚本名称为模块名加载; PyObject *pModuleObj = PyImport_ImportModule(szFilename); if ( !pModuleObj ) { printf("=>加载模块失败\n"); Py_Finalize(); return -3; } // 获取脚本的主函数名称(规定所有脚本的主函数名为main) // 加载函数:注意,如果目录下有同名的脚本文件,可能会加载失败; PyObject *pFunction = PyObject_GetAttrString(pModuleObj, "main"); if ( !pFunction || !PyCallable_Check(pFunction) ) { printf("=>加载函数失败\n"); Py_Finalize(); return -4; } // 执行main函数; PyObject *pResult = PyObject_CallObject(pFunction, NULL); if ( !pResult ) { printf("=>运行函数失败\n"); Py_Finalize(); return -5; } Py_Finalize(); return 0; } RUNPYTHON_API int RunPythonEx(LPCTSTR lpScriptFile, LPCTSTR lpExtraSentence) { // 参数有效性判断; if ( !lpScriptFile || !PathFileExists(lpScriptFile) ) return -1; // 初始化Python环境; Py_Initialize(); if ( !Py_IsInitialized() ) 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(lpScriptFile, 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 ( lpExtraSentence ) PyRun_SimpleString(lpExtraSentence); /* PyObject* main = PyModule_GetDict(PyImport_AddModule("__main__")); PyObject *res = PyRun_String(由文件内容, Py_file_input, main, main); */ // 注意:脚本名称尽量不要与系统目录其他py文件相同; // 导入脚本,以脚本名称为模块名加载; PyObject *pModuleObj = PyImport_ImportModule(szFilename); if ( !pModuleObj ) { printf("=>加载模块失败\n"); Py_Finalize(); return -3; } // 获取脚本的主函数名称(规定所有脚本的主函数名为main) // 加载函数:注意,如果目录下有同名的脚本文件,可能会加载失败; PyObject *pFunction = PyObject_GetAttrString(pModuleObj, "main"); if ( !pFunction || !PyCallable_Check(pFunction) ) { printf("=>加载函数失败\n"); Py_Finalize(); return -4; } // 执行main函数; //PyObject *pResult = PyObject_CallFunctionObjArgs(pFunction, pType, pValue, pTraceback, NULL); PyObject *pResult = PyObject_CallObject(pFunction, NULL); if ( !pResult ) { printf("=>运行函数失败\n"); #if 0 // 捕获异常; const char *pszErrMsg = NULL; TCHAR *pszTraceback = NULL; PyObject *pType = NULL; PyObject *pValue = NULL; PyObject *pTraceback = NULL; // 非控制台,使用PyErr_Fetch捕获异常; PyErr_Fetch(&pType, &pValue, &pTraceback); PyErr_NormalizeException(&pType,&pValue,&pTraceback); if ( pValue ) { PyObject *pStr = PyObject_Str(pValue); if ( pStr ) { //pszErrMsg = PyUnicode_AsUTF8String(pStr); int line, offset; TCHAR *pszMsg, *pszFile, *pszText; int res = PyArg_ParseTuple(pValue, "s(siis)", &pszMsg, &pszFile, &line, &offset, &pszText); //Q_UNUSED(); PyObject *line_no = PyObject_GetAttrString(pValue, "lineno"); PyObject *line_no_str = PyObject_Str(line_no); PyObject *line_no_unicode = PyUnicode_AsEncodedString(line_no_str, "utf-8", "Error"); char *actual_line_no = PyBytes_AsString(line_no_unicode); printf("actual_line_no --%s\n", actual_line_no); } } #else CatchPythonException(); #endif PyErr_Print(); Py_Finalize(); return -5; } Py_DECREF(pResult); Py_Finalize(); return 0; } // lpScriptFile:脚本文件; // lpCommand:命令行参数; RUNPYTHON_API int CallPython(LPCTSTR lpScriptFile, LPCTSTR lpCommand) { if ( !lpScriptFile || !PathFileExists(lpScriptFile) ) { 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 ( lpCommand ) _stprintf_s(szCommandLine, _T("python -W ignore %s %s"), lpScriptFile, lpCommand); else _stprintf_s(szCommandLine, _T("python -W ignore %s"), lpScriptFile); // 启动子进程; 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; } // 读出stdout BOOL ReadFromPipe(HANDLE hStdOutRead) { char out_buffer[BUFSIZE] = {0}; DWORD dwRead; BOOL bSuccess = FALSE; //用WriteFile,从hStdOutRead读出子进程stdout输出的数据,数据结果在out_buffer中,长度为dwRead bSuccess = ReadFile( hStdOutRead, out_buffer, BUFSIZE, &dwRead, NULL); if ((bSuccess) && (dwRead!=0)) //如果成功了,且长度>0 { // 此处加入你自己的代码 // 比如:将数据写入文件或显示到窗口中 OutputDebugString(out_buffer); } return bSuccess; } bool GetOutput( HANDLE hStdOutRead, int timeout ) { if( NULL == hStdOutRead ) { return false; } char buffer[4096] = {0}; DWORD readBytes = 0; while( timeout > 0 ) { //对管道数据进行读,但不会删除管道里的数据,如果没有数据,就立即返回 if( FALSE == PeekNamedPipe( hStdOutRead, buffer, sizeof(buffer) - 1, &readBytes, 0, NULL ) ) { return false; } //检测是否读到数据,如果没有数据,继续等待 if( 0 == readBytes ) { ::Sleep(200); timeout -= 200; continue; } readBytes = 0; if( ::ReadFile( hStdOutRead, buffer, sizeof(buffer) - 1, &readBytes, NULL) ) { OutputDebugString(buffer); return true; } else { return false; } } return false; } // lpScriptFile:脚本文件; // lpCommand:命令行参数; RUNPYTHON_API int CallPythonEx(LPCTSTR lpScriptFile, LPCTSTR lpCommand) { if ( !lpScriptFile || !PathFileExists(lpScriptFile) ) { 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); GetStartupInfo(&si); PROCESS_INFORMATION pi; ::memset(&pi, 0 ,sizeof(pi)); TCHAR szCommandLine[MAX_PATH] = {0}; if ( lpCommand ) _stprintf_s(szCommandLine, _T("python -W ignore %s %s"), lpScriptFile, lpCommand); else _stprintf_s(szCommandLine, _T("python -W ignore %s"), lpScriptFile); SECURITY_ATTRIBUTES sa; sa.bInheritHandle = TRUE; sa.lpSecurityDescriptor = NULL; sa.nLength = sizeof(sa); // 创建stdout的管道; HANDLE hStdOutRead, hStdOutWrite; if ( !CreatePipe(&hStdOutRead, &hStdOutWrite, &sa, 0) ) { printf("创建stdout管道失败\n"); return -3; } // 创建stderr的管道,由于stderr一般就是stdout,直接复制句柄; HANDLE hStdErrWrite; if ( !DuplicateHandle(GetCurrentProcess(), hStdOutWrite, GetCurrentProcess(), &hStdErrWrite, 0, TRUE, DUPLICATE_SAME_ACCESS) ) { printf("创建stderr管道失败\n"); return -3; } si.dwFlags |= STARTF_USESTDHANDLES; // 将子进程的stdout输出到句柄hStdOutWrite; si.hStdOutput = hStdOutWrite; // 将子进程的stderr输出到句柄hStdErrWrite; si.hStdError = hStdErrWrite; // 启动子进程; if( !CreateProcess( NULL, // No module name (use command line) szCommandLine, // Command line NULL, // Process handle not inheritable NULL, // Thread handle not inheritable TRUE, // 如果不设置为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; } #ifdef _DEBUG DWORD process_exit_code = 0; while (GetExitCodeProcess(pi.hProcess, &process_exit_code)) { // 读取stdout、stderr; //GetOutput(hStdOutRead, 3000); ReadFromPipe(hStdOutRead); if ( process_exit_code != STILL_ACTIVE ) break; } #endif // Wait until child process exits. WaitForSingleObject( pi.hProcess, INFINITE ); // Close process and thread handles. CloseHandle( pi.hProcess ); CloseHandle( pi.hThread ); return 0; }