Microsoft MVP성태의 닷넷 이야기
c#에서 c++로 개발된 dll에 byte[] 전달 관련하여 문의 드립니다. [링크 복사], [링크+제목 복사]
조회: 22803
글쓴 사람
김기룡 (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)
4933Kay12/15/20179139C# VS 버전 에러 질문 드립니다. [1]파일 다운로드1
4932정환나라12/13/20179057vs2013에서 빌드한 com 컨트롤 객체를 닷넷 2.0에서 사용하려 합니다 [4]
4931Arvid12/12/201710076Visual Studio 2012 c# using문 참조 에러 [5]파일 다운로드1
4929김성대12/8/20178585app.config에 관한질문입니다. [1]
4928김성대12/7/20179249SQL Server 설치에러에 대한 질문입니다. [1]파일 다운로드1
4926heyh...12/6/20178477[삭제] ContextSwitchDeadlock????
4925ho12/5/20179014[삭제] WebBrowser로 드롭박스 로그인 페이지 탐색 시 발생한 문제에 대해 질문 올립니다.파일 다운로드2
4924몽중언12/3/20179460C# 디버깅 모드에서만 DB Insert가 되는 현상 질의 [6]
4923고요한11/23/20179593파일 확장자에 연결된 프로그램을 등록하는 방법에 대한 질문입니다. [2]
4922박성훈11/23/201710549시작하세요! C# 7.1 학습 방법 [3]
4921초보개발자11/20/20177778[삭제] 폼 사이즈 질문드립니다.
4920Ques...11/19/20178897IEnumerable 의 "지연된 평가" 에 관하여 질문드립니다. [2]파일 다운로드1
4919mskim11/16/20179171Split()을 이용하여 문자 구분 시 구분문자도 같이 저장하는 방법이 있나요? [2]
4917ho11/16/20179815WPF XAML 트리거 관련해 문의 드립니다. [3]
4918ho11/16/201710105    답변글 [답변]: 예제 프로젝트 첨부합니다. [4]파일 다운로드2
4916필승11/11/20179771기본 웹 브라우저 체크는 어떻게 해야 하나요? [2]
4915필승11/10/20178844WebBrowser 컨트롤 소리 출력 문의 드립니다. [2]
4914Ques...11/10/20179530c# 버튼 이벤트에 관하여 질문드립니다. [2]
4913Arvid11/8/201711939Log4Net 라이브러리를 이용하여 특정 기간이 지났을 때 자동 로그 삭제 기능 구현 질문 드립니다! [2]
4912조범희11/8/201711610C# FTP 다운로드중 에러 발생.. [2]파일 다운로드1
4911필승11/6/201710056WebBrowser 컨트롤 사용법에 대해 궁금합니다. [2]
4910진우11/6/20179636람다 초보 질문 드립니다. [2]
4909필승11/5/201710564TextBox에 관해 질문 드립니다. [5]
4908필승11/1/201713899특정 시각에 프로그램 종료 또는 재시작시 오류 발생 [8]
4907심너울10/29/20179494선생님이 쓰신 "시작하세요! C# 7.1~"으로 공부하고 있는데요~ [2]
4906guest10/25/20179067.net core, .net standard 관련해서 궁금합니다 [2]
... 31  32  33  34  35  36  [37]  38  39  40  41  42  43  44  45  ...