VC++ :传统剪贴板的延迟提交技术

  传统剪贴板存在的局限

  传统剪贴板有一个局限性:剪贴板上的所有数据都要保存在内存上。
  对于文本字符串和其它简单数据类型,可以快速有效地传递。但是,对于比较大的数据,清空剪贴板之前,数据都要占用较大的内存。而如果没有人粘贴这个位图,给它分配的内存就毫无用处。

  延迟提交技术 

  为了避免这种浪费,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

原文地址:https://www.cnblogs.com/MakeView660/p/6552736.html