次の方法で共有


CA1060: P/Invoke を NativeMethods クラスに移動します

TypeName

MovePInvokesToNativeMethodsClass

CheckId

CA1060

[カテゴリ]

Microsoft.Design

互換性に影響する変更点

あり

原因

メソッドは、プラットフォーム呼び出しサービスを使用してアンマネージ コードにアクセスしていますが、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 という名前の新しいクラスに移動すれば十分です。

ただし、他のアプリケーションで使用するライブラリを開発している場合は、SafeNativeMethodsUnsafeNativeMethods という他の 2 つのクラスを定義することを検討する必要があります。これらのクラスは NativeMethods クラスに類似していますが、SuppressUnmanagedCodeSecurityAttribute という特別な属性を使用してマークされています。この属性が適用される場合、ランタイムで、すべての呼び出し元が UnmanagedCode アクセス許可を持つかどうかを確認するための完全なスタック ウォークが実行されません。通常、ランタイムは起動時にこのアクセス許可をチェックします。このチェックが実行されないため、これらのアンマネージ メソッドを呼び出す際のパフォーマンスが大幅に向上しています。また、アクセス許可が制限されているコードでこれらのメソッドを呼び出すこともできます。

ただし、この属性を使用する場合は細心の注意が必要です。正しく実装しないと、セキュリティに重大な影響を及ぼす可能性があります。

メソッドを実装する方法については、NativeMethodsSafeNativeMethods、および UnsafeNativeMethods の各例を参照してください。

警告を抑制する状況

この規則による警告は抑制しないでください。

使用例

この規則に違反するメソッドの宣言例を次に示します。違反を修正するには、RemoveDirectory P/Invoke を、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);
    }
}

NativeMethods の例

ms182161.collapse_all(ja-jp,VS.110).gifDescription

NativeMethods クラスは SuppressUnmanagedCodeSecurityAttribute を使用してマークできないため、このクラスに配置されている P/Invoke には UnmanagedCode アクセス許可が必要です。ほとんどのアプリケーションはローカル コンピューターから完全信頼で実行されるため、通常、これは問題になりません。ただし、再利用できるライブラリを開発している場合は、SafeNativeMethods クラスまたは UnsafeNativeMethods クラスを定義することを検討する必要があります。

user32.dll の MessageBeep 関数をラップする Interaction.Beep メソッドの例を次に示します。MessageBeep P/Invoke は NativeMethods クラスに配置されています。

ms182161.collapse_all(ja-jp,VS.110).gifコード

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

SafeNativeMethods の例

ms182161.collapse_all(ja-jp,VS.110).gifDescription

アプリケーションに公開しても安全で、副作用がない P/Invoke メソッドは、SafeNativeMethods というクラスに配置する必要があります。アクセス許可を要求する必要も、呼び出し元に多大な注意を払う必要もありません。

kernel32.dll の GetTickCount 関数をラップする Environment.TickCount プロパティの例を次に示します。

ms182161.collapse_all(ja-jp,VS.110).gifコード

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

UnsafeNativeMethods の例

ms182161.collapse_all(ja-jp,VS.110).gifDescription

呼び出しが安全でなく、副作用が発生する可能性がある P/Invoke メソッドは、UnsafeNativeMethods というクラスに配置する必要があります。これらのメソッドは、誤ってユーザーに公開されないように厳密にチェックする必要があります。これには、規則「CA2118: SuppressUnmanagedCodeSecurityAttribute の使用法を再確認します」が役立ちます。または、これらのメソッドを使用する場合に、UnmanagedCode ではなく、別のアクセス許可を要求する必要があります。

user32.dll の ShowCursor 関数をラップする Cursor.Hide メソッドの例を次に示します。

ms182161.collapse_all(ja-jp,VS.110).gifコード

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

参照

その他の技術情報

デザイン上の警告