2011-03-14 27 views
5

我遇到了第三方C++ dll的內存泄漏問題。對於某些調用,dll爲字符串分配內存,將其作爲char *傳遞出去,然後希望將該指針接收回來,以便它可以取消分配內存。從C++接收char *到c#中,並再次將其傳回

以下是來自頭文件的一些註釋,一些char * get返回的示例以及「Release」方法的簽名。

(這個dll被稱爲SW_API,它來自一個交易結算所 - 如果任何人或許已經包裝了這個,我很樂意與他們交談!)。

/* Strings returned by the API are similarly normal nul-terminated C strings. 
    * The user should not attempt to change any of the bytes or read past the 
    * terminating nul of any returned string. All returned strings must be 
    * released using SW_ReleaseString() once the user is finished with the 
    * result. Failure to do this will result in memory leaks. 
    */ 

    /** 
    * @typedef const char* SW_XML 
    * @brief A string containing an XML documents text. 
    * @note As with all output strings, returned XML must be freed 
    * by the user. See @ref resource. 
    * @sa ErrorCodes 
    */ 
    typedef const char* SW_XML; 

    const char* STDAPICALLTYPE SW_GetLastErrorSpecifics(); 

    SW_ErrCode STDAPICALLTYPE SW_DealGetSWML(SW_LoginID   lh, 
            const char*   swmlVersion, 
            SW_DealVersionHandle dealVersionHandle, 
            SW_XML*    resultXML_out); 


    void STDAPICALLTYPE SW_ReleaseString(const char* buffer); 

試圖從各種來源讀了,我已經試過如下:

// Extern declarations 
    [DllImport(sw_api_dll, EntryPoint = "[email protected]", CharSet = CharSet.Ansi)] 
    public static extern IntPtr SW_GetLastErrorSpecifics(); 

    [DllImport(sw_api_dll, EntryPoint = "[email protected]", CharSet = CharSet.Ansi)] 
    public static extern int SW_DealGetSWML(int lh, string swmlVersion, string dealVersionHandle, [Out] out IntPtr outputSWML); 

    [DllImport(sw_api_dll, EntryPoint = "[email protected]", CharSet=CharSet.Ansi)] 
    public static extern void SW_ReleaseString(IntPtr buffer); 


    // Using the externs. 
    private static string GetIntPtrStringAndRelease(IntPtr ptr) 
    { 
     string result = Marshal.PtrToStringAnsi(ptr); 
     API.SW_ReleaseString(ptr); 
     return result; 
    } 

    public static int SW_DealGetSWML(int lh, string swmlVersion, string dealVersionHandle, ref string outputSWML) 
    { 
     IntPtr outputSWML_out = new IntPtr(); 
     int result = API.SW_DealGetSWML(lh, swmlVersion, dealVersionHandle, out outputSWML_out); 

     outputSWML = GetIntPtrStringAndRelease(outputSWML_out); 

     return result; 
    } 

    public static string SW_GetLastErrorSpecifics() 
    { 
     IntPtr ptr = API.SW_GetLastErrorSpecifics(); 
     return GetIntPtrStringAndRelease(ptr); 
    } 

看來我只是不能得到API釋放繩線。

現在,這可能只是API中的一個錯誤,但我對此表示懷疑。 更可能是我做了一些錯誤的事情。

我所知道的是,我的工作組只是不斷增長。

有問題的公司提供Java包裝,但不會延伸到.Net包裝。

任何幫助最感激地收到。

Brett。

+0

這看起來像API中的一個bug。如果你回來的數據(即從'GetIntPtrStringAndRelease'返回的值是好的),那麼這應該工作。 – 2011-03-14 22:26:55

+0

'GetIntPtrStringAndRelease'對我來說看起來不錯。 – 2011-03-14 22:32:19

+0

我回來的價值很好。我幾乎希望它不是! – Brett 2011-03-15 19:03:40

回答

2

我最好的猜測是IntPtr不等於你的字符串的char *。所以當你調用SW_ReleaseString時,你並沒有提供相同的指針。

你能做什麼,就是把一個小小的C++ CLI中介放在一起。在C++ CLI中,您將可以直接訪問char*,並且可以使用Marshal :: PtrToString和託管字符串指針,並且可以使用String^

這就是我認爲這將是這樣的:

C++/CLI:

String^ GetStringAndRelease(char* ptr) 
{ 
    string result = Marshal::PtrToStringAnsi(ptr); 
    SW_ReleaseString(ptr); 
    return result; 
} 

int SW_DealGetSWML(int lh, const char* swmlVersion, const char* dealVersionHandle, String% outputSWML) 
{ 
    char* outputSWML_out; 
    int result = SW_DealGetSWML(lh, swmlVersion, dealVersionHandle, outputSWML_out); 

    outputSWML = GetStringAndRelease(outputSWML_out); 

    return result; 
} 

String^ SW_GetLastErrorSpecifics() 
{ 
    char* ptr = SW_GetLastErrorSpecifics(); 
    return GetStringAndRelease(ptr); 
} 

,然後在C#:

[DllImport(your_wrapper_dll, EntryPoint = "[email protected]", CharSet = CharSet.Ansi)] 
public static extern int SW_DealGetSWML(int lh, string swmlVersion, string dealVersionHandle, [Out] out string outputSWML); 


[DllImport(your_wrapper_dll, EntryPoint = "[email protected]", CharSet = CharSet.Ansi)] 
public static extern string SW_GetLastErrorSpecifics(); 
+2

如果您製作C++/CLI DLL,則不需要DllImport。這是一個完整的.NET程序集,您可以像添加對外部C#程序集的引用一樣添加引用,但不需要DllImports。 (C#'ref string'會變成C++/CLI'String ^%',BTW。) – 2011-03-14 22:47:12

+0

太棒了,謝謝@David!我唯一接觸C++/CLI是C#和.NET之間的橋樑,這只是最近的曝光。 – Tim 2011-03-14 22:51:29

+0

當我做了類似的事情(很久以前大約.NET 1.1)時,我必須編寫違反標準C DLL的代碼。我發現編寫一個C++/COM +組件來充當包裝器最簡單,而不是試圖在C#中使用'DllImport'。一個C++/CLI DLL可能是要走的路。 – 2011-03-16 00:58:52

0

我是一個C#的傢伙,不是C++但是在我使用char *參數的非託管C++ DLL中,我將它們編組爲StringBuilders。我沒有讀過const char *的地方,最好的選擇是System.String,但StringBuilder是char *。但是,如果你需要保持指針,所以你可以發回它來釋放內存,也許StringBuilder會更好地工作,因爲System.String是不可變的?

+0

感謝您的答覆,@Joel。我嘗試了這個(很簡單),這個過程剛剛爆炸。儘管我實施它的方式可能有許多錯誤。當我有一點喘息的空間時,我會有另一個裂縫。 – Brett 2011-03-18 19:13:03

相關問題