TimeSyncServer.cpp 12 KB

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