Delen via


CA1060: P/Invokes verplaatsen naar de klasse NativeMethods

Eigenschappen Weergegeven als
Regel-id CA1060
Titel P/Invokes verplaatsen naar de klasse NativeMethods
Categorie Ontwerpen
Oplossing is brekend of niet-brekend Breken
Standaard ingeschakeld in .NET 8 Nee

Oorzaak

Een methode maakt gebruik van Platform Invocation Services voor toegang tot onbeheerde code en is geen lid van een van de NativeMethods-klassen .

Beschrijving van regel

Platformoproepmethoden, zoals methoden die zijn gemarkeerd met behulp van het System.Runtime.InteropServices.DllImportAttribute kenmerk of methoden die zijn gedefinieerd met behulp van het Declare trefwoord in Visual Basic, hebben toegang tot onbeheerde code. Deze methoden moeten zich in een van de volgende klassen hebben:

  • NativeMethods : deze klasse onderdrukt geen stack-wandelingen voor niet-beheerde codemachtigingen. (System.Security.SuppressUnmanagedCodeSecurityAttribute mag niet worden toegepast op deze klasse.) Deze klasse is bedoeld voor methoden die overal kunnen worden gebruikt omdat er een stack-walk wordt uitgevoerd.

  • SafeNativeMethods : deze klasse onderdrukt stack-stappen voor niet-beheerde codemachtigingen. (System.Security.SuppressUnmanagedCodeSecurityAttribute wordt toegepast op deze klasse.) Deze klasse is bedoeld voor methoden die veilig zijn voor iedereen die kan aanroepen. Bellers van deze methoden zijn niet verplicht om een volledige beveiligingsbeoordeling uit te voeren om ervoor te zorgen dat het gebruik veilig is omdat de methoden ongevaarlijk zijn voor een beller.

  • UnsafeNativeMethods : deze klasse onderdrukt stack-wandelingen voor niet-beheerde codemachtigingen. (System.Security.SuppressUnmanagedCodeSecurityAttribute wordt toegepast op deze klasse.) Deze klasse is bedoeld voor methoden die mogelijk gevaarlijk zijn. Elke aanroeper van deze methoden moet een volledige beveiligingsbeoordeling uitvoeren om ervoor te zorgen dat het gebruik veilig is omdat er geen stack-wandeling wordt uitgevoerd.

Deze klassen worden gedeclareerd als internal (Friend in Visual Basic) en declareren een privéconstructor om te voorkomen dat nieuwe exemplaren worden gemaakt. De methoden in deze klassen moeten en internal (Shared en Friend in Visual Basic) zijnstatic.

Schendingen oplossen

Als u een schending van deze regel wilt oplossen, verplaatst u de methode naar de juiste NativeMethods-klasse . Voor de meeste toepassingen is het verplaatsen van P/Invokes naar een nieuwe klasse met de naam NativeMethods voldoende.

Als u echter bibliotheken ontwikkelt voor gebruik in andere toepassingen, kunt u overwegen om twee andere klassen te definiëren die SafeNativeMethods en UnsafeNativeMethods worden genoemd. Deze klassen lijken op de klasse NativeMethods. Ze worden echter gemarkeerd met een speciaal kenmerk met de naam SuppressUnmanagedCodeSecurityAttribute. Wanneer dit kenmerk wordt toegepast, voert de runtime geen volledige stack-walk uit om ervoor te zorgen dat alle bellers de machtiging UnmanagedCode hebben. De runtime controleert gewoonlijk bij het opstarten op deze machtiging. Omdat de controle niet wordt uitgevoerd, kunnen de prestaties voor aanroepen naar deze niet-beheerde methoden aanzienlijk worden verbeterd. Het maakt ook code mogelijk die beperkte machtigingen heeft om deze methoden aan te roepen.

U moet dit kenmerk echter zorgvuldig gebruiken. Dit kan ernstige gevolgen hebben voor de beveiliging als deze onjuist wordt geïmplementeerd.

Zie het voorbeeld NativeMethods, voorbeeld SafeNativeMethods en UnsafeNativeMethods voor informatie over het implementeren van de methoden.

Wanneer waarschuwingen onderdrukken

Een waarschuwing van deze regel niet onderdrukken.

Voorbeeld

In het volgende voorbeeld wordt een methode declareren die deze regel schendt. Om de schending te corrigeren, moet de RemoveDirectory P/Invoke worden verplaatst naar een geschikte klasse die is ontworpen om alleen P/Invokes te bewaren.

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

Voorbeeld nativeMethods

Omdat de klasse NativeMethods niet mag worden gemarkeerd met behulp van SuppressUnmanagedCodeSecurityAttribute, is voor P/Invokes die erin worden geplaatst, de machtiging UnmanagedCode vereist. Omdat de meeste toepassingen worden uitgevoerd vanaf de lokale computer en samen met volledig vertrouwen worden uitgevoerd, is dit meestal geen probleem. Als u echter herbruikbare bibliotheken ontwikkelt, kunt u overwegen een klasse SafeNativeMethods of UnsafeNativeMethods te definiëren.

In het volgende voorbeeld ziet u een Interaction.Beep-methode waarmee de functie MessageBeep van user32.dll wordt verpakt. De MessageBeep P/Invoke wordt in de klasse NativeMethods geplaatst.

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

Voorbeeld safeNativeMethods

P/Invoke-methoden die veilig kunnen worden blootgesteld aan elke toepassing en die geen bijwerkingen hebben, moeten worden geplaatst in een klasse met de naam SafeNativeMethods. Je hoeft niet veel aandacht te besteden aan waar ze vandaan worden gebeld.

In het volgende voorbeeld ziet u een eigenschap Environment.TickCount waarmee de functie GetTickCount van kernel32.dll wordt verpakt.

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

Voorbeeld van UnsafeNativeMethods

P/Invoke-methoden die niet veilig kunnen worden aangeroepen en die bijwerkingen kunnen veroorzaken, moeten worden geplaatst in een klasse met de naam UnsafeNativeMethods. Deze methoden moeten grondig worden gecontroleerd om ervoor te zorgen dat ze niet onbedoeld zichtbaar zijn voor de gebruiker.

In het volgende voorbeeld ziet u een Cursor.Hide-methode waarmee de functie ShowCursor van user32.dll wordt verpakt.

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

Zie ook