我试图在C#应用程序中使用c dll中的函数,每次尝试运行应用程序并调用有问题的函数时,都会遇到此错误。
起初我以为这可能是因为我使用了错误的签名,但我试图使其尽可能简单但没有运气。
简而言之:
这是我对c dll的实际源代码:

#include <stdio.h>
#include <string.h>
extern "C"
{
    struct teststruct
    {
        char acharacter;
        int  anumber;
        char* astring;
        char  anarray[10];
        const char* conststring;
    };

    __declspec(dllexport) teststruct  TestDLL()
    {
        teststruct stc;
        stc.acharacter = 'A';
        stc.anumber = 10;
        strcpy(stc.anarray, "Test");
        stc.astring = "astring!";
        stc.conststring = "Crash?";

        return stc;
    }
}

这是C#计数器部分:
    [StructLayout(LayoutKind.Sequential)]
public struct teststruct
{
    public char acharacter;
    public  int anumber;
    [MarshalAs(UnmanagedType.LPStr)]
    public string astring;
    [MarshalAs(UnmanagedType.ByValArray, SizeConst = 10)]
    public char[] anarray;
    [MarshalAs(UnmanagedType.LPStr)]
    public string conststring;
}

namespace Tcp_connections_list
{

    public partial class Form1 : Form
    {

        [DllImport("simple c dll.dll",CallingConvention= CallingConvention.Cdecl)]
        public static extern teststruct TestDLL();

        public Form1()
        {
            InitializeComponent();
        }

        private void btnTestDll_Click(object sender, EventArgs e)
        {
            teststruct test = TestDLL(); //Crash at the very begining!
            textBox1.Text = test.acharacter.ToString();
            textBox1.Text = test.anarray.ToString();
            textBox1.Text = test.anumber.ToString();
            textBox1.Text = test.astring.ToString();
            textBox1.Text = test.conststring.ToString();


        }

    }
}

以下代码段给了我相同的确切错误,我将结构更改为
struct teststruct
{
    char acharacter;
    int  anumber;
};

它的C#等价于
[StructLayout(LayoutKind.Sequential)]
public struct teststruct
{
    public char acharacter;
    public  int anumber;
}

使它尽可能简单,但是我再次得到相同的确切错误!
我在这里想念什么?

最佳答案

问题在于以零结尾的C字符串的编码。您不能期望p / invoke marshaller处理函数返回值中的那些。该结构需要这样声明:

[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi)]
public struct teststruct
{
    public byte acharacter; // don't use C# char which is 2 bytes wide
    public int anumber;
    public IntPtr astring;
    [MarshalAs(UnmanagedType.ByValArray, SizeConst = 10)]
    public char[] anarray;
    public IntPtr conststring;
}

您需要使用Marshal.PtrToStringAnsi提取C字符串的内容。

作为更一般的建议,将大型结构作为函数返回值传递是一个坏主意。没有这样做的公认的ABI。不同的编译器以不同的方式处理此问题。更好的方法是在调用代码中分配该结构,然后传递其地址。像这样:
__declspec(dllexport) void TestDLL(teststruct *ts)
{
    ts->... = ...;
    ...
}

在C#方面:

[DllImport(...)]
public static extern void TestDLL(out teststruct ts);

实际上,如果您尝试使用的结构不能被整理为返回值,这不会令我感到惊讶。您确实应该将它作为out参数传递。

10-07 13:23
查看更多