传统剪贴板存在的局限
传统剪贴板有一个局限性:剪贴板上的所有数据都要保存在内存上。
对于文本字符串和其它简单数据类型,可以快速有效地传递。但是,对于比较大的数据,清空剪贴板之前,数据都要占用较大的内存。而如果没有人粘贴这个位图,给它分配的内存就毫无用处。
延迟提交技术
为了避免这种浪费,Windows支持延迟提交。即直到需要的时候才将数据复制到剪贴板。
首先,用有效的剪贴板格式和NULL数据句柄调用::SetClipboardData。
然后,响应WM_RENDERFORMAT消息,调用::SetClipboardData将数据真正地放入剪贴板。
应用调用::GetClipboardData请求获取指定格式的数据时,就会发送WM_RENDERFORMAT消息。
如果没有人请求数据,就不会传递这条消息,就无需分配10MB的内存。
要注意,该消息的处理函数不应该调用::OpenClipboard和::CloseClipboard,因为接收该消息的窗口,收到消息时就占有了剪贴板。
处理WM_RENDERFORMAT消息的应用还必须处理WM_RENDERALLFORMATS消息。
当应用终止而剪贴板拥有应用放置的NULL数据句柄时,就会发送这条消息。
该消息处理函数的任务是打开剪贴板、传递应用承诺提供的数据、关闭剪贴板。
将数据放入剪贴板,保证使用延迟提交的应用终止后,其它应用可以使用这些数据。
延迟提交中还会使用WM_DESTROYCLIPBOARD消息。
这条消息通知应用不需要再提供延迟提交数据。
当其它应用调用::EmptyClipboard时,发送该消息。
在WM_RENDERALLFORMATS消息之后也发送该消息。
如果你拥有响应WM_RENDERFORMAT和WM_RENDERALLFORMATS所需的资源,可以在收到WM_DESTROYCLIPBOARD消息时安全释放它们。
测试实现
新建一个基于对话框的MFC应用程序,取名为TradClipboard;
一路“Next”到底;
在主对话框上增加一个按钮(IDC_BTN_SETCLIPBOARD);
在TradClipboardDlg.h中, 声明消息响应:
// Generated message map functions //{{AFX_MSG(CTradClipboardDlg) virtual BOOL OnInitDialog(); afx_msg void OnSysCommand(UINT nID, LPARAM lParam); afx_msg void OnPaint(); afx_msg HCURSOR OnQueryDragIcon(); afx_msg void OnLButtonDown(UINT nFlags, CPoint point); afx_msg void OnRenderFormat (UINT nFormat); afx_msg void OnRenderAllFormats (); afx_msg void OnDestroyClipboard (); afx_msg void OnBtnSetClipboard(); //}}AFX_MSG DECLARE_MESSAGE_MAP()
在TradClipboardDlg.cpp中, 添加消息响应映射并实现:
BEGIN_MESSAGE_MAP(CTradClipboardDlg, CDialog) //{{AFX_MSG_MAP(CTradClipboardDlg) ON_WM_SYSCOMMAND() ON_WM_PAINT() ON_WM_QUERYDRAGICON() ON_BN_CLICKED(IDC_BTN_SET_CLIPBOARD, OnBtnSetClipboard) ON_WM_LBUTTONDOWN() ON_WM_RENDERFORMAT() ON_WM_RENDERALLFORMATS() ON_WM_DESTROYCLIPBOARD() //}}AFX_MSG_MAP END_MESSAGE_MAP() void CTradClipboardDlg::OnLButtonDown(UINT nFlags, CPoint point) { MessageBox(_T("Empty zone is clicked!")); CDialog::OnLButtonDown(nFlags, point); } void CTradClipboardDlg::OnBtnSetClipboard() { if(!OpenClipboard()) { MessageBox(_T("Open Clipboard Error!")); return; } if(!EmptyClipboard() ) { MessageBox(_T("Empty Clipboard Error")); return; } SetClipboardData( CF_TEXT, NULL) ; CloseClipboard(); } void CTradClipboardDlg::OnRenderFormat (UINT nFormat) { if (nFormat == CF_TEXT) { DWORD dwLength = 14; HANDLE hGlobalMemory = GlobalAlloc(GHND, dwLength + 1); LPBYTE lpGlobalMemory = (LPBYTE)GlobalLock(hGlobalMemory); char* pText = "Michael Jordan"; for (int i = 0; i < dwLength; i++) *lpGlobalMemory++ = *pText++; GlobalUnlock(hGlobalMemory); SetClipboardData(CF_TEXT, hGlobalMemory); MessageBox("OnRenderFormat");
// Make a copy of the bitmap, and store the handle in hBitmap. //::SetClipboardData (CF_BITMAP, hBitmap); } } void CTradClipboardDlg::OnRenderAllFormats () { ::OpenClipboard(m_hWnd); OnRenderFormat(CF_TEXT); CloseClipboard(); } void CTradClipboardDlg::OnDestroyClipboard () { // Delete the temporary file. MessageBox("OnDestroyClipboard"); }
运行:
测试代码下载:
链接:http://pan.baidu.com/s/1i5zEhpV 密码:89hx