2009-11-27 56 views
1

我在Visual C++ DLL此功能的char *編組的C#

char * __stdcall GetMessage(int id) { 
char buffer[250]; 
. 
. 
. 
strcpy(buffer, entry); // entry is a char * that has allocated 250 chars 
return (char *)buffer; 
} 

我試圖導入從C#這個功能用下面的代碼

[DllImport("mydll.dll", CharSet=CharSet.Ansi)] 
public static extern string GetMessage(int id); 

我想在提出本一個MessageBox它總是在字符串的末尾有奇怪的符號。任何建議如何克服這個問題?

+0

我沒有提到,我調試的DLL的char *緩存爲0結束一個適當的字符串。 – Ioannis 2009-11-27 12:49:09

+2

我不知道它是如何與返回值,但參數適用於以下規則:使用字符串爲const char *,使用StringBuilder爲char *。另一方面,你正在返回一個指向本地變量的緩衝區的指針。這聽起來不是一個好主意。這個問題可能是你的朋友,但是:http://stackoverflow.com/questions/370079/pinvoke-for-c-function-that-returns-char – OregonGhost 2009-11-27 12:53:37

+1

@OreghonGost,不,規則是:使用'string'爲什麼你不會改變,並且使用'StringBuilder'來執行你的操作。 'const'給出了一個提示,但並不嚴格要求。 – 2009-11-27 17:19:09

回答

7

我再強調一個事實,即你的C++代碼是無效的。您正在返回一個指向當函數返回時不再有效的堆棧幀上的局部變量的指針。它現在起作用只是一個意外。只要調用另一個函數,堆棧空間將被重用,從而破壞緩衝區內容。當你從C#調用這段代碼時,這是保證發生的,P/Invoke編組器實現將覆蓋棧幀並破壞緩衝區。

更糟的是,P/Invoke編組器會嘗試釋放緩衝區。它將假定緩衝區由CoTaskMemAlloc()分配並調用CoTaskMemFree()來釋放緩衝區。這會在Windows XP和更早版本中悄然失敗,但會在Vista和更高版本上崩潰你的程序。

這是您的問題的一種解決方案,使用CoTaskMemAlloc()來分配緩衝區而不是使用局部變量。全方位更好的解決方案是讓函數的調用者通過緩衝區來填充字符串。這樣,調用者可以決定如何分配緩衝區並根據需要進行清理。函數簽名應該是這樣的:

extern "C" __declspec(dllexport) 
void __stdcall GetMessage(int id, char* buffer, size_t bufferSize); 

使用strcpy_s()來安全地填充緩衝區,並避免任何緩衝區溢出。那麼相應的C#聲明將是:

[DllImport("mydll.dll")] 
private static extern void GetMessage(int id, StringBuilder buffer, int bufferSize); 

,並呼籲像這樣:

var sb = new StringBuilder(250); 
GetMessage(id, sb, sb.Capacity); 
string retval = sb.ToString(); 
1

從DLL返回一個字符數組,即在GetMessage函數內的堆棧中的緩衝區,並且當執行返回時,由於緩衝區從堆棧彈出並且在本地堆棧也是,因此你看到的奇怪的字符。有兩種方法可以解決這個問題,將緩衝區變量聲明更改爲指針和malloc,然後再返回它或將其聲明爲靜態。

 
char *buffer; 
if (!(buffer = (char *)malloc((250 * sizeof(char)) + 1)){ 
    // Handle the out of memory condition 
} 
// Now the buffer has 250 + 1 for null terminating character. 

或者

 
static char buffer[250]; 

您也可以澄清項指針變量 - 是全球性的?

希望這會有所幫助, 最好的問候, 湯姆。

0

嘗試使用StringBuilder的返回類型,並留下了字符集屬性:

[DllImport("mydll.dll")] 
public static extern StringBuilder GetMessage(int id); 
+0

根本無助於指向死亡本地的問題。 – 2009-11-27 17:20:05