Comme Hans Passantwishes voici le scénario du mien. J'ai une application en mode mixte dans laquelle le code natif fait tout le travail dur tout en respectant les performances et le code managé est responsable uniquement de l'interface graphique. Les utilisateurs participeront également en écrivant leur code C# propriétaire. J'ai C++ pour les classes natives, C# pour l'interface graphique et le code utilisateur et C++/Cli pour les classes wrapper entre. Parmi toutes mes classes C++, il y en a une qui fait% 90 des calculs et est créée un paramètre différent à chaque fois. Appelons-le NativeClass. Il y a apprx. 2000 instances de cette NativeClass et je dois trouver la bonne instance liée à un paramètre avant de faire le calcul. J'ai donc conçu une hash_map, avec les paramètres étant le code de hachage, à cette fin. Quand j'obtiens un paramètre, je cherche la bonne instance dans hash_map, je la trouve et appelle quelques unes de ses méthodes.
Lorsque les utilisateurs effectuent des calculs en écrivant du code C# et que cette classe exécute ces codes par des rappels. C'est trivial mais parfois j'ai besoin d'informations sur les classes .Net que les utilisateurs ont construites. J'ai donc besoin de rattacher cette ManagedClass spécifique à NativeClass d'une manière ou d'une autre. Ma première solution utilise GChandle.Alloc() et transfère l'adresse des handles. Mais il y a quelques concerns sur GC qu'il ne fera pas son travail correctement. Hans a recommandé Marshal.AllocCoTaskMem() et Marshal.StructureToPtr() pour allouer des objets gérés dans la mémoire non managée, mais je crois que cela est valide pour les classes de type de valeur ou les structures. Que diriez-vous des classes de ref? Comment puis-je transmettre une référence à NativeClass tout en empêchant la collecte du GC et le bon fonctionnement du GC en même temps?GCHandle, Maréchal, mémoire gérée et non gérée: Pour épingler ou ne pas épingler
Voici quelques exemples de code:
class NativeClass
{
private:
int AddressOfManagedHandle;
public:
static NativeClass * GetNativeClassFromHashMap(int SomeParameter)
{
// return NativeClass associated with SomeParameter from NativeClassHashMap;
}
NativeClass(int addr, int SomeParameter) : AddressOfManagedHandle(addr)
{
}
int GetAddress(){return AddressOfManagedHandle;}
void DoCalculation(){
// CALCULATIONS
}
};
public ref class ManagedClass : MarshalByRefObject
{
private:
NativeClass* _nc;
//GCHandle handle;
void FreeManagedClass()
{
Marshal::FreeHGlobal(IntPtr(_nc->GetAddress()));
//if(handle.IsAllocated)
//handle.Free();
delete _nc;
}
public:
ManagedClass()
{
IntPtr addr = (Marshal::AllocHGlobal(Marshal::Sizeof(this))); // Error
Marshal::StructureToPtr(this,addr,true);
//handle = GCHandle.Alloc(this);
//IntPtr addr = handle.ToIntPtr();
_nc = new NativeClass(addr.ToInt32());
}
~ManagedClass() {FreeManagedClass();}
!ManagedClass() {FreeManagedClass();}
int GetAddress() {return _nc->GetAddress();};
static ManagedClass^ GetManagedClass(int SomeParameter)
{
int addr = NativeClass::GetNativeClassFromHashMap(SomeParameter)->GetAddress();
//Object^obj = GCHandle::FromIntPtr(IntPtr(addr)).Target;
Object^ obj = Marshal::PtrToStructure(IntPtr(addr), ManagedClass::typeid);
return dynamic_cast<ManagedClass^>(obj);
}
};
Je suis désolé qu'il est toooooo long et toujours pas claire.
Vous devez utiliser IntPtr plutôt qu'int pour stocker les pointeurs natifs. Sinon, votre code peut se bloquer sur Windows 64 bits. – Elmue
Vous ne devriez pas libérer de la mémoire dans une autre classe. Ecrivez un destructeur (finalizer) ~ NativeClass() qui appelle FreeHglobal(). – Elmue