MFC使用自定义消息

可以在一个线程的执行函数中向另一个线程发送自定义的消息来达到通信的目的.一个线程向另外一个线程发送消息是通过操作系统实现的.利用 Windows 操作系统的消息驱动机制,当一个线程发出一条消息时,操作系统首先接收到该消息,然后把该消息转发给目标线程,接收消息的线程必须已经建立了消息循环.

 

例程 7 MultiThread7
该例程演示了如何使用自定义消息进行线程间通信.首先,主线程向 CCalculateThread 线程发送消息WM_CALCULATE,CCalculateThread 线程收到消息后进行计算,再向主线程发送 WM_DISPLAY 消息,主线程收到该消息后显示计算结果.
建立一个基于对话框的工程 MultiThread7,在对话框 IDD_MULTITHREAD7_DIALOG 中加入三个单选按钮IDC_RADIO1,IDC_RADIO2,IDC_RADIO3,标题分别为1+2+3+4+......+10,1+2+3+4+......+50,1+2+3+4+......+100.加入按钮 IDC_SUM,标题为“求和”.加入标签框 IDC_STATUS,属性选中“边框”.

分别双击三个单选按钮,添加消息响应函数:
void CMultiThread7Dlg::OnRadio1()
{
nAddend=10;
}
void CMultiThread7Dlg::OnRadio2()
{
nAddend=50;
}
void CMultiThread7Dlg::OnRadio3()
{
nAddend=100;
}

并在 OnInitDialog 函数中完成相应的初始化工作:

 1 BOOL CMultiThread7Dlg::OnInitDialog()
 2 {
 3     CDialogEx::OnInitDialog();
 4 
 5     // 将“关于...”菜单项添加到系统菜单中。
 6 
 7     // IDM_ABOUTBOX 必须在系统命令范围内。
 8     ASSERT((IDM_ABOUTBOX & 0xFFF0) == IDM_ABOUTBOX);
 9     ASSERT(IDM_ABOUTBOX < 0xF000);
10 
11     CMenu* pSysMenu = GetSystemMenu(FALSE);
12     if (pSysMenu != NULL)
13     {
14         BOOL bNameValid;
15         CString strAboutMenu;
16         bNameValid = strAboutMenu.LoadString(IDS_ABOUTBOX);
17         ASSERT(bNameValid);
18         if (!strAboutMenu.IsEmpty())
19         {
20             pSysMenu->AppendMenu(MF_SEPARATOR);
21             pSysMenu->AppendMenu(MF_STRING, IDM_ABOUTBOX, strAboutMenu);
22         }
23     }
24 
25     // 设置此对话框的图标。  当应用程序主窗口不是对话框时,框架将自动
26     //  执行此操作
27     SetIcon(m_hIcon, TRUE);            // 设置大图标
28     SetIcon(m_hIcon, FALSE);        // 设置小图标
29 
30     // TODO: 在此添加额外的初始化代码
31     ((CButton*)GetDlgItem(IDC_RADIO1))->SetCheck(TRUE);
32     nAddend = 10;
33     return TRUE;  // 除非将焦点设置到控件,否则返回 TRUE
34 }

在 MultiThread7Dlg.h 中添加: #include "CalculateThread.h"

 1 // MultiThread7Dlg.h : 头文件
 2 //
 3 #include "CalculateThread.h"
 4 
 5 
 6 #define WM_DISPLAY WM_USER+2
 7 
 8 #pragma once
 9 
10 
11 // CMultiThread7Dlg 对话框
12 class CMultiThread7Dlg : public CDialogEx
13 {
14 // 构造
15 public:
16     CMultiThread7Dlg(CWnd* pParent = NULL);    // 标准构造函数
17     CCalculateThread *m_pCalculateThread;
18 // 对话框数据
19 #ifdef AFX_DESIGN_TIME
20     enum { IDD = IDD_MULTITHREAD7_DIALOG };
21 #endif
22 
23     protected:
24     virtual void DoDataExchange(CDataExchange* pDX);    // DDX/DDV 支持
25 
26 
27 // 实现
28 protected:
29     HICON m_hIcon;
30     int nAddend;
31     LRESULT OnDisplay(WPARAM wParam, LPARAM lParam);
32     // 生成的消息映射函数
33     virtual BOOL OnInitDialog();
34     afx_msg void OnSysCommand(UINT nID, LPARAM lParam);
35     afx_msg void OnPaint();
36     afx_msg HCURSOR OnQueryDragIcon();
37     DECLARE_MESSAGE_MAP()
38 public:
39     afx_msg void OnBnClickedRadio1();
40     afx_msg void OnBnClickedRadio2();
41     afx_msg void OnBnClickedRadio3();
42     afx_msg void OnBnClickedSum();
43 };

在 MultiThread7Dlg.cpp 中添加: BEGIN_MESSAGE_MAP(CMultiThread7Dlg, CDialog)

  1 // MultiThread7Dlg.cpp : 实现文件
  2 //
  3 
  4 #include "stdafx.h"
  5 #include "MultiThread7.h"
  6 #include "MultiThread7Dlg.h"
  7 #include "afxdialogex.h"
  8 
  9 #ifdef _DEBUG
 10 #define new DEBUG_NEW
 11 #endif
 12 
 13 
 14 // 用于应用程序“关于”菜单项的 CAboutDlg 对话框
 15 
 16 class CAboutDlg : public CDialogEx
 17 {
 18 public:
 19     CAboutDlg();
 20 
 21 // 对话框数据
 22 #ifdef AFX_DESIGN_TIME
 23     enum { IDD = IDD_ABOUTBOX };
 24 #endif
 25 
 26     protected:
 27     virtual void DoDataExchange(CDataExchange* pDX);    // DDX/DDV 支持
 28 
 29 // 实现
 30 protected:
 31     DECLARE_MESSAGE_MAP()
 32 };
 33 
 34 CAboutDlg::CAboutDlg() : CDialogEx(IDD_ABOUTBOX)
 35 {
 36 }
 37 
 38 void CAboutDlg::DoDataExchange(CDataExchange* pDX)
 39 {
 40     CDialogEx::DoDataExchange(pDX);
 41 }
 42 
 43 BEGIN_MESSAGE_MAP(CAboutDlg, CDialogEx)
 44 END_MESSAGE_MAP()
 45 
 46 
 47 // CMultiThread7Dlg 对话框
 48 
 49 
 50 
 51 CMultiThread7Dlg::CMultiThread7Dlg(CWnd* pParent /*=NULL*/)
 52     : CDialogEx(IDD_MULTITHREAD7_DIALOG, pParent)
 53 {
 54     m_hIcon = AfxGetApp()->LoadIcon(IDR_MAINFRAME);
 55 }
 56 
 57 void CMultiThread7Dlg::DoDataExchange(CDataExchange* pDX)
 58 {
 59     CDialogEx::DoDataExchange(pDX);
 60 }
 61 
 62 BEGIN_MESSAGE_MAP(CMultiThread7Dlg, CDialogEx)
 63     ON_WM_SYSCOMMAND()
 64     ON_WM_PAINT()
 65     ON_WM_QUERYDRAGICON()
 66     ON_BN_CLICKED(IDC_RADIO1, &CMultiThread7Dlg::OnBnClickedRadio1)
 67     ON_BN_CLICKED(IDC_RADIO2, &CMultiThread7Dlg::OnBnClickedRadio2)
 68     ON_BN_CLICKED(IDC_RADIO3, &CMultiThread7Dlg::OnBnClickedRadio3)
 69     ON_MESSAGE(WM_DISPLAY, &CMultiThread7Dlg::OnDisplay)
 70     ON_BN_CLICKED(IDC_SUM, &CMultiThread7Dlg::OnBnClickedSum)
 71 END_MESSAGE_MAP()
 72 
 73 
 74 // CMultiThread7Dlg 消息处理程序
 75 
 76 BOOL CMultiThread7Dlg::OnInitDialog()
 77 {
 78     CDialogEx::OnInitDialog();
 79 
 80     // 将“关于...”菜单项添加到系统菜单中。
 81 
 82     // IDM_ABOUTBOX 必须在系统命令范围内。
 83     ASSERT((IDM_ABOUTBOX & 0xFFF0) == IDM_ABOUTBOX);
 84     ASSERT(IDM_ABOUTBOX < 0xF000);
 85 
 86     CMenu* pSysMenu = GetSystemMenu(FALSE);
 87     if (pSysMenu != NULL)
 88     {
 89         BOOL bNameValid;
 90         CString strAboutMenu;
 91         bNameValid = strAboutMenu.LoadString(IDS_ABOUTBOX);
 92         ASSERT(bNameValid);
 93         if (!strAboutMenu.IsEmpty())
 94         {
 95             pSysMenu->AppendMenu(MF_SEPARATOR);
 96             pSysMenu->AppendMenu(MF_STRING, IDM_ABOUTBOX, strAboutMenu);
 97         }
 98     }
 99 
100     // 设置此对话框的图标。  当应用程序主窗口不是对话框时,框架将自动
101     //  执行此操作
102     SetIcon(m_hIcon, TRUE);            // 设置大图标
103     SetIcon(m_hIcon, FALSE);        // 设置小图标
104 
105     // TODO: 在此添加额外的初始化代码
106     ((CButton*)GetDlgItem(IDC_RADIO1))->SetCheck(TRUE);
107     nAddend = 10;
108     return TRUE;  // 除非将焦点设置到控件,否则返回 TRUE
109 }
110 
111 void CMultiThread7Dlg::OnSysCommand(UINT nID, LPARAM lParam)
112 {
113     if ((nID & 0xFFF0) == IDM_ABOUTBOX)
114     {
115         CAboutDlg dlgAbout;
116         dlgAbout.DoModal();
117     }
118     else
119     {
120         CDialogEx::OnSysCommand(nID, lParam);
121     }
122 }
123 
124 // 如果向对话框添加最小化按钮,则需要下面的代码
125 //  来绘制该图标。  对于使用文档/视图模型的 MFC 应用程序,
126 //  这将由框架自动完成。
127 
128 void CMultiThread7Dlg::OnPaint()
129 {
130     if (IsIconic())
131     {
132         CPaintDC dc(this); // 用于绘制的设备上下文
133 
134         SendMessage(WM_ICONERASEBKGND, reinterpret_cast<WPARAM>(dc.GetSafeHdc()), 0);
135 
136         // 使图标在工作区矩形中居中
137         int cxIcon = GetSystemMetrics(SM_CXICON);
138         int cyIcon = GetSystemMetrics(SM_CYICON);
139         CRect rect;
140         GetClientRect(&rect);
141         int x = (rect.Width() - cxIcon + 1) / 2;
142         int y = (rect.Height() - cyIcon + 1) / 2;
143 
144         // 绘制图标
145         dc.DrawIcon(x, y, m_hIcon);
146     }
147     else
148     {
149         CDialogEx::OnPaint();
150     }
151 }
152 
153 //当用户拖动最小化窗口时系统调用此函数取得光标
154 //显示。
155 HCURSOR CMultiThread7Dlg::OnQueryDragIcon()
156 {
157     return static_cast<HCURSOR>(m_hIcon);
158 }
159 
160 
161 
162 void CMultiThread7Dlg::OnBnClickedRadio1()
163 {
164     // TODO: 在此添加控件通知处理程序代码
165     nAddend = 10;
166 }
167 
168 
169 void CMultiThread7Dlg::OnBnClickedRadio2()
170 {
171     // TODO: 在此添加控件通知处理程序代码
172     nAddend = 50;
173 }
174 
175 
176 void CMultiThread7Dlg::OnBnClickedRadio3()
177 {
178     // TODO: 在此添加控件通知处理程序代码
179     nAddend = 100;
180 }
181 
182 
183 
184 LRESULT CMultiThread7Dlg::OnDisplay(WPARAM wParam, LPARAM lParam)
185 {
186     int nTemp = (int)wParam;
187     SetDlgItemInt(IDC_STATUS, nTemp, FALSE);
188     return 0;
189 }
190 
191 void CMultiThread7Dlg::OnBnClickedSum()
192 {
193     // TODO: 在此添加控件通知处理程序代码
194     m_pCalculateThread = (CCalculateThread *) AfxBeginThread(RUNTIME_CLASS(CCalculateThread));
195     Sleep(500);
196     m_pCalculateThread->PostThreadMessage(WM_CALCULATE, nAddend, NULL);
197     m_pCalculateThread = NULL;
198 }

CalculateThread.h

 1 #pragma once
 2 #include "afxwin.h"
 3 
 4 #define WM_CALCULATE WM_USER+1
 5 
 6 
 7 class CCalculateThread :public CWinThread
 8 {
 9 
10     DECLARE_DYNCREATE(CCalculateThread)
11 protected:
12     CCalculateThread();
13     ~CCalculateThread();
14 public:
15 
16     virtual BOOL InitInstance();
17     virtual int    ExitInstance();
18 
19     afx_msg void OnCalculate(UINT wParam, LONG lParam);
20 
21 protected:
22     
23     DECLARE_MESSAGE_MAP()
24 };

CalculateThread.cpp

 1 #include "stdafx.h"
 2 #include "CalculateThread.h"
 3 #include "MultiThread7Dlg.h"
 4 
 5 IMPLEMENT_DYNCREATE(CCalculateThread, CWinThread)
 6 
 7 BEGIN_MESSAGE_MAP(CCalculateThread, CWinThread)
 8     //{{AFX_MSG_MAP(CCalculateThread)
 9     // NOTE - the ClassWizard will add and remove mapping macros here.
10     //}}AFX_MSG_MAP
11     ON_THREAD_MESSAGE(WM_CALCULATE, &CCalculateThread::OnCalculate)
12     //和主线程对比,注意它们的区别
13 END_MESSAGE_MAP()
14 
15 CCalculateThread::CCalculateThread()
16 {
17 }
18 
19 
20 CCalculateThread::~CCalculateThread()
21 {
22     AfxEndThread(0);
23 }
24 
25 
26 BOOL CCalculateThread::InitInstance()
27 {
28     // TODO: 在此执行任意逐线程初始化
29     return TRUE;
30 }
31 
32 int CCalculateThread::ExitInstance()
33 {
34     // TODO: 在此执行任意逐线程清理
35     return CWinThread::ExitInstance();
36 }
37 
38 
39 void CCalculateThread::OnCalculate(UINT wParam, LONG lParam)
40 {
41     int nTmpt = 0;
42     for (int i = 0; i <= (int)wParam; i++)
43     {
44         nTmpt = nTmpt + i;
45     }
46     Sleep(500);
47     ::PostMessage((HWND)(GetMainWnd()->GetSafeHwnd()), WM_DISPLAY, nTmpt, NULL);
48     //return 0;
49 }

 

posted on 2016-10-09 16:50  程序天空下的骆驼  阅读(395)  评论(0编辑  收藏  举报

导航