C# interop 관련 질문 드립니다.
글쓴이: philos66 / 작성시간: 수, 2010/08/18 - 1:58오전
C로 짜인 라이브러리를 C#에서 호출하도록 작업하다가, 안 풀리는 문제가 있어 이곳에서 조언을 구하고 싶습니다.
먼저, 소스코드입니다.
using System; using System.Runtime.InteropServices; namespace Dialogic.Voice { public struct DX_CAP // Call Analysis Parameters { public ushort ca_nbrdna; /* # of rings before no answer. */ public ushort ca_stdely; /* Delay after dialing before analysis. */ public ushort ca_cnosig; /* Duration of no signal time out delay. */ }; public static class Dx { [DllImport("libdxxmt", EntryPoint = "dx_dial", CallingConvention = CallingConvention.Cdecl)] public static extern int Dial(int channel_device, string number, ref DX_CAP cap, int mode); } }
Dial 함수의 세번째 인수를 다음과 같이 넘기면 아무런 문제없이 제대로 작동합니다만,
DX_CAP cap = new DX_CAP(); Dx.Dial(1, "025552222", cap, 1);
그런데 C의 dx_dial 함수는 세번째 인수로 NULL 포인터를 받을 수 있게도 되어 있어서요, 위의 cap 인수 대신에 NULL Pointer를 넘기는 효과를 얻고 싶으면 어떻게 해야 할까요?
Forums:
그냥 제로 값을 넘겨 주면 안되는건가요?
---------------------------------------------
git init
git add .
git commit -am "project init"
---------------------------------------------
---------------------------------------------
git init
git add .
git commit -am "project init"
---------------------------------------------
실행 결과
C#은 type checking이 더 엄격해서 그런지, 위와 같이 넣으면 다음과 같은 컴파일 에러가 뜹니다.
^^;
굳이 null을 하고 싶으시면 IntPtr로 작업을 하셔서 Marshal로 copy를 하시거나 아니면
C#버전을 몇을 사용하는지 모르겠지면 Nullable를 활용하는것도 한방법입니다.
DX_CAP? cap = new DX_CAP();
Dx.Dial(1, "025552222", ref cap, 1);
이런씩으로 오류가 발생할수도 있습니다 ^^;
그런데 ref 키워드로 하시면 그냥 null로 셋팅되지 않는가여 ^^?
꼭 널이 필요하시면 struct보다는 class로 설정하시기 바랍니다.
그럼
C#의 null과 C의 NULL
C# 4.0을 사용하고 있고요, 지적하신 대로 nullable type을 이용해 이러 저러한 방법으로 시도해 보았습니다만, 여전히 안되는 군요.
제가 알기로는, C#의 null은 `아무런 값도 대입되어 있지 않다'는 뜻으로 알고 있습니다. 그런데 C의 NULL 포인터는 포인터 변수에 '0의 값을 대입'하는 것이이서, C#의 null이라는 개념과는 다른 개념으로 알고 있습니다.
C#의 nullable 변수에 null을 대입할 때, C# 내부적으로 어떻게 구현되어 있는지는 몰라도, NULL에 해당하는 0을 대입하는 것과는 다른 것으로 이해하고 있습니다. 혹시 저의 이해가 틀렸다면 지적해 주시기 바랍니다.
실행 결과
임시 방편으로 해결은 되었습니다만, 더 좋은 방법이 없을까요?
인터넷에서 정성태님의 도움을 받아. 일단은 해결이 되었습니다만, 더 좋은 방법이 없을까요?
다음은 정성태님이 제게 주신 해결책입니다.
=================================================================================
DllImport 는 사실 해당 메서드에 대해서 하나만 쓰라는 규칙은 없습니다. 따라서, 위와 같은 경우 NULL 포인터를 받아야 하는 상황에서는 다음과 같은 식으로 하나 더 정의(method overloading 이용)해두는 것도 방법일 수 있습니다.
그래서, 호출 할 때는 Dx.Dial(0, "test", IntPtr.Zero, 0); 과 같이 해주시면 됩니다.
==================================================================================
그런데 문제는 이런 식으로 접근하는 경우에는, 만약 'NULL값 또는 포인터'를 요구하는 인수가 4개인 C 함수를 C# 함수로 연결해야 한다면, 총 2의 4승 = 16개의 C# 함수를 일일이 정의해 놓아야 한다는 이야기가 되어, 깔끔한 접근법은 아닌 듯 싶습니다.
특히 Win32 C API 의 경우에는 NULL 값을 선택적으로 줄 수 있는 함수가 굉징히 많은 것으로 알고 있는데, 좀 더 나은 접근법은 없는 것일까요?
^^;
그냥 ref로 하시면 null이 넘어옵니다.
public static extern int Dial(int channel_device, string number, ref IntPtr pCap, int mode);
이런씩으로 정의하셔서
IntPtr tttt = IntPtr.Zero;
Dial( 0, string.Empty, ref tttt, 0 );
이렇게 하시면 바뀌는값에따라서 넘어오게 됩니다.
그럼
댓글 달기