我想问的问题是:
(1)如果我通过剪贴板类与剪贴板交互,那么“嵌入源”和“MetaFilePict”流应该是什么?
(2)如果我通过COM接口IDataObject与剪贴板交互,我应该怎么处理“嵌入源”和“MetaFilePict”中的句柄?
(3)在C#中有更好的方法来实现OLE(客户端或服务器会帮助我)吗?
更多细节:
我正在寻求在C#中实现OLE服务器(外部Windows API和其他适用于x86的方法对我来说都可以,只要它们可以在一个C#项目中).我找不到任何不涉及MFC的OLE示例.所以我先尝试了一下.
我的第一步是查看其他OLE服务器执行哪些操作以将其数据放入剪贴板.我已经尝试了2种与剪贴板交互的方法:NET Clipboard类,它给我三个Streams,如后面所述,以及OleGetClipboard返回的IDataObject接口,它给了我指针.
我发现Origin放了三个数据条目:Object Descriptor,Embed Source和MetaFilePict.它们似乎是Stream.如果我从三个Streams读取所有字节,将它们放回新的DataObject并再次将DataObject放到剪贴板中,我可以将原始对象粘贴到例如Word中,这意味着三个Streams的内容足够用于粘贴OLE容器.
我进一步发现,Object Descriptor包含带有数据类guid和一些名称的OBJECTDESCRIPTOR结构,我能够实例化该对象并将其转换为IOLEObject.但我不知道其他两个流,Embed Source和MetaFilePict应该是什么.根据我的理解,Embed Source应该包含在创建它之后传递给IOLEObject的数据(可能是由InitFromData),但是我没有成功.并且重新编写MetaFilePict,似乎没有这个条目,其他两个无法正常工作(如果只存在Object Descriptor和Embed Source,则粘贴在Word中最终没有任何内容).但同样,我不知道它里面是什么.它似乎以ASCII字符串开头(在我的例子中是“CPYA 4.2878 724#”)并且看起来不像WMF文件.
如果我使用COM对象IDataObject(在System.Runtime.InteropServices.ComTypes或Microsoft.VisualStudio.OLE.Interop命名空间中),我可以从中获取HMETAFILEPICT,但我不知道如何使用该句柄. PlayMetaFile无法正常工作.
编辑
在MFC中,该示例使用OleCreateFromData直接从剪贴板获取的IDataObject创建对象.这应该也适用于C#.但这只是客户端的实现.我将尝试找出如何实现服务器.
解决方法:
我不知道为什么我的问题被投了票.实际上,我可以在互联网上找到许多线程,要求提出类似的问题,但没有一个最终得到完整的答案.这是一种耻辱.
最后,在查看MFC示例代码后,我自己找到了答案. OLE对于新人来说真的很难学,特别是没有MFC.根本没有人可以告诉你详细的做什么.
首先,两种方法都应该以相同的方式工作.对于“对象描述符”,HGlobal只是一个内存块,它只包含OBJECTDESCRIPTOR结构.对于“嵌入源”,IStorage通常使用ILockBytes创建,ILockBytes只有一个内存块.问题是它上面有什么样的数据.实际上块上是一种称为OLE复合文件的格式.它包含两部分信息:guid和用于初始化IOLEObject的数据. guid非常重要,因为它实际上是用于创建IOLEObject的那个. “对象描述符”中的GUID仅用于显示“特殊粘贴”对话框.可以使用WriteClassStg API函数将GUID添加到IStorage中. IStorage中包含的其他数据部分通常是一个名为“Contents”的单个流(至少这是我所拥有的MFC示例的实现).
总之,我要做的准备粘贴的工作是:
>有一个实现IOLEObject,IDataObject,IPersistStorage和IViewObject的OLEObject类(不太确定IViewObject).
>有一个实现IDataObject的DataObject类(与1中的对象相同,但只有IDataObject接口).
>在2个对象的IDataObject的实现中,至少具有“Object Descriptor”,“Embed Source”和“MetaFilePict”类型的数据. MetaFile可以通过Convert an image into WMF with .NET?中提供的方法创建.
>确保COM可以访问这些类并正确注册. https://limbioliong.wordpress.com/2011/08/30/creating-a-com-server-using-c/
>执行复制时,通过StgCreateDocfile构造IStorage,使用WriteClassStg设置OLEObject的GUID,并在其中写入OLEObject所需的其他数据.
>构造DataObject类并将其作为“嵌入源”提供给IStorage.
>使用OleSetClipboard将DataObject设置为剪贴板.
似乎MFC注册了一个允许创建OLEObject的IClassFactory.我不知道如何在C#中实现这一点.
我完成后会在这里添加一些代码,以便其他寻找OLE细节的人可以轻松找到它.
一个(勉强)工作的例子:https://github.com/acaly/SharpOle