DLLImport

cs_RMI Messages postés 305 Date d'inscription vendredi 18 juillet 2003 Statut Membre Dernière intervention 2 août 2010 - 6 août 2007 à 15:59
cs_Corolle Messages postés 2 Date d'inscription vendredi 9 février 2007 Statut Membre Dernière intervention 13 août 2007 - 13 août 2007 à 19:52
Bonjour,

J'utilise une dll écrite en C++ et je n'arrive pas à exporter les fonction contenant des variables ayant pour type string
exp:
dans le .H
bool MvaSensor::setCalibPath, (, string , newpath,  ) 

Voilà ce que l'on voit avec Dependency Walker
bool MvaSensor::setCalibPath(class std::basic_string<char,struct std::char_traits<char>,class std::allocator<char> >)
et en non décorée
?setCalibPath@MvaSensor@@QAE_NV?$basic_string@DU?$char_traits@D@std@@V?$allocator@D@2@@std@@@Z

J'ai essayé
[
DllImport(DLL_NAME, EntryPoint "?setCalibPath@MvaSensor@@QAE_NV?$basic_string@DU?$char_traits@D@std@@V?$allocator@D@2@@std@@@Z",CharSet
CharSet.Ansi, CallingConvention =
CallingConvention.ThisCall)]

private
static
extern
bool SetCalibPath(
IntPtr _iPtr,
string _sCalibPath);
mais j'ai l'erreur
System.Acces.Violation
Tentative de lecture ou d'écriture de mémoire protégée. Cela indique souvent qu'une autre mémoire est endommagée.

J'ai aussi essayé avec un StringBuilder mais j'ai toujours le même problème.

Quelqu'un sait-il comment exporter cette !! de fonction ?

Merci par avance.

Théo

18 réponses

Lutinore Messages postés 3246 Date d'inscription lundi 25 avril 2005 Statut Membre Dernière intervention 27 octobre 2012 41
6 août 2007 à 21:07
Salut,

Le type string n'existe pas en C/C++ ton prototype utilise un template, c'est l'équivalent des génériques en C#, tu ne pourras pas marshaller le paramêtre en string ou en StringBuilder.

Je ne sais pas comment appeller cette fonction, j'ai jamais été confronté à ce genre de problème.. et je ne maîtrise pas les templates. La convention ThisCall est utile quand tu appeles la fonction d'une classe non-managée mais faut-il encore possèder un pointeur sur cette classe.

EntryPoint peut indiquer le numéro de la fonction c'est plus simple parfois que les noms décorés.
0
cs_RMI Messages postés 305 Date d'inscription vendredi 18 juillet 2003 Statut Membre Dernière intervention 2 août 2010 2
7 août 2007 à 08:21
Salut,

Merci de ta réponse, mais je reste sur ma faim... (J'ai un pointeur sur la classe et donc j'utilise ThisCall)

Théo
0
ctx_man Messages postés 285 Date d'inscription mardi 28 décembre 2004 Statut Membre Dernière intervention 20 janvier 2013 3
7 août 2007 à 09:30
Salut !
Je n'ai jamais eu ce genre de problèmes à résoudre et je ne peux donc pas t'indiquer ton erreur avec certitude.
Cependant, tu as écrit :
dans le .H
bool MvaSensor::setCalibPath(string newpath)

Ce qui semble indiquer que ta fonction setCalibPath n'est pas statique et fait partie d'un objet qu'il te faudra instancier.

Donc, selon moi, tu devrais tenter d'instancier un objet de la classe MvaSensor, et d'utiliser la méthode associée.

Je n'en suis pas certain non plus, mais utiliser du code non managé dans du code managé n'est permis que dans un contexte unsafe. Tu devras probablement effecuer ce changement de contexte.


Le travail c'est la santé, ne rien faire c'est la préservé !!!
0
ctx_man Messages postés 285 Date d'inscription mardi 28 décembre 2004 Statut Membre Dernière intervention 20 janvier 2013 3
7 août 2007 à 09:33
Arff, Opéra est vraiment mal prit en compte sur ce site. C'est la misère d'écrire une réponse sans faire des erreurs dans la mise en forme.

(Dites les admins ? vous pourriez pas au moins agrandir la texbox ? Parce que la, elle est toute petite, c'est trop la lutte de structurer son HTML la dedans)


Le travail c'est la santé, ne rien faire c'est la préservé !!!
0

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

Posez votre question
cs_RMI Messages postés 305 Date d'inscription vendredi 18 juillet 2003 Statut Membre Dernière intervention 2 août 2010 2
7 août 2007 à 09:38
Non, il n'y a pas de problème de contexte. sdt::string est un type spécifique à C++ et je ne sais pas le marshaller
Merci quand même

PS : t'as une fôte d'ortograf dans c'est la préservé (préserver)

Théo
0
ctx_man Messages postés 285 Date d'inscription mardi 28 décembre 2004 Statut Membre Dernière intervention 20 janvier 2013 3
7 août 2007 à 10:06
Lol ouais ! Je sais que j'ai une faute d'orthographe ! Mais je l'aime m'a faute ! Bon d'accord je corrige :'(

Concernant le contexte je suis pas sur de t'avoir compris mais c'est pas un drame.

Et qu'en est-il de ma remarque sur l'instanciation d'un objet MvaSensor ? Encore une fois, je ne fait que lancer des idées, je n'ai jamais été confronté à ce genre de problème.


Le travail c'est la santé, ne rien faire c'est la préserver !!!
0
leprov Messages postés 1160 Date d'inscription vendredi 23 juillet 2004 Statut Membre Dernière intervention 21 octobre 2010 17
7 août 2007 à 10:11
théoriquement, si cest générique, ca ne lest que dans le header et le .lib, je crois(une fois compilé et linké, on a une version de la méthode par type utilisé).
En bref, si tu connais le type dans lequel ton generic est instancié réellement lors de ton appel, cest ce type que tu dois marshaller. Au pire si tu n'y arrive pas, fait une dll C++ dans laquelle tu wrap cet objet, afin de t'éviter la généricité....C'est pas super propre, mais avec un marshalling générique, bon courage (d'ailleurs si meme lutinore seche sur un problème de DllImport, ou va le monde?) :D

Pour un programmeur en langage objet, la lutte des classes c'est tous les jours.
0
cs_RMI Messages postés 305 Date d'inscription vendredi 18 juillet 2003 Statut Membre Dernière intervention 2 août 2010 2
7 août 2007 à 10:21
Je ne connais rien au C++ et faire un wrapper je te dis pas l'ambiance....
Pour l'instant je pleure et j'implore aussi le fourniseur de ma dll de me donner des fonctions avec des appels avec des types courrants.

Théo
0
leprov Messages postés 1160 Date d'inscription vendredi 23 juillet 2004 Statut Membre Dernière intervention 21 octobre 2010 17
7 août 2007 à 10:41
faire un wrapper ca veut juste dire écrire une fonction qui appelle la fonction qui tembete, mais avec une signature différente (comprendre "qui t'arrange").

En bref, tu crée une dll en C++ qui exporte une classe qui exporte les méthode de MvaSensor en faisant un truc du type :

bool MvaSensor2::setCalibPath(string Param)
{
    m_MvaSensor.SetCalibPath((std_string<T1, T2>)Param);
}

La tas une classe MvaSensor2 qui est dite classe wrapper de MvaSensor car elle a un membre de type MvaSensor et exporte les traitements de MvaSensor mais de manière différente.
Evidemment faudra que tu remplace T1 et T2 par les bons types....et je sais pas si un cast est possible, faut ptetre faire des opérations plus compliqués, ca cest une question a poser sur un forum C++. En tous cas pour marshaller en C# je te conseille de partir sur un truc comme ca....
0
cs_RMI Messages postés 305 Date d'inscription vendredi 18 juillet 2003 Statut Membre Dernière intervention 2 août 2010 2
7 août 2007 à 10:48
Merci pour tes réponses, je vais essayer de gratter d'autres infos sur la toile avant de me lancer sur ce wrapper.

Théo
0
Lutinore Messages postés 3246 Date d'inscription lundi 25 avril 2005 Statut Membre Dernière intervention 27 octobre 2012 41
7 août 2007 à 15:48
Leprov > Merci pour la gentille remarque.

RMI > je suis en train de regarder à quoi correspond std:string en mémoire, ça semble  possible de le passer en tableau de byte, je te tiens au courant si je trouve.
0
Lutinore Messages postés 3246 Date d'inscription lundi 25 avril 2005 Statut Membre Dernière intervention 27 octobre 2012 41
7 août 2007 à 16:26
A tester..

[   DllImport(
    DLL_NAME,
    EntryPoint = "...",
    CallingConvention = CallingConvention.ThisCall )
]
[
    return: MarshalAs( UnmanagedType.U1 )
]
private static extern bool SetCalibPath( IntPtr ptr, IntPtr path );

-----


string path = "C:\\...";
IntPtr ptr = Marshal.StringToHGlobalAnsi( path );


SetCalibPath( iciTonPointeurSurMvaSensor, ptr );


Marshal.FreeHGlobal( ptr );
0
cs_RMI Messages postés 305 Date d'inscription vendredi 18 juillet 2003 Statut Membre Dernière intervention 2 août 2010 2
7 août 2007 à 16:46
Merci à tous pour votre participation, mais j'ai réussi a ce que mon fournisseur de dll change le type d'appel de std::string en char *

J'essaierai tout de même la solution de Lutinore, mais je ne comprends pas trés bien la syntaxe
[
    return: MarshalAs( UnmanagedType.U1 )
]
si tu pouvais m'expliquer celà STP

Théo
0
Lutinore Messages postés 3246 Date d'inscription lundi 25 avril 2005 Statut Membre Dernière intervention 27 octobre 2012 41
7 août 2007 à 17:13
Le type BOOL ( majuscule ) du C est sur 4 bytes, le type bool ( minuscule ) du C++ est sur 1 byte.. par défaut le marshaling C# est sur 4 bytes, donc là j'indique au marshaleur que mon type de retour ne fait que 1 byte.
0
cs_Corolle Messages postés 2 Date d'inscription vendredi 9 février 2007 Statut Membre Dernière intervention 13 août 2007
13 août 2007 à 01:42
Bonsoir,
J'ai eu le même problème (string à passer dans une dllimport), je l'ai réglé par un byte *, qui est homogère à du char * en c++ ANSI 8bits
ex:
[

DllImport(
"Vecad.dll")]

unsafe
private
static
extern
void CadGetFileName(
IntPtr hDwg,
byte *szFileName);

le unsafe ici est utile car il faut utiliser un pointeur pour récupérer szFileName

-Corolle
0
cs_RMI Messages postés 305 Date d'inscription vendredi 18 juillet 2003 Statut Membre Dernière intervention 2 août 2010 2
13 août 2007 à 08:25
Merci pour l'info Corolle !

Théo
0
Lutinore Messages postés 3246 Date d'inscription lundi 25 avril 2005 Statut Membre Dernière intervention 27 octobre 2012 41
13 août 2007 à 19:32
Il existe plusieurs façon de passer une chaine via DllImport, qu'elle soit ANSI sur 8 bits ou UNICODE sur 16 bits, inutile d'utiliser du code unsafe pour ça. 

Comme je l'ai dit plus haut vu qu'il est peut être possible que ça marche avec un tableau de bytes, ça peut marcher aussi avec un pointeur byte*, c'est pour ça que j'ai proposé un exemple avec Marshal.StringToHGlobalAnsi, ça fait la même chose en évitant le code unsafe.
0
cs_Corolle Messages postés 2 Date d'inscription vendredi 9 février 2007 Statut Membre Dernière intervention 13 août 2007
13 août 2007 à 19:52
J'ai découvert sur le net hier soir une solution très propre qui utilise les wrapper, en prime c'est très simple et très bien expliquée.
http://www.supinfo-projects.com/fr/2005/wrapper_dotnet_fr/
Bonne lecture,  ça vaut vraiment le détour, et en plus ça marche....
-Corolle
0
Rejoignez-nous