1

前回の投稿の続きです。コンテキストについては、その投稿をお読みください。厳密な 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 メソッドが機能します (マネージド コード ヒットのブレークポイント)。

4

1 に答える 1

1

編集: 問題は createInstance メソッドにあるようです。iid パラメーターで要求された、返されたインターフェイスを取得できません。

ここでは指定IidParameterIndexしても役に立ちません。の実装は次のcreateInstanceようになります。

public int createInstance(ref Guid classId, ref Guid riid, ref IntPtr instance)
{
    if (instance != IntPtr.Zero)
        return E_POINTER;

    // substitute your actual object creation code for CreateObject
    object obj = CreateObject(classId) 

    // return the correct interface
    IntPtr unk = Marshal.GetIUnknownForObject(obj);
    try
    {
        return Marshal.QueryInterface(unk, ref riid, out instance);
    }
    finally
    {
        Marshal.Release(unk);
    }
}
于 2013-10-21T13:14:39.363 に答える