【问题标题】:C function in VB.NETVB.NET 中的 C 函数
【发布时间】:2009-12-07 18:12:08
【问题描述】:

我在从 DLL 调用 C 函数时遇到了一些问题,希望有人能帮助我。该函数返回 -101,它转换为“错误参数”。我传递的值是从另一个成功的函数调用返回的,所以我目前的假设是我错误地构建了结构。任何帮助表示赞赏。

函数定义为:

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,
};

这就是我定义和称呼它的方式...

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)

【问题讨论】:

    标签: c vb.net interop marshalling


    【解决方案1】:

    我认为 SysInt 属性是导致您的问题的原因。在这种情况下没有必要,因为IntPtr 将始终根据当前平台正确编组。您还缺少 StructLayout 属性

    还有一些其他属性也不是必需的。我会尝试使用以下定义

    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
    

    【讨论】:

    • SysInt 在这里是多余的,但它不应该使情况变得更糟:“SysInt A platform-dependent, signed integer. 4-bytes on 32 bit Windows, 8-bytes on 64 bit Windows ."。此外,StructLayout 是多余的(在 VB 和 C# 中),因为即使没有它,结构也会默认获得顺序布局。
    • @Pavel,SysInt 是我见过的为数不多的导致问题的属性之一,即使在它是冗余的情况下也是如此。我遇到了几个问题,通常是在有代表的领域,没有 SysInt 的代码运行良好,但失败了。我的咖啡还没喝完,所以我很难回忆起这些案子。即便如此,去除冗余也稍微简化了问题。
    【解决方案2】:

    从您的 VB 代码中的函数名称来看,它是一个 C++ 函数,并按原样导出。因此,它不使用“stdcall”调用约定(P/Invoke 默认采用该约定),而是使用"thiscall"(VC++ 用于所有非可变参数 C++ 函数)。所以试试这个:

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

    解决这个问题的更合适的方法是在 C 代码中使用 extern "C"__stdcall 来装饰函数:

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

    那么您的原始 P/Invoke 声明应该可以正常工作。

    附带说明,您的所有 MarshalAs 属性都是多余的(它们指定的行为已经是您应用它的类型的默认行为),因此您可以完全删除它们。

    【讨论】:

    • 感谢您提供有关多余 MarshalAsAttribute 语句的提示...绝对为我节省了一些未来的打字时间。不幸的是,当我将调用约定更改为 ThisCall 时,函数调用导致内存保护错误。我不确定为什么在 DLL 中修饰这些函数,因为该产品提供的其他 API 都没有这样的行为。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-01-27
    • 1970-01-01
    • 1970-01-01
    • 2012-08-12
    • 1970-01-01
    • 2023-03-08
    相关资源
    最近更新 更多