PInvoke란, Platform Invoke의 줄임말입니다.

플랫폼 호출이라고 하는데요.. 통상 말하는 API(Application Programming Interface)를 지칭하는 단어입니다.


API를 이미 접해보신 분들이라면 CreateWindow, RegisterClass, SendMessage 등의 API는 한번쯤 사용해 보신 적이 있지 않을까 하고 조심히 예상해봅니다 ^^;


비주얼 베이직의 경우 VB6 에서는 Declare 키워드를 사용하여 API를 선언할 수 있었습니다.

.NET으로 와서는 어떨까요? Declare 키워드 혹은 DllImport 특성을 사용하여 선언할 수가 있습니다.

C#의 경우엔 DllImport 특성을 사용해서만 선언이 가능합니다.


Tip!

여기서는 '선언' 을 다루고 있으므로, 동적 API 호출은 해당사항이 없습니다.

(예: GetProcAddress API로 주소를 얻은 후 호출하는 것 등)



그럼 비주얼 베이직 사용자들은 이런 질문을 하시게 될 수도 있습니다.

'왜 Declare 안쓰고 굳이 DllImport 특성을 사용해야 하나? Declare 이 더 편한거 같은데...'

이렇게 물어보신다면 저는 이런 이유들을 내세울 수 있습니다.


1. 호출에 대한 오류 코드를 Marshal 클래스에 있는 GetLastWin32Error 함수가 반환할 것인지 설정할 수 있습니다.

(즉 GetLastError API 를 사용하지 않아도 됨)

2. DLL의 진입점(Entrypoint)을 명시할 수 있습니다. (API의 경우 API 이름에 해당됨)

3. 호출 규약(Calling Convention)을 설정할 수 있습니다.

4. 정확한 철자(ExactSpelling)를 사용할 것인지 설정할 수 있습니다.

(몇몇 API에는 이름 뒤에 A(Ansi), W(Unicode)가 붙는 API들이 있는데, 이 API에 한해서 자동으로 A, W를 붙이지 않고

입력된 함수 이름, 진입점이 명시된 경우엔 진입점 이름으로 API를 호출할 것인지의 여부를 설정합니다.

True일 경우 자동으로 A, W를 붙이지 않고, False일 경우엔 문자셋을 알아서 인식하고 A, W를 확장합니다)

5. Ansi 문자셋에서 매핑되지 않은 문자가 있을 경우 예외처리 할 것인지 설정할 수 있습니다.

(제어 문자 등이 해당됨)

6. 선언이 간결해집니다.


Tip!

DllImportAttribute 특성에 대해 더 자세한 정보는 MSDN 페이지를 참고하시기 바랍니다.

http://msdn.microsoft.com/ko-kr/library/System.Runtime.InteropServices.DllImportAttribute(v=vs.110).aspx




그럼 이제, DllImportAttribute 클래스를 살펴보도록 하겠습니다.

생성자:

C#


VB.NET



총 한 개의 매개 변수를 필요로 하고 있습니다.

이 매개 변수는 라이브러리(DLL) 이름을 저장하는군요~




이전에는 설명하지 않았었는데.. 생성자 부분에서 멤버의 값들을 설정할 수도 있습니다.

C#

[TeacherAttribute("Kim Bab", Age = 30, BloodType = AB)]


VB.NET

<TeacherAttribute("Kim Bab", Age := 30, BloodType := AB)>


이런 식으로 말이지요~!




그럼 이제 코드를 한번 살펴보도록 하겠습니다.

C#



VB.NET



SM 이라는 함수를 선언했습니다.

EntryPoint를 SendMessage로 선언하여 SM 함수는 곧 SendMessage가 됩니다. (VB의 Alias 하고 같지요)

문자셋은 유니코드로 맞췄고,

SetLastError 멤버의 값을 True로 줌으로써 Marshal.GetLastWin32Error 함수로 오류 코드를 받을 수 있습니다.



위 코드에선 문자셋을 Unicode로 주었기 때문에 EntryPoint 뒷부분에 W가 붙게 됩니다.

그래서 SendMessageW를 호출하게 됩니다.


Tip!

pinvoke.net 이란 사이트에서는 C#/VB.NET 사용자를 위한 PInvoke 선언을 모아놓은 아주 유용한 사이트입니다.

http://pinvoke.net



이번 글에서는 실행 결과가 없습니다.

왜 하필 SendMessage를 선택한거지 - _-... 죄송해요

한가지 예를 더 들어드리면 EntryPoint를 명시하지 않았을 때엔 함수 이름을 검색하게 됩니다.


[DllImport("user32")]

public extern int SendMessage(...);


이런식으로 선언을 해주면 user32!SendMessageA 혹은 W를 호출하게 됩니다.

* 그리고 정말 중요한 것! C# 에서 DllImport 특성을 이용해 PInvoke 선언할 경우 반드시 extern 키워드를 사용하셔야 합니다.



지금까지 C#/VB.NET 에서 PInvoke(Platform Invoke)를 사용하는 방법에 대해서 설명하였습니다.

궁금한 점, 틀린 것 또는 기타 지적 사항이 있는 경우 댓글로 남겨주세요!!

+ Recent posts