Condividi tramite


CA1060: Spostare i P/Invoke nella classe NativeMethods

TypeName

MovePInvokesToNativeMethodsClass

CheckId

CA1060

Categoria

Microsoft.Design

Breaking Change

Breaking

Causa

Un metodo utilizza Platform Invocation Services per accedere a codice non gestito e non è un membro di una delle classi NativeMethods.

Descrizione della regola

I metodi di chiamata al sistema operativo, ad esempio i metodi contrassegnati con l'attributo DllImportAttribute o quelli definiti mediante la parola chiave Declare in Visual Basic accedono a codice non gestito.Questi metodi devono essere contenuti in una delle classi riportate di seguito:

  • NativeMethods: questa classe non elimina i percorsi stack per l'autorizzazione del codice non gestito. SuppressUnmanagedCodeSecurityAttribute non deve essere applicato a questa classe). Questa classe è destinata ai metodi che possono essere utilizzati ovunque poiché verrà eseguito un percorso stack.

  • SafeNativeMethods: questa classe elimina i percorsi stack per l'autorizzazione del codice non gestito. SuppressUnmanagedCodeSecurityAttribute viene applicato a questa classe). Questa classe è destinata ai metodi che chiunque può chiamare in modo sicuro.Ai chiamanti di questi metodi non viene richiesto di eseguire una revisione completa della sicurezza per assicurare che l'utilizzo sia sicuro poiché i metodi sono innocui per qualsiasi chiamante.

  • UnsafeNativeMethods: questa classe elimina i percorsi stack per l'autorizzazione del codice non gestito. SuppressUnmanagedCodeSecurityAttribute viene applicato a questa classe). Questa classe è destinata ai metodi potenzialmente pericolosi.Qualsiasi chiamante di questi metodi deve eseguire una revisione completa della sicurezza per garantire che l'utilizzo sia sicuro poiché non verrà eseguito alcun percorso stack.

Queste classi sono dichiarate come internal (Friend in Visual Basic) e dichiarano un costruttore privato per impedire la creazione di nuove istanze.I metodi di queste classi devono essere static e internal (Shared e Friend in Visual Basic).

Come correggere le violazioni

Per correggere una violazione di questa regola, spostare il metodo nella classe NativeMethods appropriata.Per la maggior parte delle applicazioni è sufficiente spostare i P/Invoke in una nuova classe denominata NativeMethods.

Se tuttavia si stanno sviluppando librerie da utilizzare nelle altre applicazioni, è opportuno definire due altre classi chiamate SafeNativeMethods e UnsafeNativeMethods.Queste classi assomigliano alla classe NativeMethods, tuttavia sono contrassegnate con un attributo speciale denominato SuppressUnmanagedCodeSecurityAttribute.Quando questo attributo è applicato, il runtime non esegue un percorso stack completo per assicurarsi che tutti i chiamanti dispongano dell'autorizzazione UnmanagedCode.Il runtime verifica solitamente questa autorizzazione all'avvio.La mancata esecuzione di questo controllo migliora notevolmente le prestazioni di tutte le chiamate a questi metodi non gestiti, i quali possono venire chiamati anche dal codice con autorizzazioni limitate.

Tuttavia, è necessario utilizzare questo attributo con estrema attenzione.Se erroneamente implementato, può compromettere gravemente la sicurezza.

Per informazioni sull'implementazione dei metodi, vedere gli esempi NativeMethods, SafeNativeMethods e UnsafeNativeMethods.

Esclusione di avvisi

Non escludere un avviso da questa regola.

Esempio

Nell'esempio riportato di seguito viene dichiarato un metodo che viola questa regola.Per correggere la violazione, è necessario spostare i P/Invoke RemoveDirectory in una classe appropriata progettata per contenere solo P/Invoke.

Imports System

NameSpace MSInternalLibrary

' Violates rule: MovePInvokesToNativeMethodsClass. 
Friend Class UnmanagedApi
    Friend Declare Function RemoveDirectory Lib "kernel32" ( _
       ByVal Name As String) As Boolean 
End Class 

End NameSpace 
using System;
using System.Runtime.InteropServices;

namespace DesignLibrary
{
// Violates rule: MovePInvokesToNativeMethodsClass. 
    internal class UnmanagedApi
    {
        [DllImport("kernel32.dll", CharSet = CharSet.Unicode)]
        internal static extern bool RemoveDirectory(string name);
    }
}

Esempio NativeMethods

Descrizione

Poiché la classe NativeMethods non deve essere contrassegnata con SuppressUnmanagedCodeSecurityAttribute, i P/Invoke contenuti richiederanno l'autorizzazione UnmanagedCode.Poiché la maggior parte delle applicazioni viene eseguita dal computer locale e con attendibilità, questo non è generalmente un problema.Se tuttavia si stanno sviluppando librerie riutilizzabili, è opportuno definire una classe SafeNativeMethods o UnsafeNativeMethods.

Nell'esempio seguente viene illustrato un metodo Interaction.Beep che esegue il wrapping della funzione MessageBeep da user32.dll.Il P/Invoke MessageBeep viene inserito nella classe NativeMethods.

Codice

Imports System    
Imports System.Runtime.InteropServices    
Imports System.ComponentModel         

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
using System;    
using System.Runtime.InteropServices;    
using System.ComponentModel;              

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

Esempio SafeNativeMethods

Descrizione

I metodi di P/Invoke che possono essere esposti a una qualsiasi applicazione senza provocare effetti collaterali devono essere memorizzati in una classe denominata SafeNativeMethods.Non è necessario richiedere autorizzazioni né conoscere da dove vengono chiamati.

Nell'esempio seguente viene illustrata una proprietà Environment.TickCount che esegue il wrapping della funzione GetTickCount da kernel32.dll.

Codice

Imports System   
Imports System.Runtime.InteropServices   
Imports System.Security       

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
using System;   
using System.Runtime.InteropServices;   
using System.Security;  

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

Esempio UnsafeNativeMethods

Descrizione

I metodi P/Invoke che è sconsigliabile chiamare e che potrebbero provocare effetti collaterali devono essere inseriti in una classe denominata UnsafeNativeMethods.Questi metodi devono essere controllati rigorosamente per assicurarsi che non vengano esposti involontariamente all'utente.La regola CA2118: Verificare la sintassi di SuppressUnmanagedCodeSecurityAttribute può essere di aiuto in questo caso.In alternativa, può essere opportuno richiedere a questi metodi un'altra autorizzazione anziché UnmanagedCode durante l'utilizzo.

Nell'esempio seguente viene illustrato un metodo Cursor.Hide che esegue il wrapping della funzione ShowCursor da user32.dll.

Codice

Imports System   
Imports System.Runtime.InteropServices   
Imports System.Security   
Imports System.Security.Permissions       

Public NotInheritable Class Cursor           

    Private Sub New()       
    End Sub            

    ' Callers do not require Unmanaged permission, however,          
    ' they do require UIPermission.AllWindows        
    Public Shared Sub Hide()                 
        ' Need to demand an appropriate permission                    
        ' in  place of UnmanagedCode permission as                     
        ' ShowCursor is not considered a safe method                    
        Dim permission As New UIPermission(UIPermissionWindow.AllWindows)           
        permission.Demand()           
        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
using System;   
using System.Runtime.InteropServices;   
using System.Security;   
using System.Security.Permissions;           

public static class Cursor   
{       
    // Callers do not require UnmanagedCode permission, however,        
    // they do require UIPermissionWindow.AllWindows        
    public static void Hide()          
    {           
        // Need to demand an appropriate permission            
        // in  place of UnmanagedCode permission as             
        // ShowCursor is not considered a safe method            
        new UIPermission(UIPermissionWindow.AllWindows).Demand();           
        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);   
}

Vedere anche

Altre risorse

Avvisi di progettazione