[gelöst]C#-Callback-function in C++/Cli
- xq
- Establishment
- Beiträge: 1590
- 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
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.
Programmiert viel in Zig und nervt Leute damit.
- Krishty
- Establishment
- Beiträge: 8316
- Registriert: 26.02.2009, 11:18
- Benutzertext: state is the enemy
- Kontaktdaten:
Re: [gelöst]C#-Callback-function in C++/Cli
Du hast recht:
Dann verdränge ich den Gedanken mal ganz schnell wieder aus meinem Kopf, und aus meinem Code … :)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.
Re: [gelöst]C#-Callback-function in C++/Cli
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.
}
- xq
- Establishment
- Beiträge: 1590
- 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
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
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.
Programmiert viel in Zig und nervt Leute damit.
Re: [gelöst]C#-Callback-function in C++/Cli
Aber das mache ich doch schon!!!
Über die Funktion setCallBack übergebe ich den Funktionspointer der Klasse MyCallback. Und diese bleibt am leben...
Über die Funktion setCallBack übergebe ich den Funktionspointer der Klasse MyCallback. Und diese bleibt am leben...
Re: [gelöst]C#-Callback-function in C++/Cli
Nachtrag:
Anscheinend funktioniert das aufrufen des Funktionspointer nicht richtig.
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);
}
Re: [gelöst]C#-Callback-function in C++/Cli
Ich habe irgendwie das Gefühl, dass das hier nicht richtig ist
Das aufrufen des Delegate funktioniert ja, nur eben nicht das Aufrufen über den Funktionspointer :?
Code: Alles auswählen
typedef void(*FunctionPointer)(array<OPCDAItemData^>^ arr);
- xq
- Establishment
- Beiträge: 1590
- 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
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.
Programmiert viel in Zig und nervt Leute damit.
Re: [gelöst]C#-Callback-function in C++/Cli
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
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
- xq
- Establishment
- Beiträge: 1590
- 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
Scheint wohl endlich zu klappen?!
Gratulation!
Gratulation!
War mal MasterQ32, findet den Namen aber mittlerweile ziemlich albern…
Programmiert viel in Zig und nervt Leute damit.
Programmiert viel in Zig und nervt Leute damit.
Re: [gelöst]C#-Callback-function in C++/Cli
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...
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:
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.... :?:
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));
}
};
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());
}
};
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.... :?:
Re: [gelöst]C#-Callback-function in C++/Cli
Nachtrag:
Oh man...ich habe es mir ja so umständlich gemacht, und vollkommen...blöd.
*peinlich*
Hier mal das vereinfachte Vorgehen:
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:
:)
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);
}
};
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:
Es wird also das Delegate aufgerufen und das managed Array übergeben...MSDN hat geschrieben:Ruft das Objekt ab, das von diesem Handle dargestellt wird, oder legt dieses fest.
:)
- xq
- Establishment
- Beiträge: 1590
- 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
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.
Programmiert viel in Zig und nervt Leute damit.
Re: [gelöst]C#-Callback-function in C++/Cli
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...
Aber ja, stimmt. Ich kann auch gleich ein GCHandle als Member verwenden.
Habe es gerade geändert...
-
- Beiträge: 2
- Registriert: 24.09.2006, 22:06
Re: [gelöst]C#-Callback-function in C++/Cli
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.
Re: [gelöst]C#-Callback-function in C++/Cli
Sorry, ich war unpässlich die letzten 2 Tage...
Ich kann das Delegate nicht als Member speichern. Zumindest sagt mir das der Compiler. Kannst es mal probieren....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.
- xq
- Establishment
- Beiträge: 1590
- 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
Welche Fehlermeldung kommt?
War mal MasterQ32, findet den Namen aber mittlerweile ziemlich albern…
Programmiert viel in Zig und nervt Leute damit.
Programmiert viel in Zig und nervt Leute damit.
Re: [gelöst]C#-Callback-function in C++/Cli
VC hat geschrieben:ein Member einer nicht-verwaltet-Klasse kann kein Handle sein
- xq
- Establishment
- Beiträge: 1590
- 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
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.
Programmiert viel in Zig und nervt Leute damit.
Re: [gelöst]C#-Callback-function in C++/Cli
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 ;)
Aber ist ja auch nicht sooo schlimm. Ist halt nur ein kleiner Umweg so ;)
Re: [gelöst]C#-Callback-function in C++/Cli
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:
Wieso funktioniert das im Debug-Mode, aber nicht im Release-Mode?Fehler LNK2038 Konflikt ermittelt f³r "RuntimeLibrary": Der Wert "MT_StaticRelease" stimmt nicht mit dem Wert "MD_DynamicRelease"
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.
Re: [gelöst]C#-Callback-function in C++/Cli
Ehm...ich weiß nicht was ich da versucht habe zu erstellen, aber jetzt geht es.
Also letzter Post kann ignoriert werden^^
Also letzter Post kann ignoriert werden^^