0

P/Invoke を使用して C# からアンマネージ C 関数を呼び出し、オブジェクトの配列を渡しています。アンマネージ コードでは、IDispatch に対して IUnknown をクエリします。これは単純なケースでは機能しますが、オブジェクトの 1 つが配列自体である場合、IDispatch の取得は失敗します。

マネージド コード:

    [DllImport("NativeDll.dll")]
    static extern void TakesAnObjectArray(int len, 
        [MarshalAs(UnmanagedType.LPArray, 
         ArraySubType = UnmanagedType.IUnknown)]object[] a);

    public static void exec1(int a, object b, string c)
    {
        Object[] info_array;
        Object[] parameters_array;

        parameters_array = new object[4];
        parameters_array[0] = a;
        parameters_array[1] = b;
        parameters_array[2] = c;
        parameters_array[3] = 55;
        // THIS WORKS GREAT
        TakesAnObjectArray(4, parameters_array);

        info_array = new object[6];
        info_array[0] = parameters_array;
        // THIS DOESN'T
        // I CAN'T GET IDISPATCH FOR THE 1ST 'OBJECT'
        TakesAnObjectArray(6, info_array);
    }

アンマネージ コード:

    void TakesAnObjectArray(int len, LPUNKNOWN p[])
    {
        HRESULT hr;
        for (int i=0; i<len; i++)
        {
            IDispatch *disp = NULL;
            hr = p[i]->QueryInterface(IID_IDispatch, (void**)&disp);
        }
    }

ほとんどの場合、QueryInterface は成功します。しかし、マネージド オブジェクトが実際に「System.Object[]」である場合、IDispatch インターフェイスを取得できません (hr = 0x80004002 = E_NOINTERFACE = 「そのようなインターフェイスはサポートされていません」)。

これを修正する何らかの方法で MarshalAs(...) を使用できますか? または、これを機能させる別の方法はありますか?

4

1 に答える 1

3

CLR がスニペットの最初の部分をまったく機能させることができたのは興味深いことです。System.Array の型が [ComVisible(true)] であるため、IDispatch ポインターを生成できた可能性があります。したがって、QI を機能させることはできますが、Array クラス メンバについて十分な知識がなければ、IDispatch ポインタで実際にできることは何もありません。2 番目のスニペットでは、CLR に配列要素のマーシャリングを強制する宣言が含まれていないため、うまくいきませんでした。

これを正しい方法で修正する必要があります。配列は COM オートメーションの IDispatch オブジェクトではありません。Object[] の既定の COM マーシャリングは SAFEARRAY* で、要素が VARIANT のセーフ配列です。TakesAnObjectArray 引数の型を LPUNKNOWN[] から SAFEARRAY* に変更します。そして、pinvoke 宣言を [MarshalAs] 属性のない単純な object[] に変更します。

配列要素にアクセスするには、C++ コードで SafeArrayLock() と SafeArrayGetElement() を使用する必要があります。最初の要素は SAFEARRAY 自体を含む VARIANT であるため、2 番目のスニペットには追加の間接指定が必要です。

于 2012-04-25T10:55:29.060 に答える