百科问答小站 logo
百科问答小站 font logo



当我们在电脑按下ctrl+c,剪切板储存了哪些信息? 第1页

  

user avatar   lu-ren-25-37 网友的相关建议: 
      

论逼呼的精准推送……

这两天刚在steam上架了一个相关的工具以填补steam上没有此类工具的空白,就刷到这么个问题。


回到正题。首先,剪贴板本质上是一片共享内存,只不过跟普通的共享内存不太一样的是,其由操作系统管理各个程序的访问权限,并提供额外的高级功能。

简单解答问题正文中的提问,需要一些比喻,比喻不可避免的会损失一些细节信息,如果对程序实现有兴趣的话,文章最后我会写一些。

以问题中第二问举例剪贴板的交互

再或者,当我在浏览器中复制一段内容,粘贴到word中,word甚至能保存文字图片原来在网页中的html样式。如果我粘贴到onenote中,还会显示原网页地址。

系统提供的剪贴板,类似于一个有很多格子的空储物柜,和一些标签。你在浏览器的网页中按下复制时,浏览器通常会:

  • 打开贴着标签"文本"的柜格,把选中的内容中的文本扔进去。[1]
  • 再找一个空柜格,把选中内容所关联的html代码扔进去,找个空标签,写上"html代码",贴在柜子上。
  • 再找一个空柜格,把选中部分的详细信息,如起始位置、结束位置、来源于哪个网站,这些信息扔进去,找个空标签写上"html详细信息",贴在柜子上。

然后,你在记事本里进行了粘贴,发生了这些事:

  • 记事本扫了一眼整个柜子,发现其中三个有标签有内容,其中包含写着"文本"的。
  • 记事本不管其他格式,径直打开文本的柜格取出内容并把它放到了编辑框里。

或者,你在word里按下了粘贴,发生了这些事:

  • word扫了一眼整个柜子,发现其中三个有标签有内容。
  • 发现了有写着"html代码"的标签,根据预设的规则,优先将其取出。
  • 将取出的内容按网页解析,分析出了布局,在自己的编辑框里布置好了。

而到了onenote,其实跟上面差不多,只是他发现有"html代码"的情况下,还会去看看有没有"html详细信息",如果有,从里面翻出网址并显示

总结来说,就是剪贴板里可以放多种数据,复制时,"来源程序"可以随自己喜好,放多种格式在里面,粘贴时,"目标程序"可以根据自己需求,提取其中一种或数种并处理,然后展示给用户。

另外,这个放柜子的屋子是有反锁的,通常来说屋子里只能有一个人存放或者取出东西,以防混乱。系统剪贴板基本上就是这样一个东西。

再说题目中的第一问

如题,比如我使用远程桌面,在远程主机复制一个文件,然后粘贴到我的电脑,这个过程中,我按下复制的时候,剪切板保存的是什么信息?

绝大部分情况下,都是远程软件的远程端,读取了远程电脑的剪贴板,并且以数据形式发给了本地端,本地端再把数据还原回来,存入剪贴板。也就是说这个过程其实跟系统剪贴板没关系,相当于你复制了东西,粘贴到了qq里发送,另一个人再从qq里复制出来,此时你的电脑和他的电脑剪贴板里的东西就是相同的了,但是实际上剪贴板没做什么特殊的。(当然qq只能发文本,而远程软件把所有类型都处理了)


相关技术细节

windows剪贴板的API流程很长,并且最终的部分是在内核中处理的,以读取剪贴板图片为例的主要流程。OleGetClipboard (IDataObject::GetData)-> GetClipboardData->用户层NtUserGetClipboardData->Wow64层->Shadow SSDT-> 内核层NtUserGetClipboardData-> xxxGetClipboardData-> xxxGetDummyBitmap->xxxDIBtoBMP,然后拿着一个句柄一路回来。

其中用户层前两层都是公开了接口的,即COM(OLE)层的OleGetClipboard系列函数[2][3],和更底层来自User32的GetClipboardData系列函数[4]

基于众所周知令人头大的COM层的前者,提供了比后者更多的功能,比如说给每项剪贴板子类型一些额外的标注,图片缩略图等[5],但也继承了COM层的繁杂。起初我不知道这些额外的信息是存在哪的,疑惑了很久,后来做了逆向发现它只是自己做了个子格式Ole Private Data在其中存储其他每一项的额外数据。

       // 上面提到的相关结构 typedef struct tagFORMATETC {   CLIPFORMAT     cfFormat;   DVTARGETDEVICE *ptd;   DWORD          dwAspect;   LONG           lindex;   DWORD          tymed; } FORMATETC, *LPFORMATETC;  typedef enum tagDVASPECT {   DVASPECT_CONTENT,   DVASPECT_THUMBNAIL,   DVASPECT_ICON,   DVASPECT_DOCPRINT } DVASPECT;  typedef enum tagTYMED {   TYMED_HGLOBAL,   TYMED_FILE,   TYMED_ISTREAM,   TYMED_ISTORAGE,   TYMED_GDI,   TYMED_MFPICT,   TYMED_ENHMF,   TYMED_NULL } TYMED;      

使用起来,读写大致就是构造一个IDataObject,在里面存储数据(期间要构造成吨的类似上面的烦人结构),然后调用OleSetClipboard写入剪贴板,或者调用OleGetClipboard从剪贴板取回一个此格式并从里面读数据。

--

而后者,来自User32的api系列,就是很普通的windows api的样子了,有点繁杂,但不像前者那样恶心,不过用起来也不是很好受,你甚至不知道GetData回来的到底是个什么东西,是个句柄?是个指针?指向什么的指针?只能自己预设一个表,根据不同的类型自己解析,并且还要调用不同的释放资源api。用法有其他答主列出了我就不多说了。

--

不得不吐槽,不知是是历史兼容问题还是设计眼界问题,剪贴板这套系统非常的不优雅,甚至可以说稀烂。比如说跟窗口强关联(是的,你的程序如果没有窗口,很多剪贴板相关的api都不能用)、使用着GlobalAlloc系列古老的函数、来源和目标程序各自使用上面两者的兼容等问题。

也没有一个封装好的库能完美的解决这些,比如说c#自带的库,使用了COM层的接口,但是暴露的数据却跟User32的接口差不多,看不到那些额外数据。而且稳定性很差,随随便便都会冒出一大堆晦涩难懂的COM层异常,比如说随便去Excel里框几格表并复制,然后执行下面的代码,就是读出剪贴板并写回(几次),然后再贴到一个记事本里,多半粘贴出来的内容不对,会抛出异常,甚至你的c#程序还会崩掉,try不到的那种。

               private void button1_Click(object sender, EventArgs e)         {             for (int i = 0; i < 3; i++)             {                 var foo = Clipboard.GetDataObject();                 Clipboard.SetDataObject(foo, true);             }         }                  //补充一个更容易出问题的,不直接写回去,而是把剪贴板里所有类型读出         //放到一个新的容器里,再写回去         private void button2_Click(object sender, EventArgs e)         {             var oldDataObject = Clipboard.GetDataObject();             var newDataObject = new DataObject();              foreach (var formatName in oldDataObject.GetFormats())             {                 var data = oldDataObject.GetData(formatName);                 newDataObject.SetData(formatName, data);             }              Clipboard.SetDataObject(newDataObject, true);         }      

参考

  1. ^ 类似文本这种常用的类型,有预贴标签的柜格
  2. ^OleGetClipboard https://docs.microsoft.com/en-us/windows/win32/api/ole2/nf-ole2-olegetclipboard
  3. ^IDataObject::GetData https://docs.microsoft.com/zh-cn/windows/win32/api/objidl/nf-objidl-idataobject-getdata
  4. ^User32 Clipboard Functions https://docs.microsoft.com/en-us/windows/win32/dataxchg/clipboard-functions
  5. ^一个作为例子的繁杂的COM结构 https://docs.microsoft.com/zh-cn/windows/win32/api/objidl/ns-objidl-formatetc



  

相关话题

  汉字在计算机中的表示方式有哪些? 
  如何评价微软官宣将会在 6.24 发布下一代 Windows 操作系统的信息? 
  为什么会有人谴责微软捆绑 IE,如果 Windows 没有内置 IE,那么你拿到电脑应该怎么上网下载别的浏览器? 
  在Windows下用VIM来写代码,会不会很蛋痛? 
  如何充分利用腾讯云的1元学生服务器? 
  如何看待华为开发自有操作系统? 
  为什么很多人要禁止 Windows 10 自动更新? 
  Windows源代码值得保密吗,难道不能集中一群民间电脑高手,大家合作,反编译出源代码? 
  在中国中小学计算机课堂中,推广 Linux 系统而不用 Windows ,可能吗? 
  不懂电脑的人,对电脑方面的理解有哪些误区? 

前一个讨论
如何评价2000年版央视太平天国电视剧?
下一个讨论
有没有很“狂”很霸气的诗句?





© 2025-06-22 - tinynew.org. All Rights Reserved.
© 2025-06-22 - tinynew.org. 保留所有权利