如何在 VB6 和 C# 之间共享接口?
How can I share an interface between VB6 and C#?
我希望能够编写一个 class 接口,我可以在 C# 和 VB6 classes 中实现,以便可以用相同的方式处理这些 classes在 VB6 代码中,但我无法完成这项工作。
在VB6中我想来classVB6Class使用Implements关键字来实现一些接口ISharedInterface。
在 C# 中,我想要一些其他的 class C#Class,我可以在实现 ISharedInterface 的同时公开给 COM。
目标是 VB6 代码随后能够通过 ISharedInterface 在 VB6Class 和 C#Class 上运行,而无需关心 classes 内置于哪种语言。
我想通过连续重写 VB6 端的所有内容,将此技术用作从 VB6 迁移的一种方式,如果我可以在 C# 中实现 VB6 中已有的接口,那将是理想的选择。但是失败了,即使我必须在 C# 中重写一个接口以共享回仍然有用的 VB6(即,我什至不关心该接口是用 C# 编写并暴露给 COM 还是用 COM 编写并由C#,只要语言不通的双方都能引用同一个接口即可)。
我发现这出奇地难。我可以在 C# 中引用来自 COM 的接口,但我无法将其作为 COM 可见接口导出回 COM。如果,作为替代方案,我尝试在 C# 本身中创建一个接口,我还没有找到一种方法来直接通过 COM 和各种解决方法来查看它,我尝试间接使用它,比如创建一个存根 class 来实现当我尝试实现暴露的存根 class(即使它们编译)时,接口并将其暴露为 COM 可见只是在 VB6 中引发 运行 时间错误。
我目前对此没有好的解决方案,只有一个非常笨拙的解决方案,即在 C# 和 VB6 中实现单独的接口,将 C# 方法直接暴露给 COM,并在 VB6 中创建一个包装器 class简单地将接口方法重定向到底层的真实方法。
创建一个接口(在 VB6 或 C# 中)的最佳方法是什么,两种语言都可以引用而无需复制接口定义?
What is the best way to create a single interface (either in VB6 or C#) which both languages can reference without me having to duplicate the interface definition?
用 IDL 编写接口并编译成类型库,在 VB 中引用并导入 (tlbimp
) 到 .NET 中。 (如果你使用它来定义接口,你需要避免 IID 的重新生成,VB6 会这样做。)
您可以在 .NET 中定义接口,但这将涉及更多步骤。
我不确定我是否误解了这个问题,但您为什么要在 VB6 中实现该接口?如果您有一个在 VB6 和 C# 中实现的接口,那么您可能会复制本质上做同样事情的代码。如果您正致力于从 VB6 迁移,您可能希望限制您编写的 VB6 代码的数量。
我目前正在使用一个大型 VB6 应用程序,所有新的开发都是在 C# 中完成的。我有大约一打 C# 程序集,其中只有一个是 COM 公开的。它只是一个小程序集,通过 COM 公开了我需要的方法,因此我可以直接在我的 VB6 项目中使用。您可以在 VB6 中创建一个包装器 class,就像您所说的那样,以集中对 C# 程序集的调用。这就是我在我们的项目中所做的,因此包装器可以在首次使用时处理初始化对程序集的引用,而不是每次使用时都这样做。
听起来您目前使用的 "clunky" 解决方法更符合我所做的工作。也许主要区别在于我没有向 COM 公开任何实际的 C# 方法。这一切都在我的 COM 接口程序集中完成。到了放弃 VB6 代码的时候,COM 接口程序集就被扔掉了,其余的 C# code/assemblies 与 COM 没有任何关系。我们已经有一些其他产品共享相同的 C# 程序集,它们只是直接引用它们,因此一旦 COM 接口被丢弃,它们将不会受到影响。
创建一个 C# class 库(在本例中称为 DemoComInterface)并确保 'Make assembly COM-visible is unchecked.'(作为提醒,以下代码片段中的 GUID 应替换为唯一的 GUID你自己的。)
向class库添加一个接口,像这样:
using System.Runtime.InteropServices;
namespace DemoComInterface
{
[InterfaceType(ComInterfaceType.InterfaceIsDual)]
[ComVisible(true)]
[Guid("01B0A84D-CACE-4EF1-9C4B-6995A71F9AB8")]
public interface ISharedInterface
{
[DispId(0x60030040)]
void Question();
}
}
为了演示使用共享接口的 C# class,更新 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 'References' 浏览器中找到类型库。这可以通过直接编辑文件或填充程序集信息对话框的 'Description' 字段来完成。
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")]
注册此 class 库,通过检查项目的 'Register for COM interop' 构建 属性,或使用 REGASM 在命令提示符下手动注册它。
查看生成的类型库(在项目的bin输出文件夹中),你应该看到这样的东西:
// 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-visible C# class.
中实现
要在VB6项目中实现共享接口,添加对'Demo C# exported interfaces'的引用,实现如下:
Option Explicit
Implements ISharedInterface
' Implementation of Question.
Public Sub ISharedInterface_Question()
MsgBox ("Who is number one?")
End Sub
我希望能够编写一个 class 接口,我可以在 C# 和 VB6 classes 中实现,以便可以用相同的方式处理这些 classes在 VB6 代码中,但我无法完成这项工作。
在VB6中我想来classVB6Class使用Implements关键字来实现一些接口ISharedInterface。
在 C# 中,我想要一些其他的 class C#Class,我可以在实现 ISharedInterface 的同时公开给 COM。
目标是 VB6 代码随后能够通过 ISharedInterface 在 VB6Class 和 C#Class 上运行,而无需关心 classes 内置于哪种语言。
我想通过连续重写 VB6 端的所有内容,将此技术用作从 VB6 迁移的一种方式,如果我可以在 C# 中实现 VB6 中已有的接口,那将是理想的选择。但是失败了,即使我必须在 C# 中重写一个接口以共享回仍然有用的 VB6(即,我什至不关心该接口是用 C# 编写并暴露给 COM 还是用 COM 编写并由C#,只要语言不通的双方都能引用同一个接口即可)。
我发现这出奇地难。我可以在 C# 中引用来自 COM 的接口,但我无法将其作为 COM 可见接口导出回 COM。如果,作为替代方案,我尝试在 C# 本身中创建一个接口,我还没有找到一种方法来直接通过 COM 和各种解决方法来查看它,我尝试间接使用它,比如创建一个存根 class 来实现当我尝试实现暴露的存根 class(即使它们编译)时,接口并将其暴露为 COM 可见只是在 VB6 中引发 运行 时间错误。
我目前对此没有好的解决方案,只有一个非常笨拙的解决方案,即在 C# 和 VB6 中实现单独的接口,将 C# 方法直接暴露给 COM,并在 VB6 中创建一个包装器 class简单地将接口方法重定向到底层的真实方法。
创建一个接口(在 VB6 或 C# 中)的最佳方法是什么,两种语言都可以引用而无需复制接口定义?
What is the best way to create a single interface (either in VB6 or C#) which both languages can reference without me having to duplicate the interface definition?
用 IDL 编写接口并编译成类型库,在 VB 中引用并导入 (tlbimp
) 到 .NET 中。 (如果你使用它来定义接口,你需要避免 IID 的重新生成,VB6 会这样做。)
您可以在 .NET 中定义接口,但这将涉及更多步骤。
我不确定我是否误解了这个问题,但您为什么要在 VB6 中实现该接口?如果您有一个在 VB6 和 C# 中实现的接口,那么您可能会复制本质上做同样事情的代码。如果您正致力于从 VB6 迁移,您可能希望限制您编写的 VB6 代码的数量。
我目前正在使用一个大型 VB6 应用程序,所有新的开发都是在 C# 中完成的。我有大约一打 C# 程序集,其中只有一个是 COM 公开的。它只是一个小程序集,通过 COM 公开了我需要的方法,因此我可以直接在我的 VB6 项目中使用。您可以在 VB6 中创建一个包装器 class,就像您所说的那样,以集中对 C# 程序集的调用。这就是我在我们的项目中所做的,因此包装器可以在首次使用时处理初始化对程序集的引用,而不是每次使用时都这样做。
听起来您目前使用的 "clunky" 解决方法更符合我所做的工作。也许主要区别在于我没有向 COM 公开任何实际的 C# 方法。这一切都在我的 COM 接口程序集中完成。到了放弃 VB6 代码的时候,COM 接口程序集就被扔掉了,其余的 C# code/assemblies 与 COM 没有任何关系。我们已经有一些其他产品共享相同的 C# 程序集,它们只是直接引用它们,因此一旦 COM 接口被丢弃,它们将不会受到影响。
创建一个 C# class 库(在本例中称为 DemoComInterface)并确保 'Make assembly COM-visible is unchecked.'(作为提醒,以下代码片段中的 GUID 应替换为唯一的 GUID你自己的。)
向class库添加一个接口,像这样:
using System.Runtime.InteropServices;
namespace DemoComInterface
{
[InterfaceType(ComInterfaceType.InterfaceIsDual)]
[ComVisible(true)]
[Guid("01B0A84D-CACE-4EF1-9C4B-6995A71F9AB8")]
public interface ISharedInterface
{
[DispId(0x60030040)]
void Question();
}
}
为了演示使用共享接口的 C# class,更新 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 'References' 浏览器中找到类型库。这可以通过直接编辑文件或填充程序集信息对话框的 'Description' 字段来完成。
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")]
注册此 class 库,通过检查项目的 'Register for COM interop' 构建 属性,或使用 REGASM 在命令提示符下手动注册它。
查看生成的类型库(在项目的bin输出文件夹中),你应该看到这样的东西:
// 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-visible C# class.
中实现要在VB6项目中实现共享接口,添加对'Demo C# exported interfaces'的引用,实现如下:
Option Explicit
Implements ISharedInterface
' Implementation of Question.
Public Sub ISharedInterface_Question()
MsgBox ("Who is number one?")
End Sub