Microsoft MVP성태의 닷넷 이야기
c#에서 c++로 개발된 dll에 byte[] 전달 관련하여 문의 드립니다. [링크 복사], [링크+제목 복사]
조회: 15999
글쓴 사람
김기룡 (reverse79 at hotmail.com)
홈페이지
첨부 파일
 
안녕하세요.

공지사항을 보고 나름대로 자세히 적기는 했는데
글 솜씨가 없어서 괜히 더 복잡하게 적은건 아닌지 모르겠습니다.^^

현재 dll파일은 A 업체의 개발자가 vc++로 개발했으며,
C# 프로그램은 B 업체의 개발자가 개발했습니다.
제가 C#으로 개발된 위 프로그램의 운영을 맡게 되었는데
dll 호출 시 byte[]를 전달하는 부분에 문제가 있어서 문의 드립니다.


=== [요약] ===
웹에서 스트림으로 이미지 파일을 byte[]로 내려 받은 후
USB 장비에 웹에서 내려 받은 파일을 전달하기 위해
dll에 byte[]와 size를 전달하면 dll에서는 해당 버퍼의 포인터와 사이즈 정보를 이용해서
데이터를 읽어 들이는 과정 중 정상적으로 동작할 때가 있고 그렇지 않을때가 있다고 합니다.
세부적으로는 처음에는 일치하는데 읽다보면 전달된 사이즈와 바이트가 일치하지 않는다고 하더군요.
(참고로, dll에서 데이터를 읽어 들이는 과정은 비동기로 동작됩니다.)

dll을 개발한 A업체 개발자 이야기로는 자신이 테스트 파일을 만들어서 테스트하면
100% 정상 동작하는데 C#에서 호출할 때에는 위와 같은 현상이 있는걸로 봐서는
데이터를 유지하는 과정에 문제가 있는것 같다고 하더군요.

제가 dll을 잘 모르는데다 C#도 깊게는 모르다보니 C#에서 잘 못 구현된건지
dll에서 잘 못 처리하고 있는건지 잘 모르겠습니다.

A업체에서 vc++로 개발한 test.dll 파일을 C#에서 사용함에 있어서
아래의 readFile() API를 호출 하는 과정에 문제가 있는지 문의 드립니다.


=== [소스 및 설명] ===
dll파일의 이름은 test.dll이라고 하며,
해당 dll파일을 이용하는 C# 소스를 dll.cs와 Main.cs라고 가정하면 아래와 같습니다.

//dll에 정의된 헤더 부분
typedef int (*readFile_t)(unsigned char*, int);


[dll.cs] test.dll을 사용하기 위한 부분
[DllImport("test.dll")]
private static extern int readFile([MarshalAs(UnmanagedType.LPArray)] byte[] Data, int size);

public int _readFile(ref byte[] buffer, int size)
{
    return readFile(buffer, size);
}



[Main.cs] dll파일을 이용해서 App을 구현한 메인 소스
//웹 스트림에서 이미지 파일을 다운로드 하는 메소드입니다.
public void getImage(out byte[] buffer)
{
    buffer = null;
    IntPtr bufferData = Marshal.AllocHGlobal(1);
    int numBytesToRead = 1024*1024;
    int numBytesRead = 0;
    bufferData = Marshal.ReAllocHGlobal(bufferData, (IntPtr)numBytesRead);

    byte[] bufferTemp = new byte[numBytesToRead];

    .......... 생략 ..........

    while (numBytesToRead > 0)
    {
        int n = Stream.Read(bufferTemp, 0, numBytesToRead);

        if (n == 0) break;

        numBytesRead += n;

        bufferData = Marshal.ReAllocHGlobal(bufferData, (IntPtr)numBytesRead);

        for (int j = 0; j < n; j++)
        {
            Marshal.WriteByte(bufferData, numBytesRead - n + j, bufferTemp[j]);
        }
    }

    buffer = new byte[numBytesRead];
    Marshal.Copy(bufferData, buffer, 0, numBytesRead);
}


//문제의 에러가 발생하는 부분입니다.
//BackgroundWorker를 이용해서 처리하고 있습니다.
public long test(BackgroundWorker worker, DoWorkEventArgs e)
{
    byte[] buffer;
    getImage(out buffer);
    int result = dll._readFile(ref buffer, buffer.Length); // <-- 타 업체 연동 부분

   while(complete)
       Thread.Sleep(1000);
}


간단히, 설명드리면, BackgroundWorker로 동작되는 test() 메소드가 있습니다.
이 곳에서 getImage(out buffer)를 이용해서 buffer 배열에
웹 스트림으로부터 이미지 정보를 다운로드합니다.

다운로드된 byte[]를 test.dll 파일에 존재하는 readFile API를 이용하기 위해
_readFile() 메소드를 호출합니다.

이때, dll의 readFile API는 dll 내부적으로 비동기로 동작하며,
처리가 완료되면 사용자 정의 메시지를 발생하게됩니다.

중요한건 dll에서는 전달받은 byte[]를 전부 dll 내부의 메모리에 복사하지 않고
C#으로부터 전달받은 포인터와 Length정보를 이용해서 USB장치에 일정 Byte만큼씩 전송하는데,
dll이 내부적으로 비동기로 동작합니다.

buffer변수를 test()메소드 내부의 지역변수로 선언했기때문에
C#에서는 전달한 buffer 배열이 사라지지 않도록 무한루프를 돌면서
dll에서 모든 처리가 완료될때까지 대기하고 있습니다.
(while(complete) 부분)


dll을 개발한 개발자의 이야기를 들어보면 아마도 이 부분에서 문제가 발생하는 것 같습니다.
C#으로부터 전달 받은 값을 검증하면 초기에는 정상인데
일정 바이트씩 읽어서 처리하는 도중에 값이 초기와 다르다고 합니다.
혹시나 해서 dll 내부에 메모리를 생성해서 전달 받은 값을 내부 메모리에 복사 후
복사된 메모리에서 작업을 진행하면 정상이라고 하더군요.


=== [궁금한 부분] ===
dll에 대해서도 잘 모르고 C#쪽도 잘 모르다보니
dll을 호출 하는 방법이 잘 못 되었거나 값을 유지하는 방법이 잘 못되었을 것 같습니다.

1. C#에서 VC++로 개발된 dll에 byte[]의 값을 전달 할 때
   위 처럼 호출하였는데 문법적으로 잘 못 되었는지요?
   (참고로, dll에서는 byte[]에 처리된 결과를 리턴하지는 않습니다.)


2. 위와 같은 형태로 호출 시 메모리의 값이 GC등에 의해서 변동될 소지가 존재하나요^^

참고로, C#은 VS2008 버전으로 개발되었으며 XP, Vista, Win7에서 동작합니다.
dll은 32비트로 개발되었으며 세부적인 사항은 잘 모르겠습니다.^^;;;

제대로 공부하고 싶은데 혹시 위와 관련하여 참고할 만한 국내서적이나 국내 자료등이 있을까요?




donaricano-btn



[최초 등록일: ]
[최종 수정일: 12/13/2010 ]


비밀번호

댓글 쓴 사람
 



2010-12-14 11시04분
1. 문법적으로는 잘못되지 않았으나 ^^ 동작상으로 문제가 있습니다. Managed Heap에 있는 byte 배열 인스턴스를 C++ 쪽에 넘겼는데, GC 가 동작하면 해당 byte 배열의 위치가 변경되게 됩니다. 이러한 위치 변경을 방지하기 위해서 fixed 키워드를 사용해 주시면 해결이 될 것입니다.

        static void Main(string[] args)
        {
            byte[] byteContents = new byte[256];
            unsafe
            {
                fixed (byte* pContents = byteContents)
                {

                }
            }
        }

그럼, 2번 답까지 같이 마무리 된 것 같군요. ^^

좋은 서적은, "CLR via C# 2nd Edition" 이라는 책을 권하고 싶군요. 너무 자세한 면도 있지만 훌륭한 책입니다. ^^

CLR via C# 2nd Edition
; http://www.yes24.com/24/goods/3120074
정성태
2010-12-15 10시39분
[김기룡] 답변 감사드립니다.
MSDN의 fixed 설명을 얼핏 본 후로 GC와 관련된 문제인가?라고 고민은하고는 있었지만
역시나 자세한 동작 원리를 모르니 섣불리 fixed문을 사용하기 망설여졌는데 많은 도움이 되었습니다.
해당 블럭과 무관하게 Managed Heap에 있는 경우에는 항상 GC의 영향을 받나보군요^^
추천해주신 서적을 살짝 몇 페이지를 보기는 했었는데 아직은 내공이 너무 부족해서 그런지 어렵더군요^^
내공 향상을 위해서 열심히 읽어봐야 될 것 같습니다.

추천 서적에서는 dll과 관련된 부분의 내용을 못 본것 같은데
혹시라도 dll과 관련된 쉬운 서적이나 문서등은 없을까요?
다시한번 답변 감사드립니다.*^_^*
[손님]
2010-12-15 11시46분
DLL 관련된 부분이라... 워낙 여기저기서 습득한 정보들이라 딱히 어디라고 지적해드리기가 난감하군요. ^^
.NET DLL은 근본적으로 EXE와 다르지 않습니다. 실제로 .NET EXE 파일도 동일하게 DLL 처럼 참조하는 것이 가능합니다. 즉, .NET EXE는 Main 함수를 포함하고 실행시 그 함수를 실행하도록 지정된 것일 뿐 DLL과 전혀 다르지 않습니다.

즉, .NET 을 공부하는 것 자체가 DLL 을 함께 공부하는 것이라 보면 되겠습니다.

근데.. 구체적으로 DLL의 어떤 부분을 알고 싶은 것인지... 감이 안 오는 군요. ^^;
정성태
2010-12-16 02시42분
[김기룡] 친절한 답변 감사드립니다.
위 프로그램을 운영하고 유지보수 하다보면 MFC 기반의 dll과 C#이 연동되는 구조라서
C#의 메모리 구조외에도 MFC 기반의 dll에 관한 전반적인 내용들도 알고 있어야 할 것 같아서요.

dll이란 어떤것이며 어떤 구조로 동작하고 어떤식으로 개발하며
문제가 발생할 때 어떤식으로 디버깅을 하는지..
각 OS등과의 호환성에 대한 다양한 정보들이 아닐까 싶습니다.^^

운영하다보면 dll과 관련된 자잘한 문제들도 있을 것 같다는 생각이 들어서요^^

좀 더 정확하게는 C#과 unmanaged dll과의 연동과관련해서 세부적인 사항들이 필요하겠지만
제가 unmanaged dll에 대해서도 전혀 모르다 보니까요^^
우선은 VC나 MFC관련 서적에서 dll과 관련된 챕터들을 살펴봐야겠네요^^
감사합니다.
[손님]
2010-12-16 05시37분
말씀하신 부분은 VC++ 관련 책을 보시면 충분히 설명될 내용입니다.
참고로, 더욱 자세한 설명을 원하시면 아래의 책이 도움될 수 있습니다.

Windows 시스템 실행파일의 구조와 원리
; http://www.yes24.com/24/goods/1493278

단계적인 난이도로 보면 "CLR via C# 2nd Edition"보다도 나중에 읽어야 할 책이지만, 설명이 아주 자세하게 되어 있기 때문에 DLL에 대한 아주 상세한 부분까지 알 수 있습니다. 이 책 역시... 아주 훌륭한 책입니다. ^^
정성태
2010-12-16 09시47분
[김기룡] 감사합니다.
정말 많은 도움이 되었습니다.
[손님]

... 31  32  33  34  35  36  37  38  39  40  41  42  43  44  [45]  ...
NoWriterDateCnt.TitleFile(s)
1018강한구12/29/20118661WPF ClickOnce 배포시 콤포넌트 dll 다운로드 문제에 대하여 질문 있습니다. [1]
1017임동찬12/28/20116390smart client와 xbop, silverlight [6]
1015개똥이12/22/20115047RMCLOCK 설정 관련 질문이요ㅜ [2]
1011사길수12/16/20114408hyper-v 이더넷 카드 관련 문의 좀 드립니다. [1]
1006루로니12/13/20116729윈도우7과 XP의 DLL후킹 처리에 관해서 질문입니다. [3]
1005남산골12/13/20115958안녕하세요!! 첫 인사드립니다. [3]
1004뽀로로12/11/20113930Managed 어셈블리에서의 COM EntryPoint procaddress 문제 [1]
1003나그네12/8/20116200닷넷에서 가상메모리(Commit) 의 크기를 줄이거나 해제하는 방법은 어떻게 해야할지요? [1]
1002나그네11/29/20114671안녕하세요 ^^ 문제가 생겨서 혹시나 여기서라면 답이 나오지 않을까 해서.. [1]
1001선무당11/29/20115394clickonce+ntd 시스템에서 proxy Server 가 개입되는 경우 cache 해결을 위한 방법... [1]
1000초보개발자11/28/20114546웹서비스용 웹 서버의 SSD 가치에 대해서... [1]
999날쌘돌이11/25/20115051ADFS와 WIF 질문 [1]
998윤용한11/9/20115061File Write 도중 정전 발생 시 대처 방법 있나요? [2]
997조장원11/7/20114677Silverlight 에서의 Auth 방법에 대한 고찰 [2]파일 다운로드1
996파몽11/3/20118197VS2010 에서 타겟플랫폼이 x86으로 변경이 된걸일까요? [2]
995강신명10/24/20114831sharepoint2010+win7 client 오류 [2]파일 다운로드1
992라이언10/11/20115634캡션에 chapter numbers 넣기
993정성태10/11/20117394    답변글 [답변]: 캡션에 chapter numbers 넣기
991우상욱8/21/20119207세션 타임 아웃에 관해서 질문드립니다. [2]
990김재영8/20/201112309VS2010의 윈폼의 Load이벤트에서 예외가 잡혀지지 않습니다. [3]파일 다운로드1
989우상욱8/20/20115776polling에 대해 감이 안잡혀서 질문드립니다 [1]
988WooYoung Moon8/17/20116572성태님~ 작은 부탁 하나 있습니다~ [2]
987에스패스트8/3/20117509비밀글쓰기가 있으면 참좋을탠대 아쉽네요 ^^ 저 한가지만더.. [5]
986에스패스트8/3/201110180안녕하세요 ^^ 이렇곧도 있군요 ~ 참좋네요 질문 한가지 여쭤볼게요 [6]
985이성환7/28/20117037P/Inovke 관련 질문입니다. [4]파일 다운로드1
983이성환7/13/201113190Mouse이벤트 관련해서 질문있습니다. [10]파일 다운로드2
... 31  32  33  34  35  36  37  38  39  40  41  42  43  44  [45]  ...