2009-08-13 15 views
14

Me he encontrado con este problema de convertir un puntero C++/CLI a un puntero C++ nativo. Aquí está el fondo: Estoy escribiendo una aplicación de formularios de Windows usando C++/CLI. La aplicación realiza llamadas en varias interfaces COM. Al crear una instancia (en el interior de un C++/clase CLR) de un objeto a través de la interfaz COM, i pase en (void**)(&provider) como último argumento a CoCreateInstance, como en:Convertir del puntero C++/CLI al puntero nativo de C++

HRESULT CoCreateInstance(rclsid, pUnkOuter, dwClsContext, riid, (void**)(&provider)); 

Sin embargo, consigo el error del compilador: no se puede convertir de cli::interior_ptr<Type> a void **. He hecho un poco de investigación sobre esto, y parece que es un problema de diferentes tipos de punteros en C++ y C++/CLI. Alguien tiene algún conocimiento sobre esto, y tal vez un consejo sobre cómo se podría solucionar? Gracias por adelantado!

Primero, gracias por toda ayuda!

Como sugirió Freich, traté de usar el pin_ptr, pero esto en cambio hizo que el compilador se quejara de los problemas que se convertían de interior_ptr en pin_ptr. Si en lugar de tratar de usar la interior_ptr como en:

pin_ptr<void *> pinnedPtr = &provider; 
CoCreateInstance(CLSID_MSPRProvider, NULL, CLSCTX_LOCAL_SERVER, IID_IMSPRProvider, (void**)pinnedPtr); 

consigo no pueden convertir de interior_ptr a interior_ptr. Todo se reduce al problema de convertir el interior_ptr en void**. De esta manera: (void**)interiorPtr, donde interiorPtr por supuesto es un interior_ptr. Alguna idea en esto?

Respuesta

10

Creo que tiene que marcar el puntero como 'anclado' (en el código administrado) y luego copiar los bytes a una región de memoria no administrada, y luego usar el puntero a eso. Por ejemplo, aquí hay un trozo de código Una vez me alguna parte que convierte un puntero a un sistema gestionado :: String en un codificación UTF-8 no administrado std :: string:

std::string managedStringToStlString(System::String ^s) 
{ 
    Encoding ^u8 = Encoding::UTF8; 
    array<unsigned char> ^bytes = u8->GetBytes(s); 
    pin_ptr<unsigned char> pinnedPtr = &bytes[0]; 
    return string((char*)pinnedPtr); 
} 

Nota cómo me tengo que ir un puntero 'pinned' a la matriz bytes devuelta por la función GetBytes() y luego transfiérala a char* antes de pasarla al constructor std::string. Creo que esto es necesario para evitar que el subsistema de memoria administrada mueva la matriz bytes en la memoria mientras estoy copiando los bytes en la cadena STL.

En su caso, intente reemplazar

CoCreateInstance(rclsid, pUnkOuter, dwClsContext, riid, (void**)(&provider)); 

con

pin_ptr<void *> pinnedPtr = &provider; 
CoCreateInstance(rclsid, pUnkOuter, dwClsContext, riid, (void**)pinnedPtr); 

y ver si eso funciona.

+0

¡Esto parece ser peligroso! Tuve una situación similar (o la misma) antes: creé un puntero clavado y devolví el puntero nativo (como tú), pero luego el objeto se movió porque la función finalizó y el puntero pinchado fue eliminado, por lo que el objeto ya no estaba inmovilizado y el puntero nativo no es válido Esto puede o no verse durante la depuración, pero seguro que sucederá en su versión de lanzamiento cuando no lo espere. –

+0

@TobiasKnauss el constructor 'std :: string :: string (const char *)' crea una copia de los datos a los que se hace referencia, por lo que está bien si la memoria referenciada ya no está anclada cuando la función finaliza. –

3

Ha pasado bastante tiempo que utilicé C++/CLI, pero creo que tiene que fijar el puntero.

+0

hay una plantilla de conveniencia denominada CLI :: pin_ptr que podría ser lo que necesita el OP, ya que está diseñado para asegurar que un puntero a un objeto administrado no está siendo movido por el recolector de basura. –

3

¿Se espera que la memoria sea válida más allá de la llamada a CoCreateInstance()?

Como aludieron Frerich y Achim, puede obtener un puntero sin formato a la memoria, sin temor a que se reubique la memoria, "fijándola" y obteniendo un puntero interior. Usualmente haces esto con la plantilla pin_ptr (mira la publicación Frerich para ver un ejemplo).

Sin embargo, pin_ptr solo se puede usar deliberadamente en la pila.No puede usarlo como variable miembro o global, y no puede pasarlo como un argumento o valor devuelto. La memoria se desancla cuando deja el alcance.

Entonces, si la memoria solo es necesaria para ser válida durante la llamada a CoCreateInstance(), entonces pin_ptr es el camino a seguir. Si no, entonces tendrá que tomar una copia de la memoria y pasar que a CoCreateInstance()