2012-04-25 81 views
0

我使用P/Invoke從C#調用非託管C函數,傳遞一個對象數組。 在非託管代碼中,我查詢IDispatch的IUnknown。 這適用於簡單情況,但如果其中一個對象是數組本身,則獲取IDispatch失敗。'object []'託管到非託管封送作爲IUnknown

託管代碼:

[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(...)以某種方式解決這個問題嗎? 或者還有其他方法可以使這個工作?

回答

2

有趣的是,CLR成功地完成了片段工作的第一部分。它可能設法生成一個IDispatch指針,因爲System.Array類型是[ComVisible(true)]。所以你可以讓QI工作,但是沒有任何你可以用IDispatch指針實際做的事情,而不需要熟悉Array類的成員。您在第二個片段中運氣不佳,因爲聲明中沒有任何內容強制CLR編組數組元素。

您需要以正確的方式解決這個問題,在COM自動化中,數組不是IDispatch對象。 Object []的默認COM封送處理是SAFEARRAY *,一個安全數組,其元素是VARIANT。將TakesAnObjectArray參數類型從LPUNKNOWN []更改爲SAFEARRAY *。然後將pinvoke聲明更改爲不帶[MarshalAs]屬性的普通對象[]。

您需要在您的C++代碼中使用SafeArrayLock()和SafeArrayGetElement()來訪問數組元素。第二個片段需要額外的間接尋址,因爲第一個元素是一個包含SAFEARRAY本身的VARIANT。

+0

謝謝你的評論。 我實際上設法做了很多與IUnknown:得到一個IDispatch,得到ITypeInfo,調用typeInfo-> GetDocumentation()來獲取類型名稱。然後使用'GetIDsOfNames'和'Invoke'來執行'ToString',甚至得到正確的信息... 我會嘗試SAFEARRAY方法,看看它是否更好。 – zvikam 2012-04-25 11:57:06

+0

很酷。以SAFEARRAY的方式進行封送,我得到了主陣列的所有元素以及子陣列。 我甚至爲複雜的對象獲得了VARIANT的VT_UNKNOWN,我可以查詢更多信息。 – zvikam 2012-04-25 13:01:54