come Hans Passantwishes ecco lo scenario del mio. Ho un'applicazione in modalità mista in cui il codice nativo fa tutto il lavoro duro rispettando le prestazioni e il codice gestito è responsabile solo della GUI. Anche gli utenti parteciperanno scrivendo il loro codice C# proprietario. Ho C++ per le classi native, C# per la GUI e il codice utente e C++/Cli per le classi wrapper in mezzo. Tra tutte le mie classi C++ ce n'è una che fa% 90 dei calcoli e ogni volta viene creato un parametro diverso. Chiamiamolo NativeClass. Ci sono apprx. 2000 istanze di questo NativeClass e io dobbiamo trovare l'istanza giusta relativa ad alcuni parametri prima che faccia il calcolo. Quindi ho ideato una hash_map, con i parametri come codice hash, per questo scopo. Quando ottengo un parametro, cerco l'istanza giusta in hash_map, la trovo e richiamo alcuni dei suoi metodi.
Quando gli utenti eseguono il calcolo dei calcoli scrivendo il codice C# e questa classe esegue questi codici mediante richiamate. Questo è banale, ma a volte ho bisogno di alcune informazioni sulle classi .Net create dagli utenti. Quindi ho bisogno di collegare quella specifica ManagedClass a NativeClass in qualche modo. La mia prima soluzione è l'utilizzo di GChandle.Alloc() e il trasferimento dell'indirizzo dei manici. Ma ci sono alcuni concerns su GC che non farà il suo lavoro correttamente. Hans ha raccomandato Marshal.AllocCoTaskMem() e Marshal.StructureToPtr() per allocare oggetti gestiti nella memoria non gestita, tuttavia ritengo che questo sia valido per classi di tipi di valore o strutture. Che ne dici di lezioni di ref? Come posso passare un riferimento a NativeClass mentre impedisco loro di essere raccolti in GC e di far funzionare correttamente GC allo stesso tempo?GCHandle, maresciallo, memoria gestita e non gestita: pin o not to pin
Ecco alcuni esempi di codice:
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);
}
};
Mi dispiace che sia toooooo lungo e ancora non è chiaro.
È necessario utilizzare IntPtr anziché int per archiviare i puntatori nativi. Altrimenti il tuo codice potrebbe bloccarsi su Windows 64 bit. – Elmue
Non si dovrebbe liberare la memoria in un'altra classe. Scrivi un distruttore (finalizzatore) ~ NativeClass() che chiama FreeHglobal(). – Elmue