Sous avec des DLLImport

Résolu
z_san Messages postés 80 Date d'inscription jeudi 2 février 2006 Statut Membre Dernière intervention 24 mai 2007 - 29 mai 2006 à 13:49
z_san Messages postés 80 Date d'inscription jeudi 2 février 2006 Statut Membre Dernière intervention 24 mai 2007 - 9 juin 2006 à 16:06
Voilà j'utilise une dll que j'ai développé en C, dans un programme C#.

Quand j'appel une fonction de la dll par DLLImport, au moment ou le programme passe sur l'appel de cette méthode, celà me génére une exception du type "Is not PInvoke compatible"

J'avoue en perdre mon latin, ai-je fait une fausse manip dans l'appel de la fonction

Merci

Z.

38 réponses

Lutinore Messages postés 3246 Date d'inscription lundi 25 avril 2005 Statut Membre Dernière intervention 27 octobre 2012 41
30 mai 2006 à 17:58
Je vois pas.. pourtant le marshaling par défaut c'est ANSI.

Ta fonction est bien de type WINAPI ou __stdcall ??


Faudrait tester avec une structure simplifiée au maximum :


 




[ StructLayout( LayoutKind.Sequential ) ]
public struct MyStruct
{
    public IntPtr text; // Juste une chaine passé en IntPtr pour tester.
}


// ..


string s = Marshal.PtrToStringAnsi( myStruct.text );
3
Lutinore Messages postés 3246 Date d'inscription lundi 25 avril 2005 Statut Membre Dernière intervention 27 octobre 2012 41
1 juin 2006 à 11:39
J'ai rien pour compiler du C/C++ sur ma machine, essaye ça si tu veux.. j'espère que ça marche :

// C


typedef struct _MYSTRUCT
{
 char text[ 256 ];
} MYSTRUCT;


void MyFunc( MYSTRUCT* pMyStruct )
{
 printf( "\nText: %s\n", pMyStruct->text );
 strcpy( pMyStruct->text, "Sortie" );
}


// C#


[ StructLayout( LayoutKind.Sequential, CharSet=CharSet.Ansi ) ]
public struct MyStruct

 [ MarshalAs( UnmanagedType.ByValTStr, SizeConst = 256 ) ]
 public String text;
}


[ DllImport( "..." ) ]
private static extern void MyFunc( ref MyStruct myStruct );


MyStrcut myStruct = new MyStrcut( );
myStruct.text = "Entree";
MyFunc( ref MyStruct );


Console.WriteLine( myStrcut.text ); // devrait afficher Sortie.
3
Lutinore Messages postés 3246 Date d'inscription lundi 25 avril 2005 Statut Membre Dernière intervention 27 octobre 2012 41
2 juin 2006 à 13:21
Elle est compliquée ta structure , ça devrait passer :

public enum Enum1 { }
public enum Enum2 { }


[ StructLayout( LayoutKind.Sequential, CharSet = CharSet.Ansi ) ]
public struct MyStruct
{
    [ MarshalAs( UnmanagedType.ByValTStr, SizeConst = 11 ) ]
    public string Name;
    public Enum1 E1;
    public Enum2 E2;
    [ MarshalAs( UnmanagedType.ByValArray, SizeConst = 3 ) ]
    public StructTrame[ ] Trames;
}


[ StructLayout( LayoutKind.Sequential, CharSet = CharSet.Ansi ) ]
public struct StructTrame
{
    [ MarshalAs( UnmanagedType.ByValTStr, SizeConst = 11 ) ]
    public string Trame;
    public bool OK;
}
3
Lutinore Messages postés 3246 Date d'inscription lundi 25 avril 2005 Statut Membre Dernière intervention 27 octobre 2012 41
8 juin 2006 à 19:44
Je viens de tester.. J'avais pas installé Dev-C++ depuis 2 ans au moins.

Ca marche parfaitement !!

// CPP



typedef struct _STRUCTTRAME
{
    bool OK;
    char Trame[15];
}STRUCTTRAME;



typedef struct _MYSTRUCT
{
    char nom[11];
    int listeCle;
    int listeEtat;
    int listeDefaut;
    STRUCTTRAME Trames[4];
}MYSTRUCT;



DLLIMPORT void Fill( MYSTRUCT* p )
{
          if ( p != NULL )
          {
           // ..
          }
}



// C#



[ DllImport( "...") ]
private  static extern void Fill( ref MyStruct m );



public enum Enum1 { }
public enum Enum2 { }
public enum Enum3 { }



[ StructLayout( LayoutKind.Sequential, CharSet = CharSet.Ansi ) ]
public struct MyStruct
{
    [ MarshalAs( UnmanagedType.ByValTStr, SizeConst = 11 ) ]
    public string Nom;
    public Enum1 Cle;
    public Enum2 Etat;
    public Enum3 Defaut;
    [ MarshalAs( UnmanagedType.ByValArray, SizeConst = 4 ) ]
    public StructTrame[ ] Trames;
}



[ StructLayout( LayoutKind.Sequential, CharSet = CharSet.Ansi ) ]
public struct StructTrame
{
    [ MarshalAs( UnmanagedType.U1 ) ]
    public bool OK;
    [ MarshalAs( UnmanagedType.ByValTStr, SizeConst = 15 ) ]
    public string Trame;
}


La seule différence avec ton code c'est que j'ai utilisé des int en C à la place des enums, mais ça doit passer de la même manière.

Donc fait attention ta struct en C doit être exactement agencé de la même manière en C#.

Tu n'utilise pas la #pragma pack, par hasard !?
3

Vous n’avez pas trouvé la réponse que vous recherchez ?

Posez votre question
MorpionMx Messages postés 3466 Date d'inscription lundi 16 octobre 2000 Statut Membre Dernière intervention 30 octobre 2008 57
29 mai 2006 à 14:02
Salut
Qu'est-ce qui n'est pas "PInvoke compatible" ? Un type dans la signature de ta Méthode ?
Il nous en faudrait un peu plus (Exception complete, signature de la méthode, declaration pInvoke, ...)

Mx
MVP C# 
0
z_san Messages postés 80 Date d'inscription jeudi 2 février 2006 Statut Membre Dernière intervention 24 mai 2007
29 mai 2006 à 14:35
oui c'est au niveau de la signature que celà coince,

Method's type signature is not PInvoke Compatible

Ma méthode retourne une structutre contenant des enums un bool et un char*

C'est quand j'utilise ce char* que celà me génére une exception

dans mon appli en C# je déclare une structlayout
de la même ossature que celle dans ma dll en c

j'utilise la méthode Importé par dllimport comme suit

struct = getStruct();

C'est une MarshallDirectiveException qui est levée.
0
Lutinore Messages postés 3246 Date d'inscription lundi 25 avril 2005 Statut Membre Dernière intervention 27 octobre 2012 41
29 mai 2006 à 15:23
Salut, comme Mx j'aimerais bien voir le prototype C et le prototype managé.. Si je comprends bien tu alloues une structure avec new dans ton code en C et tu la renvois avec return.. Dans ce cas c'est un IntPtr qu'il faut, et il faut aussi mettre en place un mécanisme pour libérer la mémoire non managée.
0
z_san Messages postés 80 Date d'inscription jeudi 2 février 2006 Statut Membre Dernière intervention 24 mai 2007
29 mai 2006 à 15:48
non je n'utilise aucun new dans ma mfc en c dans le .h jé déclare une

la première structure
typedef struct  _maStruct
{
       char* nom;
       enumDefaut def;
       enumEtat etat;
       _structLigne ligne;
}maStruct;

La deusième
typedef struct _structLigne
{
       char* text;
       bool ok;
}structLigne;

le prototype de ma méthode

typedef _maStruct (WINAPI *DLL_Function_GET_Struct(void));

puis dans mon .cpp principale ma méthode

_maStruct GET_Struct(void)
{
       _maStruct struct;
       // traitement sur ma structure
       return struct;
}

Dans mon .cs

je déclare mes structure

[StructLayout(LayoutKind.Sequential)]
public struct _maStruct
{
       public string nom;
       etc....
}

de même pour _structLigne

aprés :

[DllImport(@"..\..\..\release\MADLL.dll")]
public static extern _maStruct GET_Struct();

je l'utilise aprés comme suit :

private void button1_Click(object sender, EventArgs e)
{
        _maStruct struct;
       struct = GET_Struct();
       Console.Writeline(struct.nom);
}
 en rouge se qui génére l'exception

voilà

Z.
      
0
Lutinore Messages postés 3246 Date d'inscription lundi 25 avril 2005 Statut Membre Dernière intervention 27 octobre 2012 41
29 mai 2006 à 18:47
Je me demande tout simplement si c'est possible de marshaler une structure de cette manière, je ne suis jamais tombé sur ce cas de figure..
0
z_san Messages postés 80 Date d'inscription jeudi 2 février 2006 Statut Membre Dernière intervention 24 mai 2007
29 mai 2006 à 19:02
Apparement oui j'ai vu des exemples
0
z_san Messages postés 80 Date d'inscription jeudi 2 février 2006 Statut Membre Dernière intervention 24 mai 2007
30 mai 2006 à 14:45
Vous avez des idées pour me donner un coup de main

Z.
0
Lutinore Messages postés 3246 Date d'inscription lundi 25 avril 2005 Statut Membre Dernière intervention 27 octobre 2012 41
30 mai 2006 à 15:17
Renvois un pointeur sur ta structure, après c'est très simple à marshaler vers C#.
0
z_san Messages postés 80 Date d'inscription jeudi 2 février 2006 Statut Membre Dernière intervention 24 mai 2007
30 mai 2006 à 15:30
tu peux développer ?
0
Lutinore Messages postés 3246 Date d'inscription lundi 25 avril 2005 Statut Membre Dernière intervention 27 octobre 2012 41
30 mai 2006 à 15:34
Normalement je fais comme ça :


// v1.cpp


void DoSomething( MyStruct* p )
{
   if ( p != NULL )
   {
      p->x = 0;
      p->y = 1;
   }
}


// v1.cs


[ DllImport( ".." )]
static extern void DoSomething( ref MyStruct myStruct );


MyStruct myStruct = new MyStruct( );
DoSomething( ref myStruct );


Ou alors


// v2.cpp


MyStruct* DoSomething( )
{
   MyStruct* p = new MyStruct( );
   p->x = 0;
   p->y = 1;


   return p;
}


void Free( MyStruct* p )
{
   if ( p != NULL )
      delete p;
}


// v2.cs


[ DllImport( ".." ) ]
static extern IntPtr DoSomething( );


[ DllImport( ".." ) ]
static extern void Free( IntPtr ptr );


IntPtr ptr = DoSomething( );
MyStrcut myStruct = ( MyStruct )Marshal.PtrToStructure( ... ); // Ou du code unsafe


// ..


Free( ptr );


On peut aussi utiliser CoTaskMemAlloc et FreeCoTaskMem ce qui évite de définir une fonction Free.
0
z_san Messages postés 80 Date d'inscription jeudi 2 février 2006 Statut Membre Dernière intervention 24 mai 2007
30 mai 2006 à 16:37
J'ai toujours un souci de type qd je met un string j'ai toujours mon exception de levée, même si j'utilise ref,  aprés quand je modifie que je met un int àa passe mais me retourne une valeur de int qui n'est pas celle que je veux.
0
z_san Messages postés 80 Date d'inscription jeudi 2 février 2006 Statut Membre Dernière intervention 24 mai 2007
31 mai 2006 à 08:58
je vais tester ce matin mais je suis bien en WINAPI
0
z_san Messages postés 80 Date d'inscription jeudi 2 février 2006 Statut Membre Dernière intervention 24 mai 2007
31 mai 2006 à 13:57
ok mais comment se déclare ma structure du côté de mon .cpp
0
Lutinore Messages postés 3246 Date d'inscription lundi 25 avril 2005 Statut Membre Dernière intervention 27 octobre 2012 41
31 mai 2006 à 15:59
Le plus simple possible, juste avec un pointeur char* rien d'autre.

C'est pour voir si au moins ça marche comme ça sinon c'est a plus rien n'y comprendre :/
0
z_san Messages postés 80 Date d'inscription jeudi 2 février 2006 Statut Membre Dernière intervention 24 mai 2007
31 mai 2006 à 16:18
Effectivement ça change quelque chose j'ai plus l'exception mais ma chaine de retour dans ma strucuture(celle que je marshal en string) elle est vide j'essai de l'afficher mais rien vide de chez vide

je fais un

maStruct = GetStruct();

string s = Marshal.PtrToStringAnsi( myStruct.text );

Console.WriteLine(s);

mais myStruct.text est vide (0 pour être plus précis)
0
z_san Messages postés 80 Date d'inscription jeudi 2 février 2006 Statut Membre Dernière intervention 24 mai 2007
1 juin 2006 à 10:03
Bon je crois que ça marche merci encore à tous sympa de votre part une fois mon appli terminé je ferais un tuto sur tout ça
0
Rejoignez-nous