CA1060: mover P/Invokes para a classe NativeMethods
TypeName |
MovePInvokesToNativeMethodsClass |
CheckId |
CA1060 |
Categoria |
Microsoft.Design |
Alteração Significativa |
Quebra |
Causa
Um método usa Serviços de Invocação de Plataforma para acessar código não gerenciado e não é um membro de uma das classes NativeMethods.
Descrição da Regra
Métodos de Invocação de Plataforma, tais como os marcados usando o atributo DllImportAttribute, ou métodos definidos usando a palavra-chave Declare em Visual Basic acessam código não gerenciado.Esses métodos devem estar em uma das seguintes classes:
NativeMethods - esta classe não suprime movimentação da pilha para permissão de código não gerenciado. (SuppressUnmanagedCodeSecurityAttribute não deve ser aplicado a esta classe.) Essa classe é para métodos que possam ser usados em qualquer lugar já que será feita uma movimentação de pilha.
SafeNativeMethods - essa classe suprime movimentação de pilha para permissão de código não gerenciado. (SuppressUnmanagedCodeSecurityAttribute é aplicado a esta classe.) Essa classe é para métodos que são seguros para que qualquer um chame.Os chamadores de esses métodos não precisam fazer uma checagem de segurança completa para certificar-se de que o uso é seguro, já que, os métodos são inofensivos para qualquer chamador.
UnsafeNativeMethods - essa classe suprime movimentação de pilha para permissão de código não gerenciado. (SuppressUnmanagedCodeSecurityAttribute é aplicado a esta classe.) Essa classe é para métodos potencialmente perigosos.Qualquer chamador destes métodos deve fazer uma checagem de segurança completa para certificar-se de que o uso é seguro uma vez que não haverá movimentação de pilha.
Essas classes são declaradas como internal (Friend, no Visual Basic) e declaram um construtor particular para impedir que novas instâncias sejam criadas.Os métodos nestas classes devem ser static e internal (Shared e Friend no Visual Basic).
Como Corrigir Violações
Para corrigir uma violação desta regra, mova o método para a classe apropriada de NativeMethods.Para a maioria dos aplicativos, mover P/Invokes para uma nova classe chamada de NativeMethods é suficiente.
No entanto, se você estiver desenvolvendo bibliotecas para uso em outros aplicativos, você deve considerar definir duas outras classes que chamadas de SafeNativeMethods e UnsafeNativeMethods.Essas classes são semelhantes à classe NativeMethods; no entanto, são marcadas usando um atributo especial chamado SuppressUnmanagedCodeSecurityAttribute.Quando esse atributo é aplicado, o runtime não faz uma movimentação completa de pilha para certificar-se de que todos os chamadores têm a permissão UnmanagedCode.O runtime normalmente verifica por esta permissão na inicialização.Uma vez que a verificação não é executada, é possível aumentar melhorar o desempenho para chamadas a estes métodos não gerenciados. Isso também habilita que código com permissões limitadas chame estes métodos.
Você deve, no entanto, usar este atributo com muito cuidado.Ele pode ter graves implicações na segurança se implementado incorretamente.
Para obter informações sobre como implementar métodos, consulte o exemplo NativeMethods, o exemplo SafeNativeMethods, e o exemplo UnsafeNativeMethods.
Quando Suprimir Alertas
Não elimine um alerta desta regra.
Exemplo
O exemplo a seguir declara um método que viola esta regra.Para corrigir a violação o RemoveDirectory P/Invoke deve ser movido para uma classe adequada que seja projetada para armazenar somente P/Invokes.
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);
}
}
Exemplo de NativeMethods
Descrição
Uma vez que a classe NativeMethods não deve ser marcada usando P/Invokes SuppressUnmanagedCodeSecurityAttribute, que são colocado nela ela exigirá permissão UnmanagedCode.Uma vez que a maioria dos aplicativos são executados do computador local e rodam sob confiança total, isso geralmente não é um problema.No entanto, se você estiver desenvolvendo bibliotecas reutilizáveis, você deve considerar definir uma classe SafeNativeMethods ou UnsafeNativeMethods.
O exemplo a seguir mostra um método Interaction.Beep que envolve a função MessageBeep do user32.dll.O P/Invoke MessageBeep é colocado na classe NativeMethods.
Código
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);
}
Exemplo de SafeNativeMethods
Descrição
Os métodos de P/Invoke que podem ser expostos com segurança a qualquer aplicativo e que não têm nenhum efeito colateral devem ser colocados em uma classe chamada de SafeNativeMethods.Você precisa requerer permissões e você prestar muita atenção ao local de onde são chamados.
O exemplo a seguir mostra uma propriedade Environment.TickCount que envolve a função GetTickCount de kernel32.dll.
Código
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();
}
Exemplo de UnsafeNativeMethods
Descrição
Os métodos de P/Invoke que não podem ser chamados com segurança e que podem causar efeitos colaterais devem ser colocados em uma classe chamada de UnsafeNativeMethods.Esses métodos devem rigorosamente checados para certificar-se que não sejam expostos ao usuário inadvertidamente.A regra CA2118: revisar uso de SuppressUnmanagedCodeSecurityAttribute pode ajudar com isso.Alternativamente, os métodos devem ter uma outra permissão que é demandada no lugar de UnmanagedCode quando eles os usam.
O exemplo a seguir mostra um método Cursor.Hide que envolve a função ShowCursor de user32.dll.
Código
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);
}