3

在 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# 我称之为这样的东西:

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

这可行,但问题是,正如您可能看到的那样,我为 StringBuilder 的大小赋值,但归档函数可能会返回比我给 StringBuilder 的大小更大的文本(方式)。有任何解决这个问题的方法吗?

4

5 回答 5

6

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

于 2010-05-21T17:34:21.050 回答
2

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

1-让archive函数分配缓冲区并将其返回给调用者。不利的一面是调用者将需要使用正确的函数来释放缓冲区,否则可能存在内存泄漏甚至破坏堆的风险。

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

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

于 2010-05-21T17:41:19.083 回答
2

我会让非托管代码分配内存,然后让托管端通过 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 结尾的字符串,那么您可以轻松地使用PtrToStringUniorPtrToStringAnsi来获取 astring而不是简单的数组:

在非托管方面:

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

注意:我没有测试任何这段代码,所以可能会有一些小的遗漏或错误......

于 2010-05-22T03:11:10.970 回答
0

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

cr012062(query,filename)

然后我就读文件内容

File.ReadAllText(filename)
于 2010-05-21T17:49:03.037 回答
-1

你不需要给响应一个大小。

于 2010-05-21T17:35:10.863 回答