플랫폼 호출 서비스

Platform Invocation Services

Platform Invocation Services(일반적으로 P/Invoke)Microsoft의 Common Language Runtime과 같은 공통 언어 인프라스트럭처 구현의 기능으로 관리 코드네이티브 코드를 호출할 수 있습니다.

관리 대상 코드(C#이나 VB 등).NET, 를 구성하는 라이브러리 내에서 정의된 클래스, 메서드 및 유형에 대한 네이티브액세스를 제공합니다.NET 프레임워크와 동시에.NET Framework는 광범위한 기능을 제공합니다.일반적으로 비관리 코드로 작성된 하위 수준의 운영체제 라이브러리와 비관리 코드로 작성된 서드파티 라이브러리에 액세스 할 수 없는 경우가 있습니다.P/Invoke는 프로그래머가 이러한 라이브러리의 함수에 액세스하기 위해 사용할 수 있는 기술입니다.이러한 라이브러리 내의 함수에 대한 호출은 관리 대상 코드 내에서 관리 대상 외 함수의 시그니처를 선언함으로써 발생합니다.이 시그니처는 다른 관리 대상 메서드와 마찬가지로 호출할 수 있는 실제 함수로 기능합니다.선언은 라이브러리의 파일 경로를 참조하여 함수 매개 변수를 정의하고 CLR(Common Language Run-Time)에 의해 관리되지 않는 유형으로 암묵적으로 마샬링될 가능성이 가장 높은 관리된 유형으로 반환합니다.관리되지 않는 데이터 유형이 너무 복잡하여 관리 대상 유형 간의 단순한 암묵적 변환이 불가능할 경우, 사용자는 이 프레임워크를 통해 함수의 속성, 반환 및/또는 파라미터에 대한 속성을 정의하여 암묵적으로 데이터를 마샬링하는 방법을 명시적으로 구체화할 수 있습니다.관리 대상 코드 프로그래머가 사용할 수 있는 하위 수준의 프로그래밍 개념은 관리 대상 언어에서의 프로그래밍에 비해 많이 있습니다.그 결과, 관리된 코드 경험만을 가진 프로그래머는 P/Invoke 사용에 있어 보다 기본적이지만 일반적인 장애물을 극복하기 위해 포인터, 구조체, 참조 전달과 같은 프로그래밍 개념을 복습해야 합니다.

아키텍처

개요

현재 사용 중인 P/Invoke에는 다음 두 가지 종류가 있습니다.

명시적

  • 네이티브 코드는 DLL(Dynamic Linked Library)을 통해 Import됩니다.
  • 호출자의 어셈블리에 내장된 메타데이터는 네이티브 코드를 호출하는 방법과 데이터에 액세스하는 방법을 정의합니다(일반적으로 컴파일러가 마셜 글루를 생성하는 데 도움이 되는 속성 소스 지정자필요합니다).
    • 이 정의는 "명시적" 부분입니다.

암묵적

  • C++/CLI를 사용함으로써 어플리케이션은 명시적인 선언 없이 (트래킹 포인터를 통해) 관리 대상 힙과 네이티브 메모리 영역을 동시에 사용할 수 있습니다.(암시적)
  • 이 경우 기본 데이터 구조가 변경되는 경우 이름 지정에 호환성이 있는 한 변경이 중단되지 않도록 하는 것이 주된 이점입니다.
    • 즉, 네이티브 헤더에서 구조 추가/삭제/재순서는 구조 멤버 이름도 변경되지 않는 한 투명하게 지원됩니다.

세부 사항

P/Invoke를 사용하는 경우 CLR은 DLL 로드 및 관리되지 않는 이전 유형의 CTS 유형(파라미터 [1][citation needed]마샬링이라고도 함)으로의 변환을 처리합니다.이를 수행하려면 CLR:

  • 함수를 포함하는 DLL을 찾습니다.
  • DLL을 메모리에 로드합니다.
  • 함수 주소를 메모리에서 찾아 인수를 스택에 푸시하고 필요에 따라 데이터를 마샬링합니다.

P/Invoke는 표준(관리되지 않음) C 또는 C++ DLL을 사용할 때 유용합니다.이것은 프로그래머가 광범위한 Windows API에 접근할 필요가 있을 때 사용할 수 있는데, 이는 Windows 라이브러리에서 제공되는 많은 함수가 사용 가능한 래퍼가 없기 때문이다.Win32 API가 에 의해 공개되지 않은 경우.NET Framework 이 API에 대한 래퍼는 수동으로 작성해야 합니다.

함정

P/Invoke 래퍼를 쓰는 것은 어렵고 오류가 발생하기 쉽습니다.네이티브 DLL을 사용한다는 것은 프로그래머가 보통 에서 제공하는 타입안전성과 가비지 컬렉션의 이점을 얻을 수 없게 된다는 것을 의미합니다.NET 환경잘못 사용하면 분할 장애나 메모리 누수 등의 문제가 발생할 수 있습니다.에서 사용하는 레거시 함수의 정확한 시그니처를 취득한다.NET 환경은 어려울 수 있으며, 이로 인해 이러한 문제가 발생할 수 있습니다.이를 위해 이러한 서명을 얻기 위한 도구 및 웹 사이트가 존재하여 서명 문제를 방지합니다.[1]

기타 함정은 다음과 같습니다.

  • 관리 대상 언어에서의 사용자 정의 유형의 데이터 정렬이 올바르지 않습니다.C의 컴파일러 또는 컴파일러의 지시에 따라 데이터를 정렬할 수 있는 방법이 다릅니다.따라서 CLR에 대해 데이터를 정렬하는 방법을 명확하게 지시할 필요가 있습니다.일반적인 예는 에서 데이터 유형을 정의하려고 하는 경우입니다.NET: C결합을 나타냅니다.메모리에는 2개의 다른 변수가 오버랩되어 있으며,에서 이들 2개의 변수를 유형으로 정의합니다.NET 에서는, 메모리내의 다른 장소에 배치되기 때문에, 특수한 속성을 사용해 문제를 해결할 필요가 있습니다.
  • 관리되는 언어의 가비지 컬렉터에 의한 데이터 위치 간섭: 참조가 의 메서드에 로컬인 경우.NET 및 네이티브 함수에 전달되며 관리 메서드가 반환되면 가비지 컬렉터가 참조를 회수할 수 있습니다.오브젝트 참조가 핀 접속되어 있어 가비지 콜렉터에 의해 수집 또는 이동되지 않도록 주의해 주십시오.그 결과 네이티브모듈에 의한 액세스가 무효가 됩니다.

C++/CLI 를 사용하는 경우, 발신 CIL 는 관리 대상 힙에 있는 오브젝트 및 주소 지정 가능한 임의의 네이티브메모리 위치와 자유롭게 대화할 수 있습니다.관리대상 힙 상주 객체는 단순한 "object->field;" 표기를 사용하여 호출, 변경 또는 구축할 수 있으며 값을 할당하거나 메서드 호출을 지정할 수 있습니다.불필요한 콘텍스트스위칭을 배제하고 메모리 요건을 줄임으로써 퍼포먼스가 대폭 향상됩니다(스택 단축).

여기에는 다음과 같은 새로운 과제가 수반됩니다.

  • 특별히 대처하지 않는 한, 코드는 이중 Thunking에[2] 걸리기 쉽다.
  • 로더 잠금 문제

이러한 참조에는, 이러한 문제가 발생했을 경우의 해결 방법이 기재되어 있습니다.주된 이점은 구조 선언을 제거하는 것입니다. 필드 선언 순서와 정렬 문제는 C++ Interop의 맥락에서 존재하지 않습니다.

기본적인 예

다음으로 특정 DLL 버전을 취득하는 간단한 예를 나타냅니다.

Windows API의 DllGetVersion 함수 시그니처:

결과 DllGetVersion (     DLLVERSION INFO* pdvi ) 

DllGetVersion 함수를 호출하기 위한 P/Invoke C# 코드:

[StructLayout(LayoutKind)]시퀀셜)] 사적인 구조 DLLVERSION INFO {     일반의 인트 cb 사이즈;     일반의 인트 dw Major 버전;     일반의 인트 dw Minor Version(단조 버전);     일반의 인트 dwBuildNumber(dwBuild번호);     일반의 인트 dw플랫폼아이디; } [Dll Import('shell32.dll')] 정적인 외부 인트 DllGetVersion(레퍼런스 DLLVERSION INFO pdvi); 

두 번째 예시는 파일 내의 아이콘을 추출하는 방법을 보여 줍니다.

Windows API의 Extract Icon 함수 시그니처:

HICON 추출 아이콘 (           인스턴스 hInst.,     LPCTSTR lpszExe 파일명,     인트 nIconIndex ); 

추출을 호출하기 위한 P/Invoke C# 코드아이콘 기능:

[Dll Import('shell32.dll')] 정적인 외부 인트라퍼트 추출 아이콘(     인트라퍼트 hInst.,  [MarshalAs(Unmanaged Type)]LPStr)] 스트링 lpszExe 파일명,      설치하다 nIconIndex); 

다음 복잡한 예시는 Windows 플랫폼의 두 프로세스 간에 이벤트를 공유하는 방법을 보여 줍니다.

CreateEvent 함수 시그니처:

 핸들 Create Event(이벤트 생성)(      LPSECURITY_Attributes lpEventAttributes,      부루 b매뉴얼 리셋,      부루 bInitial State(초기 상태),      LPCTSTR lpName  ); 

CreateEvent 함수를 호출하기 위한 C# 코드:

[Dll Import("커널32.dll", SetLastError=true)] 정적인 외부 인트라퍼트 Create Event(이벤트 생성)(     인트라퍼트 lpEventAttributes,      부울 b매뉴얼 리셋,     부울 bInitial State(초기 상태),  [MarshalAs(Unmanaged Type)]LPStr)] 스트링 lpName); 

보다 복잡한 예

// 네이티브 선언 유형화된 구조 _페어  {   DWORD 밸브 1;   DWORD 밸브2;  } , *PPAIR; 
// / clr을 사용하여 컴파일. #pragma managed/unmanaged 를 사용하면 이중 텀킹이 발생할 수 있습니다. // .h가 포함된 스탠드아론 .cpp를 사용하여 회피합니다. // 이것은 .h 파일에 있습니다.  템플릿<< 고객명 >>님 인라인 CLR_페어^ march_as로서< >CLR_페어^, > (컨스턴트 &Src) {    // 참조 해제 사용 주의.용도에 맞게 사용해야 합니다.  CLR_페어^ 증류 = 새로운 CLR_페어;  증류->밸브 1 = Src.밸브 1;  증류->밸브2 = Src.밸브2;  돌아가다 증류; }; 
CLR_페어^ mgd_syslog1; CLR_페어^ mgd_param2;  네이티브 0,*원어민 1=&네이티브 0;  네이티브 0 = Native Call Get Ref To 메모리();  // marshal_as를 사용합니다.큰 타입이나 자주 사용하는 타입에 적합합니다. mgd_syslog1 = march_as로서< >CLR_페어^>(*원어민 1);  // 직접 필드 사용 mgd_param2->밸브 1 = 네이티브 0.밸브 1; mgd_param2->밸브2 = 네이티브 0.밸브2;  돌아가다(mgd_syslog1); // C#으로 돌아가기 

도구들

P/Invoke 시그니처의 작성에 도움이 되도록 설계된 툴이 다수 있습니다.

C++ 헤더 파일과 네이티브 DLL 파일을 Import하여 인터페이스 어셈블리를 자동으로 생성하는 유틸리티 응용 프로그램을 작성하는 것은 매우 어려운 것으로 나타났습니다.이러한 P/Invoke 시그니처용 임포터/exporter를 생성할 때의 주된 문제는 일부 C++ 함수콜 파라미터 타입의 모호성입니다.

브래드 에이브럼스는 이 주제에 대해 이렇게 말했다.P/Invoke 문제

이 문제는 다음과 같은 C++ 함수에 있습니다.

__declspec(dllex 포트) 무효 마이 펑션( *파라미터); 

P/Invoke 시그니처의 파라미터 파라미터에는 어떤 타입을 사용해야 합니까?이것은 C++의 늘 종단 문자열일 수도 있고, 또는 C++의 null 종단 문자열일 수도 있습니다.또는 출력 char 파라미터일 수 있습니다.그러니까 우리가,[]또는 ref 차 char 문자열, StringBuilder을 사용해야 합니까?

이것과 상관 없이 문제의, 여기에는 몇가지 도구 P/Invoke 서명의 생산 평이하게 할 수 있다.

하나는 도구 아래 나열된, xInterop C++.NET다리는 같은 C++메서드의 여러 재정의를 구현함으로써 이 문제가 해결되고 있다.NET 세계 개발자들은 정확한 전화해야 하는 것 들 수 있다.

핀보크그물

PInvoke.net은 위키 표준 WindowsAPI의 많은 수로P/Invoke 서명이 포함된입니다.그것은 레드 소프트웨어에 의해 한달에 10에서 5만 히트 곡을 소유하고 있다.

그 서명은 수동으로 위키의 사용자에 의해 생산되고 있다.그들은 MicrosoftVisualStudio에 공짜 addin을 사용하여 검색할 수 있다.

핀보커

고 수출과 완전히 P/Invoke interop DLL을 수집해 형성된 네이티브 DLL및 C++.h 파일 수입하 PInvoker 응용이다.그것은 PInvoker 특정의 토착 포인터 함수 매개 변수 래핑 하여 모호성 문제 극복했읍니다.NET 인터페이스입니다.대신에 표준을 사용해.P/Invoke 메서드 정의에NET 매개 변수 형식이 P/Invoke 함수 호출에서 이러한 인터페이스 클래스를 사용하여(char[], 문자열 등).

예를 들어 위의 코드 예를 보면 PInvoker는 를 생성합니다.를 받아들이는 NET P/Invoke 함수.네이티브 char * 포인터를 랩하는 NET 인터페이스 클래스.이 클래스의 구성은 문자열 또는 char [] 배열에서 할 수 있습니다.양쪽의 실제 네이티브 메모리 구조는 동일하지만, 각 타입의 인터페이스 클래스 컨스트럭터는 다른 방법으로 메모리를 채웁니다.무엇을 결정하는 책임.NET 타입은 함수에 전달되어야 합니다.따라서 개발자에게 전달됩니다.

Microsoft Interop Assistant

Microsoft Interop Assistant는 CodePlex에서 다운로드할 수 있는 바이너리 및 소스 코드와 함께 사용할 수 있는 무료 도구입니다.Microsoft Limited Public License(Ms-LPL)에 따라 라이선스가 부여됩니다.

두 부분으로 구성되어 있습니다.

  • 구조 및 메서드 정의를 포함하는 네이티브 C++ 헤더 파일 코드의 작은 섹션을 포함하는 변환기.그런 다음 C# P/Invoke 코드를 생성하여 응용 프로그램에 복사하여 붙여넣습니다.
  • 변환된 Windows API 상수, 메서드 및 구조 정의의 검색 가능 데이터베이스입니다.

이 툴은 컴파일된 dll이 아닌 C# 소스 코드를 생성하므로 사용자는 사용하기 전에 코드를 변경할 수 있습니다.그래서 애매한 문제는 어플리케이션이 특정 하나를 선택함으로써 해결된다.P/Invoke 메서드시그니처로 사용하는NET 타입.필요에 따라서, 이것을 필요한 타입으로 변경할 수 있습니다.

P/호출 마법사

P/Invoke Wizard는 네이티브 C++.h 파일코드를 받아들여 C#(또는 VB)을 생성한다는 점에서 Microsoft Interop Assistant와 유사한 방법을 사용합니다.에 붙여넣기 위한 NET) 코드입니다.NET 어플리케이션코드

타겟으로 하는 프레임워크에 대한 옵션도 있습니다.데스크톱용 NET Framework 또는Windows Mobile 스마트 디바이스(및 Windows CE)용 NET Compact Framework.

xInterop C++ 입니다.NET 브리지

xInterop C++ 입니다.NET Bridge는 네이티브 C++ DLL 및 C++ 브릿지를 사용하여 C# 래퍼에 액세스하기 위한 윈도 어플리케이션입니다.NET 어셈블리는 C#/와 함께 제공됩니다.문자열, iostream 등 표준 C++ 클래스, C++ 클래스 및 오브젝트를 랩하는 NET 라이브러리는 에서 액세스할 수 있습니다.그물.

이 도구는 C# 래퍼 DLL을 작성하기 위해 필요한 기존 네이티브 C++ DLL 및 관련 헤더파일을 가진 C# 래퍼 DLL을 생성합니다.P/Invoke 시그니처 및 데이터 마셜링은 응용 프로그램에 의해 생성됩니다.결과 C# 래퍼에는 파라미터 타입이 로 변환된 C++와 동일한 인터페이스가 있습니다.NET 코드

이 도구는 C++ DLL에서 내보내지 않은 템플릿클래스를 인식하고 템플릿클래스를 인스턴스화하여 보충 DLL로 내보냅니다.대응하는 C++ 인터페이스를 에서 사용할 수 있습니다.그물.

「 」를 참조해 주세요.

레퍼런스

  1. ^ 파라미터 마샬링시리얼화를 의미하는 일반적인 용어 마샬링과 혼동해서는 안 됩니다.Marshaled 파라미터는 CTS 타입으로 변환된 후 CLR 스택에 복사되지만 시리얼화되지는 않습니다.
  2. ^ "Double Thunking (C++)".
  3. ^ "Initialization of Mixed Assemblies".

외부 링크