Share via


관리 코드에서 프로토타입 만들기

이 항목에서는 관리되지 않는 함수에 액세스하는 방법을 설명하고 관리 코드에서 메서드 정의에 주석을 다는 여러 특성 필드를 소개합니다. 플랫폼 호출에서 사용되는 .NET 기반 선언을 생성하는 방법을 보여 주는 예제는 플랫폼 호출을 사용하여 데이터 마샬링을 참조하세요.

관리 코드에서 관리되지 않는 DLL 함수에 액세스하기 전에 함수 이름과 함수를 내보내는 DLL 이름을 알아야 합니다. 이 정보를 사용하여 DLL에서 구현되는 관리되지 않는 함수에 대한 관리되는 정의를 쓰기 시작할 수 있습니다. 또한 플랫폼 호출이 함수를 만들고 데이터를 함수로 또는 반대로 마샬링하는 방법을 조정할 수 있습니다.

참고 항목

문자열을 할당하는 Windows API 함수를 통해 LocalFree와 같은 메서드를 사용하여 문자열을 해제할 수 있습니다. 플랫폼 호출은 매개 변수를 다르게 처리합니다. 플랫폼 호출의 경우 매개 변수를 String 형식 대신 IntPtr 형식으로 설정합니다. System.Runtime.InteropServices.Marshal 클래스에서 제공된 메서드를 사용하여 형식을 문자열로 수동으로 변환하고 해제합니다.

선언 기본 사항

관리되지 않는 함수에 대한 관리되는 정의는 다음 예제와 같이 언어 종속적입니다. 전체 코드 예제를 보려면 플랫폼 호출 예제를 참조하세요.

Friend Class NativeMethods
    Friend Declare Auto Function MessageBox Lib "user32.dll" (
        ByVal hWnd As IntPtr,
        ByVal lpText As String,
        ByVal lpCaption As String,
        ByVal uType As UInteger) As Integer
End Class

DllImportAttribute.BestFitMapping, DllImportAttribute.CallingConvention, DllImportAttribute.ExactSpelling, DllImportAttribute.PreserveSig, DllImportAttribute.SetLastError 또는 DllImportAttribute.ThrowOnUnmappableChar 필드를 Visual Basic 선언에 적용하려면 Declare 문 대신 DllImportAttribute 특성을 사용해야 합니다.

Imports System.Runtime.InteropServices

Friend Class NativeMethods
    <DllImport("user32.dll", CharSet:=CharSet.Auto)>
    Friend Shared Function MessageBox(
        ByVal hWnd As IntPtr,
        ByVal lpText As String,
        ByVal lpCaption As String,
        ByVal uType As UInteger) As Integer
    End Function
End Class
using System;
using System.Runtime.InteropServices;

internal static class NativeMethods
{
    [DllImport("user32.dll")]
    internal static extern int MessageBox(
        IntPtr hWnd, string lpText, string lpCaption, uint uType);
}
using namespace System;
using namespace System::Runtime::InteropServices;

[DllImport("user32.dll")]
extern "C" int MessageBox(
    IntPtr hWnd, String* lpText, String* lpCaption, unsigned int uType);

정의 조정

명시적으로 설정하는지와 관계없이 특성 필드는 관리 코드 동작을 정의합니다. 플랫폼 호출은 어셈블리에서 메타데이터로 있는 다양한 필드에 설정된 기본값에 따라 작동합니다. 필드 하나 이상의 값을 조정하여 이 기본 동작을 변경할 수 있습니다. 대부분 DllImportAttribute를 사용하여 값을 설정합니다.

다음 표에는 플랫폼 호출과 관련된 전체 특성 필드 집합이 나와 있습니다. 표에는 각 필드에 대한 기본값과 이들 필드를 사용하여 관리되지 않는 DLL 함수를 정의하는 방법에 대한 정보 링크가 포함됩니다.

필드 설명
BestFitMapping 최적 매핑을 사용하거나 사용하지 않도록 설정합니다.
CallingConvention 메서드 인수 전달 시 사용할 호출 규칙을 지정합니다. 기본값은 WinAPI로, 32비트 Intel 기반 플랫폼의 __stdcall에 해당합니다.
CharSet 이름 손상 및 문자열 인수가 함수로 마샬링되는 방법을 제어합니다. 기본값은 CharSet.Ansi입니다.
EntryPoint 호출할 DLL 진입점을 지정합니다.
ExactSpelling 문자 집합과 일치하도록 진입점을 수정해야 하는지를 제어합니다. 기본값은 프로프래밍 언어에 따라 달라집니다.
PreserveSig HRESULT를 반환하고 반환 값에 대한 추가 [out, retval] 인수가 포함된 관리되지 않는 서명으로 관리되는 메서드 서명을 변환할지를 제어합니다.

기본값은 true입니다(서명을 변형하지 않아야 함).
SetLastError 호출자가 Marshal.GetLastWin32Error API 함수를 사용하여 메서드를 실행하는 동안 오류가 발생했는지를 확인할 수 있도록 합니다. Visual Basic에서 기본값은 true이고, C# 및 C++에서 기본값은 false입니다.
ThrowOnUnmappableChar ANSI "?" 문자로 변환되는 매핑할 수 없는 유니코드 문자에 대한 예외 throw를 제어합니다.

자세한 참조 정보는 DllImportAttribute를 참조하세요.

플랫폼 호출 보안 고려 사항

SecurityAction 열거형의 Assert, DenyPermitOnly 멤버를 스택 워크 한정자라고 합니다. 이들 멤버는 플랫폼 호출 선언 및 COM IDL(Interface Definition Language) 문에서 선언 특성으로 사용될 경우 무시됩니다.

플랫폼 호출 예제

이 섹션의 플랫폼 호출 샘플에서는 스택 워크 한정자와 함께 RegistryPermission 특성을 사용하는 방법을 보여 줍니다.

다음 예제에서는 SecurityActionAssert, DenyPermitOnly 한정자가 무시됩니다.

[DllImport("MyClass.dll", EntryPoint = "CallRegistryPermission")]  
[RegistryPermission(SecurityAction.Assert, Unrestricted = true)]  
    private static extern bool CallRegistryPermissionAssert();  
  
[DllImport("MyClass.dll", EntryPoint = "CallRegistryPermission")]  
[RegistryPermission(SecurityAction.Deny, Unrestricted = true)]  
    private static extern bool CallRegistryPermissionDeny();  
  
[DllImport("MyClass.dll", EntryPoint = "CallRegistryPermission")]  
[RegistryPermission(SecurityAction.PermitOnly, Unrestricted = true)]  
    private static extern bool CallRegistryPermissionDeny();  

그러나 다음 예제에서 Demand 한정자는 허용됩니다.

[DllImport("MyClass.dll", EntryPoint = "CallRegistryPermission")]  
[RegistryPermission(SecurityAction.Demand, Unrestricted = true)]  
    private static extern bool CallRegistryPermissionDeny();  

SecurityAction 한정자는 플랫폼 호출을 포함(래핑)하는 클래스에 배치될 경우 제대로 작동합니다.

      [RegistryPermission(SecurityAction.Demand, Unrestricted = true)]  
public ref class PInvokeWrapper  
{  
public:  
[DllImport("MyClass.dll", EntryPoint = "CallRegistryPermission")]  
    private static extern bool CallRegistryPermissionDeny();  
};  
[RegistryPermission(SecurityAction.Demand, Unrestricted = true)]  
class PInvokeWrapper  
{  
[DllImport("MyClass.dll", EntryPoint = "CallRegistryPermission")]  
    private static extern bool CallRegistryPermissionDeny();  
}  

SecurityAction 한정자는 플랫폼 호출의 호출자에 배치되는 중첩된 시나리오에서도 제대로 작동합니다.

      {  
public ref class PInvokeWrapper  
public:  
    [DllImport("MyClass.dll", EntryPoint = "CallRegistryPermission")]  
    private static extern bool CallRegistryPermissionDeny();  
  
    [RegistryPermission(SecurityAction.Demand, Unrestricted = true)]  
    public static bool CallRegistryPermission()  
    {  
     return CallRegistryPermissionInternal();  
    }  
};  
class PInvokeScenario  
{  
    [DllImport("MyClass.dll", EntryPoint = "CallRegistryPermission")]  
    private static extern bool CallRegistryPermissionInternal();  
  
    [RegistryPermission(SecurityAction.Assert, Unrestricted = true)]  
    public static bool CallRegistryPermission()  
    {  
     return CallRegistryPermissionInternal();  
    }  
}  

COM Interop 예제

이 섹션의 COM Interop 샘플에서는 스택 워크 한정자와 함께 RegistryPermission 특성을 사용하는 방법을 보여 줍니다.

이전 섹션의 플랫폼 호출 예제와 비슷하게 다음 COM interop 인터페이스 선언은 Assert, DenyPermitOnly 한정자를 무시합니다.

[ComImport, Guid("12345678-43E6-43c9-9A13-47F40B338DE0")]  
interface IAssertStubsItf  
{  
[RegistryPermission(SecurityAction.Assert, Unrestricted = true)]  
    bool CallRegistryPermission();  
[FileIOPermission(SecurityAction.Assert, Unrestricted = true)]  
    bool CallFileIoPermission();  
}  
  
[ComImport, Guid("12345678-43E6-43c9-9A13-47F40B338DE0")]  
interface IDenyStubsItf  
{  
[RegistryPermission(SecurityAction.Deny, Unrestricted = true)]  
    bool CallRegistryPermission();  
[FileIOPermission(SecurityAction.Deny, Unrestricted = true)]  
    bool CallFileIoPermission();  
}  
  
[ComImport, Guid("12345678-43E6-43c9-9A13-47F40B338DE0")]  
interface IAssertStubsItf  
{  
[RegistryPermission(SecurityAction.PermitOnly, Unrestricted = true)]  
    bool CallRegistryPermission();  
[FileIOPermission(SecurityAction.PermitOnly, Unrestricted = true)]  
    bool CallFileIoPermission();  
}  

또한 다음 예제와 같이 Demand 한정자는 COM interop 인터페이스 선언 시나리오에서 허용되지 않습니다.

[ComImport, Guid("12345678-43E6-43c9-9A13-47F40B338DE0")]  
interface IDemandStubsItf  
{  
[RegistryPermission(SecurityAction.Demand, Unrestricted = true)]  
    bool CallRegistryPermission();  
[FileIOPermission(SecurityAction.Demand, Unrestricted = true)]  
    bool CallFileIoPermission();  
}  

참고 항목