問(wèn)題1:RichEditCtrl在用DDX進(jìn)行數(shù)據(jù)交換的時(shí)候會(huì)發(fā)生數(shù)據(jù)丟失問(wèn)題?為什么!
當(dāng)我們?cè)谕狭艘粋€(gè)控件到程序里后,通常的做發(fā)是Ctrl+W,用類(lèi)向?qū)Ыo控件關(guān)聯(lián)一個(gè)變量,然后依靠DDX/DDV進(jìn)行數(shù)據(jù)交換,如果我們用同樣的方法來(lái)給RICHEDIT關(guān)聯(lián)一個(gè)CString類(lèi)型的變量就會(huì)存在一個(gè)問(wèn)題,就是如果我們的數(shù)據(jù)大于了64K,數(shù)據(jù)就會(huì)丟失。
通過(guò)查MSDN發(fā)現(xiàn),WM_GETTEXT消息并沒(méi)有設(shè)計(jì)在RICHEDIT的數(shù)據(jù)大于64K的時(shí)候怎樣處理。而類(lèi)向?qū)傻拇a是用DDX_Text來(lái)交換控件和CString變量的數(shù)據(jù)。恰好,DDX_Text函數(shù)是調(diào)用GetWindowText函數(shù),而這個(gè)函數(shù)又會(huì)發(fā)出WM_GETTEXT消息到控件來(lái)返回控件里的數(shù)據(jù)。WM_GETTEXT消息不能接受超過(guò)64K的數(shù)據(jù),因此導(dǎo)致了RICHEDIT在數(shù)據(jù)交換的時(shí)候發(fā)生了丟失。
為了解決這個(gè)問(wèn)題,我們要用到DDX_RichText函數(shù)。添加下面兩個(gè)函數(shù)到工程
以下是引用片段:
DWORD CALLBACK ES2MemCallBack(DWORD_PTR dwCookie,LPBYTE pbBuff, LONG cb, LONG *pcb)
{
LPTSTR& lpszStrFill = *(LPTSTR*)dwCookie;
memcpy(lpszStrFill, pbBuff, *pcb = cb);
lpszStrFill += cb;
*lpszStrFill = TCHAR('\0');
return 0;
}
void AFXAPI DDX_RichText(CDataExchange* pDX, int nIDC, CString& value)
{
extern void AFXAPI AfxSetWindowText(HWND hWndCtrl, LPCTSTR lpszNew);
HWND hWndCtrl = pDX->PrepareEditCtrl(nIDC);
if (pDX->m_bSaveAndValidate)
{
int nLen = ::GetWindowTextLength(hWndCtrl);
LPTSTR lpszStrFill = value.GetBufferSetLength(nLen);
EDITSTREAM es = { (DWORD_PTR) &lpszStrFill, 0, ES2MemCallBack };
::SendMessage(hWndCtrl, EM_STREAMOUT, SF_TEXT, (LPARAM) &es);
value.ReleaseBuffer();
}
else
{
AfxSetWindowText(hWndCtrl, value);
}
}
之后我們還需要修改工程的.clw文件,用文本方式打開(kāi).clw文件。參考里面類(lèi)的格式加下面兩行代碼:
以下是引用片段:
ExtraDDXCount=1
ExtraDDX1=7;;TextOver64KB;CString;;RichText;Retrieves text in excess of 64KB from RichEdit controls
如果沒(méi)有采用上面的步驟,我們就需要手動(dòng)修改代碼,把所有的DDX_Text改為DDX_RichText。同時(shí)要把他們移到類(lèi)向?qū)Э刂拼a的外面。也就是移出:
以下是引用片段:
//{{AFX_DATA_INIT(...)
//}}AFX_DATA_INIT
//{{AFX_DATA_MAP(...)
//}}AFX_DATA_MAP
reference:
Q280447 BUG: Text from a Rich Edit Control Is Truncated During Dialog Data Exchange (DDX)
問(wèn)題2:當(dāng)我們用類(lèi)向?qū)Ыorichedit添加了EN_SETFOCUS, EN_KILLFOCUS的函數(shù)后卻不能響應(yīng),我發(fā)現(xiàn)這個(gè)響應(yīng)函數(shù)根本就沒(méi)有被調(diào)用。即使是一個(gè)MessageBox()函數(shù)也不會(huì)調(diào)用。
原來(lái)是默認(rèn)的消息映射添加錯(cuò)誤了。
正確的消息影射和響應(yīng)應(yīng)該是:
以下是引用片段:
ON_EN_SETFOCUS(IDC_RICHEDIT1,OnSetfocusRichedit1)
ON_EN_KILLFOCUS(IDC_RICHEDIT1,OnKillfocusRichedit1)
響應(yīng)函數(shù)形式為:
以下是引用片段:
afx_msg void OnSetfocusRichedit1();
afx_msg void OnKillfocusRichedit1();
但是如果我們用類(lèi)向?qū)?lái)直接添加,生成的代碼卻是:
以下是引用片段:
ON_NOTIFY(EN_SETFOCUS, IDC_RICHEDIT1, OnSetfocusRichedit1)
ON_NOTIFY(EN_KILLFOCUS, IDC_RICHEDIT1, OnKillfocusRichedit1)
我們需要自己手動(dòng)改為上面的形式。
還有一個(gè)問(wèn)題就是RichEditCtrl有時(shí)候不會(huì)出現(xiàn)在類(lèi)向?qū)У目丶蘒D列表里。這就需要我們自己添加DDX/DDV函數(shù)。自己動(dòng)手啦!^_^
以下是引用片段:
-- sampledlg.h --
class CSampleDlg : public CDialog
{
public:
CSampleDlg(CWnd* pParent = NULL);
// Dialog Data
//{{AFX_DATA(CSampleDlg)
enum { IDD = IDD_SAMPLE_DIALOG };
CString m_edit; // Added by ClassWizard for an edit control
//}}AFX_DATA
// Manually add member variables for the rich edit control
CRichEditCtrl m_richEditCtrl;
.......
sampledlg.cpp --
......
void CSampleDlg::DoDataExchange(CDataExchange* pDX)
{
CDialog::DoDataExchange(pDX);
//{{AFX_DATA_MAP(CSampleDlg)
DDX_Text(pDX, IDC_EDIT, m_edit);
DDV_MaxChars(pDX, m_edit, 10);
//}}AFX_DATA_MAP
// Manually add DDX_Control, DDX_Text and DDV_MaxChars for the
// rich edit control
DDX_Control(pDX, IDC_RICHEDIT1, m_richEditCtrl);
DDX_Text(pDX, IDC_RICHEDIT1, m_richedit);
DDV_MaxChars(pDX, m_richedit, 10);
}
當(dāng)我們?cè)谕狭艘粋€(gè)控件到程序里后,通常的做發(fā)是Ctrl+W,用類(lèi)向?qū)Ыo控件關(guān)聯(lián)一個(gè)變量,然后依靠DDX/DDV進(jìn)行數(shù)據(jù)交換,如果我們用同樣的方法來(lái)給RICHEDIT關(guān)聯(lián)一個(gè)CString類(lèi)型的變量就會(huì)存在一個(gè)問(wèn)題,就是如果我們的數(shù)據(jù)大于了64K,數(shù)據(jù)就會(huì)丟失。
通過(guò)查MSDN發(fā)現(xiàn),WM_GETTEXT消息并沒(méi)有設(shè)計(jì)在RICHEDIT的數(shù)據(jù)大于64K的時(shí)候怎樣處理。而類(lèi)向?qū)傻拇a是用DDX_Text來(lái)交換控件和CString變量的數(shù)據(jù)。恰好,DDX_Text函數(shù)是調(diào)用GetWindowText函數(shù),而這個(gè)函數(shù)又會(huì)發(fā)出WM_GETTEXT消息到控件來(lái)返回控件里的數(shù)據(jù)。WM_GETTEXT消息不能接受超過(guò)64K的數(shù)據(jù),因此導(dǎo)致了RICHEDIT在數(shù)據(jù)交換的時(shí)候發(fā)生了丟失。
為了解決這個(gè)問(wèn)題,我們要用到DDX_RichText函數(shù)。添加下面兩個(gè)函數(shù)到工程
以下是引用片段:
DWORD CALLBACK ES2MemCallBack(DWORD_PTR dwCookie,LPBYTE pbBuff, LONG cb, LONG *pcb)
{
LPTSTR& lpszStrFill = *(LPTSTR*)dwCookie;
memcpy(lpszStrFill, pbBuff, *pcb = cb);
lpszStrFill += cb;
*lpszStrFill = TCHAR('\0');
return 0;
}
void AFXAPI DDX_RichText(CDataExchange* pDX, int nIDC, CString& value)
{
extern void AFXAPI AfxSetWindowText(HWND hWndCtrl, LPCTSTR lpszNew);
HWND hWndCtrl = pDX->PrepareEditCtrl(nIDC);
if (pDX->m_bSaveAndValidate)
{
int nLen = ::GetWindowTextLength(hWndCtrl);
LPTSTR lpszStrFill = value.GetBufferSetLength(nLen);
EDITSTREAM es = { (DWORD_PTR) &lpszStrFill, 0, ES2MemCallBack };
::SendMessage(hWndCtrl, EM_STREAMOUT, SF_TEXT, (LPARAM) &es);
value.ReleaseBuffer();
}
else
{
AfxSetWindowText(hWndCtrl, value);
}
}
之后我們還需要修改工程的.clw文件,用文本方式打開(kāi).clw文件。參考里面類(lèi)的格式加下面兩行代碼:
以下是引用片段:
ExtraDDXCount=1
ExtraDDX1=7;;TextOver64KB;CString;;RichText;Retrieves text in excess of 64KB from RichEdit controls
如果沒(méi)有采用上面的步驟,我們就需要手動(dòng)修改代碼,把所有的DDX_Text改為DDX_RichText。同時(shí)要把他們移到類(lèi)向?qū)Э刂拼a的外面。也就是移出:
以下是引用片段:
//{{AFX_DATA_INIT(...)
//}}AFX_DATA_INIT
//{{AFX_DATA_MAP(...)
//}}AFX_DATA_MAP
reference:
Q280447 BUG: Text from a Rich Edit Control Is Truncated During Dialog Data Exchange (DDX)
問(wèn)題2:當(dāng)我們用類(lèi)向?qū)Ыorichedit添加了EN_SETFOCUS, EN_KILLFOCUS的函數(shù)后卻不能響應(yīng),我發(fā)現(xiàn)這個(gè)響應(yīng)函數(shù)根本就沒(méi)有被調(diào)用。即使是一個(gè)MessageBox()函數(shù)也不會(huì)調(diào)用。
原來(lái)是默認(rèn)的消息映射添加錯(cuò)誤了。
正確的消息影射和響應(yīng)應(yīng)該是:
以下是引用片段:
ON_EN_SETFOCUS(IDC_RICHEDIT1,OnSetfocusRichedit1)
ON_EN_KILLFOCUS(IDC_RICHEDIT1,OnKillfocusRichedit1)
響應(yīng)函數(shù)形式為:
以下是引用片段:
afx_msg void OnSetfocusRichedit1();
afx_msg void OnKillfocusRichedit1();
但是如果我們用類(lèi)向?qū)?lái)直接添加,生成的代碼卻是:
以下是引用片段:
ON_NOTIFY(EN_SETFOCUS, IDC_RICHEDIT1, OnSetfocusRichedit1)
ON_NOTIFY(EN_KILLFOCUS, IDC_RICHEDIT1, OnKillfocusRichedit1)
我們需要自己手動(dòng)改為上面的形式。
還有一個(gè)問(wèn)題就是RichEditCtrl有時(shí)候不會(huì)出現(xiàn)在類(lèi)向?qū)У目丶蘒D列表里。這就需要我們自己添加DDX/DDV函數(shù)。自己動(dòng)手啦!^_^
以下是引用片段:
-- sampledlg.h --
class CSampleDlg : public CDialog
{
public:
CSampleDlg(CWnd* pParent = NULL);
// Dialog Data
//{{AFX_DATA(CSampleDlg)
enum { IDD = IDD_SAMPLE_DIALOG };
CString m_edit; // Added by ClassWizard for an edit control
//}}AFX_DATA
// Manually add member variables for the rich edit control
CRichEditCtrl m_richEditCtrl;
.......
sampledlg.cpp --
......
void CSampleDlg::DoDataExchange(CDataExchange* pDX)
{
CDialog::DoDataExchange(pDX);
//{{AFX_DATA_MAP(CSampleDlg)
DDX_Text(pDX, IDC_EDIT, m_edit);
DDV_MaxChars(pDX, m_edit, 10);
//}}AFX_DATA_MAP
// Manually add DDX_Control, DDX_Text and DDV_MaxChars for the
// rich edit control
DDX_Control(pDX, IDC_RICHEDIT1, m_richEditCtrl);
DDX_Text(pDX, IDC_RICHEDIT1, m_richedit);
DDV_MaxChars(pDX, m_richedit, 10);
}