ScriptExecutor.cpp 25 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060
  1. #include "StdAfx.h"
  2. #include "ScriptExecutor.h"
  3. #include <fstream>
  4. #include <io.h>
  5. #include <fcntl.h>
  6. #include "Python.h"
  7. // 服务进程头文件;
  8. #include <Wtsapi32.h>
  9. #include <TlHelp32.h>
  10. #pragma comment(lib, "wtsapi32.lib")
  11. #include <Userenv.h>
  12. #pragma comment(lib,"userenv.lib")
  13. /*
  14. typedef struct _TOKEN_LINKED_TOKEN {
  15. HANDLE LinkedToken;
  16. } TOKEN_LINKED_TOKEN, *PTOKEN_LINKED_TOKEN;
  17. SERVICE_STATUS_HANDLE hServiceStatus;
  18. */
  19. CScriptExecutor::CScriptExecutor(void)
  20. {
  21. m_hWorkThread = NULL;
  22. m_hStdoutLogThread = NULL;
  23. m_bStatus = FALSE;
  24. m_nRunType = 0;
  25. m_hStdOutRead = NULL;
  26. m_hStdOutWrite = NULL;
  27. m_hStdErrorRead = NULL;
  28. m_hStdErrorWrite = NULL;
  29. m_hOldStdOutWrite = NULL;
  30. memset(m_szScriptPath, 0, MAX_PATH);
  31. memset(m_szLogPath, 0, MAX_PATH);
  32. memset(m_szExtraSentence, 0, MAX_PATH);
  33. memset(&m_si, 0, sizeof(m_si));
  34. memset(&m_pi, 0, sizeof(m_pi));
  35. m_si.cb = sizeof(m_si);
  36. m_bKillProcess = FALSE;
  37. m_bStopLogExport = FALSE;
  38. m_dwThreadId = 0;
  39. m_dwSubprocessId = 0;
  40. m_bRuned = FALSE;
  41. m_pCaseObj = NULL;
  42. m_ulStartTickCount = 0;
  43. }
  44. CScriptExecutor::~CScriptExecutor(void)
  45. {
  46. EndWorkThread();
  47. EndLogThread();
  48. }
  49. DWORD CScriptExecutor::_WorkerThread(LPVOID lpParam)
  50. {
  51. CScriptExecutor* that = (CScriptExecutor*)lpParam;
  52. if ( !that ) {
  53. printf("Error:参数失效\n");
  54. return -1;
  55. }
  56. if ( that->m_nRunType == EMBEDDED ) {
  57. that->RedirectProcessStdout();
  58. ResumeThread(that->m_hStdoutLogThread);
  59. that->RunEmbeddedScript();
  60. }
  61. else if (that->m_nRunType == SUBPROCESS) {
  62. #ifdef _DEBUG
  63. that->RunScriptProcess();
  64. #else
  65. that->ServiceRunScriptProcess();
  66. #endif
  67. }
  68. // 延时;
  69. Sleep(2000);
  70. // 结束日志线程;
  71. that->m_bStopLogExport = TRUE;
  72. GLOBAL::WriteTextLog(_T("脚本执行线程结束,用例名=%s"), that->m_pCaseObj->strCaseName.c_str());
  73. return 0;
  74. }
  75. DWORD CScriptExecutor::_StdoutLogExportThread(LPVOID lpParam)
  76. {
  77. CScriptExecutor* that = (CScriptExecutor*)lpParam;
  78. if (!that) {
  79. printf("Error:参数失效\n");
  80. return -1;
  81. }
  82. if (that->m_nRunType == SUBPROCESS)
  83. {
  84. DWORD dwRead;
  85. CHAR chBuf[BUFSIZE] = {0};
  86. BOOL bSuccess = FALSE;
  87. do
  88. {
  89. bSuccess = ReadFile(that->m_hStdOutRead, chBuf, BUFSIZE, &dwRead, NULL);
  90. if (!bSuccess || dwRead == 0 || !_tcslen(chBuf))
  91. continue;
  92. that->m_ulStartTickCount = GetTickCount64();
  93. GLOBAL::WritePythonLog(that->m_szLogPath, chBuf);
  94. // 更新日志时间;
  95. if ( that->m_pCaseObj )
  96. that->m_pCaseObj->_ulStartTickCount = GetTickCount64();
  97. memset(chBuf, 0, BUFSIZE);
  98. } while (!that->m_bStopLogExport);
  99. }
  100. else if ( that->m_nRunType == EMBEDDED)
  101. {
  102. DWORD dwRead;
  103. CHAR chBuf[BUFSIZE] = {0};
  104. BOOL bSuccess = FALSE;
  105. do
  106. {
  107. bSuccess = ReadFile(that->m_hStdOutRead, chBuf, BUFSIZE, &dwRead, NULL);
  108. if (!bSuccess || dwRead == 0 || !_tcslen(chBuf))
  109. continue;
  110. that->m_ulStartTickCount = GetTickCount64();
  111. GLOBAL::WritePythonLog(that->m_szLogPath, chBuf);
  112. // 更新日志时间;
  113. if ( that->m_pCaseObj )
  114. that->m_pCaseObj->_ulStartTickCount = GetTickCount64();
  115. memset(chBuf, 0, BUFSIZE);
  116. } while (!that->m_bStopLogExport);
  117. }
  118. // 结束重定向;
  119. that->EndSubprocessStdOut();
  120. GLOBAL::WriteTextLog(_T("脚本日志线程结束,用例名=%s"), that->m_pCaseObj->strCaseName.c_str());
  121. return 0;
  122. }
  123. DWORD CScriptExecutor::_StderrLogExportThread(LPVOID lpParam)
  124. {
  125. CScriptExecutor* that = (CScriptExecutor*)lpParam;
  126. if (!that) {
  127. printf("Error:参数失效\n");
  128. return -1;
  129. }
  130. if (that->m_nRunType == SUBPROCESS)
  131. {
  132. DWORD dwRead;
  133. CHAR chBuf[BUFSIZE] = {0};
  134. BOOL bSuccess = FALSE;
  135. do
  136. {
  137. bSuccess = ReadFile(that->m_hStdOutRead, chBuf, BUFSIZE, &dwRead, NULL);
  138. if (!bSuccess || dwRead == 0 || !_tcslen(chBuf))
  139. continue;
  140. that->m_ulStartTickCount = GetTickCount64();
  141. GLOBAL::WritePythonLog(that->m_szLogPath, chBuf);
  142. // 更新日志时间;
  143. if ( that->m_pCaseObj )
  144. that->m_pCaseObj->_ulStartTickCount = GetTickCount64();
  145. memset(chBuf, 0, BUFSIZE);
  146. } while (!that->m_bStopLogExport);
  147. }
  148. else if ( that->m_nRunType == EMBEDDED)
  149. {
  150. DWORD dwRead;
  151. CHAR chBuf[BUFSIZE] = {0};
  152. BOOL bSuccess = FALSE;
  153. do
  154. {
  155. bSuccess = ReadFile(that->m_hStdOutRead, chBuf, BUFSIZE, &dwRead, NULL);
  156. if (!bSuccess || dwRead == 0 || !_tcslen(chBuf))
  157. continue;
  158. that->m_ulStartTickCount = GetTickCount64();
  159. GLOBAL::WritePythonLog(that->m_szLogPath, chBuf);
  160. // 更新日志时间;
  161. if ( that->m_pCaseObj )
  162. that->m_pCaseObj->_ulStartTickCount = GetTickCount64();
  163. memset(chBuf, 0, BUFSIZE);
  164. } while (!that->m_bStopLogExport);
  165. }
  166. // 结束重定向;
  167. that->EndSubprocessStdOut();
  168. GLOBAL::WriteTextLog(_T("脚本日志线程结束,用例名=%s"), that->m_pCaseObj->strCaseName.c_str());
  169. return 0;
  170. }
  171. int CScriptExecutor::RedirectSubprocessStdout(LPSTARTUPINFO si /*=NULL*/)
  172. {
  173. #ifdef _DEBUG
  174. OutputDebugString("RedirectSubprocessStdout\n");
  175. #endif
  176. // Python脚本中,必须使用sys.__stdout__()
  177. if (m_nRunType == SUBPROCESS) {
  178. SECURITY_ATTRIBUTES sa;
  179. sa.bInheritHandle = TRUE;
  180. sa.lpSecurityDescriptor = NULL;
  181. sa.nLength = sizeof(sa);
  182. // 创建stdout的管道;
  183. if (!CreatePipe(&m_hStdOutRead, &m_hStdOutWrite, &sa, 0)) {
  184. OutputDebugString("Error:创建stdout管道失败\n");
  185. return -1;
  186. }
  187. #if 0// 标准输出和标准错误都由同一个句柄重定向,此时只需要一个线程来读取管道内容;
  188. // 创建stderr的管道,由于stderr一般就是stdout,直接复制句柄;
  189. if (!DuplicateHandle(GetCurrentProcess(), m_hStdOutWrite, GetCurrentProcess(), &m_hStdErrorWrite, 0, TRUE, DUPLICATE_SAME_ACCESS)) {
  190. OutputDebugString("创建stderr管道失败\n");
  191. return -2;
  192. }
  193. #else
  194. // 标准输出和标准错误分开,需要二个线程来读取管道内容;
  195. if (!CreatePipe(&m_hStdErrorRead, &m_hStdErrorWrite, &sa, 0)) {
  196. OutputDebugString("Error:创建stderr管道失败\n");
  197. return -1;
  198. }
  199. #endif
  200. si->dwFlags |= STARTF_USESTDHANDLES;
  201. // 将子进程的stdout输出到句柄hStdOutWrite;
  202. si->hStdOutput = m_hStdOutWrite;
  203. // 将子进程的stderr输出到句柄hStdErrWrite;
  204. si->hStdError = m_hStdErrorWrite;
  205. return 0;
  206. }
  207. // 异常类型;
  208. OutputDebugString("Error:异常类型\n");
  209. return -5;
  210. }
  211. int CScriptExecutor::RedirectProcessStdout()
  212. {
  213. #ifdef _DEBUG
  214. OutputDebugString("RedirectProcessStdout\n");
  215. #endif
  216. if (m_nRunType == EMBEDDED) {
  217. // 创建stdout的管道;
  218. if (!CreatePipe(&m_hStdOutRead, &m_hStdOutWrite, NULL, 0)) {
  219. printf("Error:创建stdout管道失败\n");
  220. return -1;
  221. }
  222. // 将 C 运行时文件描述符与现有操作系统文件句柄关联;
  223. int wpfd = _open_osfhandle((intptr_t)m_hStdOutWrite, _O_TEXT);
  224. // 为stdout分配新文件描述符;
  225. if (_dup2(wpfd, _fileno(stdout)) != 0) {
  226. printf("Error:dup2调用失败");
  227. return -2;
  228. }
  229. _close(wpfd);
  230. // 备份进程原始标准输出;
  231. m_hOldStdOutWrite = GetStdHandle(STD_OUTPUT_HANDLE);
  232. // 设备进程标准输出,重定向到管道中;
  233. if (!SetStdHandle(STD_OUTPUT_HANDLE, m_hStdOutWrite)) {
  234. printf("Error:重定向失败\n");
  235. return -3;
  236. }
  237. // 设置标准流不使用缓冲,即时写入;
  238. setvbuf(stdout, NULL, _IONBF, 0);
  239. return 0;
  240. }
  241. // 异常类型;
  242. printf("Error:异常类型\n");
  243. return -5;
  244. }
  245. void CScriptExecutor::CatchPythonException()
  246. {
  247. if (!Py_IsInitialized())
  248. {
  249. printf("Error:未初始化Python环境\n");
  250. return;
  251. }
  252. if (!PyErr_Occurred())
  253. {
  254. printf("Error:没有异常产生\n");
  255. return;
  256. }
  257. // 捕获异常;
  258. const char* pszErrMsg = NULL;
  259. TCHAR* pszTraceback = NULL;
  260. PyObject* pPyType = NULL;
  261. PyObject* pPyValue = NULL;
  262. PyObject* pPyTraceback = NULL;
  263. // 非控制台,使用PyErr_Fetch捕获异常;
  264. PyErr_Fetch(&pPyType, &pPyValue, &pPyTraceback);
  265. PyErr_NormalizeException(&pPyType, &pPyValue, &pPyTraceback); // 可有可无,不影响获取异常;
  266. if (pPyValue) {
  267. PyObject* pPyStr = PyObject_Str(pPyValue);
  268. if (PyString_Check(pPyStr)) {
  269. pszErrMsg = PyString_AsString(pPyStr);
  270. if (pszErrMsg)
  271. printf("Error Info=>%s\n", pszErrMsg);
  272. if (pPyTraceback) {
  273. PyObject* pPyTraceModule = PyImport_ImportModule("traceback");
  274. if (!pPyTraceModule)
  275. {
  276. printf("Error:导入traceback模块失败\n");
  277. return;
  278. }
  279. #if 1 // 细分出所有换行符;
  280. PyObject* pPyModuleDict = PyModule_GetDict(pPyTraceModule);
  281. if (pPyModuleDict) {
  282. PyObject* pPyFunc = PyDict_GetItemString(pPyModuleDict, "format_exception");
  283. if (!pPyFunc || !PyCallable_Check(pPyFunc)) {
  284. printf("Error:加载format_exception失败\n");
  285. return;
  286. }
  287. PyObject* pErroList = PyObject_CallFunctionObjArgs(pPyFunc, pPyType, pPyValue, pPyTraceback, NULL);
  288. if (pErroList) {
  289. int nSize = PyList_Size(pErroList);
  290. for (int i = 0; i < nSize; i++) {
  291. pszErrMsg = PyString_AsString(PyList_GetItem(pErroList, i));
  292. printf("%s", pszErrMsg);
  293. }
  294. }
  295. Py_DECREF(pErroList);
  296. }
  297. Py_XDECREF(pPyTraceModule);
  298. #else // 不细分Item;
  299. PyObject* pPyFunc = PyObject_GetAttrString(pPyTraceModule, "format_exception");
  300. if (!pPyFunc || !PyCallable_Check(pPyFunc))
  301. {
  302. printf("Error:加载format_exception失败\n");
  303. return;
  304. }
  305. PyObject* pPyResult = PyObject_CallFunctionObjArgs(pPyFunc, pPyType, pPyValue, pPyTraceback, NULL);
  306. pPyStr = PyObject_Str(pPyResult);
  307. pszErrMsg = PyString_AsString(pPyStr);
  308. if (pszErrMsg)
  309. printf("%s\n", pszErrMsg);
  310. Py_DECREF(pPyResult);
  311. Py_XDECREF(pPyTraceModule);
  312. #endif
  313. }
  314. }
  315. }
  316. Py_XDECREF(pPyType);
  317. Py_XDECREF(pPyValue);
  318. Py_XDECREF(pPyTraceback);
  319. }
  320. int CScriptExecutor::RunEmbeddedScript()
  321. {
  322. // 参数有效性判断;
  323. if (!PathFileExists(m_szScriptPath)) {
  324. printf("Error:脚本文件不存在\n");
  325. return -1;
  326. }
  327. // 初始化Python环境;
  328. if (!Py_IsInitialized())
  329. Py_Initialize();
  330. if (!Py_IsInitialized()) {
  331. printf("Error:初始化Python环境失败\n");
  332. return -2;
  333. }
  334. // 解析脚本路径和脚本名称;
  335. std::string scriptdir;
  336. TCHAR szDrive[_MAX_DRIVE] = { 0 };
  337. TCHAR szDir[_MAX_DIR] = { 0 };
  338. TCHAR szExt[_MAX_EXT] = { 0 };
  339. TCHAR szFilename[_MAX_FNAME] = { 0 };
  340. TCHAR szScriptDir[MAX_PATH] = { 0 };
  341. _tsplitpath_s(m_szScriptPath, szDrive, szDir, szFilename, szExt);
  342. _stprintf_s(szScriptDir, _T("%s%s"), szDrive, szDir);
  343. // 缓存一份路径;
  344. scriptdir = szScriptDir;
  345. // 将'\'转换成'/', Python才设置运行目录成功;
  346. int len = _tcslen(szScriptDir);
  347. for (int i = 0; i < len; i++) {
  348. if (szScriptDir[i] == '\\')
  349. szScriptDir[i] = '/';
  350. }
  351. //szScriptDir[len-1] = '\0';
  352. TCHAR szExecuteDir[MAX_PATH] = { 0 };
  353. _stprintf_s(szExecuteDir, _T("sys.path.append(\"%s\")"), szScriptDir);
  354. // 添加系统模块,并指定当前脚本路径为运行路径;
  355. PyRun_SimpleString("import sys");
  356. PyRun_SimpleString(szExecuteDir);
  357. // 运行额外的语句,一般用于传递命令行参数;
  358. if (_tcslen(m_szExtraSentence))
  359. PyRun_SimpleString(m_szExtraSentence);
  360. // 注意:脚本名称尽量不要与系统目录其他py文件相同;
  361. // 导入脚本,以脚本名称为模块名加载;
  362. PyObject* pModuleObj = PyImport_ImportModule(szFilename);
  363. if (!pModuleObj)
  364. {
  365. printf("Error:加载脚本模块失败\n");
  366. Py_Finalize();
  367. return -3;
  368. }
  369. // 获取脚本的主函数名称(规定所有脚本的主函数名为main)
  370. // 加载函数:注意,如果目录下有同名的脚本文件,可能会加载失败;
  371. PyObject* pFunction = PyObject_GetAttrString(pModuleObj, "main");
  372. if (!pFunction || !PyCallable_Check(pFunction))
  373. {
  374. printf("Error:加载函数失败\n");
  375. Py_Finalize();
  376. return -4;
  377. }
  378. // 执行main函数;
  379. PyObject* pResult = PyObject_CallObject(pFunction, NULL);
  380. if (!pResult)
  381. {
  382. printf("Error:执行函数失败\n");
  383. CatchPythonException();
  384. Py_Finalize();
  385. return -5;
  386. }
  387. // 延时;
  388. Sleep(2000);
  389. // 结束日志线程;
  390. m_bStopLogExport = TRUE;
  391. // 同时需要关闭输出的管道,否则ReadFile会阻塞;
  392. CloseHandle(m_hStdOutWrite);
  393. m_hStdOutWrite = NULL;
  394. CloseHandle(m_hStdErrorWrite);
  395. m_hStdErrorWrite = NULL;
  396. Py_DECREF(pResult);
  397. Py_Finalize();
  398. return 0;
  399. }
  400. int CScriptExecutor::RunScriptProcess()
  401. {
  402. if (!PathFileExists(m_szScriptPath))
  403. {
  404. printf("Error:脚本路径无效\n");
  405. return -1;
  406. }
  407. // 初始化参数;
  408. ::memset(&m_si, 0, sizeof(m_si));
  409. ::memset(&m_pi, 0, sizeof(m_pi));
  410. m_si.cb = sizeof(m_si);
  411. GetStartupInfo(&m_si);
  412. // 强制stdion, stdout和stderr完全无缓冲:python -u
  413. TCHAR szCommandLine[MAX_PATH] = { 0 };
  414. if (_tcslen(m_szExtraSentence))
  415. _stprintf_s(szCommandLine, _T("python -W ignore -u %s %s"), m_szScriptPath, m_szExtraSentence);
  416. else
  417. _stprintf_s(szCommandLine, _T("python -W ignore -u %s"), m_szScriptPath);
  418. // 重定向输出;
  419. RedirectSubprocessStdout(&m_si);
  420. // 恢复日志线程;
  421. ResumeThread(m_hStdoutLogThread);
  422. // 启动子进程;
  423. if (!CreateProcess(
  424. NULL, // No module name (use command line)
  425. szCommandLine, // Command line
  426. NULL, // Process handle not inheritable
  427. NULL, // Thread handle not inheritable
  428. TRUE, // Set handle inheritance to TRUE
  429. 0, // No creation flags
  430. NULL, // Use parent's environment block
  431. NULL, // Use parent's starting directory
  432. &m_si, // Pointer to STARTUPINFO structure
  433. &m_pi) // Pointer to PROCESS_INFORMATION structure
  434. )
  435. {
  436. GLOBAL::WriteTextLog("Error:创建子进程失败 (%d)", GetLastError());
  437. return -3;
  438. }
  439. m_bRuned = TRUE;
  440. m_dwSubprocessId = m_pi.dwProcessId;
  441. // 等待进程完成退出.
  442. WaitForSingleObject(m_pi.hProcess, INFINITE);
  443. Sleep(5000);
  444. GLOBAL::WriteTextLog("脚本进程结束(%ld)", m_pi.dwProcessId);
  445. // 结束日志线程;
  446. m_bStopLogExport = TRUE;
  447. // 同时需要关闭输出的管道,否则ReadFile会阻塞;
  448. CloseHandle(m_hStdOutWrite);
  449. m_hStdOutWrite = NULL;
  450. CloseHandle(m_hStdErrorWrite);
  451. m_hStdErrorWrite = NULL;
  452. // 关闭进程句柄.
  453. CloseHandle(m_pi.hProcess);
  454. CloseHandle(m_pi.hThread);
  455. // 重置;
  456. memset(&m_si, 0, sizeof(m_si));
  457. memset(&m_pi, 0, sizeof(m_pi));
  458. m_si.cb = sizeof(m_si);
  459. return 0;
  460. }
  461. int CScriptExecutor::ServiceRunScriptProcess()
  462. {
  463. if (!PathFileExists(m_szScriptPath)) {
  464. printf("Error:脚本路径无效\n");
  465. return -1;
  466. }
  467. DWORD dwProcesses = 0;
  468. BOOL bResult = FALSE;
  469. DWORD dwRet = 0;
  470. DWORD dwSid = GetActiveSessionID();
  471. HANDLE hProcess = NULL, hPToken = NULL, hUserTokenDup = NULL;
  472. if (!WTSQueryUserToken(dwSid, &hPToken)) {
  473. PROCESSENTRY32 procEntry;
  474. DWORD dwPid = 0;
  475. HANDLE hSnap = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
  476. if (hSnap == INVALID_HANDLE_VALUE) {
  477. return FALSE;
  478. }
  479. procEntry.dwSize = sizeof(PROCESSENTRY32);
  480. if (Process32First(hSnap, &procEntry)) {
  481. do {
  482. if (_tcsicmp(procEntry.szExeFile, _T("explorer.exe")) == 0) {
  483. DWORD exeSessionId = 0;
  484. if (ProcessIdToSessionId(procEntry.th32ProcessID, &exeSessionId) && exeSessionId == dwSid) {
  485. dwPid = procEntry.th32ProcessID;
  486. break;
  487. }
  488. }
  489. } while (Process32Next(hSnap, &procEntry));
  490. }
  491. CloseHandle(hSnap);
  492. // explorer进程不存在
  493. if (dwPid == 0) {
  494. return FALSE;
  495. }
  496. hProcess = ::OpenProcess(PROCESS_QUERY_INFORMATION, FALSE, dwPid);
  497. if (hProcess == NULL) {
  498. return FALSE;
  499. }
  500. if(!::OpenProcessToken(hProcess, TOKEN_ALL_ACCESS_P,&hPToken)) {
  501. CloseHandle(hProcess);
  502. return FALSE;
  503. }
  504. }
  505. if (hPToken == NULL)
  506. return -1;
  507. TOKEN_LINKED_TOKEN admin;
  508. bResult = GetTokenInformation(hPToken, (TOKEN_INFORMATION_CLASS)19, &admin, sizeof(TOKEN_LINKED_TOKEN), &dwRet);
  509. if (!bResult) {// vista 以前版本不支持TokenLinkedToken
  510. TOKEN_PRIVILEGES tp;
  511. LUID luid;
  512. if (LookupPrivilegeValue(NULL,SE_DEBUG_NAME,&luid)) {
  513. tp.PrivilegeCount =1;
  514. tp.Privileges[0].Luid =luid;
  515. tp.Privileges[0].Attributes =SE_PRIVILEGE_ENABLED;
  516. }
  517. DuplicateTokenEx(hPToken,MAXIMUM_ALLOWED,NULL,SecurityIdentification,TokenPrimary,&hUserTokenDup);
  518. } else {
  519. hUserTokenDup = admin.LinkedToken;
  520. }
  521. LPVOID pEnv =NULL;
  522. DWORD dwCreationFlags = CREATE_PRESERVE_CODE_AUTHZ_LEVEL;
  523. if(CreateEnvironmentBlock(&pEnv,hUserTokenDup,TRUE))
  524. {
  525. dwCreationFlags|=CREATE_UNICODE_ENVIRONMENT;
  526. }
  527. else
  528. {
  529. pEnv = NULL;
  530. }
  531. ZeroMemory( &m_si, sizeof(m_si) );
  532. m_si.cb = sizeof(m_si);
  533. m_si.dwFlags = STARTF_USESHOWWINDOW;
  534. m_si.wShowWindow = SW_HIDE;
  535. ZeroMemory( &m_pi, sizeof(m_pi) );
  536. // 重定向输出;
  537. RedirectSubprocessStdout(&m_si);
  538. // 恢复日志线程;
  539. ResumeThread(m_hStdoutLogThread);
  540. // 强制stdion, stdout和stderr完全无缓冲:python -u
  541. TCHAR szCommandLine[MAX_PATH] = { 0 };
  542. if (_tcslen(m_szExtraSentence))
  543. _stprintf_s(szCommandLine, _T("python -W ignore -u %s %s"), m_szScriptPath, m_szExtraSentence);
  544. else
  545. _stprintf_s(szCommandLine, _T("python -W ignore -u %s"), m_szScriptPath);
  546. bResult = CreateProcessAsUser(
  547. hUserTokenDup, // client's access token
  548. NULL, // file to execute
  549. szCommandLine, // command line
  550. NULL, // pointer to process SECURITY_ATTRIBUTES
  551. NULL, // pointer to thread SECURITY_ATTRIBUTES
  552. TRUE, // handles are not inheritable
  553. dwCreationFlags, // creation flags
  554. pEnv, // pointer to new environment block
  555. NULL, // name of current directory
  556. &m_si, // pointer to STARTUPINFO structure
  557. &m_pi // receives information about new process
  558. );
  559. if ( !bResult )
  560. return -1;
  561. m_bRuned = TRUE;
  562. m_dwSubprocessId = m_pi.dwProcessId;
  563. // 等待进程完成退出.
  564. WaitForSingleObject(m_pi.hProcess, INFINITE);
  565. Sleep(5000);
  566. // 结束日志线程;
  567. m_bStopLogExport = TRUE;
  568. // 关闭进程句柄.
  569. CloseHandle(m_pi.hProcess);
  570. CloseHandle(m_pi.hThread);
  571. // 同时需要关闭输出的管道,否则ReadFile会阻塞;
  572. CloseHandle(m_hStdOutWrite);
  573. m_hStdOutWrite = NULL;
  574. CloseHandle(m_hStdErrorWrite);
  575. m_hStdErrorWrite = NULL;
  576. // 重置;
  577. memset(&m_si, 0, sizeof(m_si));
  578. memset(&m_pi, 0, sizeof(m_pi));
  579. m_si.cb = sizeof(m_si);
  580. if (hUserTokenDup != NULL)
  581. CloseHandle(hUserTokenDup);
  582. if (hProcess != NULL)
  583. CloseHandle(hProcess);
  584. if (hPToken != NULL)
  585. CloseHandle(hPToken);
  586. if (pEnv != NULL)
  587. DestroyEnvironmentBlock(pEnv);
  588. return TRUE;
  589. }
  590. bool CScriptExecutor::StartThread()
  591. {
  592. // 创建线程;
  593. m_hWorkThread = CreateThread(NULL, 0, _WorkerThread, this, 0, &m_dwThreadId);
  594. if (!m_hWorkThread) {
  595. printf("Error:创建执行线程失败\n");
  596. return false;
  597. }
  598. // 创建线程;
  599. m_hStdoutLogThread = CreateThread(NULL, 0, _StdoutLogExportThread, this, CREATE_SUSPENDED, NULL);
  600. if (!m_hStdoutLogThread) {
  601. printf("Error:创建日志线程失败\n");
  602. return false;
  603. }
  604. return true;
  605. }
  606. void CScriptExecutor::EndWorkThread()
  607. {
  608. // 结束进程;
  609. EndSubprocess();
  610. // 等待3秒,是否能自主结束线程;
  611. if (m_hWorkThread) {
  612. if (WaitForSingleObject(m_hWorkThread, 3000) == WAIT_OBJECT_0) {
  613. CloseHandle(m_hWorkThread);
  614. m_hWorkThread = NULL;
  615. return;
  616. }
  617. }
  618. // 手动结束线程;
  619. if ( m_hWorkThread ) {
  620. // 尝试5次结束行为;
  621. for (int i = 0; i < 5; i++) {
  622. if (TerminateThread(m_hWorkThread, 0))
  623. break;
  624. }
  625. CloseHandle(m_hWorkThread);
  626. m_hWorkThread = NULL;
  627. }
  628. }
  629. void CScriptExecutor::EndLogThread()
  630. {
  631. m_bStopLogExport = TRUE;
  632. // 等待3秒,是否能自主结束线程;
  633. if ( m_hStdoutLogThread ) {
  634. if ( WaitForSingleObject(m_hStdoutLogThread, 3000) == WAIT_OBJECT_0 ) {
  635. CloseHandle(m_hStdoutLogThread);
  636. m_hStdoutLogThread = NULL;
  637. return;
  638. }
  639. }
  640. // 手动结束线程;
  641. if (m_hStdoutLogThread) {
  642. // 尝试5次结束行为;
  643. for (int i = 0; i < 5; i++) {
  644. if (TerminateThread(m_hStdoutLogThread, 0))
  645. break;
  646. }
  647. CloseHandle(m_hStdoutLogThread);
  648. m_hStdoutLogThread = NULL;
  649. }
  650. }
  651. void CScriptExecutor::EndThread()
  652. {
  653. EndWorkThread();
  654. EndLogThread();
  655. }
  656. BOOL CScriptExecutor::EndSubprocess()
  657. {
  658. BOOL ret = false;
  659. if (m_pi.hProcess) {
  660. // 尝试5次结束;
  661. for (int i = 0; i < 5; i++) {
  662. if ( (ret = TerminateProcess(m_pi.hProcess, 0)) )
  663. break;
  664. }
  665. }
  666. return ret;
  667. }
  668. void CScriptExecutor::EndProcessStdOut()
  669. {
  670. OutputDebugString("--------------EndProcessStdOut----------------\n");
  671. #if 0 // 恢复失败,代码有问题
  672. // 恢复标准输出(嵌入进程脚本);
  673. if ( m_nRunType == EMBEDDED && m_hOldStdOutWrite)
  674. {
  675. int fn = _fileno(stdout);
  676. // 恢复进程默认标准输出;
  677. int fd = _open_osfhandle((intptr_t)m_hOldStdOutWrite, _O_RDWR);
  678. if ( _dup2(fd, _fileno(stdout)) == 0)
  679. {
  680. _close(fd);
  681. // 设置标准输出;
  682. SetStdHandle(STD_OUTPUT_HANDLE, m_hOldStdOutWrite);
  683. m_hOldStdOutWrite = NULL;
  684. // 设置标准流不使用缓冲,即时写入;
  685. setvbuf(stdout, NULL, _IONBF, 0);
  686. }
  687. else
  688. {
  689. printf("Error:_dup2分配文件描述符失败\n");
  690. }
  691. }
  692. #endif
  693. // 关闭重定向句柄;
  694. if (m_hStdErrorWrite)
  695. CloseHandle(m_hStdErrorWrite);
  696. m_hStdErrorWrite = NULL;
  697. // 只有子进程方式才关闭句柄;
  698. if ( m_hStdOutWrite)
  699. CloseHandle(m_hStdOutWrite);
  700. m_hStdOutWrite = NULL;
  701. if (m_hStdOutRead)
  702. CloseHandle(m_hStdOutRead);
  703. m_hStdOutRead = NULL;
  704. }
  705. void CScriptExecutor::EndSubprocessStdOut()
  706. {
  707. OutputDebugString("--------------EndSubprocessStdOut----------------\n");
  708. // 关闭重定向句柄;
  709. if (m_hStdErrorWrite)
  710. CloseHandle(m_hStdErrorWrite);
  711. m_hStdErrorWrite = NULL;
  712. // 只有子进程方式才关闭句柄;
  713. if ( m_hStdOutWrite)
  714. CloseHandle(m_hStdOutWrite);
  715. m_hStdOutWrite = NULL;
  716. if (m_hStdOutRead)
  717. CloseHandle(m_hStdOutRead);
  718. m_hStdOutRead = NULL;
  719. }
  720. DWORD CScriptExecutor::GetActiveSessionID()
  721. {
  722. DWORD dwSessionId = 0;
  723. PWTS_SESSION_INFO pSessionInfo = NULL;
  724. DWORD dwCount = 0;
  725. WTSEnumerateSessions(WTS_CURRENT_SERVER_HANDLE, 0, 1, &pSessionInfo, &dwCount);
  726. for(DWORD i = 0; i < dwCount; i++) {
  727. WTS_SESSION_INFO si = pSessionInfo[i];
  728. if(WTSActive == si.State) {
  729. dwSessionId = si.SessionId;
  730. break;
  731. }
  732. }
  733. WTSFreeMemory(pSessionInfo);
  734. return dwSessionId;
  735. }
  736. BOOL CScriptExecutor::ServiceExecute(std::wstring wstrCmdLine, INT32& n32ExitResult)
  737. {
  738. ofstream ofile("C:\\logEvent.txt");
  739. ofile<<"start excute"<<std::endl;
  740. DWORD dwProcesses = 0;
  741. BOOL bResult = FALSE;
  742. DWORD dwSid = GetActiveSessionID();
  743. DWORD dwRet = 0;
  744. PROCESS_INFORMATION pi;
  745. STARTUPINFO si;
  746. HANDLE hProcess = NULL, hPToken = NULL, hUserTokenDup = NULL;
  747. if (!WTSQueryUserToken(dwSid, &hPToken)) {
  748. PROCESSENTRY32 procEntry;
  749. DWORD dwPid = 0;
  750. HANDLE hSnap = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
  751. if (hSnap == INVALID_HANDLE_VALUE) {
  752. return FALSE;
  753. }
  754. procEntry.dwSize = sizeof(PROCESSENTRY32);
  755. if (Process32First(hSnap, &procEntry)) {
  756. do {
  757. if (_tcsicmp(procEntry.szExeFile, _T("explorer.exe")) == 0) {
  758. DWORD exeSessionId = 0;
  759. if (ProcessIdToSessionId(procEntry.th32ProcessID, &exeSessionId) && exeSessionId == dwSid) {
  760. dwPid = procEntry.th32ProcessID;
  761. break;
  762. }
  763. }
  764. } while (Process32Next(hSnap, &procEntry));
  765. }
  766. CloseHandle(hSnap);
  767. // explorer进程不存在
  768. if (dwPid == 0)
  769. {
  770. return FALSE;
  771. }
  772. hProcess = ::OpenProcess(PROCESS_QUERY_INFORMATION, FALSE, dwPid);
  773. if (hProcess == NULL) {
  774. return FALSE;
  775. }
  776. if(!::OpenProcessToken(hProcess, TOKEN_ALL_ACCESS_P,&hPToken)) {
  777. CloseHandle(hProcess);
  778. return FALSE;
  779. }
  780. }
  781. if (hPToken == NULL)
  782. return FALSE;
  783. TOKEN_LINKED_TOKEN admin;
  784. bResult = GetTokenInformation(hPToken, (TOKEN_INFORMATION_CLASS)19, &admin, sizeof(TOKEN_LINKED_TOKEN), &dwRet);
  785. if (!bResult) {// vista 以前版本不支持TokenLinkedToken
  786. TOKEN_PRIVILEGES tp;
  787. LUID luid;
  788. if (LookupPrivilegeValue(NULL,SE_DEBUG_NAME,&luid)) {
  789. tp.PrivilegeCount =1;
  790. tp.Privileges[0].Luid =luid;
  791. tp.Privileges[0].Attributes =SE_PRIVILEGE_ENABLED;
  792. }
  793. DuplicateTokenEx(hPToken,MAXIMUM_ALLOWED,NULL,SecurityIdentification,TokenPrimary,&hUserTokenDup);
  794. } else {
  795. hUserTokenDup = admin.LinkedToken;
  796. ofile<<"token: "<<hUserTokenDup<<std::endl;
  797. }
  798. LPVOID pEnv =NULL;
  799. DWORD dwCreationFlags = CREATE_PRESERVE_CODE_AUTHZ_LEVEL;
  800. if(CreateEnvironmentBlock(&pEnv,hUserTokenDup,TRUE)) {
  801. dwCreationFlags|=CREATE_UNICODE_ENVIRONMENT;
  802. } else {
  803. pEnv = NULL;
  804. }
  805. ZeroMemory( &si, sizeof(si) );
  806. si.cb = sizeof(si);
  807. si.dwFlags = STARTF_USESHOWWINDOW;
  808. si.wShowWindow = SW_SHOWNORMAL;
  809. ZeroMemory( &pi, sizeof(pi) );
  810. bResult = CreateProcessAsUser(
  811. hUserTokenDup, // client's access token
  812. NULL, // file to execute
  813. (LPTSTR) wstrCmdLine.c_str(), // command line
  814. NULL, // pointer to process SECURITY_ATTRIBUTES
  815. NULL, // pointer to thread SECURITY_ATTRIBUTES
  816. FALSE, // handles are not inheritable
  817. dwCreationFlags, // creation flags
  818. pEnv, // pointer to new environment block
  819. NULL, // name of current directory
  820. &si, // pointer to STARTUPINFO structure
  821. &pi // receives information about new process
  822. );
  823. if(pi.hProcess) {
  824. if(WAIT_OBJECT_0 == WaitForSingleObject(pi.hProcess, 180000)) {
  825. DWORD dwResult = 0;
  826. if(GetExitCodeProcess(pi.hProcess, &dwResult)) {
  827. n32ExitResult = dwResult;
  828. } else {
  829. n32ExitResult = -1;
  830. }
  831. CloseHandle(pi.hThread);
  832. CloseHandle(pi.hProcess);
  833. } else {
  834. CloseHandle(pi.hThread);
  835. CloseHandle(pi.hProcess);
  836. n32ExitResult = -1;
  837. }
  838. }
  839. if (hUserTokenDup != NULL)
  840. CloseHandle(hUserTokenDup);
  841. if (hProcess != NULL)
  842. CloseHandle(hProcess);
  843. if (hPToken != NULL)
  844. CloseHandle(hPToken);
  845. if (pEnv != NULL)
  846. DestroyEnvironmentBlock(pEnv);
  847. return TRUE;
  848. }
  849. bool CScriptExecutor::InitScript(std::string strScript, std::string strLogPath, std::string strScriptCmd, int nRunType /*= PY_RUN_TYPE::EMBEDDED*/)
  850. {
  851. // 判断脚本是否存在;
  852. if (!PathFileExists(strScript.c_str())) {
  853. printf("Error:脚本文件不存在\n");
  854. return false;
  855. }
  856. // 判断日志文件路径是否可创建;
  857. if (!PathFileExists(strLogPath.c_str())) {
  858. // 创建路径;
  859. if (!GLOBAL::MKDIR(strLogPath.c_str())) {
  860. printf("Error:创建目录失败\n");
  861. return false;
  862. }
  863. // 创建文件;
  864. std::ofstream flog(strLogPath.c_str());
  865. if ( flog.bad() ) {
  866. printf("Error:创建文件失败\n");
  867. return false;
  868. }
  869. flog.close();
  870. }
  871. // 赋值参数;
  872. m_bRuned = FALSE;
  873. m_nRunType = nRunType;
  874. m_dwThreadId = m_dwSubprocessId = 0;
  875. _tcscpy_s(m_szScriptPath, strScript.c_str());
  876. _tcscpy_s(m_szLogPath, strLogPath.c_str());
  877. _tcscpy_s(m_szExtraSentence, strScriptCmd.c_str());
  878. return true;
  879. }
  880. bool CScriptExecutor::StartScript()
  881. {
  882. if (StartThread()) {
  883. Sleep(100);
  884. return true;
  885. }
  886. // 异常类型;
  887. printf("Error:异常类型脚本\n");
  888. return false;
  889. }
  890. void CScriptExecutor::StopScript()
  891. {
  892. // 如果是子进程运行脚本,停止线程时kill进程;
  893. if (m_nRunType == SUBPROCESS)
  894. EndSubprocess();
  895. // 结束线程;
  896. EndWorkThread();
  897. }
  898. bool CScriptExecutor::IsScriptOver()
  899. {
  900. if ( WaitForSingleObject(m_hStdoutLogThread, 0) == WAIT_OBJECT_0 && WaitForSingleObject(m_hWorkThread, 0) == WAIT_OBJECT_0)
  901. {
  902. GLOBAL::WriteTextLog(_T("====>脚本(%s)已完成"), m_pCaseObj->strCaseName.c_str());
  903. return true;
  904. }
  905. return false;
  906. }