// 2015Remote.cpp : 定义应用程序的类行为。 // #include "stdafx.h" #include "2015Remote.h" #include "SplashDlg.h" #include "2015RemoteDlg.h" #ifdef _DEBUG #define new DEBUG_NEW #endif // dump相关 #include #include #include #include "IOCPUDPServer.h" #include "ServerServiceWrapper.h" #pragma comment(lib, "Dbghelp.lib") CMy2015RemoteApp* GetThisApp() { return ((CMy2015RemoteApp*)AfxGetApp()); } config& GetThisCfg() { config *cfg = GetThisApp()->GetCfg(); return *cfg; } std::string GetMasterHash() { static std::string hash(skCrypt(MASTER_HASH)); return hash; } /** * @brief 程序遇到未知BUG导致终止时调用此函数,不弹框 * 并且转储dump文件到dump目录. */ long WINAPI whenbuged(_EXCEPTION_POINTERS *excp) { // 获取dump文件夹,若不存在,则创建之 char dumpDir[_MAX_PATH]; char dumpFile[_MAX_PATH + 64]; if (!GetModuleFileNameA(NULL, dumpDir, _MAX_PATH)) { return EXCEPTION_EXECUTE_HANDLER; } char* p = strrchr(dumpDir, '\\'); if (p) { strcpy_s(p + 1, _MAX_PATH - (p - dumpDir + 1), "dump"); } else { strcpy_s(dumpDir, _MAX_PATH, "dump"); } if (_access(dumpDir, 0) == -1) _mkdir(dumpDir); // 构建完整的dump文件路径 char curTime[64]; time_t TIME = time(0); struct tm localTime; localtime_s(&localTime, &TIME); strftime(curTime, sizeof(curTime), "\\YAMA_%Y-%m-%d %H%M%S.dmp", &localTime); sprintf_s(dumpFile, sizeof(dumpFile), "%s%s", dumpDir, curTime); HANDLE hFile = ::CreateFileA(dumpFile, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL); if(INVALID_HANDLE_VALUE != hFile) { MINIDUMP_EXCEPTION_INFORMATION einfo = {::GetCurrentThreadId(), excp, FALSE}; ::MiniDumpWriteDump(::GetCurrentProcess(), ::GetCurrentProcessId(), hFile, MiniDumpWithFullMemory, &einfo, NULL, NULL); ::CloseHandle(hFile); } return EXCEPTION_EXECUTE_HANDLER; } // CMy2015RemoteApp BEGIN_MESSAGE_MAP(CMy2015RemoteApp, CWinApp) ON_COMMAND(ID_HELP, &CWinApp::OnHelp) END_MESSAGE_MAP() std::string GetPwdHash(); // CMy2015RemoteApp 构造 CMy2015RemoteApp::CMy2015RemoteApp() { // 支持重新启动管理器 m_dwRestartManagerSupportFlags = AFX_RESTART_MANAGER_SUPPORT_RESTART; // TODO: 在此处添加构造代码, // 将所有重要的初始化放置在 InitInstance 中 m_Mutex = NULL; #ifdef _DEBUG std::string masterHash(GetMasterHash()); m_iniFile = GetPwdHash() == masterHash ? new config : new iniFile; #else m_iniFile = new iniFile; #endif srand(static_cast(time(0))); } // 唯一的一个 CMy2015RemoteApp 对象 CMy2015RemoteApp theApp; // 从服务路径中提取可执行文件路径(去除引号和参数) static void ExtractExePathFromServicePath(const char* servicePath, char* exePath, size_t exePathSize) { if (!servicePath || !exePath || exePathSize == 0) { if (exePath && exePathSize > 0) exePath[0] = '\0'; return; } const char* src = servicePath; char* dst = exePath; size_t remaining = exePathSize - 1; // 跳过前导空格 while (*src == ' ') src++; if (*src == '"') { // 带引号的路径:提取引号内的内容 src++; // 跳过开始引号 while (*src && *src != '"' && remaining > 0) { *dst++ = *src++; remaining--; } } else { // 不带引号的路径:提取到空格或结束 while (*src && *src != ' ' && remaining > 0) { *dst++ = *src++; remaining--; } } *dst = '\0'; } // 处理服务相关的命令行参数 // 返回值: TRUE 表示已处理服务命令(程序应退出),FALSE 表示继续正常启动 static BOOL HandleServiceCommandLine() { CString cmdLine = ::GetCommandLine(); cmdLine.MakeLower(); // -service: 作为服务运行 if (cmdLine.Find(_T("-service")) != -1) { ServerService_Run(); return TRUE; } // -install: 安装服务 if (cmdLine.Find(_T("-install")) != -1) { ServerService_Install(); return TRUE; } // -uninstall: 卸载服务 if (cmdLine.Find(_T("-uninstall")) != -1) { ServerService_Uninstall(); return TRUE; } // -agent: 由服务启动的GUI代理模式 // 此模式下正常运行GUI,但使用不同的互斥量名称避免冲突 if (cmdLine.Find(_T("-agent")) != -1) { // 继续正常启动GUI,但标记为代理模式 return FALSE; } // 无参数时,作为服务启动 BOOL registered = FALSE; BOOL running = FALSE; char servicePath[MAX_PATH] = { 0 }; ServerService_CheckStatus(®istered, &running, servicePath, MAX_PATH); char curPath[MAX_PATH]; GetModuleFileNameA(NULL, curPath, MAX_PATH); // 从服务路径中提取纯可执行文件路径(去除引号和参数) char serviceExePath[MAX_PATH] = { 0 }; ExtractExePathFromServicePath(servicePath, serviceExePath, MAX_PATH); if (registered && _stricmp(curPath, serviceExePath) != 0) { Mprintf("ServerService Uninstall: %s\n", servicePath); ServerService_Uninstall(); registered = FALSE; } if (!registered) { Mprintf("ServerService Install: %s\n", curPath); return ServerService_Install(); } else if (!running) { int r = ServerService_Run(); Mprintf("ServerService Run '%s' %s\n", curPath, r == ERROR_SUCCESS ? "succeed" : "failed"); if (r) { r = ServerService_StartSimple(); Mprintf("ServerService Start '%s' %s\n", curPath, r == ERROR_SUCCESS ? "succeed" : "failed"); return r == ERROR_SUCCESS; } return FALSE; } return TRUE; } // 检查是否以代理模式运行 static BOOL IsAgentMode() { CString cmdLine = ::GetCommandLine(); cmdLine.MakeLower(); return cmdLine.Find(_T("-agent")) != -1; } // CMy2015RemoteApp 初始化 BOOL CMy2015RemoteApp::InitInstance() { // 首先处理服务命令行参数 if (HandleServiceCommandLine()) { return FALSE; // 服务命令已处理,退出 } std::string masterHash(GetMasterHash()); std::string mu = GetPwdHash()==masterHash ? "MASTER.EXE" : "YAMA.EXE"; #ifndef _DEBUG { m_Mutex = CreateMutex(NULL, FALSE, mu.c_str()); if (ERROR_ALREADY_EXISTS == GetLastError()) { CloseHandle(m_Mutex); m_Mutex = NULL; MessageBoxA(NULL, "A master program is already running, please check Task Manager.", "Info", MB_ICONINFORMATION); return FALSE; } } #endif SetUnhandledExceptionFilter(&whenbuged); // 创建并显示启动画面 CSplashDlg* pSplash = new CSplashDlg(); pSplash->Create(NULL); pSplash->UpdateProgressDirect(5, _T("正在初始化系统图标...")); SHFILEINFO sfi = {}; HIMAGELIST hImageList = (HIMAGELIST)SHGetFileInfo((LPCTSTR)_T(""), 0, &sfi, sizeof(SHFILEINFO), SHGFI_LARGEICON | SHGFI_SYSICONINDEX); m_pImageList_Large.Attach(hImageList); hImageList = (HIMAGELIST)SHGetFileInfo((LPCTSTR)_T(""), 0, &sfi, sizeof(SHFILEINFO), SHGFI_SMALLICON | SHGFI_SYSICONINDEX); m_pImageList_Small.Attach(hImageList); pSplash->UpdateProgressDirect(10, _T("正在初始化公共控件...")); // 如果一个运行在 Windows XP 上的应用程序清单指定要 // 使用 ComCtl32.dll 版本 6 或更高版本来启用可视化方式, //则需要 InitCommonControlsEx()。否则,将无法创建窗口。 INITCOMMONCONTROLSEX InitCtrls; InitCtrls.dwSize = sizeof(InitCtrls); // 将它设置为包括所有要在应用程序中使用的 // 公共控件类。 InitCtrls.dwICC = ICC_WIN95_CLASSES; InitCommonControlsEx(&InitCtrls); CWinApp::InitInstance(); AfxEnableControlContainer(); // 创建 shell 管理器,以防对话框包含 // 任何 shell 树视图控件或 shell 列表视图控件。 CShellManager *pShellManager = new CShellManager; // 标准初始化 // 如果未使用这些功能并希望减小 // 最终可执行文件的大小,则应移除下列 // 不需要的特定初始化例程 // 更改用于存储设置的注册表项 // TODO: 应适当修改该字符串, // 例如修改为公司或组织名 SetRegistryKey(_T("YAMA")); CMy2015RemoteDlg dlg(nullptr); m_pMainWnd = &dlg; INT_PTR nResponse = dlg.DoModal(); if (nResponse == IDOK) { // TODO: 在此放置处理何时用 // “确定”来关闭对话框的代码 } else if (nResponse == IDCANCEL) { // TODO: 在此放置处理何时用 // “取消”来关闭对话框的代码 } // 删除上面创建的 shell 管理器。 if (pShellManager != NULL) { delete pShellManager; } // 由于对话框已关闭,所以将返回 FALSE 以便退出应用程序, // 而不是启动应用程序的消息泵。 return FALSE; } int CMy2015RemoteApp::ExitInstance() { if (m_Mutex) { CloseHandle(m_Mutex); m_Mutex = NULL; } __try { Delete(); } __except(EXCEPTION_EXECUTE_HANDLER) { } SAFE_DELETE(m_iniFile); // 只有在代理模式退出时才停止服务 if (IsAgentMode()) { ServerService_Stop(); } return CWinApp::ExitInstance(); }