windows剪切板暂存
其实最初是因为在项目中使用了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>
构造header代码:
int ClipboardHTMLHeader::size() const
{
const int numSpaces = ;
int headerSIZE = /*strlen("Version:")*/ + strlen(version);
headerSIZE += /*strlen("StartHTML:")*/ + numSpaces;
headerSIZE += /*strlen("EndHTML:")*/ + numSpaces;
headerSIZE += /*strlen("StartFargment:")*/ + numSpaces;
headerSIZE += /*strlen("EndFargment:")*/ + numSpaces;
//headerSIZE += 15/*strlen("StartSelection:")*/ + numSpaces;
//headerSIZE += 13/*strlen("EndSelection:")*/ + numSpaces;
headerSIZE += /*fields*/ * ;
return headerSIZE;
} std::ostream& operator <<(std::ostream& os, const ClipboardHTMLHeader& header)
{
using namespace std;
const int numSpaces = ;
const int headerSIZE = header.size(); os << "Version:" << header.version << endl
<< "StartHTML:" << setw(numSpaces) << setfill('') << (header.StartHTML < ? - : headerSIZE + header.StartHTML) << endl
<< "EndHTML:" << setw(numSpaces) << setfill('') << (header.EndHTML < ? - : headerSIZE + header.EndHTML) << endl
<< "StartFragment:" << setw(numSpaces) << setfill('') << (header.StartFragment < ? - : headerSIZE + header.StartFragment) << endl
<< "EndFragment:" << setw(numSpaces) << setfill('') << (header.EndFragment < ? - : headerSIZE + header.EndFragment) << endl;
//<< "StartSelection:" << setw(numSpaces) << setfill('0') << (header.StartSelection < 0 ? -1 : headerSIZE + header.StartSelection) << endl
//<< "EndSelection:" << setw(numSpaces) << setfill('0') << (header.EndSelection < 0 ? -1 : headerSIZE + header.EndSelection) << endl;
return os;
} bool CRichEditor::CopyHTMLToClipboard(LPCWSTR lpszWide)
{
using namespace std; string html = "<!--StartFragment-->" + decode(lpszWide, CP_UTF8) + "<!--EndFragment-->";
char docBegin[] = "<HTML><HEAD><TITLE>*</TITLE></HEAD><BODY>";
char docEnd[]="</BODY></HTML>"; ClipboardHTMLHeader h;
h.version = "0.9";
h.StartHTML = ;
h.EndHTML = sizeof(docBegin) + html.length() + sizeof(docEnd);
h.StartFragment = sizeof(docBegin);
h.EndFragment = sizeof(docBegin) + html.length();
//h.StartSelection = h.StartFragment;
//h.EndSelection = h.EndFragment; stringstream ss;
ss << h;
ss << docBegin;
ss << html;
ss << docEnd; // Get clipboard id for HTML format...
static int cfid = ;
cfid = RegisterClipboardFormat(L"HTML Format");
// Open the clipboard...
if(::OpenClipboard()) {
EmptyClipboard(); HGLOBAL hMem = ::GlobalAlloc(GMEM_MOVEABLE/* |GMEM_DDESHARE*/, (int)ss.tellp() + );
char* buf = (char*)GlobalLock(hMem);
ss.read( buf, ss.tellp());
buf[ss.tellp()] = ;
GlobalUnlock(hMem); ::SetClipboardData(cfid, hMem);
CloseClipboard();
GlobalFree(hMem);
} return false;
}
其中selection是可选的,重载了运算符<<,且定义了很多int类型记录它们的偏移量。
接下来需要在insert table的之前深拷贝剪切板的内容到内存中,在时候恢复内存的数据到剪切板中,这其中对用户都是不可知的并且速度也是相当快的。
刚开始我们以为GlobalLock剪切板所获得的内存块是安全的,所以写了代码在push的时候lock,然后在pop的时候unlock,谁知道调用EmptyClipboard后就照样清空了,只能老老实实的拷贝全部的内存数据了,我们采用了map来暂存剪切板中各种类型的数据,针对不同的format的clipboard分别存到不同的map中。
std::map<UINT, HGLOBAL> _clipdata;
void CRichEditor::popClipboardData()
{
::OpenClipboard();
::EmptyClipboard();
for (auto it = _clipdata.begin(); it != _clipdata.end(); ++it)
::SetClipboardData(it->first, it->second);
::CloseClipboard(); for (auto it = _clipdata.begin(); it != _clipdata.end(); ++it)
::GlobalFree(it->second); _clipdata.clear();
} void CRichEditor::pushClipboardData()
{
::OpenClipboard(); for (UINT next = ::EnumClipboardFormats(); next != ; next = ::EnumClipboardFormats(next))
{
if(::IsClipboardFormatAvailable(next))
{
HGLOBAL hmem = ::GetClipboardData(next);
void* src = ::GlobalLock(hmem);
SIZE_T bytes = ::GlobalSize(hmem); _clipdata[next] = ::GlobalAlloc( GMEM_MOVEABLE, bytes ); void* dst = ::GlobalLock( _clipdata[next] );
memcpy(dst, src, bytes);
::GlobalUnlock(_clipdata[next]); ::GlobalUnlock(hmem);
}
} ::EmptyClipboard();
::CloseClipboard();
}
切记第10、11行必须这样写,必须在CloseClipboard之后来GlobalFree,否则就没办法恢复到备份clipboard之前的状态了。
差不多到这里就是今天一天的奇遇的全部内容了。。。
相信很多人碰到这个问题的时候最开始都受到
http://stackoverflow.com/questions/15962982/how-to-set-html-unicode-text-to-clipboard-in-vc
所误导,根本就不能用,问题是代码写的乱七八糟,怕是只有自己能看得懂。例如105这个数值是怎么来的?length+4又为什么?
希望祖国的花朵们不要再受到外国人的毒代码摧残了。。.今天就写到这里,希望black早点回家~
windows剪切板暂存的更多相关文章
- 监视 Windows 剪切板
一.先看代码 import win32con,win32gui import win32clipboard as cb class MyWindow(): def __init__(self): #注 ...
- 读取图片文件MetaFile放入Windows剪切板
前言 前段时间群里有个小伙在工作中遇到一个问题,透明的图片存入剪切板在粘贴到adobe PDF中出现不透明问题但是粘贴到Excel可以,还有就是从excel复制再粘贴到PDF也是可以.小伙在群里发了两 ...
- Delphi的windows剪切板操作函数
1. Clipbrd函数 function Clipboard: TClipboard;:若应用程序从未使用过剪贴板,则调用该函数形成新的剪贴板:若之前使用过剪贴板则返回使用过的剪贴板. 属性: As ...
- 使用python读写windows剪切板
import win32clipboard as w import win32con base_addr = 0x8e00000 buffer_len = 0x123 def getText(): w ...
- 【笨嘴拙舌WINDOWS】实践检验之剪切板查看器【Delphi】
该程序能够监视Windows剪切板的内容(文字和图片) 其思路是 先调用SetClipBoardViewer(Self.Handle),让Windows剪切板内容发生改变之后,通知本程序: 然后截获W ...
- 经验分享:计算机 web 浏览器——访问剪切板图片
有时候,我们希望能访问用户的剪切板,来实现一些方便用户的功能:但是另一方面,剪切板里的数据对用户来说又是非常隐私的,所以浏览器在获取信息方面有安全限制,同时也提供访问接口. 当我们需要实现在富文本 ...
- 重新想象 Windows 8 Store Apps (40) - 剪切板: 复制/粘贴文本, html, 图片, 文件
[源码下载] 重新想象 Windows 8 Store Apps (40) - 剪切板: 复制/粘贴文本, html, 图片, 文件 作者:webabcd 介绍重新想象 Windows 8 Store ...
- 背水一战 Windows 10 (102) - 应用间通信: 剪切板
[源码下载] 背水一战 Windows 10 (102) - 应用间通信: 剪切板 作者:webabcd 介绍背水一战 Windows 10 之 应用间通信 剪切板 - 基础, 复制/粘贴 text ...
- 【Windows API】OpenClipboard --- 剪切板(转)
原文转自 http://www.cnblogs.com/wind-net/archive/2012/11/01/2749558.html 剪切板:系统维护的一个全局公共内存区域.每次只允许一个进程对其 ...
随机推荐
- Reboot
目标是将浏览器的预设样式设为一致 Native font stack 本机字体堆栈 由于padding 及 border 会改变元素在运算后的宽度 此时的实际宽度为: width+左右padding ...
- Educational Codeforces Round 52F(树形DP,VECTOR)
#include<bits/stdc++.h>using namespace std;int n,k;vector<int>son[1000007];int dp[100000 ...
- 三层登录——C#版
前言 前期了解三层架构主要是由UI层.BLL层和DAL层三部分构成.看到大牛们都采用三层的思想实现了登录,本菜鸟暗暗地站在了他们的肩膀上. 自己理解 对于三层自己的理解是:就像我们对一个大型的公司去找 ...
- KSOAP2使用注意点汇总
注意返回类型,如果是XML格式,使用 1:SoapObject soapObject = (SoapObject) envelope.getResponse(); 2:SoapObject resul ...
- java 调用SAP RFC函数错误信息
RFC接口调用SAP如果有异常会通过com.sap.mw.jco.JCO$Exception: 抛出异常 在开发中遇到的异常有如下 用户名密码可能是错误或者用户无权限,确认用户,必要时联系SAP负责人 ...
- Mybatis插件Plugin
Mybatis开源Plugin中最熟知的pagehelper,重点made in China 很多人开始用pagehelper时候,肯定很纳闷,以mysql为例,明明没有加limit语句,为什么打印出 ...
- 让你的IDEA倍爽
使用IDEA开发有 一段时间了,从陌生到熟悉的过程算是很平稳的度过,感谢IntelliJ IDEA交流群(群号244908708)里面的群友对我提供的帮助,感谢群主的github上面提供的资料. 这篇 ...
- MySQL的复制:MySQL系列之十三
一.MySQL复制相关概念 主从复制:主节点将数据同步到多个从节点 级联复制:主节点将数据同步到一个从节点,其他的从节点在向从节点复制数据 同步复制:将数据从主节点全部同步到从节点时才返回给用户的复制 ...
- C 语言实例 - 计算一个数的 n 次方
C 语言实例 - 计算一个数的 n 次方 计算一个数的 n 次方,例如: ,其中 为基数, 为指数. 实例 - 使用 while #include <stdio.h> int main() ...
- 《SQL 进阶教程》 自连接分组排序:练习题1-2-2
分组排序 SELECT d1.district, d1. NAME, (SELECT COUNT(d2.price) FROM district_products d2 WHERE d2.price ...