c# 플랫폼에서 DLL에서 실행되는 관리되지 않는 함수 호출

7461 단어 dll
플랫폼 호출 서비스(PINvoke)는 DLL에서 구현된 비 호스팅 함수를 호스팅 코드로 호출할 수 있도록 합니다.
이 문서에서는 C#에서 관리되지 않는 DLL 함수를 호출하는 방법에 대해 설명합니다.이 강좌에서 논의한 속성은 이 함수를 호출하여 데이터 형식을 정확하게 봉인할 수 있도록 합니다.
C# 코드에는 관리되지 않는 코드를 직접 호출할 수 있는 두 가지 방법이 있습니다.
  • DLL에서 내보낸 함수를 직접 호출합니다.
  • COM 객체의 인터페이스 호출 방법
  • 이 두 가지 기술에 대해 모두 C#컴파일러에게 비 트랜잭션 함수에 대한 설명을 제공해야 하며, C#컴파일러에게 비 트랜잭션 코드와 어떻게 전달하는 매개 변수와 반환 값에 대한 설명을 제공해야 할 수도 있다.
    이 문서는 다음 항목으로 구성되어 있습니다.
    1. C#에서 DLL 직접 내보내기 호출
    2. 기본 봉송 처리와 비 트랜잭션 방법의 매개 변수에 사용자 정의 봉송 처리를 지정합니다
    3. 사용자 정의 구조에 사용자 정의 봉인 처리 지정하기
    4. 등록 콜백 방법
    1. C#에서 DLL 내보내기 직접 호출
    DLL에서 내보낸 방법을 선언하려면 다음과 같이 하십시오.
  • C# 키워드 static 및 extern 선언 메서드를 사용합니다.
  • 이 메서드에 DllImport 속성을 첨부합니다.DllImport 속성을 사용하면 메서드가 포함된 DLL의 이름을 지정할 수 있습니다.일반적인 방법은 내보낸 방법과 같은 이름으로 C# 방법을 명명하는 것이지만 C# 방법에 다른 이름을 사용할 수도 있다.
  • 방법의 매개 변수와 반환 값에 사용자 정의 봉송 처리 정보를 지정할 수 있습니다. 다시 쓸 것입니다.NET Framework의 기본 봉인 처리입니다.

  • 예제 1


    이 예제에서는 호출msvcrt.dll puts를 통해 DllImport 속성을 사용하여 메시지를 출력하는 방법을 보여 줍니다.
    // PInvokeTest.cs
    
    using System;
    
    using System.Runtime.InteropServices;
    
    class PlatformInvokeTest
    
    {
    
    [DllImport("msvcrt.dll")]
    
    public static extern int puts(string c);
    
    [DllImport("msvcrt.dll")]
    
    internal static extern int _flushall();
    
    public static void Main()
    
    {
    
    puts("Test");
    
    _flushall();
    
    }
    
    }

    출력

    Test

    코드 토론


    앞의 예제에서는 관리되지 않는 DLL에서 구현된 C# 메소드를 설명하기 위한 최소 요구 사항을 보여 줍니다.PlatformInvokeTest.puts 방법은 static와 extern 수식자로 설명하고 DllImport 속성을 가지며 이 속성은 기본 이름puts을 사용하여 컴파일러에 알립니다 msvcrt.dll.C# 메서드에 다른 이름putstring을 사용하려면 다음과 같이 DllImport 속성에 EntryPoint 옵션을 사용해야 합니다.
    [DllImport("msvcrt.dll", EntryPoint="puts")]

    2. 기본 봉송 처리와 비 위탁 관리 방법의 매개 변수에 사용자 정의 봉송 처리를 지정합니다


    C# 코드에서 관리되지 않는 함수를 호출할 때 공용 언어 라이브러리는 매개 변수와 반환 값을 봉인해야 합니다.
    하나하나에 대해.NET Framework 유형에는 기본적으로 관리되지 않는 유형이 있으며, 공용 언어 실행 라이브러리에서는 이 관리되지 않는 유형을 사용하여 관리되지 않는 함수 호출에서 데이터를 봉인합니다.예를 들어, C# 문자열 값의 기본 봉인 처리는 LPTSTR(TCHAR 문자 버퍼에 대한 포인터) 유형으로 봉인됩니다.관리되지 않는 함수의 C# 선언에서 MarshalAs 속성을 사용하여 기본 봉인 처리를 다시 쓸 수 있습니다.

    예제 2


    이 예제에서는 DllImport 속성을 사용하여 문자열을 내보냅니다.MarshalAs 속성을 사용하여 함수 매개 변수의 기본 봉인 처리를 다시 쓰는 방법도 보여 줍니다.
    // Marshal.cs
    
    using System;
    
    using System.Runtime.InteropServices;
    
    class PlatformInvokeTest
    
    {
    
    [DllImport("msvcrt.dll")]
    
    public static extern int puts(
    
    [MarshalAs(UnmanagedType.LPStr)]
    
    string m);
    
    [DllImport("msvcrt.dll")]
    
    internal static extern int _flushall();
    
    public static void Main()
    
    {
    
    puts("Hello World!");
    
    _flushall();
    
    }
    
    }

    출력


    이 예시를 실행할 때 문자열
    Hello World!

    콘솔에 표시됩니다.

    코드 토론


    앞의 예에서 puts 함수의 매개 변수의 기본 봉송 처리가 기본값인 LPTSTR에서 LPSTR로 다시 작성되었습니다.
    MarshalAs 속성은 메소드 매개변수, 메소드 반환 값 및 구조 및 클래스 필드에 배치할 수 있습니다.메소드 반환 값에 대한 봉인 처리를 설정하려면 메소드 상의 메소드 블록에 MarshalAs 등록 정보를 반환 등록 정보 위치 재작성과 함께 배치합니다.예를 들어 명시적 설정puts 방법으로 값을 반환하는 봉송 처리를 하려면 다음과 같이 하십시오.
    ...
    
    [DllImport("msvcrt.dll")]
    
    [return : MarshalAs(UnmanagedType.I4)]
    
    public static extern int puts(
    
    ...

    3. 사용자 정의 구조에 사용자 정의 봉인 처리 지정


    비 트랜잭션 함수로 전달되거나 비 트랜잭션 함수에서 되돌아오는 구조와 클래스의 필드에 사용자 정의 봉송 처리 속성을 지정할 수 있습니다.구조 또는 클래스 필드에 MarshalAs 속성을 추가하면 됩니다.또한 StructLayout 속성을 사용하여 구조의 레이아웃을 설정하고 문자열 구성원의 기본 봉인 처리를 제어하며 기본 봉인 크기를 설정해야 합니다.

    예제 3


    이 예는 구조에 사용자 정의 봉송 처리 속성을 지정하는 방법을 설명한다.
    다음 C 구조를 고려하십시오.
    typedef struct tagLOGFONT
    
    {
    
    LONG lfHeight;
    
    LONG lfWidth;
    
    LONG lfEscapement;
    
    LONG lfOrientation;
    
    LONG lfWeight;
    
    BYTE lfItalic;
    
    BYTE lfUnderline;
    
    BYTE lfStrikeOut;
    
    BYTE lfCharSet;
    
    BYTE lfOutPrecision;
    
    BYTE lfClipPrecision;
    
    BYTE lfQuality;
    
    BYTE lfPitchAndFamily;
    
    TCHAR lfFaceName[LF_FACESIZE];
    
    } LOGFONT; 

    C#에서는 다음과 같이 StructLayout 및 MarshalAs 속성을 사용하여 앞의 구조를 설명할 수 있습니다.
    // logfont.cs
    
    // compile with: /target:module
    
    using System;
    
    using System.Runtime.InteropServices;
    
    [StructLayout(LayoutKind.Sequential)]
    
    public class LOGFONT
    
    {
    
    public const int LF_FACESIZE = 32;
    
    public int lfHeight;
    
    public int lfWidth;
    
    public int lfEscapement;
    
    public int lfOrientation;
    
    public int lfWeight;
    
    public byte lfItalic;
    
    public byte lfUnderline;
    
    public byte lfStrikeOut;
    
    public byte lfCharSet;
    
    public byte lfOutPrecision;
    
    public byte lfClipPrecision;
    
    public byte lfQuality;
    
    public byte lfPitchAndFamily;
    
    [MarshalAs(UnmanagedType.ByValTStr, SizeConst=LF_FACESIZE)]
    
    public string lfFaceName;
    
    }

    그런 다음 다음과 같이 C# 코드에 구조를 사용할 수 있습니다.
    // pinvoke.cs
    
    // compile with: /addmodule:logfont.netmodule
    
    using System;
    
    using System.Runtime.InteropServices;
    
    class PlatformInvokeTest
    
    {
    
    [DllImport("gdi32.dll", CharSet=CharSet.Auto)]
    
    public static extern IntPtr CreateFontIndirect(
    
    [In, MarshalAs(UnmanagedType.LPStruct)]
    
    LOGFONT lplf   // characteristics
    
    );
    
    [DllImport("gdi32.dll")]
    
    public static extern bool DeleteObject(
    
    IntPtr handle
    
    );
    
    public static void Main()
    
    {
    
    LOGFONT lf = new LOGFONT();
    
    lf.lfHeight = 9;
    
    lf.lfFaceName = "Arial";
    
    IntPtr handle = CreateFontIndirect(lf);
    
    if (IntPtr.Zero == handle)
    
    {
    
    Console.WriteLine("Can't creates a logical font.");
    
    }
    
    else
    
    {
    
    if (IntPtr.Size == 4)
    
    Console.WriteLine("{0:X}", handle.ToInt32());
    
    else
    
    Console.WriteLine("{0:X}", handle.ToInt64());
    
    // Delete the logical font created.
    
    if (!DeleteObject(handle))
    
    Console.WriteLine("Can't delete the logical font");
    
    }
    
    }
    
    }

    실행 예

    C30A0AE5

    코드 토론


    앞의 예에서 CreateFontIndirect 방법은 LOGFONT 유형의 매개 변수를 사용했다.MarshalAs 및 In 속성은 이 매개변수를 제한합니다.프로그램은 이 방법으로 되돌아오는 값을 16진 대문자 문자열로 표시합니다.

    4. 콜백 등록 방법


    비 트랜잭션 함수를 호출하는 트랜잭션 리셋을 등록하려면 같은 매개 변수 목록으로 의뢰를 설명하고 PINvoke를 통해 실례를 전달하십시오.비 트랜지스터에서 함수 바늘로 표시됩니다.예를 들어 다음과 같은 비 관리형 함수MyFunction를 고려하면 이 함수는 콜백을 매개 변수 중 하나로 요구합니다.
    typedef void (__stdcall *PFN_MYCALLBACK)();
    
    int __stdcall MyFunction(PFN_ MYCALLBACK callback);

    관리된 코드에서 호출MyFunction하려면 위임을 선언하고 함수 선언에 DllImport를 첨부하고 필요에 따라 매개 변수나 반환 값을 봉인합니다.
    public delegate void MyCallback();
    
    [DllImport("MYDLL.DLL")]
    
    public static extern void MyFunction(MyCallback callback);

    또한 위탁 실례의 생존 기간이 비 트랜잭션 코드를 덮어쓰는 생존 기간을 확보하십시오.그렇지 않으면 쓰레기 수거를 거친 후 위탁을 사용할 수 없습니다.

    좋은 웹페이지 즐겨찾기