Callback von ref class in unmanaged class?
-
Hallo,
ich habe lange in C++ programmiert und bin vor 2 Jahren auf C# umgesattelt, ohne dass es Berührungspunkte gab. In einem neuen Projekt ist es nun so, dass ich gerne in älteren C++/MFC Projekten ein paar managed Klassen verwenden muss/möchte (teilweise auch aus C#, aber auch aus C++/CLI). Prinzipiell ist das ja wohl möglich wenn ich dazu in dem C++/MFC Projekt nur den /clr Schalter setze, kann ich managed Klassen anlegen und verwenden (gcroot<>, gcnew...).
Nun habe ich eine managed Klasse, die ein delagte beschreibt und einen event dazu hat. Ist es nun prinzipiell möglich, dass ich in das event eine Methode einer unmanaged Klasse eintragen kann? Und wenn ja, wie geht das?
Ich habe ein wenig mit FunctionPointern gespielt, bekomme es aber nicht hin. Einen (natürlich von der Signatur her passenden) FunctionPointer auf ein IntPtr zu casten bzw. die Marshal::GetDelegateFor.... und Marshal::GetFunctionPointerFor... Funktionen scheinen auch nicht das zu bringen, was ich suche. Oder doch?
Würde mich über Hilfestellung sehr freuen.
Danke und Gruss,
Holgi
-
Moin,
den bisher ausbleibenden Antworten entnehme ich mal, dass meine Frage leider entweder zu doof oder zu schwer war?
Ich habe noch ein wenig rumexperimentiert und einen Callback von einer managed in eine unmanaged Klasse hinbekommen, die eine statische Methode hat. Ein Callback von einer managed C# Klasse in eine managed C++/CLI Klasse geht auch.
Was fehlt ist der Callback von einer managed in eine nicht statische unmanaged Klasse und da stellt sich die Frage, ob das überhaupt möglich ist......
Weiss hier jemand was dazu?
Gruss,
Holgi
-
Ich hab da vor einiger Zeit mal was gemacht damit, des baut quasi nen Funktionspointer zu nem Delegate um, zunächst musste beide definieren:
typedef void (*CallbackPointer) (void*, unsigned int, unsigned int); delegate void CallbackDelegate (void *, unsigned int, unsigned int);
anschließend hab ich ne Wrapper-Klasse gebaut:
[StructLayoutAttribute( LayoutKind::Sequential, CharSet = CharSet::Ansi )] public value class CallBackWrapper { public: [MarshalAsAttribute(UnmanagedType::FunctionPtr)] CallbackDelegate ^ m_Delegate; };
die gibt so n paar Infos darüber, wie das Layout ist etc, aber du siehst es ja selbst.
Zum instanziieren:
CallBackWrapper ^ wrap = gcnew CallBackWrapper(); CallbackPointer cbPointer; wrap->m_Delegate = gcnew CallbackDelegate(this, &Class::MyFunction); // in dem Fall ist Class::MyFunction im Endeffekt ein managed Funktionspointer, kann aber nicht als Funktionspointer verwendet werden, deswegen den Umweg über das Delegate.
Marshal::StructureToPtr(wrap, (IntPtr) &cbPointer, false);
Darüber kriegste jetzt den Funktionspointer raus.
Habe das benutzt, weil ich managed mit unmanaged mischen wollte und der unmanaged Teil einen Funktionspointer bei einem bestimmten Aufruf gebraucht hat.
Habe im übrigen den Code bei codeproject gefunden, oder so, bin mir da nimmer so sicher, aber grad war die Seite down.
-
Hi
zuerst mal vielen Dank für die Antwort
Wenn ich Deine Zeile
wrap->m_Delegate = gcnew CallbackDelegate(this, &Class::MyFunction);
verwende, erhalte ich den Fehler C3364: 'CallbackDelegate' : invalid argument for delegate constructor; delegate target needs to be a pointer to a member function
Im konkreten Fall befinde ich mich in einer unmanaged MFC Applikation (/clr nachträglich gesetzt).
Header der MFC Dialog Klasse CVS2005MFCAppDlg.h (Ausschnitt):
typedef System::Int32 (*CallbackPointer) (System::Int32); delegate System::Int32 CallbackDelegate (System::Int32); class CVS2005MFCAppDlg : public CDialog { public: CVS2005MFCAppDlg(CWnd* pParent = NULL); System::Int32 myEvhandler(System::Int32 i);//hier die gewünschte Callback, ist NICHT static //usw. den Rest der CVS2005MFCAppDlg.h habe ich mal abgeschnitten };
In CVS2005MFCAppDlg.cpp:
[StructLayoutAttribute( LayoutKind::Sequential, CharSet = CharSet::Ansi )] public value class CallBackWrapper { public: [MarshalAsAttribute(UnmanagedType::FunctionPtr)] CallbackDelegate ^ m_Delegate; }; //und hier die Implementierung der gewünschten Callback passender Signatur: System::Int32 CVS2005MFCAppDlg::myEvhandler(System::Int32 i) { return 42; } //usw.
Und irgendwo dann, z.B. im OnInitDialog:
CallBackWrapper ^ wrap = gcnew CallBackWrapper(); CallbackPointer cbPointer; wrap->m_Delegate = gcnew CallbackDelegate(this, &CVS2005MFCAppDlg::myEvhandler);//hier Fehler
Dann erhalte ich den o.g. Fehler
Vermutlich geht es doch nur mit statischen Klassen, oder?
Gruss,
Holger