自己写的基于MFC对话框的用于调试程序的UDP客户端服务器端程序
2011-08-01 16:54
357 查看
代码点击这里下载
服务器端截图:
![](http://hi.csdn.net/attachment/201108/1/0_1312188722p282.gif)
客户端截图:
![](http://hi.csdn.net/attachment/201108/1/0_13121887178BD0.gif)
基于MFC对话框的MFC UPD客户端以及服务器端程序
1.服务器端
1.1服务器端点击create按钮后,程序读取设置的服务器端端口,默认端口为100,创建服务器端socket,将create的按钮变换成close按钮,并且将服务器端的地址及端口与socket bind.开启读取数据线程.
1.2当服务器读取线程接收到数据时,将保存数据源的ip地址以及端口,将数据以及数据的源在receive edit控件中显示出来,并将数据源在client中显示出来.如果是第一次接收到数据,将使能send按钮.
1.3当点击send时,将读取send edit控件中的内容并且发送.
1.4当关闭对话框时将终止读取线程.
2.客户端
2.1输入服务器端ip以及端口号后reset,即可设置发送数据的目标地址,并且开启读取数据线程读取数据,使能send按钮.
2.2按下send按钮后将读取send edit控件中的数据发送至服务器端.
2.3当接收到数据时,将在receive edit控件中显示接收的数据.
2.4当关闭对话框时,将终止读取数据线程
服务器端截图:
![](http://hi.csdn.net/attachment/201108/1/0_1312188722p282.gif)
客户端截图:
![](http://hi.csdn.net/attachment/201108/1/0_13121887178BD0.gif)
基于MFC对话框的MFC UPD客户端以及服务器端程序
1.服务器端
1.1服务器端点击create按钮后,程序读取设置的服务器端端口,默认端口为100,创建服务器端socket,将create的按钮变换成close按钮,并且将服务器端的地址及端口与socket bind.开启读取数据线程.
1.2当服务器读取线程接收到数据时,将保存数据源的ip地址以及端口,将数据以及数据的源在receive edit控件中显示出来,并将数据源在client中显示出来.如果是第一次接收到数据,将使能send按钮.
1.3当点击send时,将读取send edit控件中的内容并且发送.
1.4当关闭对话框时将终止读取线程.
2.客户端
2.1输入服务器端ip以及端口号后reset,即可设置发送数据的目标地址,并且开启读取数据线程读取数据,使能send按钮.
2.2按下send按钮后将读取send edit控件中的数据发送至服务器端.
2.3当接收到数据时,将在receive edit控件中显示接收的数据.
2.4当关闭对话框时,将终止读取数据线程
// UDP_ServerDlg.h : 头文件 // #pragma once #include "afxcmn.h" #include "afxwin.h" #include <WinSock2.h> // CUDP_ServerDlg 对话框 class CUDP_ServerDlg : public CDialog { // 构造 public: CUDP_ServerDlg(CWnd* pParent = NULL); // 标准构造函数 // 对话框数据 enum { IDD = IDD_UDP_SERVER_DIALOG }; protected: virtual void DoDataExchange(CDataExchange* pDX); // DDX/DDV 支持 // 实现 protected: HICON m_hIcon; // 生成的消息映射函数 virtual BOOL OnInitDialog(); afx_msg void OnSysCommand(UINT nID, LPARAM lParam); afx_msg void OnPaint(); afx_msg HCURSOR OnQueryDragIcon(); DECLARE_MESSAGE_MAP() public: afx_msg void OnBnClickedButtonCreateServer(); public: afx_msg void OnBnClickedButtonCloseServer(); public: // 端口号控件变量 CEdit m_editPortNO; public: // IP地址数组 char m_gcIP; public: CString tempStr; public: afx_msg void OnClose(); public: CString m_strTempString; public: // 服务器端口号 unsigned short m_nPortNO; public: // 服务器端socket SOCKET m_sockServer; public: // 若已经创建服务器则为true,否则为false bool m_bServerCreated; public: struct sockaddr_in m_clientAddr; public: // 接收数据的edit控件 CEdit m_editReceive; public: // 接收数据控件的控件变量,str CString m_strReceEdit; public: afx_msg void OnBnClickedButtonSend(); public: // 发送edit控件变量,str CString m_strSendData; public: // 若为true则终止线程 bool m_bTerminateThread; };
// UDP_ServerDlg.cpp : 实现文件 // #include "stdafx.h" #include "UDP_Server.h" #include "UDP_ServerDlg.h" #ifdef _DEBUG #define new DEBUG_NEW #endif // 用于应用程序“关于”菜单项的 CAboutDlg 对话框 class CAboutDlg : public CDialog { public: CAboutDlg(); // 对话框数据 enum { IDD = IDD_ABOUTBOX }; protected: virtual void DoDataExchange(CDataExchange* pDX); // DDX/DDV 支持 // 实现 protected: DECLARE_MESSAGE_MAP() }; CAboutDlg::CAboutDlg() : CDialog(CAboutDlg::IDD) { } void CAboutDlg::DoDataExchange(CDataExchange* pDX) { CDialog::DoDataExchange(pDX); } BEGIN_MESSAGE_MAP(CAboutDlg, CDialog) END_MESSAGE_MAP() // CUDP_ServerDlg 对话框 CUDP_ServerDlg::CUDP_ServerDlg(CWnd* pParent /*=NULL*/) : CDialog(CUDP_ServerDlg::IDD, pParent) , m_gcIP(0) , tempStr(_T("")) , m_strTempString(_T("")) , m_nPortNO(0) , m_bServerCreated(false) , m_strReceEdit(_T("")) , m_strSendData(_T("")) , m_bTerminateThread(false) { m_hIcon = AfxGetApp()->LoadIcon(IDR_MAINFRAME); } void CUDP_ServerDlg::DoDataExchange(CDataExchange* pDX) { CDialog::DoDataExchange(pDX); DDX_Control(pDX, IDC_EDIT_SERVER_PORT, m_editPortNO); DDX_Control(pDX, IDC_EDIT_RECEIVE, m_editReceive); DDX_Text(pDX, IDC_EDIT_RECEIVE, m_strReceEdit); DDX_Text(pDX, IDC_EDIT_SEND, m_strSendData); } BEGIN_MESSAGE_MAP(CUDP_ServerDlg, CDialog) ON_WM_SYSCOMMAND() ON_WM_PAINT() ON_WM_QUERYDRAGICON() //}}AFX_MSG_MAP ON_BN_CLICKED(IDC_BUTTON_CREATE_SERVER, &CUDP_ServerDlg::OnBnClickedButtonCreateServer) ON_WM_CLOSE() ON_BN_CLICKED(IDC_BUTTON_SEND, &CUDP_ServerDlg::OnBnClickedButtonSend) END_MESSAGE_MAP() // CUDP_ServerDlg 消息处理程序 BOOL CUDP_ServerDlg::OnInitDialog() { CDialog::OnInitDialog(); // 将“关于...”菜单项添加到系统菜单中。 // IDM_ABOUTBOX 必须在系统命令范围内。 ASSERT((IDM_ABOUTBOX & 0xFFF0) == IDM_ABOUTBOX); ASSERT(IDM_ABOUTBOX < 0xF000); CMenu* pSysMenu = GetSystemMenu(FALSE); if (pSysMenu != NULL) { CString strAboutMenu; strAboutMenu.LoadString(IDS_ABOUTBOX); if (!strAboutMenu.IsEmpty()) { pSysMenu->AppendMenu(MF_SEPARATOR); pSysMenu->AppendMenu(MF_STRING, IDM_ABOUTBOX, strAboutMenu); } } // 设置此对话框的图标。当应用程序主窗口不是对话框时,框架将自动 // 执行此操作 SetIcon(m_hIcon, TRUE); // 设置大图标 SetIcon(m_hIcon, FALSE); // 设置小图标 // TODO: 在此添加额外的初始化代码 //WSAStartup() WSADATA wsaData; PHOSTENT hostinfo; if(WSAStartup(MAKEWORD(2,2),&wsaData)!=0) { MessageBox("WSAStartup ERROR!"); } //设置服务器IP地址 char gcTemp[255]; char * IP; if (0 == gethostname(gcTemp, 255)) { hostinfo = gethostbyname(gcTemp); //tempStr.Format("%s", gcTemp); //MessageBox(tempStr); IP = inet_ntoa (*(struct in_addr *)*hostinfo->h_addr_list); tempStr.Format(IP); //MessageBox(IP); SetDlgItemText(IDC_STATIC_SERVER_ADDRESS, tempStr); //m_addServerAddress.SetAddress(); } //设置服务器默认端口号为100 SetDlgItemText(IDC_EDIT_SERVER_PORT, "100"); m_bServerCreated = false; m_bTerminateThread = false; return TRUE; // 除非将焦点设置到控件,否则返回 TRUE } void CUDP_ServerDlg::OnSysCommand(UINT nID, LPARAM lParam) { if ((nID & 0xFFF0) == IDM_ABOUTBOX) { CAboutDlg dlgAbout; dlgAbout.DoModal(); } else { CDialog::OnSysCommand(nID, lParam); } } // 如果向对话框添加最小化按钮,则需要下面的代码 // 来绘制该图标。对于使用文档/视图模型的 MFC 应用程序, // 这将由框架自动完成。 void CUDP_ServerDlg::OnPaint() { if (IsIconic()) { CPaintDC dc(this); // 用于绘制的设备上下文 SendMessage(WM_ICONERASEBKGND, reinterpret_cast<WPARAM>(dc.GetSafeHdc()), 0); // 使图标在工作矩形中居中 int cxIcon = GetSystemMetrics(SM_CXICON); int cyIcon = GetSystemMetrics(SM_CYICON); CRect rect; GetClientRect(&rect); int x = (rect.Width() - cxIcon + 1) / 2; int y = (rect.Height() - cyIcon + 1) / 2; // 绘制图标 dc.DrawIcon(x, y, m_hIcon); } else { CDialog::OnPaint(); } } //当用户拖动最小化窗口时系统调用此函数取得光标显示。 // HCURSOR CUDP_ServerDlg::OnQueryDragIcon() { return static_cast<HCURSOR>(m_hIcon); } UINT ServerRecvThread(LPVOID lpParm ) { CUDP_ServerDlg *dlg = (CUDP_ServerDlg*)lpParm; char gcInBuffer[1027]; int lenth; int size = sizeof(sockaddr_in); CString strReceive, tempStr; char*gcClientIP; bool bSendEnable = false; while(!dlg->m_bTerminateThread) { if ((lenth = recvfrom(dlg->m_sockServer, gcInBuffer, 1024, 0, (struct sockaddr *)&dlg->m_clientAddr, &size) )>0) { if (!bSendEnable) { CWnd *cwnd = dlg->GetDlgItem(IDC_BUTTON_SEND); cwnd->EnableWindow(TRUE); bSendEnable = true; } gcClientIP = inet_ntoa((dlg->m_clientAddr).sin_addr); tempStr.Format("%s", gcClientIP); dlg->SetDlgItemText(IDC_STATIC_CLINET_ADDRESS, tempStr); tempStr.Format("%hu", dlg->m_clientAddr.sin_port); dlg->SetDlgItemText(IDC_STATIC_CLIENT_PORTNO, tempStr); tempStr.Format("%s:%hu: ", gcClientIP, dlg->m_clientAddr.sin_port); strReceive += tempStr; gcInBuffer[lenth] = '\r'; gcInBuffer[lenth+1] = '\n'; gcInBuffer[lenth+2] = '\0'; strReceive += gcInBuffer; dlg->m_editReceive.SetWindowText(strReceive); } } return 0; } void CUDP_ServerDlg::OnBnClickedButtonCreateServer() { // TODO: 在此添加控件通知处理程序代码 if (m_bServerCreated) { //终止线程 m_bTerminateThread = true; m_bServerCreated = false; m_editPortNO.EnableWindow(TRUE); SetDlgItemText(IDC_BUTTON_CREATE_SERVER, "Create"); //disable send 按钮 CWnd * cwnd = GetDlgItem(IDC_BUTTON_SEND); cwnd->EnableWindow(FALSE); } else//创建服务器端 { //读取服务器地址以及端口号 GetDlgItemText(IDC_EDIT_SERVER_PORT, m_strTempString); m_nPortNO = atoi(m_strTempString.GetBuffer()); //MessageBox(m_strTempString); //socket if ((m_sockServer = socket(AF_INET, SOCK_DGRAM, 0)) == INVALID_SOCKET) { MessageBox("ERROR: Create Server Socket Error!"); exit(-1); } //bind struct sockaddr_in serAddr; serAddr.sin_family = AF_INET; serAddr.sin_port = htons(m_nPortNO); (serAddr.sin_addr).s_addr = htonl(INADDR_ANY); if ((bind(m_sockServer, (LPSOCKADDR)&serAddr, sizeof(serAddr)))==SOCKET_ERROR) { MessageBox("ERROR: Bind Socket Error!"); exit(-1); } //disable portno m_editPortNO.EnableWindow(FALSE); SetDlgItemText(IDC_BUTTON_CREATE_SERVER, "Close"); m_bServerCreated = true; //创建线程等待 m_bTerminateThread = false; AfxBeginThread(ServerRecvThread, this, THREAD_PRIORITY_NORMAL, 0, 0, NULL); } } void CUDP_ServerDlg::OnClose() { // TODO: 在此添加消息处理程序代码和/或调用默认值 m_bTerminateThread = true; closesocket(m_sockServer); WSACleanup(); //Disable close按钮,enable create按钮 CWnd * cwnd = (GetDlgItem(IDC_BUTTON_CREATE_SERVER)); cwnd->EnableWindow(TRUE); CDialog::OnClose(); } void CUDP_ServerDlg::OnBnClickedButtonSend() { // TODO: 在此添加控件通知处理程序代码 UpdateData(TRUE); //MessageBox(m_strSendData); sendto(m_sockServer, m_strSendData, strlen(m_strSendData), 0, (struct sockaddr*)&m_clientAddr, sizeof(sockaddr)); }
// UDP_ClientDlg.h : 头文件 // #pragma once #include <WinSock2.h> #include "afxcmn.h" #include "afxwin.h" // CUDP_ClientDlg 对话框 class CUDP_ClientDlg : public CDialog { // 构造 public: CUDP_ClientDlg(CWnd* pParent = NULL); // 标准构造函数 // 对话框数据 enum { IDD = IDD_UDP_CLIENT_DIALOG }; protected: virtual void DoDataExchange(CDataExchange* pDX); // DDX/DDV 支持 // 实现 protected: HICON m_hIcon; // 生成的消息映射函数 virtual BOOL OnInitDialog(); afx_msg void OnSysCommand(UINT nID, LPARAM lParam); afx_msg void OnPaint(); afx_msg HCURSOR OnQueryDragIcon(); DECLARE_MESSAGE_MAP() public: afx_msg void OnBnClickedButtonResetServer(); public: afx_msg void OnBnClickedButtonSend(); public: CString tempStr; public: // 客户端socket SOCKET m_sockClient; public: struct sockaddr_in m_serverAddr; public: afx_msg void OnClose(); public: // 服务器端地址控件 CIPAddressCtrl m_addrServer; public: unsigned short m_nServerPortNo; public: // 若服务器ip及端口已设定则为true,否则为false bool m_bServerSet; public: CString m_strServerIPPort; public: CEdit m_editReceive; public: // 控件变量,str CString m_strSendData; public: // 若为true则终止线程 bool m_bTerminateThread; };
// UDP_ClientDlg.cpp : 实现文件 // #include "stdafx.h" #include "UDP_Client.h" #include "UDP_ClientDlg.h" #ifdef _DEBUG #define new DEBUG_NEW #endif // 用于应用程序“关于”菜单项的 CAboutDlg 对话框 class CAboutDlg : public CDialog { public: CAboutDlg(); // 对话框数据 enum { IDD = IDD_ABOUTBOX }; protected: virtual void DoDataExchange(CDataExchange* pDX); // DDX/DDV 支持 // 实现 protected: DECLARE_MESSAGE_MAP() }; CAboutDlg::CAboutDlg() : CDialog(CAboutDlg::IDD) { } void CAboutDlg::DoDataExchange(CDataExchange* pDX) { CDialog::DoDataExchange(pDX); } BEGIN_MESSAGE_MAP(CAboutDlg, CDialog) END_MESSAGE_MAP() // CUDP_ClientDlg 对话框 CUDP_ClientDlg::CUDP_ClientDlg(CWnd* pParent /*=NULL*/) : CDialog(CUDP_ClientDlg::IDD, pParent) , tempStr(_T("")) , m_nServerPortNo(0) , m_bServerSet(false) , m_strSendData(_T("")) , m_bTerminateThread(false) { m_hIcon = AfxGetApp()->LoadIcon(IDR_MAINFRAME); } void CUDP_ClientDlg::DoDataExchange(CDataExchange* pDX) { CDialog::DoDataExchange(pDX); DDX_Control(pDX, IDC_IPADDRESS_SERVER, m_addrServer); DDX_Control(pDX, IDC_EDIT_RECEIVE, m_editReceive); DDX_Text(pDX, IDC_EDIT4, m_strSendData); } BEGIN_MESSAGE_MAP(CUDP_ClientDlg, CDialog) ON_WM_SYSCOMMAND() ON_WM_PAINT() ON_WM_QUERYDRAGICON() //}}AFX_MSG_MAP ON_BN_CLICKED(IDC_BUTTON_RESET_SERVER, &CUDP_ClientDlg::OnBnClickedButtonResetServer) ON_BN_CLICKED(IDC_BUTTON_SEND, &CUDP_ClientDlg::OnBnClickedButtonSend) ON_WM_CLOSE() END_MESSAGE_MAP() // CUDP_ClientDlg 消息处理程序 BOOL CUDP_ClientDlg::OnInitDialog() { CDialog::OnInitDialog(); // 将“关于...”菜单项添加到系统菜单中。 // IDM_ABOUTBOX 必须在系统命令范围内。 ASSERT((IDM_ABOUTBOX & 0xFFF0) == IDM_ABOUTBOX); ASSERT(IDM_ABOUTBOX < 0xF000); CMenu* pSysMenu = GetSystemMenu(FALSE); if (pSysMenu != NULL) { CString strAboutMenu; strAboutMenu.LoadString(IDS_ABOUTBOX); if (!strAboutMenu.IsEmpty()) { pSysMenu->AppendMenu(MF_SEPARATOR); pSysMenu->AppendMenu(MF_STRING, IDM_ABOUTBOX, strAboutMenu); } } // 设置此对话框的图标。当应用程序主窗口不是对话框时,框架将自动 // 执行此操作 SetIcon(m_hIcon, TRUE); // 设置大图标 SetIcon(m_hIcon, FALSE); // 设置小图标 // TODO: 在此添加额外的初始化代码 m_bServerSet = false; m_bTerminateThread = false; //WSAStartup() WSADATA wsaData; PHOSTENT hostinfo; if(WSAStartup(MAKEWORD(2,2),&wsaData)!=0) { MessageBox("WSAStartup ERROR!"); } //设置客户端IP地址及端口 //读取本机ip地址 char gcTemp[255]; char * IP; if (0 == gethostname(gcTemp, 255)) { hostinfo = gethostbyname(gcTemp); //tempStr.Format("%s", gcTemp); //MessageBox(tempStr); IP = inet_ntoa (*(struct in_addr *)*hostinfo->h_addr_list); tempStr.Format(IP); //MessageBox(IP); SetDlgItemText(IDC_STATIC_CLIENT_ADDRESS, tempStr); //m_addServerAddress.SetAddress(); } //create client socket //socket if ((m_sockClient = socket(AF_INET, SOCK_DGRAM, 0)) == INVALID_SOCKET) { MessageBox("ERROR: Create Client Socket Error!"); exit(-1); } return TRUE; // 除非将焦点设置到控件,否则返回 TRUE } void CUDP_ClientDlg::OnSysCommand(UINT nID, LPARAM lParam) { if ((nID & 0xFFF0) == IDM_ABOUTBOX) { CAboutDlg dlgAbout; dlgAbout.DoModal(); } else { CDialog::OnSysCommand(nID, lParam); } } // 如果向对话框添加最小化按钮,则需要下面的代码 // 来绘制该图标。对于使用文档/视图模型的 MFC 应用程序, // 这将由框架自动完成。 void CUDP_ClientDlg::OnPaint() { if (IsIconic()) { CPaintDC dc(this); // 用于绘制的设备上下文 SendMessage(WM_ICONERASEBKGND, reinterpret_cast<WPARAM>(dc.GetSafeHdc()), 0); // 使图标在工作矩形中居中 int cxIcon = GetSystemMetrics(SM_CXICON); int cyIcon = GetSystemMetrics(SM_CYICON); CRect rect; GetClientRect(&rect); int x = (rect.Width() - cxIcon + 1) / 2; int y = (rect.Height() - cyIcon + 1) / 2; // 绘制图标 dc.DrawIcon(x, y, m_hIcon); } else { CDialog::OnPaint(); } } //当用户拖动最小化窗口时系统调用此函数取得光标显示。 // HCURSOR CUDP_ClientDlg::OnQueryDragIcon() { return static_cast<HCURSOR>(m_hIcon); } UINT ClientRecvThread(LPVOID lpParm ) { CUDP_ClientDlg *dlg = (CUDP_ClientDlg*)lpParm; char gcInBuffer[1027]; int lenth; int size = sizeof(sockaddr_in); CString strReceive, tempStr; while(!dlg->m_bTerminateThread) { if ((lenth = recvfrom(dlg->m_sockClient, gcInBuffer, 1024, 0, (struct sockaddr *)&dlg->m_serverAddr, &size) )>0) { strReceive+= dlg->m_strServerIPPort+": "; gcInBuffer[lenth] = '\r'; gcInBuffer[lenth+1] = '\n'; gcInBuffer[lenth+2] = '\0'; strReceive += gcInBuffer; dlg->m_editReceive.SetWindowText(strReceive); } } return 0; } void CUDP_ClientDlg::OnBnClickedButtonResetServer() { // TODO: 在此添加控件通知处理程序代 //重置服务器ip地址以及端口号 m_serverAddr.sin_family = AF_INET; //读取服务器端地址 BYTE addr[4]; m_addrServer.GetAddress(addr[0], addr[1], addr[2], addr[3]); //读取服务器端口号 GetDlgItemText(IDC_EDIT_SERVER_PORTNO, tempStr); m_nServerPortNo = atoi(tempStr.GetBuffer()); tempStr.Format("%d.%d.%d.%d", addr[0], addr[1], addr[2], addr[3]); m_strServerIPPort.Format("%d.%d.%d.%d:%d", addr[0], addr[1], addr[2], addr[3], m_nServerPortNo); //MessageBox(tempStr); m_serverAddr.sin_port = htons(m_nServerPortNo); m_serverAddr.sin_addr.s_addr= inet_addr(tempStr); if (m_bServerSet)//判断是否第一次按下按钮 { return; } else { m_bServerSet = true; //enable send 按钮 CWnd * cwnd = GetDlgItem(IDC_BUTTON_SEND); cwnd->EnableWindow(TRUE); //开启接收数据线程 m_bTerminateThread = false; AfxBeginThread(ClientRecvThread, this, THREAD_PRIORITY_NORMAL, 0, 0, NULL); } } void CUDP_ClientDlg::OnBnClickedButtonSend() { // TODO: 在此添加控件通知处理程序代码 UpdateData(TRUE); sendto(m_sockClient, m_strSendData, strlen(m_strSendData), 0, (struct sockaddr*)&m_serverAddr, sizeof(sockaddr)); } void CUDP_ClientDlg::OnClose() { // TODO: 在此添加消息处理程序代码和/或调用默认值 m_bTerminateThread = true; closesocket(m_sockClient); WSACleanup(); CDialog::OnClose(); }
相关文章推荐
- 基于MFC对话框的UDP简单聊天程序
- 【MFC-10】VS2010/MFC基于对话框程序的登录窗口实现
- 基于对话框的MFC程序
- 基于MFC的对话框Dialog的OpenGL程序框架
- MFC中基于对话框程序快捷键的实现
- 基于MFC对话框的Windows服务程序
- mfc中怎样在一个基于对话框程序中添加菜单栏
- C# 调试程序弹出 没有可用于当前位置的源代码 对话框
- 基于MFC对话框程序中添加菜单栏 (CMenu)
- 基于对话框的MFC程序中,实现非模态子窗口在任务栏显示图标以及窗口左上角加图标
- 孙鑫VC学习笔记:第十五讲 (四) 编写一个基于MFC对话框的聊天程序
- MFC基于对话框的的多点触控简单画图程序
- 基于MFC对话框程序中添加菜单栏 (CMenu)
- 将基于MFC的对话框应用程序修改为服务程序
- MFC基于对话框程序 转自http://www.uudo.net/
- 基于MFC对话框的NT服务程序框架
- 在基于对话框的MFC程序中实现按键响应
- 基于对话框的MFC程序加入菜单资源
- 基于MFC对话框程序中添加菜单栏
- 如何让基于对话框的MFC程序启动后自动隐藏对话框