Cara: Penunjuk yang disematkan Marshal menggunakan P/Invoke
Fungsi yang diimplementasikan dalam DLL yang tidak dikelola dapat dipanggil dari kode terkelola menggunakan fungsionalitas Platform Invoke (P/Invoke). Jika kode sumber untuk DLL tidak tersedia, P/Invoke adalah satu-satunya opsi untuk mengoperasikan. Namun, tidak seperti bahasa .NET lainnya, Visual C++ menyediakan alternatif untuk P/Invoke. Untuk informasi selengkapnya, lihat Menggunakan Interop C++ (Implisit P/Invoke) dan Cara: Pointer tersemat Marshal menggunakan Interop C++.
Contoh
Meneruskan struktur ke kode asli mengharuskan struktur terkelola yang setara dalam hal tata letak data ke struktur asli dibuat. Namun, struktur yang berisi pointer memerlukan penanganan khusus. Untuk setiap penunjuk yang disematkan dalam struktur asli, versi struktur terkelola harus berisi instans jenis IntPtr . Selain itu, memori untuk instans ini harus dialokasikan, diinisialisasi, dan dirilis secara eksplisit menggunakan AllocCoTaskMemmetode , StructureToPtr, dan FreeCoTaskMem .
Kode berikut terdiri dari modul yang tidak dikelola dan terkelola. Modul yang tidak dikelola adalah DLL yang mendefinisikan fungsi yang menerima struktur yang disebut ListString
yang berisi penunjuk, dan fungsi yang disebut 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]);
}
Modul terkelola adalah aplikasi baris perintah yang mengimpor TakesListStruct
fungsi dan mendefinisikan struktur yang disebut MListStruct
setara dengan aslinya ListStruct
kecuali bahwa double*
diwakili dengan IntPtr instans. Sebelum memanggil TakesListStruct
, main
fungsi mengalokasikan dan menginisialisasi memori yang dirujuk bidang ini.
// 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);
}
Tidak ada bagian DLL yang diekspos ke kode terkelola menggunakan arahan tradisional #include
. Bahkan, DLL diakses pada runtime saja, sehingga masalah dalam fungsi yang diimpor dengan menggunakan DllImportAttribute tidak dapat dideteksi pada waktu kompilasi.
Baca juga
Saran dan Komentar
https://aka.ms/ContentUserFeedback.
Segera hadir: Sepanjang tahun 2024 kami akan menghentikan penggunaan GitHub Issues sebagai mekanisme umpan balik untuk konten dan menggantinya dengan sistem umpan balik baru. Untuk mengetahui informasi selengkapnya, lihat:Kirim dan lihat umpan balik untuk