2

I've boiled this down to a simple example. I am writing some interop code between C# and C, and I have the following very simple struct on the unmanaged side:

typedef struct {
    bool create_if_missing;
    fdb_custom_cmp_variable custom_cmp;
} fdb_kvs_config;

typedef int (*fdb_custom_cmp_variable)(void *a, size_t len_a,
                                   void *b, size_t len_b);

So I've created this on the managed side:

public struct fdb_kvs_config
{
    [MarshalAs(UnmanagedType.I1)]
    public bool create_if_missing;

    [MarshalAs(UnmanagedType.FunctionPtr)]
    public IntPtr custom_cmp;
}

I want to use this unmanaged function

extern __declspec(dllexport)
fdb_kvs_config fdb_get_default_kvs_config(void);

And so I have this equivalent:

[DllImport("forestdb", CallingConvention=CallingConvention.Cdecl)]
public static extern fdb_kvs_config fdb_get_default_kvs_config();

However, this throws an exception:

An unhandled exception of type 'System.Runtime.InteropServices.MarshalDirectiveException' occurred in ForestDB.Test.exe

Additional information: Method's type signature is not PInvoke compatible.

Note: I've tried various MarshalAs combinations with no luck. Also note that I am only charged with the C# side of things, the C API is developed by someone else and I have no control over it.

If this simple signature is not P/Invoke compatible then what the heck is? For bonus points, why does it work on OS X in Mono?

Community
  • 1
  • 1
borrrden
  • 33,256
  • 8
  • 74
  • 109

1 Answers1

2

Well what do you know. Turns out MarshalAs was actually the problem, making the attribute almost useless on Windows. All of the members of the struct on the managed side need to be blittable types. This restriction apparently does not exist on Mono.

borrrden
  • 33,256
  • 8
  • 74
  • 109
  • I don't know your requirements and restrictions, but having tried both, I prefer to write a manged C++ wrapper instead of using pinvoke. – Taekahn Jul 11 '15 at 08:23