本篇文章属于《518抽奖软件开发日志》系列文章的一部分。
我在开发《518抽奖软件》(www.518cj.net)的时候,要在文本框粘贴从别处复制来的名单。发现一个问题,就是一些Unix传过来的多行文本,粘贴后都变成了一行。原来,它的换行符跟Winodws的不一致导致的。解决方法就是,窗口子类化,在新的窗口过程中,专门处理这个粘贴消息,兼容Windows、Mac、Unix三种不同的文本换行符。具体代码如下:
void Tapp::subclass_init()
{
oldProc = (WNDPROC)SetClassLong(GetDlgItem(m_hLoading, IDC_loading_subclass), GCL_WNDPROC, (LONG)Proc_editBox);
}
void Tapp::subclass_remove()
{
if (oldProc)
{
SetClassLong(GetDlgItem(m_hLoading, IDC_loading_subclass), GCL_WNDPROC, (LONG)oldProc);
oldProc = NULL;
}
}
static LRESULT CALLBACK Proc_editBox(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
// 在粘贴时,处理换行符不一致
if (uMsg == WM_PASTE)
{
if (!IsClipboardFormatAvailable(CF_UNICODETEXT))
return 0;
if (!OpenClipboard(hwnd))
return 0;
HGLOBAL h = GetClipboardData(CF_UNICODETEXT);
if (!h) { CloseClipboard(); return 0; }
WCHAR* p = (WCHAR*)GlobalLock(h);
if (!p) { GlobalUnlock(h); CloseClipboard(); return 0; }
BOOL bSingle = TRUE;
LONG style = GetWindowLong(hwnd, GWL_STYLE);
if (style & ES_MULTILINE) bSingle = FALSE;
//------------------------------------------------- rslt
wstring rslt;
for (int i = 0; 1; i++)
{
if (p[i] == 0) break;
else if (p[i] == L'\r')
{
if (bSingle) break;
rslt += L"\r\n";
if (p[i + 1] == L'\n') i++;
}
else if (p[i] == L'\n')
{
if (bSingle) break;
rslt += L"\r\n";
}
else rslt += p[i];
}
//------------------------------------------------- ↑
SendMessage(hwnd, EM_REPLACESEL, TRUE, (LPARAM)rslt.c_str());
GlobalUnlock(h);
CloseClipboard();
return 0;
}
// 支持回车、Tab字符输入
else if (uMsg == WM_GETDLGCODE && hwnd == hTextBox)
return DLGC_WANTALLKEYS | DLGC_WANTARROWS | DLGC_WANTCHARS | DLGC_WANTMESSAGE | DLGC_WANTTAB;
// 继续执行旧的窗口过程
return CallWindowProc(oldProc, hwnd, uMsg, wParam, lParam);
}