简体   繁体   中英

How do I handle a complex struct return type from a C DLL file within C#?

I've been trying to get a C library (DLL) working with some simple test code in C#. So far I've been able to import and use the simple functions just fine. The issue I'm having right now is that I don't know how to receive the complex struct return type from this imported function.

Here are the two function signatures:

C:

#define HID_API_EXPORT __declspec(dllexport)
#define HID_API_CALL

struct hid_device_info HID_API_EXPORT * HID_API_CALL hid_enumerate(unsigned short vendor_id, unsigned short product_id);

C#:

[DllImport("hidapi.dll")]
public static extern hid_device_info hid_enumerate(ushort vendor_id, ushort product_id);

And here are the two structs:

C:

struct hid_device_info {
    char *path;
    unsigned short vendor_id;
    unsigned short product_id;
    wchar_t *serial_number;
    unsigned short release_number;
    wchar_t *manufacturer_string;
    wchar_t *product_string;
    unsigned short usage_page;
    unsigned short usage;
    int interface_number;

    struct hid_device_info *next;
};

C#:

[StructLayout(LayoutKind.Sequential)]
public struct hid_device_info
{
    public IntPtr path;
    public ushort vendorid;
    public ushort productid;
    public IntPtr serialnumber;
    public ushort releasenumber;
    public IntPtr manufacturer;
    public IntPtr product;
    public ushort usagepage;
    public ushort usage;
    public int interfacenumber;

    public IntPtr next;
}

I'm currently getting this error when I run the program:

Managed Debugging Assistant 'PInvokeStackImbalance' has detected a problem in 'C:\\Users\\tajensen\\Documents\\hidapiCS\\hidapitest\\bin\\Debug\\hidapitest.vshost.exe'.

Additional information: A call to PInvoke function 'hidapiCS!hidapiCS.hidapi::hid_enumerate' has unbalanced the stack. This is likely because the managed PInvoke signature does not match the unmanaged target signature. Check that the calling convention and parameters of the PInvoke signature match the target unmanaged signature.

I've done a bit of digging and the only things I've been able to find describe how to receive return types of very simple structs (ie no pointers, and only basic types like ints and bools). I would really appreciate some additional insight on the issue, as I know where I want to be, but I don't know enough about this kind of code to dig deeper on my own.

Thanks in advance, Toms

Your structure looks good, baring any command line flags that change the packing of it.

Likely, it's because of this line

#define HID_API_CALL

This means you're using the default calling convention, which is generally __cdecl . So, change the P/Invoke definition to:

[DllImport("hidapi.dll", CallingConvention = CallingConvention.Cdecl)]
public static extern hid_device_info hid_enumerate(ushort vendor_id, ushort product_id);

So the rules for how to manage the stack on the C side are followed properly.

There is a tool named SWIG , a code generation tool, connects programs written in C and C++ with a variety of high-level programming languages like c#. It generates wrapper code for twenty three different target languages:

It's very powerful for these tasks, specially data type/pointer conversion and many others. It saves manual conversion.

Try to use this tool to generate C# code for your case and finally compiled Dll.

Download the binary from: http://prdownloads.sourceforge.net/swig/swigwin-3.0.10.zip .

For tutorial: http://www.swig.org/tutorial.html

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM