Benutzer mit den meisten Antworten
VS2010 C++, MFC .NET C# Assembly - Vorgehensweise, Beispiel

Frage
-
Hallo,
ich muss in VS2010 C++, MFC eine .NET C# Assembly einbinden.
- Wie kann ich das erreichen?
- Wie ist die Vorgehensweise?
- Hat jemand Tipps? Sieht jemand Fehler?
Danke im Voraus.
Zunächst einfach
C# .NET Assembly
Klasse, 2 Funktionen
-> Die muss ich in C++, MFC aufrufen.Fehler 1 error C2065: 'ConnectorMachineDataCustomerB': nichtdeklarierter Bezeichner D:\RTestAppMFCDlg.cpp 181 1 RTestAppMFC
Anbei meine Einstellungen, meine Recherche.
http://blog.kalmbach-software.de/de/2010/03/05/ccli-und-winforms-macht-keinen-sinn/
http://msdn.microsoft.com/de-de/library/vstudio/wkze6zky.aspx
http://msdn.microsoft.com/de-de/library/vstudio/wkze6zky%28v=vs.100%29.aspx
COM will ich nicht einsetzen.
Grüße Andy
P.S. Am Rande, unterstützt VS2012 C++, MFC das Einbinden wieder besser?
Antworten
-
Freigeben muss sein. Und als Parameter muss man den IntPtr übergeben, den man vom StringToHGlobalX erhalten hat.
Im Beispiel hab ich den direkt per "ToPointer()" in einen void* gecastet und dann nach wchar_t* ... aber du kannst hier auch einen anderen Weg wählen wie z.B. den IntPtr zwischenspeichern statt am Ende wieder casten.
- Als Antwort markiert Andy Bauer Montag, 18. Februar 2013 19:12
Alle Antworten
-
Nun ja... du hast ja dein MFC Projekt... dann aktiviere mal CLR... das soll so gehen
http://msdn.microsoft.com/de-de/library/ms235211(v=vs.80).aspx
... ausprobiert hab ich's nicht. Aber danach müsstest du zu deinem Projekt eine verwaltete Klasse hinzufügen können und die ansteuern (würde ich als Test mal ausprobieren).
Wenn das geht, musst du (theoretisch) nur noch den Verweis sezten (wie du das bebildert hast) und dann den richtigen Namen für den Aufruf der Klasse verwenden. Den hol ich mir jeweils aus dem Fenster "Objektkatalog" ... da kann man irgendwie die Assembly angeben, dann listet's einem auf was da drin ist.
... wie gesagt, ausprobiert hab ich das so direkt nicht. Aber in Projekten ohne MFC hab ich das schon so gemacht.
Rudolf
-
Nun ja... du hast ja dein MFC Projekt... dann aktiviere mal CLR... das soll so gehen
http://msdn.microsoft.com/de-de/library/ms235211(v=vs.80).aspx
Hallo Rudolf,
danke mal. Die Einstellungen habe ich vorgenommen.
http://msdn.microsoft.com/de-de/library/ms235211(v=vs.100).aspx
C# Namespace RGROUP1.ElementA.ConnectorA.Core
public Class ConnectorA
void Func1();
int Func2(int a, string b);
string Func3(double a, decimal b);
Kannst Du kurz aufzeigen
A) Wie erzeugst du ein Objekt in der MFC?
B) Aufrudf der 3 Funktionen mit Rückgabe String (CString)
Danke und Grüße Andy
-
Hallo
A) Das kannst du über die C++/CLI Sprachelemente machen, die man mit native C++ mixen kann. Mit gcnew (anstelle von new) kannst du so ein verwaltetes Objekt erzeugen. Also (mal ganz ohne using's)
RGROUP1::ElementA::ConnectorA::Core::ConnectorA^ pMyObject = gcnew RGROUP1::ElementA::ConnectorA::Core::ConnectorA();
das ^ entspricht dem *
B) Der Aufruf geschieht ganz normal mit pMyObject->Func3 und das Resultat ist ein System::String^ ... das muss du dann umwandeln in einen nativen String. Dazu schreibst du am einfachsten
using namespace Runtime::InteropServices;
Und dann kannst du mit den Funktionen Marshal::StringToHGlobalUni oder Marshal::StringToHGlobalAnsi den String in einen unmanaged Puffer packen.
Konkret so:
System::String^ verwString = pMyObject->Func3(/* was auch immer */);
wchar_t* strString = (wchar_t *)(Marshal::StringToHGlobalUni(verwString).ToPointer());
CString das_was_du_willst(strString);
Marshal::FreeHGlobal((IntPtr)strString);
... tja, reichlich kompliziert. :-) aber einfacher geht's nicht, das kann ich dir sagen. Ich habe gerade ein Projekt hinter mir, bei dem's darum ging solchen Marshaling-Code zu generieren.
Gruss, Rudolf
-
using namespace Runtime::InteropServices;
Und dann kannst du mit den Funktionen Marshal::StringToHGlobalUni oder Marshal::StringToHGlobalAnsi den String in einen unmanaged Puffer packen.
Konkret so:
System::String^ verwString = pMyObject->Func3(/* was auch immer */);
wchar_t* strString = (wchar_t *)(Marshal::StringToHGlobalUni(verwString).ToPointer());
CString das_was_du_willst(strString);
Marshal::FreeHGlobal((IntPtr)strString);
... tja, reichlich kompliziert. :-) aber einfacher geht's nicht, das kann ich dir sagen. Ich habe gerade ein Projekt hinter mir, bei dem's darum ging solchen Marshaling-Code zu generieren.
Hallo Rudolf,
ich teste es und melde mich ggf. nochmals. Ja kompliziert.
Das komplexe freigeben muss sein?
Marshal::FreeHGlobal((IntPtr)strString);
Grüße Andy
-
Freigeben muss sein. Und als Parameter muss man den IntPtr übergeben, den man vom StringToHGlobalX erhalten hat.
Im Beispiel hab ich den direkt per "ToPointer()" in einen void* gecastet und dann nach wchar_t* ... aber du kannst hier auch einen anderen Weg wählen wie z.B. den IntPtr zwischenspeichern statt am Ende wieder casten.
- Als Antwort markiert Andy Bauer Montag, 18. Februar 2013 19:12
-
Gemischte Anwendungen (also in dem Fall jetzt native, welches managed lädt) kann man debuggen, wenn man in der Konfiguration unter "Debuggen" den "Debuggertyp" auf "Gemischt" stellt.
Andersrum (also z.B. C# lädt C++ native dll) muss man's anders einstellen... aber das findet ihr auch in den Eigenschaften vom Projekt.
-
Freigeben muss sein. Und als Parameter muss man den IntPtr übergeben, den man vom StringToHGlobalX erhalten hat.
Im Beispiel hab ich den direkt per "ToPointer()" in einen void* gecastet und dann nach wchar_t* ... aber du kannst hier auch einen anderen Weg wählen wie z.B. den IntPtr zwischenspeichern statt am Ende wieder casten.
Hallo Rudolf,
ja Frage mal beantwortet. Danke.
Grüße Andyvoid CRTestAppMFCDlg::OnBnClickedButton1() { //gcroot<RCommunication::Implementations::ConnectorMachineDataCustomerB ^> F_TEST; // ConnectorMachineDataCustomerB fff; RCommunication::Implementations::ConnectorMachineDataCustomerB::Core::ConnectorMachineDataCustomerB ^ pMyObject = gcnew RCommunication::Implementations::ConnectorMachineDataCustomerB::Core::ConnectorMachineDataCustomerB(); int ret = pMyObject->TestOn_2(); int retOriginal = pMyObject->TestOn();
-
Ja schon klar Aber was ist mit den Dump bzw dmp Dateien um beim absturz den callstack und diverse Variablen zu debuggen bzw. die dmp Datei in den Debugger zu Laden, geht das auch bei gemischten Anwendungen ? Soweit ich mich erinnern kann ging das unter vs2005 bzw. .NET 3.x nicht. Hat sich das inzwischen geändert ?
-
> Ja schon klar Aber was ist mit den Dump bzw dmp Dateien um beim absturz den callstack und diverse Variablen zu debuggen bzw. die dmp Datei in den Debugger zu Laden, geht das auch bei gemischten Anwendungen ? Soweit ich mich erinnern kann ging das unter vs2005 bzw. .NET 3.x nicht. Hat sich das inzwischen geändert ?
Zumindest mit WinDbg geht dies... SOS unterstützt hier einen speziellen "MiniDumpMode"...
Jochen Kalmbach (MVP VC++)