I have a VB.NET winforms app which uses an ActiveX control (ocx). Via interop, I have a reference to an object defined in the ocx and call various functions on it. This works ok for the most part.
I had some issues with one function call causing a memory leak (my other question was related to this) and the developer suggested I use a different function to get the same data. The difference is that the first function returns the data, and the second function is passed an object by ref in which it puts the data.
I call the original (leaky) function which returns the data like this:
// from generated documentation of axobject
// function name obfuscated
public virtual object A();
Called from VB.NET
Dim result = CType(axobject.A(), UInt16())
That works but memory leaks. So I will try to use the other function
This is the suggested function to use
// C++ definition, names obfuscated
long axobject::B(VARIANT* var)
// from generated documentation of axobject
// function name obfuscated
public virtual int B(out object var);
Calling it from VB.NET like this
Dim o As Object = Nothing
Dim i As Integer
i = axobject.B(o) ' exception here
Dim result = CType(o, UInt16())
produces an execption
System.Runtime.InteropServices.COMException: 'Parameter not optional. (Exception from HRESULT: 0x8002000F (DISP_E_PARAMNOTOPTIONAL))'
ok, so it seems like the null object is not passed to the function. So I assign something to it something beforehand
Dim o As Object = New Object()
Dim i As Integer
i = axobject.B(o)
Dim result = CType(o, UInt16())
and now this exception
System.Runtime.InteropServices.COMException: 'Type mismatch. (Exception from HRESULT: 0x80020005 (DISP_E_TYPEMISMATCH))'
Even tried boxing a UInt array
Dim o As Object = {1US}
but I get the same error.
Well my first inclination when I saw the definition was something like C# dynamic
but it is not available in VB.NET and I've heard many times to use Object
with Option Strict Off
and Option Infer On
. These are the options I am using, and it doesn't work. But I tested it in a C# project, and it works
dynamic o = null;
int res = axobject.B(ref o);
UInt16[] result = (UInt16[])o;
// everything here works
Here is a screenshot of the debugger with working code in C#.
The definition from the perspective of the C# project has ref
instead of out
when coming from VB.NET. I am 100% sure the ocx is the same version in both projects. This is strange
// from generated documentation of axobject in C# project
public virtual int B(ref object var);
Well I'm going to make an extension method in C# and see how it goes. Any suggestions on how to make this call purely from VB.NET would be very helpful.
Edit 1
I tried making an extension method in C# and calling from VB.NET. I get the same errors as VB.NET in the C# extension method
public static int B_ex(this axobject obj, ref object var)
{
int res = obj.B(out dynamic o);
var = o;
return res;
}
DISP_E_PARAMNOTOPTIONAL
or when o is assigned to new object() first,
DISP_E_TYPEMISMATCH
Edit 2
Adding results of Ildasm
Interop.LibName.dll:
.method public hidebysig newslot virtual
instance int32 B(object& marshal( struct) var) runtime managed preservesig internalcall
{
.custom instance void [mscorlib]System.Runtime.InteropServices.DispIdAttribute::.ctor(int32) = ( 01 00 D1 00 00 00 00 00 )
.override LibName.ClassName::B
} // end of method ClassName::B
AxInterop.LibName.dll:
.method public hidebysig newslot virtual
instance int32 B(object& var) cil managed
{
// Code size 35 (0x23)
.maxstack 2
.locals init (int32 V_0)
IL_0000: ldarg.0
IL_0001: ldfld class [Interop.LibName]LibName.ClassName LibName.ClassName::ocx
IL_0006: brtrue.s IL_0014
IL_0008: ldstr "B"
IL_000d: ldc.i4.0
IL_000e: newobj instance void [System.Windows.Forms]System.Windows.Forms.AxHost/InvalidActiveXStateException::.ctor(string, valuetype [System.Windows.Forms]System.Windows.Forms.AxHost/ActiveXInvokeKind)
IL_0013: throw
IL_0014: ldarg.0
IL_0015: ldfld class [Interop.LibName]LibName.ClassName LibName.AxGetData::ocx
IL_001a: ldarg.1
IL_001b: callvirt instance int32 [Interop.LibName]LibName.ClassName::B(object&)
IL_0020: stloc.0
IL_0021: ldloc.0
IL_0022: ret
} // end of method ClassName::B
User contributions licensed under CC BY-SA 3.0