Data Marshaling using Managed Code CallingMarshaling Data with Platform Invoke

  • 03/20/2019
  • 5 minutos de lectura
    • .

    • g
    • o
    • O
    • S

Para llamar a funciones exportadas desde una biblioteca no gestionada, a .NET Framework requiere un prototipo de función en código gestionado que represente la función no gestionada.Para llamar a funciones exportadas desde una biblioteca no gestionada, una aplicación .NET Framework requiere un prototipo de función en código gestionado que represente la función no gestionada. Para crear un prototipo que permita que la invocación de la plataforma marshalice los datos correctamente, debes hacer lo siguiente:

  • Aplicar el atributo DllImportAttribute a la función o método estático en el código gestionado.Aplique el atributo DllImportAttribute a la función o método estático en el código gestionado.

  • Sustituya los tipos de datos gestionados por los no gestionados.Sustituir tipos de datos gestionados por tipos de datos no gestionados.

  • Puede utilizar la documentación suministrada con una función no gestionada para construir un prototipo gestionado equivalente aplicando el atributo con sus campos opcionales y sustituyendo tipos de datos gestionados por tipos no gestionados. Para obtener instrucciones sobre cómo aplicar el atributo DllImportAttribute, consulte Consumo de funciones DLL no administradas.

    Esta sección proporciona ejemplos que demuestran cómo crear prototipos de funciones gestionadas para pasar argumentos y recibir valores de retorno de funciones exportadas por bibliotecas no gestionadas. Los ejemplos también demuestran cuándo utilizar el atributo MarshalAsAttribute y la clase Marshal para marshalar explícitamente los datos.

    Tipos de datos de llamada de código no administradoTipos de datos de invocación de plataforma

    La siguiente tabla enumera los tipos de datos utilizados en las API de Windows y las funciones de estilo C. Muchas bibliotecas no gestionadas contienen funciones que pasan estos tipos de datos como parámetros y valores de retorno. La tercera columna enumera el correspondiente tipo de valor incorporado en .NET Framework o la clase que se utiliza en el código gestionado. En algunos casos, puede sustituir el tipo de la tabla por otro del mismo tamaño.

    Tipo no gestionado en las APIs de WindowsTipo no gestionado en las APIs de Windows Tipo de lenguaje C no gestionado . Tipo gestionadoTipo gestionado Descripción
    VOID void Sistema.Void Se aplica a una función que no devuelve un valor.Se aplica a una función que no devuelve un valor.
    HANDLE void * System.IntPtr o System.UIntPtrSystem.IntPtr o System.UIntPtr 32 bits en sistemas operativos Windows de 32 bits, 64 bits en sistemas operativos Windows de 64 bits.32 bits en sistemas operativos Windows de 32 bits, 64 bits en sistemas operativos Windows de 64 bits.
    BYTE unsigned char Sistema.Byte 8 bits8 bits
    SHORT short Sistema.Int16 16 bits16 bits
    WORD unsigned short System.UInt16 16 bits16 bits
    INT int System.Int32 32 bits32 bits
    UINT unsigned int System.UInt32 32 bits32 bits
    LONG long System.Int32 32 bits32 bits
    BOOL long System.Boolean o System.Int32System.Boolean o System.Int32 32 bits32 bits
    DWORD unsigned long System.UInt32 32 bits32 bits ULONG unsigned long System.UInt32 32 bits32 bits CHAR char System.Char Decorer avec ANSI.Decorate with ANSI.
    WCHAR wchar_t System.Char Decorer avec Unicode.Decorate with Unicode.
    LPSTR char * System.String o System.Text.StringBuilderSystem.String o System.Text.StringBuilder Décorer avec ANSI.Decorate with ANSI.
    LPCSTR const char * System.String o System.Text.StringBuilderSystem.String o System.Text.StringBuilder Décorer avec ANSI.Decorate with ANSI.
    LPWSTR wchar_t * System.String o System.Text.StringBuilderSystem.String o System.Text.StringBuilder Décorer avec Unicode.Decorate with Unicode.
    LPCWSTR const wchar_t * System.String o System.Text.StringBuilderSystem.String o System.Text.StringBuilder Décorer avec Unicode.Decorate with Unicode.
    FLOAT float System.Single 32 bits32 bits
    DOUBLE double System.Double 64 bits64 bits

    Para los tipos correspondientes en Visual Basic, C# y C++, consulte Introducción a la biblioteca de clases .NET Framework.Para los tipos correspondientes en Visual Basic, C# y C++, consulte la Introducción a la biblioteca de clases .NET Framework.

    PinvokeLib.dllPinvokeLib.dll

    El siguiente código define las funciones de biblioteca proporcionadas por Pinvoke.dll.El siguiente código define las funciones de biblioteca proporcionadas por Pinvoke.dll. De nombreux exemples décrits dans cette section appellent cette bibliothèque.Muchos ejemplos descritos en esta sección llaman a esta biblioteca.

    EjemploEjemplo

// PInvokeLib.cpp : Defines the entry point for the DLL application.//#define PINVOKELIB_EXPORTS#include "PInvokeLib.h"#include <strsafe.h>#include <objbase.h>#include <stdio.h>#pragma comment(lib,"ole32.lib")BOOL APIENTRY DllMain( HANDLE hModule, DWORD ul_reason_for_call, LPVOID lpReserved ){ switch (ul_reason_for_call) { case DLL_PROCESS_ATTACH: case DLL_THREAD_ATTACH: case DLL_THREAD_DETACH: case DLL_PROCESS_DETACH: break; } return TRUE;}//******************************************************************// This is the constructor of a class that has been exported.CTestClass::CTestClass(){ m_member = 1;}int CTestClass::DoSomething( int i ){ return i*i + m_member;}PINVOKELIB_API CTestClass* CreateTestClass(){ return new CTestClass();}PINVOKELIB_API void DeleteTestClass( CTestClass* instance ){ delete instance;}//******************************************************************PINVOKELIB_API int TestArrayOfInts( int* pArray, int size ){ int result = 0; for ( int i = 0; i < size; i++ ) { result += pArray; pArray += 100; } return result;}//******************************************************************PINVOKELIB_API int TestRefArrayOfInts( int** ppArray, int* pSize ){ int result = 0; // CoTaskMemAlloc must be used instead of the new operator // because code on the managed side will call Marshal.FreeCoTaskMem // to free this memory. int* newArray = (int*)CoTaskMemAlloc( sizeof(int) * 5 ); for ( int i = 0; i < *pSize; i++ ) { result += (*ppArray); } for ( int j = 0; j < 5; j++ ) { newArray = (*ppArray) + 100; } CoTaskMemFree( *ppArray ); *ppArray = newArray; *pSize = 5; return result;}//******************************************************************PINVOKELIB_API int TestMatrixOfInts( int pMatrix, int row ){ int result = 0; for ( int i = 0; i < row; i++ ) { for ( int j = 0; j < COL_DIM; j++ ) { result += pMatrix; pMatrix += 100; } } return result;}//******************************************************************PINVOKELIB_API int TestArrayOfStrings( char* ppStrArray, int count ){ int result = 0; STRSAFE_LPSTR temp; size_t len; const size_t alloc_size = sizeof(char) * 10; for ( int i = 0; i < count; i++ ) { len = 0; StringCchLengthA( ppStrArray, STRSAFE_MAX_CCH, &len ); result += len; temp = (STRSAFE_LPSTR)CoTaskMemAlloc( alloc_size ); StringCchCopyA( temp, alloc_size, (STRSAFE_LPCSTR)"123456789" ); // CoTaskMemFree must be used instead of delete to free memory. CoTaskMemFree( ppStrArray ); ppStrArray = (char *) temp; } return result;}//******************************************************************PINVOKELIB_API int TestArrayOfStructs( MYPOINT* pPointArray, int size ){ int result = 0; MYPOINT* pCur = pPointArray; for ( int i = 0; i < size; i++ ) { result += pCur->x + pCur->y; pCur->y = 0; pCur++; } return result;}//******************************************************************PINVOKELIB_API int TestStructInStruct( MYPERSON2* pPerson2 ){ size_t len = 0; StringCchLengthA( pPerson2->person->last, STRSAFE_MAX_CCH, &len ); len = sizeof(char) * ( len + 2 ) + 1; STRSAFE_LPSTR temp = (STRSAFE_LPSTR)CoTaskMemAlloc( len ); StringCchCopyA( temp, len, (STRSAFE_LPSTR)"Mc" ); StringCbCatA( temp, len, (STRSAFE_LPSTR)pPerson2->person->last ); CoTaskMemFree( pPerson2->person->last ); pPerson2->person->last = (char *)temp; return pPerson2->age;}//******************************************************************PINVOKELIB_API int TestArrayOfStructs2( MYPERSON* pPersonArray, int size ){ int result = 0; MYPERSON* pCur = pPersonArray; STRSAFE_LPSTR temp; size_t len; for ( int i = 0; i < size; i++ ) { len = 0; StringCchLengthA( pCur->first, STRSAFE_MAX_CCH, &len ); len++; result += len; len = 0; StringCchLengthA( pCur->last, STRSAFE_MAX_CCH, &len ); len++; result += len; len = sizeof(char) * ( len + 2 ); temp = (STRSAFE_LPSTR)CoTaskMemAlloc( len ); StringCchCopyA( temp, len, (STRSAFE_LPCSTR)"Mc" ); StringCbCatA( temp, len, (STRSAFE_LPCSTR)pCur->last ); result += 2; // CoTaskMemFree must be used instead of delete to free memory. CoTaskMemFree( pCur->last ); pCur->last = (char *)temp; pCur++; } return result;}//******************************************************************PINVOKELIB_API void TestStructInStruct3( MYPERSON3 person3 ){ printf( "\n\nperson passed by value:\n" ); printf( "first = %s last = %s age = %i\n\n", person3.person.first, person3.person.last, person3.age );}//*********************************************************************PINVOKELIB_API void TestUnion( MYUNION u, int type ){ if ( ( type != 1 ) && ( type != 2 ) ) { return; } if ( type == 1 ) { printf( "\n\ninteger passed: %i", u.i ); } else if ( type == 2 ) { printf( "\n\ndouble passed: %f", u.d ); }}//******************************************************************PINVOKELIB_API void TestUnion2( MYUNION2 u, int type ){ if ( ( type != 1 ) && ( type != 2 ) ) { return; } if ( type == 1 ) { printf( "\n\ninteger passed: %i", u.i ); } else if ( type == 2 ) { printf( "\n\nstring passed: %s", u.str ); }}//******************************************************************PINVOKELIB_API void TestCallBack( FPTR pf, int value ){ printf( "\nReceived value: %i", value ); printf( "\nPassing to callback..." ); bool res = (*pf)(value); if ( res ) { printf( "Callback returned true.\n" ); } else { printf( "Callback returned false.\n" ); }}//******************************************************************PINVOKELIB_API void TestCallBack2( FPTR2 pf2, char* value ){ printf( "\nReceived value: %s", value ); printf( "\nPassing to callback..." ); bool res = (*pf2)(value); if ( res ) { printf( "Callback2 returned true.\n" ); } else { printf( "Callback2 returned false.\n" ); }}//******************************************************************PINVOKELIB_API void TestStringInStruct( MYSTRSTRUCT* pStruct ){ wprintf( L"\nUnicode buffer content: %s\n", pStruct->buffer ); // Assuming that the buffer is big enough. StringCbCatW( pStruct->buffer, pStruct->size, (STRSAFE_LPWSTR)L"++" );}//******************************************************************PINVOKELIB_API void TestStringInStructAnsi( MYSTRSTRUCT2* pStruct ){ printf( "\nAnsi buffer content: %s\n", pStruct->buffer ); // Assuming that the buffer is big enough. StringCbCatA( (STRSAFE_LPSTR) pStruct->buffer, pStruct->size, (STRSAFE_LPSTR)"++" );}//******************************************************************PINVOKELIB_API void TestOutArrayOfStructs( int* pSize, MYSTRSTRUCT2** ppStruct ){ const int cArraySize = 5; *pSize = 0; *ppStruct = (MYSTRSTRUCT2*)CoTaskMemAlloc( cArraySize * sizeof( MYSTRSTRUCT2 )); if ( ppStruct != NULL ) { MYSTRSTRUCT2* pCurStruct = *ppStruct; LPSTR buffer; *pSize = cArraySize; STRSAFE_LPCSTR teststr = "***"; size_t len = 0; StringCchLengthA(teststr, STRSAFE_MAX_CCH, &len); len++; for ( int i = 0; i < cArraySize; i++, pCurStruct++ ) { pCurStruct->size = len; buffer = (LPSTR)CoTaskMemAlloc( len ); StringCchCopyA( buffer, len, teststr ); pCurStruct->buffer = (char *)buffer; } }}//************************************************************************PINVOKELIB_API char * TestStringAsResult(){ const size_t alloc_size = 64; STRSAFE_LPSTR result = (STRSAFE_LPSTR)CoTaskMemAlloc( alloc_size ); STRSAFE_LPCSTR teststr = "This is return value"; StringCchCopyA( result, alloc_size, teststr ); return (char *) result;}//************************************************************************PINVOKELIB_API void SetData( DataType typ, void* object ){ switch ( typ ) { case DT_I2: printf( "Short %i\n", *((short*)object) ); break; case DT_I4: printf( "Long %i\n", *((long*)object) ); break; case DT_R4: printf( "Float %f\n", *((float*)object) ); break; case DT_R8: printf( "Double %f\n", *((double*)object) ); break; case DT_STR: printf( "String %s\n", (char*)object ); break; default: printf( "Unknown type" ); break; }}//************************************************************************PINVOKELIB_API void TestArrayInStruct( MYARRAYSTRUCT* pStruct ){ pStruct->flag = true; pStruct->vals += 100; pStruct->vals += 100; pStruct->vals += 100;}

// PInvokeLib.h : The header file for the DLL application.//#pragma once#define WIN32_LEAN_AND_MEAN#include <windows.h>// The following ifdef block is the standard way of creating macros which make exporting// from a DLL simpler. All files within this DLL are compiled with the PINVOKELIB_EXPORTS// symbol defined on the command line. this symbol should not be defined on any project// that uses this DLL. This way any other project whose source files include this file see// PINVOKELIB_API functions as being imported from a DLL, wheras this DLL sees symbols// defined with this macro as being exported.#ifdef PINVOKELIB_EXPORTS#define PINVOKELIB_API __declspec(dllexport)#else#define PINVOKELIB_API __declspec(dllimport)#endif// Define the test structurestypedef struct _MYPOINT{ int x; int y;} MYPOINT;typedef struct _MYPERSON{ char* first; char* last;} MYPERSON;typedef struct _MYPERSON2{ MYPERSON* person; int age;} MYPERSON2;typedef struct _MYPERSON3{ MYPERSON person; int age;} MYPERSON3;union MYUNION{ int i; double d;};union MYUNION2{ int i; char str;};typedef struct _MYSTRSTRUCT{ wchar_t* buffer; UINT size;} MYSTRSTRUCT;typedef struct _MYSTRSTRUCT2{ char* buffer; UINT size;} MYSTRSTRUCT2;typedef struct _MYARRAYSTRUCT{ bool flag; int vals;} MYARRAYSTRUCT;// constants and pointer definitionsconst int COL_DIM = 5;typedef bool (CALLBACK *FPTR)( int i );typedef bool (CALLBACK *FPTR2)( char* str );// Data type codesenum DataType{ DT_I2 = 1, DT_I4, DT_R4, DT_R8, DT_STR};// This is an exported class.class PINVOKELIB_API CTestClass{public: CTestClass( void ); int DoSomething( int i );private: int m_member;};// Exports for PInvokeLib.dll#ifdef __cplusplusextern "C"{#endifPINVOKELIB_API CTestClass* CreateTestClass();PINVOKELIB_API void DeleteTestClass( CTestClass* instance );PINVOKELIB_API int TestArrayOfInts( int* pArray, int size );PINVOKELIB_API int TestRefArrayOfInts( int** ppArray, int* pSize );PINVOKELIB_API int TestMatrixOfInts( int pMatrix, int row );PINVOKELIB_API int TestArrayOfStrings( char* ppStrArray, int size );PINVOKELIB_API int TestArrayOfStructs( MYPOINT* pPointArray, int size );PINVOKELIB_API int TestArrayOfStructs2( MYPERSON* pPersonArray, int size );PINVOKELIB_API int TestStructInStruct( MYPERSON2* pPerson2 );PINVOKELIB_API void TestStructInStruct3( MYPERSON3 person3 );PINVOKELIB_API void TestUnion( MYUNION u, int type );PINVOKELIB_API void TestUnion2( MYUNION2 u, int type );PINVOKELIB_API void TestCallBack( FPTR pf, int value );PINVOKELIB_API void TestCallBack2( FPTR2 pf2, char* value );// buffer is an in/out paramPINVOKELIB_API void TestStringInStruct( MYSTRSTRUCT* pStruct );// buffer is in/out paramPINVOKELIB_API void TestStringInStructAnsi( MYSTRSTRUCT2* pStruct );PINVOKELIB_API void TestOutArrayOfStructs( int* pSize, MYSTRSTRUCT2** ppStruct );PINVOKELIB_API char* TestStringAsResult();PINVOKELIB_API void SetData( DataType typ, void* object );PINVOKELIB_API void TestArrayInStruct( MYARRAYSTRUCT* pStruct );#ifdef __cplusplus}#endif

Deja una respuesta

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *