本篇文章属于《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);
- }