CA1060: Pindahkan P/Invokes ke kelas NativeMethods
Properti | Nilai |
---|---|
ID Aturan | CA1060 |
Judul | Memindahkan P/Invokes ke kelas NativeMethods |
Golongan | Desain |
Perbaikan bersifat disruptif atau non-disruptif | Merusak |
Diaktifkan secara default di .NET 9 | No |
Penyebab
Metode menggunakan Platform Invocation Services untuk mengakses kode yang tidak dikelola dan bukan anggota salah satu kelas NativeMethods.
Deskripsi aturan
Metode Pemanggilan Platform, seperti metode yang ditandai dengan menggunakan atribut System.Runtime.InteropServices.DllImportAttribute, atau metode yang ditentukan dengan menggunakan kata kunci Declare
di Visual Basic, mengakses kode yang tidak dikelola. Metode ini harus berada di salah satu kelas berikut:
NativeMethods - Kelas ini tidak menekan stack walk untuk izin kode yang tidak dikelola. (System.Security.SuppressUnmanagedCodeSecurityAttribute tidak boleh diterapkan ke kelas ini.) Kelas ini ditujukan untuk metode yang dapat digunakan di mana saja karena stack walk akan dilakukan.
SafeNativeMethods - Kelas ini menekan stack walk untuk izin kode yang tidak dikelola. (System.Security.SuppressUnmanagedCodeSecurityAttribute diterapkan ke kelas ini.) Kelas ini adalah untuk metode yang aman bagi siapa saja untuk menelepon. Pemanggil metode ini tidak diperlukan untuk melakukan tinjauan keamanan penuh untuk memastikan bahwa penggunaannya aman karena metodenya tidak berbahaya bagi pemanggil apa pun.
UnsafeNativeMethods - Kelas ini tidak menekan stack walk untuk izin kode yang tidak dikelola. (System.Security.SuppressUnmanagedCodeSecurityAttribute diterapkan ke kelas ini.) Kelas ini untuk metode yang berpotensi berbahaya. Setiap pemanggil metode ini harus melakukan tinjauan keamanan penuh untuk memastikan bahwa penggunaan aman karena tidak ada stack walk yang akan dilakukan.
Kelas-kelas ini dinyatakan sebagai internal
(Friend
dalam Visual Basic) dan mendeklarasikan konstruktor privat untuk mencegah instans baru dibuat. Metode dalam kelas-kelas ini harus static
dan internal
(Shared
dan Friend
di Visual Basic).
Cara memperbaiki pelanggaran
Untuk memperbaiki pelanggaran aturan ini, pindahkan metode ke kelas NativeMethods yang sesuai. Untuk sebagian besar aplikasi, memindahkan P/Invokes ke kelas baru yang diberi nama NativeMethods sudah cukup.
Namun, jika Anda mengembangkan pustaka untuk digunakan dalam aplikasi lain, Anda harus mempertimbangkan untuk menentukan dua kelas lain yang disebut SafeNativeMethods dan UnsafeNativeMethods. Kelas-kelas ini menyerupai kelas NativeMethods ; namun, mereka ditandai dengan menggunakan atribut khusus yang disebut SuppressUnmanagedCodeSecurityAttribute. Ketika atribut ini diterapkan, runtime bahasa umum tidak melakukan stack berjalan penuh untuk memastikan bahwa semua penelepon memiliki izin UnmanagedCode. Runtime bahasa umum biasanya memeriksa izin ini saat startup. Karena pemeriksaan tidak dilakukan, pemeriksaan dapat sangat meningkatkan performa untuk panggilan ke metode yang tidak dikelola ini. Ini juga memungkinkan kode yang memiliki izin terbatas untuk memanggil metode ini.
Namun, Anda harus menggunakan atribut ini dengan sangat hati-hati. Ini dapat memiliki implikasi keamanan yang serius jika diimplementasikan dengan tidak benar.
Untuk informasi tentang cara menerapkan metode, lihat contoh NativeMethods, contoh SafeNativeMethods, dan contoh UnsafeNativeMethods.
Kapan harus menekan peringatan
Jangan menyembunyikan peringatan dari aturan ini.
Contoh
Contoh berikut mendeklarasikan metode yang melanggar aturan ini. Untuk memperbaiki pelanggaran, RemoveDirectory P/Invoke harus dipindahkan ke kelas yang sesuai yang dirancang untuk hanya menahan P/Invokes.
' Violates rule: MovePInvokesToNativeMethodsClass.
Friend Class UnmanagedApi
Friend Declare Function RemoveDirectory Lib "kernel32" (
ByVal Name As String) As Boolean
End Class
// Violates rule: MovePInvokesToNativeMethodsClass.
internal class UnmanagedApi
{
[DllImport("kernel32.dll", CharSet = CharSet.Unicode)]
internal static extern bool RemoveDirectory(string name);
}
Contoh NativeMethods
Karena kelas NativeMethods tidak boleh ditandai dengan menggunakan SuppressUnmanagedCodeSecurityAttribute, P/Invokes yang dimasukkan ke dalamnya akan memerlukan izin UnmanagedCode. Karena sebagian besar aplikasi berjalan dari komputer lokal dan berjalan bersama dengan kepercayaan penuh, ini biasanya tidak menjadi masalah. Namun, jika Anda mengembangkan pustaka yang dapat digunakan kembali, Anda harus mempertimbangkan untuk menentukan kelas SafeNativeMethods atau UnsafeNativeMethods.
Contoh berikut menunjukkan metode Interaction.Beep yang membungkus fungsi MessageBeep dari user32.dll. MessageBeep P/Invoke dimasukkan ke dalam kelas NativeMethods.
Public NotInheritable Class Interaction
Private Sub New()
End Sub
' Callers require Unmanaged permission
Public Shared Sub Beep()
' No need to demand a permission as callers of Interaction.Beep
' will require UnmanagedCode permission
If Not NativeMethods.MessageBeep(-1) Then
Throw New Win32Exception()
End If
End Sub
End Class
Friend NotInheritable Class NativeMethods
Private Sub New()
End Sub
<DllImport("user32.dll", CharSet:=CharSet.Auto)>
Friend Shared Function MessageBeep(ByVal uType As Integer) As <MarshalAs(UnmanagedType.Bool)> Boolean
End Function
End Class
public static class Interaction
{
// Callers require Unmanaged permission
public static void Beep()
{
// No need to demand a permission as callers of Interaction.Beep
// will require UnmanagedCode permission
if (!NativeMethods.MessageBeep(-1))
throw new Win32Exception();
}
}
internal static class NativeMethods
{
[DllImport("user32.dll", CharSet = CharSet.Auto)]
[return: MarshalAs(UnmanagedType.Bool)]
internal static extern bool MessageBeep(int uType);
}
Contoh SafeNativeMethods
Metode P/Invoke yang dapat diekspos dengan aman ke aplikasi apa pun dan yang tidak memiliki efek samping harus dimasukkan ke dalam kelas yang bernama SafeNativeMethods. Anda tidak perlu terlalu memperhatikan dari mana mereka dipanggil.
Contoh berikut menunjukkan properti Environment.TickCount yang membungkus fungsi GetTickCount dari kernel32.dll.
Public NotInheritable Class Environment
Private Sub New()
End Sub
' Callers do not require Unmanaged permission
Public Shared ReadOnly Property TickCount() As Integer
Get
' No need to demand a permission in place of
' UnmanagedCode as GetTickCount is considered
' a safe method
Return SafeNativeMethods.GetTickCount()
End Get
End Property
End Class
<SuppressUnmanagedCodeSecurityAttribute()>
Friend NotInheritable Class SafeNativeMethods
Private Sub New()
End Sub
<DllImport("kernel32.dll", CharSet:=CharSet.Auto, ExactSpelling:=True)>
Friend Shared Function GetTickCount() As Integer
End Function
End Class
public static class Environment
{
// Callers do not require UnmanagedCode permission
public static int TickCount
{
get
{
// No need to demand a permission in place of
// UnmanagedCode as GetTickCount is considered
// a safe method
return SafeNativeMethods.GetTickCount();
}
}
}
[SuppressUnmanagedCodeSecurityAttribute]
internal static class SafeNativeMethods
{
[DllImport("kernel32.dll", CharSet = CharSet.Auto, ExactSpelling = true)]
internal static extern int GetTickCount();
}
Contoh UnsafeNativeMethods
Metode P/Invoke yang tidak dapat dipanggil dengan aman dan itu dapat menyebabkan efek samping harus dimasukkan ke dalam kelas yang bernama UnsafeNativeMethods. Metode ini harus diperiksa dengan ketat untuk memastikan bahwa metode tersebut tidak diekspos ke pengguna secara tidak sengaja.
Contoh berikut menunjukkan metode Cursor.Hide yang membungkus fungsi ShowCursor dari user32.dll.
Public NotInheritable Class Cursor
Private Sub New()
End Sub
Public Shared Sub Hide()
UnsafeNativeMethods.ShowCursor(False)
End Sub
End Class
<SuppressUnmanagedCodeSecurityAttribute()>
Friend NotInheritable Class UnsafeNativeMethods
Private Sub New()
End Sub
<DllImport("user32.dll", CharSet:=CharSet.Auto, ExactSpelling:=True)>
Friend Shared Function ShowCursor(<MarshalAs(UnmanagedType.Bool)> ByVal bShow As Boolean) As Integer
End Function
End Class
public static class Cursor
{
public static void Hide()
{
UnsafeNativeMethods.ShowCursor(false);
}
}
[SuppressUnmanagedCodeSecurityAttribute]
internal static class UnsafeNativeMethods
{
[DllImport("user32.dll", CharSet = CharSet.Auto, ExactSpelling = true)]
internal static extern int ShowCursor([MarshalAs(UnmanagedType.Bool)] bool bShow);
}