Membuat Prototipe dalam Kode Aman
Topik ini menjelaskan cara mengakses fungsi yang tidak terkelola dan memperkenalkan beberapa bidang atribut yang membuat anotasi definisi metode dalam kode aman. Misalnya yang menunjukkan cara membuat . Deklarasi berbasis NET yang akan digunakan dengan pemanggilan platform, lihat Menyusun Data dengan Platform Invoke.
Sebelum Anda dapat mengakses fungsi DLL yang tidak terkelola dari kode aman, Anda perlu mengetahui nama fungsi dan nama DLL yang mengekspornya. Dengan informasi ini, Anda dapat mulai menulis definisi terkelola untuk fungsi tidak terkelola yang diimplementasikan dalam DLL. Selain itu, Anda dapat menyesuaikan cara platform memanggil membuat fungsi dan menyusun data ke dan dari fungsi.
Catatan
Windows fungsi API yang mengalokasikan string memungkinkan Anda membebaskan string dengan menggunakan metode seperti LocalFree
. Pemanggilan platform menangani parameter tersebut secara berbeda. Untuk panggilan pemanggilan platform, buat parameter sebagai jenis IntPtr
, bukan jenis String
. Gunakan metode yang disediakan oleh kelas System.Runtime.InteropServices.Marshal untuk mengonversi jenis menjadi string secara manual dan membebaskannya secara manual.
Dasar-Dasar Deklarasi
Definisi terkelola untuk fungsi yang tidak terkelola bergantung pada bahasa, seperti yang Anda lihat dalam contoh berikut. Untuk contoh kode yang lebih lengkap, lihat Contoh Pemanggilan Platform.
Friend Class NativeMethods
Friend Declare Auto Function MessageBox Lib "user32.dll" (
ByVal hWnd As IntPtr,
ByVal lpText As String,
ByVal lpCaption As String,
ByVal uType As UInteger) As Integer
End Class
Untuk menerapkan bidang DllImportAttribute.BestFitMapping, DllImportAttribute.CallingConvention, DllImportAttribute.ExactSpelling, DllImportAttribute.PreserveSig, DllImportAttribute.SetLastError, atau DllImportAttribute.ThrowOnUnmappableChar ke deklarasi Visual Basic, Anda harus menggunakan atribut DllImportAttribute sebagai ganti pernyataan Declare
.
Imports System.Runtime.InteropServices
Friend Class NativeMethods
<DllImport("user32.dll", CharSet:=CharSet.Auto)>
Friend Shared Function MessageBox(
ByVal hWnd As IntPtr,
ByVal lpText As String,
ByVal lpCaption As String,
ByVal uType As UInteger) As Integer
End Function
End Class
using System;
using System.Runtime.InteropServices;
internal static class NativeMethods
{
[DllImport("user32.dll")]
internal static extern int MessageBox(
IntPtr hWnd, string lpText, string lpCaption, uint uType);
}
using namespace System;
using namespace System::Runtime::InteropServices;
[DllImport("user32.dll")]
extern "C" int MessageBox(
IntPtr hWnd, String* lpText, String* lpCaption, unsigned int uType);
Menyesuaikan Definisi
Baik Anda mengaturnya secara eksplisit atau tidak, bidang atribut sedang bekerja menentukan perilaku kode aman. Pemanggilan platform beroperasi sesuai dengan nilai default yang ditetapkan pada berbagai bidang yang ada sebagai metadata dalam perakitan. Anda dapat mengubah perilaku default ini dengan menyesuaikan nilai satu atau beberapa bidang. Dalam banyak kasus, Anda menggunakan DllImportAttribute untuk menetapkan nilai.
Tabel berikut mencantumkan kumpulan lengkap bidang atribut yang berkaitan dengan pemanggilan platform. Untuk setiap bidang, tabel menyertakan nilai default dan tautan ke informasi tentang cara menggunakan bidang ini untuk menentukan fungsi DLL yang tidak terkelola.
Bidang | Deskripsi |
---|---|
BestFitMapping | Mengaktifkan atau menonaktifkan pemetaan yang paling sesuai. |
CallingConvention | Menentukan konvensi panggilan yang akan digunakan dalam argumen metode penerusan. Defaultnya adalah WinAPI , yang sesuai dengan __stdcall untuk platform berbasis Intel 32-bit. |
CharSet | Mengontrol perusakan nama dan cara argumen string harus dinaikkan ke fungsi. Default adalah CharSet.Ansi . |
EntryPoint | Menentukan titik masuk DLL yang akan dipanggil. |
ExactSpelling | Mengontrol apakah titik entri harus dimodifikasi agar sesuai dengan kumpulan karakter. Nilai default bervariasi menurut bahasa pemrograman. |
PreserveSig | Mengontrol apakah tanda tangan metode terkelola harus diubah menjadi tanda tangan tidak terkelola yang mengembalikan HRESULT dan memiliki argumen [out, retval] tambahan untuk nilai yang dikembalikan. Defaultnya adalah true (tanda tangan tidak boleh diubah). |
SetLastError | Memungkinkan pemanggil menggunakan fungsi API Marshal.GetLastWin32Error untuk menentukan apakah terjadi kesalahan saat menjalankan metode. Dalam Visual Basic, defaultnya adalah true ; dalam C# dan C++, defaultnya adalah false . |
ThrowOnUnmappableChar | Mengontrol pemberian pengecualian pada karakter Unicode yang tidak dapat dipetakan yang dikonversi menjadi karakter "?" ANSI. |
Untuk informasi referensi detail, lihat DllImportAttribute.
Pertimbangan keamanan pemanggilan platform
Anggota Assert
, Deny
, dan PermitOnly
dari enumerasi SecurityAction disebut sebagai pengubah proses pelacakan tumpukan. Anggota ini diabaikan jika mereka digunakan sebagai atribut deklaratif pada deklarasi pemanggilan platform dan pernyataan Interface Definition Language (IDL) COM.
Contoh Pemanggilan Platform
Sampel pemanggilan platform di bagian ini menggambarkan penggunaan atribut RegistryPermission
dengan pengubah proses pelacakan tumpukan.
Dalam contoh berikut, pengubah SecurityAction, Assert
, Deny
, dan PermitOnly
diabaikan.
[DllImport("MyClass.dll", EntryPoint = "CallRegistryPermission")]
[RegistryPermission(SecurityAction.Assert, Unrestricted = true)]
private static extern bool CallRegistryPermissionAssert();
[DllImport("MyClass.dll", EntryPoint = "CallRegistryPermission")]
[RegistryPermission(SecurityAction.Deny, Unrestricted = true)]
private static extern bool CallRegistryPermissionDeny();
[DllImport("MyClass.dll", EntryPoint = "CallRegistryPermission")]
[RegistryPermission(SecurityAction.PermitOnly, Unrestricted = true)]
private static extern bool CallRegistryPermissionDeny();
Namun, pengubah Demand
dalam contoh berikut diterima.
[DllImport("MyClass.dll", EntryPoint = "CallRegistryPermission")]
[RegistryPermission(SecurityAction.Demand, Unrestricted = true)]
private static extern bool CallRegistryPermissionDeny();
Pengubah SecurityAction bekerja dengan benar jika ditempatkan pada kelas yang berisi (membungkus) panggilan pemanggilan platform.
[RegistryPermission(SecurityAction.Demand, Unrestricted = true)]
public ref class PInvokeWrapper
{
public:
[DllImport("MyClass.dll", EntryPoint = "CallRegistryPermission")]
private static extern bool CallRegistryPermissionDeny();
};
[RegistryPermission(SecurityAction.Demand, Unrestricted = true)]
class PInvokeWrapper
{
[DllImport("MyClass.dll", EntryPoint = "CallRegistryPermission")]
private static extern bool CallRegistryPermissionDeny();
}
Pengubah SecurityAction juga bekerja dengan benar dalam skenario berlapis di mana ditempatkan pada pemanggil panggilan platform memanggil:
{
public ref class PInvokeWrapper
public:
[DllImport("MyClass.dll", EntryPoint = "CallRegistryPermission")]
private static extern bool CallRegistryPermissionDeny();
[RegistryPermission(SecurityAction.Demand, Unrestricted = true)]
public static bool CallRegistryPermission()
{
return CallRegistryPermissionInternal();
}
};
class PInvokeScenario
{
[DllImport("MyClass.dll", EntryPoint = "CallRegistryPermission")]
private static extern bool CallRegistryPermissionInternal();
[RegistryPermission(SecurityAction.Assert, Unrestricted = true)]
public static bool CallRegistryPermission()
{
return CallRegistryPermissionInternal();
}
}
Contoh Interop COM
Sampel interop COM di bagian ini menggambarkan penggunaan atribut RegistryPermission
dengan pengubah proses pelacakan tumpukan.
Deklarasi antarmuka interop COM berikut mengabaikan pengubah Assert
, Deny
, dan PermitOnly
, mirip dengan contoh pemanggilan platform di bagian sebelumnya.
[ComImport, Guid("12345678-43E6-43c9-9A13-47F40B338DE0")]
interface IAssertStubsItf
{
[RegistryPermission(SecurityAction.Assert, Unrestricted = true)]
bool CallRegistryPermission();
[FileIOPermission(SecurityAction.Assert, Unrestricted = true)]
bool CallFileIoPermission();
}
[ComImport, Guid("12345678-43E6-43c9-9A13-47F40B338DE0")]
interface IDenyStubsItf
{
[RegistryPermission(SecurityAction.Deny, Unrestricted = true)]
bool CallRegistryPermission();
[FileIOPermission(SecurityAction.Deny, Unrestricted = true)]
bool CallFileIoPermission();
}
[ComImport, Guid("12345678-43E6-43c9-9A13-47F40B338DE0")]
interface IAssertStubsItf
{
[RegistryPermission(SecurityAction.PermitOnly, Unrestricted = true)]
bool CallRegistryPermission();
[FileIOPermission(SecurityAction.PermitOnly, Unrestricted = true)]
bool CallFileIoPermission();
}
Selain itu, pengubah Demand
tidak diterima dalam skenario deklarasi antarmuka interop COM, seperti yang ditunjukkan dalam contoh berikut.
[ComImport, Guid("12345678-43E6-43c9-9A13-47F40B338DE0")]
interface IDemandStubsItf
{
[RegistryPermission(SecurityAction.Demand, Unrestricted = true)]
bool CallRegistryPermission();
[FileIOPermission(SecurityAction.Demand, Unrestricted = true)]
bool CallFileIoPermission();
}
Lihat 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