C# 에서 C++ DLL사용하기

Posted 2008/08/18 19:04 by 상륜소우사수련탄
C#에서 C++ DLL 을 호출 하는것은 아래 간단히 적은 내용이 있지만... PocketPC계열... 즉 eVC에 적용하려 하니.. 막히는 것이 한두가지가 아니였다... 특히 DLL 자체 버그(?)있는 경우 답답한건 몇배 더 하고...

현재 여러곳에서 End to End (이하 E2E)보안 모듈을 사용하고 있는데 지금까지 eVC 또는 VS2005에서 C++ or MFC기반으로 코딩할때는 그리 어려운 부분이 아니였다. 지금까지 해온데로 햐면 되므로...

그런데 C#으로 넘어 오려니... 보안업체에서 C#용 DLL을 제공하는 것도 아니고..(물런 돈주면 제공하긴 한다..) C#으로 프로젝트도 처음이니... 무척 답답했었다.

DLL Import해도 DLL 진입점을 찾지 못하기도 하고...(이부분은 아직도 정확히 해결을 하지 못하였다.) 같은 보안업체어서 제공 받은 DLL 2종류를 같은 방법으로 C#에서 적용해봐도 한쪽은 DLL 진입점을 찾을 수 없다는(DLL을 찾을 수 없다는 메세지)오류를 계속 내고 있다.

DLL을 작성할때 뭔가 차이가 있는것 같은데.. 내가 C++로 DLL을 만든경우에는 이러한 현상이 없어서 그 원인을 정확히 찾을 수는 없고 그냥 추정만 할뿐이다.

DLL 함수 원형을 몇가지 분류해서 설명을 해보자.

먼저 그나마 가장 간단한
__declspec( dllimport ) void SetTimeOut(int IN nTimeOut);
이 형태는 int 값을 DLL내부 함수에 넘겨주는 것이다.

C#에서 호출 할때는 다음과 같다.
[DllImport("DLL명")]
private static extern void SetTimeOut(int nTimeOut);
C++이나 C#이나 Type이 동일하므로 크게 볼 내용은 없다. 똑같은 변수 타입으로 해주면 된다.


다음은 조금(?) 어렵다.
__declspec( dllimport ) int Connect(
         TCHAR IN *pszIp,
         int IN nPort,
         void OUT **ppContext
);
결과값으로 int형을 리턴하고 문자열과 숫자를 입력 받고 void **를 받는 형태이다.

여기서 주의 할것은 eVC는 VS6와는 다르게 유니코드가 기본값이라는 것이다.
Connect(이 함수는 서버에 접속한다고 가정한 함수)일경우 아이피와 포트 그리고 그 핸들의 포인터를 받아 처리를 많이 하는 경우를 가정한것인데..(아닌가?^^;)

C나 C++은 C#에 비하면 변수 타입에 대단히 관대하기 때문에 void *형을 개인적으로 많이 사용을 햇는데 C#에서는 그것이 발목을 많이 잡았다.
특히 **를 받아서 DLL내부에서 new나 malloc을 하는 경우와 문자열값을 UniCode에서 AnsiCode로 변경하는 경우는 eVC에서 부터 많이 접해봤을것이다.

[DllImport("DLL명", CharSet = CharSet.Unicode )]
private static extern int Connect(
            [MarshalAs(UnmanagedType.LPWStr )] System.Text.StringBuilder  szip
            , int nport
            , ref IntPtr pContext
);

TimeOut함수에 비하면 조금 복잡하다.

서버 아이피 값을 넘겨주는 경우 eVC에서 _T , L , _TEXT Macro를 사용했을 것이다.
정확한 이유는 모르겠지만, C#으로 Win32가 아닌 Mobile프로젝트를 구성하는 경우 당연히 Unicode가 기본이 될것이므로 string Type을 쓰더라도 상관 없을것이라 생각했는데 ... TCHAR *로 되어 있는 경우 char *와는 다른게 UnmanagedType을 정확히 명시 해줘야 한다는 것이다.
StringBuilder의 경우 string으로 해도 무관하지만 string보다 장점이 많다고 하여 써본것이다.
StringBuilder는 string으로 대체해도 된다.

UnmanagedType은 다음과 같다.
Bool : 4바이트 불리언값
ByValArray : 고정길이 배열
FunctionPtr : 함수 포인터
I1 : 1바이트 부호화 정수
I2 : 2바이트 부호화 정수
I4 : 4바이트 부호화 정수
I8 : 8바이트 부호화 정수
LPStr : Ansi문자열
LPStruct : C언어 구조체 포인터
LPTStr : 플랫폼 독립적인 문자열. Windows98계열은 Ansi문자열 Windows2000계열은 Unicode 문자열
LPVoid : 타입이 없는 4바이트 포인터
LPWStr : 유니코드 문자열
R4 : 4바이트 부동 소숫점
R8 : 8바이트 부동 소숫점
Struct : C언어 구조체
SysInt : 플랫폼 독립 부동화 정수. 32비트 OS의 경우 4바이트 64비트 OS일 경우 8바이트
U1 : 1바이트 비부호화 정수
U2 : 2바이트 비부호화 정수
U4 : 4바이트 비부호화 정수
U8 : 8바이트 비부호화 정수

첫번째 인자가 TCHAR * 의 문자열을 받으므로 UnmanagedType을 LPWStr로 선언을 해주었다.
두번째 인자 숫자는 TimeOut과 마찬가지로 int로 쉽게 해결하면 된다.
세번째 인자는 void **를 받아서 DLL내부에서 malloc하는 경우 void **로 동일 하게 명시해줘도 상관 없지만, C#에서 void *의 &를 넘겨주기가 좀 애매하다.
C#에서 void *를 대신하는(맞는지 정확히는 모르겠다...이놈의 모래성 ㅠㅠ) IntPtr과 Call Reference의 기호 ref로 해결을 보았다.

Tag : , ,

Trackback URL : http://www.mdfo.kr/trackback/58 관련글 쓰기

  1. buy xanax online

    Tracked from buy xanax online 2012/04/21 12:04 Delete

    프로그래머의 신변잡기 :: C# 에서 C++ DLL사용하기

  1. david

    | 2011/08/11 16:30 | PERMALINK | EDIT | REPLY |

    많은 도움이 되었습니다. 감사합니다.

Write your message and submit
« PREV : 1 : ... 28 : 29 : 30 : 31 : 32 : 33 : 34 : 35 : 36 : ... 87 : NEXT »