CA1060: P/Invokes in NativeMethods-Klasse verschieben

Eigenschaft Wert
Regel-ID CA1060
Titel P/Invokes in NativeMethods-Klasse verschieben.
Kategorie Design
Fix führt oder führt nicht zur Unterbrechung Breaking
Standardmäßig in .NET 8 aktiviert Nein

Ursache

Eine Methode verwendet Platform Invocation Services, um auf nicht verwalteten Code zuzugreifen, und ist kein Member einer der NativeMethods-Klassen.

Regelbeschreibung

Plattformaufrufmethoden, beispielsweise Methoden, die mit dem System.Runtime.InteropServices.DllImportAttribute-Attribut gekennzeichnet sind, oder Methoden, die in Visual Basic mithilfe des Declare-Schlüsselworts definiert wurden, greifen auf nicht verwalteten Code zu. Diese Methoden sollten in einer der folgenden Klassen vorhanden sein:

  • NativeMethods: Diese Klasse unterdrückt keine Stackwalks für die nicht verwaltete Codeberechtigung. (System.Security.SuppressUnmanagedCodeSecurityAttribute darf nicht auf diese Klasse angewendet werden.) Diese Klasse eignet sich für Methoden, die überall verwendet werden können, da ein Stackwalk ausgeführt wird.

  • SafeNativeMethods: Diese Klasse unterdrückt Stackwalks für die nicht verwaltete Codeberechtigung. (System.Security.SuppressUnmanagedCodeSecurityAttribute wird auf diese Klasse angewendet.) Diese Klasse eignet sich für Methoden, die für jeden aufzurufenden Benutzer sicher sind. Aufrufer dieser Methoden müssen keine vollständige Sicherheitsüberprüfung durchführen, um sicherzustellen, dass die Nutzung sicher ist, da die Methoden für jeden Aufrufer harmlos sind.

  • UnsafeNativeMethods: Diese Klasse unterdrückt Stackwalks für die nicht verwaltete Codeberechtigung. (System.Security.SuppressUnmanagedCodeSecurityAttribute wird auf diese Klasse angewendet.) Diese Klasse eignet sich für Methoden, die potenziell gefährlich sind. Alle Aufrufer dieser Methoden müssen eine vollständige Sicherheitsüberprüfung durchführen, um sicherzustellen, dass die Nutzung sicher ist, da kein Stackwalk durchgeführt wird.

Diese Klassen werden als internal (Friend in Visual Basic) deklariert und deklarieren einen privaten Konstruktor, um zu verhindern, dass neue Instanzen erstellt werden. Die Methoden in diesen Klassen sollten static und internal (Shared und Friend in Visual Basic) sein.

Behandeln von Verstößen

Verschieben Sie die Methode in die entsprechende NativeMethods-Klasse, um einen Verstoß gegen diese Regel zu korrigieren. Bei den meisten Anwendungen ist das Verschieben von P/Invokes in eine neue Klasse mit dem Namen NativeMethods ausreichend.

Wenn Sie jedoch Bibliotheken für die Verwendung in anderen Anwendungen entwickeln, sollten Sie zwei andere Klassen definieren, die als SafeNativeMethods und UnsafeNativeMethods bezeichnet werden. Diese Klassen ähneln der NativeMethods-Klasse. Sie werden jedoch mit einem speziellen Attribut namens SuppressUnmanagedCodeSecurityAttribute gekennzeichnet. Wenn dieses Attribut angewendet wird, führt die Runtime keinen vollständigen Stackwalk aus, um sicherzustellen, dass alle Aufrufer über die UnmanagedCode-Berechtigung verfügen. Die Runtime prüft diese Berechtigung normalerweise beim Start. Da die Überprüfung nicht ausgeführt wird, kann dies die Leistung für Aufrufe dieser nicht verwalteten Methoden erheblich verbessern. Außerdem wird Code aktiviert, der über eingeschränkte Berechtigungen zum Aufrufen dieser Methoden verfügt.

Sie sollten dieses Attribut jedoch sehr sorgfältig verwenden. Es kann schwerwiegende Sicherheitsauswirkungen haben, wenn es nicht ordnungsgemäß implementiert wird.

Weitere Informationen zum Implementieren der Methoden finden Sie in den Beispielen für NativeMethods, SafeNativeMethods und UnsafeNativeMethods.

Wann sollten Warnungen unterdrückt werden?

Unterdrücken Sie keine Warnung dieser Regel.

Beispiel

Im folgenden Beispiel wird eine Methode deklariert, die gegen diese Regel verstößt. Die P/Invoke-Instanz RemoveDirectory sollte in eine entsprechende Klasse verschoben werden, die nur P/Invokes enthalten darf, um den Verstoß zu korrigieren.

' 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-Beispiel

Da die NativeMethods-Klasse nicht mithilfe von SuppressUnmanagedCodeSecurityAttribute gekennzeichnet werden sollte, benötigt P/Invokes in dieser Klasse die UnmanagedCode-Berechtigung. Die meisten Anwendungen werden auf dem lokalen Computer und mit voller Vertrauenswürdigkeit ausgeführt, sodass dies in der Regel kein Problem ist. Wenn Sie jedoch wiederverwendbare Bibliotheken entwickeln, sollten Sie die Definition einer SafeNativeMethods- oder einer UnsafeNativeMethods-Klasse in Erwägung ziehen.

Das folgende Beispiel zeigt eine Interaktion.Beep-Methode, die die MessageBeep-Funktion von user32.dll umschließt. Der P/Invoke MessageBeep wird in die NativeMethods-Klasse eingefügt.

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

SafeNativeMethods-Beispiel

P/Invoke-Methoden, die auf sichere Weise für jede Anwendung verfügbar gemacht werden können und die keine Nebenwirkungen haben, sollten in eine Klasse mit dem Namen SafeNativeMethods eingefügt werden. Sie müssen nicht mehr darauf achten, von wo sie abgerufen werden.

Das folgende Beispiel zeigt eine Environment.TickCount-Eigenschaft, die die GetTickCount-Funktion von kernel32.dll umschließt.

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-Beispiel

P/Invoke-Methoden, die nicht sicher aufgerufen werden können und die Nebenwirkungen verursachen könnten, sollten in eine Klasse mit dem Namen UnsafeNativeMethods eingefügt werden. Diese Methoden sollten streng überprüft werden, um sicherzustellen, dass sie nicht versehentlich für den Benutzer verfügbar gemacht werden.

Das folgende Beispiel zeigt eine Cursor.Hide-Methode, die die ShowCursor-Funktion von user32.dll umschließt.

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

Weitere Informationen