spshell.cpp 41 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311
  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. #pragma comment(lib, "dbghelp.lib")
  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. #ifdef WITH_QT
  50. #include "PollCenter.h"
  51. #include <QMessageBox>
  52. //#pragma execution_character_set("utf-8")
  53. #endif
  54. #ifndef RVC_OS_WIN
  55. static int GetParentProcessID()
  56. {
  57. #if 0
  58. return getppid();
  59. #else
  60. return (int)syscall(SYS_getppid);
  61. #endif
  62. }
  63. #endif //NOT _WIN32
  64. #ifdef RVC_OS_WIN
  65. static char spshell_execute_name[] = "SpShell.exe";
  66. static char sphost_execute_name[] = "SpHost.exe";
  67. static char guardian_execute_name[] = "Guardian.exe";
  68. static char cefclient_execute_name[] = "cefclient.exe";
  69. #else
  70. static char spshell_execute_name[] = "spshell";
  71. static char sphost_execute_name[] = "sphost";
  72. static char guardian_execute_name[] = "guardian";
  73. static char cefclient_execute_name[] = "cefclient";
  74. #endif //_WIN32
  75. #define RESTART_MODE_DEFAULT 0
  76. #define RESTART_MODE_NORMAL 1
  77. #define RESTART_MODE_PRE 2
  78. #define RESTART_MODE_SHUTDOWN 3
  79. #define RESTART_MODE_POWEROFF 4
  80. #define RESTART_MODE_REBOOT 5
  81. #define DRIVER_NAME "HelloDDK"
  82. #define DRIVER_PATH "InterceptDll.sys"
  83. #define SET_EVENT \
  84. CTL_CODE(FILE_DEVICE_UNKNOWN, 0x800, METHOD_BUFFERED, FILE_ANY_ACCESS)
  85. #define GET_SHARE_ADD \
  86. CTL_CODE(FILE_DEVICE_UNKNOWN, 0x801, METHOD_BUFFERED, FILE_ANY_ACCESS)
  87. HANDLE g_hEvent = NULL;
  88. bool g_bMD5Exist = false;
  89. bool g_bWow64 = false;
  90. CSimpleStringA g_strMD5ListPath;
  91. static int g_restartMode = RESTART_MODE_DEFAULT;
  92. static bool g_immediately = false;
  93. char* relate_processes[] = { spshell_execute_name, sphost_execute_name, cefclient_execute_name };
  94. const int relate_processes_count = 3;
  95. char* relate_processes_ex[] = { spshell_execute_name, sphost_execute_name, guardian_execute_name, cefclient_execute_name };
  96. const int relate_processes_ex_count = 4;
  97. const int MAX_LEN = 256;
  98. //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
  99. static bool IsSpPathType(const CSimpleStringA& value)
  100. {
  101. #if defined(RVC_OS_WIN)
  102. const int leastLength = strlen("C:\\version\\1.0.0.0\\");
  103. #else
  104. const int leastLength = strlen("Run/version/1.0.0.0/");
  105. #endif //RVC_OS_WIN
  106. CSimpleStringA path(value.GetData());
  107. if (path.IsNullOrEmpty() || path.GetLength() < leastLength) return false;
  108. const int sionPos = path.IndexOf("version");
  109. const int verPos = sionPos + strlen("version" SPLIT_SLASH_STR);
  110. if (sionPos < 0) return false;
  111. int suffixPos = -1, i;
  112. int dotCnt = 0;
  113. bool lastIsNum = false;
  114. for (i = verPos; i < path.GetLength() && (path[i] >= '0' && path[i] <= '9' || path[i] == '.'); ++i) {
  115. lastIsNum = !(path[i] == '.');
  116. if (!lastIsNum) dotCnt++;
  117. }
  118. if (i >= path.GetLength() || dotCnt != 3 || !lastIsNum)
  119. return false;
  120. //if(path[i] == '\\' || path[i] == '//')
  121. return true;
  122. }
  123. static CSimpleStringA CutSpPathFromPathValue(const char* value, const char* prefix)
  124. {
  125. CSimpleStringA path(value);
  126. CSimpleStringA result(true);
  127. CAutoArray<CSimpleStringA> values = path.Split(ENV_SEP_CHAR);
  128. if (values.GetCount() <= 0) {
  129. return path;
  130. }
  131. for (int i = 0; i < values.GetCount(); ++i) {
  132. if (values[i].IsStartWith(prefix) || !IsSpPathType(values[i])) {
  133. if (!result.IsNullOrEmpty()) result += ENV_SEP_STR;
  134. result += values[i];
  135. }
  136. }
  137. if (!result.IsNullOrEmpty() && path[path.GetLength() - 1] == ENV_SEP_CHAR) {
  138. result += ENV_SEP_STR;
  139. }
  140. return result;
  141. }
  142. static void SetEnvPath()
  143. {
  144. char path[MAX_PATH];
  145. char *buf;
  146. DWORD size;
  147. const char *var = "PATH";
  148. // set current path
  149. GetModuleFileNameA(NULL, path, MAX_PATH);
  150. *strrchr(path, SPLIT_SLASH) = 0;
  151. *strrchr(path, SPLIT_SLASH) = 0;
  152. SetCurrentDirectoryA(path);
  153. size = GetEnvironmentVariableA(var, NULL, 0);
  154. buf = (char*)malloc(size+MAX_PATH*3);
  155. size = GetEnvironmentVariableA(var, buf, size);
  156. CSimpleStringA newValue = CutSpPathFromPathValue(buf, path);
  157. if (newValue.GetLength() < size) {
  158. printf("before: %s,%d\n", buf, size);
  159. strcpy(buf, newValue.GetData());
  160. memset(buf + newValue.GetLength(), '\0', sizeof(char) * (size + MAX_PATH * 3 - newValue.GetLength()));
  161. size = newValue.GetLength();
  162. printf("after: %s,%d\n", buf, size);
  163. }
  164. strcpy(buf+size, ENV_SEP_STR);
  165. // append dep sub dir to %PATH%
  166. strcat(path, SPLIT_SLASH_STR "dep");
  167. strcat(buf+size, path);
  168. *strrchr(path, SPLIT_SLASH) = 0;
  169. strcat(path, SPLIT_SLASH_STR "bin");
  170. strcat(buf+size, ENV_SEP_STR);
  171. strcat(buf+size, path);
  172. //*strrchr(path, SPLIT_SLASH) = 0;
  173. //strcat(path, SPLIT_SLASH_STR "dev");
  174. //strcat(buf+size, ENV_SEP_STR);
  175. //strcat(buf+size, path);
  176. //*strrchr(path, SPLIT_SLASH) = 0;
  177. //strcat(path, SPLIT_SLASH_STR "imdep");
  178. //strcat(buf + size, ENV_SEP_STR);
  179. //strcat(buf + size, path);
  180. SetEnvironmentVariableA(var, buf);
  181. free(buf);
  182. SetEnvironmentVariableA("ModuleName", "SpShell");
  183. }
  184. #ifdef RVC_OS_WIN
  185. static void SetWorkingSet()
  186. {
  187. SIZE_T dwMinSize, dwMaxSize;
  188. HANDLE hCurrProcess = GetCurrentProcess();
  189. GetProcessWorkingSetSize(hCurrProcess, &dwMinSize, &dwMaxSize);
  190. if (dwMaxSize < (2 << 20))
  191. dwMaxSize = 2 << 20;
  192. SetProcessWorkingSetSize(hCurrProcess, dwMinSize, dwMaxSize);
  193. }
  194. static LONG WINAPI SuppressError(struct _EXCEPTION_POINTERS* ExceptionInfo)
  195. {
  196. static bool hasCall = false;
  197. if (hasCall)
  198. ExitProcess(Error_Exception);
  199. else
  200. hasCall = true;
  201. char tmp[MAX_PATH];
  202. HANDLE hDumpFile;
  203. std::string dmpFileStr;
  204. GetModuleFileNameA(NULL, tmp, MAX_PATH);
  205. *strrchr(tmp, SPLIT_SLASH) = 0;
  206. *strrchr(tmp, SPLIT_SLASH) = 0;
  207. *strrchr(tmp, SPLIT_SLASH) = 0;
  208. *strrchr(tmp, SPLIT_SLASH) = 0;
  209. *strrchr(tmp, SPLIT_SLASH) = 0;
  210. wsprintfA(tmp, "%s\\rvc\\dmp\\expt.spshell.%d.%s.dmp", tmp, GetCurrentProcessId(), STRFILEVER);
  211. hDumpFile = CreateFileA( tmp, GENERIC_READ | GENERIC_WRITE,
  212. 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL );
  213. if( ( hDumpFile != NULL ) && ( hDumpFile != INVALID_HANDLE_VALUE ) )
  214. {
  215. MINIDUMP_EXCEPTION_INFORMATION mdei;
  216. MINIDUMP_TYPE mdt;
  217. mdei.ThreadId = GetCurrentThreadId();
  218. mdei.ExceptionPointers = ExceptionInfo;
  219. mdei.ClientPointers = FALSE;
  220. mdt = MiniDumpNormal;
  221. MiniDumpWriteDump(GetCurrentProcess(), GetCurrentProcessId(),
  222. hDumpFile, mdt, (ExceptionInfo != 0) ? &mdei : 0, 0, 0 );
  223. CloseHandle( hDumpFile );
  224. }
  225. char szCmd[256];
  226. sprintf_s(szCmd, 256, "TASKKILL /f /im sphost.exe");
  227. system(szCmd);
  228. sprintf_s(szCmd, 256, "TASKKILL /f /im sphost_re.exe");
  229. system(szCmd);
  230. DbgWithLink(LOG_LEVEL_INFO, LOG_TYPE_SYSTEM).setAPI(__FUNCTION__).setLogCode(ERR_SPSHELL_EXCETION).setResultCode(RTAERR_SPSHELL_EXCEPTION)("spshell exit exception, saveDmp, %s, detail:%d:%s"
  231. , tmp, dmpFileStr.length() ,dmpFileStr.c_str());
  232. ExitProcess(Error_Exception); // exit process to suppress reporting exception
  233. return EXCEPTION_EXECUTE_HANDLER;
  234. }
  235. static void DisableSetUnhandledExceptionFilter()
  236. {
  237. void* addr = (void*)GetProcAddress(LoadLibrary("kernel32.dll"), "SetUnhandledExceptionFilter");
  238. if (addr) {
  239. DWORD dwOldFlag, dwTempFlag;
  240. unsigned char code[] = {0x33, 0xC0, 0xC2, 0x04, 0x00}; // xor eax,eax; ret 4;
  241. //VirtualProtect(addr, sizeof(code), PAGE_READWRITE, &dwOldFlag);
  242. VirtualProtectEx(GetCurrentProcess(), addr, sizeof(code), PAGE_EXECUTE_READWRITE, &dwOldFlag);
  243. WriteProcessMemory(GetCurrentProcess(), addr, code, sizeof(code), NULL);
  244. VirtualProtect(addr, sizeof(code), dwOldFlag, &dwTempFlag);
  245. }
  246. }
  247. __declspec(dllimport) bool DisableCharmbar();
  248. __declspec(dllimport) bool EnableCharmbar();
  249. static HANDLE create_process(const char *app)
  250. {
  251. //BOOL bRet;
  252. STARTUPINFOA si = { sizeof(STARTUPINFOA) };
  253. si.wShowWindow = SW_SHOWMAXIMIZED;
  254. si.dwFlags = STARTF_USESHOWWINDOW;
  255. PROCESS_INFORMATION pi;
  256. DWORD dwSessionId;
  257. HANDLE hUserTokenDup, hThisToken;
  258. HANDLE hProcess = NULL;
  259. dwSessionId = WTSGetActiveConsoleSessionId();
  260. if (OpenProcessToken(GetCurrentProcess(), TOKEN_ALL_ACCESS, &hThisToken)) {
  261. LUID luid;
  262. TOKEN_PRIVILEGES tp;
  263. LPVOID pEnv = NULL;
  264. LookupPrivilegeValueA(NULL, SE_DEBUG_NAME, &luid);
  265. tp.PrivilegeCount = 1;
  266. tp.Privileges[0].Luid = luid;
  267. tp.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;
  268. DuplicateTokenEx(hThisToken, MAXIMUM_ALLOWED, NULL,
  269. SecurityIdentification, TokenPrimary, &hUserTokenDup);
  270. SetTokenInformation(hUserTokenDup,
  271. TokenSessionId, (void*)&dwSessionId, sizeof(DWORD));
  272. AdjustTokenPrivileges(hUserTokenDup, FALSE, &tp, sizeof(TOKEN_PRIVILEGES),
  273. (PTOKEN_PRIVILEGES)NULL, NULL);
  274. //CreateEnvironmentBlock(&pEnv,hUserTokenDup,TRUE);
  275. if (CreateProcessAsUserA(hUserTokenDup, NULL,
  276. (LPSTR)app, // "D:\\Source\\RVC\\RVCProject\\Release\\version\\1.0.0.1\\bin\\MetroWatcher64.exe 732",
  277. NULL, NULL, FALSE, 0, pEnv, NULL, &si, &pi))
  278. {
  279. CloseHandle(pi.hThread);
  280. hProcess = pi.hProcess;
  281. }
  282. else
  283. DbgWithLink(LOG_LEVEL_WARN, LOG_TYPE_SYSTEM).setAPI(__FUNCTION__)("create process failed! Error : ", GetLastError());
  284. //if (pEnv)
  285. //DestroyEnvironmentBlock(pEnv);
  286. CloseHandle(hUserTokenDup);
  287. CloseHandle(hThisToken);
  288. }
  289. else {
  290. DbgWithLink(LOG_LEVEL_WARN, LOG_TYPE_SYSTEM).setAPI(__FUNCTION__)("open process token failed! Error : ", GetLastError());
  291. }
  292. return hProcess;
  293. }
  294. static void AutoHideTaskBar(bool bHide)
  295. {
  296. APPBARDATA apBar;
  297. memset(&apBar, 0, sizeof(apBar));
  298. apBar.cbSize = sizeof(apBar);
  299. apBar.lParam = bHide ? ABS_AUTOHIDE : ABS_ALWAYSONTOP;
  300. apBar.hWnd = FindWindow("Shell_TrayWnd", NULL);
  301. if (apBar.hWnd != NULL)
  302. {
  303. SHAppBarMessage(ABM_SETSTATE, &apBar);
  304. }
  305. }
  306. static bool AddRegIntValue(HKEY hKey, const char *szSubKey, const char *szKeyName, DWORD dwValue, bool bWin64)
  307. {
  308. HKEY hSubKey;
  309. LONG nRet = ::RegCreateKeyEx(hKey,
  310. szSubKey,
  311. 0,
  312. NULL,
  313. 0,
  314. bWin64 ? (KEY_ALL_ACCESS | KEY_WOW64_64KEY) : (KEY_ALL_ACCESS | KEY_WOW64_32KEY),
  315. NULL,
  316. &hSubKey,
  317. NULL);
  318. if (nRet != ERROR_SUCCESS)
  319. return false;
  320. nRet = RegSetValueExA(hSubKey, szKeyName, 0, REG_DWORD, (BYTE*)&dwValue, sizeof(DWORD));
  321. RegCloseKey(hSubKey);
  322. return (nRet == ERROR_SUCCESS);
  323. }
  324. static bool AddFirewallRules()
  325. {
  326. char szBinDir[MAX_PATH] = {};
  327. GetModuleFileNameA(NULL, szBinDir, MAX_PATH);
  328. *strrchr(szBinDir, SPLIT_SLASH) = 0;
  329. int nRet = (int)ShellExecute(NULL, "open", "cmd.exe", "/s /c \"netsh advfirewall firewall delete rule name=\"\"SpShell\"\"", NULL, SW_HIDE);
  330. nRet = (int)ShellExecute(NULL, "open", "cmd.exe", "/s /c \"netsh advfirewall firewall delete rule name=\"\"SpShell\"\"", NULL, SW_HIDE);
  331. nRet = (int)ShellExecute(NULL, "open", "cmd.exe", "/s /c \"netsh advfirewall firewall delete rule name=\"\"SpHost\"\"", NULL, SW_HIDE);
  332. nRet = (int)ShellExecute(NULL, "open", "cmd.exe", "/s /c \"netsh advfirewall firewall delete rule name=\"\"SpGuardian\"\"", NULL, SW_HIDE);
  333. nRet = (int)ShellExecute(NULL, "open", "cmd.exe", "/s /c \"netsh advfirewall firewall delete rule name=\"\"cefclient\"\"", NULL, SW_HIDE);
  334. char szParam[1024] = {};
  335. sprintf_s(szParam, 1024, "/s /c \"netsh advfirewall firewall add rule name=\"\"SpShell\"\" dir=out program=\"\"%s\\spshell.exe\"\" action=allow\"", szBinDir);
  336. nRet = (int)ShellExecute(NULL, "open", "cmd.exe", szParam, NULL, SW_HIDE);
  337. sprintf_s(szParam, 1024, "/s /c \"netsh advfirewall firewall add rule name=\"\"SpHost\"\" dir=out program=\"\"%s\\sphost.exe\"\" action=allow\"", szBinDir);
  338. nRet = (int)ShellExecute(NULL, "open", "cmd.exe", szParam, NULL, SW_HIDE);
  339. sprintf_s(szParam, 1024, "/s /c \"netsh advfirewall firewall add rule name=\"\"SpHost_re\"\" dir=out program=\"\"%s\\sphost_re.exe\"\" action=allow\"", szBinDir);
  340. nRet = (int)ShellExecute(NULL, "open", "cmd.exe", szParam, NULL, SW_HIDE);
  341. sprintf_s(szParam, 1024, "/s /c \"netsh advfirewall firewall add rule name=\"\"SpGuardian\"\" dir=out program=\"\"%s\\guardian.exe\"\" action=allow\"", szBinDir);
  342. nRet = (int)ShellExecute(NULL, "open", "cmd.exe", szParam, NULL, SW_HIDE);
  343. sprintf_s(szParam, 1024, "/s /c \"netsh advfirewall firewall add rule name=\"\"cefclient\"\" dir=out program=\"\"%s\\Chromium\\cefclient.exe\"\" action=allow\"", szBinDir);
  344. nRet = (int)ShellExecute(NULL, "open", "cmd.exe", szParam, NULL, SW_HIDE);
  345. return nRet > 32;
  346. }
  347. int AddFireAddFirewallRulesThread(void* param)
  348. {
  349. if (!AddFirewallRules())
  350. {
  351. DbgWithLink(LOG_LEVEL_FATAL, LOG_TYPE_SYSTEM).setAPI(__FUNCTION__)("设置Windows防火墙策略失败!!!");
  352. Sleep(10000);
  353. return -1;
  354. }
  355. else
  356. DbgWithLink(LOG_LEVEL_INFO, LOG_TYPE_SYSTEM).setAPI(__FUNCTION__)("设置Windows防火墙策略成功!!!");
  357. return 0;
  358. }
  359. static void AddFirewallRulesEx()
  360. {
  361. CloseHandle(CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)& AddFireAddFirewallRulesThread, NULL, 0, NULL));
  362. }
  363. bool DisableWindowsCharmBar(void *param)
  364. {
  365. auto AutoHideCharmBar = []()->bool
  366. {
  367. HWND hWnd = FindWindow(NULL, "Charm Bar");
  368. if (hWnd)
  369. {
  370. ShowWindow(hWnd, SW_HIDE);
  371. return true;
  372. }
  373. else
  374. return false;
  375. };
  376. static bool firstRun = true;
  377. while(true)
  378. {
  379. auto ret = AutoHideCharmBar();
  380. if(firstRun)
  381. {
  382. firstRun = false;
  383. if(ret) DbgWithLink(LOG_LEVEL_INFO, LOG_TYPE_SYSTEM).setAPI(__FUNCTION__)("disable windows 8 charmbar %s", "succ");
  384. }
  385. if (!ret) break;
  386. Sleep(5000);
  387. }
  388. DbgWithLink(LOG_LEVEL_INFO, LOG_TYPE_SYSTEM).setAPI(__FUNCTION__)("disable windows 8 charmbar failed, end!!");
  389. return false;
  390. }
  391. static void DisableWindowsCharmBarThread(bool bX64)
  392. {
  393. static bool curver = bX64;
  394. CloseHandle(CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)&DisableWindowsCharmBar, &curver, 0, NULL));
  395. }
  396. #endif //RVC_OS_WIN
  397. /*!
  398. * at Linux, judge whether current process runs as root privilege.
  399. * @return : True only if run as admin or root
  400. */
  401. static bool IsProcessRunAsAdmin()
  402. {
  403. BOOL bAdmin = FALSE;
  404. #ifdef RVC_OS_WIN
  405. SID_IDENTIFIER_AUTHORITY NtAuthority = SECURITY_NT_AUTHORITY;
  406. PSID AdministratorsGroup = NULL;
  407. DbgWithLink(LOG_LEVEL_INFO, LOG_TYPE_SYSTEM).setAPI(__FUNCTION__)("start AllocateAndInitializeSid");
  408. if (AllocateAndInitializeSid(
  409. &NtAuthority,
  410. 2,
  411. SECURITY_BUILTIN_DOMAIN_RID,
  412. DOMAIN_ALIAS_RID_ADMINS,
  413. 0, 0, 0, 0, 0, 0,
  414. &AdministratorsGroup))
  415. {
  416. DbgWithLink(LOG_LEVEL_INFO, LOG_TYPE_SYSTEM).setAPI(__FUNCTION__)("start CheckTokenMembership");
  417. CheckTokenMembership(NULL, AdministratorsGroup, &bAdmin);
  418. DbgWithLink(LOG_LEVEL_INFO, LOG_TYPE_SYSTEM).setAPI(__FUNCTION__)("start FreeSid");
  419. FreeSid(AdministratorsGroup);
  420. }
  421. #else
  422. if (geteuid() == 0) {
  423. bAdmin = TRUE;
  424. } else {
  425. DbgWithLink(LOG_LEVEL_WARN, LOG_TYPE_SYSTEM)("current process is not run as root privilege, euid:%u, uid:%d", geteuid(), getuid());
  426. }
  427. #endif //RVC_OS_WIN
  428. return bAdmin == TRUE;
  429. }
  430. const char *GetMachineType()
  431. {
  432. auto env = sp_get_env();
  433. if (env == NULL)
  434. {
  435. DbgWithLink(LOG_LEVEL_ERROR, LOG_TYPE_SYSTEM).setAPI(__FUNCTION__)("sp_get_env return null");
  436. return NULL;
  437. }
  438. return env->cfg->root_ini->machine_type;
  439. }
  440. #ifdef RVC_OS_WIN
  441. const char *GetCenterSettingNameBySite(const char *pszSite)
  442. {
  443. ///*TODO(80374374@3/23/2023): CenterSettings */
  444. #if defined(_MSC_VER)
  445. return "CenterSetting.ini";
  446. #else
  447. if (pszSite == NULL || strlen(pszSite) == 0)
  448. return "CenterSetting.ini";
  449. if ((stricmp(pszSite, "CMB.LIB") == 0)
  450. || (stricmp(pszSite, "CMB.SSB") == 0)) {
  451. return "CenterSetting.LAN.ini";
  452. } else if ((stricmp(pszSite, "CMB.LSS") == 0)
  453. || (stricmp(pszSite, "CMB.FLB") == 0)
  454. || (stricmp(pszSite, "CMB.OSB") == 0)
  455. || (stricmp(pszSite, "CMB.SMM") == 0)) {
  456. return "CenterSetting.DMZ.ini";
  457. } else {
  458. return "CenterSetting.DMZ.ini";
  459. }
  460. #endif //_MSC_VER
  461. }
  462. #endif //RVC_OS_WIN
  463. static bool SpTerminateProcess(HANDLE hProc, DWORD dwProcID)
  464. {
  465. if (!TerminateProcess(hProc, -1))
  466. {
  467. #ifdef RVC_OS_WIN
  468. char szCmd[256];
  469. int nRet = 0;
  470. DbgWithLink(LOG_LEVEL_DEBUG, LOG_TYPE_SYSTEM).setAPI(__FUNCTION__)("terminate process %d fail: 0x%X, retry with taskkill", dwProcID, GetLastError());
  471. sprintf_s(szCmd, 256, "TASKKILL /PID %d /F", dwProcID);
  472. WinExec(szCmd, SW_HIDE);
  473. return nRet != -1;
  474. #else
  475. return false;
  476. #endif //RVC_OS_WIN
  477. }
  478. return true;
  479. }
  480. void DisplayUsage()
  481. {
  482. char szHelp[4097] = { '\0' };
  483. sprintf_s(szHelp, 4096, "\n"
  484. "Usage spshell [--entity {EntityName}][--guardian][--test][--benchmark][--kill][--debug][--ipc <pipe|tcp>][--restart][--noroot]\n"
  485. "--entity {EntityName} --启动特定的实体,选项后面输入实体名称\n"
  486. "--guardian --以后台进程的方式运行,暂未实现\n"
  487. "--test --以测试模式运行\n"
  488. "--debug --以调试模式运行,输出更为详细的日志\n"
  489. "--benchmark --以压力测试的模式启动\n"
  490. "--kill --直接杀死终端相关进程,比如 spshell, sphost 等\n"
  491. "--shutdown --彻底退出终端相关进程,不单独使用\n"
  492. "--systemoff --执行系统关机指令,关机前会彻底退出应用,不单独使用\n"
  493. "--reboot --执行系统重启指令,重启关机前会彻底退出应用,不单独使用\n"
  494. "--ipc <pipe|tcp> --指定实体间的通讯方式,使用管道或TCP,默认使用管道\n"
  495. "--noroot -- 允许以非管理员或Root权限方式启动\n"
  496. "--restart --重启当前应用\n"
  497. "--version --显示当前的版本\n"
  498. #ifdef WITH_DEBUG
  499. "--telnet {listern port} --激活远程调用功能\n"
  500. #endif
  501. );
  502. #ifdef WITH_QT
  503. QString str = QString::fromUtf8(szHelp);
  504. QMessageBox::information(NULL, "启动命令选项", str, QMessageBox::Ok);
  505. #elif defined(RVC_OS_WIN)
  506. MessageBoxA(NULL, szHelp, "Spshell Usage Tip", MB_OK);
  507. #else
  508. printf("%s\n", szHelp);
  509. #endif
  510. }
  511. static CSimpleStringA GetTerminalVerFromShellConfig()
  512. {
  513. char tmp[MAX_PATH];
  514. GetModuleFileNameA(NULL, tmp, MAX_PATH);
  515. *strrchr(tmp, SPLIT_SLASH) = 0;
  516. *strrchr(tmp, SPLIT_SLASH) = 0;
  517. strcat(tmp, SPLIT_SLASH_STR "cfg");
  518. strcat(tmp, SPLIT_SLASH_STR "shell.ini");
  519. char* value = inifile_read_str(tmp, "Main", "SoftwareVersion", "");
  520. if (value == NULL) return "";
  521. CSimpleStringA result(value);
  522. FREE(value);
  523. return result;
  524. }
  525. static void DestroyArgs(sp_cfg_start_args_t* args)
  526. {
  527. if (args != NULL) {
  528. FREE(args->program);
  529. FREE(args->arguments);
  530. }
  531. FREE(args);
  532. }
  533. sp_cfg_start_args_t* DealWithArgs(int argc, char** argv)
  534. {
  535. int allocedEntitiyLen = 0;
  536. sp_cfg_start_args_t* args = MALLOC_T(sp_cfg_start_args_t);
  537. TOOLKIT_ASSERT(args);
  538. memset(args, 0, sizeof(sp_cfg_start_args_t));
  539. args->program = args->arguments = NULL;
  540. if (argc > 0) {
  541. args->program = CALLOC_T(strlen(argv[0]) + 1, char);
  542. if (!args->program) { exit(-1); }
  543. memset(args->program, '\0', sizeof(char) * (strlen(argv[0]) + 1));
  544. strcpy(args->program, argv[0]);
  545. printf("program: %s\n", args->program);
  546. std::string params;
  547. for (int i = 1, k=0; i < argc; ++i) {
  548. if(strcmp(argv[i], "--restart") == 0 || strcmp(argv[i], "-R") == 0 || strcmp(argv[i], "-Rwait")/*QT*/ == 0 || strcmp(argv[i], "wait") == 0)
  549. continue;
  550. if (k != 0) params += " ";
  551. params += argv[i];
  552. k++;
  553. }
  554. if (!params.empty()) {
  555. args->arguments = CALLOC_T(params.length() + 1, char);
  556. if (!args->arguments) { exit(-1); }
  557. memset(args->arguments, '\0', sizeof(char) * (params.length()));
  558. strcpy(args->arguments, params.c_str());
  559. }
  560. printf("param: %s\n", args->arguments);
  561. }
  562. args->gui = 1;
  563. args->root = 1;
  564. static struct option spshell_options[] = {
  565. {"entity", required_argument, 0, 'E' },
  566. {"guardian", no_argument, 0, 'G'},
  567. {"test", no_argument, 0, 'T'},
  568. {"debug", no_argument, 0, 'D'},
  569. {"ipc", required_argument, 0, 'I'},
  570. {"shutdown", no_argument, 0, 'S'},
  571. {"kill", no_argument, 0, 'K'},
  572. {"benchmark", no_argument, 0, 'B'},
  573. {"gui", required_argument, 0, 'U'},
  574. #ifdef WITH_DEBUG
  575. {"telnet", required_argument, 0, 'N' },
  576. #endif
  577. {"help", no_argument, 0, 'H'},
  578. {"version", no_argument, 0, 'V'},
  579. {"noroot", no_argument, 0, 'O'},
  580. {"restart", optional_argument, 0, 'R'},
  581. {"systemoff", optional_argument, 0, 'Y'},
  582. {"reboot", optional_argument, 0, 'J'},
  583. {"env", required_argument, 0, 'A' },
  584. {0, 0, 0, 0}
  585. };
  586. int spshell_index = 0;
  587. int c;
  588. while ((c = getopt_long(argc, argv, "E:GTDI:SKBU:HVOR::Y::J::A:?", spshell_options, &spshell_index)) != EOF) {
  589. switch (c) {
  590. case 'E':
  591. {
  592. if (optarg != NULL) {
  593. const int len = strlen(optarg);
  594. if (args->start_entities == NULL || len + strlen(args->start_entities) + 2 /*;\0*/ >= allocedEntitiyLen) {
  595. if (args->start_entities == NULL) {
  596. TOOLKIT_ASSERT(allocedEntitiyLen == 0);
  597. allocedEntitiyLen = 128;
  598. args->start_entities = CALLOC_T(allocedEntitiyLen, char);
  599. if (NULL == args->start_entities) {
  600. DestroyArgs(args);
  601. exit(-1);
  602. }
  603. } else {
  604. TOOLKIT_ASSERT(allocedEntitiyLen != 0);
  605. const int newLen = allocedEntitiyLen + len + 32;
  606. char* newAlloc = CALLOC_T(newLen, char);
  607. if (NULL == newAlloc) {
  608. DestroyArgs(args);
  609. exit(-1);
  610. }
  611. memset(newAlloc, '\0', sizeof(char) * newLen);
  612. strcpy_s(newAlloc, newLen, args->start_entities);
  613. FREE(args->start_entities);
  614. args->start_entities = newAlloc;
  615. allocedEntitiyLen = newLen;
  616. }
  617. }
  618. strcat(args->start_entities, optarg);
  619. strcat(args->start_entities, ";");
  620. }
  621. }
  622. break;
  623. case 'G':
  624. args->guardian_mode = 1;
  625. break;
  626. case 'D':
  627. args->debug_mode = 1;
  628. break;
  629. case 'T':
  630. args->test_mode = (args->test_mode | 1);
  631. break;
  632. case 'B':
  633. args->test_mode = (args->test_mode | 2);
  634. break;
  635. case 'I':
  636. if (optarg) {
  637. if (strnicmp(optarg, "tcp", strlen("tcp")) == 0)
  638. args->ipc_type = 1;
  639. }
  640. break;
  641. #ifdef WITH_DEBUG
  642. case 'N':
  643. if (optarg) {
  644. int nPort = 0;
  645. if (0 < sscanf(optarg, "%d", &nPort))
  646. args->telnet_port = nPort;
  647. }
  648. break;
  649. #endif
  650. case 'K':
  651. {
  652. osutil_terminate_related_process(relate_processes_ex, array_size(relate_processes_ex));
  653. DestroyArgs(args);
  654. exit(0);
  655. }
  656. break;
  657. case 'U':
  658. if (optarg) {
  659. if (strnicmp(optarg, "ON", strlen("ON")) == 0)
  660. args->gui = 1;
  661. else if(strnicmp(optarg, "OFF", strlen("OFF")) == 0)
  662. args->gui = 0;
  663. }
  664. break;
  665. case 'A':
  666. if (optarg) {
  667. if (strnicmp(optarg, "ST", strlen("ST")) == 0)
  668. args->test_mode = (args->test_mode | 4);
  669. else if (strnicmp(optarg, "UAT", strlen("UAT")) == 0)
  670. args->test_mode = (args->test_mode | 8);
  671. }
  672. break;
  673. case 'V':
  674. {
  675. DestroyArgs(args);
  676. exit(0);
  677. break;
  678. }
  679. break;
  680. case 'O':
  681. args->root = 0;
  682. break;
  683. case 'R':
  684. g_restartMode = RESTART_MODE_NORMAL;
  685. if (optarg && strcmp(optarg, "wait") == 0) {
  686. g_restartMode = RESTART_MODE_PRE;
  687. }
  688. break;
  689. case 'S':
  690. g_restartMode = RESTART_MODE_SHUTDOWN;
  691. break;
  692. case 'Y':
  693. g_restartMode = RESTART_MODE_POWEROFF;
  694. if (optarg && strnicmp(optarg, "now", strlen("now")) == 0) {
  695. g_immediately = true;
  696. }
  697. break;
  698. case 'J':
  699. g_restartMode = RESTART_MODE_REBOOT;
  700. if (optarg && strnicmp(optarg, "now", strlen("now")) == 0) {
  701. g_immediately = true;
  702. }
  703. break;
  704. case 'H':
  705. case '?':
  706. default:
  707. DisplayUsage();
  708. DestroyArgs(args);
  709. exit(0);
  710. break;
  711. }
  712. }
  713. if (optind < argc) {
  714. while (optind < argc) {
  715. //DbgWithLink(LOG_LEVEL_WARN, LOG_TYPE_SYSTEM)("\t%s", argv[optind++]);
  716. }
  717. }
  718. if (args && args->start_entities != 0) {
  719. args->start_entities[strlen(args->start_entities) - 1] = '\0';
  720. }
  721. return args;
  722. }
  723. static void QtPostEvent(void* user_data)
  724. {
  725. #ifdef WITH_QT
  726. QApplication* app = (QApplication*)user_data;
  727. app->processEvents();
  728. DbgWithLink(LOG_LEVEL_DEBUG, LOG_TYPE_SYSTEM)("test: QEventLoop::ExcludeUserInputEvents");
  729. #endif
  730. }
  731. void normal_signal_handle(int num)
  732. {
  733. DbgWithLink(LOG_LEVEL_INFO, LOG_TYPE_SYSTEM)("receive signal %d", num);
  734. signal(num, SIG_DFL);
  735. raise(num);
  736. }
  737. static bool NeedToRestartFramework()
  738. {
  739. //Shutdown 表明退掉框架不重启
  740. return !((g_restartMode == RESTART_MODE_SHUTDOWN
  741. || g_restartMode == RESTART_MODE_POWEROFF
  742. || g_restartMode == RESTART_MODE_REBOOT));
  743. }
  744. #if defined(_MSC_VER)
  745. ///*TODO(80374374@3/23/2023): osutil_detect_unique_app 替代 */
  746. static bool DetectDuplicateInstance(char** pNames, int nNum)
  747. {
  748. DWORD dwCurProcID = GetCurrentProcessId();
  749. HANDLE hSnapshot = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
  750. std::shared_ptr<void> delHandleFun((void*)0, [&](void*) {
  751. if (NULL != hSnapshot)
  752. CloseHandle(hSnapshot);
  753. });
  754. if (hSnapshot) {
  755. PROCESSENTRY32 pe = {};
  756. pe.dwSize = sizeof(pe);
  757. if (Process32First(hSnapshot, &pe)) {
  758. do {
  759. for (int i = 0; i < nNum; i++) {
  760. if (stricmp(&pe.szExeFile[0], pNames[i]) == 0 && pe.th32ProcessID != dwCurProcID) {
  761. HANDLE hProc = OpenProcess(PROCESS_ALL_ACCESS, FALSE, pe.th32ProcessID);
  762. if (hProc == NULL) {
  763. DbgWithLink(LOG_LEVEL_ERROR, LOG_TYPE_SYSTEM).setAPI(__FUNCTION__)("find duplicated process: %s, id: %d", pNames[i], pe.th32ProcessID);
  764. return false;
  765. }
  766. if (!SpTerminateProcess(hProc, pe.th32ProcessID)) {
  767. DbgWithLink(LOG_LEVEL_ERROR, LOG_TYPE_SYSTEM).setAPI(__FUNCTION__)("terminate duplicated process %s fail, id: %d, error: %d",
  768. pNames[i], pe.th32ProcessID, GetLastError());
  769. return false;
  770. }
  771. DbgWithLink(LOG_LEVEL_INFO, LOG_TYPE_SYSTEM).setAPI(__FUNCTION__)("terminate duplicated process: %s, id: %d", pNames[i], pe.th32ProcessID);
  772. }
  773. }
  774. } while (Process32Next(hSnapshot, &pe));
  775. }
  776. } else
  777. DbgWithLink(LOG_LEVEL_INFO, LOG_TYPE_SYSTEM).setAPI(__FUNCTION__)("DetectDuplicateInstance can not enter Process32First!");
  778. return true;
  779. }
  780. #endif //_MSC_VER
  781. void SPBASE_API __stdcall setCurEntityIdx(int idx);
  782. std::string generateCenterSettingPath()
  783. {
  784. char pathbuf[1024] = "";
  785. int pathlen = ::GetModuleFileNameA(NULL, pathbuf, 1024);//获得GuiConsole路径
  786. // 替换掉单杠
  787. int times = 0;
  788. while (pathlen > 0) {
  789. if (pathbuf[pathlen--] == SPLIT_SLASH)
  790. times++;
  791. if (2 == times)
  792. break;
  793. }
  794. pathbuf[++pathlen] = '\0';
  795. std::string dstPath = pathbuf;
  796. #if defined(_MSC_VER)
  797. dstPath.append(SPLIT_SLASH_STR "cfg" SPLIT_SLASH_STR "CenterSetting.ini");
  798. #else
  799. dstPath.append(SPLIT_SLASH_STR "cfg" SPLIT_SLASH_STR "CenterSetting.LAN.ini");
  800. #endif //_MSC_VER
  801. return dstPath;
  802. }
  803. int main(int argc, char** argv)
  804. {
  805. #ifdef WITH_QT
  806. Center app(argc, argv);
  807. #endif
  808. sp_cfg_start_args_t* args = DealWithArgs(argc, argv);
  809. #ifdef WITH_QT
  810. app.Init();
  811. const Qt::Alignment bottomLeft = Qt::AlignBottom | Qt::AlignLeft;
  812. sp_trace_init();
  813. #endif
  814. #if defined(RVC_OS_LINUX)
  815. if (args->debug_mode) {
  816. SP::Perf::LeakDetector leakInstance;
  817. WLog_initRVC("SpShell");
  818. }
  819. #else
  820. _CrtSetDebugFillThreshold(0);
  821. #endif //RVC_OS_LINUX
  822. #ifdef RVC_SAVEFILE
  823. bool saveFile = true;
  824. #else
  825. char tmp[MAX_LEN] = "";
  826. bool saveFile = false;
  827. if (Error_Succeed == sp_tryReadFromCenterSetting("Common", "SaveFile", tmp, MAX_LEN) && 0 == CSimpleStringA(tmp).Compare("1"))
  828. saveFile = true;
  829. #endif // RVC_SAVEFILE
  830. if (saveFile)
  831. sp_dbg_init("SpShell", 1);
  832. else
  833. sp_dbg_init("SpShell", 0);
  834. EntityResource::setSaveFile(saveFile);
  835. #if defined(RVC_OS_LINUX)
  836. sp_dbg_set_level(XLOG_LEVEL_DEBUG);
  837. #endif //RVC_OS_LINUX
  838. if (argc > 1) {
  839. std::string args_str;
  840. char cmdline[1024] = { '\0' };
  841. for (int i = 0; i < argc; ++i) {
  842. sprintf_s(cmdline, 1024, "%s", argv[i]);
  843. if (i != 0) args_str += " ";
  844. args_str += cmdline;
  845. }
  846. DbgWithLink(LOG_LEVEL_INFO, LOG_TYPE_SYSTEM).setAPI(__FUNCTION__)("prefix: %s", args_str.c_str());
  847. }
  848. #if defined(_MSC_VER)
  849. auto centersettingPath = generateCenterSettingPath();
  850. load_debugLevelInCentersetting(centersettingPath.c_str());
  851. load_specialRunInfoInCentersetting(centersettingPath.c_str());
  852. auto setAffinity = [](long ulCpuMask) {
  853. HANDLE hCurrentProc;
  854. DWORD_PTR dwpProcAffinityMask = ulCpuMask;
  855. // Obtain a usable handle of the current process
  856. hCurrentProc = GetCurrentProcess();
  857. // Get the old affinity mask
  858. SetProcessAffinityMask(hCurrentProc, dwpProcAffinityMask);
  859. SetProcessAffinityUpdateMode(hCurrentProc, PROCESS_AFFINITY_ENABLE_AUTO_UPDATE);
  860. CloseHandle(hCurrentProc);
  861. };
  862. setAffinity(1);
  863. char* arrProcName[] = { "SpShell.exe", "SpHost.exe", "SpHost_re.exe" };
  864. //实际可以加快这个过程,如果进程过多会比较慢
  865. //后续可考虑用mutex进行控制
  866. if (!DetectDuplicateInstance(&arrProcName[0], sizeof(arrProcName) / sizeof(arrProcName[0]))) {
  867. DbgWithLink(LOG_LEVEL_FATAL, LOG_TYPE_SYSTEM).setAPI(__FUNCTION__).setResultMsg(RTAERR_SPSHELL_REPEATPROCESS)("检测到重复spshell/sphost进程,系统启动失败!!!");
  868. Sleep(10000);
  869. return -200;
  870. }
  871. #else
  872. if (!!g_restartMode) {
  873. const int maxTimes = 10;
  874. const int maxPreTimies = 60;
  875. const DWORD eachPreTimeout = 1000;
  876. const DWORD eachTimeout = 1000;
  877. const DWORD skipInterval = 5;
  878. int currTimes = 0, preTimes = 0;
  879. bool needWait = (g_restartMode > RESTART_MODE_NORMAL && !g_immediately); //Rwait 框架触发的重启
  880. const bool needlessRestart = !NeedToRestartFramework();
  881. int aliveCount = 0, lastAliveCount(1000);
  882. char** relates = relate_processes;
  883. int reletes_cnt = relate_processes_count;
  884. if (needWait) {
  885. #ifdef WITH_QT
  886. app.GetSplash()->showMessage(QString("等待应用进程退出..."), bottomLeft, Qt::black);
  887. #endif
  888. }
  889. if (needlessRestart) {
  890. DbgWithLink(LOG_LEVEL_INFO, LOG_TYPE_SYSTEM)("to shutdown guardian...");
  891. char* tmp_processes[] = { guardian_execute_name };
  892. osutil_terminate_related_process(tmp_processes, array_size(tmp_processes));
  893. relates = relate_processes_ex;
  894. reletes_cnt = relate_processes_ex_count;
  895. }
  896. bool switch_flag = false;
  897. while (switch_flag || !osutil_detect_unique_app(relates, reletes_cnt, &aliveCount, NULL)) {
  898. if (!needWait && ++currTimes >= maxTimes) {
  899. DbgWithLink(LOG_LEVEL_FATAL, LOG_TYPE_SYSTEM)("detect ex-spshell or sphost process, abort cur boot !!!");
  900. #ifdef WITH_QT
  901. app.GetSplash()->finish(nullptr);
  902. QMessageBox::critical(NULL, "错误", "等待应用进程退出超时,请尝试重启机器!", QMessageBox::Yes);
  903. #endif
  904. sp_dbg_term();
  905. DestroyArgs(args);
  906. return -200;
  907. } else {
  908. if (needWait) {
  909. Sleep(eachPreTimeout);
  910. if (++preTimes >= maxPreTimies && (aliveCount >= lastAliveCount)) {
  911. needWait = false;
  912. }
  913. DbgWithLink(LOG_LEVEL_INFO, LOG_TYPE_SYSTEM)("wait... last active process count:%d, curr process count: %d, ppid: %d", lastAliveCount, aliveCount, GetParentProcessID());
  914. lastAliveCount = aliveCount;
  915. } else {
  916. DbgWithLink(LOG_LEVEL_WARN, LOG_TYPE_SYSTEM)("detect ex-spshell or sphost process %d, %d !!!", preTimes, currTimes);
  917. osutil_terminate_related_process(relates, reletes_cnt);
  918. Sleep(eachTimeout);
  919. }
  920. #ifdef WITH_QT
  921. const DWORD consumedTime = (currTimes * eachTimeout) / 1000 + (eachPreTimeout * preTimes) / 1000;
  922. if (consumedTime > 0) {
  923. app.GetSplash()->showMessage(QString("等待应用进程退出,已等待 %1 秒...").arg(consumedTime), bottomLeft, Qt::black);
  924. }
  925. #endif
  926. }
  927. //aliveCount = 0; //important!!!
  928. switch_flag = (((preTimes + currTimes) % skipInterval) != 0);
  929. if (!switch_flag) {
  930. aliveCount = 0;
  931. DbgWithLink(LOG_LEVEL_INFO, LOG_TYPE_SYSTEM)("will enter osutil_detect_unique_app");
  932. }
  933. }
  934. DbgWithLink(LOG_LEVEL_INFO, LOG_TYPE_SYSTEM)("finish detecting unique app.");
  935. if (needlessRestart) {
  936. const DWORD sleepMillsecs = 2000;
  937. DbgWithLink(LOG_LEVEL_INFO, LOG_TYPE_SYSTEM)("restart mode: %d", g_restartMode);
  938. #ifdef WITH_QT
  939. if (g_restartMode == RESTART_MODE_SHUTDOWN) {
  940. app.GetSplash()->showMessage(QString("应用进程已完全清理,退出当前窗口..."), bottomLeft, Qt::black);
  941. } else if (g_restartMode == RESTART_MODE_POWEROFF) {
  942. app.GetSplash()->showMessage(QString("应用进程已完全清理,准备关机..."), bottomLeft, Qt::black);
  943. osutil_shutdown_system();
  944. app.GetSplash()->showMessage(QString("应用进程已完全清理,正在关机..."), bottomLeft, Qt::black);
  945. } else if (g_restartMode == RESTART_MODE_REBOOT) {
  946. app.GetSplash()->showMessage(QString("应用进程已完全清理,准备关机重启..."), bottomLeft, Qt::black);
  947. osutil_restart_system();
  948. app.GetSplash()->showMessage(QString("应用进程已完全清理,正在关机并重启..."), bottomLeft, Qt::black);
  949. }
  950. #endif
  951. Sleep(sleepMillsecs);
  952. sp_dbg_term();
  953. DestroyArgs(args);
  954. return 0;
  955. }
  956. } else if (!osutil_detect_unique_app(relate_processes, array_size(relate_processes), NULL, NULL)) {
  957. do {
  958. #ifdef WITH_QT
  959. //QMessageBox::critical(NULL, "错误", "检测到有相关进程正在运行!", QMessageBox::Yes);
  960. const QMessageBox::StandardButton rb = QMessageBox::question(NULL, "警告", "检测到已有相关进程在运行!是否要强制启动?",
  961. QMessageBox::Yes | QMessageBox::No, QMessageBox::No);
  962. if (rb == QMessageBox::Yes) {
  963. osutil_terminate_related_process(relate_processes, array_size(relate_processes));
  964. Sleep(1000);
  965. int count = MAX_ALIVE_PROCESS_COUNT;
  966. alive_process_info processes[MAX_ALIVE_PROCESS_COUNT];
  967. memset(processes, 0, sizeof(processes));
  968. if (osutil_detect_unique_app(relate_processes, array_size(relate_processes), &count, processes)) {
  969. break;
  970. }
  971. TOOLKIT_ASSERT(count > 0);
  972. DbgWithLink(LOG_LEVEL_WARN, LOG_TYPE_SYSTEM)("clear ex-spshell/sphost process failed!");
  973. QString str = QString("强制重启失败:无法完全清理已有进程!(%1)").arg(count);
  974. for (int i = 0; i < count; ++i) {
  975. str += "\n";
  976. QString tmp = QString("%1(%2) - %3").arg(processes[i].name).arg(processes[i].pid).arg(processes[i].path);
  977. str += tmp;
  978. }
  979. QMessageBox::critical(NULL, "错误", str, QMessageBox::Yes);
  980. }
  981. DbgWithLink(LOG_LEVEL_FATAL, LOG_TYPE_SYSTEM)("detect duplicate spshell/sphost process, abort cur boot !!!");
  982. app.GetSplash()->finish(nullptr);
  983. #endif //WITH_QT
  984. //osutil_terminate_related_process(relate_processes, array_size(relate_processes));
  985. // Sleep(3000);
  986. sp_dbg_term();
  987. DestroyArgs(args);
  988. return -200;
  989. } while (false);
  990. }
  991. #endif //_MSC_VER
  992. create_log_producer_default("SpShell", 0);
  993. DbgWithLink(LOG_LEVEL_INFO, LOG_TYPE_SYSTEM).setAPI(__FUNCTION__)("===================SpShell start=====================");
  994. DbgWithLink(LOG_LEVEL_INFO, LOG_TYPE_SYSTEM).setAPI(__FUNCTION__)("process id: %d, saveFile:%d", GetCurrentProcessId(), saveFile);
  995. if (argc > 1) {
  996. std::string args_str;
  997. char cmdline[1024] = { '\0' };
  998. for (int i = 0; i < argc; ++i) {
  999. sprintf_s(cmdline, 1024, "%s", argv[i]);
  1000. if (i != 0) args_str += " ";
  1001. args_str += cmdline;
  1002. }
  1003. DbgWithLink(LOG_LEVEL_INFO, LOG_TYPE_SYSTEM).setAPI(__FUNCTION__)(args_str.c_str());
  1004. SP_TRACE(args_str.c_str());
  1005. }
  1006. if (!IsProcessRunAsAdmin()) {
  1007. if (args->root) {
  1008. DbgWithLink(LOG_LEVEL_FATAL, LOG_TYPE_SYSTEM)("current process need run with administrator or root privilege !!!");
  1009. #ifdef WITH_QT
  1010. QMessageBox::warning(NULL, "警告", "需要以管理员或ROOT用户权限启动!", QMessageBox::Yes);
  1011. #else
  1012. DbgWithLink(LOG_LEVEL_FATAL, LOG_TYPE_SYSTEM).setAPI(__FUNCTION__).setResultMsg(RTAERR_SPSHELL_NOPRIVILEGE)("需要以管理员权限运行!!!");
  1013. Sleep(10000);
  1014. #endif
  1015. sp_dbg_term();
  1016. DestroyArgs(args);
  1017. return -201;
  1018. } else {
  1019. DbgWithLink(LOG_LEVEL_INFO, LOG_TYPE_SYSTEM).setAPI(__FUNCTION__)("current process requires normal privilege.");
  1020. }
  1021. } else {
  1022. DbgWithLink(LOG_LEVEL_DEBUG, LOG_TYPE_SYSTEM).setAPI(__FUNCTION__)("current process has been run with administrator or root privilege.");
  1023. args->root = (char)1;
  1024. #if defined(_MSC_VER)
  1025. SYSTEM_INFO SystemInfo;
  1026. GetSystemInfo(&SystemInfo);
  1027. DbgWithLink(LOG_LEVEL_INFO, LOG_TYPE_SYSTEM).setAPI(__FUNCTION__)("当前以管理员权限运行, curProcessId:%d, curVersion:%s ,dwNumberOfProcessors=%u, dwActiveProcessorMask=%u, wProcessorLevel=%u, wProcessorArchitecture=%u, dwPageSize=%u",
  1028. GetCurrentProcessId(), STRFILEVER, SystemInfo.dwNumberOfProcessors, SystemInfo.dwActiveProcessorMask, SystemInfo.wProcessorLevel,
  1029. SystemInfo.wProcessorArchitecture, SystemInfo.dwPageSize);
  1030. #endif //_MSC_VER
  1031. }
  1032. #ifdef RVC_OS_WIN
  1033. #ifdef WITH_QT
  1034. app.GetSplash()->showMessage(QObject::tr("Config firewall policies......"), bottomLeft, Qt::black);
  1035. #endif
  1036. // 设置防火墙注册表配置
  1037. AddFirewallRulesEx();
  1038. #endif //RVC_OS_WIN
  1039. #ifdef RVC_OS_WIN
  1040. setlocale(LC_ALL, "chs");
  1041. #else
  1042. if (NULL == setlocale(LC_ALL, "zh_CN.UTF-8")) {
  1043. //zh_CN.UTF-8 zh_CN.GBK
  1044. DbgWithLink(LOG_LEVEL_ERROR, LOG_TYPE_SYSTEM)("setlocale failed: %s", strerror(errno));
  1045. }
  1046. #endif //RVC_OS_WIN
  1047. SetEnvPath();
  1048. #ifdef RVC_OS_WIN
  1049. #ifdef WITH_QT
  1050. app.GetSplash()->showMessage(QObject::tr("Config working set......"), bottomLeft, Qt::black);
  1051. #endif
  1052. SetWorkingSet();//获取设置内存使用率,4G
  1053. #ifdef WITH_QT
  1054. app.GetSplash()->showMessage(QObject::tr("Setup exception filter......"), bottomLeft, Qt::black);
  1055. #endif
  1056. #endif //RVC_OS_WIN
  1057. DbgWithLink(LOG_LEVEL_INFO, LOG_TYPE_SYSTEM).setAPI(__FUNCTION__)("basic config success");
  1058. #ifdef RVC_OS_WIN
  1059. // 检测是否Win8及64位
  1060. OSVERSIONINFO ver = {};
  1061. ver.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);
  1062. GetVersionEx(&ver);
  1063. bool bWin8 = (ver.dwMajorVersion >= 7 || (ver.dwMajorVersion == 6 && ver.dwMinorVersion >= 2)); //version over 7 or over 6.2
  1064. SYSTEM_INFO sysInfo = {};
  1065. GetNativeSystemInfo(&sysInfo);
  1066. bool bX64 = (sysInfo.wProcessorArchitecture == PROCESSOR_ARCHITECTURE_AMD64);
  1067. 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,
  1068. 0 == SetErrorMode(SEM_FAILCRITICALERRORS | SEM_NOGPFAULTERRORBOX | SEM_NOOPENFILEERRORBOX) ? "success" : "failed");
  1069. SetUnhandledExceptionFilter(&SuppressError);
  1070. #endif //RVC_OS_WIN
  1071. auto msg_lamda_func = [&](const char* msg, bool ctritial)->void {
  1072. #ifdef WITH_QT
  1073. app.GetSplash()->showMessage(QObject::tr(msg), bottomLeft, ctritial ? Qt::red : Qt::black);
  1074. #endif
  1075. };
  1076. #ifdef WITH_QT
  1077. app.GetSplash()->showMessage(QObject::tr("应用初始化中..."), bottomLeft, Qt::black);
  1078. #endif
  1079. //////////////////////////////////////////////////////////////////////////
  1080. #if defined(_MSC_VER)
  1081. auto rc = app_init(args);
  1082. int result = rc.first;
  1083. #else
  1084. int result = app_init(args, msg_lamda_func);
  1085. #endif //_MSC_VER
  1086. //////////////////////////////////////////////////////////////////////////
  1087. if (result == 0)
  1088. {
  1089. #ifdef WITH_QT
  1090. app.GetSplash()->showMessage(QObject::tr("应用初始化完成"), bottomLeft, Qt::black);
  1091. sp_trace_term();
  1092. #endif
  1093. #if NO_GUI_WITH_WTL
  1094. if(args->gui) {
  1095. app.Run();
  1096. } else
  1097. #endif
  1098. {
  1099. #ifdef WITH_QT
  1100. app.processEvents();
  1101. app.GetSplash()->finish(app.mWidget);
  1102. #endif
  1103. DbgWithLink(LOG_LEVEL_DEBUG, LOG_TYPE_SYSTEM)("run circle loop in main thread!!");
  1104. result = app_run();
  1105. app_term();
  1106. }
  1107. }
  1108. else
  1109. {
  1110. uint32_t waitIntervals = 10000;
  1111. #ifdef WITH_QT
  1112. app.GetSplash()->finish(nullptr);
  1113. if (sp_trace_exist()) {
  1114. char* last_err = NULL;
  1115. sp_trace_retrieve(&last_err, NULL);
  1116. if (last_err) {
  1117. DbgWithLink(LOG_LEVEL_DEBUG, LOG_TYPE_SYSTEM)("to show last error dialog...");
  1118. QString str = QString("%1").arg(last_err);
  1119. QMessageBox::critical(NULL, "应用启动失败", str, QMessageBox::Yes);
  1120. waitIntervals = 1;
  1121. FREE(last_err);
  1122. DbgWithLink(LOG_LEVEL_DEBUG, LOG_TYPE_SYSTEM)("to show last error dialog done!");
  1123. }
  1124. sp_trace_term();
  1125. }
  1126. #endif
  1127. #if defined(_MSC_VER)
  1128. DbgWithLink(LOG_LEVEL_ERROR, LOG_TYPE_SYSTEM).setAPI(__FUNCTION__)("======================================================");
  1129. DbgWithLink(LOG_LEVEL_ERROR, LOG_TYPE_SYSTEM).setAPI(__FUNCTION__).setResultMsg(RTAERR_SPSHELL_APPINITERR)(rc.second.GetData());
  1130. DbgWithLink(LOG_LEVEL_ERROR, LOG_TYPE_SYSTEM).setAPI(__FUNCTION__)("!!!!!! 启动失败,请检查dbg\\spshell日志排除故障 !!!!!!");
  1131. DbgWithLink(LOG_LEVEL_ERROR, LOG_TYPE_SYSTEM).setAPI(__FUNCTION__)("======================================================");
  1132. #else
  1133. DbgWithLink(LOG_LEVEL_ERROR, LOG_TYPE_SYSTEM).setAPI(__FUNCTION__)("======================================================");
  1134. DbgWithLink(LOG_LEVEL_ERROR, LOG_TYPE_SYSTEM).setAPI(__FUNCTION__).setResultMsg(RTAERR_SPSHELL_APPINITERR)("!!!!!! Startup failed, get more detail information from dbg/spshell !!!!!!");
  1135. DbgWithLink(LOG_LEVEL_ERROR, LOG_TYPE_SYSTEM).setAPI(__FUNCTION__)("======================================================");
  1136. #endif //_MSC_VER
  1137. app_upload_last_log();
  1138. Sleep(waitIntervals);
  1139. }
  1140. #ifdef RVC_OS_WIN
  1141. if (bWin8 && !bX64) {
  1142. EnableCharmbar();
  1143. }
  1144. #endif //RVC_OS_WIN
  1145. sp_dbg_term();
  1146. DestroyArgs(args);
  1147. return result;
  1148. }
  1149. #ifdef RVC_OS_WIN
  1150. int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nShowCmd)
  1151. {
  1152. return main(__argc, __argv);
  1153. }
  1154. #endif //RVC_OS_WIN