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