简体   繁体   English

VB6变体类型到.NET类型

[英]VB6 Variant Type to .NET Type

I have some VB6 code that can't be modified easily that looks like this: 我有一些无法轻易修改的VB6代码,如下所示:

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. 它调用的方法目前是一个VB6组件,我们已经迁移到.NET,只有一个问题。 We're not sure what type the result() is looking for since it's a variant type. 我们不确定result()正在寻找什么类型,因为它是变体类型。 We've tried object, object[], object[][], string, string[], etc, none of which have worked. 我们已经尝试过object,object [],object [] [],string,string []等,其中没有一个有效。

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: 我甚至尝试将第三个参数设置为VariantWrapper,因为它会根据需要添加ByRef:

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. 我已经创建了一个测试接口(用于COM),测试类和测试VB6应用程序,以确保它是Variant的一个问题。 So, it's defined like so: 所以,它的定义如下:

.NET Interface: .NET接口:

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

VB 6 method: VB 6方法:

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. 在VB6中,它只是抛弃了我。 If I compile and run it, I get a generic .NET exception and it throws me out. 如果我编译并运行它,我会得到一个通用的.NET异常,它会抛弃我。

Your C# declaration is wrong. 您的C#声明是错误的。 A VB6 "Long" is 32-bits for historical reasons. 由于历史原因,VB6“Long”是32位。 That's an int on the C# side. 这是C#方面的一个int。 With the stack frame wrong, you have no odds of getting the "result" argument passed correctly. 如果堆栈帧错误,则无法正确传递“result”参数。

It ought to be a SafeArray of Variants, object[] in C#. 它应该是一个变量的SafeArray,C#中的object []。

Put a breakpoint on the mx.GetList(rCount,cCount,result) line. mx.GetList(rCount,cCount,result)行上放置一个断点。 Once hit, add a "quick watch" expression of mx.GetList(rCount,cCount,result) . 点击后,添加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. 最有可能的是它是“comresult”并且不会提供太多信息,但它可能提供返回类型的提示。

I think the ref keyword may be causing some trouble here. 我认为ref关键字可能会在这里造成一些麻烦。 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. 但是,如果你的方法只是通过接受对任何object的引用(而不是ref ),它可以传递任何东西,因为所有东西都是从.NET中的object派生的。

How well this translates to VB6/COM interop, I don't know. 我不知道这对于VB6 / COM互操作有多好。 But it seems that this is at least worth a shot: 但似乎这至少值得一试:

C# code : C#代码

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

VB6 code : VB6代码

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... 我在这里可能是错误的 - 我没有太多将VB6应用程序迁移到.NET的经验 - 但在我看来,如果你可以达到(C#相当于)这一行......

Set mx = CreateObject("Component.Class")

...then you're golden. ......那你就是金色的。 You can use reflection to figure out what parameters the GetList method wants. 您可以使用反射来确定GetList方法想要的参数。

First get the System.Type object representing the type of mx : 首先获取表示mx类型的System.Type对象:

Type mxType = mx.GetType();

Then find the GetList method(s) for that type: 然后找到该类型的GetList方法:

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. 这将为您提供一个MethodInfo[]数组,其中GetList 3个参数的GetList的所有公共重载。 From here the possible types of result will be: 从这里可能的result类型将是:

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

I know only how it's used in .Net where you pass a reference to a Variant like this: 我只知道在.Net中如何使用它来传递对Variant的引用,如下所示:

 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. 主要的是使用VariantWrapper所以dll理解。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM