Mémoire partagée entre une appli c# et une appli c++

Résolu
websinh Messages postés 25 Date d'inscription jeudi 9 septembre 2004 Statut Membre Dernière intervention 31 octobre 2012 - 16 sept. 2009 à 10:11
Lutinore Messages postés 3246 Date d'inscription lundi 25 avril 2005 Statut Membre Dernière intervention 27 octobre 2012 - 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

10 réponses

Lutinore Messages postés 3246 Date d'inscription lundi 25 avril 2005 Statut Membre Dernière intervention 27 octobre 2012 41
16 sept. 2009 à 15:19
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 ).
3
Lutinore Messages postés 3246 Date d'inscription lundi 25 avril 2005 Statut Membre Dernière intervention 27 octobre 2012 41
16 sept. 2009 à 11:31
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
0
websinh Messages postés 25 Date d'inscription jeudi 9 septembre 2004 Statut Membre Dernière intervention 31 octobre 2012
16 sept. 2009 à 11:47
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# ?
0
Lutinore Messages postés 3246 Date d'inscription lundi 25 avril 2005 Statut Membre Dernière intervention 27 octobre 2012 41
16 sept. 2009 à 12:58
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
0

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

Posez votre question
websinh Messages postés 25 Date d'inscription jeudi 9 septembre 2004 Statut Membre Dernière intervention 31 octobre 2012
16 sept. 2009 à 13:26
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 ?
0
Lutinore Messages postés 3246 Date d'inscription lundi 25 avril 2005 Statut Membre Dernière intervention 27 octobre 2012 41
16 sept. 2009 à 14:02
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#.
}
0
websinh Messages postés 25 Date d'inscription jeudi 9 septembre 2004 Statut Membre Dernière intervention 31 octobre 2012
16 sept. 2009 à 14:53
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# ?
0
websinh Messages postés 25 Date d'inscription jeudi 9 septembre 2004 Statut Membre Dernière intervention 31 octobre 2012
16 sept. 2009 à 15:39
Très bien, merci beaucoup à toi Lutinore, je vais chercher dans cette zone là.
0
websinh Messages postés 25 Date d'inscription jeudi 9 septembre 2004 Statut Membre Dernière intervention 31 octobre 2012
17 sept. 2009 à 14:59
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.
0
Lutinore Messages postés 3246 Date d'inscription lundi 25 avril 2005 Statut Membre Dernière intervention 27 octobre 2012 41
17 sept. 2009 à 19:15
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 .
0
Rejoignez-nous