我试图在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
参数传递。