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

1  2  3  4  5  [6]  7  8  9  10  11  12  13  14  15  ...
NoWriterDateCnt.TitleFile(s)
5806스레드1/25/20233168총정리 - 다양한 스레드들 [초안] [1]파일 다운로드1
5805어웨이트1/25/20233026Taskcontinuewith vs Async/Await [2]파일 다운로드1
5804나이많은...1/25/20232895MS의 Dependency Injection(DI)에 AddSingleton으로 등록된 객체의 Event 등록후 사용시 앱 종료시 별도로 Event를 해지해야 하나요? [2]
5803dssc...1/24/20233121드라이브 문자를 통해서 물리 디스크 명칭을 알아내고 싶습니다. [1]
5802모바일앱1/22/20233000XAMARINE vs Android Studio [7]
5801블루투스1/19/20233739WPF 은행지폐계수기 개조 후 결과값 서버 전송 [2]파일 다운로드1
5800김민아1/19/20234084안녕하세요 가비지 컬렉터 동작 원리 중 궁금한점이 있습니다 [5]
5799guest1/19/20233214C# 공유폴더 내 Acess 디비 공유 [2]
5798kss1/19/20233007책 오탈인가요? [1]
5797이거비버1/19/20233079C# 공부 이후 MS 프레임워크.. 어느것을 공부해야할까요? 너무 많아서 정신이 없네요 [5]
5796guest1/19/20232797해킹 test [3]
5795동기1/18/20232644동기 스레드와 메서드와 While [2]
5794박규동1/18/20232612.net publish 할때마다 runtimeconfig 값이 바뀌는 현상 [1]
5793후후훗1/18/20232794.NET Core 에서 사용중인 함수 후킹 방법 [2]
5792Will...1/18/20232710소스코드 Log Write 기능을 리스트업 질문 [9]
5791PLC1/16/20233432C# - 실시간 5개 룸 모니터링 [15]
5790집으로 ...1/13/20233085[UI 멈춤 현상]deadlock 관련 글을 보고 혹시나 하고 문의 드립니다. [4]
5789guest1/10/20232977스레드와 Async Task [2]파일 다운로드1
5788kr11/10/20233437C# 에서 제공하는 컬렉션들의 차이점이 궁금합니다. [3]
5787stack1/10/20233220STACKOVERFLOW [1]
5786Dev ...1/9/20234100익명 클래스 말고 익명 구조체는 불가능한걸까요? [4]
5785음성인식1/8/20233691음성인식 System.Speech - 문법에 사용된 언어가 음성 인식기의 언어와 일치하지 않습니다. [2]
5784MS워드1/8/20233310MS워드에서 ctrl Z는 클립보드를 이용하나요? 아니면 참조자 이용하나요? [7]
5783구직자1/7/20233351C#개발자 구인광고와 초급개발자 [3]파일 다운로드1
5782Sqli...1/5/20233350윈도우11 노트북에서 exe(Sqlite)만들어 윈도우 7 PC에 설치 시 [5]
5781List맨1/5/20233867List.Add("newobj") 속도는 빠른 편인지요? [11]
1  2  3  4  5  [6]  7  8  9  10  11  12  13  14  15  ...