VB6 变体类型到 .NET 类型

发布于 2024-09-09 00:07:48 字数 1082 浏览 1 评论 0原文

我有一些无法轻易修改的 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 异常并将我抛出。

I have some VB6 code that can't be modified easily that looks like this:

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

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

The method it calls is currently a VB6 component that we've migrated to .NET with one issue. We're not sure what type the result() is looking for since it's a variant type. We've tried object, object[], object[][], string, string[], etc, none of which have worked.

Here's an example:

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

I've even tried setting the third param to VariantWrapper since it will add ByRef as necessary:

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

Any ideas what I can set the incoming result to be so that I don't have an unhandled exception?

I've created a test Interface (for COM), test Class, and test VB6 app to ensure it was an issue with the Variant. So, it's defined like so:

.NET Interface:

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

VB 6 method:

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

Same issue as described above. In VB6, it just throws me out. If I compile and run it, I get a generic .NET exception and it throws me out.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

木緿 2024-09-16 00:07:48

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

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

Your C# declaration is wrong. A VB6 "Long" is 32-bits for historical reasons. That's an int on the C# side. With the stack frame wrong, you have no odds of getting the "result" argument passed correctly.

It ought to be a SafeArray of Variants, object[] in C#.

忘年祭陌 2024-09-16 00:07:48

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

Put a breakpoint on the mx.GetList(rCount,cCount,result) line. Once hit, add a "quick watch" expression of mx.GetList(rCount,cCount,result). The toolwindow should show you what the resulting runtime-type is. Most likely it is a "comresult" and will not provide much information, but it may provide a hint to the return type.

昔梦 2024-09-16 00:07:48

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

但是,如果您的方法只是通过接受对任何对象的引用(而不是通过ref),那么它可以传递任何内容,因为一切都源自 .NET 中的object

我不知道这对于 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();

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

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

I think the ref keyword may be causing some trouble here. The types have to match exactly for that to work.

However, if your method simply accepts a reference to any object by value, (instead of by ref), it can get passed anything, since everything derives from object in .NET.

How well this translates to VB6/COM interop, I don't know. But it seems that this is at least worth a shot:

C# code:

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

VB6 code:

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

MsgBox mx.GetTypeName(result)

Does that give you anything?


Here's an idea. I could be dead wrong here -- I've not much experience in migrating VB6 apps to .NET -- but it seems to me that if you can get as far as (the C# equivalent of) this line...

Set mx = CreateObject("Component.Class")

...then you're golden. You can use reflection to figure out what parameters the GetList method wants.

First get the System.Type object representing the type of mx:

Type mxType = mx.GetType();

Then find the GetList method(s) for that type:

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

This will give you a MethodInfo[] array of all the public overloads of GetList taking 3 parameters. From here the possible types of result will be:

Type[] possibleResultTypes = getListMethods
    .Select(m => m.GetParameters()[2].ParameterType)
    .ToArray();
秋风の叶未落 2024-09-16 00:07:48

我只知道它在 .Net 中的使用方式,其中您传递对 Variant 的引用,如下所示:

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

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

最主要的是使用 VariantWrapper 以便 dll 能够理解。

I know only how it's used in .Net where you pass a reference to a Variant like this:

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

After this, put a breakpoint and check the variant type if you're not sure about it.

The main thing is using VariantWrapper so the dll understands.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文