|
@@ -0,0 +1,733 @@
|
|
|
+#include "StdAfx.h"
|
|
|
+#include "PythonExecutor.h"
|
|
|
+#include <fstream>
|
|
|
+#include <io.h>
|
|
|
+#include <fcntl.h>
|
|
|
+#include "Python.h"
|
|
|
+// 服务进程头文件;
|
|
|
+#include <Wtsapi32.h>
|
|
|
+#include <TlHelp32.h>
|
|
|
+#pragma comment(lib, "wtsapi32.lib")
|
|
|
+#include <Userenv.h>
|
|
|
+#pragma comment(lib,"userenv.lib")
|
|
|
+
|
|
|
+/*
|
|
|
+typedef struct _TOKEN_LINKED_TOKEN {
|
|
|
+HANDLE LinkedToken;
|
|
|
+} TOKEN_LINKED_TOKEN, *PTOKEN_LINKED_TOKEN;
|
|
|
+SERVICE_STATUS_HANDLE hServiceStatus;
|
|
|
+*/
|
|
|
+
|
|
|
+CPythonExecutor::CPythonExecutor(void)
|
|
|
+{
|
|
|
+ m_hWorkThread = NULL;
|
|
|
+ m_hStdoutLogThread = NULL;
|
|
|
+ m_bStatus = FALSE;
|
|
|
+
|
|
|
+ m_hStdOutRead = NULL;
|
|
|
+ m_hStdOutWrite = NULL;
|
|
|
+ m_hStdErrorRead = NULL;
|
|
|
+ m_hStdErrorWrite = 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_pCaseObj = NULL;
|
|
|
+ m_ulStartTickCount = 0;
|
|
|
+}
|
|
|
+
|
|
|
+CPythonExecutor::~CPythonExecutor(void)
|
|
|
+{
|
|
|
+ EndWorkThread();
|
|
|
+ EndLogThread();
|
|
|
+}
|
|
|
+
|
|
|
+DWORD CPythonExecutor::_WorkerThread(LPVOID lpParam)
|
|
|
+{
|
|
|
+ CPythonExecutor* that = (CPythonExecutor*)lpParam;
|
|
|
+ if ( !that ) {
|
|
|
+ printf("Error:参数失效\n");
|
|
|
+ return -1;
|
|
|
+ }
|
|
|
+
|
|
|
+#ifdef _DEBUG
|
|
|
+ that->RunScriptProcess();
|
|
|
+#else
|
|
|
+ that->ServiceRunScriptProcess();
|
|
|
+#endif
|
|
|
+
|
|
|
+ // 延时;
|
|
|
+ Sleep(2000);
|
|
|
+ // 结束日志线程;
|
|
|
+ that->m_bStopLogExport = TRUE;
|
|
|
+ GLOBAL::WriteTextLog(_T("脚本执行线程结束,用例名=%s"), that->m_pCaseObj->strCaseName.c_str());
|
|
|
+
|
|
|
+ return 0;
|
|
|
+}
|
|
|
+
|
|
|
+DWORD CPythonExecutor::_StdoutLogExportThread(LPVOID lpParam)
|
|
|
+{
|
|
|
+ CPythonExecutor* that = (CPythonExecutor*)lpParam;
|
|
|
+ if (!that) {
|
|
|
+ printf("Error:参数失效\n");
|
|
|
+ return -1;
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
+ 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;
|
|
|
+
|
|
|
+ that->m_ulStartTickCount = GetTickCount64();
|
|
|
+ GLOBAL::WritePythonLog(that->m_szLogPath, chBuf);
|
|
|
+ // 更新日志时间;
|
|
|
+ if ( that->m_pCaseObj )
|
|
|
+ that->m_pCaseObj->_ulStartTickCount = GetTickCount64();
|
|
|
+ memset(chBuf, 0, BUFSIZE);
|
|
|
+ } while (!that->m_bStopLogExport);
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+ // 结束重定向;
|
|
|
+ that->EndSubprocessStdOut();
|
|
|
+ GLOBAL::WriteTextLog(_T("脚本日志线程结束,用例名=%s"), that->m_pCaseObj->strCaseName.c_str());
|
|
|
+
|
|
|
+ return 0;
|
|
|
+}
|
|
|
+
|
|
|
+DWORD CPythonExecutor::_StderrLogExportThread(LPVOID lpParam)
|
|
|
+{
|
|
|
+ CPythonExecutor* that = (CPythonExecutor*)lpParam;
|
|
|
+ if (!that) {
|
|
|
+ printf("Error:参数失效\n");
|
|
|
+ return -1;
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
+ 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;
|
|
|
+
|
|
|
+ that->m_ulStartTickCount = GetTickCount64();
|
|
|
+ GLOBAL::WritePythonLog(that->m_szLogPath, chBuf);
|
|
|
+ // 更新日志时间;
|
|
|
+ if ( that->m_pCaseObj )
|
|
|
+ that->m_pCaseObj->_ulStartTickCount = GetTickCount64();
|
|
|
+ memset(chBuf, 0, BUFSIZE);
|
|
|
+ } while (!that->m_bStopLogExport);
|
|
|
+
|
|
|
+ // 结束重定向;
|
|
|
+ that->EndSubprocessStdOut();
|
|
|
+ GLOBAL::WriteTextLog(_T("脚本日志线程结束,用例名=%s"), that->m_pCaseObj->strCaseName.c_str());
|
|
|
+
|
|
|
+ return 0;
|
|
|
+}
|
|
|
+
|
|
|
+int CPythonExecutor::RedirectSubprocessStdout(LPSTARTUPINFO si /*=NULL*/)
|
|
|
+{
|
|
|
+ // Python脚本中,必须使用sys.__stdout__()
|
|
|
+ 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;
|
|
|
+ }
|
|
|
+
|
|
|
+#if 0// 标准输出和标准错误都由同一个句柄重定向,此时只需要一个线程来读取管道内容;
|
|
|
+ // 创建stderr的管道,由于stderr一般就是stdout,直接复制句柄;
|
|
|
+ if (!DuplicateHandle(GetCurrentProcess(), m_hStdOutWrite, GetCurrentProcess(), &m_hStdErrorWrite, 0, TRUE, DUPLICATE_SAME_ACCESS)) {
|
|
|
+ OutputDebugString("创建stderr管道失败\n");
|
|
|
+ return -2;
|
|
|
+ }
|
|
|
+#else
|
|
|
+ // 标准输出和标准错误分开,需要二个线程来读取管道内容;
|
|
|
+ if (!CreatePipe(&m_hStdErrorRead, &m_hStdErrorWrite, &sa, 0)) {
|
|
|
+ OutputDebugString("Error:创建stderr管道失败\n");
|
|
|
+ return -1;
|
|
|
+ }
|
|
|
+#endif
|
|
|
+
|
|
|
+ si->dwFlags |= STARTF_USESTDHANDLES;
|
|
|
+ // 将子进程的stdout输出到句柄hStdOutWrite;
|
|
|
+ si->hStdOutput = m_hStdOutWrite;
|
|
|
+ // 将子进程的stderr输出到句柄hStdErrWrite;
|
|
|
+ si->hStdError = m_hStdErrorWrite;
|
|
|
+
|
|
|
+ return 0;
|
|
|
+}
|
|
|
+
|
|
|
+int CPythonExecutor::RunScriptProcess()
|
|
|
+{
|
|
|
+ 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_hStdoutLogThread);
|
|
|
+
|
|
|
+ // 启动子进程;
|
|
|
+ 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
|
|
|
+ )
|
|
|
+ {
|
|
|
+ GLOBAL::WriteTextLog("Error:创建子进程失败 (%d)", GetLastError());
|
|
|
+ return -3;
|
|
|
+ }
|
|
|
+
|
|
|
+ m_dwSubprocessId = m_pi.dwProcessId;
|
|
|
+ // 等待进程完成退出.
|
|
|
+ WaitForSingleObject(m_pi.hProcess, INFINITE);
|
|
|
+
|
|
|
+ Sleep(5000);
|
|
|
+ GLOBAL::WriteTextLog("脚本进程结束(%ld)", m_pi.dwProcessId);
|
|
|
+ // 结束日志线程;
|
|
|
+ m_bStopLogExport = TRUE;
|
|
|
+ // 同时需要关闭输出的管道,否则ReadFile会阻塞;
|
|
|
+ CloseHandle(m_hStdOutWrite);
|
|
|
+ m_hStdOutWrite = NULL;
|
|
|
+ CloseHandle(m_hStdErrorWrite);
|
|
|
+ m_hStdErrorWrite = NULL;
|
|
|
+
|
|
|
+ // 关闭进程句柄.
|
|
|
+ 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;
|
|
|
+}
|
|
|
+
|
|
|
+int CPythonExecutor::ServiceRunScriptProcess()
|
|
|
+{
|
|
|
+ if (!PathFileExists(m_szScriptPath)) {
|
|
|
+ printf("Error:脚本路径无效\n");
|
|
|
+ return -1;
|
|
|
+ }
|
|
|
+
|
|
|
+ DWORD dwProcesses = 0;
|
|
|
+ BOOL bResult = FALSE;
|
|
|
+ DWORD dwRet = 0;
|
|
|
+ DWORD dwSid = GetActiveSessionID();
|
|
|
+
|
|
|
+ HANDLE hProcess = NULL, hPToken = NULL, hUserTokenDup = NULL;
|
|
|
+ if (!WTSQueryUserToken(dwSid, &hPToken)) {
|
|
|
+ PROCESSENTRY32 procEntry;
|
|
|
+ DWORD dwPid = 0;
|
|
|
+ HANDLE hSnap = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
|
|
|
+ if (hSnap == INVALID_HANDLE_VALUE) {
|
|
|
+ return FALSE;
|
|
|
+ }
|
|
|
+
|
|
|
+ procEntry.dwSize = sizeof(PROCESSENTRY32);
|
|
|
+ if (Process32First(hSnap, &procEntry)) {
|
|
|
+ do {
|
|
|
+ if (_tcsicmp(procEntry.szExeFile, _T("explorer.exe")) == 0) {
|
|
|
+ DWORD exeSessionId = 0;
|
|
|
+ if (ProcessIdToSessionId(procEntry.th32ProcessID, &exeSessionId) && exeSessionId == dwSid) {
|
|
|
+ dwPid = procEntry.th32ProcessID;
|
|
|
+ break;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ } while (Process32Next(hSnap, &procEntry));
|
|
|
+ }
|
|
|
+ CloseHandle(hSnap);
|
|
|
+
|
|
|
+ // explorer进程不存在
|
|
|
+ if (dwPid == 0) {
|
|
|
+ return FALSE;
|
|
|
+ }
|
|
|
+
|
|
|
+ hProcess = ::OpenProcess(PROCESS_QUERY_INFORMATION, FALSE, dwPid);
|
|
|
+ if (hProcess == NULL) {
|
|
|
+ return FALSE;
|
|
|
+ }
|
|
|
+
|
|
|
+ if(!::OpenProcessToken(hProcess, TOKEN_ALL_ACCESS_P,&hPToken)) {
|
|
|
+ CloseHandle(hProcess);
|
|
|
+ return FALSE;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ if (hPToken == NULL)
|
|
|
+ return -1;
|
|
|
+
|
|
|
+ TOKEN_LINKED_TOKEN admin;
|
|
|
+ bResult = GetTokenInformation(hPToken, (TOKEN_INFORMATION_CLASS)19, &admin, sizeof(TOKEN_LINKED_TOKEN), &dwRet);
|
|
|
+
|
|
|
+ if (!bResult) {// vista 以前版本不支持TokenLinkedToken
|
|
|
+ TOKEN_PRIVILEGES tp;
|
|
|
+ LUID luid;
|
|
|
+ if (LookupPrivilegeValue(NULL,SE_DEBUG_NAME,&luid)) {
|
|
|
+ tp.PrivilegeCount =1;
|
|
|
+ tp.Privileges[0].Luid =luid;
|
|
|
+ tp.Privileges[0].Attributes =SE_PRIVILEGE_ENABLED;
|
|
|
+ }
|
|
|
+ DuplicateTokenEx(hPToken,MAXIMUM_ALLOWED,NULL,SecurityIdentification,TokenPrimary,&hUserTokenDup);
|
|
|
+ } else {
|
|
|
+ hUserTokenDup = admin.LinkedToken;
|
|
|
+ }
|
|
|
+
|
|
|
+ LPVOID pEnv =NULL;
|
|
|
+ DWORD dwCreationFlags = CREATE_PRESERVE_CODE_AUTHZ_LEVEL;
|
|
|
+
|
|
|
+ if(CreateEnvironmentBlock(&pEnv,hUserTokenDup,TRUE))
|
|
|
+ {
|
|
|
+ dwCreationFlags|=CREATE_UNICODE_ENVIRONMENT;
|
|
|
+ }
|
|
|
+ else
|
|
|
+ {
|
|
|
+ pEnv = NULL;
|
|
|
+ }
|
|
|
+
|
|
|
+ ZeroMemory( &m_si, sizeof(m_si) );
|
|
|
+ m_si.cb = sizeof(m_si);
|
|
|
+ m_si.dwFlags = STARTF_USESHOWWINDOW;
|
|
|
+ m_si.wShowWindow = SW_HIDE;
|
|
|
+ ZeroMemory( &m_pi, sizeof(m_pi) );
|
|
|
+
|
|
|
+ // 重定向输出;
|
|
|
+ RedirectSubprocessStdout(&m_si);
|
|
|
+ // 恢复日志线程;
|
|
|
+ ResumeThread(m_hStdoutLogThread);
|
|
|
+
|
|
|
+ // 强制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);
|
|
|
+
|
|
|
+ bResult = CreateProcessAsUser(
|
|
|
+ hUserTokenDup, // client's access token
|
|
|
+ NULL, // file to execute
|
|
|
+ szCommandLine, // command line
|
|
|
+ NULL, // pointer to process SECURITY_ATTRIBUTES
|
|
|
+ NULL, // pointer to thread SECURITY_ATTRIBUTES
|
|
|
+ TRUE, // handles are not inheritable
|
|
|
+ dwCreationFlags, // creation flags
|
|
|
+ pEnv, // pointer to new environment block
|
|
|
+ NULL, // name of current directory
|
|
|
+ &m_si, // pointer to STARTUPINFO structure
|
|
|
+ &m_pi // receives information about new process
|
|
|
+ );
|
|
|
+ if ( !bResult )
|
|
|
+ return -1;
|
|
|
+
|
|
|
+ m_dwSubprocessId = m_pi.dwProcessId;
|
|
|
+
|
|
|
+ // 等待进程完成退出.
|
|
|
+ WaitForSingleObject(m_pi.hProcess, INFINITE);
|
|
|
+
|
|
|
+ Sleep(5000);
|
|
|
+ // 结束日志线程;
|
|
|
+ m_bStopLogExport = TRUE;
|
|
|
+
|
|
|
+ // 关闭进程句柄.
|
|
|
+ CloseHandle(m_pi.hProcess);
|
|
|
+ CloseHandle(m_pi.hThread);
|
|
|
+ // 同时需要关闭输出的管道,否则ReadFile会阻塞;
|
|
|
+ CloseHandle(m_hStdOutWrite);
|
|
|
+ m_hStdOutWrite = NULL;
|
|
|
+ CloseHandle(m_hStdErrorWrite);
|
|
|
+ m_hStdErrorWrite = NULL;
|
|
|
+
|
|
|
+ // 重置;
|
|
|
+ memset(&m_si, 0, sizeof(m_si));
|
|
|
+ memset(&m_pi, 0, sizeof(m_pi));
|
|
|
+ m_si.cb = sizeof(m_si);
|
|
|
+
|
|
|
+ if (hUserTokenDup != NULL)
|
|
|
+ CloseHandle(hUserTokenDup);
|
|
|
+ if (hProcess != NULL)
|
|
|
+ CloseHandle(hProcess);
|
|
|
+ if (hPToken != NULL)
|
|
|
+ CloseHandle(hPToken);
|
|
|
+ if (pEnv != NULL)
|
|
|
+ DestroyEnvironmentBlock(pEnv);
|
|
|
+
|
|
|
+ return TRUE;
|
|
|
+}
|
|
|
+
|
|
|
+bool CPythonExecutor::StartThread()
|
|
|
+{
|
|
|
+ // 创建线程;
|
|
|
+ m_hWorkThread = CreateThread(NULL, 0, _WorkerThread, this, 0, &m_dwThreadId);
|
|
|
+ if (!m_hWorkThread) {
|
|
|
+ printf("Error:创建执行线程失败\n");
|
|
|
+ return false;
|
|
|
+ }
|
|
|
+
|
|
|
+ // 创建线程;
|
|
|
+ m_hStdoutLogThread = CreateThread(NULL, 0, _StdoutLogExportThread, this, CREATE_SUSPENDED, NULL);
|
|
|
+ if (!m_hStdoutLogThread) {
|
|
|
+ printf("Error:创建日志线程失败\n");
|
|
|
+ return false;
|
|
|
+ }
|
|
|
+
|
|
|
+ return true;
|
|
|
+}
|
|
|
+
|
|
|
+void CPythonExecutor::EndWorkThread()
|
|
|
+{
|
|
|
+ // 结束进程;
|
|
|
+ EndSubprocess();
|
|
|
+ // 等待3秒,是否能自主结束线程;
|
|
|
+ if (m_hWorkThread) {
|
|
|
+ if (WaitForSingleObject(m_hWorkThread, 3000) == WAIT_OBJECT_0) {
|
|
|
+ CloseHandle(m_hWorkThread);
|
|
|
+ m_hWorkThread = NULL;
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ // 手动结束线程;
|
|
|
+ if ( m_hWorkThread ) {
|
|
|
+ // 尝试5次结束行为;
|
|
|
+ for (int i = 0; i < 5; i++) {
|
|
|
+ if (TerminateThread(m_hWorkThread, 0))
|
|
|
+ break;
|
|
|
+ }
|
|
|
+
|
|
|
+ CloseHandle(m_hWorkThread);
|
|
|
+ m_hWorkThread = NULL;
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+void CPythonExecutor::EndLogThread()
|
|
|
+{
|
|
|
+ m_bStopLogExport = TRUE;
|
|
|
+ // 等待3秒,是否能自主结束线程;
|
|
|
+ if ( m_hStdoutLogThread ) {
|
|
|
+ if ( WaitForSingleObject(m_hStdoutLogThread, 3000) == WAIT_OBJECT_0 ) {
|
|
|
+ CloseHandle(m_hStdoutLogThread);
|
|
|
+ m_hStdoutLogThread = NULL;
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ // 手动结束线程;
|
|
|
+ if (m_hStdoutLogThread) {
|
|
|
+ // 尝试5次结束行为;
|
|
|
+ for (int i = 0; i < 5; i++) {
|
|
|
+ if (TerminateThread(m_hStdoutLogThread, 0))
|
|
|
+ break;
|
|
|
+ }
|
|
|
+
|
|
|
+ CloseHandle(m_hStdoutLogThread);
|
|
|
+ m_hStdoutLogThread = NULL;
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+void CPythonExecutor::EndThread()
|
|
|
+{
|
|
|
+ EndWorkThread();
|
|
|
+ EndLogThread();
|
|
|
+}
|
|
|
+
|
|
|
+BOOL CPythonExecutor::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 CPythonExecutor::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;
|
|
|
+}
|
|
|
+
|
|
|
+DWORD CPythonExecutor::GetActiveSessionID()
|
|
|
+{
|
|
|
+ DWORD dwSessionId = 0;
|
|
|
+ PWTS_SESSION_INFO pSessionInfo = NULL;
|
|
|
+ DWORD dwCount = 0;
|
|
|
+
|
|
|
+ WTSEnumerateSessions(WTS_CURRENT_SERVER_HANDLE, 0, 1, &pSessionInfo, &dwCount);
|
|
|
+
|
|
|
+ for(DWORD i = 0; i < dwCount; i++) {
|
|
|
+ WTS_SESSION_INFO si = pSessionInfo[i];
|
|
|
+ if(WTSActive == si.State) {
|
|
|
+ dwSessionId = si.SessionId;
|
|
|
+ break;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ WTSFreeMemory(pSessionInfo);
|
|
|
+
|
|
|
+ return dwSessionId;
|
|
|
+}
|
|
|
+
|
|
|
+BOOL CPythonExecutor::ServiceExecute(std::wstring wstrCmdLine, INT32& n32ExitResult)
|
|
|
+{
|
|
|
+ ofstream ofile("C:\\logEvent.txt");
|
|
|
+ ofile<<"start excute"<<std::endl;
|
|
|
+ DWORD dwProcesses = 0;
|
|
|
+ BOOL bResult = FALSE;
|
|
|
+
|
|
|
+ DWORD dwSid = GetActiveSessionID();
|
|
|
+
|
|
|
+ DWORD dwRet = 0;
|
|
|
+ PROCESS_INFORMATION pi;
|
|
|
+ STARTUPINFO si;
|
|
|
+ HANDLE hProcess = NULL, hPToken = NULL, hUserTokenDup = NULL;
|
|
|
+ if (!WTSQueryUserToken(dwSid, &hPToken)) {
|
|
|
+ PROCESSENTRY32 procEntry;
|
|
|
+ DWORD dwPid = 0;
|
|
|
+ HANDLE hSnap = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
|
|
|
+ if (hSnap == INVALID_HANDLE_VALUE) {
|
|
|
+ return FALSE;
|
|
|
+ }
|
|
|
+
|
|
|
+ procEntry.dwSize = sizeof(PROCESSENTRY32);
|
|
|
+ if (Process32First(hSnap, &procEntry)) {
|
|
|
+ do {
|
|
|
+ if (_tcsicmp(procEntry.szExeFile, _T("explorer.exe")) == 0) {
|
|
|
+ DWORD exeSessionId = 0;
|
|
|
+ if (ProcessIdToSessionId(procEntry.th32ProcessID, &exeSessionId) && exeSessionId == dwSid) {
|
|
|
+ dwPid = procEntry.th32ProcessID;
|
|
|
+ break;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ } while (Process32Next(hSnap, &procEntry));
|
|
|
+ }
|
|
|
+ CloseHandle(hSnap);
|
|
|
+
|
|
|
+ // explorer进程不存在
|
|
|
+ if (dwPid == 0)
|
|
|
+ {
|
|
|
+ return FALSE;
|
|
|
+ }
|
|
|
+
|
|
|
+ hProcess = ::OpenProcess(PROCESS_QUERY_INFORMATION, FALSE, dwPid);
|
|
|
+ if (hProcess == NULL) {
|
|
|
+ return FALSE;
|
|
|
+ }
|
|
|
+
|
|
|
+ if(!::OpenProcessToken(hProcess, TOKEN_ALL_ACCESS_P,&hPToken)) {
|
|
|
+ CloseHandle(hProcess);
|
|
|
+ return FALSE;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ if (hPToken == NULL)
|
|
|
+ return FALSE;
|
|
|
+
|
|
|
+ TOKEN_LINKED_TOKEN admin;
|
|
|
+ bResult = GetTokenInformation(hPToken, (TOKEN_INFORMATION_CLASS)19, &admin, sizeof(TOKEN_LINKED_TOKEN), &dwRet);
|
|
|
+
|
|
|
+ if (!bResult) {// vista 以前版本不支持TokenLinkedToken
|
|
|
+ TOKEN_PRIVILEGES tp;
|
|
|
+ LUID luid;
|
|
|
+ if (LookupPrivilegeValue(NULL,SE_DEBUG_NAME,&luid)) {
|
|
|
+ tp.PrivilegeCount =1;
|
|
|
+ tp.Privileges[0].Luid =luid;
|
|
|
+ tp.Privileges[0].Attributes =SE_PRIVILEGE_ENABLED;
|
|
|
+ }
|
|
|
+ DuplicateTokenEx(hPToken,MAXIMUM_ALLOWED,NULL,SecurityIdentification,TokenPrimary,&hUserTokenDup);
|
|
|
+ } else {
|
|
|
+ hUserTokenDup = admin.LinkedToken;
|
|
|
+ ofile<<"token: "<<hUserTokenDup<<std::endl;
|
|
|
+ }
|
|
|
+
|
|
|
+ LPVOID pEnv =NULL;
|
|
|
+ DWORD dwCreationFlags = CREATE_PRESERVE_CODE_AUTHZ_LEVEL;
|
|
|
+
|
|
|
+ if(CreateEnvironmentBlock(&pEnv,hUserTokenDup,TRUE)) {
|
|
|
+ dwCreationFlags|=CREATE_UNICODE_ENVIRONMENT;
|
|
|
+ } else {
|
|
|
+ pEnv = NULL;
|
|
|
+ }
|
|
|
+
|
|
|
+ ZeroMemory( &si, sizeof(si) );
|
|
|
+ si.cb = sizeof(si);
|
|
|
+ si.dwFlags = STARTF_USESHOWWINDOW;
|
|
|
+ si.wShowWindow = SW_SHOWNORMAL;
|
|
|
+ ZeroMemory( &pi, sizeof(pi) );
|
|
|
+
|
|
|
+ bResult = CreateProcessAsUser(
|
|
|
+ hUserTokenDup, // client's access token
|
|
|
+ NULL, // file to execute
|
|
|
+ (LPTSTR) wstrCmdLine.c_str(), // command line
|
|
|
+ NULL, // pointer to process SECURITY_ATTRIBUTES
|
|
|
+ NULL, // pointer to thread SECURITY_ATTRIBUTES
|
|
|
+ FALSE, // handles are not inheritable
|
|
|
+ dwCreationFlags, // creation flags
|
|
|
+ pEnv, // pointer to new environment block
|
|
|
+ NULL, // name of current directory
|
|
|
+ &si, // pointer to STARTUPINFO structure
|
|
|
+ &pi // receives information about new process
|
|
|
+ );
|
|
|
+
|
|
|
+ if(pi.hProcess) {
|
|
|
+ if(WAIT_OBJECT_0 == WaitForSingleObject(pi.hProcess, 180000)) {
|
|
|
+ DWORD dwResult = 0;
|
|
|
+ if(GetExitCodeProcess(pi.hProcess, &dwResult)) {
|
|
|
+ n32ExitResult = dwResult;
|
|
|
+ } else {
|
|
|
+ n32ExitResult = -1;
|
|
|
+ }
|
|
|
+
|
|
|
+ CloseHandle(pi.hThread);
|
|
|
+ CloseHandle(pi.hProcess);
|
|
|
+ } else {
|
|
|
+ CloseHandle(pi.hThread);
|
|
|
+ CloseHandle(pi.hProcess);
|
|
|
+ n32ExitResult = -1;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ if (hUserTokenDup != NULL)
|
|
|
+ CloseHandle(hUserTokenDup);
|
|
|
+ if (hProcess != NULL)
|
|
|
+ CloseHandle(hProcess);
|
|
|
+ if (hPToken != NULL)
|
|
|
+ CloseHandle(hPToken);
|
|
|
+ if (pEnv != NULL)
|
|
|
+ DestroyEnvironmentBlock(pEnv);
|
|
|
+
|
|
|
+ return TRUE;
|
|
|
+
|
|
|
+}
|
|
|
+
|
|
|
+bool CPythonExecutor::InitScript(std::string strScript, std::string strLogPath, std::string strScriptCmd)
|
|
|
+{
|
|
|
+ // 判断脚本是否存在;
|
|
|
+ if (!PathFileExists(strScript.c_str())) {
|
|
|
+ printf("Error:脚本文件不存在\n");
|
|
|
+ return false;
|
|
|
+ }
|
|
|
+
|
|
|
+ // 判断日志文件路径是否可创建;
|
|
|
+ if (!PathFileExists(strLogPath.c_str())) {
|
|
|
+ // 创建路径;
|
|
|
+ if (!GLOBAL::MKDIR(strLogPath.c_str())) {
|
|
|
+ printf("Error:创建目录失败\n");
|
|
|
+ return false;
|
|
|
+ }
|
|
|
+
|
|
|
+ // 创建文件;
|
|
|
+ std::ofstream flog(strLogPath.c_str());
|
|
|
+ if ( flog.bad() ) {
|
|
|
+ printf("Error:创建文件失败\n");
|
|
|
+ return false;
|
|
|
+ }
|
|
|
+ flog.close();
|
|
|
+ }
|
|
|
+
|
|
|
+ // 赋值参数;
|
|
|
+ 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());
|
|
|
+
|
|
|
+ return true;
|
|
|
+}
|
|
|
+
|
|
|
+bool CPythonExecutor::StartScript()
|
|
|
+{
|
|
|
+ if (StartThread()) {
|
|
|
+ Sleep(100);
|
|
|
+ return true;
|
|
|
+ }
|
|
|
+
|
|
|
+ // 异常类型;
|
|
|
+ printf("Error:异常类型脚本\n");
|
|
|
+
|
|
|
+ return false;
|
|
|
+}
|
|
|
+
|
|
|
+void CPythonExecutor::StopScript()
|
|
|
+{
|
|
|
+ // 如果是子进程运行脚本,停止线程时kill进程;
|
|
|
+ EndSubprocess();
|
|
|
+ // 结束线程;
|
|
|
+ EndWorkThread();
|
|
|
+}
|
|
|
+
|
|
|
+bool CPythonExecutor::IsScriptOver()
|
|
|
+{
|
|
|
+ if ( WaitForSingleObject(m_hStdoutLogThread, 0) == WAIT_OBJECT_0 && WaitForSingleObject(m_hWorkThread, 0) == WAIT_OBJECT_0)
|
|
|
+ {
|
|
|
+ GLOBAL::WriteTextLog(_T("====>脚本(%s)已完成"), m_pCaseObj->strCaseName.c_str());
|
|
|
+ return true;
|
|
|
+ }
|
|
|
+
|
|
|
+ return false;
|
|
|
+}
|