posted by 방랑군 2009. 9. 29. 13:13

참조 : http://kingcrap.com/entry/닷넷에서-native-dll-사용하기



닷넷에서 C/C++로 작성된 dll을 사용하고자 할 경우 다음과 같은 방법이 있다.

1. 일반적인 native dll의 경우 - P/Invoke (Platform Invoke)를 써서 직접 호출
닷넷에서 Win32 API를 호출하거나 C/C++로 작성된 native dll을 호출할 경우, native dll이 제공하는 메소드의 signature나 타입에 대해 닷넷에서 인식하고 호출할 수 있도록 이에 대한 선언을 해야 한다. 크게 보면 세 단계로 구성되는데, 첫째 DllImport하여 필요한 dll 로딩하는 부분, 둘째 원하는 메소드 signature를 extern으로 선언하는 부분(즉, 이 메소드가 외부 native dll에서 정의되어 있다고 선언하는 부분), 마지막으로 이 메소드를 호출하여 원하는 값을 취하는 부분으로 되어 있다.

Win32 API에 대한 선언을 일일이 기억하기란 쉽지 않기 때문에 웹에 이에 대한 데이터베이스 형태의 wiki로서 PInvoke.net이 존재한다. 아래 화면은 http://www.pinvoke.net 에서 볼 수 있다.pinvoke 
아울러 PInvoke.net에서는 Visual Studio 2005에 대한 플러그 인을 제공하여 무료로 다운받아 설치할 수 있으며 아래 그림에서 처럼 VS내에서 원하는 선언문을 검색하여 바로 붙여 넣을 수 있다.
image 

이보다 좀 더 나은 방식으로 간단한 애플리케이션 형태의  AppViewer가 존재하여 편리하게 원하는 API에 대한 선언문을 사용할 수 있다. 아래 그림에서 보듯이 다양한 언어, 심지어 delphi나 MASM에서 사용할 수 있는 기능까지 제공하고 있다.
 image image

자바에서도 이와 동일한 세 단계 방식의 호출 방법이 있는데, JNI (Java Native Interface)라고 부른다. System.loadLibrary()하여 dll을 메모리에 올리는 부분, 호출하고자 하는 메소드의 signature를 native라는 modifier를 써서 선언하는 부분(역시 이 메소드의 구현은 native하게 외부에 정의되어 있다고 선언하는 부분), 마지막으로 이 메소드를 호출하는 부분으로 구성된다. 자바가 호출하는 메소드를 C/C++에서 구현하기 위해서는 각 언어에 맞는 헤더파일이 필요한데 이를 위해 javah -jni 명령어를 써서 *.h 파일을 생성하며 이렇게 생성된 *.h를 C/C++에서 include하여 개발하는 과정을 거치게 된다.

2. COM 서버 접근 - RCW (Runtime-Callable Wrapper)를 이용하는 방법
COM 객체에 대한 wrapper를 만들어서 닷넷에서는 마치 일반적인 닷넷 객체를 호출하듯 프로그래밍할 수 있도록 지원하는 방법이다. Visual Studio에서 Add Reference기능을 클릭하며 아래에서 처럼 COM 컴포넌트를 선택할 수 있으며 OK를 누르는 순간 레퍼런스가 추가되면서 이 COM 컴포넌트에 대한 닷넷 Wrapper가 생성된다. 생성되는 wrapper는 Interop.xxx.dll의 어셈블리가 된다. 따라서 개발자는 닷넷 프로그래밍 하는 방식으로 COM 객체를 생성하고 호출할 수 있게 된다.
image
Visual Studio를 사용하지 않는 경우에는 .NET SDK에 들어있는 TlbImp.exe 명령어를 사용하여 wrapper를 생성할 수도 있다.
COM 객체가 대단히 크거나 복잡할 경우 생성되는 Wrapper의 크기 또한 부담스러우며, COM 내부에서 사용하기 위해 만든 인터페이스를 wrapper에서 숨길 수 있는 방안도 없기 때문에, 간편하게 생성하여 사용할 수 있는 장점이 있지만  COM 객체의 특성에 따라 이 방법이 적합한지 한번쯤은 생각해 볼 필요가 있다. 아울러 사용이 끝난 COM 객체는 해당 wrapper가  GCed될 때까지 살아 있기 때문에, wrapper가  Garbage Collector에 의해 GCed될 때까지 기다리지 말고 System.Runtime.InteropServices.Marshal.ReleaseComObject()를 이용하여 즉시 해제해주는 것이 좋다.

Posted by 장현춘