简体   繁体   中英

Method's type signature is not PInvoke compatible while calling DLL method

I have a DLL with interface

struct modeegPackage
{
    uint8_t     version;    // = 2
    uint8_t     count;      // packet counter. Increases by 1 each packet
    uint16_t    data[6];    // 10-bit sample (= 0 - 1023) in big endian (Motorola) format
    uint8_t     switches;   // State of PD5 to PD2, in bits 3 to 0
};

__declspec(dllexport) void __cdecl initSerial();

__declspec(dllexport) void __cdecl closeSerialPort();

__declspec(dllexport) struct modeegPackage __cdecl getPackage();

And C# adapter

class EEGCommunication
{
    [StructLayout(LayoutKind.Sequential)]
    public struct modeegPackage
    {

        /// unsigned char
        public byte version;

        /// unsigned char
        public byte count;

        /// unsigned int[6]
        [MarshalAs(UnmanagedType.ByValArray, SizeConst = 6, ArraySubType = UnmanagedType.U2)]
        public UInt16[] data;

        /// unsigned char
        public byte switches;
    }

    private const string DLL = "libneureader-lib.dll";

    [DllImport(DLL, EntryPoint = "_Z10initSerialv")]
    public static extern void InitSerial();

    [DllImport(DLL, EntryPoint = "_Z15closeSerialPortv")]
    internal static extern void CloseSerialPort();

    [DllImport(DLL, EntryPoint = "_Z10getPackagev", CallingConvention = CallingConvention.Cdecl)]
    public static extern modeegPackage GetPackage();
}

But when I'm trying to call GetPackage method, I receive an error Method's type signature is not PInvoke compatible.

What's wrong with my code?

UPDATE: Code updated

The answer marked as an "ANSWER" before mine is not really correct and it has been 1.5 years.

The reason the OP got that error is indeed just what the error description says, "Method's type signature is not PInvoke compatible"

When you have a C/C++ function such as the one declared below,

    __declspec(dllexport) struct modeegPackage __cdecl getPackage();

Since the function returns a value of struct which is bigger than any register can hold, GCC compiler will try to optimize it(Return Value Optimize), so the actual implementation looks like the following,

    __declspec(dllexport) void __cdecl getPackage(struct* modeegPackage);

So your P/Invoke declaration should be,

    [DllImport(DLL, EntryPoint = "_Z10getPackagev", CallingConvention = CallingConvention.Cdecl)]
    public static extern GetPackage(out modeegPackage);

I hope my answer help any other developers who may have similar issue in the future.

It is the array that is causing the problem. The pinvoke marshaller doesn't like dealing with it in the specific case of returning a structure by value as a function return value. It is in general troublesome, the way this is done is highly compiler dependent. With good odds that you'll have trouble since it sounds like you are using GCC. It is typically done by the caller allocating space for the return value on the stack and passing a pointer to it.

A crude but effective trick is to expand the array yourself, practical enough since it has only 6 elements. Substitute the array like this:

        /// unsigned int[6]
        public short data0;
        public short data1;
        //...
        public short data5;

Which will solve the exception. Whether you'll get the data correctly remains to be seen, if not then you may have to switch to MSVC.

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