There is a library a colleague of mine has made in C and I would like to call it from C#. I think it almost right but its getting an AccessViolationException when I call the 2nd method/function. I've tried a few different things:
- class instead of struct
- adding [MarshalAs(UnmanagedType.FunctionPtr)] to callbacks/delegates (this actually throws exception on first call instead of second)
- Removing [MarshalAs(UnmanagedType.LPStr)] for string in struct (this will then throw exception after second method on closing brace)
The code below for the C# side and the C header I'm using.
C:
#pragma once
#define MAX_FEATURE_LENGTH 30
#define HELPERDLL_API __declspec(dllimport)
struct HelperAttributes {
void(*SaveCallBack) ();
void(*ExitCallBack) ();
char* feature_name;
int attempt_limit;
int check_interval;
};
extern "C"
{
void HELPERDLL_API DoStartUp();
void HELPERDLL_API ReSpecify();
void HELPERDLL_API Initialise(HelperAttributes* attributes);
}
C#:
namespace test
{
public partial class Form1 : Form
{
public delegate void SaveCallBack();
public delegate void ExitCallBack();
public Form1()
{
InitializeComponent();
}
[StructLayout(LayoutKind.Sequential)]
public struct HelperAttributes
{
public SaveCallBack saveCallBack;
public ExitCallBack exitCallBack;
[MarshalAs(UnmanagedType.LPStr)]
public string feature_name;
public int attempt_limit;
public int check_interval;
};
[DllImport("testing.dll", CallingConvention = CallingConvention.Cdecl)]
public static extern int DoStartUp();
[DllImport("testing.dll", CallingConvention = CallingConvention.Cdecl)]
public static extern int ReSpecify();
[DllImport("testing.dll", CallingConvention = CallingConvention.Cdecl)]
public static extern int Initialise(
[In, MarshalAs(UnmanagedType.LPStruct)]
HelperAttributes attributes
);
private void button1_Click(object sender, EventArgs e)
{
HelperAttributes attributes = new HelperAttributes();
attributes.saveCallBack = saveCallBackDelegate;
attributes.exitCallBack = exitCallBackDelegate;
attributes.feature_name = "XXX";
attributes.attempt_limit = 10;
attributes.check_interval = 30;
Initialise(attributes);
DoStartUp();
}
public void saveCallBackDelegate()
{
this.textBox1.Text = "save callback made";
}
public void exitCallBackDelegate()
{
this.textBox1.Text = "exit callback made";
}
}
}