使用VB.NET中的ref参数调用ActiveX控件函数

时间:2018-04-23 16:39:36

标签: c# vb.net dynamic com-interop

我有一个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

  

System.Runtime.InteropServices.COMException:'参数不是可选的。 (HRESULT异常:0x8002000F(DISP_E_PARAMNOTOPTIONAL))'

好的,所以看起来null对象没有传递给函数。所以我事先为它指定了一些东西

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#中的工作代码。

enter image description here

从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

0 个答案:

没有答案