TimeSyncServer.cpp 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458
  1. // TimeSyncServer.cpp : 定义应用程序的类行为。
  2. //
  3. #include "stdafx.h"
  4. #include "TimeSyncServer.h"
  5. #include "TimeSyncServerDlg.h"
  6. #include "Simplelog.h"
  7. #include <thread>
  8. #include "AppService.h"
  9. #ifdef _DEBUG
  10. #define new DEBUG_NEW
  11. #endif
  12. //设置两个全局变量
  13. SERVICE_STATUS m_ServiceStatus;
  14. SERVICE_STATUS_HANDLE m_ServiceStatusHandle;
  15. class CDumpCatch
  16. {
  17. public:
  18. CDumpCatch();
  19. ~CDumpCatch();
  20. private:
  21. static LPTOP_LEVEL_EXCEPTION_FILTER WINAPI TempSetUnhandledExceptionFilter(LPTOP_LEVEL_EXCEPTION_FILTER lpTopLevelExceptionFilter);
  22. static BOOL ReleaseDumpFile(const std::string& strPath, EXCEPTION_POINTERS* pException);
  23. static LONG WINAPI UnhandledExceptionFilterEx(struct _EXCEPTION_POINTERS* pException);
  24. static void MyPureCallHandler(void);
  25. static void MyInvalidParameterHandler(const wchar_t* expression, const wchar_t* function, const wchar_t* file, unsigned int line, uintptr_t pReserved);
  26. BOOL AddExceptionHandle();
  27. BOOL RemoveExceptionHandle();
  28. BOOL PreventSetUnhandledExceptionFilter();
  29. void SetInvalidHandle();
  30. void UnSetInvalidHandle();
  31. private:
  32. LPTOP_LEVEL_EXCEPTION_FILTER m_preFilter;
  33. _invalid_parameter_handler m_preIph;
  34. _purecall_handler m_prePch;
  35. };
  36. void WINAPI ServiceMain(DWORD argc, LPTSTR * argv)
  37. {
  38. // DWORD status;
  39. // DWORD specificError;
  40. SPDLOG_INFO("当用SCM启动程序的时候,程序执行下面的代码");
  41. m_ServiceStatus.dwServiceType = SERVICE_WIN32;
  42. m_ServiceStatus.dwCurrentState = SERVICE_START_PENDING;
  43. m_ServiceStatus.dwControlsAccepted = SERVICE_ACCEPT_STOP;
  44. m_ServiceStatus.dwWin32ExitCode = 0;
  45. m_ServiceStatus.dwServiceSpecificExitCode = 0;
  46. m_ServiceStatus.dwCheckPoint = 0;
  47. m_ServiceStatus.dwWaitHint = 0;
  48. m_ServiceStatusHandle = RegisterServiceCtrlHandler("TimeSyncServer", ServiceCtrlHandler);
  49. if (m_ServiceStatusHandle == (SERVICE_STATUS_HANDLE)0)
  50. {
  51. CSimpleLog::Save("Handler not installed", true, CSimpleLog::error);
  52. return;
  53. }
  54. m_ServiceStatus.dwCurrentState = SERVICE_RUNNING;
  55. m_ServiceStatus.dwCheckPoint = 0;
  56. m_ServiceStatus.dwWaitHint = 0;
  57. if (!SetServiceStatus(m_ServiceStatusHandle, &m_ServiceStatus))
  58. {
  59. }
  60. std::thread th(CTimeSyncServerApp::StartTheAppServices, 5);
  61. th.detach();
  62. return;
  63. }
  64. void WINAPI ServiceCtrlHandler(DWORD Opcode)
  65. {
  66. switch (Opcode)
  67. {
  68. case SERVICE_CONTROL_PAUSE:
  69. m_ServiceStatus.dwCurrentState = SERVICE_PAUSED;
  70. break;
  71. case SERVICE_CONTROL_CONTINUE:
  72. m_ServiceStatus.dwCurrentState = SERVICE_RUNNING;
  73. break;
  74. case SERVICE_CONTROL_STOP:
  75. m_ServiceStatus.dwWin32ExitCode = 0;
  76. m_ServiceStatus.dwCurrentState = SERVICE_STOPPED;
  77. m_ServiceStatus.dwCheckPoint = 0;
  78. m_ServiceStatus.dwWaitHint = 0;
  79. SetServiceStatus(m_ServiceStatusHandle, &m_ServiceStatus);
  80. //bRunning=false;
  81. break;
  82. case SERVICE_CONTROL_INTERROGATE:
  83. break;
  84. }
  85. return;
  86. }
  87. BOOL InstallService(CString &strPath)//无法创建其他应用程序为服务,因为它们不能响应启动请求
  88. {
  89. //char strDir[1024]={0};
  90. SC_HANDLE schSCManager, schService;
  91. // GetCurrentDirectory(1024,strDir);
  92. // strcat(strDir," //test.exe ");
  93. schSCManager = OpenSCManager(NULL, NULL, SC_MANAGER_ALL_ACCESS);
  94. if (schSCManager == NULL)
  95. return false;
  96. //LPCTSTR lpszBinaryPathName=strDir;
  97. LPCTSTR lpszBinaryPathName;
  98. if (strPath == "")
  99. {
  100. AfxMessageBox("You must tell me Exepath!");
  101. return FALSE;
  102. }
  103. else
  104. {
  105. lpszBinaryPathName = strPath;
  106. }
  107. schService = CreateService(schSCManager, "DataCenter", "DataCenter",// service name to display
  108. SERVICE_ALL_ACCESS, // desired access
  109. SERVICE_WIN32_OWN_PROCESS | SERVICE_INTERACTIVE_PROCESS, // service type
  110. //SERVICE_DEMAND_START, // start type
  111. SERVICE_AUTO_START, //系统启动时自动启动
  112. SERVICE_ERROR_NORMAL, // error control type
  113. lpszBinaryPathName, // service's binary
  114. NULL, // no load ordering group
  115. NULL, // no tag identifier
  116. NULL, // no dependencies
  117. NULL, // LocalSystem account
  118. NULL); // no password
  119. if (schService == NULL)
  120. return false;
  121. CloseServiceHandle(schService);
  122. return true;
  123. }
  124. BOOL DeleteService()
  125. {
  126. SC_HANDLE schSCManager;
  127. SC_HANDLE hService;
  128. schSCManager = OpenSCManager(NULL, NULL, SC_MANAGER_ALL_ACCESS);
  129. if (schSCManager == NULL)
  130. return false;
  131. hService = OpenService(schSCManager, "DataCenter", SERVICE_ALL_ACCESS);
  132. if (hService == NULL)
  133. return false;
  134. if (DeleteService(hService) == 0)
  135. return false;
  136. if (CloseServiceHandle(hService) == 0)
  137. return false;
  138. else
  139. return true;
  140. }
  141. // CTimeSyncServerApp
  142. BEGIN_MESSAGE_MAP(CTimeSyncServerApp, CWinApp)
  143. ON_COMMAND(ID_HELP, &CWinApp::OnHelp)
  144. END_MESSAGE_MAP()
  145. // CTimeSyncServerApp 构造
  146. CTimeSyncServerApp::CTimeSyncServerApp()
  147. {
  148. // 支持重新启动管理器
  149. m_dwRestartManagerSupportFlags = AFX_RESTART_MANAGER_SUPPORT_RESTART;
  150. // TODO: 在此处添加构造代码,
  151. // 将所有重要的初始化放置在 InitInstance 中
  152. }
  153. // 唯一的一个 CTimeSyncServerApp 对象
  154. CTimeSyncServerApp theApp;
  155. CDumpCatch g_dumpCatch;
  156. //////////////////////////////////////////////////////////////////////////////////////
  157. void CDumpCatch::MyPureCallHandler(void)
  158. {
  159. throw std::invalid_argument("");
  160. }
  161. void CDumpCatch::MyInvalidParameterHandler(const wchar_t* expression, const wchar_t* function, const wchar_t* file, unsigned int line, uintptr_t pReserved)
  162. {
  163. //The parameters all have the value NULL unless a debug version of the CRT library is used.
  164. throw std::invalid_argument("");
  165. }
  166. void CDumpCatch::SetInvalidHandle()
  167. {
  168. #if _MSC_VER >= 1400 // MSVC 2005/8
  169. m_preIph = _set_invalid_parameter_handler(MyInvalidParameterHandler);
  170. #endif // _MSC_VER >= 1400
  171. m_prePch = _set_purecall_handler(MyPureCallHandler); //At application, this call can stop show the error message box.
  172. }
  173. void CDumpCatch::UnSetInvalidHandle()
  174. {
  175. #if _MSC_VER >= 1400 // MSVC 2005/8
  176. _set_invalid_parameter_handler(m_preIph);
  177. #endif // _MSC_VER >= 1400
  178. _set_purecall_handler(m_prePch); //At application this can stop show the error message box.
  179. }
  180. LPTOP_LEVEL_EXCEPTION_FILTER WINAPI CDumpCatch::TempSetUnhandledExceptionFilter(LPTOP_LEVEL_EXCEPTION_FILTER lpTopLevelExceptionFilter)
  181. {
  182. return NULL;
  183. }
  184. BOOL CDumpCatch::AddExceptionHandle()
  185. {
  186. m_preFilter = ::SetUnhandledExceptionFilter(UnhandledExceptionFilterEx);
  187. PreventSetUnhandledExceptionFilter();
  188. return TRUE;
  189. }
  190. BOOL CDumpCatch::RemoveExceptionHandle()
  191. {
  192. if (m_preFilter != NULL)
  193. {
  194. ::SetUnhandledExceptionFilter(m_preFilter);
  195. m_preFilter = NULL;
  196. }
  197. return TRUE;
  198. }
  199. CDumpCatch::CDumpCatch()
  200. {
  201. SetInvalidHandle();
  202. AddExceptionHandle();
  203. }
  204. CDumpCatch::~CDumpCatch()
  205. {
  206. UnSetInvalidHandle();
  207. RemoveExceptionHandle();
  208. }
  209. BOOL CDumpCatch::ReleaseDumpFile(const std::string& strPath, EXCEPTION_POINTERS* pException)
  210. {
  211. HANDLE hDumpFile = ::CreateFile(strPath.c_str(), GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
  212. if (hDumpFile == INVALID_HANDLE_VALUE)
  213. {
  214. return FALSE;
  215. }
  216. MINIDUMP_EXCEPTION_INFORMATION dumpInfo;
  217. dumpInfo.ExceptionPointers = pException;
  218. dumpInfo.ThreadId = ::GetCurrentThreadId();
  219. dumpInfo.ClientPointers = TRUE;
  220. // ::MiniDumpWriteDump(::GetCurrentProcess(), ::GetCurrentProcessId(), hDumpFile, MiniDumpNormal, &dumpInfo, NULL, NULL);
  221. BOOL bRet = ::MiniDumpWriteDump(::GetCurrentProcess(), ::GetCurrentProcessId(), hDumpFile, MiniDumpWithFullMemory, &dumpInfo, NULL, NULL);
  222. ::CloseHandle(hDumpFile);
  223. return bRet;
  224. }
  225. #include <spdlog/fmt/fmt.h>
  226. LONG WINAPI CDumpCatch::UnhandledExceptionFilterEx(struct _EXCEPTION_POINTERS* pException)
  227. {
  228. char szPath[MAX_PATH] = { 0 };
  229. ::GetModuleFileName(NULL, szPath, MAX_PATH);
  230. ::PathRemoveFileSpec(szPath);
  231. SYSTEMTIME st;
  232. GetLocalTime(&st);
  233. std::string strPath = fmt::format("{}\\DataCenter_{}_{:0>4}{:0>2}{:0>2}_{:0>2}{:0>2}{:0>2}.dmp",
  234. szPath, g_strVersion, st.wYear, st.wMonth, st.wDay, st.wHour, st.wMinute, st.wSecond);
  235. SPDLOG_CRITICAL("异常崩溃:{} 版本:{}", strPath, g_strVersion);
  236. BOOL bRelease = ReleaseDumpFile(strPath.c_str(), pException);
  237. //::FatalAppExit(0, L"Error");
  238. if (bRelease)
  239. {
  240. return EXCEPTION_EXECUTE_HANDLER;
  241. }
  242. return EXCEPTION_CONTINUE_SEARCH;
  243. }
  244. BOOL CDumpCatch::PreventSetUnhandledExceptionFilter()
  245. {
  246. HMODULE hKernel32 = LoadLibrary("kernel32.dll");
  247. if (hKernel32 == NULL)
  248. {
  249. return FALSE;
  250. }
  251. void* pOrgEntry = ::GetProcAddress(hKernel32, "SetUnhandledExceptionFilter");
  252. if (pOrgEntry == NULL)
  253. {
  254. return FALSE;
  255. }
  256. unsigned char newJump[5];
  257. DWORD dwOrgEntryAddr = (DWORD)pOrgEntry;
  258. dwOrgEntryAddr += 5; //jump instruction has 5 byte space.
  259. void* pNewFunc = &TempSetUnhandledExceptionFilter;
  260. DWORD dwNewEntryAddr = (DWORD)pNewFunc;
  261. DWORD dwRelativeAddr = dwNewEntryAddr - dwOrgEntryAddr;
  262. newJump[0] = 0xE9; //jump
  263. memcpy(&newJump[1], &dwRelativeAddr, sizeof(DWORD));
  264. SIZE_T bytesWritten;
  265. DWORD dwOldFlag, dwTempFlag;
  266. ::VirtualProtect(pOrgEntry, 5, PAGE_READWRITE, &dwOldFlag);
  267. BOOL bRet = ::WriteProcessMemory(::GetCurrentProcess(), pOrgEntry, newJump, 5, &bytesWritten);
  268. ::VirtualProtect(pOrgEntry, 5, dwOldFlag, &dwTempFlag);
  269. return bRet;
  270. }
  271. long __stdcall callback(_EXCEPTION_POINTERS* excp)
  272. {
  273. //CString strLog;
  274. //strLog.Format("Error address %x\r\nCPU register:\r\neax %x ebx %x ecx %x edx %x\r\n",
  275. // excp->ExceptionRecord->ExceptionAddress, excp->ContextRecord->Eax, excp->ContextRecord->Ebx,excp->ContextRecord->Ecx,
  276. // excp->ContextRecord->Edx);
  277. SPDLOG_CRITICAL("异常,程序退出 {}", g_strVersion);
  278. exit(0);
  279. return EXCEPTION_EXECUTE_HANDLER;
  280. }
  281. // CTimeSyncServerApp 初始化
  282. BOOL CTimeSyncServerApp::InitInstance()
  283. {
  284. // 如果一个运行在 Windows XP 上的应用程序清单指定要
  285. // 使用 ComCtl32.dll 版本 6 或更高版本来启用可视化方式,
  286. //则需要 InitCommonControlsEx()。 否则,将无法创建窗口。
  287. INITCOMMONCONTROLSEX InitCtrls;
  288. InitCtrls.dwSize = sizeof(InitCtrls);
  289. // 将它设置为包括所有要在应用程序中使用的
  290. // 公共控件类。
  291. InitCtrls.dwICC = ICC_WIN95_CLASSES;
  292. InitCommonControlsEx(&InitCtrls);
  293. CWinApp::InitInstance();
  294. if (!AfxSocketInit())
  295. {
  296. AfxMessageBox(IDP_SOCKETS_INIT_FAILED);
  297. return FALSE;
  298. }
  299. AfxEnableControlContainer();
  300. // 创建 shell 管理器,以防对话框包含
  301. // 任何 shell 树视图控件或 shell 列表视图控件。
  302. CShellManager *pShellManager = new CShellManager;
  303. // 激活“Windows Native”视觉管理器,以便在 MFC 控件中启用主题
  304. CMFCVisualManager::SetDefaultManager(RUNTIME_CLASS(CMFCVisualManagerWindows));
  305. // 标准初始化
  306. // 如果未使用这些功能并希望减小
  307. // 最终可执行文件的大小,则应移除下列
  308. // 不需要的特定初始化例程
  309. // 更改用于存储设置的注册表项
  310. // TODO: 应适当修改该字符串,
  311. // 例如修改为公司或组织名
  312. SetRegistryKey(_T("应用程序向导生成的本地应用程序"));
  313. HANDLE hMutex = ::CreateMutex(NULL, FALSE, "DataCenter");
  314. if (GetLastError() == ERROR_ALREADY_EXISTS)
  315. ::TerminateProcess((HANDLE)-1, 0);
  316. std::string strParam = R"(netsh advfirewall firewall delete rule name="DataCenter" dir=in & netsh advfirewall firewall add rule name="DataCenter" dir=in protocol=tcp localport=10086,10088,10089,10090,21006,21008 action=allow)";
  317. hjfunc_CmdExecParam(strParam, 1, SW_HIDE);
  318. //日志初始化
  319. CSpdlogMng::Instance()->InitLog("DataCenter");
  320. //SPDLOG_DEBUG("debug");
  321. //SPDLOG_INFO("info");
  322. //SPDLOG_ERROR("error");
  323. //SPDLOG_CRITICAL("critical");
  324. //启动服务(两种方式:双击运行和SCM启动,执行流程如刚开始提到的那样),对话框在下面显示
  325. SERVICE_TABLE_ENTRY DispatchTable[] = { { "DataCenter",ServiceMain },{ NULL,NULL } };
  326. //StartServiceCtrlDispatcher(DispatchTable);
  327. if (!StartServiceCtrlDispatcher(DispatchTable))
  328. {
  329. SPDLOG_INFO("当不是用SCM启动程序的时候,程序执行下面的代码");
  330. std::thread th(CTimeSyncServerApp::StartTheAppServices, 3);
  331. th.detach();
  332. CTimeSyncServerDlg dlg;
  333. //m_pMainWnd = &dlg;
  334. int nResponse = dlg.DoModal();
  335. if (nResponse == IDOK)
  336. {
  337. // TODO: Place code here to handle when the dialog is
  338. // dismissed with OK
  339. }
  340. else if (nResponse == IDCANCEL)
  341. {
  342. // TODO: Place code here to handle when the dialog is
  343. // dismissed with Cancel
  344. }
  345. }
  346. // 删除上面创建的 shell 管理器。
  347. if (pShellManager != NULL)
  348. {
  349. delete pShellManager;
  350. }
  351. #ifndef _AFXDLL
  352. ControlBarCleanUp();
  353. #endif
  354. // 由于对话框已关闭,所以将返回 FALSE 以便退出应用程序,
  355. // 而不是启动应用程序的消息泵。
  356. return FALSE;
  357. }
  358. void CTimeSyncServerApp::StartTheAppServices(WORD seconds)
  359. {
  360. for (auto i = 0; i < seconds; i++)
  361. std::this_thread::sleep_for(std::chrono::seconds(1));
  362. if (CAppService::Instance()->Start())
  363. {
  364. }
  365. else
  366. {
  367. SPDLOG_CRITICAL("启动失败.程序退出");
  368. ::TerminateProcess((HANDLE)-1, 0);
  369. }
  370. }