Microsoft MVP성태의 닷넷 이야기
c#에서 c++로 개발된 dll에 byte[] 전달 관련하여 문의 드립니다. [링크 복사], [링크+제목 복사]
조회: 22744
글쓴 사람
김기룡 (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비트로 개발되었으며 세부적인 사항은 잘 모르겠습니다.^^;;;

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








[최초 등록일: ]
[최종 수정일: 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과 관련된 쉬운 서적이나 문서등은 없을까요?
다시한번 답변 감사드립니다.*^_^*
[guest]
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과 관련된 챕터들을 살펴봐야겠네요^^
감사합니다.
[guest]
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분
[김기룡] 감사합니다.
정말 많은 도움이 되었습니다.
[guest]

... 31  32  33  34  35  36  37  38  39  40  41  [42]  43  44  45  ...
NoWriterDateCnt.TitleFile(s)
4796Bere...1/13/201711666++ 후위연산자와 = 을 함께 사용할 때 생성되는 IL 코드 관련... [2]
4795김철환1/11/201712752이벤트 부분을 읽고 있는데 이해가 안되서 질문합니다.. [11]
4794김철환1/10/201710058안녕하세요 c# 6.0 책을 구매한 사람인데요 [3]
4793장준영1/7/201712099안녕하세요 c언어 처음 공부해보는 학생입니다 [4]파일 다운로드1
4792김재영1/4/201713106소스코드 공개 전 성태님의 의견을 듣고싶습니다 [3]
4791C#초보12/28/201612919비동기 소켓 close시 ObjectDisposedException 문제점 질문 있습니다.. [1]
4790미나리12/24/201613154파워포인트 쇼 제어 SimpleHttpServer.cs 작동문제 [4]파일 다운로드1
4789김솔지12/21/201611988프린트 시, 프린트하는 파일의 파일명 구하는 부분에 대해서 질문드립니다. [1]
4788짜두12/19/201611713Visual Studio 2015 에서 msbuild 12 사용 [5]
4787guest12/18/201613507VLC라이브러리에 대해 아시나요? [3]파일 다운로드1
4785Hyou...12/16/201613625WPF 개발 시 MVVM 프레임워크 사용 [2]
4784ds12/15/201610287문의 드립니다. [2]
4783후배12/13/201611887MemoryStream에 관한 질문 입니다. [5]
4782김형민12/6/201610212[ C# 6.0 ] 126p 오타인가요? [6]
4781질문자11/29/201610337ms워드 저장 오류 [1]
4780최진11/28/201614773안녕 하세요 빌드 관련해서 질문드립니다 꾸벅 [4]
4779손니11/28/201611109안녕하세요 질문하다 드려도 될까요 [3]
4778김상호11/25/201610643재귀호출->비재귀호출 [2]파일 다운로드1
4777권오영11/12/201612891아래 질문 상세 소스전체입니다.. [3]
4776권오영11/11/201610816제가 이클립스를 공부중인데..이상한것을 찾았습니다.. [2]
4775이성환11/11/201614261안녕하세요. SnapsToDevicePixels 질문입니다. [5]파일 다운로드1
4774popo11/10/201610883.net SSL통신 관련 질문 드립니다. [1]
4773김상호11/4/201613375재귀함수 반복문 변환 [1]파일 다운로드1
4772자연인10/27/201614360hwpctrl을 사용하는 사이트에서 나와 브라우저를 종료하면 오류메세지가 나옵니다. [1]파일 다운로드1
4771문종훈10/18/201614403.net 소스 질문이 있습니다 [2]
4770누구게~...10/15/201611633세도나 [1]
... 31  32  33  34  35  36  37  38  39  40  41  [42]  43  44  45  ...