Partager via


CA1060 : Déplacer les P/Invoke vers une classe NativeMethods

TypeName

MovePInvokesToNativeMethodsClass

CheckId

CA1060

Catégorie

Microsoft.CSharp

Modification avec rupture

Oui

Cause

Une méthode utilise des services d'appel de code non managé pour accéder à du code non managé et n'est membre d'aucune des classes NativeMethods.

Description de la règle

Les méthodes d'appel de code non managé, telles que celles qui sont marquées avec l'attribut System.Runtime.InteropServices.DllImportAttribute (ou les méthodes définies à l'aide du mot clé Declare en Visual Basic) accèdent à du code non managé. Ces méthodes doivent se trouver dans l'une des classes suivantes :

  • NativeMethods - Cette classe ne supprime aucun parcours de pile pour l'autorisation de code non managé. (System.Security.SuppressUnmanagedCodeSecurityAttribute ne doit pas être appliqué à cette classe.) Cette classe est destinée aux méthodes qui ne peuvent pas être utilisées n'importe où, du fait de l'exécution d'un parcours de pile.

  • SafeNativeMethods - Cette classe supprime des parcours de pile pour l'autorisation de code non managé. (System.Security.SuppressUnmanagedCodeSecurityAttribute est appliqué à cette classe.) Cette classe est destinée aux méthodes qui garantissent la sécurité de tous les appelants. Les appelants de ces méthodes ne sont pas contraints de procéder à une révision de sécurité complète pour garantir la sécurisation de leur utilisation car elles ne présentent de danger pour aucun appelant.

  • UnsafeNativeMethods - Cette classe supprime des parcours de pile pour l'autorisation de code non managé. (System.Security.SuppressUnmanagedCodeSecurityAttribute est appliqué à cette classe.) Cette classe est destinée à des méthodes potentiellement dangereuses. Tout appelant de ces méthodes doit procéder à une révision de sécurité complète pour garantir la sécurisation de leur utilisation, car aucun parcours de pile ne sera effectué.

Ces classes sont déclarées en tant que internal (Friend en Visual Basic) et déclarent un constructeur privé pour empêcher la création de nouvelles instances. Les méthodes présentes dans ces classes doivent être static et internal (Shared et Friend en Visual Basic).

Comment corriger les violations

Pour corriger une violation de cette règle, placez la méthode dans la classe NativeMethods appropriée. Pour la plupart des applications, le fait de déplacer les P/Invoke vers une classe nouvelle nommée NativeMethods est suffisant.

Toutefois, si vous développez des bibliothèques pour une utilisation dans d'autres applications, vous devez envisager de définir deux autres classes appelées SafeNativeMethods et UnsafeNativeMethods. Ces classes ressemblent à la classe NativeMethods. Toutefois, elles sont marquées avec un attribut spécial appelé SuppressUnmanagedCodeSecurityAttribute. Lorsque cet attribut est appliqué, l'exécution n'effectue pas de parcours complet de la pile afin de s'assurer que tous les appelants ont l'autorisation UnmanagedCode. Le runtime vérifie habituellement la présence de cette autorisation au démarrage. Dans la mesure où le contrôle n'est pas effectué, cela peut améliorer grandement la performance pour les appels à ces méthodes non managées, et permet également au code avec des autorisations limitées d'appeler ces méthodes.

Cependant, vous devez utiliser cet attribut avec précaution. Les conséquences au niveau de la sécurité peuvent être sérieuses s'il est implémenté de manière incorrecte.

Pour plus d'informations sur l'implémentation de ces méthodes, consultez les exemples NativeMethods, SafeNativeMethods et UnsafeNativeMethods.

Quand supprimer les avertissements

Ne supprimez aucun avertissement de cette règle.

Exemple

L'exemple suivant déclare une méthode qui ne respecte pas cette règle. Pour corriger la violation, le P/Invoke RemoveDirectory doit être déplacé vers une classe appropriée destinée à contenir uniquement les 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);
    }
}

Exemple NativeMethods

Description

Dans la mesure où la classe NativeMethods ne doit pas être marquée avec SuppressUnmanagedCodeSecurityAttribute, les P/Invoke qui y sont placés nécessiteront l'autorisation UnmanagedCode. Comme la plupart des applications s'exécutent ensemble à partir de l'ordinateur local et avec la confiance totale, ceci ne pose généralement pas problème. Toutefois, si vous développez des bibliothèques réutilisables, vous devez envisager de définir une classe SafeNativeMethods ou UnsafeNativeMethods.

L'exemple suivant affiche une méthode Interaction.Beep qui encapsule la fonction MessageBeep à partir d'user32.dll. P/Invoke de MessageBeep est placé dans la classe NativeMethods.

Code

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

Exemple SafeNativeMethods

Description

Les méthodes P/Invoke qui peuvent être exposées sans risque à toute application et qui n'ont pas d'effets secondaires doivent être placées dans une classe nommée SafeNativeMethods. Vous n'avez pas à demander des autorisations et vous n'avez pas à faire trop attention à l'emplacement à partir duquel elles sont appelées.

L'exemple suivant affiche une propriété Environment.TickCount qui encapsule la fonction GetTickCount à partir de kernel32.dll.

Code

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

Exemple UnsafeNativeMethods

Description

Les méthodes P/Invoke qui ne peuvent pas être appelées sans risque et qui peuvent provoquer des effets secondaires doivent être placées dans une classe nommée UnsafeNativeMethods. Ces méthodes doivent être vérifiées rigoureusement pour s'assurer qu'elles ne sont pas exposées involontairement à l'utilisateur. La règle CA2118 : Révision de l'utilisation de SuppressUnmanagedCodeSecurityAttribute peut y contribuer. Les méthodes doivent également avoir une autre autorisation demandée à la place du UnmanagedCode lorsqu'elles les utilisent.

L'exemple suivant montre une méthode Cursor.Hide qui encapsule la fonction ShowCursor à partir d'user32.dll.

Code

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

Voir aussi

Autres ressources

Avertissements liés au design