Averius
Averius

Reputation: 175

typedef equivalent in C# to use C++ DLL

I'm trying to call a C++ structure, exported to a DLL, from C#-Code

This is the C++ interface to the Method I want to call:

typedef void *Handle;
typedef void (*Callback)(Info *info);
typedef void (*Timeout)(Info *info);

typedef struct {
    WORD port;
    WORD flag;
    char name[16];
} Info;

__declspec(dllexport) Handle open(Info *info, Callback c,
                           Timeout timeout);

This article teached me how to declare the info-struct in C#:

[StructLayout(LayoutKind.Explicit,
    Pack=1,Size=36)]
public struct Info
{
    [FieldOffset(0)]
        public ushort port;
    [FieldOffset(2)]
        public ushort flag;
    [FieldOffset(4)]
        public char name;
}

Then I would import the Method in C#:

[DllImport ("MyDLL")] private static extern void Handle open(Info
*info, Callback c, Timeout timeout);

Then I'm stucked, because I don't know how to transfer the typedefs of Handle, Callback and Timeout to C#. Any suggestions?

Upvotes: 0

Views: 2675

Answers (2)

xanatos
xanatos

Reputation: 111890

It is quite complex... Try this... It will probably go boom but then you can tell me how it did go boom and I can help you:

public class MyDllhelper
{
    [StructLayout(LayoutKind.Sequential)]
    public unsafe struct Info
    {
        public ushort port;
        public ushort flag;
        public fixed byte name[16];

        public unsafe string Name
        {
            get
            {
                fixed (byte* ptr = name)
                {
                    IntPtr ptr2 = (IntPtr)ptr;
                    return Marshal.PtrToStringAnsi(ptr2, 16).TrimEnd('\0');
                }
            }

            set
            {
                fixed (byte* ptr = name)
                {
                    IntPtr ptr2 = (IntPtr)ptr;

                    byte[] bytes = Encoding.Default.GetBytes(value);
                    int length = Math.Min(15, bytes.Length);
                    Marshal.Copy(bytes, 0, ptr2, length);
                    ptr[length] = 0;
                }
            }
        }
    }

    public VoidRefInfoDelegate C { get; set; }
    public VoidRefInfoDelegate Timeout { get; set; }

    [UnmanagedFunctionPointer(CallingConvention.Cdecl)]
    public delegate void VoidRefInfoDelegate(ref Info info);

    [DllImport("MyDLL", CallingConvention = CallingConvention.Cdecl)]
    private static extern IntPtr open(ref Info info, VoidRefInfoDelegate c, VoidRefInfoDelegate timeout);

    public IntPtr Open(ref Info info, VoidRefInfoDelegate c, VoidRefInfoDelegate timeout)
    {
        C = c;
        Timeout = timeout;
        return open(ref info, C, Timeout);
    }
}

Note that you'll have to do something like:

public void CMethod(ref MyDllhelper.Info info)
{
    Console.WriteLine("C method called");
}

public void TimeoutMethod(ref MyDllhelper.Info info)
{
    Console.WriteLine("Timeout method called");
}

var info = new MyDllhelper.Info();
info.Name = "012345678901234567890"; // Use Name, not name!
info.flag = 1;
info.port = 2;

var helper = new MyDllhelper();
IntPtr handle = helper.Open(ref info, CMethod, TimeoutMethod); // Use Open, not open!

You will need to compile the code with the Properties->Build->Allow unsafe code.

There are two or three interesting points in the code: the C array has been converted to a fixed byte array. I've added a getter/setter Name to handle the conversion from Ansi/ASCII to Unicode and back.

The C function has two callback methods (c and timeout). To use them, you need to "save" somewhere C#-side the delegates you'll use, because otherwise the garbage collector will free the delegates, and you'll receive an exception (see for example https://stackoverflow.com/a/6193914/613130). The C and Timeout properties are used for this.

Upvotes: 2

Richard Schwartz
Richard Schwartz

Reputation: 14628

Those typedefs are for callback functions that will be called from the open(..) method that you are calling. Each of those callback functions is going to take a *Info argument. See answers for calling C++ functions containing callbacks in C# for some examples of how those functions are declared. Of course, you're going to need to do more than just declare them; you're going to have to write the code for doing the work in those functions, too.

Upvotes: 0

Related Questions