使用C#中的VARIANT参数类型调用托管API方法

时间:2012-02-06 17:41:07

标签: c# marshalling com-interop

我有一个ActiveX DLL,我尝试在我的C#应用​​程序中使用它。大多数互操作方法都有效。我遇到以下方法(非托管定义)的问题:

HRESULT SendData([in] long lChID, [in] short nIndex, 
    [in] VARIANT vData, [out, retval] VARIANT_BOOL *bResult);

VARIANT 数据类型对我来说很不寻常,我不知道该怎么做,因为COM和编组对我来说是个新主题。

BOOL CControl::SendData(long lChID, short nIndex, const VARIANT& vData)
{
    BOOL result;
    static BYTE parms[] = VTS_I4 VTS_I2 VTS_VARIANT;

    InvokeHelper(0x1f, DISPATCH_METHOD, VT_BOOL,
        (void*)&result, parms, lChID, nIndex, &vData);

    return result;
}

我使用.NET工具 AxImp.exe 来获取该方法的托管包装器:

[DispId(31)]
[MethodImpl(MethodImplOptions.InternalCall,
    MethodCodeType = MethodCodeType.Runtime)]
public virtual bool SendData([In] int lChID, [In] short nIndex, 
    [MarshalAs(UnmanagedType.Struct), In] object vData);

是否正确生成了C#方法包装器?

初始化和填充vData参数的正确方法是什么?

修改

帮助破译第三个参数VARIANT的更多代码示例。

VARIANT var;
VariantInit(&var);

var.vt = VT_UI1 | VT_BYREF;
var.pbVal = (unsigned char *)pSend;

if (!m_Control.SendData(m_lCurChID, m_combo.GetCurSel() + 1, var))
    AfxMessageBox(_T("SendData failed"));

我不知道 var.vt var.pbVal 。 C#中有相应的代码吗?

1 个答案:

答案 0 :(得分:1)

结帐the System.Runtime.InteropServices.Marshal.GetNativeVariantForObject() method。假设您知道vData的实际内容应该是什么,您应该能够使用IntPtr定义互操作签名,并传递该方法的结果。

你的签名应该是这样的:

public virtual bool SendData(
    [In] int lChID, 
    [In] short nIndex, 
    [MarshalAs(UnmanagedType.Struct), In] IntPtr vData);

虽然调用代码是:

MyClass vData = ...;// build the actual data. 
IntPtr variantPtr = Marshal.AllocHGlobal(Marshal.SizeOf(vData ) + ???); // Allocate the space. I'm not entirely sure how much space you need here in addition to the base object size.
Marshal.GetNativeVariantForObject(vData , variantPtr); //fills the allocated memory with the VARIANT.

现在看一遍,似乎有一些问号。这就是为什么最好的行动方案通常是让默认的编组人员完成其工作。如果你的vData是一个byte [],只需用byte []定义interop函数,看看会发生什么。