P/调用传递给 StringBuilder 的函数

发布于 2024-09-02 03:17:57 字数 679 浏览 11 评论 0原文

在 C# 文件中,我有一个

class Archiver {
    [DllImport("Archiver.dll")]
    public static extern void archive(string data, StringBuilder response);
}

字符串数据作为输入,StringBuilder 响应是函数写入内容的地方,

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

void archive(char * dataChr, char * outChr);

它接收 dataChr 中的字符串,然后

strcpy(outChr,"some big text");

从 C# i 执行 a称之为这样的东西:

string message = "some text here";
StringBuilder response = new StringBuilder(10000);
Archiver.archive(message,response);

这可行,但问题是,正如您可能看到的那样,我为 StringBuilder 大小赋予了一个值,但存档函数可能会返回一个比我给我的大小更大的文本字符串生成器。有办法解决这个问题吗?

in a C# file i have a

class Archiver {
    [DllImport("Archiver.dll")]
    public static extern void archive(string data, StringBuilder response);
}

string data is an input, and StringBuilder response is where the function writes something

the archive function prototype (written in C) looks like this:

void archive(char * dataChr, char * outChr);

and it receives a string in dataChr, and then does a

strcpy(outChr,"some big text");

from C# i call it something like this:

string message = "some text here";
StringBuilder response = new StringBuilder(10000);
Archiver.archive(message,response);

this works, but the problem, as you might see is that i give a value to the StringBuilder size, but the archive function might give back a (way) larger text than the size i've given to my StringBuilder. any way to fix this?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(5

地狱即天堂 2024-09-09 03:17:57

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

You need to write a function that tells you how big the StringBuilder needs to be, then call that function to initialize the StringBuilder.

仅冇旳回忆 2024-09-09 03:17:57

您是否控制archive 功能的实现?如果您这样做,那么您有几个选择。

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

2- 将缓冲区的大小传递给 archive 函数,以便填充缓冲区时不会超过缓冲区长度。

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

Do you control the implementation of the archive function? If you do then you have a few options.

1- Have the archive function allocate the buffer and return it to the caller. The down side is that the caller wil need to use the right function to free the buffer otherwise risk either memory leak and even corrupting the heap.

2- Pass the size of the buffer you have to the archive function so that it will not exceed the buffer length when filling the buffer.

3- If you can have a function that can return the required buffer size then you can use that. This is a common approach in the windows API, passing null as the buffer and a pointer to a DWORD which receives the required buffer size, which you can then allocate and make a second call passing the allocated buffer.

狼亦尘 2024-09-09 03:17:57

我会让非托管代码分配内存,然后让托管端通过 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);
}

您没有指定数据是否实际上是字符串,或者是否使用字符串缓冲区来保存不透明二进制数据。如果响应数据是以 null 结尾的字符串,那么您可以轻松使用 PtrToStringUniPtrToStringAnsi 来获取 string 而不是简单的数组

:非托管方面:

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);
}

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

I would have the unmanaged code allocate the memory, then let the managed side copy it into a managed array via an IntPtr and release the allocation.

You need to first make your unmanaged function return the size of it's output array:

void archive(char * dataChr, char * outChr, int length);

Then the managed side needs to get it as an 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);
}

You didn't specify if your data was actually a string or if you were using a stringbuffer to hold opaque binary data. If the response data is a null-terminated string then you can easily use PtrToStringUni or PtrToStringAnsi to get a string instead of a simple array:

On the unmanaged side:

void archive(char * dataChr, char * outChr);

On the managed side:

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);
}

NB: I didn't test any of this code, so there may be some small omissions or bugs...

浮云落日 2024-09-09 03:17:57

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

cr012062(query,filename)

然后我将只读取文件内容

File.ReadAllText(filename)

I had a very similar problem once, but I had the dll's source code, so I added a function that would dump a file, the new call looked like this:

cr012062(query,filename)

then I would just read the file contents

File.ReadAllText(filename)
猥︴琐丶欲为 2024-09-09 03:17:57

您不需要为响应指定大小。

You don't need to give the response a size.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文