【问题标题】:Calling a VB6 DLL function with a complex User Defined Type (UDT) from C#从 C# 调用具有复杂用户定义类型 (UDT) 的 VB6 DLL 函数
【发布时间】:2016-09-12 15:57:45
【问题描述】:

我正在编写一个 C# 应用程序来调用第三方 VB6 DLL。我在 References->COM 选项卡中添加了对 VB6 DLL 的引用。

DLL 中的特定方法将 VB6 UDT(用户定义类型)作为参数。

此 UDT 在自动生成的 COM .NET 包装器中显示为结构。该结构有许多子 UDT/结构以及 VBA.Collection 类型的成员(如 .NET 元数据所示)。它还具有常规数据类型,如 string、short、double、int 等。

我在我的 C# 代码中将这个结构初始化为:

udtEmployee udtEmpData = default(udtEmployee);

我也试过了

udtEmpData = new udtEmployee();

如果我不使用 default 或 new 对其进行初始化,我将无法编译我的 C# 代码,因为编译器会抱怨使用未分配的变量。

我需要将此结构作为参考传递。我是这样做的:

clsEmployee.SetData(ref udtEmpData);

在调用 VB6 DLL 的这个方法时,我得到了错误:

错误:试图读取或写入受保护的内存。这通常是一个 指示其他内存已损坏。

是什么原因,有什么解决办法?

注意,我无法更改 VB6 DLL,因为我没有它的源代码。我正在使用 VS 2005。

编辑 1:

这是一个完整的背景:

有本地开发的ERP产品,支持使用VB6进行插件开发。它有一个配置文件,它指定要加载的附加 DLL 的名称。这些插件随后会显示在 ERP 应用程序的菜单中。单击菜单时,ERP 调用一个名为 StartAddOn() 的函数,该函数应存在于 VB6 DLL 中。

我想用 C# 开发插件,所以我用 StartAddOn 方法开发了一个简单的 VB6 插件,然后将控制权传递给我的 .NET DLL。

.NET DLL 使用 ERP 公开的业务类,并来回传递数据对象。在 .NET DLL 中,我添加了对 ERP 供应商发布的 DLL 的 COM 引用。

所以架构是这样的: ERP->VB6 AddOn with StartAddOn 方法->.NET DLL->使用 ERP 供应商发布的 COM DLL 及其数据类(结构/UDT)。

如何调试内存错误?

【问题讨论】:

  • 会不会是一些子结构需要'new'ing以及最高级别的?祝你好运,你有一个棘手的问题。
  • 我尝试对每个成员结构使用 new,并检查它们是否依次具有其他结构。我仍然得到同样的错误。初始化接口类型 VBA.Collection 的成员的正确方法是什么?我尝试使用新的 VBA.CollectionClass。但我收到另一个错误:错误:检索具有 CLSID {A4C4671C-499F-101B-BB78-00AA00383CBB} 的组件的 COM 类工厂失败,原因是以下错误:80040154。 ------------- --------------
  • 您是从 64 位 .net 应用程序调用 32 位 com dll 吗?
  • @AllSolutions 尝试在 C# 中定义一个静态类并将StandardModuleAttribute 应用到它。
  • @AllSolutions 忘记我之前的评论,您使用的是 COM 互操作,而不是 P/Invoke。不过,我仍然相信您的问题是 C# 和 VB6 之间的编组和/或共享内存。如果 UDT 将 VBA 集合作为字段,您可能需要像 link 这样的实现。不过,我不确定如果 VB6 尝试通过添加/删除成员来修改集合会发生什么(谁将拥有支持集合的内存??)

标签: c# dll vb6 com-interop user-defined-types


【解决方案1】:

结构是什么样的?自从我进行任何认真的 VB6 开发以来已经有一段时间了,但我记得有时在语言之间调用时让我绊倒的一件事是 VB6 坚持双字对齐它的所有结构。因此,例如,如果您在中间混合了一些字节值,它将插入填充,以便所有值在偶数 4 字节边界上对齐。考虑以下几点:

Type MyType
    A As Long
    B As Byte
    C As Long
End Type

在内存中,B 和 C 之间会有 3 个字节的未使用空间。当然,如果 C# 没有执行相同的填充,它可能会丢弃你的值并导致各种混乱。

对于某些编译器(例如 C),可以设置编译器开关以使用这种对齐方式。我不知道C#是否有类似的东西。如果没有,解决方案是在 C# 大小的结构中插入一些适当大小的虚拟字段。

这里有一篇文章提供了有关 VB6 如何对齐 UDT 的更多信息: http://www.developerfusion.com/article/3367/copymemory-and-arrays-proper-use/4/

【讨论】:

  • 结构对齐可以使用 StructLayout 属性进行操作:msdn.microsoft.com/en-us/library/…
  • UDT 没有任何字节类型的成员。
  • @Aloraman,当我在项目中添加对 COM DLL 的引用时,该结构是由 .NET 自动生成的。
  • 即使 UDT 没有 byte 数据类型,它也有 short、double 和 bool 数据类型以及这些数据类型的数组声明。
  • 任何长度不为 4 的偶数倍的东西都是可疑的,包括固定长度的字符串。你会认为如果互操作层自动生成结构,它会考虑到这一点,但你永远不知道。 Aloraman 关于 StructLayout 的评论很有趣。我不知道该属性,但如果这是问题所在,这听起来像是答案。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2010-09-07
  • 1970-01-01
  • 1970-01-01
  • 2012-10-17
  • 2012-03-04
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多