2009-02-20 21 views
5

Estoy creando una DLL contenedora C++/CLI que depende de numerosas bibliotecas estáticas de C++. Algunas de las llamadas a funciones esperan que se pasen punteros no administrados. ¿Cómo los paso a pasar correctamente?Pasar punteros no administrados en C++/CLI

Además, otras funciones esperan que "este puntero" pase como un vacío *. ¿Cuál es la forma correcta de pasar "esto"?

Aquí está mi definición de clase ...

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

     bool Connect(); 
     void Disconnect(); 

    private: 
     CIsmaClient* mClient; 
}; 

Aquí está mi uso, donde se utilizan los punteros en cuestión ...

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

El uso de & mClient y " esto "causa los siguientes errores del compilador ... 1>. \ VBLoadSimulatorDll.cpp (40): error C2664: 'CIs maClient :: Create': no ​​se puede convertir el parámetro 1 de 'cli :: interior_ptr' a 'CIsmaClient **' 1> con 1> [1 > Tipo = CIsmaClient * 1>]

1> \. VBLoadSimulatorDll.cpp (40): error C2664: 'CIsmaClient :: Create': no ​​se puede convertir el parámetro 5 de 'VBLoadSimulator :: RTPClient^const' a 'VOID *'

Respuesta

9

Si pasa un puntero a una clase administrada, entonces es fácil convertir la referencia^en un puntero, pero debe anclar el objeto administrado para que el GC no lo mueva en la memoria (lo que invalida el puntero)

Esto es simple con pin_ptr

Sin embargo, su código está haciendo dos cosas que no funcionarán

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

1) Usted está tratando de tomar la dirección de algo en el montón administrado (la ubicación del puntero al puntero mClient está en el montón administrado.

Como tal, se puede mover en la memoria, por lo tanto, el puntero del interior del proveedor del compilador (cuyo valor se mantiene durante las operaciones del GC). Esto debe ser pinned y esto solo funcionará si la función Crear no espera usar el puntero después de que su alcance ha finalizado (si lo pasa a otro lugar para almacenarlo, esto dará lugar a errores).

2) Usted está pasando un handle (el símbolo del sombrero gracioso) en lugar de un puntero. (Lea la sección de wikipedia sobre estos son una buena descripción) Esto no es (ni puede) entendido por el código no administrado.

La única razón que se me ocurre para este parámetro en este contexto es como una variable de estado explícita que se pasa a las devoluciones de funciones posteriores (corrígeme si estoy equivocado). 'esto' en este contexto NUNCA va a funcionar correctamente, ya que esto puede moverse en la memoria una vez que el pin_ptr queda fuera del alcance.

Con esto en mente aquí hay una implementación (parcialmente) corregida que deja en claro lo que puede y no puede ser reparado.

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 proporciona más información sobre lo que se utiliza el último parámetro de lo que puedo sugerir posibles soluciones

+0

Aquí es el enlace correcto: http://msdn.microsoft.com/en-us/library/1dz8byfh.aspx –

+0

el puntero apunta a una clase no administrada, aunque ... – cjserio

+0

si es administrado entonces simplemente pasando una llanura solo C + + puntero está bien. No veo cuál es el problema ... – ShuggyCoUk

2

Creo que usted que esta es la forma más sencilla de pasar a través de una referencia conseguido un puntero nulo:

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

¿Por qué está usando 'new' y' delete'? –

+0

porque no puede tomar la dirección de un gcroot. Si lo desea, deberías usar GCHandle directamente. Además, en muchos casos, no tengas miedo de usar Obect^* si el objeto subyacente^está en la pila. así que aquí: SomeFunction (& handle); y la entrada se debe convertir a ManagedClass^* – reuns

Cuestiones relacionadas