ソースを変更できないC++で記述されたCOMコンポーネントがあり、そのメソッドの1つに対する引数の1つはですVARIANT *pParamArray
。を使用しtlbimp
て、そのためのマネージドスタブを作成し、C#から配列を渡すことができます。
残念ながら、COMコンポーネントは、配列が参照によって渡されることを期待しています。明示的なチェックがpParamArray->vt != (VT_BYREF | VT_ARRAY | VT_VARIANT)
あり、そのチェックに合格しなかった場合はエラーが返されます。
PDBとCOMコンポーネントのソースがあるので、C#とアンマネージコードの両方を同時にデバッグしています。私のC#配列object[]
がとして渡されていることがわかります。VT_ARRAY | VT_VARIANT
これは基本的SAFEARRAY
に私が理解している限りです。
VT_BYREF
遠端の型にマスクが含まれるように、参照によって渡すことをC#に明示的に伝えるにはどうすればよいですか?
- 入れてみました
VariantWrapper
- 「 」ArgumentException
というメッセージが表示されますVariantWrappers cannot be stored in Variants.
Marshal.AllocHGlobal
を使ってみましたが、COM側でMarshal.GetNativeVariantForObject()
しか取得できません。int
tlbimp
デフォルトでは、問題のパラメータを。としてマーシャリングしますUnmanagedType.Struct
。tlbimp
マーシャリングをどのように行うか、またはこれが違いを生むかどうかはわかりませんIntPtr
(CodePlexからの拡張機能も使用しようとしましたが、構成ファイルでtlbimp2
の要求を認識していないようです)。IntPtr
私は決して相互運用の専門家ではないので、あなたにとって明白に見えるかもしれない何かを自由に提案してください。
アップデート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;
...
}