Microsoft MVP성태의 닷넷 이야기
c#에서 c++로 개발된 dll에 byte[] 전달 관련하여 문의 드립니다. [링크 복사], [링크+제목 복사],
조회: 23019
글쓴 사람
김기룡 (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]

... 61  [62]  63  64  65  66  67  68  69  70  71  72  73  74  75  ...
NoWriterDateCnt.TitleFile(s)
1051최정수4/10/201213472WCF 클라이언트 비정상 종료 관련 [1]
1050에슈리온4/6/201215424관리자 권한과 ClickOnce, 그리고 Bootstrapper문제 [6]
1049김성혁4/4/201210149스마트클라이언트 stand-alone 방식의 배포 문제.. [1]
1048C#조으다3/27/201213901어셈블리 로드 / 언로드와 관련해서.. [6]
1047김우형3/23/201211609WCF 서비스를 이용한 데이터 전송 중 Exception 문의 [1]
1044임동찬2/29/201211462웹에서 COM Exception.. [2]
1043박성준2/24/201210278Lazy<T> 의 지연객체 생성 전에 실 객체의 Attribute분석 [2]파일 다운로드1
1042이성환2/20/201210681BlockingMethod에 빠진 스레드를 즉시 죽이고 싶습니다...;ㅅ; [2]파일 다운로드1
1039김재영2/15/20129836어셈블리에 사용자마다 다른 값을 적용하여 자동 빌드 방법이 있을까요? [2]
1037윈드로니2/12/201211295WPF 관련 질문 드립니다. [2]
1035임동찬2/9/20129623XML, XSD, XMLCodeGenerator 관련 [2]
1033곽성현2/7/20129896훔..윈도우 디바이스 드라이버 관련 [1]
1030궁빈2/2/201212299msbuild를 이용한 웹게시 및 자동 Dist 방법론에 대해 질문 드립니다!! [6]
1028신정환1/30/20129602기존 legacy Windows application이 WoA 환경에서 동작되지 않는 이유가 무얼까요? [2]
1026노현철1/19/201211363WPF가 XP에서 느리게 로딩되는 현상에 대해 질문드립니다. [4]
1025궁그미1/18/201212306네이버 소켓 로그인 이해가 안되는점이 있는데요 [2]
1022선무당1/11/201210558TFS 에서 공통 Assembly 공유 방법에 대해서 해결책이 없을까요? [2]
1021김재영1/8/20129746대리자를 메소드 파라메터로 넘겨도 됩니까? [2]파일 다운로드1
1019남산골11/13/201911876안녕하세요!! 성태님~~ [3]
1018강한구12/29/201115029WPF ClickOnce 배포시 콤포넌트 dll 다운로드 문제에 대하여 질문 있습니다. [1]
1017임동찬12/28/201112508smart client와 xbop, silverlight [6]
1015개똥이12/22/201110245RMCLOCK 설정 관련 질문이요ㅜ [2]
1011사길수12/16/201110022hyper-v 이더넷 카드 관련 문의 좀 드립니다. [1]
1006루로니12/13/201112191윈도우7과 XP의 DLL후킹 처리에 관해서 질문입니다. [3]
1005남산골12/13/201111895안녕하세요!! 첫 인사드립니다. [3]
1004뽀로로12/12/20119273Managed 어셈블리에서의 COM EntryPoint procaddress 문제 [1]
... 61  [62]  63  64  65  66  67  68  69  70  71  72  73  74  75  ...