Anders
Anders

Reputation: 17554

DllIImport function throws stack exception

I trying to call the function getFirstAvailableTSSComPort in this h-file

http://sourceforge.net/p/yeicapi/code/11/tree/trunk/include/yei_threespace_api.h

Relevant structs and enums taken from h file (And converted to C# code)

private enum TSS_Type
{
    TSS_BTL = 0,
    TSS_USB = 1,
    TSS_DNG = 2,
    TSS_WL = 3, //wireless wired (connected to PC)
    TSS_WL_W = 4, //wireless wireless
    TSS_EM = 5,
    TSS_DL = 6,
    TSS_BT = 7,
    TSS_UNKNOWN = 8
}

[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi)]
private struct Comport
{
    [MarshalAs(UnmanagedType.LPStr, SizeConst = 64)]
    public string Port;
    [MarshalAs(UnmanagedType.LPStr, SizeConst = 256)]
    public string FriendlyName;
    public TSS_Type Type;
}

DllImport

[DllImport("ThreeSpace_API.dll")]
private static extern int getFirstAvailableTSSComPort([Out, MarshalAs(UnmanagedType.Struct)] out Comport port, int filter);

Calling

Comport port;
var error = getFirstAvailableTSSComPort(out port, 0);

I get

A call to PInvoke function 'YEi3!YEi3.Program::getFirstAvailableTSSComPort' 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.

Upvotes: 0

Views: 101

Answers (1)

David Heffernan
David Heffernan

Reputation: 612864

The C code uses the cdecl calling convention, but your C# code uses stdcall. That is the reason why you receive the p/invoke stack imbalance message.

Change the DllImport to specify the calling convention:

[DllImport("ThreeSpace_API.dll", CallingConvention=CallingConvention.Cdecl)]
private static extern int getFirstAvailableTSSComPort(
    out Comport port, 
    int filter
);

Note that the default marshalling for the parameters is sufficient.

This change will resolve the stack imbalance, but your code will still fail to work. That's because the struct is translated incorrectly. The inline strings needs to be marshalled as ByValTStr:

[StructLayoutAttribute(LayoutKind.Sequential, CharSet=CharSet.Ansi)]
public struct ComPort {
    [MarshalAsAttribute(UnmanagedType.ByValTStr, SizeConst=64)]
    public string com_port;
    [MarshalAsAttribute(UnmanagedType.ByValTStr, SizeConst=256)]
    public string friendly_name;
    public TSS_Type sensor_type;
}

Upvotes: 3

Related Questions