Usar la interoperabilidad de C++ (PInvoke implícito)
A diferencia de otros lenguajes de .NET, Visual C++ cuenta con compatibilidad de interoperabilidad que permite que haya código administrado y no administrado en la misma aplicación, e incluso en el mismo archivo (con las directivas pragma managed, unmanaged). De este modo, los desarrolladores de Visual C++ pueden integrar la funcionalidad de .NET en las aplicaciones de Visual C++ existentes sin que esto afecte al resto de la aplicación.
También se puede llamar a funciones no administradas desde una operación de compilación administrada mediante dllexport, dllimport.
PInvoke implícito es útil cuando no es necesario especificar cómo se van a calcular las referencias de los parámetros de una función ni cualquiera de los otros detalles que se pueden especificar cuando se llama explícitamente a DllImportAttribute.
Visual C++ proporciona dos formas de interoperabilidad para las funciones administradas y no administradas:
.NET Framework admite PInvoke explícito, que está disponible en la mayoría de los lenguajes de .NET. Pero, como su propio nombre indica, la interoperabilidad de C++ es específica de Visual C++.
Interoperabilidad de C++
La interoperabilidad de C++ proporciona una mejor seguridad de tipos y, por lo general, es menos tediosa de implementar. Sin embargo, la interoperabilidad de C++ no es una opción si el código fuente no administrado no está disponible, o para proyectos multiplataforma.
Interoperabilidad COM de C++
Las características de interoperabilidad admitidas por Visual C++ ofrecen una ventaja concreta con respecto a otros lenguajes de .NET en lo que se refiere a la interoperabilidad con componentes COM. En lugar de limitarse a las restricciones de TlbImp.exe (Importador de la biblioteca de tipos) de .NET Framework, como la compatibilidad limitada para tipos de datos y la exposición obligatoria de cada miembro de cada interfaz COM, la interoperabilidad de C++ permite el acceso a voluntad a componentes COM y no requiere ensamblados de interoperabilidad independientes. A diferencia de Visual Basic y C#, Visual C++ puede usar objetos COM directamente mediante los mecanismos COM habituales (como CoCreateInstance y QueryInterface). Esto es posible debido a las características de interoperabilidad de C++ que hacen que el compilador inserte automáticamente el código de transición para pasar de funciones administradas a funciones no administradas y viceversa.
Con la interoperabilidad de C++, los componentes COM se pueden usar como se usan normalmente o se pueden encapsular dentro de clases de C++. Estas clases contenedoras se denominan contenedor RCW, o CRCW, y tienen dos ventajas sobre el uso de COM directamente en el código de la aplicación:
La clase resultante se puede usar desde lenguajes distintos de Visual C++.
Los detalles de la interfaz COM se pueden ocultar en el código de cliente administrado. Los tipos de datos de .NET se pueden usar en lugar de tipos nativos y los detalles de las referencias de datos se pueden realizar de forma transparente dentro del CRCW.
Independientemente de si COM se usa directamente o a través de un CRCW, los tipos de argumentos distintos de los tipos simples que se pueden transferir en bloque de bits deben serializarse.
Tipos que pueden transferirse en bloque de bits
Para las API no administradas que usan tipos intrínsecos simples (vea Tipos que pueden o que no pueden transferirse en bloque de bits), no se requiere una codificación especial porque estos tipos de datos tienen la misma representación en memoria, pero los tipos de datos más complejos requieren el cálculo de referencias de datos explícito. Para ver un ejemplo, consulte Cómo: Llamar a archivos DLL nativos desde el código administrado mediante PInvoke.
Ejemplo
// vcmcppv2_impl_dllimp.cpp
// compile with: /clr:pure user32.lib
using namespace System::Runtime::InteropServices;
// Implicit DLLImport specifying calling convention
extern "C" int __stdcall MessageBeep(int);
// explicit DLLImport needed here to use P/Invoke marshalling because
// System::String ^ is not the type of the first parameter to printf
[DllImport("msvcrt.dll", EntryPoint = "printf", CallingConvention = CallingConvention::Cdecl, CharSet = CharSet::Ansi)]
// or just
// [DllImport("msvcrt.dll")]
int printf(System::String ^, ...);
int main() {
// (string literals are System::String by default)
printf("Begin beep\n");
MessageBeep(100000);
printf("Done\n");
}
Begin beep
Done
En esta sección
Cómo: Serializar cadenas ANSI mediante la interoperabilidad de C++
Cómo: Serializar cadenas Unicode mediante la interoperabilidad de C++
Cómo: Serializar cadenas COM mediante la interoperabilidad de C++
Cómo: Serializar estructuras mediante la interoperabilidad de C++
Cómo: Serializar matrices mediante la interoperabilidad de C++
Cómo: Serializar devoluciones de llamadas y delegados mediante la interoperabilidad de C++
Cómo: Serializar punteros insertados mediante la interoperabilidad de C++
Cómo: Cargar recursos no administrados en una matriz de bytes
Cómo: Modificar la clase de referencia en una función nativa
Cómo: Agregar un archivo DLL nativo a la memoria caché global de ensamblados
Cómo: Mantener la referencia a un tipo de valor en un tipo nativo
Cómo: Mantener una referencia a objeto en la memoria no administrada
Para obtener información sobre cómo utilizar delegados en un escenario de interoperabilidad, vea delegate (extensiones de componente de C++).