utilisation en C de fonctions écrites en C#

utilisation en C de fonctions écrites en C# - C#/.NET managed - Programmation

Marsh Posté le 09-04-2008 à 13:56:20    

bonjour,
 
Mon problème est le suivant : je dispose d'une dll écrite en C# avec le visual studio 2008 (code 'managé' avec net framework 3.5), et je souhaite utiliser les fonctions de cette dll ds un programme C++ standard (non managé).  
 
En guise d'exemple, ma dll ne contient actuellement qu'une seule fct :
 
public class Class1
{
  public static int functopo()
  {
    return 11;
  }
}
 
 
J'ai résolu un 1er problème : rendre les fcts exportées 'visibles' pour le code non managé; en gros cela consiste à générer le fichier .il (intermediate langage) à partir de la dll, y modifier quelques lignes puis regénérer la dll (pour + de détails : http://www.c-sharpcorner.com/Uploa [...] ged.aspx). Après cette manipulation, l'outil Dependency Walker me montre bien les fonctions exportées par la dll.
 
Ensuite je génère un fichier .def :
LIBRARY   DLLTOPO
EXPORTS
   functopo  
 
puis un fichier .lib (confer http://support.microsoft.com/kb/131313/en-us), et ds visual studio 2005 j'incorpore ce lib ds mon projet C++ ; le code appelant la fct de dll :
 
extern int functopo();
 
int APIENTRY WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR     lpCmdLine, int  nCmdShow)
{
  functopo();
  ...
}
 
--> erreur au linkage : error LNK2001: unresolved external symbol "int __cdecl functopo(void)" (?functopo@@YAHXZ)
 
Je sais que __cdecl est la 'calling convention' propre au C, et que en C# c'est la _stdcall convention qui est utilisée, mais à ce stade je suis bloqué.


Message édité par jpg16 le 11-04-2008 à 09:02:14
Reply

Marsh Posté le 09-04-2008 à 13:56:20   

Reply

Marsh Posté le 10-04-2008 à 08:47:55    

Tu devrais plutôt mettre :

extern "C" int functopo();


Si tu veux utiliser la même fonction que celle du .def.
Ca devrait déjà linker, tu rajouteras ensuite le _stdcall si tu ne veux pas que ca plante lors de l'exécution.
 
Remarque en supposant que ta dll soit correcte : vu qu'elle n'a pas de paramètre ca devrait marcher sans _stdcall même si ce n'est pas très propre.

Reply

Marsh Posté le 11-04-2008 à 08:38:21    

j'ai exposé mon problème ds un autre forum (experts-exchange), on m' a conseillé à peu près la même déclaration de fct :
 
extern "C" __declspec(dllimport) int functopo();  
 
çà fonctionne, mais effectivement les problèmes dès qu'on commence à passer des paramètres ; si je passe un int :
extern "C" __declspec(dllimport) int functopo(int x);  
 
l'appel de la fct provoque le msg suivant :
"The value of ESP was not properly saved across a function call. This is usually a result of calling a function declared with one calling convention with a function pointer declared with a different calling convention."
Néanmoins le code continue ensuite, et la valeur retournée est bien celle attendue.
 
Je ne vois pas comment rajouter le  _stdcall :
extern stdcall "C" int functopo(int x);  
provoque "error C2059: syntax error : 'string"

Reply

Marsh Posté le 11-04-2008 à 10:30:46    

Et avec un _ devant stdcall ca marche pas non plus ?

Reply

Marsh Posté le 11-04-2008 à 11:07:40    

erreur de frappe ds mon précédent message, mais en fait ds mon code j'avais bien mis  
extern _stdcall "C" int functopo(int x);

Reply

Marsh Posté le 11-04-2008 à 11:37:40    

Essaye plutôt :

extern "C" _stdcall int functopo(int x);

Reply

Marsh Posté le 11-04-2008 à 11:55:22    

j'avais essayé çà aussi, c'est pire ... :
 
Compiling...
warning C4518: 'int ' : storage-class or type specifier(s) unexpected here; ignored
warning C4230: anachronism used : modifiers/qualifiers interspersed, qualifier ignored
Linking...
error LNK2001: unresolved external symbol _functopo@4

Reply

Marsh Posté le 11-04-2008 à 13:19:45    

Autant pour moi je crois que c'est :

extern "C" int _stdcall functopo(int x);


 
Et tu dois modifier ton .def en rajoutant @4 après le nom de ta fonction (qui correspond au nombre d'octet en paramètre : int = 4 octets sur ta machine)

Reply

Marsh Posté le 11-04-2008 à 13:51:19    

comme çà, çà compile et çà linke, mais ne çà s'exécute pas : "le point d'entrée de procédure functopo@4 est introuvable dans la bibliothèque de liaisons dynamique dlltopo.dll"

Reply

Marsh Posté le 11-04-2008 à 15:02:41    

Ok je ne me souvient plus exactement de la syntaxe mais ca doit être entry=function@N donc en gros ton .def devrait ressembler à ca :

LIBRARY   DLLTOPO  
EXPORTS  
   functopo=functopo@4

Reply

Marsh Posté le 11-04-2008 à 15:02:41   

Reply

Marsh Posté le 11-04-2008 à 15:10:26    

merci pour ta persévérance ...  
mon .def était en effet différent de ce que tu proposes :
 
LIBRARY   DLLTOPO
EXPORTS
   functopo@4
 
là j'ai fini boulot, je teste çà lundi, encore merci

Reply

Marsh Posté le 14-04-2008 à 08:20:23    

test avec fichier .def corrigé (functopo=functopo@4) -->
Linking...
calltopo.obj : error LNK2001: unresolved external symbol _functopo@4

Reply

Marsh Posté le 14-04-2008 à 18:57:02    

Essaye ça :

LIBRARY   DLLTOPO  
EXPORTS  
   functopo=_functopo@4


 
Pour faire court :
- à gauche du "=" c'est ce que t'as dans ta dll.
- à droite c'est ce que ton compilateur te demande.
 
Si c'est la même chose pas besoin de "=".


Message édité par Tarabiscote le 14-04-2008 à 18:57:51
Reply

Marsh Posté le 15-04-2008 à 08:46:40    

--> même résultat : le linker ne connait pas _functopo@4

Reply

Marsh Posté le 15-04-2008 à 19:04:31    

Je disais ça de tête, c'est peut être dans l'autre sens (j'ai pas de quoi tester actuellement) :
 

LIBRARY   DLLTOPO    
EXPORTS    
   functopo@4=functopo


Reply

Marsh Posté le 16-04-2008 à 11:32:22    

idem (_functopo@4 inconnu) ...

Reply

Marsh Posté le 16-04-2008 à 23:01:51    

Bon j'ai vérifié sur des .def que j'avais et j'ai bien dans le style la :

LIBRARY   DLLTOPO  
EXPORTS  
   functopo@4


Mais je doit dire que j'avais utilisé gcc à l'époque, enfin comme tu disais qu'il n'y avait pas de problème de link, je ne suis pas sûr que le problème viens de là.
 
Sinon tu peux essayer en mettant l'ordinal de la fonction que tu peux voir avec depends (rajouter un espace et @N après le nom de la fonction).
Pour l'ordinal 1 ça donnerait quelque chose comme ça :

LIBRARY   DLLTOPO  
EXPORTS  
   functopo@4 @1


Si ça marche il faudrait voir pour fixer la valeur de l'ordinal quand tu crées la dll.

Reply

Marsh Posté le 17-04-2008 à 12:56:52    

Je me suis demandé si tu voulais me faire tourner en bourrique ... mais cette fois, en ajoutant l'ordinal de la fct de le .def,  çà passe complètement, j'ai une fonction qui transmet un entier et retourne un entier.  
Maintenant on peut passer aux choses sérieuses ... il faudrait que je passe une string , donc en C un tableau de char. Tu m'as déjà ôté une fameuse épine du pied, mais peut-être pourrai-je encore compter sur ton expérience.
 
Mes 1er essais :
 
En c# je reçois le paramètre en tant que tableau de byte (pas de char, sachant qu'en c# les char sont de l'unicode donc des double bytes); la fct suivante vérifie juste que je peux accèder aux différents char de ma string :
 
public static int functopo(byte[] s)
{
 int c = s[0];
 return c;
}
 
et en c :
extern "C" int _stdcall functopo(char * s);
 
int x = functopo("123456" );
 
Cà passe pour la lecture du 1er char : la fct retourne 49 (code ascii de "1" ).
 
Mais dès que j'essaye d'accéder aux caractères suivants ( int c = s[1] ds la fct c#), j'ai une "unhandled exception in calltopo.exe (KERNEL32.DLL: 0xE0434F4D: (no name)".
 
 

Reply

Marsh Posté le 17-04-2008 à 16:07:14    

bon quand j'ai trouvé un gourou je deviens paresseux ...
après un peu de recherche , je vois que je peux très bien utiliser des pointeurs en c# (code unsafe) -->
 
unsafe public static int functopo(byte* s)
et plus de problème pour accèder à tous les chars de ma string

Reply

Marsh Posté le 17-04-2008 à 17:00:19    

et pour conclure voici la manière de convertir le byte * en string du c# :
string str1 = System.Runtime.InteropServices.Marshal.PtrToStringAnsi(new IntPtr((int)s));

Reply

Sujets relatifs:

Leave a Replay

Make sure you enter the(*)required information where indicate.HTML code is not allowed