2014-10-10 20 views
0

我有以下結構中聲明(C++):整個C++/C#邊界管理非託管字符串的P/Invoke

struct NativeOperationResult { 
    const INTEROP_BOOL Success; // INTEROP_BOOL = char 
    const char16_t* const ErrorMessage; 

    NativeOperationResult(const NativeOperationResult& c); 
    /* various constructors, omitted for brevity */ 
}; 

現在,我有一個導出函數的定義在別處:

extern "C" __declspec(dllexport) NativeOperationResult ReturnFailureWithMessage() { 
    return { INTEROP_BOOL_FALSE, "Test" }; 
} 

我預計將通過P/Invoke從C#中調用ReturnFailureWithMessage(如果您想知道該測試方法)。在構造函數NativeOperationResult中,它需要「Test」的一個副本並將其放入ErrorMessage

NativeOperationResult擁有char16_t*的所有權,所以我需要在結構被銷燬時將其刪除。這沒有問題,但我不想在.NET CLR有機會將字符串複製到託管堆之前刪除內存。

坦率地說,我對刪除內存的位置有些模糊。我認爲C++編譯器會複製我的結構(或者只是移動它),然後CLR將使用該副本......這意味着我應該使用Marshal.FreeHGlobal從.NET中刪除本機內存。

這是正確的嗎?

+0

喜漢斯,感謝您的評論。我在C#端使用ICustomMarshaler作爲字符串。而且我已經用U1類型對bool進行了註釋。 – Xenoprimate 2014-10-10 14:42:14

回答

1

不,這是不正確的。您需要區分兩種情況:

1)您沒有在C++端進行任何分配。 這就是你現在談論的情況

2)你確實在C++端做了分配,你需要照顧重新分配。

因此回答你的問題:不,你的例子不需要任何「刪除」內存,因爲沒有人明確地分配內存。

第二種情況有點棘手。如果您在C++端使用new char16_t[blah]進行內存分配,則需要使用delete[] nativeOperationResult.ErrorMessage釋放內存。這不可能在C#端做。內存可以使用不同的分配器(如; malloc,new)分配,C#不知道如何處理這些指針。

您需要添加一個新標誌到NativeOperationResult,如DeletionRequired,並從非管理端輸出新功能:FreeNativeOperationResultIfNeeded(..)There is longer discussion here

用C++ strings可以避免所有這些無意義。他們神奇地工作,並且不需要刪除。

struct NativeOperationResult { 
    const INTEROP_BOOL Success; // INTEROP_BOOL = char 
    const string const ErrorMessage; 

    NativeOperationResult(const NativeOperationResult& c); 
    /* various constructors, omitted for brevity */ 
}; 
+0

注意:['std :: u16string'是'std :: string'的char16_t版本,'std :: u32string'是'char32_t'版本](http://en.cppreference.com/w/CPP /串/ basic_string的)。不確定C#是否具有與它們等效的功能。 – 2016-11-17 00:12:40

0

而不是返回NativeOperationResult,可以使其成爲一個out參數,並期望調用方法傳遞正確的內存量。這樣.Net可以分配內存,然後在完成pinvoke之後清理它。但是你必須找出一種方式來告知.Net預計分配的內存量。

的extern 「C」 __declspec(dllexport)的無效ReturnFailureWithMessage(NativeOperationResult *結果)