Als Hans Passantwishes hier ist das Szenario von mir. Ich habe eine Anwendung im gemischten Modus, in der der native Code die ganze Arbeit unter Einhaltung der Performance erledigt und verwalteter Code nur für die GUI zuständig ist. Auch Benutzer werden teilnehmen, indem sie ihren proprietären C# -Code schreiben. Ich habe C++ für native Klassen, C# für GUI und Benutzercode und C++/Cli für Wrapper-Klassen dazwischen. Unter all meinen C++ - Klassen gibt es eine, die% 90 der Berechnungen durchführt und jedesmal einen anderen Parameter erzeugt. Nennen wir es NativeClass. Es gibt apprx. 2000 Instanzen dieser NativeClass und ich müssen die richtige Instanz in Bezug auf einige Parameter finden, bevor sie berechnet. Also habe ich eine Hash-Map entwickelt, deren Parameter der Hash-Code ist. Wenn ich einen Parameter erhalte, suche ich nach der richtigen Instanz in hash_map, finde sie und rufe einige ihrer Methoden auf.
Wenn Benutzer zu Berechnungen durch Schreiben von C# -Code und dieser Klasse beitragen, führen Sie diese Codes durch Rückrufe aus. Das ist trivial, aber manchmal brauche ich einige Informationen über die .NET-Klassen, die Benutzer erstellt haben. Also muss ich diese bestimmte ManagedClass irgendwie an NativeClass anhängen. Meine erste Lösung ist GChandle.Alloc() und Übertragung der Handles-Adresse. Aber es gibt einige concerns über GC, dass es seine Arbeit nicht richtig machen wird. Hans empfahl die Marshal.AllocCoTaskMem() und Marshal.StructureToPtr(), um verwaltete Objekte in nicht verwaltetem Speicher zuzuordnen, jedoch glaube ich, dass dies für Werttypklassen oder -strukturen gültig ist. Wie wäre es mit Ref-Klassen? Wie kann ich einen Verweis auf NativeClass übergeben, während verhindert wird, dass GC erfasst wird und GC gleichzeitig ordnungsgemäß funktioniert? HierGCHandle, Marshal, verwalteten und nicht verwalteten Speicher: Zu pinnen oder nicht zu pinnen
ist ein Beispielcode:
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);
}
};
Es tut mir leid, dass es toooooo lang ist und noch nicht klar.
Sie sollten IntPtr anstelle von int verwenden, um native Zeiger zu speichern. Andernfalls kann Ihr Code auf 64-Bit-Windows abstürzen. – Elmue
Sie sollten den Speicher in einer anderen Klasse nicht freigeben. Schreiben Sie einen Destruktor (Finalizer) ~ NativeClass(), der FreeHglobal() aufruft. – Elmue