CA1060: P/Invokes in NativeMethods-Klasse verschieben
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, z. B. solche, 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.
Behandeln 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 diese Methoden aufrufen.
Sie sollten jedoch dieses Attribut mit großer Sorgfalt verwenden. Dies kann bei einer falschen Implementierung ernste Auswirkungen auf die Sicherheit haben.
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
Beschreibungen
Da die NativeMethods-Klasse nicht mit SuppressUnmanagedCodeSecurityAttribute markiert werden sollte, erfordern darin platzierte P/Invokes die UnmanagedCode-Berechtigung. Da die meisten Anwendungen vom lokalen Computer ausgeführt werden und zusammen 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. Der P/Invoke MessageBeep wird in 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
Beschreibungen
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
Beschreibungen
P/Invoke-Methoden, die nicht sicher aufgerufen werden können und unter Umständen Nebeneffekte verursachen, sollten in einer Klasse mit dem Namen UnsafeNativeMethods definiert werden. Diese Methoden sollten streng überprüft werden, um sicherzustellen, dass sie nicht unbeabsichtigt für den Benutzer verfügbar gemacht werden. Die Regel CA2118: Überprüfen der Verwendung von SuppressUnmanagedCodeSecurityAttribute 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);
}