spshell.cpp 34 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030
  1. #include "precompile.h"
  2. #include "app.h"
  3. #include "osutil.h"
  4. #include "version.h"
  5. #include "memtrace.h"
  6. #include "sp_def.h"
  7. #ifdef RVC_OS_WIN
  8. #include <DbgHelp.h>
  9. #include <TlHelp32.h>
  10. #include <shellapi.h>
  11. #else
  12. #include <unistd.h>
  13. #endif //RVC_OS_WIN
  14. #include "fileutil.h"
  15. #include "iniutil.h"
  16. #include "getopt.h"
  17. #include "toolkit.h"
  18. #include "SimpleString.h"
  19. #include "md5file.h"
  20. #include "SpBase.h"
  21. #include "SpComm.hpp"
  22. #ifdef RVC_OS_WIN
  23. #include <io.h>
  24. #include "sp_firewallControl.h"
  25. #else
  26. #include <unistd.h>
  27. #include <sys/syscall.h>
  28. #endif //RVC_OS_WIN
  29. #include <map>
  30. #include <iterator>
  31. #include <fstream>
  32. #include "libtoolkit/log.h"
  33. #include <signal.h>
  34. #include "SpBase.h"
  35. #include "sp_dbg_export.h"
  36. #include "versionBase.h"
  37. #include "base64File.hpp"
  38. #include "RVCEventCode.h"
  39. #include "dbgutil.h"
  40. #include <locale.h>
  41. #include <winpr/library.h>
  42. #include <winpr/environment.h>
  43. #include <winpr/registry.h>
  44. #include <winpr/sysinfo.h>
  45. #ifdef realloc
  46. #undef realloc //(p, s)
  47. #endif
  48. using namespace std;
  49. #include <spbase/sp_runTask.h>
  50. #ifndef RVC_OS_WIN
  51. static int GetParentProcessID()
  52. {
  53. #if 0
  54. return getppid();
  55. #else
  56. return (int)syscall(SYS_getppid);
  57. #endif
  58. }
  59. #endif //NOT _WIN32
  60. #ifdef RVC_OS_WIN
  61. static char spshell_execute_name[] = "SpShell.exe";
  62. static char sphost_execute_name[] = "SpHost.exe";
  63. static char guardian_execute_name[] = "Guardian.exe";
  64. static char cefclient_execute_name[] = "cefclient.exe";
  65. #else
  66. static char spshell_execute_name[] = "spshell";
  67. static char sphost_execute_name[] = "sphost";
  68. static char guardian_execute_name[] = "guardian";
  69. static char cefclient_execute_name[] = "cefclient";
  70. #endif //_WIN32
  71. #define RESTART_MODE_DEFAULT 0
  72. #define RESTART_MODE_NORMAL 1
  73. #define RESTART_MODE_PRE 2
  74. #define RESTART_MODE_SHUTDOWN 3
  75. #define RESTART_MODE_POWEROFF 4
  76. #define RESTART_MODE_REBOOT 5
  77. #define DRIVER_NAME "HelloDDK"
  78. #define DRIVER_PATH "InterceptDll.sys"
  79. #define SET_EVENT \
  80. CTL_CODE(FILE_DEVICE_UNKNOWN, 0x800, METHOD_BUFFERED, FILE_ANY_ACCESS)
  81. #define GET_SHARE_ADD \
  82. CTL_CODE(FILE_DEVICE_UNKNOWN, 0x801, METHOD_BUFFERED, FILE_ANY_ACCESS)
  83. HANDLE g_hEvent = NULL;
  84. bool g_bMD5Exist = false;
  85. bool g_bWow64 = false;
  86. CSimpleStringA g_strMD5ListPath;
  87. static int g_restartMode = RESTART_MODE_DEFAULT;
  88. static bool g_immediately = false;
  89. char* relate_processes[] = { spshell_execute_name, sphost_execute_name, cefclient_execute_name };
  90. const int relate_processes_count = 3;
  91. char* relate_processes_ex[] = { spshell_execute_name, sphost_execute_name, guardian_execute_name, cefclient_execute_name };
  92. const int relate_processes_ex_count = 4;
  93. const int MAX_LEN = 256;
  94. //E:\Run\version\3.10.0.1\dep;E:\Run\version\3.10.0.1\bin;E:\Run\version\3.10.0.1\dev;E:\Run\version\3.10.0.1\imdep
  95. static bool IsSpPathType(const CSimpleStringA& value, const char* key)
  96. {
  97. const int leastLength = strlen("Run//1.0.0.0/") + strlen(key);
  98. CSimpleStringA path(value.GetData());
  99. if (path.IsNullOrEmpty() || path.GetLength() < leastLength) return false;
  100. for (int i = 0; i < path.GetLength(); ++i) {
  101. if (path[i] >= 'A' && path[i] <= 'Z') path[i] = path[i] + ('a' - 'A');
  102. }
  103. const int sionPos = path.IndexOf(key);
  104. const int verPos = sionPos + strlen(key) + strlen(SPLIT_SLASH_STR);
  105. if (sionPos < 0) return false;
  106. int suffixPos = -1, i;
  107. int dotCnt = 0;
  108. bool lastIsNum = false;
  109. for (i = verPos; i < path.GetLength() && (path[i] >= '0' && path[i] <= '9' || path[i] == '.'); ++i) {
  110. lastIsNum = !(path[i] == '.');
  111. if (!lastIsNum) dotCnt++;
  112. }
  113. //if (i == path.GetLength() && dotCnt == 3 && lastIsNum) return true; //D:\Run\version\3.7.1.0
  114. if (i >= path.GetLength() || dotCnt != 3 || !lastIsNum)
  115. return false;
  116. return true;
  117. }
  118. static CSimpleStringA CutSpPathFromPathValue(const char* value, const char* prefix)
  119. {
  120. CSimpleStringA path(value);
  121. CSimpleStringA result(true);
  122. CAutoArray<CSimpleStringA> values = path.Split(ENV_SEP_CHAR);
  123. if (values.GetCount() <= 0) {
  124. return path;
  125. }
  126. for (int i = 0; i < values.GetCount(); ++i) {
  127. if (!values[i].IsStartWith(prefix) && !IsSpPathType(values[i], "version") &&! IsSpPathType(values[i], "dep")) {
  128. if (!result.IsNullOrEmpty()) result += ENV_SEP_STR;
  129. result += values[i];
  130. }
  131. }
  132. //if (!result.IsNullOrEmpty() && path[path.GetLength() - 1] == ENV_SEP_CHAR) {
  133. // result += ENV_SEP_STR;
  134. //}
  135. return result;
  136. }
  137. static void ResetEnvPath()
  138. {
  139. char path[MAX_PATH];
  140. char *buf;
  141. DWORD size;
  142. #if defined(_MSC_VER)
  143. const char* name = "PATH";
  144. #else
  145. const char* name = "LD_LIBRARY_PATH";
  146. #endif //_MSC_VER
  147. // set current path
  148. GetModuleFileNameA(NULL, path, MAX_PATH);
  149. *strrchr(path, SPLIT_SLASH) = 0; //bin
  150. *strrchr(path, SPLIT_SLASH) = 0; //1.2.3.4
  151. SetCurrentDirectoryA(path);
  152. size = GetEnvironmentVariableA(name, NULL, 0);
  153. buf = (char*)malloc(size+MAX_PATH*3);
  154. size = GetEnvironmentVariableA(name, buf, size);
  155. DbgWithLink(LOG_LEVEL_DEBUG, LOG_TYPE_SYSTEM)("origin path:%s", buf);
  156. CSimpleStringA newValue = CutSpPathFromPathValue(buf, path);
  157. memset(buf, 0, size + MAX_PATH * 3);
  158. size = newValue.GetLength();
  159. if (!newValue.IsNullOrEmpty()) {
  160. strcpy(buf, newValue.GetData());
  161. strcat(buf, ENV_SEP_STR);
  162. }
  163. // append bin sub dir to %PATH%
  164. strcat(path, SPLIT_SLASH_STR "bin");
  165. strcat(buf, path);
  166. DbgWithLink(LOG_LEVEL_DEBUG, LOG_TYPE_SYSTEM)("new path:%s", buf);
  167. SetEnvironmentVariableA(name, buf);
  168. free(buf);
  169. SetEnvironmentVariableA("ModuleName", "SpShell");
  170. }
  171. #ifdef RVC_OS_WIN
  172. static void SetWorkingSet()
  173. {
  174. SIZE_T dwMinSize, dwMaxSize;
  175. HANDLE hCurrProcess = GetCurrentProcess();
  176. GetProcessWorkingSetSize(hCurrProcess, &dwMinSize, &dwMaxSize);
  177. if (dwMaxSize < (2 << 20))
  178. dwMaxSize = 2 << 20;
  179. SetProcessWorkingSetSize(hCurrProcess, dwMinSize, dwMaxSize);
  180. }
  181. static LONG WINAPI SuppressError(struct _EXCEPTION_POINTERS* ExceptionInfo)
  182. {
  183. static bool hasCall = false;
  184. if (hasCall)
  185. ExitProcess(Error_Exception);
  186. else
  187. hasCall = true;
  188. char tmp[MAX_PATH];
  189. HANDLE hDumpFile;
  190. std::string dmpFileStr;
  191. GetModuleFileNameA(NULL, tmp, MAX_PATH);
  192. *strrchr(tmp, SPLIT_SLASH) = 0;
  193. *strrchr(tmp, SPLIT_SLASH) = 0;
  194. *strrchr(tmp, SPLIT_SLASH) = 0;
  195. *strrchr(tmp, SPLIT_SLASH) = 0;
  196. *strrchr(tmp, SPLIT_SLASH) = 0;
  197. wsprintfA(tmp, "%s\\rvc\\dmp\\expt.spshell.%d.%s.dmp", tmp, GetCurrentProcessId(), STRFILEVER);
  198. hDumpFile = CreateFileA( tmp, GENERIC_READ | GENERIC_WRITE,
  199. 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL );
  200. if( ( hDumpFile != NULL ) && ( hDumpFile != INVALID_HANDLE_VALUE ) )
  201. {
  202. MINIDUMP_EXCEPTION_INFORMATION mdei;
  203. MINIDUMP_TYPE mdt;
  204. mdei.ThreadId = GetCurrentThreadId();
  205. mdei.ExceptionPointers = ExceptionInfo;
  206. mdei.ClientPointers = FALSE;
  207. mdt = MiniDumpNormal;
  208. MiniDumpWriteDump(GetCurrentProcess(), GetCurrentProcessId(),
  209. hDumpFile, mdt, (ExceptionInfo != 0) ? &mdei : 0, 0, 0 );
  210. CloseHandle( hDumpFile );
  211. }
  212. char szCmd[256];
  213. sprintf_s(szCmd, 256, "TASKKILL /f /im sphost.exe");
  214. system(szCmd);
  215. sprintf_s(szCmd, 256, "TASKKILL /f /im sphost_re.exe");
  216. system(szCmd);
  217. DbgWithLink(LOG_LEVEL_WARN, LOG_TYPE_SYSTEM).setAPI(__FUNCTION__).setLogCode(ERR_SPSHELL_EXCETION).setResultCode(RTAERR_SPSHELL_EXCEPTION)("spshell exit exception, saveDmp, %s, detail:%d:%s"
  218. , tmp, dmpFileStr.length() ,dmpFileStr.c_str());
  219. ExitProcess(Error_Exception); // exit process to suppress reporting exception
  220. return EXCEPTION_EXECUTE_HANDLER;
  221. }
  222. __declspec(dllimport) bool DisableCharmbar();
  223. __declspec(dllimport) bool EnableCharmbar();
  224. static void AutoHideTaskBar(bool bHide)
  225. {
  226. APPBARDATA apBar;
  227. memset(&apBar, 0, sizeof(apBar));
  228. apBar.cbSize = sizeof(apBar);
  229. apBar.lParam = bHide ? ABS_AUTOHIDE : ABS_ALWAYSONTOP;
  230. apBar.hWnd = FindWindow("Shell_TrayWnd", NULL);
  231. if (apBar.hWnd != NULL)
  232. {
  233. SHAppBarMessage(ABM_SETSTATE, &apBar);
  234. }
  235. }
  236. static bool AddFirewallRules()
  237. {
  238. char szBinDir[MAX_PATH] = {};
  239. GetModuleFileNameA(NULL, szBinDir, MAX_PATH);
  240. *strrchr(szBinDir, SPLIT_SLASH) = 0;
  241. int nRet = (int)ShellExecute(NULL, "open", "cmd.exe", "/s /c \"netsh advfirewall firewall delete rule name=\"\"SpShell\"\"", NULL, SW_HIDE);
  242. nRet = (int)ShellExecute(NULL, "open", "cmd.exe", "/s /c \"netsh advfirewall firewall delete rule name=\"\"SpHost_re\"\"", NULL, SW_HIDE);
  243. nRet = (int)ShellExecute(NULL, "open", "cmd.exe", "/s /c \"netsh advfirewall firewall delete rule name=\"\"SpHost\"\"", NULL, SW_HIDE);
  244. nRet = (int)ShellExecute(NULL, "open", "cmd.exe", "/s /c \"netsh advfirewall firewall delete rule name=\"\"SpGuardian\"\"", NULL, SW_HIDE);
  245. nRet = (int)ShellExecute(NULL, "open", "cmd.exe", "/s /c \"netsh advfirewall firewall delete rule name=\"\"cefclient\"\"", NULL, SW_HIDE);
  246. char szParam[1024] = {};
  247. sprintf_s(szParam, 1024, "/s /c \"netsh advfirewall firewall add rule name=\"\"SpShell\"\" dir=out program=\"\"%s\\spshell.exe\"\" action=allow\"", szBinDir);
  248. nRet = (int)ShellExecute(NULL, "open", "cmd.exe", szParam, NULL, SW_HIDE);
  249. sprintf_s(szParam, 1024, "/s /c \"netsh advfirewall firewall add rule name=\"\"SpHost\"\" dir=out program=\"\"%s\\sphost.exe\"\" action=allow\"", szBinDir);
  250. nRet = (int)ShellExecute(NULL, "open", "cmd.exe", szParam, NULL, SW_HIDE);
  251. sprintf_s(szParam, 1024, "/s /c \"netsh advfirewall firewall add rule name=\"\"SpGuardian\"\" dir=out program=\"\"%s\\guardian.exe\"\" action=allow\"", szBinDir);
  252. nRet = (int)ShellExecute(NULL, "open", "cmd.exe", szParam, NULL, SW_HIDE);
  253. sprintf_s(szParam, 1024, "/s /c \"netsh advfirewall firewall add rule name=\"\"cefclient\"\" dir=out program=\"\"%s\\Chromium\\cefclient.exe\"\" action=allow\"", szBinDir);
  254. nRet = (int)ShellExecute(NULL, "open", "cmd.exe", szParam, NULL, SW_HIDE);
  255. return nRet > 32;
  256. }
  257. int AddFireAddFirewallRulesThread(void* param)
  258. {
  259. LOG_FUNCTION();
  260. if (!sp_CheckAllRules())
  261. {
  262. DbgWithLink(LOG_LEVEL_WARN, LOG_TYPE_SYSTEM).setAPI(__FUNCTION__)("设置Windows防火墙策略失败!!!");
  263. Sleep(10000);
  264. return -1;
  265. }
  266. else
  267. DbgWithLink(LOG_LEVEL_INFO, LOG_TYPE_SYSTEM).setAPI(__FUNCTION__)("设置Windows防火墙策略成功!!!");
  268. return 0;
  269. }
  270. static void AddFirewallRulesEx()
  271. {
  272. CloseHandle(CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)& AddFireAddFirewallRulesThread, NULL, 0, NULL));
  273. }
  274. #endif //RVC_OS_WIN
  275. /*!
  276. * at Linux, judge whether current process runs as root privilege.
  277. * @return : True only if run as admin or root
  278. */
  279. static bool IsProcessRunAsAdmin()
  280. {
  281. BOOL bAdmin = FALSE;
  282. #ifdef RVC_OS_WIN
  283. SID_IDENTIFIER_AUTHORITY NtAuthority = SECURITY_NT_AUTHORITY;
  284. PSID AdministratorsGroup = NULL;
  285. DbgWithLink(LOG_LEVEL_INFO, LOG_TYPE_SYSTEM).setAPI(__FUNCTION__)("start AllocateAndInitializeSid");
  286. if (AllocateAndInitializeSid(
  287. &NtAuthority,
  288. 2,
  289. SECURITY_BUILTIN_DOMAIN_RID,
  290. DOMAIN_ALIAS_RID_ADMINS,
  291. 0, 0, 0, 0, 0, 0,
  292. &AdministratorsGroup))
  293. {
  294. DbgWithLink(LOG_LEVEL_INFO, LOG_TYPE_SYSTEM).setAPI(__FUNCTION__)("start CheckTokenMembership");
  295. CheckTokenMembership(NULL, AdministratorsGroup, &bAdmin);
  296. DbgWithLink(LOG_LEVEL_INFO, LOG_TYPE_SYSTEM).setAPI(__FUNCTION__)("start FreeSid");
  297. FreeSid(AdministratorsGroup);
  298. }
  299. #else
  300. if (geteuid() == 0) {
  301. bAdmin = TRUE;
  302. } else {
  303. DbgWithLink(LOG_LEVEL_WARN, LOG_TYPE_SYSTEM)("current process is not run as root privilege, euid:%u, uid:%d", geteuid(), getuid());
  304. }
  305. #endif //RVC_OS_WIN
  306. return bAdmin == TRUE;
  307. }
  308. static bool SpTerminateProcess(HANDLE hProc, DWORD dwProcID)
  309. {
  310. if (!TerminateProcess(hProc, -1))
  311. {
  312. #ifdef RVC_OS_WIN
  313. char szCmd[256];
  314. int nRet = 0;
  315. DbgWithLink(LOG_LEVEL_DEBUG, LOG_TYPE_SYSTEM).setAPI(__FUNCTION__)("terminate process %d fail: 0x%X, retry with taskkill", dwProcID, GetLastError());
  316. sprintf_s(szCmd, 256, "TASKKILL /PID %d /F", dwProcID);
  317. WinExec(szCmd, SW_HIDE);
  318. return nRet != -1;
  319. #else
  320. return false;
  321. #endif //RVC_OS_WIN
  322. }
  323. return true;
  324. }
  325. void DisplayUsage()
  326. {
  327. char szHelp[4097] = { '\0' };
  328. sprintf_s(szHelp, 4096, "\n"
  329. "Usage spshell [--entity {EntityName}][--guardian][--test][--benchmark][--kill][--debug][--ipc <pipe|tcp>][--restart][--noroot]\n"
  330. "--entity {EntityName} --启动特定的实体,选项后面输入实体名称\n"
  331. "--guardian --以后台进程的方式运行,暂未实现\n"
  332. "--test --以测试模式运行\n"
  333. "--autotest --自动化验证\n"
  334. "--debug --以调试模式运行,输出更为详细的日志\n"
  335. "--benchmark --以压力测试的模式启动\n"
  336. "--kill --直接杀死终端相关进程,比如 spshell, sphost 等\n"
  337. "--shutdown --彻底退出终端相关进程,不单独使用\n"
  338. "--systemoff --执行系统关机指令,关机前会彻底退出应用,不单独使用\n"
  339. "--reboot --执行系统重启指令,重启关机前会彻底退出应用,不单独使用\n"
  340. "--ipc <pipe|tcp> --指定实体间的通讯方式,使用管道或TCP,默认使用管道\n"
  341. "--noroot -- 允许以非管理员或Root权限方式启动\n"
  342. "--restart --重启当前应用\n"
  343. "--version --显示当前的版本\n"
  344. #ifdef WITH_DEBUG
  345. "--telnet {listern port} --激活远程调用功能\n"
  346. #endif
  347. );
  348. #ifdef RVC_OS_WIN
  349. MessageBoxA(NULL, szHelp, "Spshell Usage Tip", MB_OK);
  350. #else
  351. printf("%s\n", szHelp);
  352. #endif
  353. }
  354. static void DestroyArgs(sp_cfg_start_args_t* args)
  355. {
  356. if (args != NULL) {
  357. FREE(args->program);
  358. FREE(args->arguments);
  359. }
  360. FREE(args);
  361. }
  362. sp_cfg_start_args_t* DealWithArgs(int argc, char** argv)
  363. {
  364. int allocedEntitiyLen = 0;
  365. sp_cfg_start_args_t* args = MALLOC_T(sp_cfg_start_args_t);
  366. TOOLKIT_ASSERT(args);
  367. memset(args, 0, sizeof(sp_cfg_start_args_t));
  368. args->program = args->arguments = NULL;
  369. if (argc > 0) {
  370. args->program = CALLOC_T(strlen(argv[0]) + 1, char);
  371. if (!args->program) { exit(-1); }
  372. memset(args->program, '\0', sizeof(char) * (strlen(argv[0]) + 1));
  373. strcpy(args->program, argv[0]);
  374. printf("program: %s\n", args->program);
  375. std::string params;
  376. for (int i = 1, k=0; i < argc; ++i) {
  377. if(strcmp(argv[i], "--restart") == 0 || strcmp(argv[i], "-R") == 0 || strcmp(argv[i], "-Rwait")/*QT*/ == 0 || strcmp(argv[i], "wait") == 0)
  378. continue;
  379. if (k != 0) params += " ";
  380. params += argv[i];
  381. k++;
  382. }
  383. if (!params.empty()) {
  384. args->arguments = CALLOC_T(params.length() + 1, char);
  385. if (!args->arguments) { exit(-1); }
  386. memset(args->arguments, '\0', sizeof(char) * (params.length()));
  387. strcpy(args->arguments, params.c_str());
  388. }
  389. printf("param: %s\n", args->arguments);
  390. }
  391. args->gui = 1;
  392. args->root = 1;
  393. static struct option spshell_options[] = {
  394. {"entity", required_argument, 0, 'E' },
  395. {"guardian", no_argument, 0, 'G'},
  396. {"test", no_argument, 0, 'T'},
  397. {"autotest", no_argument, 0, 'C'},
  398. {"debug", no_argument, 0, 'D'},
  399. {"ipc", required_argument, 0, 'I'},
  400. {"shutdown", no_argument, 0, 'S'},
  401. {"kill", no_argument, 0, 'K'},
  402. {"benchmark", no_argument, 0, 'B'},
  403. {"gui", required_argument, 0, 'U'},
  404. #ifdef WITH_DEBUG
  405. {"telnet", required_argument, 0, 'N' },
  406. #endif
  407. {"help", no_argument, 0, 'H'},
  408. {"version", no_argument, 0, 'V'},
  409. {"noroot", no_argument, 0, 'O'},
  410. {"restart", optional_argument, 0, 'R'},
  411. {"systemoff", optional_argument, 0, 'Y'},
  412. {"reboot", optional_argument, 0, 'J'},
  413. {"env", required_argument, 0, 'A' },
  414. {0, 0, 0, 0}
  415. };
  416. int spshell_index = 0;
  417. int c;
  418. while ((c = getopt_long(argc, argv, "E:GTCDI:SKBU:HVOR::Y::J::A:?", spshell_options, &spshell_index)) != EOF) {
  419. switch (c) {
  420. case 'C':
  421. #ifndef DEVOPS_ON_PRD
  422. //非生产情况下,才支持测试模式
  423. args->auto_test = 1;
  424. #endif // DEVOPS_ON_PRD
  425. break;
  426. case 'E':
  427. {
  428. if (optarg != NULL) {
  429. const int len = strlen(optarg);
  430. if (args->start_entities == NULL || len + strlen(args->start_entities) + 2 /*;\0*/ >= allocedEntitiyLen) {
  431. if (args->start_entities == NULL) {
  432. TOOLKIT_ASSERT(allocedEntitiyLen == 0);
  433. allocedEntitiyLen = 128;
  434. args->start_entities = CALLOC_T(allocedEntitiyLen, char);
  435. if (NULL == args->start_entities) {
  436. DestroyArgs(args);
  437. exit(-1);
  438. }
  439. } else {
  440. TOOLKIT_ASSERT(allocedEntitiyLen != 0);
  441. const int newLen = allocedEntitiyLen + len + 32;
  442. char* newAlloc = CALLOC_T(newLen, char);
  443. if (NULL == newAlloc) {
  444. DestroyArgs(args);
  445. exit(-1);
  446. }
  447. memset(newAlloc, '\0', sizeof(char) * newLen);
  448. strcpy_s(newAlloc, newLen, args->start_entities);
  449. FREE(args->start_entities);
  450. args->start_entities = newAlloc;
  451. allocedEntitiyLen = newLen;
  452. }
  453. }
  454. strcat(args->start_entities, optarg);
  455. strcat(args->start_entities, ";");
  456. }
  457. }
  458. break;
  459. case 'G':
  460. args->guardian_mode = 1;
  461. break;
  462. case 'D':
  463. args->debug_mode = 1;
  464. break;
  465. case 'T':
  466. args->test_mode = (args->test_mode | 1);
  467. break;
  468. case 'B':
  469. args->test_mode = (args->test_mode | 2);
  470. break;
  471. case 'I':
  472. if (optarg) {
  473. if (strnicmp(optarg, "tcp", strlen("tcp")) == 0)
  474. args->ipc_type = 1;
  475. }
  476. break;
  477. #ifdef WITH_DEBUG
  478. case 'N':
  479. if (optarg) {
  480. int nPort = 0;
  481. if (0 < sscanf(optarg, "%d", &nPort))
  482. args->telnet_port = nPort;
  483. }
  484. break;
  485. #endif
  486. case 'K':
  487. {
  488. osutil_terminate_related_process(relate_processes_ex, array_size(relate_processes_ex), 1);
  489. DestroyArgs(args);
  490. exit(0);
  491. }
  492. break;
  493. case 'U':
  494. if (optarg) {
  495. if (strnicmp(optarg, "ON", strlen("ON")) == 0)
  496. args->gui = 1;
  497. else if(strnicmp(optarg, "OFF", strlen("OFF")) == 0)
  498. args->gui = 0;
  499. }
  500. break;
  501. case 'A':
  502. if (optarg) {
  503. if (strnicmp(optarg, "ST", strlen("ST")) == 0)
  504. args->test_mode = (args->test_mode | 4);
  505. else if (strnicmp(optarg, "UAT", strlen("UAT")) == 0)
  506. args->test_mode = (args->test_mode | 8);
  507. }
  508. break;
  509. case 'V':
  510. {
  511. DestroyArgs(args);
  512. exit(0);
  513. break;
  514. }
  515. break;
  516. case 'O':
  517. args->root = 0;
  518. break;
  519. case 'R':
  520. g_restartMode = RESTART_MODE_NORMAL;
  521. if (optarg && strcmp(optarg, "wait") == 0) {
  522. g_restartMode = RESTART_MODE_PRE;
  523. }
  524. break;
  525. case 'S':
  526. g_restartMode = RESTART_MODE_SHUTDOWN;
  527. break;
  528. case 'Y':
  529. g_restartMode = RESTART_MODE_POWEROFF;
  530. if (optarg && strnicmp(optarg, "now", strlen("now")) == 0) {
  531. g_immediately = true;
  532. }
  533. break;
  534. case 'J':
  535. g_restartMode = RESTART_MODE_REBOOT;
  536. if (optarg && strnicmp(optarg, "now", strlen("now")) == 0) {
  537. g_immediately = true;
  538. }
  539. break;
  540. case 'H':
  541. case '?':
  542. default:
  543. DisplayUsage();
  544. DestroyArgs(args);
  545. exit(0);
  546. break;
  547. }
  548. }
  549. if (optind < argc) {
  550. while (optind < argc) {
  551. //DbgWithLink(LOG_LEVEL_WARN, LOG_TYPE_SYSTEM)("\t%s", argv[optind++]);
  552. }
  553. }
  554. if (args && args->start_entities != 0) {
  555. args->start_entities[strlen(args->start_entities) - 1] = '\0';
  556. }
  557. return args;
  558. }
  559. void normal_signal_handle(int num)
  560. {
  561. DbgWithLink(LOG_LEVEL_INFO, LOG_TYPE_SYSTEM)("receive signal %d", num);
  562. signal(num, SIG_DFL);
  563. raise(num);
  564. }
  565. static bool NeedToRestartFramework()
  566. {
  567. //Shutdown 表明退掉框架不重启
  568. return !((g_restartMode == RESTART_MODE_SHUTDOWN
  569. || g_restartMode == RESTART_MODE_POWEROFF
  570. || g_restartMode == RESTART_MODE_REBOOT));
  571. }
  572. #if defined(_MSC_VER)
  573. ///*TODO(80374374@3/23/2023): osutil_detect_unique_app 替代 */
  574. static bool DetectDuplicateInstance(char** pNames, int nNum)
  575. {
  576. DWORD dwCurProcID = GetCurrentProcessId();
  577. HANDLE hSnapshot = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
  578. std::shared_ptr<void> delHandleFun((void*)0, [&](void*) {
  579. if (NULL != hSnapshot)
  580. CloseHandle(hSnapshot);
  581. });
  582. if (hSnapshot) {
  583. PROCESSENTRY32 pe = {};
  584. pe.dwSize = sizeof(pe);
  585. if (Process32First(hSnapshot, &pe)) {
  586. do {
  587. for (int i = 0; i < nNum; i++) {
  588. if (stricmp(&pe.szExeFile[0], pNames[i]) == 0 && pe.th32ProcessID != dwCurProcID) {
  589. HANDLE hProc = OpenProcess(PROCESS_ALL_ACCESS, FALSE, pe.th32ProcessID);
  590. if (hProc == NULL) {
  591. DbgWithLink(LOG_LEVEL_ERROR, LOG_TYPE_SYSTEM).setAPI(__FUNCTION__)("find duplicated process: %s, id: %d", pNames[i], pe.th32ProcessID);
  592. return false;
  593. }
  594. if (!SpTerminateProcess(hProc, pe.th32ProcessID)) {
  595. DbgWithLink(LOG_LEVEL_ERROR, LOG_TYPE_SYSTEM).setAPI(__FUNCTION__)("terminate duplicated process %s fail, id: %d, error: %d",
  596. pNames[i], pe.th32ProcessID, GetLastError());
  597. return false;
  598. }
  599. DbgWithLink(LOG_LEVEL_INFO, LOG_TYPE_SYSTEM).setAPI(__FUNCTION__)("terminate duplicated process: %s, id: %d", pNames[i], pe.th32ProcessID);
  600. }
  601. }
  602. } while (Process32Next(hSnapshot, &pe));
  603. }
  604. } else
  605. DbgWithLink(LOG_LEVEL_INFO, LOG_TYPE_SYSTEM).setAPI(__FUNCTION__)("DetectDuplicateInstance can not enter Process32First!");
  606. return true;
  607. }
  608. #endif //_MSC_VER
  609. void SPBASE_API __stdcall setCurEntityIdx(int idx);
  610. std::string generateCenterSettingPath()
  611. {
  612. char pathbuf[1024] = "";
  613. int pathlen = ::GetModuleFileNameA(NULL, pathbuf, 1024);//获得GuiConsole路径
  614. // 替换掉单杠
  615. int times = 0;
  616. while (pathlen > 0) {
  617. if (pathbuf[pathlen--] == SPLIT_SLASH)
  618. times++;
  619. if (2 == times)
  620. break;
  621. }
  622. pathbuf[++pathlen] = '\0';
  623. std::string dstPath = pathbuf;
  624. dstPath.append(SPLIT_SLASH_STR "cfg" SPLIT_SLASH_STR "CenterSetting.ini");
  625. return dstPath;
  626. }
  627. int main(int argc, char** argv)
  628. {
  629. //SendTestLog_loki("spshell", "log", "startup");
  630. sp_cfg_start_args_t* args = DealWithArgs(argc, argv);
  631. #if defined(RVC_OS_LINUX)
  632. if (args->debug_mode) {
  633. SP::Perf::LeakDetector leakInstance;
  634. WLog_initRVC("SpShell");
  635. }
  636. #else
  637. //WLog_initRVC("SpShell");
  638. _CrtSetDebugFillThreshold(0);
  639. #endif //RVC_OS_LINUX
  640. #ifdef RVC_SAVEFILE
  641. bool saveFile = true;
  642. #else
  643. char tmp[MAX_LEN] = "";
  644. bool saveFile = false;
  645. if (Error_Succeed == sp_tryReadFromCenterSetting("Common", "SaveFile", tmp, MAX_LEN) && 0 == CSimpleStringA(tmp).Compare("1"))
  646. saveFile = true;
  647. #endif // RVC_SAVEFILE
  648. if (saveFile)
  649. sp_dbg_init("SpShell", 1);
  650. else
  651. sp_dbg_init("SpShell", 0);
  652. EntityResource::setSaveFile(saveFile);
  653. #if defined(RVC_OS_LINUX)
  654. sp_dbg_set_level(XLOG_LEVEL_DEBUG);
  655. #endif //RVC_OS_LINUX
  656. if (argc > 1) {
  657. std::string args_str;
  658. char cmdline[1024] = { '\0' };
  659. for (int i = 0; i < argc; ++i) {
  660. sprintf_s(cmdline, 1024, "%s", argv[i]);
  661. if (i != 0) args_str += " ";
  662. args_str += cmdline;
  663. }
  664. DbgWithLink(LOG_LEVEL_INFO, LOG_TYPE_SYSTEM).setAPI(__FUNCTION__)("prefix: %s", args_str.c_str());
  665. }
  666. #if defined(_MSC_VER)
  667. //TODO: CrossPlaform 等良瑜确认,应该不再涉及本地集中配置了 [Gifur@2025820]
  668. auto centersettingPath = generateCenterSettingPath();
  669. load_debugLevelInCentersetting(centersettingPath.c_str());
  670. load_specialRunInfoInCentersetting(centersettingPath.c_str());
  671. auto setAffinity = [](long ulCpuMask) {
  672. HANDLE hCurrentProc;
  673. DWORD_PTR dwpProcAffinityMask = ulCpuMask;
  674. // Obtain a usable handle of the current process
  675. hCurrentProc = GetCurrentProcess();
  676. // Get the old affinity mask
  677. SetProcessAffinityMask(hCurrentProc, dwpProcAffinityMask);
  678. SetProcessAffinityUpdateMode(hCurrentProc, PROCESS_AFFINITY_ENABLE_AUTO_UPDATE);
  679. CloseHandle(hCurrentProc);
  680. };
  681. setAffinity(1);
  682. char* arrProcName[] = { "SpShell.exe", "SpHost.exe", "SpHost_re.exe" };
  683. //实际可以加快这个过程,如果进程过多会比较慢
  684. //后续可考虑用mutex进行控制
  685. if (!DetectDuplicateInstance(&arrProcName[0], sizeof(arrProcName) / sizeof(arrProcName[0]))) {
  686. DbgWithLink(LOG_LEVEL_FATAL, LOG_TYPE_SYSTEM).setAPI(__FUNCTION__).setResultMsg(RTAERR_SPSHELL_REPEATPROCESS)("检测到重复spshell/sphost进程,系统启动失败!!!");
  687. Sleep(10000);
  688. return -200;
  689. }
  690. #else
  691. if (!!g_restartMode) {
  692. /** 因为没有明显的提示,等的时间(次数)不宜过长 [Gifur@202475]*/
  693. /*
  694. 阶段一:框架收到退出事件后会调用实体的stop接口,具体实现在app.cpp::stop_all_stated_entity
  695. 阶段二:框架会温和杀死实体相关进程
  696. 阶段三:框架会强制杀死实体相关进程
  697. */
  698. const DWORD eachPreTimeout = 500;//等待进程自行退出的每次等待间隔时间
  699. const int maxPreTimies = 6;//等待进程自行退出的最大等待次数
  700. const DWORD eachTimeout = 2000;//杀死进程后的每次等待间隔时间
  701. const int maxTimes = 15;//杀死进程后的最大等待次数
  702. const int gentleKillThresholdTimes = 10; //允许温和杀死实体进程的次数
  703. const DWORD skipInterval = 5;
  704. int currTimes = 0, preTimes = 0;
  705. bool needWait = (g_restartMode > RESTART_MODE_NORMAL && !g_immediately); //Rwait 框架触发的重启
  706. const bool needlessRestart = !NeedToRestartFramework();
  707. int aliveCount = 0, lastAliveCount(1000);
  708. char** relates = relate_processes;
  709. int reletes_cnt = relate_processes_count;
  710. if (needWait) {
  711. DbgWithLink(LOG_LEVEL_DEBUG, LOG_TYPE_SYSTEM)("等待应用进程退出...");
  712. }
  713. if (needlessRestart) {
  714. DbgWithLink(LOG_LEVEL_INFO, LOG_TYPE_SYSTEM)("to shutdown guardian...");
  715. char* tmp_processes[] = { guardian_execute_name };
  716. osutil_terminate_related_process(tmp_processes, array_size(tmp_processes), 1);
  717. relates = relate_processes_ex;
  718. reletes_cnt = relate_processes_ex_count;
  719. }
  720. bool switch_flag = false;
  721. while (switch_flag || !osutil_detect_unique_app(relates, reletes_cnt, &aliveCount, NULL)) {
  722. if (!needWait && currTimes++ >= maxTimes) {
  723. DbgWithLink(LOG_LEVEL_FATAL, LOG_TYPE_SYSTEM)("detect ex-spshell or sphost process, abort cur boot !!!");
  724. DbgWithLink(LOG_LEVEL_INFO, LOG_TYPE_SYSTEM)("等待应用进程退出超时,请尝试重启机器!");
  725. sp_dbg_term();
  726. DestroyArgs(args);
  727. return -200;
  728. } else {
  729. if (needWait) {
  730. Sleep(eachPreTimeout);
  731. if (preTimes++ >= maxPreTimies && (aliveCount >= lastAliveCount)) {
  732. needWait = false;
  733. DbgWithLink(LOG_LEVEL_DEBUG, LOG_TYPE_SYSTEM)("set need wait flag false");
  734. }
  735. DbgWithLink(LOG_LEVEL_DEBUG, LOG_TYPE_SYSTEM)("wait... last active process count:%d, curr process count: %d, ppid: %d", lastAliveCount, aliveCount, GetParentProcessID());
  736. lastAliveCount = aliveCount;
  737. } else {
  738. const int force_flag = gentleKillThresholdTimes < currTimes ? 1 : 0;
  739. DbgWithLink(LOG_LEVEL_WARN, LOG_TYPE_SYSTEM)("detect ex-spshell or sphost process %d, %d, %d terminate all !!!", preTimes, currTimes, force_flag);
  740. osutil_terminate_related_process(relates, reletes_cnt, force_flag);
  741. Sleep(eachTimeout);
  742. }
  743. const DWORD consumedTime = (currTimes * eachTimeout) / 1000 + (eachPreTimeout * preTimes) / 1000;
  744. if (consumedTime > 0) {
  745. DbgWithLink(LOG_LEVEL_DEBUG, LOG_TYPE_SYSTEM)("等待应用进程退出,已等待 %d 秒...", consumedTime);
  746. }
  747. }
  748. //aliveCount = 0; //important!!!
  749. switch_flag = (((preTimes + currTimes) % skipInterval) != 0);
  750. if (!switch_flag) {
  751. aliveCount = 0;
  752. DbgWithLink(LOG_LEVEL_INFO, LOG_TYPE_SYSTEM)("will enter osutil_detect_unique_app");
  753. }
  754. }
  755. DbgWithLink(LOG_LEVEL_INFO, LOG_TYPE_SYSTEM)("finish detecting unique app.");
  756. if (needlessRestart) {
  757. const DWORD sleepMillsecs = 2000;
  758. DbgWithLink(LOG_LEVEL_INFO, LOG_TYPE_SYSTEM)("restart mode: %d", g_restartMode);
  759. if (g_restartMode == RESTART_MODE_SHUTDOWN) {
  760. DbgWithLink(LOG_LEVEL_DEBUG, LOG_TYPE_SYSTEM)("应用进程已完全清理,退出当前窗口...");
  761. } else if (g_restartMode == RESTART_MODE_POWEROFF) {
  762. DbgWithLink(LOG_LEVEL_DEBUG, LOG_TYPE_SYSTEM)("应用进程已完全清理,准备关机...");
  763. osutil_shutdown_system();
  764. DbgWithLink(LOG_LEVEL_DEBUG, LOG_TYPE_SYSTEM)("应用进程已完全清理,正在关机...");
  765. } else if (g_restartMode == RESTART_MODE_REBOOT) {
  766. DbgWithLink(LOG_LEVEL_DEBUG, LOG_TYPE_SYSTEM)("应用进程已完全清理,准备关机重启...");
  767. osutil_restart_system();
  768. DbgWithLink(LOG_LEVEL_DEBUG, LOG_TYPE_SYSTEM)("应用进程已完全清理,正在关机并重启...");
  769. }
  770. Sleep(sleepMillsecs);
  771. sp_dbg_term();
  772. DestroyArgs(args);
  773. return 0;
  774. }
  775. } else if (!osutil_detect_unique_app(relate_processes, array_size(relate_processes), NULL, NULL)) {
  776. do {
  777. bool clearTotal = false;
  778. int innerClearEnhance = 0;
  779. do
  780. {
  781. osutil_terminate_related_process(relate_processes, array_size(relate_processes), innerClearEnhance > 8 ? 1 : 0);
  782. Sleep(3000);
  783. int count = MAX_ALIVE_PROCESS_COUNT;
  784. alive_process_info processes[MAX_ALIVE_PROCESS_COUNT];
  785. memset(processes, 0, sizeof(processes));
  786. if (osutil_detect_unique_app(relate_processes, array_size(relate_processes), &count, processes)) {
  787. clearTotal = true;
  788. break;
  789. }
  790. } while (innerClearEnhance++ < 10);
  791. if (clearTotal) {
  792. break;
  793. }
  794. DbgWithLink(LOG_LEVEL_WARN, LOG_TYPE_SYSTEM)("clear ex-spshell/sphost process failed!");
  795. sp_dbg_term();
  796. DestroyArgs(args);
  797. return -200;
  798. } while (false);
  799. }
  800. #endif //_MSC_VER
  801. sp_runtask_loadLogLevel();
  802. sp_tryquickStartCef();
  803. create_log_producer_default("SpShell", 0);
  804. DbgWithLink(LOG_LEVEL_INFO, LOG_TYPE_SYSTEM).setAPI(__FUNCTION__)("===================SpShell start=====================");
  805. DbgWithLink(LOG_LEVEL_INFO, LOG_TYPE_SYSTEM).setAPI(__FUNCTION__)("process id: %d, saveFile:%d", GetCurrentProcessId(), saveFile);
  806. if (argc > 1) {
  807. std::string args_str;
  808. char cmdline[1024] = { '\0' };
  809. for (int i = 0; i < argc; ++i) {
  810. sprintf_s(cmdline, 1024, "%s", argv[i]);
  811. if (i != 0) args_str += " ";
  812. args_str += cmdline;
  813. }
  814. DbgWithLink(LOG_LEVEL_INFO, LOG_TYPE_SYSTEM).setAPI(__FUNCTION__)(args_str.c_str());
  815. SP_TRACE(args_str.c_str());
  816. }
  817. if (!IsProcessRunAsAdmin()) {
  818. if (args->root) {
  819. DbgWithLink(LOG_LEVEL_FATAL, LOG_TYPE_SYSTEM)("current process need run with administrator or root privilege !!!");
  820. DbgWithLink(LOG_LEVEL_FATAL, LOG_TYPE_SYSTEM).setAPI(__FUNCTION__).setResultMsg(RTAERR_SPSHELL_NOPRIVILEGE)("需要以管理员权限运行!!!");
  821. Sleep(10000);
  822. sp_dbg_term();
  823. DestroyArgs(args);
  824. return -201;
  825. } else {
  826. DbgWithLink(LOG_LEVEL_INFO, LOG_TYPE_SYSTEM).setAPI(__FUNCTION__)("current process requires normal privilege.");
  827. }
  828. } else {
  829. DbgWithLink(LOG_LEVEL_DEBUG, LOG_TYPE_SYSTEM).setAPI(__FUNCTION__)("current process has been run with administrator or root privilege.");
  830. args->root = (char)1;
  831. #if defined(_MSC_VER)
  832. SYSTEM_INFO SystemInfo;
  833. GetSystemInfo(&SystemInfo);
  834. DbgWithLink(LOG_LEVEL_INFO, LOG_TYPE_SYSTEM).setAPI(__FUNCTION__)("当前以管理员权限运行, curProcessId:%d, curVersion:%s ,dwNumberOfProcessors=%u, dwActiveProcessorMask=%u, wProcessorLevel=%u, wProcessorArchitecture=%u, dwPageSize=%u",
  835. GetCurrentProcessId(), STRFILEVER, SystemInfo.dwNumberOfProcessors, SystemInfo.dwActiveProcessorMask, SystemInfo.wProcessorLevel,
  836. SystemInfo.wProcessorArchitecture, SystemInfo.dwPageSize);
  837. #endif //_MSC_VER
  838. }
  839. #ifdef RVC_OS_WIN
  840. DbgWithLink(LOG_LEVEL_DEBUG, LOG_TYPE_SYSTEM)("Config firewall policies......");
  841. // 设置防火墙注册表配置
  842. AddFirewallRulesEx();
  843. setlocale(LC_ALL, "chs");
  844. #else
  845. if (NULL == setlocale(LC_ALL, "zh_CN.UTF-8")) {
  846. //zh_CN.UTF-8 zh_CN.GBK
  847. DbgWithLink(LOG_LEVEL_ERROR, LOG_TYPE_SYSTEM)("setlocale failed: %s", strerror(errno));
  848. }
  849. #endif //RVC_OS_WIN
  850. ResetEnvPath();
  851. #ifdef RVC_OS_WIN
  852. DbgWithLink(LOG_LEVEL_DEBUG, LOG_TYPE_SYSTEM)("Config working set......");
  853. SetWorkingSet();//获取设置内存使用率,4G
  854. #endif //RVC_OS_WIN
  855. DbgWithLink(LOG_LEVEL_INFO, LOG_TYPE_SYSTEM).setAPI(__FUNCTION__)("basic config success");
  856. #ifdef RVC_OS_WIN
  857. // 检测是否Win8及64位
  858. OSVERSIONINFO ver = {};
  859. ver.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);
  860. GetVersionEx(&ver);
  861. bool bWin8 = (ver.dwMajorVersion >= 7 || (ver.dwMajorVersion == 6 && ver.dwMinorVersion >= 2)); //version over 7 or over 6.2
  862. SYSTEM_INFO sysInfo = {};
  863. GetNativeSystemInfo(&sysInfo);
  864. bool bX64 = (sysInfo.wProcessorArchitecture == PROCESSOR_ARCHITECTURE_AMD64);
  865. DbgWithLink(LOG_LEVEL_INFO, LOG_TYPE_SYSTEM).setAPI(__FUNCTION__)("OS version: %s %d.%d.%d , SetErrorMode %s", bX64 ? "windows 64" : "windows 32", ver.dwMajorVersion, ver.dwMinorVersion, ver.dwBuildNumber,
  866. 0 == SetErrorMode(SEM_FAILCRITICALERRORS | SEM_NOGPFAULTERRORBOX | SEM_NOOPENFILEERRORBOX) ? "success" : "failed");
  867. SetUnhandledExceptionFilter(&SuppressError);
  868. #endif //RVC_OS_WIN
  869. auto msg_lamda_func = [&](const char* msg, bool ctritial)->void {
  870. };
  871. //////////////////////////////////////////////////////////////////////////
  872. #if defined(_MSC_VER)
  873. auto rc = app_init(args);
  874. int result = rc.first;
  875. #else
  876. int result = app_init(args, msg_lamda_func);
  877. #endif //_MSC_VER
  878. //////////////////////////////////////////////////////////////////////////
  879. if (result == 0)
  880. {
  881. sp_trace_term();
  882. DbgWithLink(LOG_LEVEL_DEBUG, LOG_TYPE_SYSTEM)("run circle loop in main thread!!");
  883. result = app_run();
  884. app_term();
  885. }
  886. else
  887. {
  888. uint32_t waitIntervals = 10000;
  889. if (sp_trace_exist()) {
  890. char* last_err = NULL;
  891. sp_trace_retrieve(&last_err, NULL);
  892. if (last_err) {
  893. DbgWithLink(LOG_LEVEL_DEBUG, LOG_TYPE_SYSTEM)("to show last error dialog...");
  894. DbgWithLink(LOG_LEVEL_ERROR, LOG_TYPE_SYSTEM)("应用启动失败:%s", last_err);
  895. waitIntervals = 1;
  896. FREE(last_err);
  897. DbgWithLink(LOG_LEVEL_DEBUG, LOG_TYPE_SYSTEM)("to show last error dialog done!");
  898. }
  899. sp_trace_term();
  900. }
  901. #if defined(_MSC_VER)
  902. DbgWithLink(LOG_LEVEL_ERROR, LOG_TYPE_SYSTEM).setAPI(__FUNCTION__)("======================================================");
  903. DbgWithLink(LOG_LEVEL_ERROR, LOG_TYPE_SYSTEM).setAPI(__FUNCTION__).setResultMsg(RTAERR_SPSHELL_APPINITERR)(rc.second.GetData());
  904. DbgWithLink(LOG_LEVEL_ERROR, LOG_TYPE_SYSTEM).setAPI(__FUNCTION__)("!!!!!! 启动失败,请检查dbg\\spshell日志排除故障 !!!!!!");
  905. DbgWithLink(LOG_LEVEL_ERROR, LOG_TYPE_SYSTEM).setAPI(__FUNCTION__)("======================================================");
  906. #else
  907. DbgWithLink(LOG_LEVEL_ERROR, LOG_TYPE_SYSTEM).setAPI(__FUNCTION__)("======================================================");
  908. DbgWithLink(LOG_LEVEL_ERROR, LOG_TYPE_SYSTEM).setAPI(__FUNCTION__).setResultMsg(RTAERR_SPSHELL_APPINITERR)("!!!!!! Startup failed, get more detail information from dbg/spshell !!!!!!");
  909. DbgWithLink(LOG_LEVEL_ERROR, LOG_TYPE_SYSTEM).setAPI(__FUNCTION__)("======================================================");
  910. #endif //_MSC_VER
  911. app_upload_last_log();
  912. Sleep(waitIntervals);
  913. }
  914. #ifdef RVC_OS_WIN
  915. if (bWin8 && !bX64) {
  916. EnableCharmbar();
  917. }
  918. #endif //RVC_OS_WIN
  919. sp_dbg_term();
  920. DestroyArgs(args);
  921. return result;
  922. }
  923. #ifdef RVC_OS_WIN
  924. int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nShowCmd)
  925. {
  926. return main(__argc, __argv);
  927. }
  928. #endif //RVC_OS_WIN