2009-12-07 7 views
0

Je rencontre des problèmes pour appeler une fonction C depuis une DLL et j'espérais que quelqu'un puisse m'aider. La fonction retourne -101 qui se traduit par un "mauvais paramètre". Les valeurs que je transmets ont été renvoyées à partir d'un autre appel de fonction réussi, donc mon hypothèse actuelle est que j'ai mal construit la structure. Toute aide est appréciée.Fonction C dans VB.NET

La définition de la fonction est:

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

Et voici comment je l'ai appelé & défini ...

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) 

Répondre

0

Je pense que l'attribut SysInt est ce qui cause votre problème. Ce n'est pas nécessaire dans ce cas car IntPtr sera toujours correctement marshal basé sur la plate-forme actuelle. Il vous manque également un attribut StructLayout

Il existe plusieurs autres attributs qui ne sont pas nécessaires. Je voudrais essayer d'utiliser la définition suivante

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 
+0

'SysInt' est redondant ici, mais cela ne devrait pas le rendre pire:" SysInt Entier dépendant de la plate-forme, signé, 4 octets sur Windows 32 bits, 8 octets sur Windows 64 bits ". De plus, 'StructLayout' est redondant (à la fois en VB et en C#), car les structures sont mises en page séquentiellement par défaut même sans elles. –

+0

@Pavel, SysInt est l'un des rares attributs que j'ai vu poser des problèmes, même dans le cas où il est redondant. J'ai rencontré plusieurs problèmes, généralement dans la zone avec des délégués, où le code fonctionne bien sans SysInt mais échoue avec. Pas encore fini avec mon café, donc j'ai du mal à me souvenir des cas. Même ainsi, la suppression de la redondance simplifie un peu le problème. – JaredPar

0

A en juger par le nom de la fonction dans votre code VB, il est une fonction C++, et exportés en tant que tel. Par conséquent, il n'utilise pas la convention d'appel "stdcall" (que P/Invoke assume par défaut), mais "thiscall" (que VC++ utilise pour toutes les fonctions C++ non vararg). Donc, essayez ceci:

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

La façon plus appropriée de résoudre ce problème serait de décorer la fonction dans le code C avec extern "C" et __stdcall à la place:

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

Ensuite, votre déclaration P/Invoke d'origine devrait travailler est. En remarque, tous vos attributs MarshalAs sont redondants (ils spécifient un comportement qui est déjà le comportement par défaut pour les types auxquels vous l'appliquez), vous pouvez donc les supprimer complètement.

+0

Merci pour les conseils sur les déclarations MarshalAsAttribute superflues ... certainement me sauve une frappe future. Malheureusement quand j'ai changé la convention d'appel à ThisCall l'appel de fonction a provoqué une faute de protection de mémoire. Je ne sais pas pourquoi les fonctions sont décorées dans la DLL, car aucune des autres API fournies par ce produit ne se comporte ainsi. – lags

+0

Avez-vous essayé la deuxième option ('__stdcall' etc.)? –