Share via


CA1060: Flytta P/Invokes till klassen NativeMethods

Property Värde
Regel-ID CA1060
Rubrik Flytta P/Invokes till klassen NativeMethods
Kategori Designa
Korrigeringen är icke-bakåtkompatibel Bryta
Aktiverad som standard i .NET 8 Nej

Orsak

En metod använder Plattformsanropstjänster för att komma åt ohanterad kod och är inte medlem i någon av NativeMethods-klasserna .

Regelbeskrivning

Plattformsanropsmetoder, till exempel de som markeras med hjälp System.Runtime.InteropServices.DllImportAttribute av attributet eller metoder som definieras med hjälp av nyckelordet Declare i Visual Basic, får åtkomst till ohanterad kod. Dessa metoder bör finnas i någon av följande klasser:

  • NativeMethods – Den här klassen undertrycker inte stackvandringar för ohanterad kodbehörighet. (System.Security.SuppressUnmanagedCodeSecurityAttribute får inte tillämpas på den här klassen.) Den här klassen är avsedd för metoder som kan användas var som helst eftersom en stackvandring utförs.

  • Valv NativeMethods – Den här klassen undertrycker stackvandringar för ohanterad kodbehörighet. (System.Security.SuppressUnmanagedCodeSecurityAttribute tillämpas på den här klassen.) Den här klassen är avsedd för metoder som är säkra för alla att anropa. Anropare av dessa metoder behöver inte utföra en fullständig säkerhetsgranskning för att se till att användningen är säker eftersom metoderna är ofarliga för alla anropare.

  • UnsafeNativeMethods – Den här klassen undertrycker stackvandringar för ohanterad kodbehörighet. (System.Security.SuppressUnmanagedCodeSecurityAttribute tillämpas på den här klassen.) Den här klassen är avsedd för metoder som kan vara farliga. Alla anropare av dessa metoder måste utföra en fullständig säkerhetsgranskning för att se till att användningen är säker eftersom ingen stackvandring kommer att utföras.

Dessa klasser deklareras som internal (Friend i Visual Basic) och deklarerar en privat konstruktor för att förhindra att nya instanser skapas. Metoderna i dessa klasser ska vara static och internal (Shared och Friend i Visual Basic).

Så här åtgärdar du överträdelser

Om du vill åtgärda ett brott mot den här regeln flyttar du metoden till lämplig NativeMethods-klass . För de flesta program räcker det att flytta P/Invokes till en ny klass med namnet NativeMethods .

Men om du utvecklar bibliotek för användning i andra program bör du överväga att definiera två andra klasser som kallas Valv NativeMethods och UnsafeNativeMethods. Dessa klasser liknar klassen NativeMethods. De markeras dock med hjälp av ett särskilt attribut som kallas SuppressUnmanagedCodeSecurityAttribute. När det här attributet tillämpas utför körningen inte en fullständig stack-promenad för att se till att alla anropare har behörigheten UnmanagedCode . Körningen söker vanligtvis efter den här behörigheten vid start. Eftersom kontrollen inte utförs kan den avsevärt förbättra prestanda för anrop till dessa ohanterade metoder. Det aktiverar också kod som har begränsade behörigheter för att anropa dessa metoder.

Du bör dock använda det här attributet med stor försiktighet. Det kan få allvarliga säkerhetskonsekvenser om det implementeras felaktigt.

Information om hur du implementerar metoderna finns i exemplet NativeMethods, Valv NativeMethods och UnsafeNativeMethods.

När du ska ignorera varningar

Ignorera inte en varning från den här regeln.

Exempel

I följande exempel deklareras en metod som bryter mot den här regeln. För att åtgärda överträdelsen bör RemoveDirectory P/Invoke flyttas till en lämplig klass som är utformad för att endast innehålla 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);
}

NativeMethods-exempel

Eftersom klassen NativeMethods inte ska markeras med hjälp av SuppressUnmanagedCodeSecurityAttribute kräver P/Invokes som placeras i den unmanagedCode-behörighet . Eftersom de flesta program körs från den lokala datorn och körs tillsammans med fullständigt förtroende är detta vanligtvis inte ett problem. Men om du utvecklar återanvändbara bibliotek bör du överväga att definiera klassen Valv NativeMethods eller UnsafeNativeMethods.

I följande exempel visas en Interaction.Beep-metod som omsluter funktionen MessageBeep från user32.dll. MessageBeep P/Invoke placeras i klassen 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);
}

Valv NativeMethods-exempel

P/Invoke-metoder som kan exponeras på ett säkert sätt för alla program och som inte har några biverkningar bör placeras i en klass som heter Valv NativeMethods. Du behöver inte ägna mycket uppmärksamhet åt var de anropas från.

I följande exempel visas egenskapen Environment.TickCount som omsluter funktionen GetTickCount från 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();
}

Exempel på UnsafeNativeMethods

P/Invoke-metoder som inte kan anropas på ett säkert sätt och som kan orsaka biverkningar bör placeras i en klass med namnet UnsafeNativeMethods. Dessa metoder bör kontrolleras noggrant för att säkerställa att de inte oavsiktligt exponeras för användaren.

I följande exempel visas metoden Cursor.Hide som omsluter funktionen ShowCursor från 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);
}

Se även