前回の投稿の続きです。コンテキストについては、その投稿をお読みください。厳密な COM 相互運用性ではないことに注意してください。ただし、C++ インターフェイスは COM と互換性があります。
このC++インターフェースをC#で実装しようとしています
class IPluginFactory : public FUnknown
{
virtual tresult PLUGIN_API createInstance (FIDString cid, FIDString iid, void** obj) = 0;
};
私のC#コードは次のようになります:
[ComImport]
[Guid(Interfaces.IPluginFactory)]
[InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
public interface IPluginFactory
{
[PreserveSig]
[return: MarshalAs(UnmanagedType.Error)]
Int32 CreateInstance([In] ref Guid classId, [In] ref Guid interfaceId, [MarshalAs(UnmanagedType.IUnknown), In, Out] ref object instance);
}
実装は、新しいオブジェクト インスタンスを「インスタンス」パラメーターに割り当て、0 (S_OK) を返します。予想される(管理された)インターフェースにキャストすることさえあります。
instance = (IPluginBase)new PluginBase();
return 0;
返されるオブジェクトは、次の C++ インターフェイスで表されます。
class IPluginBase: public FUnknown
{
public:
virtual tresult PLUGIN_API initialize (FUnknown* context) = 0;
virtual tresult PLUGIN_API terminate () = 0;
};
私のC#実装では次のようになります。
[ComImport]
[Guid(Interfaces.IPluginBase)]
[InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
public interface IPluginBase
{
[PreserveSig]
[return: MarshalAs(UnmanagedType.Error)]
Int32 Initialize([MarshalAs(UnmanagedType.IUnknown), In] object context);
[PreserveSig]
[return: MarshalAs(UnmanagedType.Error)]
Int32 Terminate();
}
私が作成したアンマネージ C++ テスト アプリケーションでは、createInstance を正常に呼び出し、コードが IPluginBase* として使用する null 以外のポインターを受け取ることができます。
この IPluginBase* ポインターで「initialize」メソッドを呼び出そうとすると、問題が発生します。マネージ コードに到達することはなく (ブレークポイントはヒットせず、他のブレークポイントは正常に動作します)、リターン コードは 0x80004003 です。ラッパーがここでインターセプトを行っているようです...
私の質問は: CreateInstance のマネージド表現の宣言は正しいですか? ここで何が欠けていますか?(これは普通の相互運用であるべきですよね?)
宣言 'style' に関するその他の提案も歓迎します。ありがとう、マーク。
編集: 問題は createInstance メソッドにあるようです。iid パラメーターで要求された、返されたインターフェイスを取得できません。
[PreserveSig]
[return: MarshalAs(UnmanagedType.Error)]
Int32 CreateInstance([In] ref Guid classId, [In] ref Guid interfaceId, [MarshalAs(UnmanagedType.IUnknown, IidParameterIndex = 1), In, Out] ref object instance);
IidParameterIndex と組み合わせて UnmanagedType.Interface も試しましたが、どちらも IUnknown がマーシャリングされて返されます。IPluginBase インターフェイスを再クエリすると、IPluginBase::initialize メソッドが機能します (マネージド コード ヒットのブレークポイント)。