大家好,博主在這裏跟大家分享一下學習MFC的經驗。關於MFC的每篇帖子我都會奉上原文檔下載地址(百度文庫)和源代碼的下載地址(CSDN),都是免金幣或積分的!目的就是更加有利於與大家交流,共同進步!因爲是初學,所以肯定有疏漏之處,請大家指正。
原文檔地址:http://wenku.baidu.com/view/d10b41b8c77da26925c5b0d6.html
源代碼地址:http://download.csdn.net/detail/songliduo/4498576
這裏主要講一下mfc中SendMessage的使用方法。傳遞消息主要分4步:
1. 在類的定義中聲明消息函數:afx_msg void AAA();
2. 在相應的cpp文件中的MESSAGE_MAP區域內添加ON_MESSAGE(MESSAGE_ID,AAA),其中參數1爲要傳遞消息的ID,參數2爲剛剛聲明的函數名稱,不用帶括號。
3. 實現消息函數:在cpp文件中添加
LRESULT 類名::AAA(WPARAM wparam,LPARAM lparam)
{
執行內容
……
return 0;
}
4. 發送消息:在需要發送消息的地方添加下列語句:
HWND hWnd = ::FindWindowEx( m_hWnd, NULL, NULL, WINDOW_TEXT ) ;
FromHandle(hWnd)->SendMessage(MESSAGE_ID,a,b);
其中,m_hWnd爲接收消息的父窗口的句柄,WINDOW_TEXT爲接收消息窗口的標題,得到的hWnd爲接收消息窗口的句柄。調用該窗口的SendMessage函數,MESSAGE_ID爲剛剛設定的消息ID,a和b是要傳遞的參數。
注:在這4個步驟中,前三個我在做的時候基本沒什麼障礙。問題主要出現在第4步。開始找到網上的例子給的都是FindWindow函數,怎麼用都不好使。後來看到有人說FindWindow是找操作系統下打開的窗口的句柄,找窗口中子窗口要用FindWindowEx函數。我也嘗試過用對話框的ID找到相應的句柄,像GetDlgItem(ID)函數一樣,未果。我使用的對話框都是沒有標題欄的,所以也就沒有窗口的標題,當然這並不會影響我設置標題。只要在生成該窗口的區域內添加SetWindowText(“窗口標題”)就可以了。也就是說窗口標題可以設置,但是不會顯示。最後一點在SendMessage()函數中,MFC默認傳遞的參數是WPARAM和LPARAM型(一個是UINT型,一個LONG型),如果要傳遞浮點類型,或者其它不是整數的類型,就可以用指針的形式傳遞(如果發送方只是申請一個變量並以地址的形式傳遞,然後接收方以指針的形式接收,如果在執行完SendMessage之後原函數體立即結束了,我不知道在接收函數體接收和使用該變量的之間的一瞬間,該內存區域會不會被佔用,我覺得還是有這種可能的。所以我覺得還是在原函數體先申請一塊內存,然後在接收函數使用完之後再釋放該內存比較合理吧)。
在以下這個例子中是一個MFC的對話框應用程序,名字爲MessageTest。它包括左邊的一個發送對話框,和右邊的兩個接收對話框,其中發送對話框和接收對話框1分別是主對話框的子對話框,在接受對話框中有一個Tab Control,在Tab Control中有個接受對話框2。這麼做的目的主要是爲了理解如何找句柄的,爲此我把幾個對話框設置成深陷下去的便於觀察。
準備工作:
1. 手動添加1個設置全局變量的頭文件GlobalSetting.h,這樣做的目的是讓所有的地方都能知道對話框的標題和自定義的結構。
2. 在GlobalSetting.h中加入下列語句:
#define RECEIVE1_TITLE "receive1 title"
#define RECEIVE2_TITLE "receive2 title"
#define GET_INT WM_USER+1000
#define GET_DOUBLE WM_USER+1001
#define GET_STRING WM_USER+1002
#define GET_STRUCT WM_USER+1003
struct SendStruct
{
int a;
int b;
int c;
int d;
};
RECEIVE1_TITLE和RECEIVE2_TITLE定義兩個接收對話框的標題,後邊的4個GET_是4個消息ID,WM_USER是用戶自定義消息的起始ID。
3. 在各個需要使用這些內容的位置添加#include “GlobalSetting.h”。
4. 在生成兩個接受對話框的位置加入SetWindowText(RECEIVE1_TITLE)和SetWindowText(RECEIVE2_TITLE)。
例1:從發送對話框發送整數到接受對話框1中。
1. 在接受對話框1的類的定義中加入
afx_msg LRESULT GetInt(WPARAM wparam,LPARAM lparam);
2. 在對應的cpp文件中加入
ON_MESSAGE(GET_INT,Receive1Dlg::GetInt)
3. 在函數實現部分加入
LRESULT Receive1Dlg::GetInt(WPARAM wparam,LPARAM lparam)
{
CString str;
str.Format("%d %d",wparam,lparam);
CEdit* edit1=(CEdit*)GetDlgItem(IDC_EDIT1);
edit1->SetWindowText(str);
return 0;
}
4. 在發送消息的函數中加入
int a=1;
int b=2;
HWND hWnd = ::FindWindowEx( this->GetParent()->m_hWnd, NULL, NULL, RECEIVE1_TITLE);
FromHandle(hWnd)->SendMessage(GET_INT,a,b);
注:在這個部分中只是簡單地傳遞兩個整數。第3步是將得到的兩個整數顯示到編輯框中,wparam和lparam如果是整數可以直接使用。第4步中this->GetParent()->m_hWnd是找到了接收對話框1父窗口的句柄,將a和b的值發過去。
例2:從發送對話框發送小數到接受對話框1中。
1. 在接受對話框1的類的定義中加入
afx_msg LRESULT GetDouble(WPARAM wparam,LPARAM lparam);
2. 在對應的cpp文件中加入
ON_MESSAGE(GET_DOUBLE,Receive1Dlg::GetDouble)
3. 在函數實現部分加入
LRESULT Receive1Dlg::GetDouble(WPARAM wparam, LPARAM lparam)
{
CString str;
double* a=(double*)wparam;
str.Format("%lf",*a);
CEdit* edit1=(CEdit*)GetDlgItem(IDC_EDIT1);
edit1->SetWindowText(str);
delete a;
return 0;
}
4. 在發送消息的函數中加入
double *a=new double;
*a=1.111;
HWND hWnd = ::FindWindowEx( this->GetParent()->m_hWnd, NULL, NULL, RECEIVE1_TITLE);
FromHandle(hWnd)->SendMessage(GET_DOUBLE,(WPARAM)(a),0);
注:在這個部分中是傳遞1個小數。第3步是將得到的小數顯示到編輯框中。第4步中先爲double類型的變量申請一塊內存併爲其負值,然後以指針的形式發送消息過去。在第3步中首先獲得double型指針,最後將內存釋放。
例3:從發送對話框發送字符串到接受對話框2中。
1. 在接受對話框2的類的定義中加入
afx_msg LRESULT GetString(WPARAM wparam,LPARAM lparam);
2. 在對應的cpp文件中加入
ON_MESSAGE(GET_STRING,Receive2Dlg::GetString)
3. 在函數實現部分加入
LRESULT Receive2Dlg::GetString(WPARAM wparam,LPARAM lparam)
{
CString *str=(CString*)wparam;
CEdit* edit1=(CEdit*)GetDlgItem(IDC_EDIT1);
edit1->SetWindowText(*str);
delete str;
return 0;
}
4. 在發送消息的函數中加入
CString *p_str=new CString("Hello");
HWND hWnd = ::FindWindowEx(this->GetParent()->m_hWnd, NULL, NULL, RECEIVE1_TITLE);
hWnd=::FindWindowEx(FromHandle(hWnd)->GetDlgItem(IDC_TAB1)->m_hWnd, NULL, NULL, RECEIVE2_TITLE);
FromHandle(hWnd)->SendMessage(GET_STRING,(WPARAM)(p_str),0);
注:在這個部分中是傳遞1個字符串。第3步是將得到的字符串顯示到編輯框中。第4步中先爲CString類型的變量申請一塊內存併爲其賦值,然後以指針的形式發送消息過去。這個我在獲得對話框句柄的時候遇到了一些問題,首先一定要弄清楚各個窗口之間的父子關係,並知道對話框和控件獲得句柄的方法是不同的。在這個例子中,接收對話框2的父窗口是那個Tab Control,Tab Control的父窗口是接收對話框1,接收對話框1和發送對話框擁有共同的父窗口。調理清晰了就好寫了。HWND hWnd = ::FindWindowEx(this->GetParent()->m_hWnd, NULL, NULL, RECEIVE1_TITLE);前邊已經說過了,是獲得了接收對話框1的句柄,下邊那條語句中的FromHandle(hWnd)->GetDlgItem(IDC_TAB1)->m_hWnd是獲得Tab Control的句柄,hWnd= ::FindWindowEx (FromHandle(hWnd)-> GetDlgItem(IDC_TAB1)-> m_hWnd, NULL, NULL, RECEIVE2_TITLE);就是獲得接收對話框2的句柄了。
例4:從發送對話框發送結構到接受對話框2中。
1. 在接受對話框1的類的定義中加入
afx_msg LRESULT GetStruct(WPARAM wparam,LPARAM lparam);
2. 在對應的cpp文件中加入
ON_MESSAGE(GET_STRUCT,Receive2Dlg::GetStruct)
3. 在函數實現部分加入
LRESULT Receive2Dlg::GetStruct(WPARAM wparam,LPARAM lparam)
{
SendStruct* ss=(SendStruct*)wparam;
CString str;
str.Format("%d,%d,%d,%d",ss->a,ss->b,ss->c,ss->d);
CEdit* edit1=(CEdit*)GetDlgItem(IDC_EDIT1);
edit1->SetWindowText(str);
free(ss);
return 0;
}
4. 在發送消息的函數中加入
SendStruct *ss = (SendStruct *)malloc(sizeof(SendStruct));
ss->a=1;
ss->b=2;
ss->c=3;
ss->d=4;
HWND hWnd = ::FindWindowEx(this->GetParent()->m_hWnd, NULL, NULL, RECEIVE1_TITLE);
hWnd = ::FindWindowEx( FromHandle(hWnd)-> GetDlgItem(IDC_TAB1)-> m_hWnd, NULL, NULL ,RECEIVE2_TITLE);
FromHandle(hWnd)->SendMessage(GET_STRUCT,(WPARAM)(ss),0);
這個就不多做解釋了。
錯誤的情況:下面說一下我在開始使用消息時使用錯誤的情況(我認爲這是錯的)。拿例2的第4步來說:
double a=1.1111;
HWND hWnd = ::FindWindowEx( this->GetParent()->m_hWnd, NULL, NULL, RECEIVE1_TITLE);
FromHandle(hWnd)->SendMessage(GET_DOUBLE,(WPARAM)(&a),0);
第3步中去掉delete a;
我認爲這是錯的,爲什麼呢?很多時候在發送完成消息之後,函數體就結束了,a的內存就會被收回了,而消息接收的函數可能在很久的時間內都使用這個變量,說不定什麼時候a的內存就被重新佔用了。如果a是一個很龐大的對象,這種現象可能會更明顯。
CDlgTestDlg::CDlgTestDlg
CDlgTestDlg::DoModal
CDialog::DoModal
CDlgTestDlg::PreSubclassWindow
CDlgTestDlg::OnCreate
CDlgTestDlg::OnSize
CDialog::OnInitDialog
CWndUpdateData(FALSE)
CDlgTestDlg::DoDataExchange
CDlgTestDlg::OnInitDialog
CDlgTestDlg::OnShowWindow
CDlgTestDlg::OnPaint
CDlgTestDlg::OnCtlColor
CDlgTestDlg::PreTranslateMessage
CDlgTestDlg::OnPaint