简体   繁体   English

如何在C#中实现OLE服务器

[英]How to implement OLE server in C#

The question I want to ask is: 我想问的问题是:

(1) If I interact with clipboard by Clipboard class, what should be in "Embed Source" and "MetaFilePict" streams? (1)如果我通过剪贴板类与剪贴板交互,那么“嵌入源”和“MetaFilePict”流应该是什么?

(2) If I interact with clipboard by COM interface IDataObject, what should I do with the handle in "Embed Source" and "MetaFilePict"? (2)如果我通过COM接口IDataObject与剪贴板交互,我应该怎么处理“嵌入源”和“MetaFilePict”中的句柄?

(3) Is there better methods to implement OLE (either client or server will help me) in C#? (3)在C#中有更好的方法来实现OLE(客户端或服务器会帮助我)吗?

More details: 更多细节:

I am seeking for an implementation of OLE Server in C# (extern Windows APIs and other methods that work on x86 are all OK for me, as long as they can be in one C# project). 我正在寻求在C#中实现OLE服务器(外部Windows API和其他适用于x86的方法对我来说都可以,只要它们可以在一个C#项目中)。 I can not find any examples of OLE that does not involve MFC. 我找不到任何不涉及MFC的OLE示例。 So I first tried a little bit. 所以我先尝试了一下。

My first step is to see what other OLE servers do in order to put their data into the clipboard. 我的第一步是查看其他OLE服务器执行哪些操作以将其数据放入剪贴板。 I have tried 2 methods to interact with clipboard: NET Clipboard class which gives me three Streams as described later, and IDataObject interface returned by OleGetClipboard which gives me pointers. 我已经尝试了2种与剪贴板交互的方法:NET Clipboard类,它给我三个Streams,如后面所述,以及OleGetClipboard返回的IDataObject接口,它给了我指针。

I found that Origin puts three data entries: Object Descriptor, Embed Source and MetaFilePict. 我发现Origin放了三个数据条目:Object Descriptor,Embed Source和MetaFilePict。 They appear to be Stream. 它们似乎是Stream。 If I read all bytes from the three Streams, put them back to a new DataObject and put the DataObject to clipboard again, I am able to paste the original object in, for example, Word, which means the contents of the three Streams are enough for an OLE container to paste. 如果我从三个Streams读取所有字节,将它们放回新的DataObject并再次将DataObject放到剪贴板中,我可以将原始对象粘贴到例如Word中,这意味着三个Streams的内容足够用于粘贴OLE容器。

What I find further is that Object Descriptor contains the OBJECTDESCRIPTOR structure with guid of the data class and some names, and I am able to instantiate the object and convert it to an IOLEObject. 我进一步发现,Object Descriptor包含带有数据类guid和一些名称的OBJECTDESCRIPTOR结构,我能够实例化该对象并将其转换为IOLEObject。 But I don't know what should be in the other two stream, Embed Source and MetaFilePict. 但我不知道其他两个流,Embed Source和MetaFilePict应该是什么。 From my understanding, Embed Source should contain data that is passed to IOLEObject (probably by InitFromData) after creating it, but I did not succeed in doing so. 根据我的理解,Embed Source应该包含在创建它之后传递给IOLEObject的数据(可能是由InitFromData),但是我没有成功。 And reagrding MetaFilePict, it seems that without this entry, the other two can not work properly (paste in Word end up with nothing if only Object Descriptor and Embed Source exist). 并且重新编写MetaFilePict,似乎没有这个条目,其他两个无法正常工作(如果只存在Object Descriptor和Embed Source,则粘贴在Word中最终没有任何内容)。 But again, I don't know what is in it. 但同样,我不知道它里面是什么。 It seems that it begins with an ASCII string (in my case it is "CPYA 4.2878 724#") and does not look like a WMF file. 它似乎以ASCII字符串开头(在我的例子中是“CPYA 4.2878 724#”)并且看起来不像WMF文件。

If I use COM object IDataObject (in either System.Runtime.InteropServices.ComTypes or Microsoft.VisualStudio.OLE.Interop namespace), I can get HMETAFILEPICT from it, but I don't know how to use the handle. 如果我使用COM对象IDataObject(在System.Runtime.InteropServices.ComTypes或Microsoft.VisualStudio.OLE.Interop命名空间中),我可以从中获取HMETAFILEPICT,但我不知道如何使用该句柄。 PlayMetaFile does not work on it. PlayMetaFile无法正常工作。

EDIT 编辑

In MFC, the example uses OleCreateFromData to create the object directly from the IDataObject got from clipboard. 在MFC中,该示例使用OleCreateFromData直接从剪贴板获取的IDataObject创建对象。 This should also work in C#. 这应该也适用于C#。 But this is only the implementation of client. 但这只是客户端的实现。 I will try to find out how to implement a server. 我将尝试找出如何实现服务器。

I don't know why my question is down voted. 我不知道为什么我的问题被投了票。 Actually I can find many threads on the Internet that asks for similar question but none of them ends up with a complete answer. 实际上,我可以在互联网上找到许多线程,要求提出类似的问题,但没有一个最终得到完整的答案。 This is a shame. 这是一种耻辱。

Finally I find the answer myself, after looking through MFC example code. 最后,在查看MFC示例代码后,我自己找到了答案。 OLE is really hard for a new person to learn, especially without MFC. OLE对于新人来说真的很难学,特别是没有MFC。 There is simply no one who can tell you what to do in detail. 根本没有人可以告诉你详细的做什么。

First, both method should work in the same way. 首先,两种方法都应该以相同的方式工作。 For "Object Descriptor", HGlobal is just a memory block, which just contains OBJECTDESCRIPTOR structure. 对于“对象描述符”,HGlobal只是一个内存块,它只包含OBJECTDESCRIPTOR结构。 For "Embed Source", the IStorage is usually created with ILockBytes, which just has a memory block. 对于“嵌入源”,IStorage通常使用ILockBytes创建,ILockBytes只有一个内存块。 The question is what kind of data is on it. 问题是它上面有什么样的数据。 Actually on the block is a format called OLE Compound File. 实际上块上是一种称为OLE复合文件的格式。 It contains two parts of information: a guid and data used to initialize IOLEObject. 它包含两部分信息:guid和用于初始化IOLEObject的数据。 The guid is very important because it is actually the one that is used to create IOLEObject. guid非常重要,因为它实际上是用于创建IOLEObject的那个。 The GUID in "Object Descriptor" is just used to show Special Paste dialog. “对象描述符”中的GUID仅用于显示“特殊粘贴”对话框。 The GUID can be added into IStorage with WriteClassStg API function. 可以使用WriteClassStg API函数将GUID添加到IStorage中。 Other parts of data contained in the IStorage is usually a single stream called "Contents" (at least this is the implementation of MFC example I have). IStorage中包含的其他数据部分通常是一个名为“Contents”的单个流(至少这是我所拥有的MFC示例的实现)。

In conclusion, what I have to do to prepare for a paste is: 总之,我要做的准备粘贴的工作是:

  1. Have a OLEObject class that implements IOLEObject, IDataObject, IPersistStorage and IViewObject (not quite sure about IViewObject). 有一个实现IOLEObject,IDataObject,IPersistStorage和IViewObject的OLEObject类(不太确定IViewObject)。
  2. Have a DataObject class that implements IDataObject (do same thing as the object in 1, but only the IDataObject interface). 有一个实现IDataObject的DataObject类(与1中的对象做同样的事情,但只有IDataObject接口)。
  3. In the implementation for IDataObject of the 2 objects, at least have data for type "Object Descriptor", "Embed Source" and "MetaFilePict". 在2个对象的IDataObject的实现中,至少具有类型“Object Descriptor”,“Embed Source”和“MetaFilePict”的数据。 MetaFile can be created by the method provided in Convert an image into WMF with .NET? 可以通过使用.NET将图像转换为WMF中提供的方法来创建MetaFile 吗? .
  4. Ensure the classes can be accessed by COM and is properly registered. 确保COM可以访问这些类并正确注册。 https://limbioliong.wordpress.com/2011/08/30/creating-a-com-server-using-c/ https://limbioliong.wordpress.com/2011/08/30/creating-a-com-server-using-c/
  5. When performing the copy, construct an IStorage by StgCreateDocfile, set GUID of the OLEObject with WriteClassStg, and write other data required by OLEObject in it. 执行复制时,通过StgCreateDocfile构造IStorage,使用WriteClassStg设置OLEObject的GUID,并在其中写入OLEObject所需的其他数据。
  6. Construct the DataObject class and provide it with the IStorage as "Embed Source". 构造DataObject类并将其作为“嵌入源”提供给IStorage。
  7. Set the DataObject to clipboard with OleSetClipboard. 使用OleSetClipboard将DataObject设置为剪贴板。

It seems that MFC registers a IClassFactory that allows the OLEObject to be created. 似乎MFC注册了一个允许创建OLEObject的IClassFactory。 I am not sure how to achieve this in C#. 我不知道如何在C#中实现这一点。

I will add some code here after I finish so that someone else who looks for the details of OLE can easily find it. 我完成后会在这里添加一些代码,以便其他寻找OLE细节的人可以轻松找到它。

A (barely) working example: https://github.com/acaly/SharpOle 一个(几乎没有)工作的例子: https//github.com/acaly/SharpOle

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM