• 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

  • 相关阅读:
    C#基础知识汇总(不断更新中)
    比较两个DataTable是否相等
    C#利用SerialPort控件进行串口编程小记
    C# ListBox 自动滚动到底部 方法:
    IIS配置文件的XML格式不正确 applicationHost.config崩溃 恢复解决办法
    net4log 添加自定义变量
    net4log 日志管理
    C#实现加简单的Http请求
    H5,Css小姐又作画了
    H5 ,Css实现了你的logo
  • 原文地址:https://www.cnblogs.com/MakeView660/p/6552736.html
Copyright © 2020-2023  润新知