Visual Studio 2017 を使用することをお勧めします

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

 

Visual Studio 2017 RC の最新のドキュメントの詳細については、Visual Studio 2017 RC ドキュメントをご参照ください。

TypeNameMovePInvokesToNativeMethodsClass
CheckIdCA1060
分類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 のみの格納用に設計されている適切なクラスに移動する必要があります。

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

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

コード

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/Invoke メソッドは、SafeNativeMethods というクラスに配置する必要があります。 アクセス許可を要求する必要も、呼び出し元に多大な注意を払う必要もありません。

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

コード

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/Invoke メソッドは、UnsafeNativeMethods というクラスに配置する必要があります。 これらのメソッドは、誤ってユーザーに公開されないように厳密にチェックする必要があります。 これには、規則「CA2118: SuppressUnmanagedCodeSecurityAttribute の使用法を再確認します」が役立ちます。 または、これらのメソッドを使用する場合に、UnmanagedCode ではなく、別のアクセス許可を要求する必要があります。

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

コード

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

デザイン上の警告

表示: