2016-07-20 2 views
0

J'ai essayé de passer un pointeur de classe d'une DLL native à CLR. Je n'ai pas tellement de succès avec ça. J'arrive au point où il retourne le pointeur en utilisant void * et plus tard, il le convertit en ClassType * en utilisant IntrPtr et ToPointer(). Mais la minute où j'essaie d'accéder à ses méthodes membres, ce n'est pas en mesure d'obtenir les anciennes valeurs de propriété. Je reçois à la place 0 et quelques valeurs aléatoires.Les pointeurs d'objet peuvent-ils être transmis entre CLR et C++ natif?

J'ai même essayé d'utiliser VC100 comme jeu d'outils pour le CLR et la DLL native. Pourtant, j'ai la valeur "Erreur de lecture des caractères de chaîne".

J'ai essayé de google et ne peux pas trouver beaucoup d'information sur passer des pointeurs d'objet d'indigène à CLR. J'ai mentionné même le step-by-step disponible dans le projet de code.

Edité ajouter ceci:


J'ai un dll natif où une fonction qui renvoie un pointeur d'objet

Native.dll:

#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.. 
} 
... 
} 

Et plus tard dans le code managé clr I appelez memberFunct1 en utilisant le pointeur de retour.

[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(); 

J'utilise ce pointeur obj1 pour appeler une méthode membre, mais dans la méthode membre des valeurs membres font preuve aussi mauvais ptr.


Quelqu'un peut-il me diriger dans la bonne direction s'il vous plaît?

Merci d'avance.


J'ai ajouté une méthode supplémentaire dans ma DLL native.

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

et l'a appelé de mon projet CLR

[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)); 

Mais je reçois des erreurs de lien? Je l'ai déjà lié ?? !! ??

erreur LNK2028: jeton non résolu (0A000356) "public: __thiscall Obj1 :: Obj1 (int, char const *, char const *)" (?? 0Obj1 @@ $$ FQAE @ HPBD0 @ Z) référencé dans la fonction " int __cdecl principal (void) »

erreur LNK2028 (principale @@ $$ HYAHXZ?): jeton non résolu (0A00035B) "void __cdecl SomeMethod2 (int, char const *, char const *, classe Obj1 *)"(? SomeMethod2 @@ $$ FYAXHPBD0PAVObj1 @@@ Z) référencé dans la fonction "int __cdecl main (void)" (? Main @@ $$ HYAHXZ)

erreur LNK2019: symbole externe non résolu "public: __thiscall Obj1 :: Obj1 (int, char const *, char const *) "(?? 0Obj1 @@ $$ FQAE @ HPBD0 @ Z) référencé dans la fonction" int __cdecl main (void) "(? main @@ $$ HYAHXZ)

erreur LNK2019: symbole externe non résolu "void __cdecl SomeMethod2 (int, char const *, char const *, classe Obj1 *)" (? SomeMethod2 @@ $$ FYAXHPBD0PAVObj1 @@@ Z) référencé dans la fonction "int __cdecl main (vide) "([email protected]@ principale $$ HYAHXZ)

enter image description here

+0

@Martin Désolé, j'ai édité ma publication et ajouté quelques codes. – ras

+0

Ceci est une norme de tourbière [bug pointeur dangling] (https://en.wikipedia.org/wiki/Dangling_pointer). Un bogue très courant dans un programme C ou C++, généralement très difficile à diagnostiquer. Mais pas quand vous utilisez pinvoke, l'espace de pile requis par le marshaller pinvoke garantit que 'obj 'est écrasé de manière fiable. Vous devez le stocker ailleurs, le meilleur endroit est presque toujours le cadre de la pile de l'appelant. Remplacez le type de retour par void et ajoutez un paramètre 'Obj1 * retval'. –

+0

@HansPassant J'ai aussi essayé le vôtre. Mais j'ai toujours une erreur de lien. J'ai modifié mon message pour inclure ce que vous avez mentionné et ajouté une image montrant le lien. – ras

Répondre

1

Vous n'utilisez pas C++/CLI de cette façon!

L'ensemble point de C++/CLI doit agir comme un lien entre le monde .NET et le monde natif.

Ce que vous faites est plutôt:

  • Inclure les C++ en-têtes pour SomeMethod et class Obj1 dans le fichier source C++/CLI et
  • ont l'assemblage C++/CLI référence du projet Native.dll

Ensuite, vous pouvez simplement l'utiliser comme vous le feriez normalement en C++ - convert any CLR types to native representation first (System :: String peut être converti par MFC CString si vous incluez MFC):

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

Quant à savoir pourquoi vous voyez des ordures dans le débogueur: Il est probablement parce que vous retournez l'adresse d'un objet local:

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 
} 

Dans ce cas, obj sera nettoyé up (son D'tor invoqué et sa mémoire de pile recyclée) dès que vous revenez de SomeMethod.

  • soit retourner l'objet par valeur
  • ou new l'objet et revenir le pointeur. (bien que ce soit un code de fuite-risque)
+0

Je l'ai fait. J'ai inclus le fichier d'en-tête et copié le Native.dll et l'a ajouté comme référence à mon projet CLR. Je l'ai instancié et j'ai une erreur de lien ??! ?? [erreur LNK2028: jeton non résolu (0A00041D) "public: __thiscall SomeDLLClass1 :: SomeDLLClass1 (int, char const *, char const *)" (?? 0SomeDLLClass1 @@ $$ FQAE @ HPBD0 @ Z) référencé dans la fonction "int __clrcall main (cli :: array ^) "] – ras

+0

La ligne d'insanation [Obj1 testPtr2 = Obj1 (1, (char *) (void *) Marshal :: StringToHGlobalAnsi (str1), (char *) (void *) Marshal :: StringToHGlobalAnsi (str2));] – ras

+0

@ras - vous ne copiez pas Native.dll et ne l'ajoutez pas comme référence. Vous devez ajouter le Native.vcxproj comme référence et activer 'Link Lib Dependencies == true'. - Alternativement, vous liez le fichier '.lib' du projet natif, si le projet natif vit dans une autre solution. –