Cómo: serializar matrices mediante P/Invoke
Puede llamar a funciones nativas que aceptan cadenas de estilo C mediante el tipo de cadena CLR String cuando se usa compatibilidad con la invocación de plataforma de .NET Framework (P/Invoke). Le recomendamos que use las características de interoperabilidad de C++ en lugar de P/Invoke cuando sea posible. P/Invoke proporciona pocos informes de errores en tiempo de compilación, no es con seguridad de tipos e implementarlo puede ser tedioso. Si la API no administrada se empaqueta como una DLL y el código fuente no está disponible, P/Invoke es la única opción. De lo contrario, vea Utilizar la interoperabilidad de C++ (PInvoke implícito).
Ejemplo
Dado que las matrices nativas y administradas se diseñan de forma diferente en la memoria, pasarlas correctamente a través del límite administrado o no administrado requiere conversión o serialización. En este artículo se muestra cómo se puede pasar una matriz de elementos simples (blitables) a funciones nativas desde código administrado.
Como sucede con las referencias de datos administradas o no administradas en general, el atributo DllImportAttribute se usa para crear un punto de entrada administrado para cada función nativa que se usa. En las funciones que toman matrices como argumentos, el atributo MarshalAsAttribute debe usarse para especificar cómo serializar los datos. En el ejemplo siguiente, la enumeración UnmanagedType se usa para indicar que la matriz administrada se serializa como una matriz de estilo C.
El código siguiente consta de un módulo administrado y uno no administrado. El módulo no administrado es un archivo DLL que define una función que acepta una matriz de enteros. El segundo módulo es una aplicación de línea de comandos administrada que importa esta función, pero la define en términos de una matriz administrada. Usa el atributo MarshalAsAttribute para especificar que la matriz se debe convertir en una matriz nativa cuando se lo llama.
// TraditionalDll4.cpp
// compile with: /LD /EHsc
#include <iostream>
#define TRADITIONALDLL_EXPORTS
#ifdef TRADITIONALDLL_EXPORTS
#define TRADITIONALDLL_API __declspec(dllexport)
#else
#define TRADITIONALDLL_API __declspec(dllimport)
#endif
extern "C" {
TRADITIONALDLL_API void TakesAnArray(int len, int[]);
}
void TakesAnArray(int len, int a[]) {
printf_s("[unmanaged]\n");
for (int i=0; i<len; i++)
printf("%d = %d\n", i, a[i]);
}
El módulo administrado se compila mediante /clr
.
// MarshalBlitArray.cpp
// compile with: /clr
using namespace System;
using namespace System::Runtime::InteropServices;
value struct TraditionalDLL {
[DllImport("TraditionalDLL4.dll")]
static public void TakesAnArray(
int len,[MarshalAs(UnmanagedType::LPArray)]array<int>^);
};
int main() {
array<int>^ b = gcnew array<int>(3);
b[0] = 11;
b[1] = 33;
b[2] = 55;
TraditionalDLL::TakesAnArray(3, b);
Console::WriteLine("[managed]");
for (int i=0; i<3; i++)
Console::WriteLine("{0} = {1}", i, b[i]);
}
Ninguna parte de la DLL se expone al código administrado mediante la directiva tradicional #include
. De hecho, solo se accede al archivo DLL en runtime, por lo que los problemas en las funciones importadas mediante DllImportAttribute no se pueden detectar en tiempo de compilación.
Consulte también
Utilizar un elemento PInvoke explícito en C++ (Atributo DllImport
)