【问题标题】:VB6 Variant Type to .NET TypeVB6 变体类型到 .NET 类型
【发布时间】:2010-07-13 19:19:51
【问题描述】:

我有一些无法轻易修改的 VB6 代码,如下所示:

Dim cCount as Long
Dim rCount as Long
Dim result()

Set mx = CreateObject("Component.Class")
Dim rtn = mx.GetList(rCount,cCount,result)

它调用的方法当前是一个 VB6 组件,我们已将其迁移到 .NET,但存在一个问题。我们不确定 result() 正在寻找什么类型,因为它是一个变体类型。我们尝试过object、object[]、object[][]、string、string[]等,都没有奏效。

这是一个例子:

public bool GetList(ref long rCount, ref long cCount, ref object result)
{
  ...
}

我什至尝试将第三个参数设置为 VariantWrapper,因为它会根据需要添加 ByRef:

public bool GetList(ref long rCount, ref long cCount, VariantWrapper result)
{
  ...
}

任何想法我可以将传入结果设置为什么,以便我没有未处理的异常?

我创建了一个测试接口(用于 COM)、测试类和测试 VB6 应用程序,以确保它是变体的问题。所以,它是这样定义的:

.NET 接口:

[DispId(1)]
[ComVisible(true)]
string Test(ref object[] value);

VB 6 方法:

Private Sub Command1_Click()
    Set mx = CreateObject("Component.Class")
    Dim result()
    MsgBox mx.Test(result)
End Sub

与上述相同的问题。在 VB6 中,它只是让我失望。如果我编译并运行它,我会得到一个通用的 .NET 异常,它会把我扔出去。

【问题讨论】:

  • 可以看到result()是如何声明和传递的,但看不到GetList返回后是如何使用的?
  • 因此,当将 Variant() 类型分配给 result 并传递给 GetList 时,.NET 会报错。
  • 添加 VariantWrapper 会给我一个错误 5 非法过程调用。
  • 看看 .NET 中的反射,以完成过去在 VB6 中使用后期绑定完成的工作。
  • 我已将我的问题提交给 VB 团队。最后我知道,他们认为我所做的应该有效。所以我向他们提交了一个完整的项目。我会在这里回复他们的回复。

标签: c# vb.net vb6 interop com-interop


【解决方案1】:

您的 C# 声明错误。由于历史原因,VB6 “Long”是 32 位的。这是 C# 方面的 int 。如果堆栈帧错误,您就不可能正确传递“结果”参数。

它应该是一个 SafeArray of Variants, object[] in C#。

【讨论】:

  • 我已将其切换为 bool GetList(ref int rCount, ref int cCount, ref object[] result);它仍然不起作用。我马上得到一个 .NET 异常。
  • 请不要让我猜测异常。
  • 汉斯,抛出的异常是“Visual Basic 已生成异常......”它只发生在结果 Variant() 类型中。我创建了一个新的 .NET 方法来测试(下面是我的签名形式的接口): string Test(ref object[] value);然后,我创建了一个测试 VB6 应用程序,如下所示: Private Sub Command1_Click() Set mx = CreateObject("Component.Class") Dim result() MsgBox mx.Test(result) End Sub 与上述相同的问题。正如我最初描述的那样,它不喜欢 Variant 类型。
  • 我需要一段时间才能启动那台旧机器。呜呜。我会推荐奖金。
【解决方案2】:

mx.GetList(rCount,cCount,result) 行放置一个断点。点击后,添加mx.GetList(rCount,cCount,result) 的“快速观看”表达式。工具窗口应该向您显示生成的运行时类型是什么。很可能它是一个“comresult”,不会提供太多信息,但它可能会提供返回类型的提示。

【讨论】:

  • 我已经修改了代码,这样只要它到达方法,它就会返回一个真正的布尔值。如果我将结果变量切换为不同的类型并在快速的 VB6 测试应用程序中对其进行测试,它就可以正常工作。
【解决方案3】:

我认为ref 关键字在这里可能会造成一些麻烦。类型必须完全匹配才能正常工作。

但是,如果您的方法只是通过(而不是通过ref)接受对任何object 的引用,则它可以传递任何内容,因为所有内容都来自object .NET。

这对 VB6/COM 互操作的转化效果如何,我不知道。但似乎这至少值得一试:

C# 代码

public string GetTypeName(object value)
{
    return value.GetType().FullName;
}

VB6 代码

Set mx = CreateObject("Component.Class")
Dim result()

MsgBox mx.GetTypeName(result)

这对你有什么好处吗?


这是一个想法。我在这里可能大错特错——我在将 VB6 应用程序迁移到 .NET 方面没有太多经验——但在我看来,如果你能做到这一行(相当于 C#)......

Set mx = CreateObject("Component.Class")

...那你就是金子了。您可以使用反射来确定GetList 方法需要哪些参数。

首先获取代表mx类型的System.Type对象:

Type mxType = mx.GetType();

然后找到该类型的GetList 方法:

MethodInfo[] getListMethods = mxType.GetMember("GetList")
    .OfType<MethodInfo>()
    .Where(m => m.GetParameters().Length == 3)
    .ToArray();

这将为您提供一个 MethodInfo[] 数组,其中包含 GetList 的所有公共重载,采用 3 个参数。从这里开始,result 的可能类型将是:

Type[] possibleResultTypes = getListMethods
    .Select(m => m.GetParameters()[2].ParameterType)
    .ToArray();

【讨论】:

  • 这行不通,因为 VB6 应用程序正在传递给 C#。这不是我需要在 VB6 中使用什么类型的问题,因为它是在 C# 中设置 COM 方法的类型。 VB6 类型是 Variant()。 C# 类型应该是 object[] 或 VariantWrapper 两者都不起作用。
  • @Jason:我想我很困惑。您是说是您的 VB6 代码引发了异常吗?而您只是想弄清楚如何定义您的 C# 方法以便可以从 VB6 调用它?还是倒退了?
  • 我想弄清楚如何定义我的 C# 方法,以便我可以从 VB6 调用它。但是,VB6 并没有抛出异常,它是 .NET。调用转到 Interop 中的类库,但由于它是一个 .NET 程序集,因此 .NET 会生成异常。
  • @Jason:我发布了另一个想法。让我知道这是否对您有用/完成任何事情。我什至不应该为我提供帮助,因为我对 VB6 或 COM 互操作几乎一无所知,但我对这个问题很感兴趣,所以我只是把我的想法扔在那里。
【解决方案4】:

我只知道它在 .Net 中的使用方式,您可以像这样传递对 Variant 的引用:

 int port = 2;
 object pvPort = new System.Runtime.InteropServices.VariantWrapper(port);
 gimp.SetPort(ref pvPort);

在此之后,如果您不确定,请放置一个断点并检查变体类型。

主要是使用VariantWrapper,这样dll就可以理解了。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2011-06-14
    • 2020-04-21
    • 2022-01-02
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多