Utilisation dll C/C++ en C#

Résolu
garcimor59 Messages postés 66 Date d'inscription mardi 18 juillet 2006 Statut Membre Dernière intervention 6 mars 2008 - 22 sept. 2006 à 10:09
Lutinore Messages postés 3246 Date d'inscription lundi 25 avril 2005 Statut Membre Dernière intervention 27 octobre 2012 - 28 sept. 2006 à 18:13
Bonjour tout le monde,

Bon voilà j'ai mon probleme :

J'ai une DLL faite en C/C++, et j'aimerais pouvoir faire appelle à des fonctions contenus dans cette DLL dans mon application C#. Mais comme je veux y faire reference Visual Studio 2003 me dit que ne s'agit pas d'une assembly valide......

Donc j'ai essayé de créer une bibliotheque de classe (.NET) C++ qui fait appelle à la DLL C/C++
pour ensuite utilisé cette bibliotheque dans mon application C#, pour cela j'ai inclus le.H que j'ai.

Mais le probleme c'est qu'il me fait une error LNK2001 symbol externe non reconnu....
J'ai essayé d'ajouter la DLL pareil il fait une erreur (mais pas la meme que celle cité en haut) là il me dit juste qu'il peut pas.

Bon pour m'aider un peu je vous donne plus d'info.

La dll je l'ai testé en C elle fonctionne bien. et j'ai aussi un  .h et un .lib.

Voila merci beaucoup.

++

18 réponses

cs_Bidou Messages postés 5487 Date d'inscription dimanche 4 août 2002 Statut Membre Dernière intervention 20 juin 2013 61
22 sept. 2006 à 10:46
Hello,
Allez, je donne aussi un petit lien pratique (discussion sur le forum)

<hr size="2" />VC# forever
3
Lutinore Messages postés 3246 Date d'inscription lundi 25 avril 2005 Statut Membre Dernière intervention 27 octobre 2012 41
26 sept. 2006 à 04:07
Salut, LPSECURITY_ATTRIBUTES est un pointeur sur une structure, tu dois réécrire la structure avec l'attribut StructLayout ( voir la doc sur PInvoke ) dans ton code en C# en respectant sa définition que tu peux trouver dans la MSDN ou dans le fichier Winbase.h du SDK Windows. Mais comme c'est un pointeur sur une structure il faudra la passer avec le mot clé ref ( là aussi voir la doc PInvoke ). Ou bien tu simules un pointeur NULL avec IntPtr.Zero. ( passer un uint comme dans l'exemple que tu as trouvé n'est pas la meilleure façon de faire ).

Les constantes sont définies dans les fichiers headers ( *.h ) du C/C++ que tu trouves dans le SDK Windows ou dans Visual Studio.

http://www.pinvoke.net/default.aspx/kernel32/CreateFile.html
3
Lutinore Messages postés 3246 Date d'inscription lundi 25 avril 2005 Statut Membre Dernière intervention 27 octobre 2012 41
28 sept. 2006 à 18:13
C'est quoi emission + 1 ? emission + 1 byte ou emission + sizeof( MESSAGE_EMI ) ?

Il y a quelque chose qui ne colle pas dans ta structure, 'option', 'reserve', 'taille' sont de type long en C ils devraient être des int en C#.
3
MorpionMx Messages postés 3466 Date d'inscription lundi 16 octobre 2000 Statut Membre Dernière intervention 30 octobre 2008 57
22 sept. 2006 à 10:17
Salut,

pour utiliser une dll en c/c++ non managé, en C#, il faut regarder du coté du p/invoke.
Je te laisse aller lire ce post

Au fait, on ne peut pas voir tes images, car elles sont en local, sur ton poste

Mx
MVP C# 
0

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

Posez votre question
garcimor59 Messages postés 66 Date d'inscription mardi 18 juillet 2006 Statut Membre Dernière intervention 6 mars 2008
22 sept. 2006 à 11:01
Oki merci beaucoup, je regarde ça.

Quelles images?
0
MorpionMx Messages postés 3466 Date d'inscription lundi 16 octobre 2000 Statut Membre Dernière intervention 30 octobre 2008 57
22 sept. 2006 à 11:03
Il y a 4 images qui ne s'affichent pas en dessous de ton "++". "moz-screenshot.jpg" , ...





Mx
MVP C#
 
0
garcimor59 Messages postés 66 Date d'inscription mardi 18 juillet 2006 Statut Membre Dernière intervention 6 mars 2008
22 sept. 2006 à 11:36
Lol bizarre moi je vois rien...
0
cs_Bidou Messages postés 5487 Date d'inscription dimanche 4 août 2002 Statut Membre Dernière intervention 20 juin 2013 61
22 sept. 2006 à 11:45
Chez toi les images s'affichent car elles sont sur ton disque, mais nous on les voit pas...

[file:///C:/DOCUME~1/assystem/LOCALS~1/Temp/moz-screenshot-3.jpg file:///C:/DOCUME~1/assystem/LOCALS~1/Temp/moz-screenshot-3.jpg]
[file:///C:/DOCUME~1/assystem/LOCALS~1/Temp/moz-screenshot.jpg file:///C:/DOCUME~1/assystem/LOCALS~1/Temp/moz-screenshot.jpg]

par exemple...
C'est ta signature qui n'est pas au point je pense !

<hr size="2" />VC# forever
0
garcimor59 Messages postés 66 Date d'inscription mardi 18 juillet 2006 Statut Membre Dernière intervention 6 mars 2008
22 sept. 2006 à 12:42
Lol mais je vois pas d'image chez moi, et j'ai pas voulu mettre d'image non plus!!

Mort de rire c'est quoi ce bug!!

bon sinon pour revenir à nos moutons : j'ai essayé la méthode indiquée dans les liens que vous m'avez donnés. Mais il me fait une erreur que je ne comprends pas : "Identificateur attendu, char est un mot clé :

[DllImport("toto.dll", CharSet=CharSet.Auto)]
public static extern long Emission (char* szNomPipeEmi, unsigned char* cBuffer)

Merci
0
garcimor59 Messages postés 66 Date d'inscription mardi 18 juillet 2006 Statut Membre Dernière intervention 6 mars 2008
22 sept. 2006 à 16:17
Re, bon pour les char etc... il faut utiliser le tableau de conversion de cette page :

http://www.microsoft.com/france/msdn/vcsharp/Utilisez-Pinvoke.mspx#docum_topic3

Et la page est tres bien en elle-meme pour inserer dll C/C++ en C#
0
Lutinore Messages postés 3246 Date d'inscription lundi 25 avril 2005 Statut Membre Dernière intervention 27 octobre 2012 41
23 sept. 2006 à 00:53
Salut,

"char*" c'est le type en C comme tu l'as compris il faut le convertir vers C#. Dans ton cas c'est String ou StringBuilder si le type est en entrée/sortie et l'attribut CharSet.Ansi.

( Tu pourrais utiliser directement le pointeur char même en C# )

Le tableau de conversion des types :



http://msdn.microsoft.com/library/fre/default.asp?url=/library/FRE/cpguide/html/cpconplatforminvokedatatypes.asp
0
garcimor59 Messages postés 66 Date d'inscription mardi 18 juillet 2006 Statut Membre Dernière intervention 6 mars 2008
25 sept. 2006 à 11:58
Bonjour tout le monde,

Alors voilà, je souhaite utilisé la fonction C++ CreateFile :
The [ lpFileName]</italique>,
DWORD[ dwDesiredAccess],
DWORD[ dwShareMode],
LPSECURITY_ATTRIBUTES[ lpSecurityAttributes],
DWORD[ dwCreationDisposition],
DWORD[ dwFlagsAndAttributes],
HANDLE[ hTemplateFile]
);

Donc pour cela j'utilise la méthode qu'on a vu plus haut avec le DLLIMPORT avec une
conversion de type grace au lien :
http://msdn.microsoft.com/library/fre/default.asp?url=/library/FRE/cpguide/html/cpconplatforminvokedatatypes.asp

Donc mon premiere probleme, c'est que LPSECURITY_ATTRIBUTES je ne sais pas en quoi le convertir.

Ensuite lors de l'appel de cette fonction à l'origine j'ai :

CreateFile(slotname, GENERIC_WRITE | GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);

Et bien sur il ne connait pas GENERIC_WRITE et autres...

Alors comment puis-je faire pour qu'il accepte ces constantes.

Merci beaucoup.
0
garcimor59 Messages postés 66 Date d'inscription mardi 18 juillet 2006 Statut Membre Dernière intervention 6 mars 2008
25 sept. 2006 à 12:06
Un lien interressant qui repond à la premiere partie de ma question :

http://msdn2.microsoft.com/fr-fr/library/2d9wy99d.aspx

Par contre je sais pas comment je peux avoir les valoirs des constantes, autrement dit comment puis-je savoir que :

const uint GENERIC_READ = 0x80000000;

Merci
0
garcimor59 Messages postés 66 Date d'inscription mardi 18 juillet 2006 Statut Membre Dernière intervention 6 mars 2008
26 sept. 2006 à 10:54
Excellent lien merci beaucoup.
0
garcimor59 Messages postés 66 Date d'inscription mardi 18 juillet 2006 Statut Membre Dernière intervention 6 mars 2008
26 sept. 2006 à 15:00
Bonjour,

J'ai encore quelques petits problemes.
Donc voilà j'utilise des fonctions contenus dans kernel32.dll. Donc grace à votre aide et DLLImport j'ai réussi à les implementés dans mon code C#.

J'utilise notamment la fonction WriteFile :




//Code C
// hfile : handle, m : structure MESSAGE_EMI
WriteFile(hfile, m, sizeof(MESSAGE_EMI), &NbWritten, NULL);

ma structure MESSAGE_EMI en C:
typedef struct //Buffer d'envoi compatible IPT
{
    char nomLiaison[15];
    char filler1;
    char nomMes[16];   
    long option;      
    float dvie;
    long reserve;
    long taille;
    char data[32000]; 
}MESSAGE_EMI;

Donc en C# j'ai donc :

[System.Runtime.InteropServices.DllImport("kernel32", SetLastError = true)]
static extern unsafe bool WriteFile
   (
       IntPtr hFile,
       string lpBuffer,
       int nNumberOfBytesToWrite,
       out uint lpNumberOfBytesWritten,
       int lpOverlapped
   );

lpBuffer est de type char * dans mon application C.
Donc en utilisant le tableau de conversion(lien que l'on ma donné) j'ai utilisé un string à la place.

De plus autre probleme, ma structure MESSAGE_EMI je la recrée en C# donc je n'utilise pas Struct_Layout
et j'ai mis des string pour remplacer les tableaux de caracteres.  (C'est peut-etre pas top).

J'ai également essayé avec un lpBuffer en char [], mais sans résultat non plus.

Autre chose à savoir, j'utilise WriteFile pour écrire dans une mailbox, et si je n'envoi pas la structure
MESSAGE_EMI comme defini plus haut le programme (independant) chargé d'envoyer les messages de la mailbox vers
les autres pc ne se declenche pas.

Merci par avance.

N'hésitez pas à me dire si je n'ai pas été clair.
0
garcimor59 Messages postés 66 Date d'inscription mardi 18 juillet 2006 Statut Membre Dernière intervention 6 mars 2008
26 sept. 2006 à 16:37
Re bonjour,

Bon j'ai des nouveaux éléments qui pourront peut-etre vous aider à m'aider (lol).

Aprés avoir fait environ un million de test à peu prés (lol), je pense qu'il faut que je passe en parametre de WriteFile
une chaine avec de  0 à 14 le nom de ma liaison en 15eme position filler1 etc...

Mais bon avec les string j'ai jamais la bonne taille puisque le nom de ma liaison ne fait pas forcement 15 caracteres.
Donc j'ai declaré nomLiaison et nomMessage et data comme des char []
Et dans mon constructeur je leur affecte une taille (ex : nomLiaison = new char [15])
Jusqu'ici tout va bien.

Mais lorsque j'essaie d'affecter une chaine à mes char[] je passe par un string et la fonction ToCharArray()

Mais en faisant des tests avant et aprés l'affectation je me rends compte qu'avant l'affectation nomLiaison fait bien 15,
mais aprés elle est plus petite (normal je met que 11 caractere dedans) cependant j'aimerais que l'espace alloué à nomLiaison
soit toujours de 15, ainsi lorsque je passe ma structure en parametre j'ai bien telle chose à telle position ....

Pour information, vu que dans ma fonction WriteFile lpBuffer est un char (ou un string) je concatene tout les éléments de ma structure
MESSAGE_EMI pour lui passé en tant que char[] (ou string).
Personne aurait une solution plus simple pour que je puisse passé tout les éléments de ma structure sans faire cette manip longue et
fastidieuse?? J'ai essayé avec un ToString mon élément MESSAGE_EMI instancié mais il m'affiche un truc qui a rien à voir.

Enfin voilà un grand merci dejà à ceux qui ont pris la peine de tout lire (lol) et un autre grand merci à ceux qui pourront m'aider.

Cordialement,

G
0
Lutinore Messages postés 3246 Date d'inscription lundi 25 avril 2005 Statut Membre Dernière intervention 27 octobre 2012 41
27 sept. 2006 à 08:28
La fonction WriteFile attend un tableau de bytes. Il est possible d'allouer de l'espace dans la mémore non managée et de passer un IntPtr à la place d'un pointeur void. ou de fixer un tableau en mémoire et de passer un pointeur.




Pour passer un tableau char de taille fixe dans une structure :


[ MarshalAs( UnmanagedType.ByValTStr, SizeConst = 32 ) ]
public String str;


regardes ici :



http://www.csharpfr.com/infomsg_Sous%20avec%20des%20DLLImport_747879.aspx?p=3
0
garcimor59 Messages postés 66 Date d'inscription mardi 18 juillet 2006 Statut Membre Dernière intervention 6 mars 2008
28 sept. 2006 à 17:24
Bonjour,

Pour m'aider à debugger pourriez-vous m'indiquer une méthode pour connaitre ce qui se trouve à l'emplacement i de ma structure.

Je m'explique plus clairement :

J'ai la structure suivante  :

[ StructLayout( LayoutKind.Sequential, CharSet=CharSet.Ansi)]
        public unsafe struct MESSAGE_EMI
        {
            [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 15)]
            public string nomLiaison;            //Nom liaison id fichier IPSecure
            public char filler1;
            [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 16)]
            public string nomMessage;            //Nom du message
            public short option;                //Option de stockage
            public Single dvie;
            public short reserve;
            public short taille;
            [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 32000)]
            public string data;
        }

Lors de mon appel à WriteFile je passe en parametre " ref emission" (avec emission de type MESSAGE_EMI bien sur)

donc en gros j'aimerais savoir ce que j'ai à emission+1.

A c'était mieux au bon vieux temps du C.

Merci
0
Rejoignez-nous