【问题标题】:How to pass an uninitialized array from VB6 to .NET via COM?如何通过 COM 将未初始化的数组从 VB6 传递到 .NET?
【发布时间】:2018-03-04 06:57:09
【问题描述】:

我想用一个用 VB.NET 编写的新组件替换一个用 VB6 编写的组件。新组件必须与其他 VB6 应用程序一起工作,直到这些应用程序也被替换。我在使用将字符串数组作为参数的函数时遇到问题。

我正在使用包含此函数的 VB6 类来复制问题:

Public Function MyMethod(arr() As String, arr2() As String, Result$) As Integer     
    Result = Join(arr, ", ")
    MyMethod = 0        
End Function

我可以从这样的测试程序 (VB6) 中成功调用它,显示“Hello, World”:

    Dim obj As Object
    Dim arr() As String
    Dim arr2() As String
    Dim result As String

    Set obj = CreateObject("MyHelloWorld.MyClass")
    'Set obj = CreateObject("HelloWorldCOMNet.MyNetClass")

    arr = Split("Hello World", " ")
    'ReDim arr2(0)
    result = ""

    If Not obj.MyMethod(arr, arr2, result) Then
        MsgBox result
    End If

我无法修改实际的 VB6 应用程序,但我想用 .NET 编写的类替换 VB6 ActiveX 组件。新类如下所示:

<ComClass("cd74ab4a-76ca-4c84-9f49-147e6f6ac01f", "b3314f71-cb8d-48ea-bfe6-9d1995aa4f58", "40c30052-0cc8-4ef6-b1e8-92e4ddbcb515")> _
Public Class MyNetClass

    Public Sub New()
        MyBase.New()
    End Sub

    Public Function MyMethod(ByRef arr() As String, ByRef arr2() As String, ByRef result As String) As Short
        result = String.Join(", ", arr) + " from .NET"
        Return 0
    End Function

End Class

我通过在测试应用程序中将Set obj = CreateObject("MyHelloWorld.MyClass") 替换为Set obj = CreateObject("HelloWorldCOMNet.MyNetClass") 来测试它。

我在 .NET 类的构造函数中使用了断点来验证它是否已被执行。

当测试应用调用MyMethod时,会出现FatalExecutionEngineException

我将错误缩小到第二个参数arr2。当我使用ReDim arr2(0) 初始化变量时,.NET 代码有效。所以我的猜测是它与这个变量未初始化的事实有关。不幸的是,我无法修改实际的 VB6 应用程序。

我使用 OleWoo 比较了方法签名,它们看起来是相同的(除了 id)。

如何修改 .NET 函数的签名以接受未初始化的字符串数组?

编辑:OleWoo 的输出:

[id(0x00000001)]
short MyMethod(
   [in, out] SAFEARRAY(BSTR)* arr,
   [in, out] SAFEARRAY(BSTR)* arr2,
   [in, out] BSTR* result
);

【问题讨论】:

  • 基于stackoverflow.com/q/35190653/11683stackoverflow.com/q/39351476/11683,我会尝试将其声明为Array 和/或应用编组属性。
  • 我希望有一个类似的解决方案。不幸的是,我无法让它工作。使用ByRef arr2 As Array 我得到“无效的过程调用或参数(错误5)”,&lt;MarshalAs(UnmanagedType.SafeArray, SafearraySubType:=VarEnum.VT_BSTR)&gt; ByRef arr2 As Array 导致与以前相同的异常。我希望最后一个工作。 ByRef 或 ByVal 也没有区别。我用 OleWoo 的输出更新了问题。
  • 在寻找解决方案时,您可以在 VB6 中编写一个带有预期签名的 dll,用于接收数组、根据需要重新调整并调用 .NET 中的实际实现。但我很惊讶编组器无法编组一个空数组 - 至少是Nothing
  • 我在 VBA 中重新创建了您的案例(最接近 VB6)并得到了同样的错误。如果我添加对.Net 程序集的引用并将obj 声明为MyNetClass,则代码有效。所以问题似乎出在后期绑定编组中。

标签: .net vb.net com vb6


【解决方案1】:

我认为这是 .NET Framework 中的一个错误。

我将调试器附加到 VB6 应用程序。这是崩溃时的堆栈跟踪:

这是该位置的反汇编代码:

这就是函数DispatchInfo::IsVariantByrefStaticArray。它取消引用(*V_ARRAYREF(pOle)) 的结果而不检查它是否为NULL。成员 fFeatures 位于偏移量 2 处,导致地址 0x00000002 发生访问冲突。

我相信这是我偶然发现的问题。我想我必须找到另一种方法来解决我原来的问题。

【讨论】:

    猜你喜欢
    • 2012-07-13
    • 2010-11-20
    • 2011-07-13
    • 2023-04-11
    • 2012-05-15
    • 2012-01-30
    • 1970-01-01
    • 1970-01-01
    • 2017-02-10
    相关资源
    最近更新 更多