// MTerm1.cpp: 定义应用程序的类行为。 // #include "pch.h" #include "framework.h" #include "afxwinappex.h" #include "afxdialogex.h" #include "MTerm1.h" #include "MainFrm.h" #include "ChildFrm.h" #include "MTerm1Doc.h" #include "MTerm1View.h" #ifdef _DEBUG #define new DEBUG_NEW #endif #include #include #include #include #pragma comment(lib,"dbghelp.lib") #pragma comment(lib,"gdiplus.lib") #pragma comment(lib,"SetupAPI.lib") MHash MyCfg1; Logger MyLogger1; //KLinkProtocol MyKLProtocol1; // CSerialCom MySerialCom1; //HvSerialPort MyHvSerialPort1; // CMTerm1App BEGIN_MESSAGE_MAP(CMTerm1App, CWinAppEx) ON_COMMAND(ID_APP_ABOUT, &CMTerm1App::OnAppAbout) // 基于文件的标准文档命令 // ON_COMMAND(ID_FILE_NEW, &CWinAppEx::OnFileNew) ON_COMMAND(ID_FILE_NEW, &OnFileNew) ON_COMMAND(ID_FILE_OPEN, &CWinAppEx::OnFileOpen) // 标准打印设置命令 ON_COMMAND(ID_FILE_PRINT_SETUP, &CWinAppEx::OnFilePrintSetup) END_MESSAGE_MAP() // CMTerm1App 构造 CMTerm1App::CMTerm1App() noexcept { m_bHiColorIcons = TRUE; // 支持重新启动管理器 m_dwRestartManagerSupportFlags = AFX_RESTART_MANAGER_SUPPORT_ALL_ASPECTS; #ifdef _MANAGED // 如果应用程序是利用公共语言运行时支持(/clr)构建的,则: // 1) 必须有此附加设置,“重新启动管理器”支持才能正常工作。 // 2) 在您的项目中,您必须按照生成顺序向 System.Windows.Forms 添加引用。 System::Windows::Forms::Application::SetUnhandledExceptionMode(System::Windows::Forms::UnhandledExceptionMode::ThrowException); #endif // TODO: 将以下应用程序 ID 字符串替换为唯一的 ID 字符串;建议的字符串格式 //为 CompanyName.ProductName.SubProduct.VersionInformation SetAppID(_T("MTerm1.AppID.NoVersion")); // TODO: 在此处添加构造代码, // 将所有重要的初始化放置在 InitInstance 中 } // 唯一的 CMTerm1App 对象 CMTerm1App theApp; // CMTerm1App 初始化 BOOL CMTerm1App::InitInstance() { // 如果一个运行在 Windows XP 上的应用程序清单指定要 // 使用 ComCtl32.dll 版本 6 或更高版本来启用可视化方式, //则需要 InitCommonControlsEx()。 否则,将无法创建窗口。 INITCOMMONCONTROLSEX InitCtrls; InitCtrls.dwSize = sizeof(InitCtrls); // 将它设置为包括所有要在应用程序中使用的 // 公共控件类。 InitCtrls.dwICC = ICC_WIN95_CLASSES; InitCommonControlsEx(&InitCtrls); CWinAppEx::InitInstance(); // 初始化 OLE 库 if (!AfxOleInit()) { AfxMessageBox(IDP_OLE_INIT_FAILED); return FALSE; } Gdiplus::GdiplusStartupInput gdiplusStartupInput; Gdiplus::GdiplusStartup(&m_gdiplusToken, &gdiplusStartupInput, NULL); AfxEnableControlContainer(); EnableTaskbarInteraction(); // 使用 RichEdit 控件需要 AfxInitRichEdit2() // AfxInitRichEdit2(); // 标准初始化 // 如果未使用这些功能并希望减小 // 最终可执行文件的大小,则应移除下列 // 不需要的特定初始化例程 // 更改用于存储设置的注册表项 // TODO: 应适当修改该字符串, // 例如修改为公司或组织名 SetRegistryKey(_T("应用程序向导生成的本地应用程序")); LoadStdProfileSettings(4); // 加载标准 INI 文件选项(包括 MRU) InitContextMenuManager(); InitKeyboardManager(); InitTooltipManager(); CMFCToolTipInfo ttParams; ttParams.m_bVislManagerTheme = TRUE; theApp.GetTooltipManager()->SetTooltipParams(AFX_TOOLTIP_TYPE_ALL, RUNTIME_CLASS(CMFCToolTipCtrl), &ttParams); // 注册应用程序的文档模板。 文档模板 // 将用作文档、框架窗口和视图之间的连接 CMultiDocTemplate* pDocTemplate; pDocTemplate = new CMultiDocTemplate(IDR_MTerm1TYPE, RUNTIME_CLASS(CMTerm1Doc), RUNTIME_CLASS(CChildFrame), // 自定义 MDI 子框架 RUNTIME_CLASS(CMTerm1View)); if (!pDocTemplate) return FALSE; AddDocTemplate(pDocTemplate); // 创建主 MDI 框架窗口 CMainFrame* pMainFrame = new CMainFrame; if (!pMainFrame || !pMainFrame->LoadFrame(IDR_MAINFRAME)) { delete pMainFrame; return FALSE; } m_pMainWnd = pMainFrame; // 分析标准 shell 命令、DDE、打开文件操作的命令行 CCommandLineInfo cmdInfo; ParseCommandLine(cmdInfo); // 调度在命令行中指定的命令。 如果 // 用 /RegServer、/Register、/Unregserver 或 /Unregister 启动应用程序,则返回 FALSE。 if (!ProcessShellCommand(cmdInfo)) return FALSE; // 主窗口已初始化,因此显示它并对其进行更新 pMainFrame->ShowWindow(m_nCmdShow); pMainFrame->UpdateWindow(); return TRUE; } int CMTerm1App::ExitInstance() { //TODO: 处理可能已添加的附加资源 Gdiplus::GdiplusShutdown(m_gdiplusToken); // CoUninitialize(); SaveMyConfig(); AfxOleTerm(FALSE); return CWinAppEx::ExitInstance(); } // CMTerm1App 消息处理程序 // 用于应用程序“关于”菜单项的 CAboutDlg 对话框 class CAboutDlg : public CDialogEx { public: CAboutDlg() noexcept; // 对话框数据 #ifdef AFX_DESIGN_TIME enum { IDD = IDD_ABOUTBOX }; #endif protected: virtual void DoDataExchange(CDataExchange* pDX); // DDX/DDV 支持 // 实现 protected: DECLARE_MESSAGE_MAP() }; CAboutDlg::CAboutDlg() noexcept : CDialogEx(IDD_ABOUTBOX) { } void CAboutDlg::DoDataExchange(CDataExchange* pDX) { CDialogEx::DoDataExchange(pDX); } BEGIN_MESSAGE_MAP(CAboutDlg, CDialogEx) END_MESSAGE_MAP() // 用于运行对话框的应用程序命令 void CMTerm1App::OnAppAbout() { CAboutDlg aboutDlg; aboutDlg.DoModal(); } // CMTerm1App 自定义加载/保存方法 void CMTerm1App::PreLoadState() { BOOL bNameValid; CString strName; bNameValid = strName.LoadString(IDS_EDIT_MENU); ASSERT(bNameValid); GetContextMenuManager()->AddMenu(strName, IDR_POPUP_EDIT); bNameValid = strName.LoadString(IDS_EXPLORER); ASSERT(bNameValid); GetContextMenuManager()->AddMenu(strName, IDR_POPUP_EXPLORER); } void CMTerm1App::LoadCustomState() { } void CMTerm1App::SaveCustomState() { } // CMTerm1App 消息处理程序 int SysLog(CString s, int channel) { MyLogger1.LogTxt(s, channel); return 1; } int PopupMessage(CString Msg, int channel) { Msg.Trim(_T("\r\n")); SysLog(_T("报警信息: ") + Msg + _T("\r\n"), channel); return 0; } void DoEvents() { MSG msg; while (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)) { DispatchMessage(&msg); TranslateMessage(&msg); } } void dump_callstack(PCONTEXT pcontext, CString & infostr) { #ifdef _WIN64 STACKFRAME64 sf; memset(&sf, 0, sizeof(STACKFRAME64)); sf.AddrPC.Offset = pcontext->Rip; //context-> sf.AddrPC.Mode = AddrModeFlat; sf.AddrStack.Offset = pcontext->Rsp; sf.AddrStack.Mode = AddrModeFlat; sf.AddrFrame.Offset = pcontext->Rbp; sf.AddrFrame.Mode = AddrModeFlat; DWORD machineType = //IMAGE_FILE_MACHINE_I386; IMAGE_FILE_MACHINE_AMD64; #elif defined _WIN32 STACKFRAME sf; memset(&sf, 0, sizeof(STACKFRAME)); sf.AddrPC.Offset = pcontext->Eip; //context-> sf.AddrPC.Mode = AddrModeFlat; sf.AddrStack.Offset = pcontext->Esp; sf.AddrStack.Mode = AddrModeFlat; sf.AddrFrame.Offset = pcontext->Ebp; sf.AddrFrame.Mode = AddrModeFlat; DWORD machineType = //IMAGE_FILE_MACHINE_I386; IMAGE_FILE_MACHINE_AMD64; #endif HANDLE hProcess = GetCurrentProcess(); HANDLE hThread = GetCurrentThread(); for (;;) { if (!StackWalk(machineType, hProcess, hThread, &sf, pcontext, 0, SymFunctionTableAccess, SymGetModuleBase, 0)) { break; } if (sf.AddrFrame.Offset == 0) { break; } BYTE symbolBuffer[sizeof(SYMBOL_INFO) + 1024]; PSYMBOL_INFO pSymbol = (PSYMBOL_INFO)symbolBuffer; pSymbol->SizeOfStruct = sizeof(symbolBuffer); pSymbol->MaxNameLen = 1024; DWORD64 symDisplacement = 0; if (SymFromAddr(hProcess, sf.AddrPC.Offset, 0, pSymbol)) { printf("Function : %s\n", pSymbol->Name); infostr.AppendFormat(_T("Function : %S \r\n"), pSymbol->Name); } else { printf("SymFromAdd failed!\n"); // infostr.AppendFormat(_T("SymFromAdd failed \r\n"),pSymbol->Name); } DWORD dwLineDisplacement; #ifdef _WIN64 IMAGEHLP_LINEW64 lineInfoW = { sizeof(IMAGEHLP_LINEW64) }; if (SymGetLineFromAddrW(hProcess, sf.AddrPC.Offset, &dwLineDisplacement, &lineInfoW)) { // printf( "[Source File : %s]\n", lineInfo.FileName ); // printf( "[Source Line : %u]\n", lineInfo.LineNumber ); CString s1(lineInfoW.FileName); infostr.AppendFormat(_T("File %s Line %d\r\n"), s1.Mid(s1.ReverseFind(_T('\\')) + 1, 99), lineInfoW.LineNumber); } else { printf("SymGetLineFromAddr failed!\n"); // infostr.Append(_T("SymGetLineFromAddr failed!\r\n")); } #elif defined _WIN32 IMAGEHLP_LINE lineInfo = { sizeof(IMAGEHLP_LINE) }; if (SymGetLineFromAddr(hProcess, sf.AddrPC.Offset, &dwLineDisplacement, &lineInfo)) { // printf( "[Source File : %s]\n", lineInfo.FileName ); // printf( "[Source Line : %u]\n", lineInfo.LineNumber ); CString s1(lineInfo.FileName); infostr.AppendFormat(_T("File %s Line %d\r\n"), s1.Mid(s1.ReverseFind(_T('\\')) + 1, 99), lineInfo.LineNumber); } else { printf("SymGetLineFromAddr failed!\n"); // infostr.Append(_T("SymGetLineFromAddr failed!\r\n")); } #endif } } DWORD excep_filter(LPEXCEPTION_POINTERS lpEP) { /**//// init dbghelp.dll CString s1; if (SymInitialize(GetCurrentProcess(), NULL, TRUE)) { printf("Init dbghelp ok.\n"); } dump_callstack(lpEP->ContextRecord, s1); if (SymCleanup(GetCurrentProcess())) { printf("Cleanup dbghelp ok.\n"); } return EXCEPTION_EXECUTE_HANDLER; } void Trans_Tunc(unsigned int n, EXCEPTION_POINTERS* pExp) { // pExp->ExceptionRecord. // throw SE_Exception(n); CString s1; if (SymInitialize(GetCurrentProcess(), NULL, TRUE)) { printf("Init dbghelp ok.\n"); // s1=_T("Init dbghelp ok.\r\n"); } dump_callstack(pExp->ContextRecord, s1); if (SymCleanup(GetCurrentProcess())) { printf("Cleanup dbghelp ok.\n"); // s1.Append(_T("Cleanup dbghelp ok.\n")); } throw SE_Exception(n, pExp->ExceptionRecord->ExceptionAddress, s1); } int DisplayException(CString File, int Line, CString Func, CString Sentence, SE_Exception &e) { CString Serror; CString s1; s1.Format(_T("程序发生SE异常 代码 %08X 地址 %p \r\nFile: %s \r\nLine: %d \r\nFunc %s \r\n语句 %s \r\n 信息\r\n %s \r\n"), e.getSeNumber(), e.getAddress(), File, Line, Func, Sentence, e.getInfoStr());; PopupMessage(s1); return 0; } int DisplayException(CString File, int Line, CString Func, CString Sentence, CException *e) { CString Serror; CString s1; e->GetErrorMessage(Serror.GetBuffer(256), 256); Serror.ReleaseBuffer(); s1.Format(_T("程序发生C++异常 %s 在File: %s Line: %d Func %s Sentence %s \r\n"), Serror, File, Line, Func, Sentence); PopupMessage(s1); return 0; } int DisplayException(CString File, int Line, CString Func, CString Sentence) { CString s1; s1.Format(_T("程序发生未知错误 File: %s Line: %d Func %s Sentence %s \r\n"), File, Line, Func, Sentence); PopupMessage(s1); return 0; } int LoadMyConfig() { CString ConfigFilePathName; ConfigFilePathName = _T("./Settings.ini"); int j = MyCfg1.LoadFromFile(ConfigFilePathName); return j; } int SaveMyConfig() { CString ConfigFilePathName; ConfigFilePathName = _T("./Settings.ini"); int j = MyCfg1.SaveToFile(ConfigFilePathName); return j; } //得到COMx的名字 //namebuf:用于存放名字的缓冲区 //bufsize:缓冲区大小 //comx:要查找的COM编号.例如:COM1,COM2,COM3.... //返回值:0,成功找到了. // 1,失败. int get_com_name(CString comx, CString &namebuf) { HDEVINFO hdinfo; int res = 0; SP_DEVINFO_DATA hddevinfo = { sizeof(SP_DEVINFO_DATA) }; hdinfo = SetupDiGetClassDevs(&GUID_DEVCLASS_PORTS, 0, 0, DIGCF_PRESENT);//获取PORTS类别的已安装设备信息 if (hdinfo != INVALID_HANDLE_VALUE)//获取成功 { for (int i = 0; SetupDiEnumDeviceInfo(hdinfo, i, &hddevinfo); i++)//轮询所有已安装设备 { SetupDiGetDeviceRegistryProperty(hdinfo, &hddevinfo, SPDRP_FRIENDLYNAME, 0, (PBYTE)(namebuf.GetBuffer(2048)), 2048, 0);//获得单个装置的详细资料 namebuf.ReleaseBuffer(); if (namebuf.Find(comx) != -1) { res = 1; break; } //char *t; //t = strstr(namebuf, comx); //if (t) //{ // t--; // *t = '\0';//添加结束符,作用就是把"(COMX)"这段字符去掉 // res = 0; // break;//成功找到了COMx的名字 //} } } return res; } CString & intToString(int num) { static CString Str1; Str1.Format(_T("%d"), num); int k = Str1.GetLength(); int j = (k - 1) / 3; //逗号个数 int l = k - j * 3; //起始位置 for (int i = l; i < k + j; i += 4) { Str1.Insert(i, _T(",")); } return Str1; } CString & intToBinString(int num, int digits) { static CString Str1; Str1.Empty(); int mask = 1 << (digits - 1); for (int i = 0; i < digits; i++) { if (num&mask) Str1.Append(_T("*")); else Str1.Append(_T(".")); mask >>= 1; } return Str1; }