CA1060: Přesuňte volání nespravovaných kódů do třídy NativeMethods
TypeName |
MovePInvokesToNativeMethodsClass |
CheckId |
CA1060 |
Kategorie |
Microsoft.Design |
Narušující změna |
Narušující |
Příčina
Metoda používá služby vyvolání platformy k přístupu k nespravovanému kódu a není členem jedné z tříd NativeMethods.
Popis pravidla
Metody vyvolání platformy, například ty, které jsou označeny pomocí atributu DllImportAttribute nebo metody, které jsou definovány pomocí použitím klíčového slova Declare v rámci Visual Basic, přistupují k nespravovanému kódu.Tyto metody by měly být v jedné z následujících tříd:
NativeMethods - Tato třída nepotlačuje krokování zásobníku pro oprávnění k nespravovanému kódu. (SuppressUnmanagedCodeSecurityAttribute nesmí být použito u této třídy.) Tato třída je pro metody, které lze použít kdekoli, protože zásobníku bude prováděno krokování zásobníku.
SafeNativeMethods - Tato třída potlačuje krokování zásobníku pro oprávnění k nespravovanému kódu. (SuppressUnmanagedCodeSecurityAttribute je použito u této třídy.) Tato třída je pro metody, které jsou bezpečné při každém volání.Volající těchto metod nejsou povinni provádět úplné přezkoumání zabezpečení pro ujištění, zda je použití zabezpečené, jelikož jsou metody neškodné pro všechny volající.
UnsafeNativeMethods - Tato třída potlačuje krokování zásobníku pro oprávnění k nespravovanému kódu. (SuppressUnmanagedCodeSecurityAttribute je použito u této třídy.) Tato třída je pro metody, které jsou potenciálně nebezpečné.Jakýkoliv volající těchto metod musí provést úplné přezkoumání zabezpečení pro ujištění, zda je použití zabezpečené, protože žádné krokování zásobníku nebude provedeno.
Tyto třídy jsou v jazyce Visual Basic deklarovány jako internal (Friend a deklarují privátní konstruktor pro zabránění vytváření nových instancí.Metody uvedené v těchto tříd by měly být static a internal (Shared a Friend v jazyce Visual Basic).
Jak vyřešit porušení
Pro vyřešení porušení tohoto pravidla odstranit, přesuňte metodu do příslušné třídy NativeMethods.Pro většinu aplikací je dostačující přesunutí do nové třídy s názvem NativeMethods.
Pokud však vyvíjíte knihovny pro použití v jiných aplikacích, zvažte definování dvou dalších tříd s názvem SafeNativeMethods a UnsafeNativeMethods.Tyto třídy se podobají třídě NativeMethods, avšak jsou označeny použitím speciálního atributu s názvem SuppressUnmanagedCodeSecurityAttribute.Při použití tohoto atributu neprovádí modul runtime úplné krokování zásobníku k ověření, zda mají všichni volající oprávnění UnmanagedCode.Modul runtime obvykle toto oprávnění zkontroluje při spuštění.Protože se kontrola neprovádí, může to znamenat značné zlepšení výkon pro volání těchto nespravovaných metod. Je také umožněno volání těchto metod kódem, který který má k volání minimální oprávnění.
Tento atribut by měl být však používán velmi opatrně.Pokud je nesprávně implementován může vést k závažným následkům při zabezpečení..
Informace o implementaci metod naleznete v příkladu NativeMethods, v příkladu SafeNativeMethods a v příkladu UnsafeNativeMethods.
Kdy potlačit upozornění
Nepotlačujte upozornění na toto pravidlo.
Příklad
Následující příklad deklaruje metodu, která toto pravidlo porušuje.Pro odstranění konfliktu by mělo být P/Invoke RemoveDirectory přesunuto do příslušné třídy, která je určena pro uložení pouze 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);
}
}
Příklad NativeMethods
Description
Protože by třída NativeMethods neměla být označena použitím P/Invoke SuppressUnmanagedCodeSecurityAttribute, které jsou v ni umístěny, bude zapotřebí oprávnění UnmanagedCode.Protože většina aplikací je spuštěna z místního počítače a je spuštěna s plnou důvěrou, nepředstavuje toto obvykle problém.Pokud však vyvíjíte opakovaně využitelné knihovny, zvažte definování třídy SafeNativeMethods nebo třídy UnsafeNativeMethods.
Následující příklad ukazuje metodu Interaction.Beep, která zabalí funkci MessageBeep z knihovny user32.dll.P/Invoke MessageBeep je vložen do třídy NativeMethods.
Kód
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);
}
Příklad SafeNativeMethods
Description
Metody P/Invoke, které mohou být bezpečně vystaveny a nemají žádné vedlejší účinky by měly být umístěny do třídy s názvem SafeNativeMethods.Nemusíte požadovat oprávnění a nemusíte příliš věnovat pozornost odkud kam jsou volány.
Následující příklad ukazuje vlastnost Environment.TickCount, která zabalí funkci GetTickCount z knihovny kernel32.dll.
Kód
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();
}
Příklad UnsafeNativeMethods
Description
Metody P/Invoke, které nelze bezpečně volat a které mohou způsobit vedlejší účinky by měly být umístěny do třídy s názvem UnsafeNativeMethods.Tyto metody by měly být důsledně kontrolovány pro ujištění, že nedojde k jejich neúmyslnému vystavení uživateli.S tím může pomoci pravidlo CA2118: Zkontrolujte použití SuppressUnmanagedCodeSecurityAttribute.Případně by měly metody mít jiné oprávnění, které bude při jejich použití požadováno místo UnmanagedCode.
Následující příklad ukazuje metodu Cursor.Hide, která zabalí funkci ShowCursor z knihovny user32.dll.
Kód
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);
}