Mémoire partagée entre une appli c# et une appli c++ [Résolu]

websinh 25 Messages postés jeudi 9 septembre 2004Date d'inscription 31 octobre 2012 Dernière intervention - 16 sept. 2009 à 10:11 - Dernière réponse : Lutinore 3248 Messages postés lundi 25 avril 2005Date d'inscription 27 octobre 2012 Dernière intervention
- 17 sept. 2009 à 19:15
Bonjour à tous,

Je travaille dans le secteur de l'automation et je développe la partie IHM. Actuellement, mon IHM est un projet Borland C++ Builder 6 et je souhaiterait la passer en projet visual c#.
J'ai décidé de refaire l'ensemble de l'application pour apprendre à utiliser l'environnement c#, mais voilà, je n'arrive pas à reproduire certaines fonctions.

Celles qui me posent un énorme problème est la gestion d'une mémoire partagée. En effet, sous Borland, j'utilisais un fichier .h contenant une strucutre, que je mappais pour être utilisée dans mon application. Je dois pouvoir faire la même chose, avec ce même fichier .h, mais en c#. La partie PLC est encore codée en c++ et je n'y ai pas du tout accès.

J'arpente google et les différents sites dédiés à c#, et je ne trouve que peu d'information sur le mapping en c# et surtout de manière très parsemée. J'ai trouvé quelques explications sur le DLLIMPORT pour me permettre d'utiliser les API WIN32, mais je ne sais pas exactement par où commencer, et surtout, comment faire pour que c# reconnaisse mon fichier .h comme une structure...

Voici le code c++ pour le mapping :


//Creation d'un fichier MAP
G_hFileMap = CreateFileMapping(INVALID_HANDLE_VALUE,0,PAGE_READWRITE,0,sizeof(SharedDataStruct),FileSharedMemoryTxt);
if ((G_hFileMap !NULL) && (GetLastError() ERROR_ALREADY_EXISTS))
{
//Si le fichier MAP est déjà créer on le détruit et on ouvre celui qui est déjà créer
CloseHandle(G_hFileMap);
G_hFileMap = NULL;

G_hDataShared = NULL;
G_hDataOpen = NULL;
G_hDataOpen = OpenFileMapping(FILE_MAP_ALL_ACCESS, false, FileSharedMemoryTxt);
if (G_hDataOpen != NULL)
{
G_hDataShared = MapViewOfFile(G_hDataOpen, FILE_MAP_ALL_ACCESS, 0, 0, 0);
if (G_hDataShared != NULL)
SharedDataPtr = (SharedDataStruct*)G_hDataShared;
else
Application->MessageBox("Error MapViewOfFile","",MB_OK);
}
else
Application->MessageBox("Error OpenFileMapping","",MB_OK);
}
else
{
//---------- SHARED MEMORY: INITIALISATION SUR MASTER & SLAVE ----------
G_hDataShared = NULL;
G_hDataOpen = NULL;
G_hDataOpen = OpenFileMapping(FILE_MAP_ALL_ACCESS, false, FileSharedMemoryTxt);
if (G_hDataOpen != NULL)
{
G_hDataShared = MapViewOfFile(G_hFileMap, FILE_MAP_ALL_ACCESS, 0, 0, 0);
if (G_hDataShared != NULL)
SharedDataPtr = (SharedDataStruct*)G_hDataShared;
else
Application->MessageBox("Error MapViewOfFile","",MB_OK);
}
else
Application->MessageBox("Error OpenFileMapping","",MB_OK);
}

Est-ce que vous auriez une idée ? une direction oû chercher ?

Merci à tous et meilleures salutations
Afficher la suite 

Votre réponse

10 réponses

Meilleure réponse
Lutinore 3248 Messages postés lundi 25 avril 2005Date d'inscription 27 octobre 2012 Dernière intervention - 16 sept. 2009 à 15:19
3
Merci
Je ne code pas en C++/CLI mais je sais que plusieurs modes sont disponibles pour le compiltateur CLI dont un mode qui permet de mixer le code natif et managé.

Oui c'est possible de créer une classe managée qui sera accessible en C# comme n'importe qu'elle autre classe .NET mais qui contiendra du code natif, ce qui évite de réécrire le header.

Cela dit, si une fonction managée doit passer ou recevoir des arguments vers ou depuis une fonction native, on retombe dans le même problème et il faudra plus ou moins convertir les types, le mecanisme ne sera plus P/Invoke ( DllImport .. ) mais quelque chose d'un peu plus intuitif ( quoi que ), anciennement appéllé IJW ( It just Works ).

Merci Lutinore 3

Avec quelques mots c'est encore mieux Ajouter un commentaire

Codes Sources a aidé 98 internautes ce mois-ci

Commenter la réponse de Lutinore
Lutinore 3248 Messages postés lundi 25 avril 2005Date d'inscription 27 octobre 2012 Dernière intervention - 16 sept. 2009 à 11:31
0
Merci
Salut, toutes les APIs en flat C sont utilisables en C#, c'est vrai aussi pour les APIs en C++ mais souvent ça nécessite de possèder le code source.

Il faut réécrire le header .h coté C#, les fonctions sont definies avec l'attribut DllImport et les structures avec l'attribut StructLayout. Dans ces définitions il faut remplacer les types C++ par les types C# correspondants, de même taille, et faire attention au passage par valeur et par référence.

Tout est là :

http://msdn.microsoft.com/fr-fr/library/sd10k43k.aspx
Commenter la réponse de Lutinore
websinh 25 Messages postés jeudi 9 septembre 2004Date d'inscription 31 octobre 2012 Dernière intervention - 16 sept. 2009 à 11:47
0
Merci
Hello Lutinore,

Merci beaucoup pour ta réponse rapide. J'ai consulter le site que tu m'as linké, mais je ne pense pas avoir compris. Pour faire simple, imaginons que j'ai un fichier nommé mastruct.h qui vient d'une application c++ avec le contenu suivante :

#ifndef mastruct
#define mastruct

const AnsiString SharedMemoryVersion = "3.13";

enum TState {Stopped 0, Closed 0};

struct SharedDataStruct
{
bool RecipeIsInvalide;
TState DoorState;
}

#endif // PlanarSharedMemoryDef

En réalité, ce fichierest bien plus volumineux et change assez fréquemment (il m'est donc impossible de le réécrire à chaque fois). Est-ce qu'il y a moyen d'instancier directement ce fichier comme si il s'agissait d'une classe c# ?
Commenter la réponse de websinh
Lutinore 3248 Messages postés lundi 25 avril 2005Date d'inscription 27 octobre 2012 Dernière intervention - 16 sept. 2009 à 12:58
0
Merci
Absolument pas, tu peux te contenter de réécrire seulement les définitions utiles et non pas l'intégralité du header.

Seul le C++/CLI peut mixer du code natif et du code managé mais attention au claquage de cerveau lol
Commenter la réponse de Lutinore
websinh 25 Messages postés jeudi 9 septembre 2004Date d'inscription 31 octobre 2012 Dernière intervention - 16 sept. 2009 à 13:26
0
Merci
Merci Lutinore,

Est-ce que tu aurais un petit exemple simple me permettant de réécrire une définition utile ?
Par exemple pour récupérer la structure SharedDataStruct ?
Commenter la réponse de websinh
Lutinore 3248 Messages postés lundi 25 avril 2005Date d'inscription 27 octobre 2012 Dernière intervention - 16 sept. 2009 à 14:02
0
Merci
public enum TState{ Stopped = 0, Closed = 0 };

[ StructLayout( LayoutKind.Sequential ) ]
public struct SharedDataStruct
{
// bool du C++ sur 1 byte et non BOOL Win32 sur 4 bytes.
[ MarshalAs( UnmanagedType.U1 ) ]
public bool RecipeIsInvalide;
public TState DoorState; // 32 bits en C#.
}
Commenter la réponse de Lutinore
websinh 25 Messages postés jeudi 9 septembre 2004Date d'inscription 31 octobre 2012 Dernière intervention - 16 sept. 2009 à 14:53
0
Merci
Encore une fois, merci beaucoup pour ton intervention.

Une dernière petite information pour la route, est-ce que je pourrais mixer un projet C++/CLI avec mon projet C# afin de palier à ce problème ?
Je pensais par exemple créer une DLL avec visual c++ express 2008 qui puisse implémenter une classe détenant la structure de mon fichier mastruct.h ... est-ce que cela serait possible, ou je tomberait encore dans la même problématique, c'est à dire utiliser du DLL IMPORT et StructLayout et redéfinir ma structure dans c# ?
Commenter la réponse de websinh
websinh 25 Messages postés jeudi 9 septembre 2004Date d'inscription 31 octobre 2012 Dernière intervention - 16 sept. 2009 à 15:39
0
Merci
Très bien, merci beaucoup à toi Lutinore, je vais chercher dans cette zone là.
Commenter la réponse de websinh
websinh 25 Messages postés jeudi 9 septembre 2004Date d'inscription 31 octobre 2012 Dernière intervention - 17 sept. 2009 à 14:59
0
Merci
Voici quelques nouvelles du front....

Alors j'ai créer un projet C++ Builder 2008 qui contient le fameux .h avec ma structure. Mise à part quelques petites adaptations dans les types, je peux donc accéder à ma mémoire partagée.
Cet application génère une DLL qui est compatible .net, et donc que je peux récupérer sous mon projet c#.

Le problème étant toujours le même... je ne sais pas comment faire autrement que d'utiliser du DllImport. Est-ce qu'il y a un autre moyen pour accéder directement les membres de la dll ? Ou est-ce que je dois les redéfinir dans mon projet c# (avec l'attribut StructLayout)... ce qui me ramènerait à la case départ.
Commenter la réponse de websinh
Lutinore 3248 Messages postés lundi 25 avril 2005Date d'inscription 27 octobre 2012 Dernière intervention - 17 sept. 2009 à 19:15
0
Merci
Il ne suffit pas de compiler du code natif dans une DLL .NET ce serait bien trop simble, j'ai parlé du mécanisme IJW.

En C++/CLI tu dois écrire une classe managée, dans cette classe tu pourras mixer le code natif et le code managé mais une fois compilé en DLL .NET le C# lui ne verra que les fonction managées de cette DLL, pas besoin de P/INVOKE.

Un exemple d'une classe native contenue dans une classe managée :

http://msdn.microsoft.com/fr-fr/library/ms235281.aspx

Mais bon, le CLI c'est bien compliqué même si j'ai parlé de cette solution je prefère de loin P/INVOKE .
Commenter la réponse de Lutinore

Vous n'êtes pas encore membre ?

inscrivez-vous, c'est gratuit et ça prend moins d'une minute !

Les membres obtiennent plus de réponses que les utilisateurs anonymes.

Le fait d'être membre vous permet d'avoir un suivi détaillé de vos demandes et codes sources.

Le fait d'être membre vous permet d'avoir des options supplémentaires.