2016-07-20 28 views
0

Ich habe versucht, einen Klassenzeiger von einer nativen DLL an CLR zu übergeben. Ich bin damit nicht so erfolgreich. Ich komme an den Punkt, der den Zeiger mit void * zurückgibt und ihn später mit IntrPtr und ToPointer() in ClassType * umwandelt. Aber sobald ich versuche, auf seine Member-Methoden zuzugreifen, ist es nicht möglich, die alten Eigenschaftswerte zu erhalten. Ich bekomme stattdessen 0 und einige zufällige Werte.Können Objektzeiger zwischen CLR und nativem C++ übergeben werden?

Ich habe sogar versucht, VC100 als Toolset für die CLR und native DLL zu verwenden. Ich bekomme immer noch den Wert "Fehler beim Lesen der Zeichen der Zeichenfolge".

Ich habe versucht, google und kann nicht viele Informationen über die Übergabe von Objektzeigern von nativen CLR finden. Ich habe mich sogar auf das step-by-step verfügbare Code-Projekt bezogen.

Edited dies hinzufügen:


Ich habe eine native DLL, wo eine Funktion, die Objektzeiger

Native.dll zurück:

#if defined EXPORTDLL // inside DLL 
#define DLL_EXPORT __declspec(dllexport) 
#else // outside DLL 
#define DLL_EXPORT __declspec(dllimport) 
#endif 

..... 

DLL_EXPORT void* SomeMethod(uint16_t num1, const char * str1, const char * str2) 
{ 
    Obj1 obj(...); 
    ... 
    return (void*)&obj; // <- at this point it is still correct 
} 

.... 
class DLL_EXPORT Obj1{ 
.... 
const std::string var1; 
const std::string var2; 
const std::string var3; 
.... 
DLL_EXPORT strct1 memberFunction1() 
{ 
    // do something with the variables 
    // here when its called by managed code, the var1, var2, var3 shows random values and bad ptr.. 
} 
... 
} 

Und später in verwaltetem Code clr I Rufen Sie den memberFunct1 mit dem Rückgabezeiger auf.

[DllImport("Native.dll", EntryPoint = "[email protected]@[email protected]@@[email protected][email protected]@[email protected]@[email protected]@[email protected]@[email protected]@[email protected]", CallingConvention = CallingConvention::Cdecl)] 
IntPtr * SomeMethod(uint16_t num1, [In, MarshalAs(UnmanagedType::LPStr)]String^ str1, [In, MarshalAs(UnmanagedType::LPStr)] String^ str2); 
..... 

String^ str1 = gcnew String("1223568"); 
String^ str2 = gcnew String("1.2.3.5"); 
Obj1 *objptr = (Obj1*)(SomeMethod(1,str1, str2)).ToPointer(); 
// <- at this point the objptr properties are showing garbage 
objptr->memberFunction1(); 

Ich benutze dieses obj1 Zeiger ein Element-Methode aufrufen, aber in dem Element-Methode als schlecht ptr die Mitgliedswerte zeigen.


Kann mir bitte jemand in die richtige Richtung zeigen?

Vielen Dank im Voraus.


Ich habe eine zusätzliche Methode in meiner nativen DLL hinzugefügt.

void DLL_EXPORT SomeMethod2(int i1, const char* var1, const char* var2, Obj1* retval); 

und nannte es aus meinem CLR Projekt

[DllImport("Native.dll", EntryPoint = "[email protected]@[email protected]@@Z", CallingConvention = CallingConvention::Cdecl)] 
void SomeMethod2(int i1, [MarshalAs(UnmanagedType::LPStr)]String^ var1, [MarshalAs(UnmanagedType::LPStr)]String^ var2, Obj1* retval); 
.... 
Obj1 * testPtr3; 
SomeMethod2(1, (char*)(void*)Marshal::StringToHGlobalAnsi(str1), (char*)(void*)Marshal::StringToHGlobalAnsi(str2), testPtr3); 
SomeMethod2(1, str1, str2, testPtr3); 

Obj1 testPtr2 = Obj1(1, (char*)(void*)Marshal::StringToHGlobalAnsi(str1), (char*)(void*)Marshal::StringToHGlobalAnsi(str2)); 

Aber ich Linkfehler bekommen? Ich habe es schon verlinkt ?? !! ??

Fehler LNK2028: unaufgelöster Token (0A000356) "public: __thiscall Obj1 :: Obj1 (int, Zeichenkonst *, Zeichenkonst *)" (?? 0Obj1 @@ $$ FQAE @ HPBD0 @ Z) verwiesen in Funktion " int __cdecl main (void) "

Fehler LNK2028: nicht aufgelöstes Token (0A00035B)" void __cdecl SomeMethod2 (int, Zeichenkonst *, Zeichenkonst *, Klasse Obj1 *) "(? SomeMethod2 @@ $$ FYAXHPBD0PAVObj1 @@@ Z) referenziert in der Funktion "int __cdecl main (void)"

Fehler LNK2019: nicht aufgelöstes externes Symbol "public: __thiscall Obj1 :: Obj1 (int, char const *, char const *) "(?? 0Obj1 @@ $$ FQAE @ HPBD0 @ Z) referenziert in der Funktion" int __cdecl main (void) "(? main @@ $$ HYAHXZ)

Fehler LNK2019: nicht aufgelöstes externes Symbol "void __cdecl SomeMethod2 (int, Zeichenkonst *, Zeichenkonst *, Klasse Obj1 *)" (? SomeMethod2 @@ $$ FYAXHPBD0PAVObj1 @@@ Z) referenziert in der Funktion "int __cdecl main (ungültig) "(?)Haupt @@ $$ HYAHXZ)

enter image description here

+0

@Martin Sorry, ich habe meinen Beitrag bearbeitet und einige Codes hinzugefügt. – ras

+0

Dies ist ein Moor-Standard [Dangling Pointer Bug] (https://en.wikipedia.org/wiki/Dangling_pointer). Ein sehr häufiger Fehler in einem C- oder C++ - Programm, normalerweise sehr schwer zu diagnostizieren. Aber nicht, wenn Sie pinvoke verwenden, sorgt der Stack-Platz, den der pinvoke marshaller benötigt, dafür, dass "obj" zuverlässig überschrieben wird. Sie müssen es woanders speichern, der beste Platz ist fast immer der Stapelrahmen des Anrufers. Ändern Sie den Rückgabetyp in void und fügen Sie einen Parameter "Obj1 * retval" hinzu. –

+0

@HansPassant Ich habe es auch versucht. Aber ich bekomme immer noch einen Linkfehler. Ich habe meinen Beitrag bearbeitet, um das, was Sie erwähnt haben, einzuschließen und ein Bild hinzugefügt, das den Link zeigt. – ras

Antwort

1

Sie nicht C++ verwenden/CLI auf diese Weise!

Das ganze Punkt von C++/CLI soll als Klebstoff zwischen der .NET-Welt und der nativen Welt fungieren.

Was Sie tun, ist stattdessen:

  • Fügen Sie die C++ Header für SomeMethod und class Obj1 in der C++/CLI-Quelldatei und
  • haben die C++/CLI-Referenzanordnung, die die Native.dll Projekt

Dann können Sie es einfach verwenden, wie Sie normalerweise in C++ - convert any CLR types to native representation first (System :: String kann von MFC CString konvertiert werden, wenn Sie MFC enthalten):

String^ str1 = gcnew String("1223568"); 
String^ str2 = gcnew String("1.2.3.5"); 
Obj1 *objptr = SomeMethod(1, CString(str1), CString(str2)); 

Was, warum Sie sehen, Müll im Debugger: Es ist wahrscheinlich, weil Sie die Adresse eines lokalen Objekt zurück:

DLL_EXPORT void* SomeMethod(uint16_t num1, const char * str1, const char * str2) 
{ 
    Obj1 obj(...); 
    ... 
    return (void*)&obj; // <- at this point it is still correct 
} 

In diesem Fall wird obj gereinigt werden up (der D'tor wird aufgerufen und der Stackspeicher wird recycelt), sobald Sie von SomeMethod zurückkehren.

  • entweder zurück durch das Objekt Wert
  • new oder bis das Objekt und den Zeiger zurück. (obwohl das ist Leck-Risiko-Code)
+0

Ich habe das getan. Ich habe die Header-Datei aufgenommen und die Native.dll kopiert und sie als Referenz zu meinem CLR-Projekt hinzugefügt. Ich habe es instanziiert und bekomme einen Linkfehler ??! ?? [Fehler LNK2028: nicht aufgelöstes Token (0A00041D) "public: __thiscall SomeDLLClass1 :: SomeDLLClass1 (int, Zeichen const *, Zeichen const *)" (?? 0SomeDLLClass1 @@ $$ FQAE @ HPBD0 @ Z) referenziert in der Funktion "int __clrcall main (cli :: array ^) "] – ras

+0

Die insantiation line [Obj1 testPtr2 = Obj1 (1, (char *) (void *) Marshal :: StringToHGlobalAnsi (str1), (char *) (void *) Marshal :: StringToHGlobalAnsi (str2));] – ras

+0

@ras - Sie kopieren die Native.dll nicht und fügen sie als Referenz hinzu. Sie müssen Native.vcxproj als Referenz hinzufügen und 'Link Lib Dependencies == true' aktivieren. - Alternativ verknüpfen Sie die Datei ".lib" aus dem nativen Projekt, wenn das native Projekt in einer anderen Lösung ausgeführt wird. –