首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >专栏 >CA1060:将 P/Invoke 移动到 NativeMethods 类

CA1060:将 P/Invoke 移动到 NativeMethods 类

作者头像
呆呆
发布于 2022-02-22 12:52:17
发布于 2022-02-22 12:52:17
45900
代码可运行
举报
文章被收录于专栏:centosDaicentosDai
运行总次数:0
代码可运行

规则 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
代码运行次数:0
运行
AI代码解释
复制
' 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
代码运行次数:0
运行
AI代码解释
复制
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
代码运行次数:0
运行
AI代码解释
复制
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
代码运行次数:0
运行
AI代码解释
复制
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 删除。

评论
登录后参与评论
暂无评论
推荐阅读
编辑精选文章
换一批
TabControl控件的美化
文件下载:http://files.cnblogs.com/zfanlong1314/TabControlEX.rar
跟着阿笨一起玩NET
2018/09/19
2.1K0
TabControl控件的美化
打印自定义纸张大小
长江支流说的办法保留太多了,结果不行,很多类都是他在程序集里自定义的,源码又没公开
Java架构师必看
2021/03/22
8440
扫描仪对接(C#)
源代码地址:http://www.codeproject.com/Articles/171666/Twain-for-WPF-Applications-Look-Ma-No-Handles
码客说
2022/09/19
4.9K0
扫描仪对接(C#)
C# DllImport的用法
大家在实际工作学习C#的时候,可能会问:为什么我们要为一些已经存在的功能(比如Windows中的一些功能,C++中已经编写好的一些方法)要重新编写代码,C#有没有方法可以直接都用这些原本已经存在的功能呢?答案是肯定的,大家可以通过C#中的DllImport直接调用这些功能。 DllImport所在的名字空间 using System.Runtime.InteropServices; MSDN中对DllImportAttribute的解释是这样的:可将该属性应用于方法。DllImportAttribute 属性提供对从非托管 DLL 导出的函数进行调用所必需的信息。作为最低要求,必须提供包含入口点的 DLL 的名称。 DllImport 属性定义如下: namespace System.Runtime.InteropServices {   [AttributeUsage(AttributeTargets.Method)]   public class DllImportAttribute: System.Attribute   {    public DllImportAttribute(string dllName) {…}    public CallingConvention CallingConvention;    public CharSet CharSet;    public string EntryPoint;    public bool ExactSpelling;    public bool PreserveSig;    public bool SetLastError;    public string Value { get {…} }   } }   说明:   1、DllImport只能放置在方法声明上。   2、DllImport具有单个定位参数:指定包含被导入方法的 dll 名称的 dllName 参数。   3、DllImport具有五个命名参数:    a、CallingConvention 参数指示入口点的调用约定。如果未指定 CallingConvention,则使用默认值 CallingConvention.Winapi。    b、CharSet 参数指示用在入口点中的字符集。如果未指定 CharSet,则使用默认值 CharSet.Auto。    c、EntryPoint 参数给出 dll 中入口点的名称。如果未指定 EntryPoint,则使用方法本身的名称。    d、ExactSpelling 参数指示 EntryPoint 是否必须与指示的入口点的拼写完全匹配。如果未指定 ExactSpelling,则使用默认值 false。    e、PreserveSig 参数指示方法的签名应当被保留还是被转换。当签名被转换时,它被转换为一个具有 HRESULT 返回值和该返回值的一个名为 retval 的附加输出参数的签名。如果未指定 PreserveSig,则使用默认值 true。    f、SetLastError 参数指示方法是否保留 Win32″上一错误”。如果未指定 SetLastError,则使用默认值 false。   4、它是一次性属性类。   5、此外,用 DllImport 属性修饰的方法必须具有 extern 修饰符。
全栈程序员站长
2022/07/23
1.2K0
【NEW】WPF MVVM 模式下自写自用的窗口样式
SVG是一种图形文件格式,它的英文全称为Scalable Vector Graphics,意思为可缩放的矢量图形。它是基于XML(Extensible Markup Language),由World Wide Web Consortium(W3C)联盟进行开发的。严格来说应该是一种开放标准的矢量图形语言,可让你设计激动人心的、高分辨率的Web图形页面。用户可以直接用代码来描绘图像,可以用任何文字处理工具打开SVG图像,通过改变部分代码来使图像具有交互功能,并可以随时插入到HTML中通过浏览器来观看。
Shunnet
2022/09/01
2.5K0
【NEW】WPF MVVM 模式下自写自用的窗口样式
wpf键盘记录器
很简单的一个wpf键盘记录器 这个程序我一样用了全局勾子,之前用的都是winform上运行了,前一段时间 在国外的论坛上逛看到了一个wpf能用的就做了一个小程序记录一下,为了方便大家直关的看我在页面上
lpxxn
2018/01/31
1.3K0
wpf键盘记录器
C++/CLI(二)Mono C++/CLI Native调用和P/Invoke调用
本文根据Mono C++原文档翻译,这篇文章的目的,就是想说CLR程序在VS下面生成的DLL不能给Unity调用,因为Mono的Native调用的编码和MS CLR的不一样,如果Unity想要去调用C++程序,需要使用P/Invoke的方式,这两者的不兼容使得本来非常方便的C++/CLI在Unity下毫无用武之地,希望有一天MS能够给Mono CLR一片土地,方便你我他,还有就是高高兴兴写了半个月MS CLR以为能在Unity下使用了,结果一Run就炸,所以说以后代码未动,单元测试一定要先写啊,这片区代码需要全部重构了,血与泪的教训。
Pulsar-V
2019/04/01
3.9K0
.NET简谈互操作(五:基础知识之Dynamic平台调用)
我们继续.NET互操作学习。在上篇文章中我们学习了关于托管与非托管内存Dispose(释放)问题;下面我们继续学习基础知识中的Dynamic(动态)平台调用技术;
王清培
2022/03/14
4620
.NET简谈互操作(五:基础知识之Dynamic平台调用)
基于windowsphone7的控制ppt播放 第一部分 服务器端
最近突然想起了一个学长的一个利用手机控制ppt播放的一个创意,并想将其在windows phone7上实现一下。 经过几天的努力已经可以控制ppt的播放,暂停,上一张,下一张了,并且电脑会将当前ppt的截图发送到手机端这里。 在代码的编写过程中,参考了IT黄老邪的Windows Phone开发(46):与Socket有个约会 进行服务端与wp客户端的socket通讯的编写,并加入了键盘消息模拟,服务端截屏,图片发送,与客户端的图片接受。 代码如下: WP客户端 1、新建Windows Phone应用程序项目
magicsoar
2018/02/06
9720
基于windowsphone7的控制ppt播放 第一部分 服务器端
CA2109:检查可见的事件处理程序
除非绝对必要,否则不要公开事件处理方法。 只要处理程序和事件签名匹配,就可以将调用公开方法的事件处理程序(委托类型)添加到任何事件中。 事件可能由任何代码引发,并且经常由高度可信的系统代码引发,以响应用户操作(例如单击某个按钮)。 向事件处理方法添加安全检查不会阻止代码注册调用方法的事件处理程序。
用户4268038
2022/02/20
6730
WPF内存优化
下载地址: https://pan.baidu.com/s/1nLF6njntaVgrXVdIaT1mOw 提取码: phsy
码客说
2020/08/19
1.7K0
WPF 使用GDI+提取图片主色调并生成Mica材质特效背景
TwilightLemon/MicaImageTest: WPF 使用GDI+提取图片主色调并生成Mica材质特效背景
郑子铭
2025/07/02
430
WPF 使用GDI+提取图片主色调并生成Mica材质特效背景
关于Form.Close跟Form.Dispose
我们在Winform开发的时候,使用From.Show来显示窗口,使用Form.Close来关闭窗口。熟悉Winform开发的想必对这些非常熟悉。但是Form类型实现了IDisposable接口,那我
MJ.Zhou
2018/01/04
1.6K0
关于Form.Close跟Form.Dispose
.NET 7 AOT 的使用以及 .NET 与 Go 互相调用
最近时总更新太快了,太卷了,所以借着 .NET 7 正式版发布,熬夜写完这篇文章,希望能够追上时总的一点距离。
痴者工良
2022/11/23
2.6K0
.NET 7 AOT 的使用以及 .NET 与 Go 互相调用
C# 窗体常用API函数 应用程序窗体查找
常用的处理窗体的API函数如下(注意:API函数必须放在窗体中...): 使用C#语言,要引用DllImport,必须要添加using System.Runtime.InteropServices命名空间 (1)获得当前前台窗体句柄 [DllImport("user32.dll", CharSet = CharSet.Auto, ExactSpelling = true)]public static extern IntPtr GetForegroundWindow(); 返回值类型是IntPtr,即为当前
逸鹏
2018/04/10
4.2K0
C#中通过API实现的打印类---修改自泥人张版本
using System; using System.Collections; using System.Text; using System.Runtime.InteropServices; using System.Security; using System.ComponentModel; using System.Drawing.Printing; namespace PrinterAPI {  public class Printer  {   private Printer()   {   }  ///泥人张版本加强版   #region API声明   [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)]    internal struct structPrinterDefaults   {    [MarshalAs(UnmanagedType.LPTStr)]    public String pDatatype;    public IntPtr pDevMode;    [MarshalAs(UnmanagedType.I4)]    public int DesiredAccess;   };   [DllImport("winspool.Drv", EntryPoint = "OpenPrinter", SetLastError = true,     CharSet = CharSet.Unicode, ExactSpelling = false, CallingConvention = CallingConvention.StdCall),   SuppressUnmanagedCodeSecurityAttribute()]   internal static extern bool OpenPrinter([MarshalAs(UnmanagedType.LPTStr)]    string printerName,    out IntPtr phPrinter,    ref structPrinterDefaults pd);   [DllImport("winspool.Drv", EntryPoint = "ClosePrinter", SetLastError = true,     CharSet = CharSet.Unicode, ExactSpelling = false,     CallingConvention = CallingConvention.StdCall), SuppressUnmanagedCodeSecurityAttribute()]   internal static extern bool ClosePrinter(IntPtr phPrinter);   [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)]    internal struct structSize   {    public Int32 width;    public Int32 height;   }   [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)]    internal struct structRect   {    public Int32 left;    public Int32 top;    public Int32 right;    public Int32 bottom;   }   [StructLayout(LayoutKind.Explicit, CharSet = CharSet.Unicode)]    internal struct FormInfo1   {    [FieldOffset(0), MarshalAs(UnmanagedType.I4)]    public uint Flags;    [FieldOffset(4), MarshalAs(UnmanagedType.LPWStr)]    public String pName;    [FieldOffset(8)]    public structSize Size;    [FieldOffset(16)]    public structRect ImageableArea;   };   [StructLayout(LayoutKind.Sequential, CharSet = CharSet
jack.yang
2025/04/05
1040
进程注入
通过 KernelCallBackTable 的进程注入涉及用自定义有效载荷替换原始回调函数,以便每当调用该函数时,都会触发有效载荷。在这种情况下,使用了 fnCOPYDATA 回调函数。
Khan安全团队
2021/12/31
5880
dotnet 获取指定进程的输入命令行
我找到两个方法,一个需要引用 C++ 库支持 x86 和 x64 程序,另一个都是C#代码,但是只支持 x64 程序
林德熙
2019/03/13
1.3K0
【C#】分享一个弹出容器层,像右键菜单那样召即来挥则去
------------------201508261813更新(源码有更新、Demo未更新)------------------
AhDung
2018/09/13
3K0
【C#】分享一个弹出容器层,像右键菜单那样召即来挥则去
C#进阶——记一次USB HID的各种坑(x86,x64,win10,win7)
写工控上位机的搬砖人,难免会遇到USB通讯,在一个项目中,我写的上位机使用USB HID协议和STM32通讯传输数据,从零大概花了几天找例程,找资料,最后是各种搬砖修补,终于出来了一个出版DOME,能和下位机实时通讯了。
vv彭
2022/05/10
2.9K2
相关推荐
TabControl控件的美化
更多 >
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档
本文部分代码块支持一键运行,欢迎体验
本文部分代码块支持一键运行,欢迎体验