// 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") BOOL ServerPair::StartServer(pfnNotifyProc NotifyProc, pfnOfflineProc OffProc, USHORT uPort) { UINT ret1 = m_tcpServer->StartServer(NotifyProc, OffProc, uPort); if (ret1) THIS_APP->MessageBox(CString("启动TCP服务失败: ") + std::to_string(uPort).c_str() + CString("。错误码: ") + std::to_string(ret1).c_str(), "提示", MB_ICONINFORMATION); UINT ret2 = m_udpServer->StartServer(NotifyProc, OffProc, uPort); if (ret2) THIS_APP->MessageBox(CString("启动UDP服务失败: ") + std::to_string(uPort).c_str() + CString("。错误码: ") + std::to_string(ret2).c_str(), "提示", MB_ICONINFORMATION); return (ret1 == 0 || ret2 == 0); } 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; // 处理服务相关的命令行参数 // 返回值: TRUE 表示已处理服务命令(程序应退出),FALSE 表示继续正常启动 static BOOL HandleServiceCommandLine() { CString cmdLine = ::GetCommandLine(); cmdLine.MakeLower(); // -service: 作为服务运行 if (cmdLine.Find(_T("-service")) != -1) { int r = ServerService_Run(); Mprintf("[HandleServiceCommandLine] ServerService_Run %s", r ? "failed" : "succeed"); return TRUE; } // -install: 安装服务 if (cmdLine.Find(_T("-install")) != -1) { BOOL r = ServerService_Install(); Mprintf("[HandleServiceCommandLine] ServerService_Install %s", !r ? "failed" : "succeed"); return TRUE; } // -uninstall: 卸载服务 if (cmdLine.Find(_T("-uninstall")) != -1) { BOOL r = ServerService_Uninstall(); Mprintf("[HandleServiceCommandLine] ServerService_Uninstall %s", !r ? "failed" : "succeed"); return TRUE; } // -agent: 由服务启动的GUI代理模式 // 此模式下正常运行GUI,但使用不同的互斥量名称避免冲突 if (cmdLine.Find(_T("-agent")) != -1) { // 继续正常启动GUI,但标记为代理模式 Mprintf("[HandleServiceCommandLine] Run service agent: '%s'", cmdLine.GetString()); return FALSE; } // 无参数时,作为服务启动 BOOL registered = FALSE; BOOL running = FALSE; char servicePath[MAX_PATH] = { 0 }; BOOL r = ServerService_CheckStatus(®istered, &running, servicePath, MAX_PATH); Mprintf("[HandleServiceCommandLine] ServerService_CheckStatus %s", !r ? "failed" : "succeed"); char curPath[MAX_PATH]; GetModuleFileNameA(NULL, curPath, MAX_PATH); _strlwr(servicePath); _strlwr(curPath); BOOL same = (strstr(servicePath, curPath) != 0); if (registered && !same) { BOOL r = ServerService_Uninstall(); Mprintf("[HandleServiceCommandLine] ServerService Uninstall %s: %s\n", r ? "succeed" : "failed", servicePath); registered = FALSE; } if (!registered) { BOOL r = ServerService_Install(); Mprintf("[HandleServiceCommandLine] ServerService Install: %s\n", r ? "succeed" : "failed", curPath); return r; } else if (!running) { int r = ServerService_Run(); Mprintf("[HandleServiceCommandLine] ServerService Run '%s' %s\n", curPath, r == ERROR_SUCCESS ? "succeed" : "failed"); if (r) { r = ServerService_StartSimple(); Mprintf("[HandleServiceCommandLine] ServerService Start '%s' %s\n", curPath, r == ERROR_SUCCESS ? "succeed" : "failed"); return r == ERROR_SUCCESS; } return TRUE; } return TRUE; } // 检查是否以代理模式运行 static BOOL IsAgentMode() { CString cmdLine = ::GetCommandLine(); cmdLine.MakeLower(); return cmdLine.Find(_T("-agent")) != -1; } // CMy2015RemoteApp 初始化 BOOL IsRunningAsAdmin() { BOOL isAdmin = FALSE; PSID administratorsGroup = NULL; SID_IDENTIFIER_AUTHORITY NtAuthority = SECURITY_NT_AUTHORITY; if (AllocateAndInitializeSid(&NtAuthority, 2, SECURITY_BUILTIN_DOMAIN_RID, DOMAIN_ALIAS_RID_ADMINS, 0, 0, 0, 0, 0, 0, &administratorsGroup)) { if (!CheckTokenMembership(NULL, administratorsGroup, &isAdmin)) { isAdmin = FALSE; } FreeSid(administratorsGroup); } return isAdmin; } BOOL LaunchAsAdmin(const char* szFilePath, const char* verb) { SHELLEXECUTEINFOA shExecInfo; ZeroMemory(&shExecInfo, sizeof(SHELLEXECUTEINFOA)); shExecInfo.cbSize = sizeof(SHELLEXECUTEINFOA); shExecInfo.fMask = SEE_MASK_DEFAULT; shExecInfo.hwnd = NULL; shExecInfo.lpVerb = verb; shExecInfo.lpFile = szFilePath; shExecInfo.nShow = SW_NORMAL; return ShellExecuteExA(&shExecInfo); } BOOL CMy2015RemoteApp::InitInstance() { char curFile[MAX_PATH] = { 0 }; GetModuleFileNameA(NULL, curFile, MAX_PATH); if (!IsRunningAsAdmin() && LaunchAsAdmin(curFile, "runas")) { Mprintf("[InitInstance] 程序没有管理员权限,用户选择以管理员身份重新运行。"); return FALSE; } // 首先处理服务命令行参数 if (HandleServiceCommandLine()) { Mprintf("[InitInstance] 服务命令已处理,退出。"); 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; MessageBox("一个主控程序已经在运行,请检查任务管理器。", "提示", MB_ICONINFORMATION); Mprintf("[InitInstance] 一个主控程序已经在运行,退出。"); return FALSE; } } #endif Mprintf("[InitInstance] 主控程序启动运行。"); 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(); Mprintf("[InitInstance] 主控程序为代理模式,停止服务。"); } Mprintf("[InitInstance] 主控程序退出运行。"); return CWinApp::ExitInstance(); }