네이티브 확장 DLL을 managed DLL로 바꾸면서..
처음 이 주제를 다루게 되었을 때, 두가지 상황을 생각했다.

1. 네이티브 확장 DLL의 소스를 변환하여 managed DLL을 생성한다.
2. 확장 DLL을 감싸는 Wrapper 클래스를 작성한다.

이 두가지 방법 중에서 첫번째 방법이 더 깔끔하고 확실하다고 생각했기 때문에, 당연히 첫번째 방법부터 시도했다. 물론 첫번째 방법이 가능한 이유는 내가 소스 코드를 가지고 있었기 때문에 가능한 일이었다. 일단 전체 소스를 받아서 컴파일해 보았는데, 이 소스에도 문제가 있는지 컴파일이 제대로 되지 않았으며 이 문제는 나중에 해결한다고 하더라도 __gc 클래스를 외부에 익스포트하는 과정에서 __gc 클래스는 unmanaged 클래스를 멤버 변수로 가질 수 없다는(대신 포인터는 가능하다)걸 발견하여 전체 소스를 모두 수정해야 했으며, 특히 이 소스는 const를 과도하게 사용하여 내가 이를 수정하기가 만만치 않았다.

두번째 방법은 내가 그동안 외부에서 공개된 DLL을 사용할 때 많이 사용했던 방법이어서 첫번째 방법이 되지 않을 경우, 곧바로 테스트해보고 싶은 방법이었다. 이 방법을 시작하기전에 다음과 같은 사항들을 확인하였다.

- managed C++ 클래스 라이브러리를 C#에서 손쉽게 사용할 수 있는가? 데이터 변환은 용이한가?
- 네이티브 C++ 클래스 라이브러리를 managed C++로 만들 수 있는가? Wrapper 클래스의 작성이 비교적 용이한가?

이 방법을 간단히 테스트해 본 후, 두번째 방법에 확신을 갖게 되어 곧바로 작업에 들어갔다. 프로그램을 진행하는 성격상 여러 가지 예제 프로그램을 작성해 보면서 예제에서 작성한 소스를 토대로 전체 프로그램을 완성해가기 때문에 앞서 만든 예제를 토대로 managed C++ 클래스 라이브러리를 작성하기 시작하였다.

------------------------

참고 사항
네이티브 C++ 클래스 라이브러리에서 익스포트하는 헤더 파일을 managed C++ 클래스 라이브러리에서 include 했더니 다음과 같은 에러가 발생하였다. 이상한 점은 이 에러가 managed C++ 응용 프로그램에서는 절대로 발생하지 않는다는 것이었다. 일단 링크 에러였기 때문에 링커 옵션에서 msvcrt.lib libcmtd.lib를 추가하고 컴파일 해 보았지만, 이번에는 main 함수가 없다는 오류를 출력하였다. 사실 DLL에서 main 함수가 필요하지는 않지만 컴파일 오류를 없애기 위해서 CPP 파일에 더미 main 함수를 추가하였더니 컴파일이 아무 문제없이 정상적으로 수행되었다.

LINK : error LNK2020: 확인되지 않은 토큰(0A000038) delete
LINK : error LNK2020: 확인되지 않은 토큰(0A000059) _CxxThrowException
LINK : fatal error LNK1120: 2개의 확인할 수 없는 외부 참조입니다.

------------------------


내가 필요한 정보는 네이티브 C++ 클래스의 헤더 파일과 컴파일된 DLL 파일 뿐이었다. managed C++ 클래스 라이브러리 프로젝트를 생성하고 동시에 이를 테스트할 수 있는 콘솔용 C# 프로젝트를 생성하였다. 클래스 라이브러리 쪽에서 테스트용 클래스를 만들어 본 후, 앞으로 작업을 진행해 나가야하는 시나리오를 가늠해보기 위해서 C# 프로젝트에서 해당 DLL을 테스트해보았다. 테스트가 제대로 진행되는 것을 확인한 후, 헤더 파일에 있는 모든 C++ 클래스에 대한 Wrapper 클래스를 하나씩 작성하기 시작했다. 방법은 헤더 파일에 있는 클래스 선언부분을 복사하고 나서 private 부분은 모두 삭제하고 내부용으로 사용되고 있는 함수들도 모두 삭제하였다. public으로 공개된 함수만을 간추린 후, 데이터 타입이 C#에서도 사용할 수 있도록 바꾸어 주었다. 이 과정에서 const는 무조건 삭제하였으며 char *는 String *로 바꾸어 주었다. 가장 문제가 되었던 점은 네이티브 DLL에서 char *를 받을 때, 내가 작성하고 있던 managed DLL에서는 String*를 받아야 했기 때문에 이 둘의 데이터 변환이 필요하였다. System::String 클래스에는 char *를 반환해주는 함수가 없었다. 그래서 인터넷을 검색하여 MS 사이트로부터 다음과 같은 기사를 찾을 수 있었다. 이 링크에서는 3가지 방법을 추천하고 있었는데, 나는 두번째 방법을 사용하였다. 기본적인 문제들이 해결되니 나머지는 상당히 반복적인 작업 뿐이었다. 마지막으로 namespace CCZZANG과 namespace COM이라는 더미(dummy) 네임스페이스를 사용하는 것도 잊지 않았다.


느낀점

사실 프로젝트를 진행하기 전에는, 앞서 소개했던 두 가지 방법 중에서 첫번째 방법이 해결책이라고 생각했었기 때문에 일이 제대로 진척되지 못했다. 다행히도 두번째 방법도 함께 고려를 하고 있어서 이 둘을 병행하여 테스트해본 것이 주요했다. 아울러 한 두번만으로 포기하지 않고 일을 끝까지 진행했던 것이 프로젝트를 완성하게된 힘이 아닌가 싶다. 아마도 나와 같은 문제로 많은 C++ 개발자들이 어려움을 겪고 있을거라고 생각한다. 왜냐하면 네이티브 Win32 환경에서 .NET 환경으로 넘어가는 일이 쉬운일은 아니기 때문이다. 또한 데이터 호환에서도 문제가 많고 이 프로젝트를 진행하는 개발자는 네이티브와 .NET 환경을 모두 제대로 이해하고 있어야 하기 때문이다.
by smile | 2003/10/28 00:11 | 기술정보 | 트랙백 | 덧글(9)
트랙백 주소 : http://smile.egloos.com/tb/84859
☞ 내 이글루에 이 글과 관련된 글 쓰기 (트랙백 보내기) [도움말]
Commented by 미친병아리 at 2003/10/28 02:07
좋은 내용같은데 잘 모르겠네요.. 쿠쿠.. 소스를 가지고 있으므로 그냥 /clr 옵션으로 컴파일하면 안될런지..
Commented by preludeb at 2003/10/28 09:19
훗.... GG
ㅡ.ㅡ/
Commented by smile at 2003/10/28 11:07
미병님.. 사실 저도 그럴줄 알고 당연히 /clr 옵션으로 컴파일을 해보았지만, 사실 네이티브 DLL을 managed DLL을 바꾸는게 잘 안되네요. 이번 경우를 경험으로 볼 때, 쉽지만은 아닐듯이요. ^^;;
Commented by 손대 at 2003/10/28 18:52
혹시 영환이형 스타크래프트 리플 분석기 이야기인건가요?
그거라면 고쳐진 소스 저도 보고 싶네요^^;(무리한 부탁인가..)
Commented by 미친병아리 at 2003/10/29 02:16
아.. 영환님꺼.. 그거라면 저도 /clr로 시도했다 꽝.. 후후..
글쿤요.. 우석님 시도, 다시 함 읽어봐야겠습니다..
Commented by smile at 2003/10/29 11:15
손대.. 영환이한테 소스가 있지.. 대단한 소스는 아닌데. 그리고 무엇보다도 내가 너무 순식간에 짜버려서 말야. -_-;;;
Commented by smile at 2003/10/29 11:16
미병님. 미병님께서 1차적으로 시도해보셨다는 소식을 듣고 난 후, 제가 다시 작업을 시작한 거죠. ^^ 미병님께서 워낙 바쁘시니깐.. 헤헤. 암튼 그 소스를 .NET 용으로 수정하기 위해서 작업한 내용입니다. 꾸벅~
Commented by 홍번구 at 2008/12/05 09:34
퍼갑니다.
마지막 by smile 라인까지요..
이정도면 출처도 확실히 될듯싶습니다.
Commented by 홍번구 at 2008/12/05 09:43
작업하면서 나름 얻은 결론은 native 와 managed 코드간의 타입은 반드시 공용을 사용해야만 하는 제약이 있는듯 하더군요.
하나라도 어긋날시 '확인되지 않은 토큰' 뒤에는 '해결되지 않은 토큰' 이라는 무시무시한 에러가 숨어있더군요.
뭐 에러에대한 자료도없고 결국 일단접고 p/invoke 로 처리하게되었는데 처리하고 보니..
p/invoke 에서 처리했던 방식이 c++/cli 에서도 왠지 통할듯할거같은데..
언제 해볼수있으려나...ㅡㅡ
아무튼 좋은 정보공유 감사드립니다~^^

:         :

:

비공개 덧글



< 이전페이지 다음페이지 >