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 j开发者_运维技巧ust throws me out. If I compile and run it, I get a generic .NET exception and it throws me out.
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#.
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.
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();
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.
精彩评论