Microsoft MVP성태의 닷넷 이야기
C#에서의 함수포인터 [링크 복사], [링크+제목 복사]
조회: 17081
글쓴 사람
왕초보
홈페이지
첨부 파일
 

안녕하세요? 성태님.
카메라 한대 사서 프로그래밍중인데요...ㅠㅠ~ dll에 파라미터로 정의된 함수포인터 골치아프네요.
카메라에 첨부된 샘플에는 C++로 아래와 같이 되어있는데...

__declspec(dllimport) MVSTATUS_CODES __stdcall MVStartGrab(HANDLE hCam,int (*StreamCB)(MV_IMAGE_INFO*,long nUserVal),long nUserVal);
...

int StreamCB(MV_IMAGE_INFO *pInfo,long nUserVal)
{
 ...
 return 0;
}
...
void CGCapDlg::OnBnClickedStart()
{
 ...
 MVStartGrab(m_hCam,StreamCB,(long)this);
 ...
}
흠~~ 위의 코드는 dll의 MVStartGrab함수가 카메라로부터 화상을 읽고 동기에 맞추어 읽은 화상데이터를 사용자에게 넘겨주기 위해 사용자처리루틴(int StreamCB(...))을
함수포인터로 넘겨받는 과정이죠. 일단 MVStartGrab(...)함수가 실행되면 동기에 맞춰 StreamCB가 주기적으로 호출되요.
C#에서 아래와 같이 변환했어요.^^

class Form1
{
 ...
 delegate short StreamCB(ref MV_IMAGE_INFO imageInfo, int nUserVal);
 [DllImport("MVGigE.dll")]
 public static extern MvStatus MVStartGrab(IntPtr hCam, StreamCB streamCB, int nUserVal);
 ...

 short OnStreamCB(ref MV_IMAGE_INFO info, int nUserVal)
 {
   ...
   return 0;
 }
 ...
 StreamCB sb;
 private void b_CamRun_Click(object sender, EventArgs e)
 {
   ...
   sb = OnStreamCB;
   MVStartGrab(m_hCam, sb, (int)this.Handle);
   ...
 }
}
나로선 어딘가 틀린데가 없어보이는데 OnStreamCB는 맨 첨 한번밖에 실행안되요.
한번만은 데이터랑 완전하게 받아요.
내보기엔 초기에 넘겨준 함수포인터를 잃어버리는것같은데 왜 그럴까요?
MFC에선 제대로 작동되요. 물론 MFC로 해도 되겠지만 품들여 C#에서 영상처리기반 자작했는데... 꼭 C#으로 돌리고 싶네요.
귀중한 시간 자꾸 앗아서 죄송합니다.








[최초 등록일: ]
[최종 수정일: 11/1/2014]


비밀번호

댓글 작성자
 



2014-11-03 12시32분
이게 문제인지는 모르겠지만, StreamCB 함수 포인터의 반환값이 int 인데, C# 측에서는 short로 되어 있습니다. 그리고, MV_IMAGE_INFO 구조체를 잘 구성했는지, sizeof 같은 방법을 이용해서 C++에서의 크기와 C#에서의 크기가 동일한지 확인해 보세요. 그 외에는, 딱히 문제가 없어 보입니다.
정성태
2014-11-03 03시28분
[왕초보] C++에서 정의된 구조체는

typedef struct _IMAGE_INFO
{
    uint64_t    nTimeStamp;        
    USHORT        nBlockId;        
    UCHAR        *pImageBuffer;
    ULONG        nImageSizeAcq;    
    UCHAR        nMissingPackets;
    uint64_t    nPixelType;        
    uint32_t    nSizeX;            
    uint32_t    nSizeY;
    uint32_t    nOffsetX;        
    uint32_t    nOffsetY;
} MV_IMAGE_INFO, * pMV_IMAGE_INFO ;

이구요 C#에서 구현한 구조체는

 unsafe public struct MV_IMAGE_INFO
 {
        public ulong nTimeStamp;        
        public ushort nBlockId;        
        public byte* pImageBuffer;    
        public uint nImageSizeAcq;    
        public byte nMissingPackets;
        public ulong nPixelType;        
        public uint nSizeX;            
        public uint nSizeY;
        public uint nOffsetX;        
        public uint nOffsetY;
        public MV_IMAGE_INFO (ulong Ts, ushort BI, byte* IB, uint ISA, byte MP, ulong PT, uint SX, uint SY, uint OX, uint OY)
        {
            nTimeStamp = Ts;
            nBlockId = BI;
            pImageBuffer = IB;
            nImageSizeAcq = ISA;
            nMissingPackets = MP;
            nPixelType = PT;
            nSizeX = SX;
            nSizeY = SY;
            nOffsetX = OX;
            nOffsetY = OY;
        }
  }

예요. 함수 반환값은 int로 바꿔보았고 unsafe예약어 잘못썼나 해서 위의 구조체 리용하는곳들에 다 unsafe달아줘봤어요. C++과 C#에서 위의 구조체 크기는 48로 같게 나오고... 하지만 결과는 같애요.^^
dll로 실행권이 넘어가면 디버그도 할수 없어 속상하네요. 이상한건 첨 한번 결과를 되돌린 후 dll이 전혀 작동 안하는건 아니고, Task Manager에서 보면, 메모리 사용량은 C++과 같은데, CPU이용량은 C#쪽이 엄청 크네요(70%정도로 CPU를 아예 독점해버리죠. ㅠㅠ~~).
결국 함수 포인터 한번 참조후에 실행주소가 향방을 잃은것같은데...???^^. 그렇다고 완전 크래쉬된건 아녜요. 다른 함수들 호출하면 제대로 작동되요.
C++에서 함수포인터는 본질상 그냥 포인터이고 C#에서는 delegate로 선언된 객체가 클래스네요. delegate로 C++에 함수포인터 넘기는 메카니즘 표상이 잘 안가요. 그리고,
C++에서 전역함수와 클래스 멤버함수의 포인터 참조형식이 좀 다르죠. 근데 C#에는 전역함수나 전역변수를 선언할수 없어요. 혹시 시리얼화된 클래스 멤버함수의 주소배치가 C++과 C#에서 조금 차이나는건 아닌지...
이런 의문점들은 배열이나 string타입에서도 같죠. C++의 CString은 구조체로 선언되었고 본질상 char형의 배렬로 구성되지만 C#의 string은 강력한 탐색기능을 제공하는 클래스이고, 근데 C++과의 호환에서는 System.Runtime.InteropServices만 using하고 그냥 통한다고 하네요.(실제로 해보면 LPCSTR 에로의 string변환도 잘 안되요.)^^ 후~~으-ㅁ~~...암튼 이루루한 메카니즘 표상을 정확히 갖고 머리를 정돈해서 봐야 할것같군요...
말이 길어져서 미안합니다. 살틀한 방조에 사의를 표합니다.
[guest]
2014-11-03 08시47분
[왕초보] p.s.
혹시 구조체에 포함된 byte*포인터변수때문이 아닌지...^^
제생각에는, 제 프로젝트에서 위의 구조체리용은 C#쪽에서 메모리를 할당한것이 아니라 C++로 컴파일된 dll에서 할당한 주소공간을 단지 넘겨받는것이라서 가비지수집과는 무관한걸로 예상되는데...
unsafe예약어를 없애고 byte*타입을 IntPtr타입으로 바꾸어주어도 별다른 변화가 없어요.제가 써넣은 코드상에서 포인터관리가 잘못되였는지 테스트 하느라 OnStreamCB함수에서 아무런 처리도 하지 않고 포인터를 넘겨줘도 호출은 한번밖에 안되요.
만일 참조를 포함한 구조체참조에 문제가 있다면, 위의 경우는 피할길이 없다는 절망감이 드네요...^^
[guest]
2014-11-03 11시21분
[왕초보] 문제가 또 있네요^^.
앞에서도 말씀드렸지만 함수포인터를 받는 dll함수는 그 포인터를 받아 일단 내부에 저장하고, thread를 창조하여 포인터로 지적된 함수를 주기적으로 호출해요.
근데 dll함수를 호출할 당시 넘겨준 함수(StreamCB)의 포인터값은 이후 가비지수집기에 의해 변경될 가능성이 있어요. 결국 dll함수의 입장에서 보면, 넘겨받은 포인터가 지적하는 함수에로의 한번 접근 후, 다음번 호출시 같은 포인터로 접근하면 그 주소에는 이미 그 함수가 없어지고, 따라서 포인터조작은 향방을 잃게되죠... (어쨋든 이건 가정이고 .Net에 왕초보인 저로서는 아마 그럴거라고...ㅎㅎㅎ)
메모리를 고정하는 fixed예약어가 있기는 한데 브레이크로 제한된 구역에서만 효과를 가지니 위의 경우에는 효력이 없고 ㅠㅠ~~...
많은 API함수들이 내부에 thread를 가지고 있고 고정된 주소에로의 자료반환을 진행해요. 이러한 경우를 예상해서 C#에서도 대책이 있을거라고 생각되요.
전 왕초보라서 가정에 가정만을 되풀이하는데 선배님의 고견 기대됩니다. 선배님께 자꾸 수고로움 끼치게 됩니다.
[guest]
2014-11-03 12시48분
우선 GC에 의한 포인터 변경은 신경쓰지 않아도 됩니다. PInvoke 호출 시에 delegate에 대해서는 자동으로 pinning 시키기 때문입니다. byte * 포인터는, 말씀하신 것처럼 OnStremCB 측에서 아무런 처리도 하지 않고 포인터를 넘겼는데도 그런 현상이 있는 것이라면 무관한 것 같습니다.

정히 안되면, 그냥 C++/CLI로 해보세요. 아니면, 간단한 C#/C++ 예제를 만들어서 IMAGE_INFO를 동일하게 넘겨보고 문제 발생 지점을 축소해서 재현해 보세요.

(그나저나... 사용하시는 용어가 특이하시군요. '살틀한 방조에 사의를 표...', '이루루한 메카니즘 표상' 같은 말은 무슨 뜻인지 모르겠습니다. ^^;)
정성태
2021-10-06 10시59분
[방문자] 정성태님, 살틀한 방조라는건 북한말 표현입니다....
콤퓨타력량을 키우려는 전사였나 봅니다.
[guest]
2021-10-07 10시06분
한편으로는, 북한에서 ^^; MFC를 할 것 같지는 않고... 뭔가, 젊은 세대에서 유행처럼 번진 그런 용어가 아닐까 싶습니다. 게다가 "이루루"라고 검색하니 일본 애니메이션 쪽 자료가 나열되는 것도 그렇고... ^^;;; 암튼, 묘현 표현들입니다.

그래도 .NET은 하는 듯합니다. ^^

북한 프로그래머가 작성한 닷넷 코드...
; http://www.simpleisbest.net/archive/2005/07/26/188.aspx
정성태
2021-10-07 11시07분
[dimohy] 아 저도 질문 읽어 내려가다 보니 아 이분 뭔가 좀 표현이 특이하다. (북한 사람인가? 까지는 생각을 못했고요) 그런데 와 문장 구조와 표현이 상당히 멋있다는 생각 또한 했습니다. 나한테 없는 유니크한 분의 문장을 보면 부럽기도 합니다.
[guest]
2021-10-08 10시32분
[방문자] 농처럼 썼지만 글 중간을 읽어보시면 '리용'이라고 하는 등 흔적은 이미 차고 넘칩니다.... 그리고 젊은(?) 사람들에게 이런 하드코어한 북한말이 유행한 적은 한번도 없습니다.
한편 북에서 정보전 능력을 키우는 쪽이건, 중국/동남아에서 흔히 하는 외화벌이 산업이건 프로그래밍 스킬은 상당히 크게 요구됩니다. 합법적, 불법적을 막론하고요. MFC가 필요한 일은 충분히 많을겁니다.

북한에서 인터넷으로 접속해서 타국인들에게 물어보는 일들이 전례가 없는것도 아니구요. 확정된게 없으니 그렇지...
https://kldp.org/node/108269
[guest]
2021-10-08 10시36분
[방문자] dimohy님, 이미 북한말은 우리와 많이 갈라져 있으니까요... 영어를 쓰는 나라들끼리도 어법과 단어가 다르듯이요
멋보다도 외국어스러운 거죠.
[guest]
2021-10-08 10시49분
[방문자] 이루루로 검색해서 일본 애니가 나오는건 어쩌다 그런 이름의 캐릭터가 있기 때문일겁니다 ㅋㅋㅋ 이모티콘이나 말투만 보아도 최소 30후반 이상, pc통신시대 이상의 말투인데 '젊은 세대'라면 그게 더 놀라운 일일겁니다.
메카니즘 표상representation of mechanism 같은 표현이 자연스럽게 말에 스며있다는 게 놀랍지 않으십니까 ㅎㅎ
[guest]
2021-10-08 12시00분
kldp 링크 글은 너무 티나지 않나요? 아이디부터 redstar라고 하는데... 정말 북한 사람이라면 그런 아이디를 지을까요? ^^;;; 게다가 그 아이디로 올린 지난 글들을 보면("https://kldp.org/user/58175/track") 전혀 북한 사람같지 않습니다.

그런데... 갑자기 덧글이 이상한 방향으로 흐르는군요. ^^; 이 글을 작성하신 분이 북한 사람인지, 탈북해 IT 교육 수강 중인지... 자세한 정보를 알 수 있는 단서가 없으므로 더 이상의 (글과 관련 없는) 덧글은 삭제하겠습니다.
정성태
2021-10-12 08시41분
[방문자] 앗, 알겠습니다. 저도 댓글을 더 이상 달지 않겠습니다.
생각해보면 덧글 출신지를 증명할 의무감이나 확증을 가진 것도 아니었는데... 애니메이션 키워드 검색 히트수 같은 것을 말씀하시기에 가볍게 말을 시작했다가 '이 말투가 북한식인가' 에 대해 납득기준을 확 엄격하게 가져가시는 것 같아 당황해서 공을 들이려 했나봅니다.
댓글란을 잡아먹어 실례했습니다.
[guest]

... 31  32  33  34  35  36  37  38  39  40  41  42  43  44  [45]  ...
NoWriterDateCnt.TitleFile(s)
4719이민구4/29/201612035[시작하세요! C# 프로그래밍] 4.5.1.6 열거형 마지막 예제 질문입니다. [4]파일 다운로드1
4718ds4/27/201610349오라클 DB 칼럼에 있는 특정 데이터를 가져올수가 있나여? [1]
4717최령진4/26/20169430모바일 웹 앱 관련문의 드립니다 [1]
4715과객4/7/201611428TFS 와 Stylecop Integration 시 체크인 정책 적용 방법이 궁금합니다. [1]
4714임형복4/7/201611359DLL 을 프로세스처럼 사용하기 [3]파일 다운로드1
4713김태훈4/5/201611564하위 폴더 권한 상속 문제 [1]
4712차가워4/5/201613270멀티코어 스레드 문의 [1]
4711이대희4/1/201610757Xamarin 라이센스 변경 (Visual Sutuio 무료 사용) [2]
4709가가멜3/25/201635152국내 WPF 책은 왜 2010 년 이후로 전멸인지요? [1]
4704최훈3/15/201615063C# 6.0 예제 7.1 관련 질문입니다. [2]
4702popo3/14/201614554C# WeakReference이 CPU 플랫폼 설정 마다 결과가 틀리게 나옵니다. [9]
4701쌉쓰릅3/13/201612269uwp에서 그림판의 지우개 기능을 구현하려고하는데요 참고할 만한 정보가 있을가요? [2]
4700정우진3/12/201610671안녕하세요. 10049소켓에러의 해결법을 알고싶습니다. - 수정본 [1]파일 다운로드1
4699정우진3/11/201613456안녕하세요. 10049소켓에러의 해결법을 알고싶습니다. [1]
4698지나가는3/10/201612058안녕하세요. 주기적으로 일어나는 .net 관련 질문이 있습니다 [1]
4697정우진3/9/20169675안녕하세요. AWS EC2를 이용한 서버 개발에 대해 질문드립니다. [1]
4696삽질맨3/9/201614249Winform Cold Start 로딩 속도 개선 방법이 없을까요? [1]
4695popo3/9/201612009wpf의 ICommand 질문 입니다. [5]파일 다운로드1
4694아무개2/28/201611620책 잘보고있습니다~ [1]
4693초보2/25/20169813카카오톡 오류 질문 [1]
3701강준2/19/2016192842개의 DataTable Join 결과 전체 컬럼을 DataTable 로 리턴하기 [5]
3700박성훈2/18/201610890시작하세요! C# 6.0 프로그래밍 105쪽 예제 질문 [1]
3699박성훈2/18/201610497공부 방향성 질문 [2]
3698강준2/16/201611110Entity Framework 에서 Select for Update 가 가능한가요??? [1]
3697ds2/16/201610650어느 정도 문법을 알고 나면 [6]
3695Bere...2/15/201612898호출당한 메서드가 호출한 메서드를 알 수 있는 방법이 일반적인 방법 말고도 있을까요? [2]
... 31  32  33  34  35  36  37  38  39  40  41  42  43  44  [45]  ...