Udostępnij za pośrednictwem


CA1060: Przenieś P/Invokes do klasy NativeMethods

TypeName

MovePInvokesToNativeMethodsClass

CheckId

CA1060

Kategoria

Microsoft.Design

Zmiana kluczowa

Kluczowa

Przyczyna

Metoda używa usług Platform Invocation, aby uzyskać dostęp do niezarządzanego kodu i nie jest elementem członkowskim żadnej z klas NativeMethods.

Opis reguły

Metody Platform Invocation, na przykład takie, które zostały oznaczone za pomocą atrybutu DllImportAttribute lub metody, które zostały zdefiniowane za pomocą słowa kluczowego Declare w Visual Basic uzyskują dostęp do kodu niezarządzanego.Metody te powinny być w jednej z następujących klas:

  • NativeMethods - Klasa nie odrzuca przeszukiwań stosu dla uprawnienia dla kodu niezarządzanego. (SuppressUnmanagedCodeSecurityAttribute nie może być stosowane do tej klasy.) Ta klasa jest stosowana dla metod, które mogą być wykorzystywane wszędzie, ponieważ zostanie wykonane przeszukanie stosu.

  • SafeNativeMethods - Klasa odrzuca przeszukiwania stosu dla uprawnienia dla kodu niezarządzanego. (SuppressUnmanagedCodeSecurityAttribute jest stosowany do tej klasy.) Ta klasa jest stosowana dla metod, które są bezpieczne dla każdego wywołania.Od wywołujących te metody nie wymaga się wykonania pełnego przeglądu zabezpieczeń, aby upewnić się, że użycie jest bezpieczne, ponieważ metody są nieszkodliwe dla każdego wywołującego.

  • UnSafeNativeMethods - Klasa odrzuca przeszukiwania stosu dla uprawnienia dla kodu niezarządzanego. (SuppressUnmanagedCodeSecurityAttribute jest stosowany do tej klasy.) Ta klasa jest stosowana dla metod, które są potencjalnie niebezpieczne.Każdy obiekt wywołujący którąkolwiek z metod musi wykonać pełny przegląd zabezpieczeń, aby upewnić się, że użycie jest bezpieczne ponieważ nie zostanie wykonane przeszukanie stosu.

Te klasy są zadeklarowane jako internal (Friend, w języku Visual Basic) i deklarują prywatny konstruktor, aby zapobiec tworzeniu nowych wystąpień.Metod tych klas powinny być static i internal (Shared i Friend w języku Visual Basic).

Jak naprawić naruszenia

Aby naprawić naruszenie tej zasady, należy przenieść metodę do odpowiedniej klasy NativeMethods.Dla większości aplikacji przesunięcie wywołań P/Invoke do nowej klasy o nazwie NativeMethods jest wystarczające.

Jednakże podczas opracowywania biblioteki do użytku w innych aplikacjach, należy rozważyć zdefiniowanie dodatkowych dwóch klas, które są wywoływane: SafeNativeMethods i UnsafeNativeMethods.Klasy te przypominają klasę NativeMethods; Jednakże są one oznaczone za pomocą atrybutu specjalnego o nazwie SuppressUnmanagedCodeSecurityAttribute.Po zastosowaniu tego atrybutu środowisko wykonawcze nie wykonuje pełnego przeszukiwania stosu, aby upewnić się, że wszystkie obiekty wywołujące mają uprawnienie UnmanagedCode.To uprawnienie jest zwykle sprawdzane podczas uruchamiania przez środowisko wykonawcze.Ponieważ nie jest przeprowadzana kontrola, można znacznie poprawić wydajność dla wywołań tych metod niezarządzanych, Umożliwia to także wywołanie tych metod przez kod o ograniczonych uprawnieniach.

Jednak atrybutu należy używać z dużą ostrożnością.Jeśli jest zaimplementowany niepoprawnie może to mieć poważne konsekwencje dla zabezpieczeń.

Aby uzyskać informacje o sposobie implementacji metody, zobacz przykład NativeMethods, przykład SafeNativeMethods, i przykład UnsafeNativeMethods.

Kiedy pominąć ostrzeżenia

Nie pomijaj ostrzeżeń dla tej reguły.

Przykład

W poniższym przykładzie deklarowana jest metoda, która narusza regułę.Aby poprawić naruszenie, wywołanie P/Invoke RemoveDirectory powinno zostać przeniesione do odpowiedniej klasy, przeznaczonej do przechowywania jedynie wywołań 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);
    }
}

Przykład NativeMethods

Opis

Ponieważ klasa NativeMethods nie powinna być oznaczona za pomocą SuppressUnmanagedCodeSecurityAttribute, wywołania P/Invoke, które są w niej umieszczone będą wymagały uprawnienia UnmanagedCode.Ponieważ większość aplikacji jest uruchamiane z komputera lokalnego i z pełnym zaufaniem, zwykle nie jest to problem.Jednakże podczas opracowywania bibliotek wielokrotnego użytku, należy rozważyć zdefiniowanie klasy SafeNativeMethods lub UnsafeNativeMethods.

W poniższym przykładzie pokazano metodę Interaction.Beep, która otacza funkcję MessageBeep z user32.dll.Wywołanie P/Invoke MessageBeep jest umieszczane w klasie NativeMethods.

Kod

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

Przykład SafeNativeMethods

Opis

Należy wprowadzić metody wywołań P/Invoke, które można bezpiecznie udostępniać dowolnej aplikacji i nie mają żadnych efektów ubocznych do klasy o nazwie SafeNativeMethods.Nie jest konieczne żądanie uprawnień, ani nie trzeba zwracać zbyt wiele uwagi na to skąd są wywoływane.

W poniższym przykładzie pokazano właściwość Environment.TickCount, która otacza funkcję GetTickCount z kernel32.dll.

Kod

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

Przykład UnsafeNativeMethods

Opis

Należy wprowadzić metody wywołań P/Invoke, których nie można wywołać bezpiecznie i mogą spowodować skutki uboczne do klasy o nazwie UnsafeNativeMethods.Metody te powinny być rygorystycznie sprawdzane, aby upewnić się, że te nie są niechcący wystawione dla użytkownika.Reguła CA2118: Przegląd wykorzystania SuppressUnmanagedCodeSecurityAttribute okazać się pomocna.Ewentualnie, metody powinny mieć inne uprawnienie żądane zamiast UnmanagedCode podczas ich używania.

W poniższym przykładzie pokazano metodę Cursor.Hide, która otacza funkcję ShowCursor z user32.dll.

Kod

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

Zobacz też

Inne zasoby

Ostrzeżenia projektu