Microsoft MVP성태의 닷넷 이야기
P/Inovke 관련 질문입니다. [링크 복사], [링크+제목 복사]
조회: 12563
글쓴 사람
이성환 (vactorman at naver.com)
홈페이지
첨부 파일

이렇게 연타석 질문을 날리게 됐습니다....(__)

다른 회사의 SDK를 받아다가 dll로 만든 후에 닷넷 솔루션에서 사용해야하는 상황입니다.
SDK를 받아서 만들어야하는 dll 역시 C#으로 만들어야하고 64비트 빌드되어야 하는 상황입니다.

일단 SDK를 받아보니
종류별로 dll과 lib 파일이 들어 있고 문서도 함께 들어있는데요. C/C++로 만들어져 있습니다.

이걸 가지고 P/Invoke를 하려고 하는데요.
P/Invoke로 가능한 것인지 의문 나는 게 있어서 질문 드립니다.

일단 사용하고자 하는 dll의 헤더 파일을 보니
제가 호출하고자 하는 함수가 특정 Struct 안에 함수 포인터로 작성되어 있더군요.
그리고 그 Struct는 Init(params)이라는 함수를 호출해서 포인터로 넘겨받는 거구요.

간단히 일부만 예로 들면

헤더 파일에

#ifdef WIN32
    #ifdef _USRDLL
        #define NVSNETLIB_API EXTERN_C __declspec(dllexport)
    #elif _LIB
        #define NVSNETLIB_API EXTERN_C
    #else
        #define NVSNETLIB_API EXTERN_C __declspec(dllimport)
    #endif
#else
    #define NVSNETLIB_API
#endif

typedef struct CNetSession {
    unsigned int dataSize;
    char *recvData;
    
    int (*sendAudio)(void *_this, char *_buf, unsigned int _size);
    int (*sendControl)(void *_this, unsigned int _type, char *_buf, unsigned int _size);
} CNetSession, *pCNetSession;

NVSNETLIB_API void * NETSESSION_Init(
    char *_address,
    unsigned short _port,
    char *_url,
    char *_id,
    char *_passwd,
    unsigned char _connectType
    );

뭐 이렇게 작성되어 있구요.

예제 소스에서는

int main(int argc, char **argv) {
pCNetSession netSession;
char connectType = 0x07;

netSession = (pCNetSession)NETSESSION_Init(argv[1], atoi(argv[2]), NULL, argv[3], argv[4], connectType );

if( netSession->sendAudio(netSession, audioBuf, dwByteRead) == 0 )
{
    printf(".");
}
//

}

이런 식으로 사용하더군요.

지금 제가 호출해서 사용해야하는 함수가 sendControl이라는 함수인데
(이 함수에 대한 사용예제는 문서에 없더군요.)

이걸 C#에서 P/Invoke로 호출하려고 합니다.

일단 NETSESSION_Init()은

[DllImport("References/DLL.dll")]
public static extern IntPtr NETSESSION_Init(String _address, UInt16 _port, String _url, String _id, String _passwd, Byte _connectType);

이렇게 작성했습니다.

그리고 CNetSession Struct를 사용하기 위해

[StructLayout(LayoutKind.Sequential)]
public class CNetSession
{
    public UInt32 dataSize;
    public String recvData;
    
    public delegate int sendAudio(IntPtr _this, String _buf, UInt32 _size);
    public delegate int sendControl(IntPtr _this, UInt32 _type, String _buf, UInt32 _size);
}

이렇게 만들었습니다.

근데 여기서부터 이해가 잘 안 되는데요. 요약하자면

1. dll 헤더파일에 정의 되어있는 CNetSession Struct 안에 함수포인터로 작성되어 있는 것들을 C#의 클래스로 치환할 때 델리게이트로 만드는게 맞는건지?
2. 그렇다면 이 델리게이트들의 콜백은 어떻게 연결하고 호출하는지?
3. NETSESSION_Init() 메서드를 호출해서 반환 받은 IntPtr를 제가 만든 CNetSession 클래스로 변환 하는 게 가능한건지?

입니다.

SDK 문서의 사용 예제처럼, NETSESSION_Init() 함수를 호출해 반환 받은 포인터에서
직접 sendAudio() 함수를 호출하는 걸로봐서 (netSession->sendAudio() 이런 식...)
이미 dll 내부에서 sendAudio() 의 콜백을 연결 해 놓은 거 같은데 (아닌가요?)

이걸 C#에서 바로 사용할 수 있을지가 의문입니다.
(이미 콜백이 연결된 녀석인지 아니면 따로 연결을 해줘야하는 건지 모르겠습니다. 따로 연결해야한다면 어떻게 해야하나요?)

단순하게 Win32 API정도 P/Invoke 해서 쓰다가 이런 경우를 처음 마주치니까
하나도 이해가 안 되네요.

C/C++ 지식이 전무하다보니 사실 SDK에서 제공되는 예제를 봐도 이해가 잘 안 가는데,
필요한 부분만 가지고와서 P/Invoke로 쓸려니 더 이해가 안 가네요.
(예제 솔루션도 못 만들겠습니다...;ㅅ;)




혹시 질문 내용이 난해하시다면 SDK를 보내드릴게요.

답변 부탁드립니다...;ㅅ;








[최초 등록일: ]
[최종 수정일: 7/28/2011]


비밀번호

댓글 작성자
 



2011-07-28 10시07분
[이성환] 간략하게 테스트 솔루션하나 추가 해봤습니다.

이렇게 쓰는 게 맞는 지 모르겠네요.

일단 실행하면

Attempted to read or write protected memory. This is often an indication that other memory is corrupt.

이 에러가 떨어지는 데요.

아무래도 시그니처를 제대로 못 맞춰서 그런 거 같은데 어디서 잘못 됐는지 확인이 안 되네요.

바쁘신데 다른 건 신경 안 쓰셔도 괜찮은데

제가 만든 테스트 소스 처럼 하는 게 맞는 지만 알려주시면 될 거 같습니다.

그럼 좀 고민을 해볼 게요.

...C 메모리 구조(packed 한다고 들었는데 맞는지 모르겠네요)와 닷넷 메모리 구조를 맞추는 게 너무 어려워요.
[guest]
2011-07-29 03시20분
[이성환] 아.. 이틀 동안 P/Invoke로 어떻게든 해보려고 했는데

결국 C++/CLI로 dll을 만들어 작업은 마무리 했네요.

작업은 작업이지만 그냥 제가 생각한대로 사용하는 게 맞는지 궁금합니다.

플랫폼간 호출은 P/Invoke으로 뭐든 쉽게 할 줄 알았는데 그게 아니었네요...;ㅅ;
[guest]
2011-08-02 12시51분
(아... 답변이 너무 늦었군요. ^^ 제가 근래들어 퇴근 후 컴퓨터를 쓸 일이 거의 없어서... ^^;)

예, 소스 코드를 보았는데... 잘 하셨습니다. ^^ 그런데, 몇몇 부분에서 약간의 실수가 보이는데요. 대표적으로 dataSize, recvData 필드 쪽을 살펴보면,

unsigned int dataSize;
 char *recvData;

이런 경우, 대개 recvData 포인터에 할당된 크기를 dataSize가 지정하는 경우라고 볼 수 있는데 C# 의 PtrToStructure 함수는 이에 대해 마샬링을 자동으로 하지 못합니다. 그런 부분 때문에 "Attemped..." 오류가 발생한 것일테고.

제가 이성환님이 올려준 소스 코드를 약간 변경해서 sendAudio 메서드가 '오류 없이' 호출되는 것 까지 변경해 보았으니 참고하세요.

http://www.sysnet.pe.kr/temp/CellinxPInvokeTest.zip

^^ 어쨌든 C++/CLI로 해결하셨으니, 의미가 좀 떨어지겠지만. ^^

(참고로, C++ 의 struct 인스턴스를 마샬링 할 때 포인터 부분은 IntPtr 로 일단 설정해 두면서 맞춰주는 것이 편합니다.)
정성태
2011-08-03 09시12분
[이성환] 답변 감사합니다.

역시 확인해 다른 소스에서도 마샬링할 때 포인터 부분을 IntPtr로 바꾸니까 잘 되는 군요.

마샬링에 대응하는 타입만 보고 그냥 치환해서 타입들을 집어넣었는데 역시나 포인터가 문제였군요.

C++/CLI로 작업된 DLL들 외에 다른 DLL들은 이렇게 수정해서 잘 쓰고 있습니다.

도움 감사합니다 (__)
[guest]

... 31  32  33  34  35  36  37  38  39  40  41  42  43  [44]  45  ...
NoWriterDateCnt.TitleFile(s)
4745힘찬도약7/27/201612052.NET 자식창 데이터를 부모창에 전달시 오류 질문드립니다. [4]파일 다운로드1
4744변찬연7/27/201611812안녕하세요 그 edge를 이용하는 데 조금 불편함이 있어서 문의드립니다 [1]
4743딸랑구아빠7/26/201610744IE 사용 시 인증 정보 계속 보내기? [1]
4741차가워7/20/201612368UWP 에서 COM 참조 불가능한가요? [6]
4740luna...7/19/201612769clickonce manifest 파일 질문 [1]
4739윤똘씨7/19/201612212정말 감동적입니다... [7]
4738닷넷초보7/7/201611090안녕하세요. C#의 개체 전달방식(참조)에 관련해서 질문 있습니다. [3]파일 다운로드1
4737beau...7/6/201613410python embedding 한 c++ 프로그램의 배포에 관해서 질문드리고 싶습니다. [1]
4736spow...7/6/201610298Property Lambda에 대한 심층 분석을 의뢰합니다 [7]
4735힘찬도약7/5/201611429.Net/Web.config에서 MSSQL을 쓰는데, MysqlSiteMap 참조오류 [3]파일 다운로드1
4734spow...6/28/201611000Visual Studio 2015 + Windows Forms 환경에서 컴파일 할 때 드물게 개발환경이 Crash 됩니다 [1]
4733feel...6/15/201611463타 서버로 소스 이전 중 [3]파일 다운로드1
4732구봉근6/14/201610205안녕하세요 [1]파일 다운로드1
4731초급개발자6/7/201612756Windows Form Application는 사라질까요? [2]
4730김시현6/4/201610811책으로 공부하던 도중 생성자에 대해서 궁금한게 생겼는데 혹시 답변좀 해주실수 있나요? [1]
4729Jeah...6/3/201612262C#.Net 프로그램에서 C++로 만들어진 dll 파일 이용관련 문의 하나 드립니다. [3]
4727링거5/30/201610916WPF MediaElement 파일 실행 후 삭제시 오류 문의 [1]파일 다운로드1
4728링거5/30/201611288    답변글 [답변]: WPF MediaElement 파일 실행 후 삭제시 오류 문의 [2]파일 다운로드1
4726spow...5/25/201610730덧글을 달고 나서 F5를 눌렀을 때 똑같은 덧글이 달리는 현상 고쳐주세요 [4]
4725Futu...5/23/201611191책 잘보고 있습니다. Task관련 질문을!!! [1]
4724학생15/23/201612472웹소켓과 소켓 관련해서 질문 드립니다. [2]
4722지나가던...5/15/201614306Part 3 pdf파일 그림 재수정 문의 [1]
4723지나가던...5/16/201611547    답변글 [답변]: Part 3 pdf파일 그림 재수정 문의 [1]
4721김종희4/30/2016116953D 시뮬레이션 개발 [1]
4720DC4/29/201611086C# 6.0 델리게이트 인스턴스화 관련 질문~ [2]
4719이민구4/29/201612029[시작하세요! C# 프로그래밍] 4.5.1.6 열거형 마지막 예제 질문입니다. [4]파일 다운로드1
... 31  32  33  34  35  36  37  38  39  40  41  42  43  [44]  45  ...