1. 用Tlbimp.exe,通过一个定义了该interface的typelib生成interface的managed definition. 然后你的类从它的interface继承就行了。2. 自己手工写这个interface的managed definition,加上GuidAttribute,表示正确的COM Interface的GUID,然后你的类从这个自己定义的interface继承,如果定义正确的话,一样可以用来进行COM Interop。3. 无论哪种方法,如果要在COM中调用该组件的话,类定义的时候一定要保证COMVisibleAttribute = true (Default)。4. IUnkown/IDispatch等少数几个接口不能这样实现。

解决方案 »

  1.   

    问题是这样的,我原来写过一个DLL,通过“原始”的COM Interface(不是Disp Interface)提供调用接口,在C#中我不知道该怎么做,直接用C#的interface又不行。
    大致的源程序如下:
    C++的DLL:class ISomething : public IUnknown
    {
        STDMETHOD FuncX();
        STDMETHOD FuncXX();
    };extern "C"
    {
        __declspec(dllexport)int __stdcall GetSomething(ISomething * pSomething);
    }原来用VC时我的客户端可以这么写:
    class CSomething : public ISomething
    {
        // ...
    };main()
    {
        CSomething s;
        GetSomethingProc(&s);
    }现在在C#中我就faint了我不想用Disp interface,一是因为速度慢,二是因为十有八九要和注册表打交道,我打算让我的程序跨平台,所以不能依赖它(尽管这个在C#中我知道怎么用,写一个TypeLib然后用那个tlbimp就行)
    确切的说我连GUID都不想用(在上面那个特殊情况中,我根本不需要去QueryInterface,直接返回this就可以了,在Delphi中也一样)之所以会有这么多麻烦,是因为我原来的DLL写得并不完全遵循COM规范,比如传递的参数和返回值就不是COM兼容类型(有好几个自定义的结构体),在C#中想要用它说不定还需要自己写一个boxing/unboxing的处理程序。如果实在没办法,我只好重写我的VC DLL了,这可是个浩大的工程…………
      

  2.   

    这下我糊涂了,你的Interface究竟定义在哪里?C的DLL里?还是...
    在你的代码例子中,实际上是CSomething实现了ISomething接口,怎么能说他是Client呢?究竟需要C#扮演怎样的角色,实现什么功能?原来的DLL有实现了什么功能?
    tlbimp生成的代理不一定会通过IDispatch的,一般仍然是普通的COM接口方式。
    而且COM本身就不垮平台,而且标准COM一定会用到注册表...
      

  3.   

    “标准”COM不一定会用到注册表的,虽然每一个COM Interface都会绑定一个GUID,但是这个GUID不一定需要写入注册表,仅仅是在QI的时候用来判定对方需要的是哪个接口的指针,倒是OLE的Dispatch Interface一定会用到注册表(因为ActiveX客户需要通过注册表中写入的InProcServer或者LocalServer来装载相应的DLL或者EXE并创建一个CoClass的实例)。我上面的问题说得不太清楚,这里再解释一下,我需要用C#实现一个接口,然后将这个接口指针传递到一个DLL中,有点类似于ActiveX里面的IConnectionPointContainer。我不想用DispInterface,因为这个效率比较低,那个Invoke确实很慢(当然,如果实在没办法,也只好将就了),我知道写一个IDL文件可以用来描述接口,但是我的接口中可能有IDL不支持的数据类型,比如一个原始指针,我可不想把他们都变成unsigned long。现在我想问的问题其实可以归结为:
    假设我有一个COM Interface的定义如上述的ISomething,我如何才能在C#里面实现它并且让它对于其他COM程序可见。
      

  4.   

    那个InProcServer的确不是用来QI的,而是在CoCreateInstance里面用到。如果要通过正规途径创建COM组建的话,注册表示不可少的,这个应该何是不是duel interface没什么关系,IDispatch的overhead也并不很大,相对于需要完成一定工作的函数实体,还是可以承受的。:)先看看简单数据类型的处理:
    1. 假设你在IDL里面有定义:
    interface IHello;
    [
          odl,
          uuid(4371C4F5-CD87-4CAB-8F99-C3336BF6FD46),
    ]
    interface IHello : IUnknown {
         HRESULT _stdcall SayHello();
    };2. 必须先将接口转换成C#的形式(或者用tlbimp.exe也可以):
    [ComVisible(true)]
    [Guid("4371C4F5-CD87-4CAB-8F99-C3336BF6FD46")]
    //没有IDispatch,duel interface
    [InterfaceType(ComInterfaceType.InterfaceIsIUnknown)] 
    public interface IHello {
         void SayHello();
    }3. 实现该接口:
    [ComVisible(true)] //找你的传指针的做法,这里是false也没关系
    //避免CLR为你生成default class duel interface, 使用IHello
    [ClassInterface(ClassInterfaceType.None)]
    public class MyHello {
         public void SayHello() {
               Console.WriteLine("hello, Universe!");
         }
    }4. 在unmanaged code中使用:
    a. 如果unmanaged code接受一个IUnknown:
       _declspec(dllexport) void DllSayHello(IUnknown* punk) {
             IHello* phello;
             punk ->QueryInterface(IID_IHello, (void**)&phello);
             phello ->SayHello();
             ...
       }
       C#调用:
       [DllImport("mydll.dll")]
       public static extern void DllSayHello(
       [MarshalAs(UnmanagedType.Interface)] object o);
       ...
       MyHello hello = new MyHello();
       DllSayHello(hello);b. Dll接受一个IHello*:
      _declspec(dllexport) void DllSayHello(IHello* phello) {
             phello ->SayHello();
             ...
       }
       C#调用:
       [DllImport("mydll.dll")]
       public static extern void DllSayHello(IntPtr pinterface);
       ...
       MyHello hello = new MyHello();
       IntPtr punk = Marshal.GetIUnknownForObject(hello);
       IntPtr phello;
       Marshal.QueryInterface(punk, ref guid, out phello);
       DllSayHello(phello); 
       ...对于复杂的数据类型,只要按照Marshal规则将它转换成对应的C#类型就可以了。
      

  5.   

    写错了一点:
    3. 实现该接口:
    [ComVisible(true)] //找你的传指针的做法,这里是false也没关系
    //避免CLR为你生成default class duel interface, 使用IHello
    [ClassInterface(ClassInterfaceType.None)]
    public class MyHello : IHello {  <-----漏了!!!!!!!。
         public void SayHello() {
               Console.WriteLine("hello, Universe!");
         }
    }
      

  6.   

    唉,就是这些该死的Attributes把我搞糊涂了,多谢指点