2009-02-20 9 views
5

Je crée une DLL encapsuleur C++/CLI qui dépend de nombreuses bibliothèques statiques C++. Certains appels de fonctions attendent que des pointeurs non gérés soient transmis. Comment les transmettre correctement?Passage de pointeurs non gérés en C++/CLI

En outre, d'autres fonctions attendent qu'un "ce pointeur" soit passé en tant que vide *. Quelle est la bonne façon de passer "ceci"?

Voici ma définition de la classe ...

public ref class RTPClient 
{ 
    public: 
     RTPClient(); 
     ~RTPClient(); 

     bool Connect(); 
     void Disconnect(); 

    private: 
     CIsmaClient* mClient; 
}; 

Voici mon utilisation où les pointeurs en question sont utilisés ...

RTPClient::RTPClient(): 
    mClient(NULL) 
{ 
    CIsmaClient::Create(&mClient, NULL, &AllocBuffer, &GetDataPointer, this); 
} 

L'utilisation de & mClient et " cela "provoque les erreurs de compilation suivantes ... 1>. \ VBLoadSimulatorDll.cpp (40): erreur C2664: 'CIs maClient :: Créer »: ne peut pas convertir le paramètre 1 de 'cli :: interior_ptr' à 'CIsmaClient **' 1> avec 1> [1 > Type = CIsmaClient * 1>]

1> \. VBLoadSimulatorDll.cpp (40): erreur C2664: 'CIsmaClient :: Create': impossible de convertir le paramètre 5 de 'VBLoadSimulator :: RTPClient^const' à 'VOID *'

Répondre

9

Si vous passez un pointeur sur une classe managée, alors il est facile de convertir la référence^en un pointeur mais vous devez épingler l'objet géré pour que le GC ne le déplace pas dans la mémoire (invalidant ainsi le pointeur)

est simple avec pin_ptr

Cependant votre code est en train de faire deux choses qui ne fonctionnent pas

RTPClient::RTPClient(): 
     mClient(NULL) 
{ 
    CIsmaClient::Create(
     &mClient,   // 1 
     NULL, 
     &AllocBuffer, 
     &GetDataPointer, 
     this);   //2 
} 

1) Vous essayez de prendre l'adresse de quelque chose sur le tas managé (l'emplacement du pointeur au pointeur mClient se trouve sur le tas géré. En tant que tel, il peut se déplacer en mémoire, donc le pointeur intérieur du fournisseur du compilateur (dont la valeur est maintenue sur les opérations GC). Cela doit être pinned et cela ne fonctionnera que si la fonction Create ne s'attend pas à utiliser le pointeur après la fin de sa portée (si elle le passe ailleurs pour le stocker, cela conduira à des bogues).

2) Vous passez un handle (le symbole du chapeau drôle) plutôt qu'un pointeur. (Lisez la section wikipedia sur ceux-ci, ils sont un bon aperçu) Ce n'est pas (et ne peut pas) être compris par le code non géré. La seule raison pour laquelle je peux penser à ce paramètre dans ce contexte est une variable d'état explicite transmise aux rappels de fonction suivants (corrigez-moi si je me trompe). 'this' dans ce contexte ne fonctionnera JAMAIS correctement car cela peut se déplacer en mémoire une fois que le pin_ptr est hors de portée. Dans cet esprit, voici une implémentation (partiellement) corrigée qui clarifie ce qui peut et ne peut pas être corrigé.

RTPClient::RTPClient(): 
     mClient(NULL) 
{ 
    // make it clear you want the address of the instance variable 
    pin_ptr<CIsmaClient*> pinnedClient = &this->mClient; 
    CIsmaClient::Create(
     pinnedClient,   // fixed 
     NULL, 
     &AllocBuffer, 
     &GetDataPointer, 
     x /* pass something else in */);   //2 
} 

Si vous fournissez plus d'informations sur ce que le dernier paramètre est utilisé pour que je peux suggérer des solutions possibles

+0

Voici le lien correct: http://msdn.microsoft.com/en-us/library/1dz8byfh.aspx –

+0

le pointeur est à une classe non géré si ... – cjserio

+0

si elle est non géré alors simplement passant une plaine seulement C + + pointeur est très bien. Je ne vois pas quel est le problème .... – ShuggyCoUk

2

Je pense que vous que c'est la façon la plus simple de passer une référence via un pointeur géré vide:

void SomeFunction(void* input) 
{ 
    gcroot<ManagedClass^>* pointer = (gcroot<ManagedClass^>*)(input); 
    (*pointer)->ManagedFunction(); 
} 

void Example() 
{ 
    ManagedClass^ handle = gcnew ManagedClass(); 
    gcroot<ManagedClass^>* pointer = new gcroot<ManagedClass^>(handle); 
    SomeFunction((void*)pointer); 
    delete pointer; 
} 
+0

Pourquoi utilisez-vous 'new' et' delete'? –

+0

parce que vous ne pouvez pas prendre l'adresse d'un gcroot. vous devriez utiliser GCHandle directement.En outre, dans de nombreux cas, n'ayez pas peur d'utiliser Obect^* si le L'objet sous-jacent^est sur la pile. donc ici: SomeFunction (& handle); et les entrées doivent être transtypées dans ManagedClass^* – reuns