#include "StdAfx.h"
#include "ScriptExecutor.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;
*/

CScriptExecutor::CScriptExecutor(void)
{
	m_hWorkThread = NULL;
	m_hLogThread = 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;
	m_pCaseObj = NULL;
	m_ulStartTickCount = 0;
}

CScriptExecutor::~CScriptExecutor(void)
{
	EndWorkThread();
	EndLogThread();
}

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)
	{
#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 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;

			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);
	}
	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;

			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 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;
	}

	// 执行main函数;
	PyObject* pResult = PyObject_CallObject(pFunction, NULL);
	if (!pResult)
	{
		printf("Error:执行函数失败\n");
		CatchPythonException();
		Py_Finalize();
		
		return -5;
	}

	// 延时;
	Sleep(2000);
	// 结束日志线程;
	m_bStopLogExport = TRUE;
	// 同时需要关闭输出的管道,否则ReadFile会阻塞;
	CloseHandle(m_hStdOutWrite);
	m_hStdOutWrite = NULL;
	CloseHandle(m_hStdErrorWrite);
	m_hStdErrorWrite = NULL;

	Py_DECREF(pResult);

	Py_Finalize();

	return 0;
}

int CScriptExecutor::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_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
		)
	{
		GLOBAL::WriteTextLog("Error:创建子进程失败 (%d)", GetLastError());
		return -3;
	}

	m_bRuned = TRUE;
	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 CScriptExecutor::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_hLogThread);

	// 强制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_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);
	// 同时需要关闭输出的管道,否则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 CScriptExecutor::StartThread()
{
	// 创建线程;
	m_hWorkThread = CreateThread(NULL, 0, _WorkerThread, this, 0, &m_dwThreadId);
	if (!m_hWorkThread)
	{
		printf("Error:创建执行线程失败\n");
		return false;
	}

	// 创建线程;
	m_hLogThread = CreateThread(NULL, 0, _LogExportThread, this, CREATE_SUSPENDED, NULL);
	if (!m_hLogThread)
	{
		printf("Error:创建日志线程失败\n");
		return false;
	}

	return true;
}

void CScriptExecutor::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 CScriptExecutor::EndLogThread()
{
	m_bStopLogExport = TRUE;
	// 等待3秒,是否能自主结束线程;
	if ( m_hLogThread ) {
		if ( WaitForSingleObject(m_hLogThread, 3000) == WAIT_OBJECT_0 ) {
			CloseHandle(m_hLogThread);
			m_hLogThread = NULL;
			return;
		}	
	}

	// 手动结束线程;
	if (m_hLogThread) {
		// 尝试5次结束行为;
		for (int i = 0; i < 5; i++) {
			if (TerminateThread(m_hLogThread, 0))
				break;
		}

		CloseHandle(m_hLogThread);
		m_hLogThread = NULL;
	}
}

void CScriptExecutor::EndThread()
{
	EndWorkThread();
	EndLogThread();
}

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;	
}

DWORD CScriptExecutor::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 CScriptExecutor::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))
	{
		ofile<<"get token error 1"<<std::endl;
		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
	{
		ofile<<"Get token info error" <<std::endl;
		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 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 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_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());

	return true;
}

bool CScriptExecutor::StartScript()
{
	if (StartThread()) {
		Sleep(100);
		return true;
	}

	// 异常类型;
	printf("Error:异常类型脚本\n");

	return false;
}

void CScriptExecutor::StopScript()
{
	// 如果是子进程运行脚本,停止线程时kill进程;
	if (m_nRunType == SUBPROCESS)
		EndSubprocess();

	// 结束线程;
	EndWorkThread();
}

bool CScriptExecutor::IsScriptOver()
{
	if ( WaitForSingleObject(m_hLogThread, 0) == WAIT_OBJECT_0  && WaitForSingleObject(m_hWorkThread, 0) == WAIT_OBJECT_0)
	{
		GLOBAL::WriteTextLog(_T("====>脚本(%s)已完成"), m_pCaseObj->strCaseName.c_str());
		return true;
	}

	return false;
}