Bagikan melalui


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.GetLastWin32Erroruntuk 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