如何在VB6和C#之间共享接口?

如何在VB6和C#之间共享接口?,c#,com,vb6,com-interop,vb6-migration,C#,Com,Vb6,Com Interop,Vb6 Migration,我希望能够编写一个可以在C#和VB6类中实现的类接口,以便在VB6代码中以相同的方式处理这些类,但我无法做到这一点 在VB6中,我想用Implements关键字来实现一些接口 在C#中,我希望有一些其他的C#类,我可以将其公开给COM,同时实现ISharedInterface 目标是VB6代码能够通过ISharedInterface在VB6Class和C#Class上运行,而无需关心这些类是用哪种语言构建的 我想使用这种技术,通过在VB6端连续重写所有内容来从VB6迁移,如果我能在C#中实现VB

我希望能够编写一个可以在C#和VB6类中实现的类接口,以便在VB6代码中以相同的方式处理这些类,但我无法做到这一点

在VB6中,我想用Implements关键字来实现一些接口

在C#中,我希望有一些其他的C#类,我可以将其公开给COM,同时实现ISharedInterface

目标是VB6代码能够通过ISharedInterface在VB6Class和C#Class上运行,而无需关心这些类是用哪种语言构建的

我想使用这种技术,通过在VB6端连续重写所有内容来从VB6迁移,如果我能在C#中实现VB6中已有的接口,这将是理想的。但如果做不到这一点,即使我必须用C#重写一个接口以共享回VB6,它仍然是有用的(即,我甚至不在乎该接口是用C#编写并暴露于COM还是用COM编写并被C#使用,只要语言障碍的双方都可以引用同一个接口)

我发现这很难。我可以在C#中引用来自COM的接口,但不能将其作为COM可见接口导出回COM。如果,作为替代,我尝试在C#本身中创建一个接口,我还没有找到通过COM直接查看它的方法以及我尝试间接使用它的各种解决方法,比如创建一个存根类来实现接口,并将其公开为COM可见。当我尝试实现公开的存根类时,只会在VB6中引发运行时错误(即使他们编译)

我目前没有很好的解决方案,只有一个非常笨拙的工作,就是在C#和VB6中实现单独的接口,将C#方法直接公开给COM,并在VB6中创建一个包装类,将接口方法重定向到底层的true方法

创建两种语言都可以引用的单个接口(VB6或C#)的最佳方法是什么,而无需复制接口定义

创建两种语言都可以引用的单个接口(VB6或C#)的最佳方法是什么,而无需复制接口定义

在IDL中编写接口并编译成一个类型库,该类型库在VB中引用并导入(
tlbimp
)到.NET中。(如果使用VB6定义接口,则需要避免重新生成IID。)


您可以在.NET中定义接口,但这将涉及更多步骤。

我不确定是否误解了这个问题,但您为什么要在VB6中实现接口?如果您有一个在VB6和C中实现的接口,那么您可能会复制基本上做相同事情的代码。如果您正在使用从VB6迁移时,您可能希望限制编写的VB6代码量

我目前正在使用一个大型VB6应用程序,所有新的开发都是在C#中完成的。我有十几个C#程序集,其中只有一个是COM公开的。它只是一个小程序集,通过COM公开我需要的方法,这样我就可以直接在我的VB6项目中使用。你可以在VB6中创建一个包装器类,就像你说的那样第一,集中对C#程序集的调用。这是我在项目中所做的,这样包装器可以在程序集首次使用时初始化对它的引用,而不是每次使用时都初始化

听起来像你的“笨重”您当前使用的解决方法与我所做的更接近。可能主要的区别在于我没有向COM公开任何实际的C#方法。这都是在我的COM接口程序集中完成的。当需要抛弃VB6代码时,COM接口程序集就被扔掉了,其余的C#代码/程序集没有任何关联到COM。我们已经有一些其他产品共享相同的C#程序集,它们只是直接引用它们,因此一旦COM接口被抛出,它们就不会受到影响。

创建一个C#类库(在本例中称为DemoComInterface),并确保“未选中确保程序集COM可见”(作为提醒,以下代码段中的GUID应替换为您自己的唯一GUID。)

向类库添加一个接口,如下所示:

using System.Runtime.InteropServices;

namespace DemoComInterface
{
    [InterfaceType(ComInterfaceType.InterfaceIsDual)]
    [ComVisible(true)]
    [Guid("01B0A84D-CACE-4EF1-9C4B-6995A71F9AB8")]
    public interface ISharedInterface
    {
        [DispId(0x60030040)]
        void Question();
    }
}
// Generated .IDL file (by the OLE/COM Object Viewer)
// 
// typelib filename: DemoComInterface.tlb

[
uuid(4294F846-DD61-418D-95CC-63400734C876),
version(1.0),
helpstring("Demo C# exported interfaces"),
custom(90883F05-3D28-11D2-8F17-00A0C9A6186D, "DemoComInterface, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null")

]
library DemoComInterface
{
    // TLib :     // TLib : mscorlib.dll : {BED7F4EA-1A96-11D2-8F08-00A0C9A6186D}
    importlib("mscorlib.tlb");
    // TLib : OLE Automation : {00020430-0000-0000-C000-000000000046}
    importlib("stdole2.tlb");

    // Forward declare all types defined in this typelib
    interface ISharedInterface;

    [
    uuid(CC9A9CBC-054A-4C9C-B559-CE39A5EA2742),
    version(1.0),
    custom(0F21F359-AB84-41E8-9A78-36D110E6D2F9, "DemoComInterface.Class1")
    ]
    coclass Class1 {
        interface _Object;
        [default] interface ISharedInterface;
    };

    [
    odl,
    uuid(01B0A84D-CACE-4EF1-9C4B-6995A71F9AB8),
    version(1.0),
    dual,
    oleautomation,
    custom(0F21F359-AB84-41E8-9A78-36D110E6D2F9, "DemoComInterface.ISharedInterface")    

    ]
    interface ISharedInterface : IDispatch {
        [id(0x60030040)]
        HRESULT Question();
    };
};
要演示使用共享接口的C#类,请更新Class1以实现共享接口,并使用以下属性对其进行修饰:

using System.Runtime.InteropServices;

namespace DemoComInterface
{
    [Guid("CC9A9CBC-054A-4C9C-B559-CE39A5EA2742")]
    [ProgId("DemoComInterface.Class1")]
    [ClassInterface(ClassInterfaceType.None)]
    [ComVisible(true)]
    public class Class1 : ISharedInterface
    {
        public void Question()
        {
            throw new NotImplementedException();
        }
    }
}
现在,将AssemblyInfo.cs文件的AssemblyDescription属性修改为有意义的属性,以便可以在VB6“引用”浏览器中找到类型库。这可以通过直接编辑文件或填充程序集信息对话框的“说明”字段来完成

using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;

// General Information about an assembly is controlled through the following
// set of attributes. Change these attribute values to modify the information
// associated with an assembly.
[assembly: AssemblyTitle("DemoComInterface")]
// This is what will be seen in VB6's 'References' browser.**
[assembly: AssemblyDescription("Demo C# exported interfaces")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("")]
[assembly: AssemblyProduct("DemoComInterface")]
[assembly: AssemblyCopyright("Copyright ©  2020")]
[assembly: AssemblyTrademark("")]
[assembly: AssemblyCulture("")]

// Setting ComVisible to false makes the types in this assembly not visible
// to COM components.  If you need to access a type in this assembly from
// COM, set the ComVisible attribute to true on that type.
[assembly: ComVisible(false)]

// The following GUID is for the ID of the typelib if this project is exposed to COM
[assembly: Guid("4294f846-dd61-418d-95cc-63400734c876")]

// Version information for an assembly consists of the following four values:
//
//      Major Version
//      Minor Version
//      Build Number
//      Revision
//
// You can specify all the values or you can default the Build and Revision Numbers
// by using the '*' as shown below:
// [assembly: AssemblyVersion("1.0.*")]
[assembly: AssemblyVersion("1.0.0.0")]
[assembly: AssemblyFileVersion("1.0.0.0")]
通过检查项目的“Register for COM interop”生成属性,或使用REGASM在命令提示符中手动注册此类库,来注册此类库

查看生成的类型库(在项目的bin输出文件夹中),您应该会看到如下内容:

using System.Runtime.InteropServices;

namespace DemoComInterface
{
    [InterfaceType(ComInterfaceType.InterfaceIsDual)]
    [ComVisible(true)]
    [Guid("01B0A84D-CACE-4EF1-9C4B-6995A71F9AB8")]
    public interface ISharedInterface
    {
        [DispId(0x60030040)]
        void Question();
    }
}
// Generated .IDL file (by the OLE/COM Object Viewer)
// 
// typelib filename: DemoComInterface.tlb

[
uuid(4294F846-DD61-418D-95CC-63400734C876),
version(1.0),
helpstring("Demo C# exported interfaces"),
custom(90883F05-3D28-11D2-8F17-00A0C9A6186D, "DemoComInterface, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null")

]
library DemoComInterface
{
    // TLib :     // TLib : mscorlib.dll : {BED7F4EA-1A96-11D2-8F08-00A0C9A6186D}
    importlib("mscorlib.tlb");
    // TLib : OLE Automation : {00020430-0000-0000-C000-000000000046}
    importlib("stdole2.tlb");

    // Forward declare all types defined in this typelib
    interface ISharedInterface;

    [
    uuid(CC9A9CBC-054A-4C9C-B559-CE39A5EA2742),
    version(1.0),
    custom(0F21F359-AB84-41E8-9A78-36D110E6D2F9, "DemoComInterface.Class1")
    ]
    coclass Class1 {
        interface _Object;
        [default] interface ISharedInterface;
    };

    [
    odl,
    uuid(01B0A84D-CACE-4EF1-9C4B-6995A71F9AB8),
    version(1.0),
    dual,
    oleautomation,
    custom(0F21F359-AB84-41E8-9A78-36D110E6D2F9, "DemoComInterface.ISharedInterface")    

    ]
    interface ISharedInterface : IDispatch {
        [id(0x60030040)]
        HRESULT Question();
    };
};
共享接口现在在COM可见C#类中实现

要在VB6项目中实现共享接口,请添加对“Demo C#exported interfaces”的引用,并按照以下方式实现它:

Option Explicit

Implements ISharedInterface
    
' Implementation of Question.
Public Sub ISharedInterface_Question()
    MsgBox ("Who is number one?")
End Sub

的确如此。我们的目标是向C#转移,我们已经有了一个C#“层”来处理所有的接口逻辑(我这里指的是用户界面)。下一步是迁移业务逻辑。显然,一个选择是“大爆炸”,一次转换所有内容,可能使用转换工具,但有很多VB6代码,我正在考虑逐步解决问题的方法。如果我可以与共享类接口进行互操作,则有大量代码可以独立迁移。感谢指针。这是一种不