从C#调用带有复杂用户定义类型(UDT)的VB6 DLL函数

9
我正在编写一个C#应用程序,以调用第三方VB6 DLL。我已在“引用->COM”选项卡中添加了对VB6 DLL的引用。
DLL中的特定方法需要将VB6 UDT(用户定义类型)作为参数。
这个UDT在COM的自动生成的.NET封装器中显示为结构体。该结构体有许多子UDT / 结构体,以及类型为VBA.Collection的成员(由.NET元数据显示)。它还具有常规数据类型,如字符串,短整型,双精度浮点数,整型等。
我正在我的C#代码中初始化此结构体:
udtEmployee udtEmpData = default(udtEmployee);

我也尝试过。
udtEmpData = new udtEmployee();

如果我不使用默认值或new来初始化它,我的C#代码将无法编译,因为编译器会抱怨使用未赋值的变量。
我需要将这个结构体作为引用传递。我是这样做的:
clsEmployee.SetData(ref udtEmpData);

在调用VB6 DLL的此方法时,我遇到了错误:

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

原因是什么?解决方案是什么?
注意,我无法更改VB6 DLL,因为我没有其源代码。我正在使用VS 2005。
编辑1:
完整背景如下:
有一款本地开发的ERP产品,支持使用VB6进行插件开发。它有一个配置文件,指定要加载的插件DLL的名称。然后在ERP应用程序中的菜单中显示这些插件。单击菜单时,ERP会调用名为StartAddOn()的函数,该函数应存在于VB6 DLL中。
我想用C#开发插件,因此我开发了一个简单的VB6插件,并带有StartAddOn方法,该方法再将控制传递给我的.NET DLL。
.NET DLL使用ERP公开的业务类,并传递数据对象。在.NET DLL中,我已经添加了对ERP供应商发布的DLL的COM引用。
因此,架构如下: ERP->具有StartAddOn方法的VB6 AddOn->.NET DLL->使用ERP供应商的COM DLL及其数据类(结构/UDT)。
如何调试内存错误?

1
有可能一些子结构体也需要进行“new”操作,而不仅仅是最高级别的那个结构体吗?祝你好运,你面临着一个棘手的问题。 - OldBoyCoder
我尝试使用 new 关键字对每个成员结构进行初始化,并检查它们是否再次包含其他结构体,但仍然遇到相同的错误。初始化类型为 VBA.Collection 的成员变量该如何正确执行?我尝试使用 new VBA.CollectionClass,但是又出现了一个新的错误: 错误:由于以下错误,无法检索具有 CLSID {A4C4671C-499F-101B-BB78-00AA00383CBB} 的组件的 COM 类工厂: 80040154。 - AllSolutions
你正在从一个64位的.NET应用程序中调用一个32位的COM DLL吗? - Mike Miller
1
@AllSolutions 请尝试在C#中定义一个静态类,并将StandardModuleAttribute应用于它。 - GSerg
1
@AllSolutions 忘记我的先前评论吧,你正在使用COM互操作,而不是P/Invoke。尽管如此,我仍然相信你的问题在于C#和VB6之间的封送和/或共享内存。如果UDT具有VBA集合作为字段,则可能需要像这样实现链接。但是,如果VB6尝试通过添加/删除成员来修改集合,我不确定会发生什么(谁将拥有支持集合的内存??) - Andrés Robinet
显示剩余22条评论
1个回答

3

结构体长什么样子?我已经有一段时间没有进行严谨的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属性进行操作:https://msdn.microsoft.com/zh-cn/library/system.runtime.interopservices.structlayoutattribute.aspx - Aloraman
UDT没有任何Byte类型的成员。 - AllSolutions
@Aloraman,当我在我的项目中添加对COM DLL的引用时,该结构是由.NET自动生成的。 - AllSolutions
虽然UDT没有字节数据类型,但它有short、double和bool数据类型,以及每种类型的数组声明。 - AllSolutions
我的猜测是Pack 4,但如果C#结构体在Interop层中定义,我不确定该如何指定它。很抱歉我没有更多的细节。我的经验是在VB和C/C++库之间。我仍然有一些与VB6互操作的项目,但它们是相反的(C#->VB),我们完全避免使用结构体。 - Steve In CO
显示剩余2条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接