現象:使用 ClassWizard 將 RichEdit 控制項關聯 CString 變數,透過 DDX_Text 交換資料時,超過 64KB 的文字會遺失。
原因:DDX_Text 內部呼叫 GetWindowText,發送 WM_GETTEXT 訊息,但該訊息無法處理超過 64KB 的資料。
解決方案:自訂 DDX_RichText 函數,使用 EM_STREAMOUT 訊息串流讀取:
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 檔案註冊新 DDX 函數:
ExtraDDXCount=1
ExtraDDX1=7;;TextOver64KB;CString;;RichText;Retrieves text in excess of 64KB from RichEdit controls
或手動將程式碼中 DDX_Text 改為 DDX_RichText 並移出 ClassWizard 管理區塊。
現象:ClassWizard 加入 EN_SETFOCUS、EN_KILLFOCUS 處理函數,但完全不被呼叫。
原因:ClassWizard 錯誤生成 ON_NOTIFY 宏,正確應為 ON_EN_SETFOCUS/ON_EN_KILLFOCUS(命令訊息而非通知訊息)。
正確訊息映射:
ON_EN_SETFOCUS(IDC_RICHEDIT1, OnSetfocusRichedit1)
ON_EN_KILLFOCUS(IDC_RICHEDIT1, OnKillfocusRichedit1)
響應函數宣告:
afx_msg void OnSetfocusRichedit1();
afx_msg void OnKillfocusRichedit1();
需手動修正訊息映射巨集與函數簽章。
若 RichEdit 控制項 ID 未出現在 ClassWizard,需手動在 DoDataExchange 中加入:
DDX_Control(pDX, IDC_RICHEDIT1, m_richEditCtrl);
DDX_Text(pDX, IDC_RICHEDIT1, m_richedit);
DDV_MaxChars(pDX, m_richedit, 10);