我有一个用 C++ 编写的 COM 组件,我无法更改其源代码,并且其中一个方法的参数之一是VARIANT *pParamArray
. 使用tlbimp
我可以为它创建一个托管存根并从 C# 传递一个数组。
不幸的是,COM 组件期望它的数组通过引用传递——有一个明确的检查,pParamArray->vt != (VT_BYREF | VT_ARRAY | VT_VARIANT)
如果它没有通过检查,它会返回一个错误。
我有 COM 组件的 PDB 和源代码,因此我正在同时调试 C# 和非托管代码。我可以看到我的 C# 数组object[]
被传递为,据我所知VT_ARRAY | VT_VARIANT
,这本质上是 a 。SAFEARRAY
如何明确告诉 C# 我想通过引用传递它,以便远端的类型具有VT_BYREF
掩码?
- 我试过把它放在一个
VariantWrapper
- 我得到一个ArgumentException
消息“VariantWrappers cannot be stored in Variants.
” - 我试过做一个
Marshal.AllocHGlobal
并使用Marshal.GetNativeVariantForObject()
,但我只int
在 COM 端得到一个。
tlbimp
默认情况下,将有问题的参数编组为UnmanagedType.Struct
. 我不确定如何将tlbimp
其编组为IntPtr
,或者即使这会有所作为(我也尝试使用tlbimp2
CodePlex 的增强功能,但它似乎无法识别我IntPtr
在其配置文件中的请求)。
我绝不是 Interop 专家,因此请随意提出一些对您来说可能很明显的建议。
更新 1
根据@ZdeslavVojkovic 的要求,以下是 IDL 的相关部分:
[
uuid(01234567-89AB-CDEF-0123-3456789ABCDE),
version(1.0),
helpstring("XXX")
]
library LAbc
{
[
object,
uuid(01234567-89AB-CDEF-0123-3456789ABCDE),
dual,
helpstring("XXX"),
pointer_default(unique)
]
interface IAbc : IDispatch
{
[id(1), helpstring("XXX")]
HRESULT CallFunction([in] myEnum Function, [in, out] VARIANT* pParamArray, [out, retval] long* pVal);
};
[
uuid(01234567-89AB-CDEF-0123-3456789ABCDE),
helpstring("XXXs")
]
coclass Abc
{
[default] interface IAbc;
};
};
这是方法签名本身和参数类型的内部检查:
STDMETHODIMP XAbc::CallFunction(myEnum Function, VARIANT *pParamArray, long *pVal)
{
...
// we must get a pointer to an array of variants
if(!pParamArray ||
(pParamArray->vt != (VT_BYREF | VT_ARRAY | VT_VARIANT)) ||
!(psa = *pParamArray->pparray))
return E_INVALIDARG;
...
}