2010-11-17 55 views
0

我有一個C++方法與此簽名:調用C++方法與字符串作爲字符串數組處理

STDMETHODIMP ClassName::FunctionName(long number, BSTR* names, long* status) 

裏面的名稱變量作爲一個字符串數組訪問的方法,即

char * tempString = NULL; 

for (int n = 0; n < number; n++) 
{ 
    tempString = OLE2T(names[n]); 
... 

我編譯C++項目,它生成一個dll,然後我註冊這個DLL並在VB項目中添加一個引用。 當我添加的基準,一互操作組件是自動生成的,並在互操作組件中的方法的簽名如下:

FunctionName (number as Integer, ByRef names as String) As Integer 

從VB.Net我調用這樣的方法:

result = FunctionName (number, names(0)) 

其中names是一個包含多個元素的字符串數組,而number和result是整數。

問題是,當C++代碼嘗試訪問名稱數組(名稱[1]和前面)中的其餘元素時,它開始在這些字段上出現「垃圾」。

我的問題是,我如何發送整個字符串數組而不是第一個值。

C++代碼是我無法修改的庫,因此我所做的任何更改都必須在VB.Net代碼上。

我在想,也許使用PInvoke來調用該方法可能會訣竅(聲明一個正確的簽名),但我希望有更好的東西。

任何想法?

謝謝!

編輯:

我在互操作/編組專家,但我查了方法的IDL定義,其計算方法如下:

[id(60), helpstring("method FunctionName")] 
     HRESULT FunctionName(
        [in] long number, 
        [in, size_is(number)] BSTR* names, 
        [out, retval] long* status); 

不應該size_is表明名字參數是一個數組,因此,Interop程序集生成時是否相應地執行?

再次感謝

+0

您需要一些特殊的IDL指令來告訴COM編組人員'number'意味着字符串數組'names'的大小。否則,編組不知道這一點,只是期望獨立的值,不知道'names'是一個數組。 當然,您可以編寫一個C++包裝器,它可以「知道」原始C++庫的無效行爲,並更正接口。 – gimpf 2010-11-17 13:08:19

+0

感謝您的及時答覆,我剛剛編輯了這個問題,我認爲是您所說的所需idl信息。有什麼建議? – willvv 2010-11-17 13:37:47

+0

VB沒有p/invoke或'MarshalAsAttribute',也許你的意思是VB.net?並且'names [0]'不是VB中的數組元素語法?解決你的問題的最簡單的方法是使用一個C++/CLI包裝器,它接受一個.NET'array ',轉換成一個'BSTR'數組,然後調用C++函數。 – 2010-11-17 14:28:27

回答

2

不,[size_is]是隻有MIDL.EXE知道如何使用的屬性。它在爲接口生成代理/存根時會這樣做,當您想跨越進程邊界進行調用時會使用該代理/存根。

它在類型庫中是不能表達的。參數以「指向BSTR的指針」的形式發出,它可以指示BSTR通過引用或BSTR數組傳遞。 Tlbimp.exe無法區分,它挑選前者。它必須,它不能合理地推斷數組的大小。你在運行時會產生垃圾,因爲CLR互操作層只傳遞數組中的一個元素。任何COM客戶端使用這種方法都有一個大問題,它不是.NET特定的。 .NET pinvoke編組器有解決此問題的方法,請注意[MarshalAs]屬性的SizeParamIndex屬性。

如果你不能修改C++代碼,那麼你需要手工編輯互操作庫來注入[MarshalAs]屬性。這非常難看,你必須用ildasm反編譯庫。exe,編輯.il並將它與ilasm.exe放在一起。你不想經常這樣做。

如果你可以,那麼你應該使用自動化兼容的方式來傳遞數組。使用SAFEARRAY。這完全由類型庫和CLR互操作管道支持,管理端不需要在結尾處理任何工作。另外請注意,您現在不再需要號碼的說法,安全數組知道它們有多長。與託管陣列不同。

+0

太棒了!非常感謝,如果有人感興趣,我修改IL中的方法聲明:[in] string&marshal(bstr)names)runtime managed internalcall to this:[in] string [] marshal(bstr [0] )名稱)運行時管理的內部呼叫。這表明該參數將是一個字符串數組,並且該數組的長度將是該方法的第一個參數。 – willvv 2010-11-17 15:36:39