Nota
El acceso a esta página requiere autorización. Puede intentar iniciar sesión o cambiar directorios.
El acceso a esta página requiere autorización. Puede intentar cambiar los directorios.
Las funciones que se implementan en archivos DLL no administrados se pueden llamar desde código administrado mediante la funcionalidad de invocación de plataforma (P/Invoke). Si el código fuente del archivo DLL no está disponible, P/Invoke es la única opción para interoperar. Pero a diferencia de otros lenguajes .NET, Visual C++ proporciona una alternativa a P/Invoke. Para más información, vea Utilizar la interoperabilidad de C++ (PInvoke implícito) y Cómo: Calcular las referencias de punteros incrustados mediante la interoperabilidad de C++.
Ejemplo
Pasar estructuras al código nativo requiere que se cree una estructura administrada equivalente en términos de diseño de datos a la estructura nativa. Pero las estructuras que contienen punteros requieren un control especial. Para cada puntero incrustado en la estructura nativa, la versión administrada de la estructura debe contener una instancia del tipo IntPtr. Además, la memoria de estas instancias debe asignarse, inicializarse y liberarse explícitamente mediante los métodos AllocCoTaskMem, StructureToPtr y FreeCoTaskMem.
El código siguiente consta de un módulo administrado y uno no administrado. El módulo no administrado es una DLL que define una función que acepta una estructura denominada ListString
que contiene un puntero, y una función denominada TakesListStruct
.
// TraditionalDll6.cpp
// compile with: /EHsc /LD
#include <stdio.h>
#include <iostream>
#define TRADITIONALDLL_EXPORTS
#ifdef TRADITIONALDLL_EXPORTS
#define TRADITIONALDLL_API __declspec(dllexport)
#else
#define TRADITIONALDLL_API __declspec(dllimport)
#endif
#pragma pack(push, 8)
struct ListStruct {
int count;
double* item;
};
#pragma pack(pop)
extern "C" {
TRADITIONALDLL_API void TakesListStruct(ListStruct);
}
void TakesListStruct(ListStruct list) {
printf_s("[unmanaged] count = %d\n", list.count);
for (int i=0; i<list.count; i++)
printf_s("array[%d] = %f\n", i, list.item[i]);
}
El módulo administrado es una aplicación de línea de comandos que importa la función TakesListStruct
y define una estructura denominada MListStruct
equivalente a ListStruct
nativo, salvo que double*
se representa con una instancia de IntPtr. Antes de llamar TakesListStruct
, la función main
asigna e inicializa la memoria a la que hace referencia este campo.
// EmbeddedPointerMarshalling.cpp
// compile with: /clr
using namespace System;
using namespace System::Runtime::InteropServices;
[StructLayout(LayoutKind::Sequential, Pack=8)]
value struct MListStruct {
int count;
IntPtr item;
};
value struct TraditionalDLL {
[DllImport("TraditionalDLL6.dll")]
static public void TakesListStruct(MListStruct);
};
int main() {
array<double>^ parray = gcnew array<double>(10);
Console::WriteLine("[managed] count = {0}", parray->Length);
Random^ r = gcnew Random();
for (int i=0; i<parray->Length; i++) {
parray[i] = r->NextDouble() * 100.0;
Console::WriteLine("array[{0}] = {1}", i, parray[i]);
}
int size = Marshal::SizeOf(double::typeid);
MListStruct list;
list.count = parray->Length;
list.item = Marshal::AllocCoTaskMem(size * parray->Length);
for (int i=0; i<parray->Length; i++) {
IntPtr t = IntPtr(list.item.ToInt32() + i * size);
Marshal::StructureToPtr(parray[i], t, false);
}
TraditionalDLL::TakesListStruct( list );
Marshal::FreeCoTaskMem(list.item);
}
Ninguna parte del archivo 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
)