[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 »

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: 8229
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...
biertrinker
Beiträge: 2
Registriert: 24.09.2006, 22:06

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

Beitrag von biertrinker »

Ich versteh gar nicht, wozu du überhaupt ein GCHandle brauchst. Wenn du das Delegate als Member speicherst, hat der Garbage Collector eine Referenz darauf, die so lange gültig ist wie die Lebensdauer der MyCallback Instanz.
joggel

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

Beitrag von joggel »

Sorry, ich war unpässlich die letzten 2 Tage...
biertrinker hat geschrieben:Ich versteh gar nicht, wozu du überhaupt ein GCHandle brauchst. Wenn du das Delegate als Member speicherst, hat der Garbage Collector eine Referenz darauf, die so lange gültig ist wie die Lebensdauer der MyCallback Instanz.
Ich kann das Delegate nicht als Member speichern. Zumindest sagt mir das der Compiler. Kannst es mal probieren....
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 »

Welche Fehlermeldung kommt?
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 »

VC hat geschrieben:ein Member einer nicht-verwaltet-Klasse kann kein Handle sein
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 »

Kannst du die klasse nicht einfach verwaltet machen? Würde mit C++/CLI native Klassen soweit es geht vermeiden
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 »

Nein, kann ich nicht. Ich übergebe ja eine Instanz davon einer C++-Bibliothek.
Aber ist ja auch nicht sooo schlimm. Ist halt nur ein kleiner Umweg so ;)
joggel

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

Beitrag von joggel »

Und wieder ein Problem vor dem ich stehe!!

Wenn ich mein Projekt, welches ja eine managed Bibliothek werden soll, mit Debug erstelle, funktioniert alles gut.
Wenn ich das Projekt aber als Releas erstellen will, sagt mir VS:
Fehler LNK2038 Konflikt ermittelt f³r "RuntimeLibrary": Der Wert "MT_StaticRelease" stimmt nicht mit dem Wert "MD_DynamicRelease"
Wieso funktioniert das im Debug-Mode, aber nicht im Release-Mode?
Die Bibliothek die ich verwenden möchte, wird für statisches Linken erstellt.
Ich würde sie ja auch dynamisch als DLL erstellen, nur wird mir NUR eine DLL ausgespuckt, und die kann ich ja nicht in meinem Projekt verwenden; zumindest braucht man doch da eine LIB-File, oder irre ich mich??
Zuletzt geändert von joggel am 13.02.2017, 11:32, insgesamt 1-mal geändert.
joggel

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

Beitrag von joggel »

Ehm...ich weiß nicht was ich da versucht habe zu erstellen, aber jetzt geht es.
Also letzter Post kann ignoriert werden^^
Antworten