我有一个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#中有相应的代码吗?
答案 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函数,看看会发生什么。