从C#调用具有VARIANT参数类型的托管API方法

本文关键字:API 方法 类型 参数 调用 VARIANT | 更新日期: 2023-09-27 18:23:35

我有一个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.vtvar.pbVal。C#中有相应的代码吗?

从C#调用具有VARIANT参数类型的托管API方法

检查System.Runtime.InteropServices.Marshal.GetNativeVariantForObject()方法。假设您知道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[]定义互操作函数,然后看看会发生什么。