spshell.cpp 41 KB

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