其实最初是因为在项目中使用了html网页编辑器,通过ie的com组件和javascript通讯完成一些事情,其中有一个功能是插入表格,我们原本使用的range.pasteHTML(HTMLstr);根据用户传入的行和列等参数在javascript端创建好用户想要的表格的html字串,然后的然后,测试人员就发现一个bug,因为这种pasterHTML会破坏TextArea原本的剪切板内容,会直接导致无法撤销到插入表格之前(包含插入表格)的状态。

有一个同事想出一个方法,使用剪切板来代替pasterHTML这样的操作,因为粘贴一个html有格式的内容是可以撤销的,这样就又会涉及到一个问题,如果借用了剪切板的内容就需要备份之前的内容,并在使用完之后恢复,不管原来是图片、纯文本、还是word、表格、带格式的复杂的内容。

首先在MSDN上找到这篇文章:http://msdn.microsoft.com/en-us/library/windows/desktop/ms649015%28v=vs.85%29.aspx

因为我需要加入的是一个html表格所以找来了它所需要的格式,并使用SetClipboardData进行设置。

官方格式示例:

Version:0.9
StartHTML:71
EndHTML:170
StartFragment:140
EndFragment:160
StartSelection:140
EndSelection:160
<!DOCTYPE>
<HTML>
<HEAD>
<TITLE> The HTML Clipboard</TITLE>
<BASE HREF="http://sample/specs">
</HEAD>
<BODY>
<UL>
<!--StartFragment -->
<LI> The Fragment </LI>
<!--EndFragment -->
</UL>
</BODY>
</HTML>

View Code

构造header代码:

 1 int ClipboardHTMLHeader::size() const
 2 {
 3     const int numSpaces = 8;
 4     int headerSIZE = 8/*strlen("Version:")*/ + strlen(version);
 5     headerSIZE += 10/*strlen("StartHTML:")*/ + numSpaces;
 6     headerSIZE += 8/*strlen("EndHTML:")*/ + numSpaces;
 7     headerSIZE += 14/*strlen("StartFargment:")*/ + numSpaces;
 8     headerSIZE += 12/*strlen("EndFargment:")*/ + numSpaces;
 9     //headerSIZE += 15/*strlen("StartSelection:")*/ + numSpaces;
10     //headerSIZE += 13/*strlen("EndSelection:")*/ + numSpaces;
11     headerSIZE += 5/*fields*/ * 1;
12     return headerSIZE;
13 }
14
15 std::ostream& operator <<(std::ostream& os, const ClipboardHTMLHeader& header)
16 {
17     using namespace std;
18     const int numSpaces = 8;
19     const int headerSIZE = header.size();
20
21     os  << "Version:" << header.version << endl
22         << "StartHTML:" << setw(numSpaces) << setfill('0') << (header.StartHTML < 0 ? -1 : headerSIZE + header.StartHTML) << endl
23         << "EndHTML:" << setw(numSpaces) << setfill('0') << (header.EndHTML < 0 ? -1 : headerSIZE + header.EndHTML) << endl
24         << "StartFragment:" << setw(numSpaces) << setfill('0') << (header.StartFragment < 0 ? -1 : headerSIZE + header.StartFragment) << endl
25         << "EndFragment:" << setw(numSpaces) << setfill('0') << (header.EndFragment < 0 ? -1 : headerSIZE + header.EndFragment) << endl;
26         //<< "StartSelection:" << setw(numSpaces) << setfill('0') << (header.StartSelection < 0 ? -1 : headerSIZE + header.StartSelection) << endl
27         //<< "EndSelection:" << setw(numSpaces) << setfill('0') << (header.EndSelection < 0 ? -1 : headerSIZE + header.EndSelection) << endl;
28     return os;
29 }
30
31 bool CRichEditor::CopyHTMLToClipboard(LPCWSTR lpszWide)
32 {
33     using namespace std;
34
35     string html = "<!--StartFragment-->" + decode(lpszWide, CP_UTF8) + "<!--EndFragment-->";
36     char docBegin[] = "<HTML><HEAD><TITLE>*</TITLE></HEAD><BODY>";
37     char docEnd[]="</BODY></HTML>";
38
39     ClipboardHTMLHeader h;
40     h.version = "0.9";
41     h.StartHTML = 0;
42     h.EndHTML = sizeof(docBegin) + html.length() + sizeof(docEnd);
43     h.StartFragment = sizeof(docBegin);
44     h.EndFragment = sizeof(docBegin) + html.length();
45     //h.StartSelection = h.StartFragment;
46     //h.EndSelection = h.EndFragment;
47
48     stringstream ss;
49     ss << h;
50     ss << docBegin;
51     ss << html;
52     ss << docEnd;
53
54
55
56     // Get clipboard id for HTML format...
57     static int cfid = 0;
58     cfid = RegisterClipboardFormat(L"HTML Format");
59     // Open the clipboard...
60     if(::OpenClipboard(0)) {
61         EmptyClipboard();
62
63         HGLOBAL hMem = ::GlobalAlloc(GMEM_MOVEABLE/* |GMEM_DDESHARE*/, (int)ss.tellp() + 1);
64         char* buf = (char*)GlobalLock(hMem);
65         ss.read( buf, ss.tellp());
66         buf[ss.tellp()] = 0;
67         GlobalUnlock(hMem);
68
69         ::SetClipboardData(cfid, hMem);
70         CloseClipboard();
71         GlobalFree(hMem);
72     }
73
74     return false;
75 }

其中selection是可选的,重载了运算符<<,且定义了很多int类型记录它们的偏移量。

接下来需要在insert table的之前深拷贝剪切板的内容到内存中,在时候恢复内存的数据到剪切板中,这其中对用户都是不可知的并且速度也是相当快的。

刚开始我们以为GlobalLock剪切板所获得的内存块是安全的,所以写了代码在push的时候lock,然后在pop的时候unlock,谁知道调用EmptyClipboard后就照样清空了,只能老老实实的拷贝全部的内存数据了,我们采用了map来暂存剪切板中各种类型的数据,针对不同的format的clipboard分别存到不同的map中。

 1 std::map<UINT, HGLOBAL> _clipdata;
 2 void CRichEditor::popClipboardData()
 3 {
 4     ::OpenClipboard(0);
 5     ::EmptyClipboard();
 6     for (auto it = _clipdata.begin(); it != _clipdata.end(); ++it)
 7         ::SetClipboardData(it->first, it->second);
 8     ::CloseClipboard();
 9
10     for (auto it = _clipdata.begin(); it != _clipdata.end(); ++it)
11         ::GlobalFree(it->second);
12
13     _clipdata.clear();
14 }
15
16 void CRichEditor::pushClipboardData()
17 {
18     ::OpenClipboard(0);
19
20     for (UINT next = ::EnumClipboardFormats(0); next != 0; next = ::EnumClipboardFormats(next))
21     {
22         if(::IsClipboardFormatAvailable(next))
23         {
24             HGLOBAL hmem = ::GetClipboardData(next);
25             void* src = ::GlobalLock(hmem);
26             SIZE_T bytes = ::GlobalSize(hmem);
27
28             _clipdata[next] = ::GlobalAlloc( GMEM_MOVEABLE, bytes );
29
30             void* dst = ::GlobalLock( _clipdata[next] );
31             memcpy(dst, src, bytes);
32             ::GlobalUnlock(_clipdata[next]);
33
34             ::GlobalUnlock(hmem);
35         }
36     }
37
38     ::EmptyClipboard();
39     ::CloseClipboard();
40 }

切记第10、11行必须这样写,必须在CloseClipboard之后来GlobalFree,否则就没办法恢复到备份clipboard之前的状态了。

差不多到这里就是今天一天的奇遇的全部内容了。。。

相信很多人碰到这个问题的时候最开始都受到

http://stackoverflow.com/questions/15962982/how-to-set-html-unicode-text-to-clipboard-in-vc

http://social.msdn.microsoft.com/Forums/es-ES/acc07c85-d0d3-4c4d-83e9-08f1a239758c/how-to-set-html-unicode-text-to-clipboard-in-vc?forum=vcgeneral

所误导,根本就不能用,问题是代码写的乱七八糟,怕是只有自己能看得懂。例如105这个数值是怎么来的?length+4又为什么?

希望祖国的花朵们不要再受到外国人的毒代码摧残了。。.今天就写到这里,希望black早点回家~

转载于:https://www.cnblogs.com/hyb1/p/3378065.html

windows剪切板暂存相关推荐

  1. windows剪切板文本和文件的获取设置

    介绍 windows剪切板的内容包含很多不同的格式,例如:CF_TEXT.CF_BITMAP.CF_METAFILEPICT.CF_SYLK.CF_DIF.CF_TIFF.CF_OEMTEXT.CF_ ...

  2. Windows 剪切板的应用——复制浏览器or本地目录图片

    一.简述 最近看了windows的剪切板相关的应用代码,于是乎,便想将浏览器中复制的图片保存到本地,经过尝试,通过以下代码完成在浏览器中右键选择复制图片,然后监控键盘事件,当按下Ctrl + v 时保 ...

  3. windows剪切板的历史记录

    windows剪切板的历史记录 最近遇到一件比较坑的事情.当然可能也是我本人粗心大意了吧.但是这种事情难免要发生.比如说你要移动一个比较重要的东西,然后按了ctrl+x,但是之间因为别的事情耽搁了一下 ...

  4. windows剪切板api

    Windows 剪切板API详解 (一) ChangeClipboardChain  将剪贴的连接从一个句柄转到下一个句柄.  BOOL ChangeClipboardChain(  HWND hWn ...

  5. 如何获取windows剪切板中内容

    一个简单的获取windows剪切板中文本内容的代码 // 获取剪切板中的内容public static String getClipboardText() {Clipboard clip = Tool ...

  6. 如何对Windows剪切板里的内容进行取证分析 Windows剪切板取证

    前言 无论是在现实中对设备进行取证分析,还是在ctf中做取证类的题目,剪切板里的内容都需要去查看,以免遗漏什么重要信息 剪切板位置 剪切板是计算机操作系统提供的一个临时存储区域,用于在不同应用程序之间 ...

  7. 写入windows剪切板,粘贴出来乱码

    操作windows剪切板,写入正常,粘贴出来时候乱码了. 之前的代码: BOOL CopyStringToClipBoard( HWND hOwner, CString strSource ) {if ...

  8. matlab复制矢量图形,Matlab4.2b提供了将wmf格式矢量图复制到Windows剪切板.doc

    Matlab4.2b提供了将wmf格式矢量图复制到Windows剪切板.doc Matlab 4.2b提供了将wmf格式矢量图复制到Windows剪切板的功能,可以将它直接粘贴到Word文档中而不发生 ...

  9. 在Git for windows(MSYS2)中实现tmux和windows剪切板的共享功能

    一直以来个人开发环境中linux下tmux和系统剪切板的共享功能都是通过xclip机制实现的,废话不多说直接贴在用的tmux配置文件吧: # 显示vi-cope模式下的映射 tmux list-key ...

最新文章

  1. Unity网络多玩家游戏开发教程(上册)
  2. 用iPhone薅Google羊毛:相册可无限存储高清照片,只要一步设置就搞定
  3. nginx+tomcat的负载均衡
  4. python程序会监控错误的语句_python装饰器实现对异常代码出现进行自动监控
  5. asp.net读取用户控件,自定义加载用户控件
  6. qq互联开放平台 开源SDK共享 常见问题
  7. vue element container 子路由
  8. Error 2503 and 2502 when installing/uninstalling on Windows 10
  9. TeeChart Pro VCL,提供高性能图表
  10. Android jdwp 自动断开,android – 安装调试器有时会导致应用程序崩溃
  11. 进销存excel_Excel教程:简易进销存!厉害了,SUMIFS!
  12. Delphi FireMonkey 的动画以及多线程
  13. html css 鼠标手势,CSS设置鼠标手势:cursor属性说明
  14. “Java:詹姆斯?”
  15. 加密系列 | SHA加密和解密算法详解代码示例
  16. web攻击之一:XSS跨站脚本
  17. 软件项目延期,怎么办?
  18. 五、椒盐排骨(Pepper Salt Spareribs)
  19. 深度学习基于DEAP的脑电情绪识别情感分类(附代码)
  20. c语言程序设计上机总结,C语言程序设计上机实践心得报告.doc

热门文章

  1. 比起第一代,《最后生还者2》到底做错了什么?
  2. 五个简单的原则,带你写出整洁代码
  3. 学习手机游戏原画设计需要多长时间?难学吗?
  4. springboot2.5.0 整合 redis 配置详解
  5. 【2022年蓝桥杯】蓝桥杯第一次海选考试题(5题考试大二)(C#题解)
  6. 【JavaScript脚本】——T2事件操作
  7. 【Java】switch 是否能作用在 byte 上,是否能作用在 long 上,是否能作用在 String 上
  8. 从Oracle9i中发送电子邮件
  9. antd 刷新页面及后退时菜单栏高亮问题
  10. Yii CDBCriteria常用方法