views:

152

answers:

2

I'm having some problems calling a C function from a DLL, and was hoping someone could help me out. The function is returning -101 which translates as a "bad parameter". The values I am passing have been returned from another, successful function call, so my current assumption is that I've built the structure incorrectly. Any help is appreciated.

The function definition is:

int sm_switch_channel_input(struct sm_switch_channel_parms *switchp) 

Parameters
*switchp (a structure of the following type): 
typedef struct sm_switch_channel_parms {
     tSMChannelId channel;     /* in */
     tSM_INT st;      /* in */
     tSM_INT ts;      /* in */
     enum kSMTimeslotType type;    /* in */
} SM_SWITCH_CHANNEL_PARMS;

typedef struct tSMChannelId_struct *tSMChannelId;
typedef int tSM_INT;
enum kSMTimeslotType {
 kSMTimeslotTypeALaw,
 kSMTimeslotTypeMuLaw,
 kSMTimeslotTypeData,
};

And here is how I've defined & called it...

Enum kSMTimeslotType
    kSMTimeslotTypeALaw = 0
    kSMTimeslotTypeMuLaw = 1
    kSMTimeslotTypeData = 2
End Enum
Public Structure sm_switch_channel_input_params
    <MarshalAsAttribute(UnmanagedType.SysInt)> _
    Public channel As IntPtr
    <MarshalAsAttribute(UnmanagedType.I4)> _
    Public stream As Integer
    <MarshalAsAttribute(UnmanagedType.I4)> _
    Public timeslot As Integer
    <MarshalAsAttribute(UnmanagedType.U4)> _
    Public tsType As kSMTimeslotType
End Structure

<DllImport("TiNG.dll")> _
Private Shared Function sm_switch_channel_input_iPsCtiie1_3__(ByRef x As sm_switch_channel_input_params) As Integer
End Function

Dim sscip As sm_switch_channel_input_params
Dim err as Integer

sscip.channel = chanA
sscip.stream = streamA
sscip.timeslot = timeSlotA
sscip.tsType = kSMTimeslotType.kSMTimeslotTypeMuLaw
err = sm_switch_channel_input_iPsCtiie1_3__(sscip)
A: 

I think the SysInt attribute is what's causing your problem. It's not necessary in this case because IntPtr will always marshal correctly based on the current platform. You're also missing a StructLayout attribute

There are a couple of other attributes which are not necessary as well. I would try using the following definition

Enum kSMTimeslotType
    kSMTimeslotTypeALaw = 0
    kSMTimeslotTypeMuLaw = 1
    kSMTimeslotTypeData = 2
End Enum

<StructLayout(LayoutKind.Sequential)> _
Public Structure sm_switch_channel_input_params
    Public channel As IntPtr
    Public stream As Integer
    Public timeslot As Integer
    Public tsType As kSMTimeslotType
End Structure
JaredPar
`SysInt` is redundant here, but it shouldn't make it any worse: "SysInt A platform-dependent, signed integer. 4-bytes on 32 bit Windows, 8-bytes on 64 bit Windows.". Also, `StructLayout` is redundant (in both VB and C#), because structures get sequential layout by default even without it.
Pavel Minaev
@Pavel, SysInt is one of the few attributes that I've seen cause problems even in the case where it's redundant. I've run into several problems, typically in the area with delegates, where code runs fine without SysInt but fails with it. Not finished with my coffee yet so I'm struggling to recall the cases. Even so, removing the redundancy simplifies the problem a bit.
JaredPar
A: 

Judging by the name of the function in your VB code, it is a C++ function, and exported as such. Therefore, it doesn't use the "stdcall" calling convention (which P/Invoke assumes by default), but "thiscall" (which VC++ uses for all non-vararg C++ functions). So try this:

<DllImport("TiNG.dll", CallingConvention := CallingConvention.ThisCall)> _
Private Shared Function sm_switch_channel_input_iPsCtiie1_3__ ...

The more appropriate way to fix this would be to decorate the function in C code with extern "C" and __stdcall instead:

extern "C" {
    int __stdcall sm_switch_channel_input(struct sm_switch_channel_parms *switchp) 
    ...
}

Then your original P/Invoke declaration should work as is.

As a side note, all your MarshalAs attributes are redundant (they specify behavior which is already the default for types to which you apply it), so you can drop them altogether.

Pavel Minaev
Thanks for the tips about the superfluous MarshalAsAttribute statements... definitely saves me some future typing. Unfortunately when I changed the calling convention to ThisCall the function call caused a memory protection fault. I'm not sure why the functions are decorated in the DLL, as none of the other APIs this product provide behave this way.
lags
Have you tried the second option (`__stdcall` etc)?
Pavel Minaev