Share via


P/Invokes in NativeMethods-Klasse verschieben

Aktualisiert: November 2007

     TypeName

MovePInvokesToNativeMethodsClass

CheckId

CA1060

Kategorie

Microsoft.Design

Unterbrechende Änderung

Breaking

Ursache

Eine Methode verwendet Plattformaufrufdienste für den Zugriff auf nicht verwalteten Code und ist kein Member einer der NativeMethods-Klassen.

Regelbeschreibung

Plattformaufrufmethoden, beispielsweise Methoden, die mit dem System.Runtime.InteropServices.DllImportAttribute-Attribut gekennzeichnet sind, oder Methoden, die in Visual Basic mithilfe des Declare-Schlüsselworts definiert wurden, greifen auf nicht verwalteten Code zu. Diese Methoden müssen in einer der folgenden Klassen enthalten sein:

  • NativeMethods – Diese Klasse unterdrückt keine Stackwalks für eine Berechtigung für nicht verwalteten Code. (System.Security.SuppressUnmanagedCodeSecurityAttribute darf auf diese Klasse nicht angewendet werden.) Diese Klasse ist für Methoden vorgesehen, die an einer beliebigen Stelle verwendet werden können, da ein Stackwalk ausgeführt wird.

  • SafeNativeMethods – Diese Klasse unterdrückt Stackwalks für eine Berechtigung für nicht verwalteten Code. (System.Security.SuppressUnmanagedCodeSecurityAttribute wird auf diese Klasse angewendet.) Diese Klasse ist für Methoden vorgesehen, die von jedem Benutzer gefahrlos aufgerufen werden können. Aufrufer dieser Methoden müssen keine vollständige Sicherheitsüberprüfung durchführen, um sicherzustellen, dass ihre Verwendung sicher ist, da die Methoden für jeden Aufrufer kein Risiko darstellen.

  • UnsafeNativeMethods – Diese Klasse unterdrückt Stackwalks für eine Berechtigung für nicht verwalteten Code. (System.Security.SuppressUnmanagedCodeSecurityAttribute wird auf diese Klasse angewendet.) Diese Klasse ist für Methoden vorgesehen, die möglicherweise ein Sicherheitsrisiko darstellen. Jeder Aufrufer dieser Methoden muss eine vollständige Sicherheitsüberprüfung durchführen, um sicherzustellen, dass die Verwendung sicher ist, da kein Stackwalk ausgeführt wird.

Diese Klassen sind als internal (Friend in Visual Basic) deklariert und deklarieren einen privaten Konstruktor, um die Erstellung neuer Instanzen zu verhindern. Die Methoden in diesen Klassen sollten static und internal (Shared und Friend in Visual Basic) sein.

Behandlung von Verstößen

Um einen Verstoß gegen diese Regel zu korrigieren, verschieben Sie die Methode in die entsprechende NativeMethods-Klasse. Für die meisten Anwendungen reicht es aus, P/Invokes in eine neue Klasse mit dem Namen NativeMethods zu verschieben.

Wenn Sie jedoch Bibliotheken entwickeln, die in anderen Anwendungen verwendet werden sollen, sollten Sie zwei weitere Klassen mit dem Namen SafeNativeMethods und UnsafeNativeMethods definieren. Diese Klassen ähneln der NativeMethods-Klasse, werden jedoch mit einem bestimmten Attribut namens SuppressUnmanagedCodeSecurityAttribute markiert. Wenn dieses Attribut angewendet wird, führt die Laufzeit keinen vollständigen Stackwalk aus, um sicherzustellen, dass alle Aufrufer über die UnmanagedCode-Berechtigung verfügen. Die Laufzeit überprüft diese Berechtigung normalerweise beim Start. Da die Überprüfung nicht ausgeführt wird, kann die Leistung bei Aufrufen dieser nicht verwalteten Methoden beträchtlich gesteigert werden und Code mit eingeschränkten Berechtigungen kann darüber hinaus die Genehmigung erteilt werden, diese Methoden aufzurufen.

Dieses Attribut sollte jedoch mit besonderer Sorgfalt angewendet werden, da es bei falscher Implementierung ernste Sicherheitsprobleme verursachen kann.

Weitere Informationen zum Implementieren der Methoden finden Sie in den Beispielen NativeMethods, SafeNativeMethods und UnsafeNativeMethods.

Wann sollten Warnungen unterdrückt werden?

Unterdrücken Sie keine Warnung dieser Regel.

Beispiel

Im folgenden Beispiel wird eine Methode deklariert, die gegen diese Regel verstößt. Um den Verstoß zu beheben, sollte RemoveDirectory P/Invoke in die entsprechende Klasse verschoben werden, die nur für die Aufnahme von P/Invokes vorgesehen ist.

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

NativeMethods-Beispiel

Beschreibung

Da die NativeMethods-Klasse nicht mit SuppressUnmanagedCodeSecurityAttribute markiert werden sollte, erfordert die darin platzierte P/Invokes-Klasse die UnmanagedCode-Berechtigung. Da die meisten Anwendungen vom lokalen Computer ausgeführt werden und voll vertrauenswürdig sind, stellt dies normalerweise kein Problem dar. Wenn Sie jedoch wiederverwendbare Bibliotheken entwickeln, sollten Sie erwägen, eine SafeNativeMethods-Klasse oder UnsafeNativeMethods-Klasse zu definieren.

Im folgenden Beispiel wird eine Interaction.Beep-Methode veranschaulicht, die die MessageBeep-Funktion von user32.dll umschließt. MessageBeep P/Invoke wird innerhalb der NativeMethods-Klasse platziert.

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

SafeNativeMethods-Beispiel

Beschreibung

P/Invoke-Methoden, die für beliebige Anwendungen verfügbar gemacht werden können und keine Nebeneffekte haben, sollten in der Klasse SafeNativeMethods platziert werden. Sie müssen in diesem Fall keine Berechtigungen fordern und nicht besonders darauf achten, von wo sie aufgerufen werden.

Im folgenden Beispiel wird eine Environment.TickCount-Eigenschaft veranschaulicht, die die GetTickCount-Funktion aus kernel32.dll umschließt.

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

UnsafeNativeMethods-Beispiel

Beschreibung

P/Invoke-Methoden, die nicht sicher aufgerufen werden und Nebeneffekte verursachen können, sollten in einer Klasse mit dem Namen UnsafeNativeMethods platziert werden. Diese Methoden sollten streng überprüft werden, um sicherzustellen, dass sie nicht unbeabsichtigt für den Benutzer verfügbar gemacht werden. Die Regel Überprüfen der SuppressUnmanagedCodeSecurityAttribute-Verwendung kann dabei hilfreich sein. Alternativ sollten die Methoden über eine andere Berechtigung verfügen, die anstelle von UnmanagedCode gefordert wird, wenn sie verwendet wird.

Im folgenden Beispiel wird eine Cursor.Hide-Methode veranschaulicht, die die ShowCursor-Funktion aus user32.dll umschließt.

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

Siehe auch

Weitere Ressourcen

Entwurfswarnungen