从c ++接收char*到c#,然后再将其传回

Bre*_*ett 5 c# c++ marshalling char

我有第三方c ++ dll的内存泄漏问题.对于某些调用,dll为字符串分配内存,将其作为char*传递出去,然后期望接收该指针,以便它可以取消分配内存.

以下是头文件中的一些注释,几个返回char*的示例,以及"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);
Run Code Online (Sandbox Code Playgroud)

试图从各种来源阅读,我尝试了以下内容:

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

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

    [DllImport(sw_api_dll, EntryPoint = "_SW_ReleaseString@4", 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);
    }
Run Code Online (Sandbox Code Playgroud)

看来我只是无法让API释放字符串.

现在,这可能只是API中的一个错误,但我对此表示怀疑.更可能的是我做了一些基本错误的事情.

我所知道的是,我的工作组不断发展.

有问题的公司提供了Java包装器,但不会延伸到.Net包装器.

最感激的任何帮助.

布雷特.

Tim*_*Tim 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);
}
Run Code Online (Sandbox Code Playgroud)

然后在 C# 中:

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


[DllImport(your_wrapper_dll, EntryPoint = "_SW_GetLastErrorSpecifics@0", CharSet = CharSet.Ansi)]
public static extern string SW_GetLastErrorSpecifics();
Run Code Online (Sandbox Code Playgroud)

  • 如果您正在制作 C++/CLI DLL,则不需要 DllImport。它是一个成熟的 .NET 程序集,您可以像添加对外部 C# 程序集的引用一样添加对它的引用,无需 DllImports。(顺便说一句,C# `ref string` 将变成 C++/CLI `String^%`。) (2认同)