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)로 선언되고 새 인스턴스가 만들어지지 않도록 하기 위해 private 생성자를 선언합니다.이들 클래스의 메서드는 static 및 internal(Visual Basic의 경우 Shared 및 Friend)이어야 합니다.

위반 문제를 해결하는 방법

이 규칙 위반 문제를 해결하려면 메서드를 적절한 NativeMethods 클래스로 이동합니다.대부분의 응용 프로그램에서는 P/Invoke를 이름이 NativeMethods인 새 클래스로 이동하면 됩니다.

그러나 다른 응용 프로그램에서 사용하기 위한 라이브러리를 개발하는 경우에는 다른 두 클래스, 즉 SafeNativeMethodsUnsafeNativeMethods를 정의해야 할 수 있습니다.이러한 클래스는 NativeMethods 클래스와 비슷하지만 SuppressUnmanagedCodeSecurityAttribute라는 특수한 특성을 사용하여 표시됩니다.이 특성을 적용하면 런타임이 모든 호출자에게 UnmanagedCode 권한이 있는지를 확인하기 위한 전체 스택 워크를 수행하지 않으며대개 시작 시에만 이 권한을 확인합니다.확인이 수행되지 않기 때문에 이와 같은 관리되지 않는 메서드 호출에 대한 성능을 크게 향상시킬 수 있으며, 권한이 제한된 코드를 사용하여 이러한 메서드를 호출할 수도 있습니다.

그러나 이 특성을 사용할 때는 주의를 기울여야 합니다.잘못 구현할 경우 심각한 보안 관련 문제가 발생할 수 있습니다.

메서드를 구현하는 방법에 대한 자세한 내용은 NativeMethods 예제, SafeNativeMethods 예제 및 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(ko-kr,VS.110).gif설명

NativeMethods 클래스는 SuppressUnmanagedCodeSecurityAttribute를 사용하여 표시해서는 안 되기 때문에 이 클래스에 있는 P/Invoke에는 UnmanagedCode 권한이 필요합니다.대부분의 응용 프로그램은 로컬 컴퓨터에서 완전 신뢰로 실행되므로 일반적으로 이는 문제가 되지 않습니다.그러나 재사용 가능한 라이브러리를 개발하는 경우에는 SafeNativeMethods 또는 UnsafeNativeMethods 클래스를 정의해야 할 수 있습니다.

다음 예제에서는 user32.dll에서 MessageBeep 함수를 래핑하는 Interaction.Beep 메서드를 보여 줍니다.MessageBeep P/Invoke는 NativeMethods 클래스에 배치됩니다.

ms182161.collapse_all(ko-kr,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(ko-kr,VS.110).gif설명

모든 응용 프로그램에 안전하게 노출할 수 있으며 부정적인 결과를 유발하지 않는 P/Invoke 메서드는 이름이 SafeNativeMethods인 클래스에 배치해야 합니다.그러면 권한을 요청할 필요가 없으며 메서드를 호출하는 위치에 대해 크게 신경쓰지 않아도 됩니다.

다음 예제에서는 kernel32.dll에서 GetTickCount 함수를 래핑하는 Environment.TickCount 속성을 보여 줍니다.

ms182161.collapse_all(ko-kr,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(ko-kr,VS.110).gif설명

안전하게 호출할 수 없고 부정적인 결과를 유발할 수 있는 P/Invoke 메서드는 이름이 UnsafeNativeMethods인 클래스에 배치해야 합니다.이러한 메서드는 실수로 사용자에게 노출하는 일이 없도록 엄격하게 확인해야 합니다.규칙 CA2118: SuppressUnmanagedCodeSecurityAttribute 사용을 검토하십시오.를 사용하면 이 작업을 수행하는 데 도움이 됩니다.또한 이 메서드는 사용되는 경우 UnmanagedCode 대신 다른 권한을 요청해야 합니다.

다음 예제에서는 user32.dll에서 ShowCursor 함수를 래핑하는 Cursor.Hide 메서드를 보여 줍니다.

ms182161.collapse_all(ko-kr,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);   
}

참고 항목

기타 리소스

디자인 경고