使用平台叫用封送處理資料

若要呼叫從 Unmanaged 程式庫匯出的函式,.NET Framework 應用程式需要代表此 Unmanaged 函式之 Managed 程式碼中的函式原型。 若要建立使平台叫用正確地封送處理資料的原型,您必須執行下列動作:

  • DllImportAttribute 屬性套用至使用 Managed 程式碼的靜態函式或方法。

  • 將 Unmanaged 資料類型替代為 Managed 資料類型。

您可以使用 Unmanaged 函式所提供的文件,以選擇性欄位套用屬性,並且將 Unmanaged 資料類型替代為 Managed 資料類型,來建構對等的 Managed 原型。 如需如何套用 DllImportAttribute 的指示,請參閱使用 Unmanaged DLL 函式

本節提供範例,示範如何建立 Managed 函式原型,供傳遞引數至函式和接收 Unmanaged 程式庫所匯出函式的傳回值。 此範例也會示範使用 MarshalAsAttribute 屬性和 Marshal 類別來明確封送處理資料的時機。

平台叫用資料類型

下表列出 Windows API 和 C 樣式函式中所使用的資料類型。 許多 Unmanaged 程式庫包含傳遞資料類型做為參數和傳回值的函式。 第三個行列出對應的 .NET Framework 內建實值類型或您在 Managed 程式碼中使用的類別。 在某些情況下,您可將本表格中所列的類型取代為相同大小的類型。

Windows API 中的 Unmanaged 類型 Unmanaged C 語言類型 Managed 類型 描述
VOID void System.Void 套用至未傳回值的函式。
HANDLE void * System.IntPtrSystem.UIntPtr 在 32 位元 Windows 作業系統上為 32 位元,在 64 位元 Windows 作業系統上為 64 位元。
BYTE unsigned char System.Byte 8 位元
SHORT short System.Int16 16 位元
WORD unsigned short System.UInt16 16 位元
INT int System.Int32 32 位元
UINT unsigned int System.UInt32 32 位元
LONG long System.Int32 32 位元
BOOL long System.BooleanSystem.Int32 32 位元
DWORD unsigned long System.UInt32 32 位元
ULONG unsigned long System.UInt32 32 位元
CHAR char System.Char 使用 ANSI 裝飾。
WCHAR wchar_t System.Char 使用 Unicode 裝飾。
LPSTR char * System.StringSystem.Text.StringBuilder 使用 ANSI 裝飾。
LPCSTR const char * System.StringSystem.Text.StringBuilder 使用 ANSI 裝飾。
LPWSTR wchar_t * System.StringSystem.Text.StringBuilder 使用 Unicode 裝飾。
LPCWSTR const wchar_t * System.StringSystem.Text.StringBuilder 使用 Unicode 裝飾。
FLOAT float System.Single 32 位元
DOUBLE double System.Double 64 位元

如需 Visual Basic、C# 和 C++ 中的對應類型,請參閱 .NET Framework 類別庫簡介

PinvokeLib.dll

下列程式碼定義 Pinvoke.dll 所提供的程式庫函式。 本節所描述的許多範例會呼叫此程式庫。

範例

// 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[ i ];
        pArray[i] += 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)[i];
    }

    for ( int j = 0; j < 5; j++ )
    {
        newArray[j] = (*ppArray)[j] + 100;
    }

    CoTaskMemFree( *ppArray );
    *ppArray = newArray;
    *pSize = 5;

    return result;
}

//******************************************************************
PINVOKELIB_API int TestMatrixOfInts( int pMatrix[][COL_DIM], int row )
{
    int result = 0;

    for ( int i = 0; i < row; i++ )
    {
        for ( int j = 0; j < COL_DIM; j++ )
        {
            result += pMatrix[i][j];
            pMatrix[i][j] += 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[i], 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[i] );
       ppStrArray[i] = (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[0] += 100;
    pStruct->vals[1] += 100;
    pStruct->vals[2] += 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 structures

typedef 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[128];
};

typedef struct _MYSTRSTRUCT
{
    wchar_t* buffer;
    UINT size;
} MYSTRSTRUCT;

typedef struct _MYSTRSTRUCT2
{
    char* buffer;
    UINT size;
} MYSTRSTRUCT2;

typedef struct _MYARRAYSTRUCT
{
    bool flag;
    int vals[3];
} MYARRAYSTRUCT;

// constants and pointer definitions

const int COL_DIM = 5;

typedef bool (CALLBACK *FPTR)( int i );

typedef bool (CALLBACK *FPTR2)( char* str );

// Data type codes
enum 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 __cplusplus
extern "C"
{
#endif

PINVOKELIB_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[][COL_DIM], 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 param
PINVOKELIB_API void TestStringInStruct( MYSTRSTRUCT* pStruct );

// buffer is in/out param
PINVOKELIB_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

若要從受控程式碼呼叫程式庫函式,請先針對您想要叫用的每個函式實作受控原型。 如果非受控程式碼使用任何自訂類型,您也必須在受控程式碼中宣告這些類型。
使用 DllImportAttribute 屬性裝飾原型。

下列程式碼顯示原型範例:

// Managed prototype for TestingStructInStruct, which is declared and defined in an unmanaged library.
[DllImport("..\\LIB\\PinvokeLib.dll", CallingConvention = CallingConvention.Cdecl)]
internal static extern int TestStructInStruct(ref MyPerson2 person2);

如需詳細資訊和範例,請參閱下列文章: