2009-02-20 9 views
5

Sto creando una DLL wrapper C++/CLI che dipende da numerose librerie statiche C++. Alcune delle chiamate alle funzioni prevedono l'invio di puntatori non gestiti. Come li passo correttamente?Passaggio di puntatori non gestiti in C++/CLI

Inoltre, altre funzioni prevedono che un "puntatore" venga passato come un vuoto *. Qual è il modo giusto per passare "questo"?

Ecco la mia definizione della classe ...

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

     bool Connect(); 
     void Disconnect(); 

    private: 
     CIsmaClient* mClient; 
}; 

Ecco il mio utilizzo in cui vengono utilizzati i puntatori in questione ...

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

L'utilizzo di & mClient e " questo "causa i seguenti errori del compilatore ... 1>. \ VBLoadSimulatorDll.cpp (40): errore C2664: 'Elementi di configurazione maClient :: Create': non può convertire il parametro 1 da 'cli :: interior_ptr' a 'CIsmaClient **' 1> con 1> [ 1> Type = CIsmaClient * 1>]

1> \. VBLoadSimulatorDll.cpp (40): errore C2664: 'CIsmaClient :: Create': impossibile convertire il parametro 5 da 'VBLoadSimulator :: RTPClient^const' a 'VOID *'

risposta

9

Se si passa un puntatore a una classe gestita quindi è facile convertire il riferimento in un puntatore, ma devi bloccare l'oggetto gestito in modo che il GC non lo sposti in memoria (invalidando quindi il puntatore)

Questo è semplice con pin_ptr

Tuttavia il codice sta facendo due cose che non funzionano

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

1) Si sta tentando di prendere l'indirizzo di qualcosa sul mucchio gestito (la posizione del puntatore al puntatore mClient si trova nell'heap gestito.

Come tale può spostarsi in memoria, quindi il puntatore interno del fornitore del compilatore (il cui valore viene mantenuto su operazioni GC). Questo deve essere pinned e questo funzionerà solo se la funzione Crea non prevede di utilizzare il puntatore dopo che l'ambito è terminato (se lo passa in un altro punto per memorizzarlo, ciò porterà a bug).

2) Si sta passando un handle (il simbolo del cappello buffo) piuttosto che un puntatore. (Leggi la sezione wikipedia su questi sono una buona panoramica) Questo non è (e non può) essere compreso dal codice non gestito.

L'unico motivo per cui posso considerare questo parametro in questo contesto è come una variabile di stato esplicita passata a callback di funzioni successive (correggimi se ho torto). 'questo' in questo contesto non funzionerà MAI correttamente poiché questo può spostarsi in memoria una volta che pin_ptr esce dall'ambito.

Con questo in mente ecco un'implementazione (parzialmente) corretta che rende chiaro ciò che può e non può essere risolto.

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 
} 

Se si fornisce ulteriori informazioni su ciò che l'ultimo parametro viene utilizzato per quello che posso suggerire possibili soluzioni

+0

Ecco il link corretto: http://msdn.microsoft.com/en-us/library/1dz8byfh.aspx –

+0

il puntatore è quello di una classe non gestita però ... – cjserio

+0

se è gestito poi semplicemente passando un piano solo C + + il puntatore va bene. Non vedo quale sia il problema .... – ShuggyCoUk

2

Credo che sarete che questo è il modo più semplice di passare un riferimento gestito tramite un puntatore nullo:

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

Perché stai usando 'new' e' delete'? –

+0

perché non puoi prendere l'indirizzo di un gcroot. dovresti usare direttamente GCHandle e, in molti casi, non avere paura di usare Obect^* se il l'oggetto sottostante^è in pila. quindi qui: SomeFunction (& handle); e l'input deve essere eseguito su ManagedClass^* – reuns