前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >CA1060:将 P/Invoke 移动到 NativeMethods 类

CA1060:将 P/Invoke 移动到 NativeMethods 类

作者头像
呆呆
发布2022-02-22 20:52:17
4110
发布2022-02-22 20:52:17
举报
文章被收录于专栏:centosDai

规则 ID

CA1060

类别

设计

修复是中断修复还是非中断修复

重大

原因

方法使用平台调用服务访问非托管代码,不是 NativeMethods 类之一的成员。

规则说明

平台调用方法(如使用 System.Runtime.InteropServices.DllImportAttribute 属性标记的方法)或在 Visual Basic 中使用 Declare 关键字定义的方法可访问非托管代码。 这些方法应是处于以下一个类中:

NativeMethods - 此类不会对非托管代码权限取消堆栈审核。 (System.Security.SuppressUnmanagedCodeSecurityAttribute 不得应用于此类。)此类用于可在任何位置使用的方法,因为会执行堆栈审核。

SafeNativeMethods - 此类会对非托管代码权限取消堆栈审核。 (System.Security.SuppressUnmanagedCodeSecurityAttribute 应用于此类。)此类用于可供任何人安全调用的方法。 这些方法的调用方不需要执行完整安全评审以确保使用是安全的,因为这些方法对于任何调用方都无害。

UnsafeNativeMethods - 此类会对非托管代码权限取消堆栈审核。 (System.Security.SuppressUnmanagedCodeSecurityAttribute 应用于此类。)此类用于有潜在危险的方法。 这些方法的任何调用方都必须执行完整安全检查,以确保使用是安全的,因为不会执行任何堆栈审核。

这些类声明为 internal(在 Visual Basic 中为 Friend),并声明一个私有构造函数来阻止创建新实例。 这些类中的方法应是 static 和 internal(在在 Visual Basic 中是 Shared 和 Friend)。

如何解决冲突

若要解决与此规则的冲突,请将方法移动到合适的 NativeMethods 类中。 对于大多数应用程序,将 P/Invoke 移动到名为 NativeMethods 的新类便足够了。

但是,如果要开发在其他应用程序中使用的库,应考虑定义两个名为 SafeNativeMethods 和 UnsafeNativeMethods 的其他类。 这些类与 NativeMethods 类相似;但是,它们使用名为 SuppressUnmanagedCodeSecurityAttribute 的特殊属性进行标记 。 应用此属性时,运行时不会执行完整堆栈审核来确保所有调用方都具有 UnmanagedCode 权限。 运行时通常会在启动时检查是否具有此权限。 因此可极大地提高对这些非托管方法的调用的性能,还使具备有限权限的代码可以调用这些方法。

不过,应非常小心地使用此属性。 如果未正确实现,则可能会产生严重的安全隐患。

有关如何实现这些方法的信息,请参阅 NativeMethods 示例、SafeNativeMethods 示例和 UnsafeNativeMethods 示例 。

何时禁止显示警告

不禁止显示此规则发出的警告。

示例

下面的示例声明了违反此规则的方法。 若要更正该冲突,应将 RemoveDirectory P/Invoke 移动到设计为仅保存 P/invoke 的适当类。

代码语言:javascript
复制
' Violates rule: MovePInvokesToNativeMethodsClass.
Friend Class UnmanagedApi
    Friend Declare Function RemoveDirectory Lib "kernel32" (
   ByVal Name As String) As Boolean
End Class
// Violates rule: MovePInvokesToNativeMethodsClass.
internal class UnmanagedApi
{
    [DllImport("kernel32.dll", CharSet = CharSet.Unicode)]
    internal static extern bool RemoveDirectory(string name);
}

NativeMethods 示例

由于 NativeMethods 类不应使用 SuppressUnmanagedCodeSecurityAttribute 进行标记,因此,置于其中的 P/invoke 需要 UnmanagedCode 权限 。 由于大多数应用程序从本地计算机运行并随完全信任一起运行,因此这通常不会成为问题。 但是,如果要开发可重用的库,则应考虑定义 SafeNativeMethods 或 UnsafeNativeMethods 类 。

下面的示例演示了一个 Interaction.Beep 方法,它可包装来自 user32.dll 的 MessageBeep 函数 。 MessageBeep P/Invoke 会置于 NativeMethods 类中 。

代码语言:javascript
复制
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
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 示例

可以安全地向任何应用程序公开并且没有任何副作用的 P/Invoke 方法应置于名为 SafeNativeMethods 的类中。 不必要求获得权限,也不必过多注意从其处调用权限。

下面的示例演示了一个 Environment.TickCount 属性,它可包装来自 kernel32.dll 的 GetTickCount 函数 。

代码语言:javascript
复制
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
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 示例

不能安全调用并且可能导致副作用的 P/Invoke 方法应置于名为 UnsafeNativeMethods 的类中。 应严格检查这些方法,以确保不会无意中向用户公开它们。 此外,这些方法在使用时,还应具有所需的其他权限,而不是 UnmanagedCode。

下面的示例演示了一个 Cursor.Hide 方法,它可包装来自 user32.dll 的 ShowCursor 函数 。

代码语言:javascript
复制
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
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);
}

另请参阅

设计规则

本文系外文翻译,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文系外文翻译前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档