[gelöst]C#-Callback-function in C++/Cli

Programmiersprachen, APIs, Bibliotheken, Open Source Engines, Debugging, Quellcode Fehler und alles was mit praktischer Programmierung zu tun hat.
Benutzeravatar
xq
Establishment
Beiträge: 1581
Registriert: 07.10.2012, 14:56
Alter Benutzername: MasterQ32
Echter Name: Felix Queißner
Wohnort: Stuttgart & Region
Kontaktdaten:

Re: [gelöst]C#-Callback-function in C++/Cli

Beitrag von xq »

Managed-Klassen gehen nicht.

Was geht, findest du hier: Marshaling Classes, Structures, and Unions

Du kannst Structs zurückgeben, auch Arrays von Structs. Aber alles nur mit "call-by-value"
War mal MasterQ32, findet den Namen aber mittlerweile ziemlich albern…

Programmiert viel in ⚡️Zig⚡️ und nervt Leute damit.
joggel

Re: [gelöst]C#-Callback-function in C++/Cli

Beitrag von joggel »

MasterQ32 hat geschrieben:Managed-Klassen gehen nicht.
Noooooooo :(

Okay, ich schaue mal wie ich das löse. Danke!
Benutzeravatar
xq
Establishment
Beiträge: 1581
Registriert: 07.10.2012, 14:56
Alter Benutzername: MasterQ32
Echter Name: Felix Queißner
Wohnort: Stuttgart & Region
Kontaktdaten:

Re: [gelöst]C#-Callback-function in C++/Cli

Beitrag von xq »

Was hast du denn genau vor?
War mal MasterQ32, findet den Namen aber mittlerweile ziemlich albern…

Programmiert viel in ⚡️Zig⚡️ und nervt Leute damit.
joggel

Re: [gelöst]C#-Callback-function in C++/Cli

Beitrag von joggel »

Fällt mir schwer das jetzt auch so wiederzugeben. Aber ich versuche es mal...

Ich möchte ja Teile einer C++-Bibliothek, oder besser gesagt, ein paar Funktionalitäten nach C# portieren.
Um genauer zu sein, geht es um einen OPC-Client, der ganz simpel nur Variablen von einem OPC-Server lesen oder schreiben soll.
Es gibt dabei auch eine Funktionalität, bei dem der Server den Clienten benachrichtigt wenn sich eine Variable ändert, und zwar übergibt man der C++-Bibliothek dann eine bestimmte abgeleitete Klasse als "Callback-Klasse". Sobald sich die bestimmten Variablen auf dem OPC-Server ändern, wird die (überschrieben) Funktion der "Callback-Klasse" aufgerufen.
Nun dachte ich mir eben, ich schreibe mir so eine Callback-Klasse und implementiere in die Aufruffunktion so, dass sie meine C#-Funktion aufruft...also mit einem Funktionspointer.
Die Aufruffunktion hat folgende Signatur:

Code: Alles auswählen

MyCallbckClass::onItemChange(CAtlMap<COPCItem *, OPCItemData *>& changes)
{
// hier dann der C#-Funktionsaufruf mit den Änderungen
}
Ich hatte jetzt auch die Klasse COPCItem als managed Klasse gewrapped, und die OPCItemData auch.
Aber eigentlich sind die relevanten Information NUR in OPCItemData. Was ich eigentlich auch als struct kapseln kann, was ich bestimmt auch bei Gelegenheit machen werde...
Benutzeravatar
xq
Establishment
Beiträge: 1581
Registriert: 07.10.2012, 14:56
Alter Benutzername: MasterQ32
Echter Name: Felix Queißner
Wohnort: Stuttgart & Region
Kontaktdaten:

Re: [gelöst]C#-Callback-function in C++/Cli

Beitrag von xq »

Ja, in dem fall wirst du wohl eher IN der onImteChange einfach Managed Code verwenden, und das Array übersetzen. Das dürfte dir Stress sparen
War mal MasterQ32, findet den Namen aber mittlerweile ziemlich albern…

Programmiert viel in ⚡️Zig⚡️ und nervt Leute damit.
joggel

Re: [gelöst]C#-Callback-function in C++/Cli

Beitrag von joggel »

That's the plan...
joggel

Re: [gelöst]C#-Callback-function in C++/Cli

Beitrag von joggel »

Huhu,

ich muß noch mal das Thema rauskramen.

Ich bekomme es nämlich nicht hin :(

Mir kommt es so vor, als wird diese onItemChange-Funktion irgendwie nicht aufgerufen.

Habe ich das hier richtig gemacht?

Code: Alles auswählen

	[UnmanagedFunctionPointer(CallingConvention::Cdecl)]
	public delegate void CallbackFunc(array<OPCDAItemData^>^ args);
OPCDAItemData ist eine managed struktur.

HELP!!!
Benutzeravatar
xq
Establishment
Beiträge: 1581
Registriert: 07.10.2012, 14:56
Alter Benutzername: MasterQ32
Echter Name: Felix Queißner
Wohnort: Stuttgart & Region
Kontaktdaten:

Re: [gelöst]C#-Callback-function in C++/Cli

Beitrag von xq »

Könntest du mal ALLE relevanten Codestellen zu deinem Problem posten? Das würde einige Sachen massiv vereinfachen. Das oben ist ja irgendwie ein Mashup aus C# und C++/CLI, von daher ;)
War mal MasterQ32, findet den Namen aber mittlerweile ziemlich albern…

Programmiert viel in ⚡️Zig⚡️ und nervt Leute damit.
joggel

Re: [gelöst]C#-Callback-function in C++/Cli

Beitrag von joggel »

Jo, sorry.
Wollte ich gerade auch machen...aber du warst schneller.

Aaaaalso:
Hier in dieser Funktion scheint es immer einen Ausnahmefehler oder so zu geben.

Code: Alles auswählen

	void OnDataChange(COPCGroup &group, CAtlMap<COPCItem*, OPCItemData*> &changes)
	{
		array<OPCDAItemData^>^ arr = gcnew array<OPCDAItemData^>(changes.GetCount());
		POSITION pos;
		COPCItem* key;
		OPCItemData* value;
		pos = changes.GetStartPosition();

		int index(0);

		while ( pos != NULL )
		{
			key = changes.GetKeyAt(pos);
			value = changes.GetNextValue(pos);
			arr[index] = gcnew OPCDAItemData(value);
			++index;
		}

		mFunctionPtr(arr); // <= ich denke mal hier läuft irgend etwas schief. Wie der Name es schon sagt, ist das der Funktionspointer, dem ich das Array überegeb
}
Der Funktionspointer ist wie folgt deklariert:

Code: Alles auswählen

typedef void(*FunctionPointer)(array<OPCDAItemData^>^ arr);
Und hier ...(wie sagt man dazu?) die CallbackFunction-Deklaration

Code: Alles auswählen

	[UnmanagedFunctionPointer(CallingConvention::Cdecl)]
	public delegate void CallbackFunc(/*[MarshalAs(UnmanagedType::LPArray, SizeConst = 5)]*/ array<OPCDAItemData^>^ args);

So, ich habe jetzt erstmal Feierabend. Ich hoffe ich habe alles hier geschrieben.
Wünsch euch was :)
Benutzeravatar
xq
Establishment
Beiträge: 1581
Registriert: 07.10.2012, 14:56
Alter Benutzername: MasterQ32
Echter Name: Felix Queißner
Wohnort: Stuttgart & Region
Kontaktdaten:

Re: [gelöst]C#-Callback-function in C++/Cli

Beitrag von xq »

Zwei Sachen: Ist der Funktionspointer mFunctionPtr != nullptr und hast du deinen Delegaten, den du in den Funktionspointer marshalst, auch brav vom GC eingesammelt zu werden abgehalten (durch das Halten einer Referenz auf das Objekt)?
War mal MasterQ32, findet den Namen aber mittlerweile ziemlich albern…

Programmiert viel in ⚡️Zig⚡️ und nervt Leute damit.
joggel

Re: [gelöst]C#-Callback-function in C++/Cli

Beitrag von joggel »

Guten Morgen,

ob mFunctionPtr != nullptr ist, muß ich mal prüfen, denke aber schon das er nicht NULL ist.
und hast du deinen Delegaten, den du in den Funktionspointer marshalst, auch brav vom GC eingesammelt zu werden abgehalten (durch das Halten einer Referenz auf das Objekt)?
Denke habe ich auch. Mittels GC::KeepAlive(theCallback);

Hier mal der Code, also die Funktionsimplementation wo ich den Delegate überge

Code: Alles auswählen

void OPCDAGroup::enableAsynch(CallbackFunc^ theCallback)
{
	auto funcPtr = static_cast<FunctionPointer>(Marshal::GetFunctionPointerForDelegate(theCallback).ToPointer());

	if (mCallback == NULL)
	{
		mCallback = new MyCallBack();
		mCallback->setCallBack(funcPtr);
	}

	mGroup->enableAsynch(*mCallback);

	// Sorgt dafür, dass das Delegate nicht vorzeitig vom Garbage Collector eingesammelt wird
	GC::KeepAlive(theCallback);
}
Ich hoffe Du kannst das alles halbwegs nachvollziehen was ich hier schreibe; ist, glaube ich, alles ziemlich verwoben und so....
Vlt kann ich Dir ja auch mal das Projekt zuschicken oder so....natürlich nur, wenn du magst und ne freie minute hast...
joggel

Re: [gelöst]C#-Callback-function in C++/Cli

Beitrag von joggel »

Nachtrag:
Diese Fehlermeldung schmeißt mir VS um die Ohren. Kann ich aber wenig damit anfangen
Fehler.png
Weitere Meldung:
Weitere Informationen finden Sie unter: Die Laufzeit hat einen schwerwiegenden Fehler entdeckt. Fehleradresse: "0x7399020d" in Thread "0x3c0". Fehlercode: 0xc0000005. Bei diesem Fehler könnte es sich um ein Problem in der CLR oder in den unsicheren oder nicht verifizierbaren Teilen des Benutzercodes handeln. Übliche Ursachen dieses Bugs sind Marshallerfehler für COM-Interop oder PInvoke, die den Stapel beschädigen können.
Benutzeravatar
xq
Establishment
Beiträge: 1581
Registriert: 07.10.2012, 14:56
Alter Benutzername: MasterQ32
Echter Name: Felix Queißner
Wohnort: Stuttgart & Region
Kontaktdaten:

Re: [gelöst]C#-Callback-function in C++/Cli

Beitrag von xq »

GC::KeepAlive(...) tut nicht das, was du erwartest. Das verhindert nur die Garbage Collection bis zum Call der Funktion. Du musst den theCallback in einer Membervariable eines lebendigen Objektes zwischenspeichern, bis du den Callback nicht mehr benötigst.
War mal MasterQ32, findet den Namen aber mittlerweile ziemlich albern…

Programmiert viel in ⚡️Zig⚡️ und nervt Leute damit.
joggel

Re: [gelöst]C#-Callback-function in C++/Cli

Beitrag von joggel »

Achso. Okay, werd ich dann mal ausprobieren.
Ich sag bescheid, ob es geklappt hat.
Benutzeravatar
Krishty
Establishment
Beiträge: 8236
Registriert: 26.02.2009, 11:18
Benutzertext: state is the enemy
Kontaktdaten:

Re: [gelöst]C#-Callback-function in C++/Cli

Beitrag von Krishty »

Reicht das denn? Könnte der GC nicht auch den Speicher kompaktieren, während die Funktion ausgeführt wird, und sie dabei an einen neuen Ort verschieben? Ich jedenfalls musste sie explizit pinnen (siehe erste Antwort).
seziert Ace Combat, Driver, und S.T.A.L.K.E.R.   —   rendert Sterne
Benutzeravatar
xq
Establishment
Beiträge: 1581
Registriert: 07.10.2012, 14:56
Alter Benutzername: MasterQ32
Echter Name: Felix Queißner
Wohnort: Stuttgart & Region
Kontaktdaten:

Re: [gelöst]C#-Callback-function in C++/Cli

Beitrag von xq »

Das Problem ist mir noch nicht untergekommen, scheinbar ist dieser Fall abgedeckt.
War mal MasterQ32, findet den Namen aber mittlerweile ziemlich albern…

Programmiert viel in ⚡️Zig⚡️ und nervt Leute damit.
Benutzeravatar
Krishty
Establishment
Beiträge: 8236
Registriert: 26.02.2009, 11:18
Benutzertext: state is the enemy
Kontaktdaten:

Re: [gelöst]C#-Callback-function in C++/Cli

Beitrag von Krishty »

Du hast recht:
https://blogs.msdn.microsoft.com/cbrumme/2003/05/06/asynchronous-operations-pinning/ hat geschrieben:Clearly the unmanaged function pointer must refer to a fixed address. It would be a disaster if the GC were relocating that! This leads many applications to create a pinning handle for the delegate. This is completely unnecessary. The unmanaged function pointer actually refers to a native code stub that we dynamically generate to perform the transition & marshaling. This stub exists in fixed memory outside of the GC heap.
Dann verdränge ich den Gedanken mal ganz schnell wieder aus meinem Kopf, und aus meinem Code … :)
seziert Ace Combat, Driver, und S.T.A.L.K.E.R.   —   rendert Sterne
joggel

Re: [gelöst]C#-Callback-function in C++/Cli

Beitrag von joggel »

Ich habe gerade gesehen, dass ich das ja schon mache.

Code: Alles auswählen

        if (mCallback == NULL)
        {
                mCallback = new MyCallBack();
                mCallback->setCallBack(funcPtr); // <= hier übergebe ich ja den Funktionspointer der Klasse MyCallback.
        }
Benutzeravatar
xq
Establishment
Beiträge: 1581
Registriert: 07.10.2012, 14:56
Alter Benutzername: MasterQ32
Echter Name: Felix Queißner
Wohnort: Stuttgart & Region
Kontaktdaten:

Re: [gelöst]C#-Callback-function in C++/Cli

Beitrag von xq »

ja und der funktionspointer wird WO gespeichert? Es geht nicht darum, dass du die klasse, die den funktionspointern nutzt, vorm aufräumen schützt, sondern den funktionspointer an sich!

also schön brav funcPtr in eine member-variable von mCallback legen, am besten in mCallback::setCallbackFunc
War mal MasterQ32, findet den Namen aber mittlerweile ziemlich albern…

Programmiert viel in ⚡️Zig⚡️ und nervt Leute damit.
joggel

Re: [gelöst]C#-Callback-function in C++/Cli

Beitrag von joggel »

Aber das mache ich doch schon!!!
Über die Funktion setCallBack übergebe ich den Funktionspointer der Klasse MyCallback. Und diese bleibt am leben...
joggel

Re: [gelöst]C#-Callback-function in C++/Cli

Beitrag von joggel »

Nachtrag:

Anscheinend funktioniert das aufrufen des Funktionspointer nicht richtig.

Code: Alles auswählen

void OPCDAGroup::enableAsynch(CallbackFunc^ theCallback)
{
        auto funcPtr = static_cast<FunctionPointer>(Marshal::GetFunctionPointerForDelegate(theCallback).ToPointer());

        if (mCallback == NULL)
        {
                mCallback = new MyCallBack();
                mCallback->setCallBack(funcPtr);
        }

        mGroup->enableAsynch(*mCallback);
// Ich habe mal testweise hier den Funktionspointer aufgerufen.
	array<OPCDAItemData^>^ arr = gcnew array<OPCDAItemData^>(10);
	funcPtr(arr); // <= Hier knallt es. also scheint dieser Funktionspointer nicht richtig zu sein!!!
//*******************************
        // Sorgt dafür, dass das Delegate nicht vorzeitig vom Garbage Collector eingesammelt wird
        GC::KeepAlive(theCallback);
}

joggel

Re: [gelöst]C#-Callback-function in C++/Cli

Beitrag von joggel »

Ich habe irgendwie das Gefühl, dass das hier nicht richtig ist

Code: Alles auswählen

typedef void(*FunctionPointer)(array<OPCDAItemData^>^ arr);
Das aufrufen des Delegate funktioniert ja, nur eben nicht das Aufrufen über den Funktionspointer :?
Benutzeravatar
xq
Establishment
Beiträge: 1581
Registriert: 07.10.2012, 14:56
Alter Benutzername: MasterQ32
Echter Name: Felix Queißner
Wohnort: Stuttgart & Region
Kontaktdaten:

Re: [gelöst]C#-Callback-function in C++/Cli

Beitrag von xq »

Die Doku besagt, dass ein native function pointer keine managed-objekte enthalten darf. Von daher solltest du das Array wohl als native Datentypen übertragen. Da musst du eventuell umbauen.
War mal MasterQ32, findet den Namen aber mittlerweile ziemlich albern…

Programmiert viel in ⚡️Zig⚡️ und nervt Leute damit.
joggel

Re: [gelöst]C#-Callback-function in C++/Cli

Beitrag von joggel »

Na ganz toll!!!! PRIMA!!!
Ich überlege schon die ganze Zeit wie ich das Problem jetzt löse, also wie ich das umbauen soll....und mir fällt da nix ein.
Ich habe es bis jetzt so gemacht, das ich eine unmanaged Struktur habe, die alle geänderten Items speichert in eine List.
Nun frage ich mich, wie ich das anstelle, dass bei diesem Event eine funktion der managed Klasse aufgerufen werden kann.
Dieser Funktion würde ich gerne diese Liste der unmanaged Items übergeben, welche ich ja in einer unmanaged klasse generiert habe.
Nur ist das Problem, dass ich aus einer unmanaged Klasse keine Funktion aufrufen kann einer managed Klasse.!!!!!
FUUUU....

Nachtrag:
Aber ich glaube, das hier ist so etwas was ich bräuchte.
https://msdn.microsoft.com/de-de/librar ... x#Anchor_1
joggel

Re: [gelöst]C#-Callback-function in C++/Cli

Beitrag von joggel »

MISSION ACCOMPLISHED
34477803.jpg
Benutzeravatar
xq
Establishment
Beiträge: 1581
Registriert: 07.10.2012, 14:56
Alter Benutzername: MasterQ32
Echter Name: Felix Queißner
Wohnort: Stuttgart & Region
Kontaktdaten:

Re: [gelöst]C#-Callback-function in C++/Cli

Beitrag von xq »

Scheint wohl endlich zu klappen?!

Gratulation!
War mal MasterQ32, findet den Namen aber mittlerweile ziemlich albern…

Programmiert viel in ⚡️Zig⚡️ und nervt Leute damit.
joggel

Re: [gelöst]C#-Callback-function in C++/Cli

Beitrag von joggel »

Japp!! Hörnse uff...das war ein rumgehacke^^
Mein größtes Problem war ja, wie bekomme ich die unmanaged Datentypen in managed Code.
Ist jetzt etwas kompliziert zu erklären, aber nach einiger Googlezeit fand ich dann das hier:
Mist, finde den Link nicht mehr...
Dann halt etwas Code:

Eine Wrapper-Klasse die die umwandlung der unmanaged Daten in managed Daten macht.
Ich habe meine ganze Kreativität rausgelassen, und diese Klasse "Wrapper" genannt...

Code: Alles auswählen

class Wrapper
{
private:
	IntPtr m_handle;

public:
	Wrapper()
	{}

	~Wrapper()
	{
		static_cast<GCHandle>(m_handle).Free();
	}

	void makeManagedArray(OPCDAItemDataUnmanaged list[], const unsigned int& countListEntry)
	{
		array<OPCDAItemData^>^ arr = gcnew array<OPCDAItemData^>(countListEntry);

		for (int index(0); index < countListEntry; ++index)
			arr[index] = gcnew OPCDAItemData(list[index].mData, list[index].mName);

		safe_cast< CallbackFunc ^ >(static_cast<GCHandle>(m_handle).Target)(arr); // <= Diese Stelle ist das entscheidende! Von hier aus wird das Delegate (also C#-Funktion) aufgerufen
	}

	void setDelegate(CallbackFunc^ delegateFunc)
	{
		m_handle = static_cast<IntPtr>(GCHandle::Alloc(delegateFunc));
	}
};
Dann static Wrapper wrapper; im Header (öffentlicher Namensraum) um die Instanz in der Klasse zu verwenden, die als Callbackklasse von der Bibliothek genutzt wird.
Ich weiß jetzt garnicht ob das static erforderlich ist...

Und dann in dieser besagten Callback-Klasse:

Code: Alles auswählen

class MyCallBack : public IAsynchDataCallback
{
public:
	void setDelegate(CallbackFunc^ delegateFunc)
	{
		wrapper.setDelegate(delegateFunc);
	}

	void OnDataChange(COPCGroup &group, CAtlMap<COPCItem*, OPCItemData*> &changes)
	{
		array<OPCDAItemData^>^ arr = gcnew array<OPCDAItemData^>(changes.GetCount());
		POSITION pos;
		COPCItem* key;
		OPCItemData* value;
		pos = changes.GetStartPosition();

		int index(0);

		OPCDAItemDataUnmanaged* list = new OPCDAItemDataUnmanaged[changes.GetCount()];

		while ( pos != NULL )
		{
			key = changes.GetKeyAt(pos);
			value = changes.GetNextValue(pos);
			list[index] = OPCDAItemDataUnmanaged(value, key->getName());
			++index;
		}
		wrapper.makeManagedArray(list, changes.GetCount());
	}
};
Und Voila. Jochen hat sich gefreut wie sonstwas....

Hintergrund sollte ja der sein, dass eine C#-Funktion immer dann aufgerufen werden muß wenn sich Werte auf dem OPC-Server ändern.
Die C++-Bibliothek biedet dazu ein Callback-Klassen-Interface; also davon erben, Methode implementieren, und instanz der Klasse an die Bibliothek übergeben. Ganz leicht.
Nun aber sollte aus dieser Callback-Klasse ja ein Delegate aufgerufen werden....und dies gestaltete sich echt als schwierig, da ja zB in einer unmanaged Klasse keine managed Klassenhandler oder Delegates erlaubt sind. Deswegen der Umweg über diesen....naja...."Pointer"(?)...und Wrappen.

Jau. Danke noch mal für die Hilfe...


Nachtrag:
Ich sehe gerade, dass ich mir wahrscheinlich diese statische Instanz der Wrapper-Klasse im header hätte sparen können.
Ich könnte sie evtl auch als Member in MyCallback packen.
nur frage ich mich, wieso ich das nicht gemacht habe.... :?:
joggel

Re: [gelöst]C#-Callback-function in C++/Cli

Beitrag von joggel »

Nachtrag:
Oh man...ich habe es mir ja so umständlich gemacht, und vollkommen...blöd.
*peinlich*

Hier mal das vereinfachte Vorgehen:

Code: Alles auswählen

class MyCallBack : public IAsynchDataCallback
{
private:
	IntPtr mHandle;
public:
	void setDelegate(CallbackFunc^ delegateFunc)
	{
		mHandle = static_cast<IntPtr>(GCHandle::Alloc(delegateFunc));
	}

	void OnDataChange(COPCGroup &group, CAtlMap<COPCItem*, OPCItemData*> &changes)
	{
		array<OPCDAItemData^>^ arr = gcnew array<OPCDAItemData^>(changes.GetCount());
		POSITION pos;
		COPCItem* key;
		OPCItemData* value;
		pos = changes.GetStartPosition();

		int index(0);
		while ( pos != NULL )
		{
			key = changes.GetKeyAt(pos);
			value = changes.GetNextValue(pos);
			arr[index] = gcnew OPCDAItemData(value, key->getName());
			++index;
		}
		safe_cast<CallbackFunc^>(static_cast<GCHandle>(mHandle).Target)(arr);
	}
};
Ja...was soll ich sagen, manchmal baue ich ganz schön mist im code... :?

Mal zusammenfassen was *ich* hier mache.
Dieses GCHandle::Alloc(Object) reserviert einen Speicherbereich im managed-Speicher für ein Object und gibt ein Handle darauf zurück, und verhindert natürlich das es vom GC eingesammelt wird...
Und zu dieser Zeile:
safe_cast<CallbackFunc^>(static_cast<GCHandle>(mHandle).Target)(arr);
Dieses Target:
MSDN hat geschrieben:Ruft das Objekt ab, das von diesem Handle dargestellt wird, oder legt dieses fest.
Es wird also das Delegate aufgerufen und das managed Array übergeben...
:)
Benutzeravatar
xq
Establishment
Beiträge: 1581
Registriert: 07.10.2012, 14:56
Alter Benutzername: MasterQ32
Echter Name: Felix Queißner
Wohnort: Stuttgart & Region
Kontaktdaten:

Re: [gelöst]C#-Callback-function in C++/Cli

Beitrag von xq »

Mal ne ganz blöde frage: Warum wandelst du das GCHandle in einen IntPtr um und wieder zurück? Das könnte man auch noch weg lassen...
War mal MasterQ32, findet den Namen aber mittlerweile ziemlich albern…

Programmiert viel in ⚡️Zig⚡️ und nervt Leute damit.
joggel

Re: [gelöst]C#-Callback-function in C++/Cli

Beitrag von joggel »

Warum? Na damit du blöden fragen stellen kannst^^

Aber ja, stimmt. Ich kann auch gleich ein GCHandle als Member verwenden.
Habe es gerade geändert...
Antworten