2011-05-12 60 views
3

對於c/C++和PInvoke,我是一個完整的noob,所以請和我一起裸照。PInvoke和char **

我從我想在我的c#應用程序中使用的人那裏得到了這個程序集。

標題是這樣的:

int __declspec(dllimport) s2o(WCHAR* filename, char** out, int* len); 

我設法得到它的部分工作,使用:

[DllImport("s2o.dll", EntryPoint = "[email protected]@[email protected]", CallingConvention = CallingConvention.Cdecl)] 
public static extern int s2o(
    [MarshalAs(UnmanagedType.LPWStr)] 
    string filename, 
    ref char[] @out, 
    ref int len 
); 

,然後調用它像這樣:

char[] result = null; 
int length = 0; 
s2o("filepath", ref result, ref length); 

似乎部分工作,因爲'長度'實際上是有價值的。不幸的是,'結果'保持爲空。

我該怎麼做才能做到這一點?

編輯:

好,我設法通過與IntPtr的替換的char [],然後調用「Marshal.PtrToStringAnsi就像尼克工作建議:

string result = Marshal.PtrToStringAnsi(ptr); 

然而,由於同樣的答案中的意見,我有點擔心內存使用情況。組件中沒有提供其他方法,因此我該如何清理它?

謝謝!

+0

您可以嘗試用_IntPtr_替換_char [] _併爲指針調用_PtrToStringAuto_:_Marshal.PtrToStringAuto(@out)_ – Centro 2011-05-12 08:56:07

+0

請使用extern「C」在您的DLL中聲明您的函數以禁用名稱修改。現在你的問題。在告訴我們'out'參數如何工作之前,我們不能告訴你如何調用這個函數。誰分配什麼?你有沒有關於's2o'的文檔? – 2011-05-12 08:58:49

+0

@David:我想他說這是第三方DLL,所以他可能不能添加extern「C」。 – Nick 2011-05-12 09:06:59

回答

2

看看Marshal.PtrToStringAnsi方法。

或作爲Centro在您的問題的評論中說,PtrToStringAuto可能更合適。

將所有字符,直到達到從非託管ANSI字符串 到託管String第一 空字符,並且加寬 每個ANSI字符爲Unicode。

另請注意,您可能負責釋放此函數返回的內存。

+1

在本機代碼中分配的託管代碼可用內存如何?如果本機代碼提供了釋放它的方法,導出分配器或使用COM分配器,那麼這隻能工作。 – 2011-05-12 09:02:30

+0

@大衛:是的,你說得對。 O.P.需要查看DLL的文檔並找出內存如何被釋放。 – Nick 2011-05-12 09:04:39

+0

雖然PtrToStringAuto的作品,我沒有得到預期的結果(而是我得到了很多中文字符),所以我認爲出了問題。另外,我相當確信'out'是一個char數組,所以我不需要首先進行某種轉換? – SaphuA 2011-05-12 11:24:28

6

關於你的最後一個問題:

  • char是單個字符。
  • char*是一個指向char的指針。如果這被解釋爲一個字符串,那麼在該存儲器地址之後的存儲器中的所有數據將被視爲屬於該字符串,直到遇到0x0的值。將char*傳遞給方法意味着,此方法可以更改字符串的內容,但不能更改其長度。
  • char**是一個指向char的指針。將此傳遞給方法意味着該方法能夠創建一個新字符串並將新地址返回給調用者。
+6

另一種可能性是'char **'是一個C字符串數組,例如'argv'。 – 2011-05-12 09:35:33

+0

感謝您的解釋! – SaphuA 2011-05-12 11:24:43