C# P/调用传递给StringBuilder的函数

C# P/调用传递给StringBuilder的函数,c#,c,pinvoke,dllimport,stringbuilder,C#,C,Pinvoke,Dllimport,Stringbuilder,在C#文件中,我有一个 class Archiver { [DllImport("Archiver.dll")] public static extern void archive(string data, StringBuilder response); } 字符串数据是一个输入,StringBuilder响应是函数写入内容的地方 存档函数原型(用C编写)如下所示: void archive(char * dataChr, char * outChr); string me

在C#文件中,我有一个

class Archiver {
    [DllImport("Archiver.dll")]
    public static extern void archive(string data, StringBuilder response);
}
字符串数据是一个输入,StringBuilder响应是函数写入内容的地方

存档函数原型(用C编写)如下所示:

void archive(char * dataChr, char * outChr);
string message = "some text here";
StringBuilder response = new StringBuilder(10000);
Archiver.archive(message,response);
cr012062(query,filename)
它在dataChr中接收一个字符串,然后执行

strcpy(outChr,"some big text");
从C#我把它叫做这样的东西:

void archive(char * dataChr, char * outChr);
string message = "some text here";
StringBuilder response = new StringBuilder(10000);
Archiver.archive(message,response);
cr012062(query,filename)

这是可行的,但问题是,正如您可能看到的,我为StringBuilder大小指定了一个值,但存档函数返回的文本可能比我为StringBuilder指定的大小大很多。有没有办法解决这个问题?

您需要编写一个函数,告诉您
StringBuilder
需要有多大,然后调用该函数初始化
StringBuilder
您不需要给响应一个大小。

您控制
存档
函数的实现吗?如果你这样做了,那么你有几个选择

1-让
archive
函数分配缓冲区并将其返回给调用者。缺点是调用者需要使用正确的函数来释放缓冲区,否则可能会导致内存泄漏,甚至损坏堆

2-将所需的缓冲区大小传递给
存档
功能,以便在填充缓冲区时不会超过缓冲区长度


3-如果您可以使用一个函数返回所需的缓冲区大小,则可以使用该函数。这是windows API中的一种常见方法,将
null
作为缓冲区和指向接收所需缓冲区大小的DWORD的指针传递,然后您可以分配该缓冲区并通过分配的缓冲区进行第二次调用。

我曾经遇到过一个非常类似的问题,但我有dll的源代码,因此,我添加了一个转储文件的函数,新调用如下所示:

void archive(char * dataChr, char * outChr);
string message = "some text here";
StringBuilder response = new StringBuilder(10000);
Archiver.archive(message,response);
cr012062(query,filename)
然后我会读文件内容

File.ReadAllText(filename)

我会让非托管代码分配内存,然后让托管端通过IntPtr将其复制到托管阵列中并释放分配

您需要首先使非托管函数返回其输出数组的大小:

void archive(char * dataChr, char * outChr, int length);
然后,托管端需要将其作为IntPtr获取:

class Archiver {
    public static byte[] Archive(string data) {
        IntPtr responsePtr = IntPtr.Zero;
        int length = 0;

        // Call the unmanaged function with our output params
        archive(data, responsePtr, length);

        byte[] responseArray;
        try {
            // Create an array for the response
            responseArray = new byte[length];
            // Copy from unmanaged into managed
            Marshal.Copy(responsePtr, responseArray, 0, length);
        } finally {
            // Free the unmanaged memory once copied
            Marshal.FreeHGlobal(responsePtr);
        }

        return responseArray;
    }

    [DllImport("Archiver.dll")]
    private static extern void archive(string data, [Out]IntPtr encoded, [Out]int length);
}

您没有指定您的数据实际上是字符串还是使用stringbuffer保存不透明的二进制数据。如果响应数据是以null结尾的字符串,则可以轻松使用
PtrToStringUni
PtrToStringAnsi
获取
字符串而不是简单数组:

在非托管端:

void archive(char * dataChr, char * outChr);
class Archiver {
    public static string Archive(string data) {
        IntPtr responsePtr = IntPtr.Zero;

        // Call the unmanaged function with our output params
        archive(data, responsePtr);

        string responseString;
        try {
            // Marshal the string from unmanaged SZ String
            responseString = Marshal.PtrToStringAnsi(responsePtr);
        } finally {
            // Free the unmanaged memory once copied
            Marshal.FreeHGlobal(responsePtr);
        }

        return responseString;
    }

    [DllImport("Archiver.dll")]
    private static extern void archive(string data, [Out]IntPtr encoded);
}
在管理方面:

void archive(char * dataChr, char * outChr);
class Archiver {
    public static string Archive(string data) {
        IntPtr responsePtr = IntPtr.Zero;

        // Call the unmanaged function with our output params
        archive(data, responsePtr);

        string responseString;
        try {
            // Marshal the string from unmanaged SZ String
            responseString = Marshal.PtrToStringAnsi(responsePtr);
        } finally {
            // Free the unmanaged memory once copied
            Marshal.FreeHGlobal(responsePtr);
        }

        return responseString;
    }

    [DllImport("Archiver.dll")]
    private static extern void archive(string data, [Out]IntPtr encoded);
}

注意:我没有测试任何代码,因此可能会有一些小的遗漏或错误…

我正在考虑先运行另一个函数,该函数将返回一个包含要放入stringbuilder的大小的int值(我想我在windows api函数中看到过这种做法),但这听起来不太好nice@SLaks:你为什么要这么做?它有一个无参数构造函数,创建一个空缓冲区,当缓冲区满时,缓冲区大小将自动增长。如果没有解释,您的注释将毫无帮助。@runraygun:不在非托管代码中@安德鲁:那是你唯一的选择。请参阅我的anwser。@runraygun:对于封送处理,
StringBuilder
只是一个编码感知字节数组。不可能有自动增长的原始数组。@Alex:Raj错了<代码>StringBuilder
在编组时的使用方式不同。我刚才正在考虑这个问题。也许是最好的办法。该死,你们真快@安得烈,你真的应该考虑把缓冲区的大小传递到存档函数中,这将有助于防止缓冲区溢出,存档应该只将缓冲区填充到缓冲区的大小。这是一个非常糟糕的解决方案。