我正在尝试使用c dll中的函数,在c#应用程序中,每次我尝试运行应用程序并调用有问题的函数时,我都会遇到此错误。
起初我想也许这是因为我正在使用错误的签名,但我试图让它尽可能简单但没有运气。!
长话短说:
这是我实际的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;
}
尽可能简单,但我又得到了同样的错误! 我在这里缺少什么?
答案 0 :(得分:5)
问题是空终止的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
参数传递。