我有一个VB.NET winforms应用程序,它使用ActiveX控件(ocx)。通过interop,我有一个对ocx中定义的对象的引用,并在其上调用各种函数。这在大多数情况下都可以正常工作。
我遇到了一个导致内存泄漏的函数调用问题(my other question was related to this),开发人员建议我使用不同的函数来获取相同的数据。区别在于第一个函数返回数据,第二个函数通过ref传递一个对象,在该对象中放入数据。
我调用原始(泄漏)函数,它返回如下数据:
// from generated documentation of axobject
// function name obfuscated
public virtual object A();
从VB.NET调用
Dim result = CType(axobject.A(), UInt16())
这有效但内存泄漏。所以我会尝试使用其他功能
这是建议使用的功能
// C++ definition, names obfuscated
long axobject::B(VARIANT* var)
// from generated documentation of axobject
// function name obfuscated
public virtual int B(out object var);
像这样从VB.NET调用它
Dim o As Object = Nothing
Dim i As Integer
i = axobject.B(o) ' exception here
Dim result = CType(o, UInt16())
产生一个execption
好的,所以看起来null对象没有传递给函数。所以我事先为它指定了一些东西System.Runtime.InteropServices.COMException:'参数不是可选的。 (HRESULT异常:0x8002000F(DISP_E_PARAMNOTOPTIONAL))'
Dim o As Object = New Object()
Dim i As Integer
i = axobject.B(o)
Dim result = CType(o, UInt16())
现在这个例外
System.Runtime.InteropServices.COMException:'类型不匹配。 (HRESULT异常:0x80020005(DISP_E_TYPEMISMATCH))'
甚至尝试拳击一个UInt数组
Dim o As Object = {1US}
但我得到同样的错误。
当我看到定义类似于C#dynamic
时,我的第一个倾向是,但它在VB.NET和I've heard many times to use Object
with Option Strict Off
and Option Infer On
中不可用。这些是我正在使用的选项,它不起作用。但是我在C#项目中测试了它,它可以工作
dynamic o = null;
int res = axobject.B(ref o);
UInt16[] result = (UInt16[])o;
// everything here works
以下是调试器的屏幕截图,其中包含C#中的工作代码。
从VB.NET开始,从C#项目的角度来看,定义有ref
而不是out
。我100%确定ocx在两个项目中都是相同的版本。这很奇怪
// from generated documentation of axobject in C# project
public virtual int B(ref object var);
我想在C#中创建一个扩展方法,看看它是怎么回事。关于如何纯粹使用VB.NET进行调用的任何建议都会非常有用。
修改1
我尝试在C#中创建扩展方法并从VB.NET调用。我在C#扩展方法中得到与VB.NET相同的错误
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
或首先将o分配给新对象(),
DISP_E_TYPEMISMATCH
修改2
添加Ildasm的结果
Interop.LibName.dll:
.method public hidebysig newslot virtual
实例int32 B (对象& marshal(struct)var)运行时管理preservesig internalcall
{
.custom instance void [mscorlib] System.Runtime.InteropServices.DispIdAttribute ::。ctor(int32)=(01 00 D1 00 00 00 00 00)
.override LibName 。 ClassName :: B
} //方法结束 ClassName :: B
AxInterop.LibName.dll:
.method public hidebysig newslot virtual
实例int32 B (object& var)cil托管
{
//代码大小35(0x23)
.maxstack 2
.locals init(int32 V_0)
IL_0000:ldarg.0
IL_0001:ldfld类[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:扔
IL_0014:ldarg.0
IL_0015:ldfld类[Interop。 LibName ] LibName 。 ClassName LibName .AxGetData :: ocx
IL_001a:ldarg.1
IL_001b:callvirt实例int32 [Interop。 LibName ] LibName 。 ClassName :: B (对象& ;)
IL_0020:stloc.0
IL_0021:ldloc.0
IL_0022:ret
} //方法结束 ClassName :: B