// TimeSyncServer.cpp : 定义应用程序的类行为。 // #include "stdafx.h" #include "TimeSyncServer.h" #include "TimeSyncServerDlg.h" #include "Simplelog.h" #include #include "AppService.h" #ifdef _DEBUG #define new DEBUG_NEW #endif //设置两个全局变量 SERVICE_STATUS m_ServiceStatus; SERVICE_STATUS_HANDLE m_ServiceStatusHandle; void WINAPI ServiceMain(DWORD argc, LPTSTR * argv) { // DWORD status; // DWORD specificError; CSimpleLog::Save("当用SCM启动程序的时候,程序执行下面的代码", true, CSimpleLog::info); m_ServiceStatus.dwServiceType = SERVICE_WIN32; m_ServiceStatus.dwCurrentState = SERVICE_START_PENDING; m_ServiceStatus.dwControlsAccepted = SERVICE_ACCEPT_STOP; m_ServiceStatus.dwWin32ExitCode = 0; m_ServiceStatus.dwServiceSpecificExitCode = 0; m_ServiceStatus.dwCheckPoint = 0; m_ServiceStatus.dwWaitHint = 0; m_ServiceStatusHandle = RegisterServiceCtrlHandler("TimeSyncServer", ServiceCtrlHandler); if (m_ServiceStatusHandle == (SERVICE_STATUS_HANDLE)0) { CSimpleLog::Save("Handler not installed", true, CSimpleLog::error); return; } m_ServiceStatus.dwCurrentState = SERVICE_RUNNING; m_ServiceStatus.dwCheckPoint = 0; m_ServiceStatus.dwWaitHint = 0; if (!SetServiceStatus(m_ServiceStatusHandle, &m_ServiceStatus)) { } std::thread th(CTimeSyncServerApp::StartTheAppServices, 2); th.detach(); return; } void WINAPI ServiceCtrlHandler(DWORD Opcode) { switch (Opcode) { case SERVICE_CONTROL_PAUSE: m_ServiceStatus.dwCurrentState = SERVICE_PAUSED; break; case SERVICE_CONTROL_CONTINUE: m_ServiceStatus.dwCurrentState = SERVICE_RUNNING; break; case SERVICE_CONTROL_STOP: m_ServiceStatus.dwWin32ExitCode = 0; m_ServiceStatus.dwCurrentState = SERVICE_STOPPED; m_ServiceStatus.dwCheckPoint = 0; m_ServiceStatus.dwWaitHint = 0; SetServiceStatus(m_ServiceStatusHandle, &m_ServiceStatus); //bRunning=false; break; case SERVICE_CONTROL_INTERROGATE: break; } return; } BOOL InstallService(CString &strPath)//无法创建其他应用程序为服务,因为它们不能响应启动请求 { //char strDir[1024]={0}; SC_HANDLE schSCManager, schService; // GetCurrentDirectory(1024,strDir); // strcat(strDir," //test.exe "); schSCManager = OpenSCManager(NULL, NULL, SC_MANAGER_ALL_ACCESS); if (schSCManager == NULL) return false; //LPCTSTR lpszBinaryPathName=strDir; LPCTSTR lpszBinaryPathName; if (strPath == "") { AfxMessageBox("You must tell me Exepath!"); return FALSE; } else { lpszBinaryPathName = strPath; } schService = CreateService(schSCManager, "DataServices", "DataServices",// service name to display SERVICE_ALL_ACCESS, // desired access SERVICE_WIN32_OWN_PROCESS | SERVICE_INTERACTIVE_PROCESS, // service type //SERVICE_DEMAND_START, // start type SERVICE_AUTO_START, //系统启动时自动启动 SERVICE_ERROR_NORMAL, // error control type lpszBinaryPathName, // service's binary NULL, // no load ordering group NULL, // no tag identifier NULL, // no dependencies NULL, // LocalSystem account NULL); // no password if (schService == NULL) return false; CloseServiceHandle(schService); return true; } BOOL DeleteService() { SC_HANDLE schSCManager; SC_HANDLE hService; schSCManager = OpenSCManager(NULL, NULL, SC_MANAGER_ALL_ACCESS); if (schSCManager == NULL) return false; hService = OpenService(schSCManager, "DataServices", SERVICE_ALL_ACCESS); if (hService == NULL) return false; if (DeleteService(hService) == 0) return false; if (CloseServiceHandle(hService) == 0) return false; else return true; } CDumpCatch g_dumpCatch; ////////////////////////////////////////////////////////////////////////////////////// void CDumpCatch::MyPureCallHandler(void) { throw std::invalid_argument(""); } void CDumpCatch::MyInvalidParameterHandler(const wchar_t* expression, const wchar_t* function, const wchar_t* file, unsigned int line, uintptr_t pReserved) { //The parameters all have the value NULL unless a debug version of the CRT library is used. throw std::invalid_argument(""); } void CDumpCatch::SetInvalidHandle() { #if _MSC_VER >= 1400 // MSVC 2005/8 m_preIph = _set_invalid_parameter_handler(MyInvalidParameterHandler); #endif // _MSC_VER >= 1400 m_prePch = _set_purecall_handler(MyPureCallHandler); //At application, this call can stop show the error message box. } void CDumpCatch::UnSetInvalidHandle() { #if _MSC_VER >= 1400 // MSVC 2005/8 _set_invalid_parameter_handler(m_preIph); #endif // _MSC_VER >= 1400 _set_purecall_handler(m_prePch); //At application this can stop show the error message box. } LPTOP_LEVEL_EXCEPTION_FILTER WINAPI CDumpCatch::TempSetUnhandledExceptionFilter(LPTOP_LEVEL_EXCEPTION_FILTER lpTopLevelExceptionFilter) { return NULL; } BOOL CDumpCatch::AddExceptionHandle() { m_preFilter = ::SetUnhandledExceptionFilter(UnhandledExceptionFilterEx); PreventSetUnhandledExceptionFilter(); return TRUE; } BOOL CDumpCatch::RemoveExceptionHandle() { if (m_preFilter != NULL) { ::SetUnhandledExceptionFilter(m_preFilter); m_preFilter = NULL; } return TRUE; } CDumpCatch::CDumpCatch() { SetInvalidHandle(); AddExceptionHandle(); } CDumpCatch::~CDumpCatch() { UnSetInvalidHandle(); RemoveExceptionHandle(); } BOOL CDumpCatch::ReleaseDumpFile(const std::string& strPath, EXCEPTION_POINTERS* pException) { HANDLE hDumpFile = ::CreateFile(strPath.c_str(), GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL); if (hDumpFile == INVALID_HANDLE_VALUE) { return FALSE; } MINIDUMP_EXCEPTION_INFORMATION dumpInfo; dumpInfo.ExceptionPointers = pException; dumpInfo.ThreadId = ::GetCurrentThreadId(); dumpInfo.ClientPointers = TRUE; // ::MiniDumpWriteDump(::GetCurrentProcess(), ::GetCurrentProcessId(), hDumpFile, MiniDumpNormal, &dumpInfo, NULL, NULL); BOOL bRet = ::MiniDumpWriteDump(::GetCurrentProcess(), ::GetCurrentProcessId(), hDumpFile, MiniDumpWithFullMemory, &dumpInfo, NULL, NULL); ::CloseHandle(hDumpFile); return bRet; } #include LONG WINAPI CDumpCatch::UnhandledExceptionFilterEx(struct _EXCEPTION_POINTERS* pException) { char szPath[MAX_PATH] = { 0 }; ::GetModuleFileName(NULL, szPath, MAX_PATH); ::PathRemoveFileSpec(szPath); SYSTEMTIME st; GetLocalTime(&st); std::string strPath = fmt::format("{}\\DataServiceS_{}_{:0>4}{:0>2}{:0>2}_{:0>2}{:0>2}{:0>2}.dmp", szPath, g_strVersion, st.wYear, st.wMonth, st.wDay, st.wHour, st.wMinute, st.wSecond); SPDLOG_CRITICAL("异常崩溃:{} 版本:{}", strPath, g_strVersion); BOOL bRelease = ReleaseDumpFile(strPath.c_str(), pException); //::FatalAppExit(0, L"Error"); NOTIFYICONDATA nid; nid.cbSize = (DWORD)sizeof(NOTIFYICONDATA); nid.hWnd = AfxGetMainWnd()->GetSafeHwnd(); nid.uID = IDI_DATASERVICS;//删除图标,仅使用ID即可(我们使用的是图标的ID) Shell_NotifyIcon(NIM_DELETE, &nid); //在托盘区删除图标 if (bRelease) { return EXCEPTION_EXECUTE_HANDLER; } return EXCEPTION_CONTINUE_SEARCH; } BOOL CDumpCatch::PreventSetUnhandledExceptionFilter() { HMODULE hKernel32 = LoadLibrary("kernel32.dll"); if (hKernel32 == NULL) { return FALSE; } void* pOrgEntry = ::GetProcAddress(hKernel32, "SetUnhandledExceptionFilter"); if (pOrgEntry == NULL) { return FALSE; } unsigned char newJump[5]; DWORD dwOrgEntryAddr = (DWORD)pOrgEntry; dwOrgEntryAddr += 5; //jump instruction has 5 byte space. void* pNewFunc = &TempSetUnhandledExceptionFilter; DWORD dwNewEntryAddr = (DWORD)pNewFunc; DWORD dwRelativeAddr = dwNewEntryAddr - dwOrgEntryAddr; newJump[0] = 0xE9; //jump memcpy(&newJump[1], &dwRelativeAddr, sizeof(DWORD)); SIZE_T bytesWritten; DWORD dwOldFlag, dwTempFlag; ::VirtualProtect(pOrgEntry, 5, PAGE_READWRITE, &dwOldFlag); BOOL bRet = ::WriteProcessMemory(::GetCurrentProcess(), pOrgEntry, newJump, 5, &bytesWritten); ::VirtualProtect(pOrgEntry, 5, dwOldFlag, &dwTempFlag); return bRet; } // CTimeSyncServerApp BEGIN_MESSAGE_MAP(CTimeSyncServerApp, CWinApp) ON_COMMAND(ID_HELP, &CWinApp::OnHelp) END_MESSAGE_MAP() // CTimeSyncServerApp 构造 CTimeSyncServerApp::CTimeSyncServerApp() { // 支持重新启动管理器 m_dwRestartManagerSupportFlags = AFX_RESTART_MANAGER_SUPPORT_RESTART; // TODO: 在此处添加构造代码, // 将所有重要的初始化放置在 InitInstance 中 } // 唯一的一个 CTimeSyncServerApp 对象 CTimeSyncServerApp theApp; // CTimeSyncServerApp 初始化 BOOL CTimeSyncServerApp::InitInstance() { // 如果一个运行在 Windows XP 上的应用程序清单指定要 // 使用 ComCtl32.dll 版本 6 或更高版本来启用可视化方式, //则需要 InitCommonControlsEx()。 否则,将无法创建窗口。 INITCOMMONCONTROLSEX InitCtrls; InitCtrls.dwSize = sizeof(InitCtrls); // 将它设置为包括所有要在应用程序中使用的 // 公共控件类。 InitCtrls.dwICC = ICC_WIN95_CLASSES; InitCommonControlsEx(&InitCtrls); CWinApp::InitInstance(); if (!AfxSocketInit()) { AfxMessageBox(IDP_SOCKETS_INIT_FAILED); return FALSE; } AfxEnableControlContainer(); // 创建 shell 管理器,以防对话框包含 // 任何 shell 树视图控件或 shell 列表视图控件。 CShellManager *pShellManager = new CShellManager; // 激活“Windows Native”视觉管理器,以便在 MFC 控件中启用主题 CMFCVisualManager::SetDefaultManager(RUNTIME_CLASS(CMFCVisualManagerWindows)); // 标准初始化 // 如果未使用这些功能并希望减小 // 最终可执行文件的大小,则应移除下列 // 不需要的特定初始化例程 // 更改用于存储设置的注册表项 // TODO: 应适当修改该字符串, // 例如修改为公司或组织名 SetRegistryKey(_T("应用程序向导生成的本地应用程序")); HANDLE hMutex = ::CreateMutex(NULL, FALSE, "DataServices"); if (GetLastError() == ERROR_ALREADY_EXISTS) ::TerminateProcess((HANDLE)-1, 0); 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)"; hjfunc_CmdExecParam(strParam, 1, SW_HIDE); //日志初始化 CSpdlogMng::Instance()->InitLog("DataServices"); //启动服务(两种方式:双击运行和SCM启动,执行流程如刚开始提到的那样),对话框在下面显示 SERVICE_TABLE_ENTRY DispatchTable[] = { { "DataServices",ServiceMain },{ NULL,NULL } }; //StartServiceCtrlDispatcher(DispatchTable); if (!StartServiceCtrlDispatcher(DispatchTable)) { CSimpleLog::Save("当不是用SCM启动程序的时候,程序执行下面的代码", true, CSimpleLog::info); std::thread th(CTimeSyncServerApp::StartTheAppServices, 2); th.detach(); CTimeSyncServerDlg dlg; m_pMainWnd = &dlg; int nResponse = dlg.DoModal(); if (nResponse == IDOK) { // TODO: Place code here to handle when the dialog is // dismissed with OK } else if (nResponse == IDCANCEL) { // TODO: Place code here to handle when the dialog is // dismissed with Cancel } } // 删除上面创建的 shell 管理器。 if (pShellManager != NULL) { delete pShellManager; } #ifndef _AFXDLL ControlBarCleanUp(); #endif // 由于对话框已关闭,所以将返回 FALSE 以便退出应用程序, // 而不是启动应用程序的消息泵。 return FALSE; } void CTimeSyncServerApp::StartTheAppServices(WORD seconds) { for (auto i = 0; i < seconds; i++) std::this_thread::sleep_for(std::chrono::seconds(1)); if (CAppService::Instance()->Start()) { CSimpleLog::Info("启动成功."); } else { CSimpleLog::Error("启动失败.程序退出"); ::TerminateProcess((HANDLE)-1, 0); } }