Bagikan melalui


Cara: Array Marshal menggunakan P/Invoke

Anda dapat memanggil fungsi asli yang menerima string gaya C dengan menggunakan jenis String string CLR saat menggunakan dukungan .NET Framework Platform Invoke (P/Invoke). Kami mendorong Anda untuk menggunakan fitur Interop C++ alih-alih P/Invoke jika memungkinkan. P/Invoke menyediakan sedikit pelaporan kesalahan waktu kompilasi, tidak aman untuk jenis, dan dapat melelahkan untuk diterapkan. Jika API yang tidak dikelola dikemas sebagai DLL dan kode sumber tidak tersedia, P/Invoke adalah satu-satunya opsi. Jika tidak, lihat Menggunakan Interop C++ (Implicit P/Invoke)).

Contoh

Karena array asli dan terkelola ditata secara berbeda dalam memori, berhasil melewatinya di seluruh batas terkelola/tidak terkelola memerlukan konversi, atau marshaling. Artikel ini menunjukkan bagaimana array item sederhana (stabil) dapat diteruskan ke fungsi asli dari kode terkelola.

Seperti halnya marshaling data terkelola/tidak dikelola secara umum, DllImportAttribute atribut digunakan untuk membuat titik masuk terkelola untuk setiap fungsi asli yang digunakan. Dalam fungsi yang mengambil array sebagai argumen, MarshalAsAttribute atribut harus digunakan untuk menentukan cara melakukan marshal data. Dalam contoh berikut, UnmanagedType enumerasi digunakan untuk menunjukkan bahwa array terkelola dinamai sebagai array gaya C.

Kode berikut terdiri dari modul yang tidak dikelola dan terkelola. Modul yang tidak dikelola adalah DLL yang menentukan fungsi yang menerima array bilangan bulat. Modul kedua adalah aplikasi baris perintah terkelola yang mengimpor fungsi ini, tetapi mendefinisikannya dalam hal array terkelola. Ini menggunakan MarshalAsAttribute atribut untuk menentukan bahwa array harus dikonversi ke array asli saat dipanggil.

// 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]);
}

Modul terkelola dikompilasi dengan menggunakan /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]);
}

Tidak ada bagian DLL yang terekspos ke kode terkelola melalui arahan tradisional #include . Bahkan, karena DLL diakses pada runtime saja, masalah dalam fungsi yang diimpor dengan menggunakan DllImportAttribute tidak dapat dideteksi pada waktu kompilasi.

Lihat juga

Menggunakan P/Invoke eksplisit di C++ (DllImport atribut)