CA1060: P/Invokes öğesini NativeMethods sınıfına taşıyın

Özellik Değer
Kural Kimliği CA1060
Başlık P/Invokes'u NativeMethods sınıfına taşıyın
Kategori Tasarım
Hataya neden olan veya bozulmayan düzeltme Yeni
.NET 8'de varsayılan olarak etkin Hayır

Neden

Yöntem, yönetilmeyen koda erişmek için Platform Çağırma Hizmetleri'ni kullanır ve NativeMethods sınıflarından birinin üyesi değildir.

Kural açıklaması

Özniteliği kullanılarak System.Runtime.InteropServices.DllImportAttribute işaretlenmiş olanlar gibi platform çağırma yöntemleri veya Visual Basic'te anahtar sözcüğü kullanılarak Declare tanımlanan yöntemler yönetilmeyen koda erişin. Bu yöntemler aşağıdaki sınıflardan birinde olmalıdır:

  • NativeMethods - Bu sınıf yönetilmeyen kod izni için yığın adımlarını gizlemez. (System.Security.SuppressUnmanagedCodeSecurityAttribute bu sınıfa uygulanmamalıdır.) Bu sınıf, yığın yürüyüşü gerçekleştirileceği için her yerde kullanılabilecek yöntemler içindir.

  • Kasa NativeMethods - Bu sınıf yönetilmeyen kod izni için yığın adımlarını gizler. (System.Security.SuppressUnmanagedCodeSecurityAttribute bu sınıfa uygulanır.) Bu sınıf, herkesin çağırabilecekleri güvenli yöntemlere yöneliktir. Bu yöntemleri çağıranların, yöntemlerin herhangi bir arayan için zararsız olması nedeniyle kullanımın güvenli olduğundan emin olmak için tam bir güvenlik incelemesi gerçekleştirmesi gerekmez.

  • UnsafeNativeMethods - Bu sınıf yönetilmeyen kod izni için yığın adımlarını gizler. (System.Security.SuppressUnmanagedCodeSecurityAttribute bu sınıfa uygulanır.) Bu sınıf, potansiyel olarak tehlikeli yöntemler içindir. Bu yöntemlerin çağıranlarından herhangi biri, yığın yürüyüşü yapılmayacağından kullanımın güvenli olduğundan emin olmak için tam bir güvenlik gözden geçirmesi gerçekleştirmelidir.

Bu sınıflar (Friend Visual Basic'te) olarak internal bildirilir ve yeni örneklerin oluşturulmasını önlemek için özel bir oluşturucu bildirir. Bu sınıflardaki yöntemler ve internal (Shared ve Friend Visual Basic'te) olmalıdırstatic.

İhlalleri düzeltme

Bu kuralın ihlalini düzeltmek için yöntemini uygun NativeMethods sınıfına taşıyın. Çoğu uygulama için P/Invoke'ları NativeMethods adlı yeni bir sınıfa taşımak yeterlidir.

Ancak, diğer uygulamalarda kullanılmak üzere kitaplıklar geliştiriyorsanız, Kasa NativeMethods ve UnsafeNativeMethods adlı iki sınıf daha tanımlamayı düşünmelisiniz. Bu sınıflar NativeMethods sınıfına benzer; ancak SuppressUnmanagedCodeSecurityAttribute adlı özel bir öznitelik kullanılarak işaretlenir. Bu öznitelik uygulandığında, çalışma zamanı tüm çağıranların UnmanagedCode iznine sahip olduğundan emin olmak için tam yığın yürüyüşü gerçekleştirmez. Çalışma zamanı normalde başlangıçta bu izni denetler. Denetim gerçekleştirilmediğinden, bu yönetilmeyen yöntemlere yapılan çağrıların performansını büyük ölçüde iyileştirebilir. Ayrıca, bu yöntemleri çağırmak için sınırlı izinlere sahip kodu etkinleştirir.

Ancak, bu özniteliği büyük bir dikkatle kullanmanız gerekir. Yanlış uygulandığında ciddi güvenlik etkileri olabilir.

Yöntemleri uygulama hakkında bilgi için NativeMethods örneğine, Kasa NativeMethods örneğine ve UnsafeNativeMethods örneğine bakın.

Uyarıların ne zaman bastırılması gerekiyor?

Bu kuraldan uyarıyı bastırmayın.

Örnek

Aşağıdaki örnek, bu kuralı ihlal eden bir yöntem bildirir. İhlali düzeltmek için RemoveDirectory P/Invoke yalnızca P/Invoke'ları barındıracak şekilde tasarlanmış uygun bir sınıfa taşınmalıdır.

' 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);
}

NativeMethods örneği

NativeMethods sınıfı SuppressUnmanagedCodeSecurityAttribute kullanılarak işaretlenmemesi gerektiğinden, içine konulan P/Invoke'lar UnmanagedCode izni gerektirir. Çoğu uygulama yerel bilgisayardan çalıştığından ve tam güven ile birlikte çalıştığından, bu genellikle bir sorun değildir. Ancak, yeniden kullanılabilir kitaplıklar geliştiriyorsanız bir Kasa NativeMethods veya UnsafeNativeMethods sınıfı tanımlamayı düşünmelisiniz.

Aşağıdaki örnekte messagebeep işlevini user32.dll dosyasından sarmalayan bir Interaction.Beep yöntemi gösterilmektedir. MessageBeep P/Invoke nativeMethods sınıfına konur.

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

Kasa NativeMethods örneği

Herhangi bir uygulamaya güvenli bir şekilde gösterilebilen ve yan etkileri olmayan P/Invoke yöntemleri, Kasa NativeMethods adlı bir sınıfa yerleştirilmelidir. Nereden çağrıldıklarına çok dikkat etmek zorunda değilsin.

Aşağıdaki örnekte, kernel32.dll dosyasından GetTickCount işlevini sarmalayan bir Environment.TickCount özelliği gösterilmektedir.

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();
}

UnsafeNativeMethods örneği

Güvenli bir şekilde çağrılamayan ve yan etkilere neden olabilecek P/Invoke yöntemleri UnsafeNativeMethods adlı bir sınıfa yerleştirilmelidir. Bu yöntemlerin istemeden kullanıcıya açık olmadığından emin olmak için titizlikle denetlenmesi gerekir.

Aşağıdaki örnekte, ShowCursor işlevini user32.dll dosyasından sarmalayan bir Cursor.Hide yöntemi gösterilmektedir.

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

Ayrıca bkz.