簡體   English   中英

Char *在C#中編組

[英]Char * marshalling in C#

我在Visual C ++ DLL中有此功能

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中呈現它,它總是在字符串的末尾有奇怪的符號。 有什么建議如何克服這個問題?

我會再次強調你的C ++代碼無效的事實。 您正在返回指向堆棧幀上的局部變量的指針,該變量在函數返回時不再有效。 它現在起作用僅僅是一次意外。 一旦調用另一個函數,堆棧空間將被重用,破壞緩沖區內容。 當您從C#調用此代碼時,保證會發生這種情況,P / Invoke marshaller實現將覆蓋堆棧幀並破壞緩沖區。

更糟糕的是,P / Invoke marshaller將嘗試釋放緩沖區。 它將假設緩沖區由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();

從DLL返回一個chars數組,即緩沖區,它位於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];

你也可以澄清入口指針變量 - 是全局的嗎?

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

嘗試使用StringBuilder作為返回類型,並省略CharSet屬性:

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

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM