C# interop 관련 질문 드립니다.

philos66의 이미지

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를 넘기는 효과를 얻고 싶으면 어떻게 해야 할까요?

madman93의 이미지

---------------------------------------------
git init
git add .
git commit -am "project init"
---------------------------------------------

---------------------------------------------
git init
git add .
git commit -am "project init"
---------------------------------------------

philos66의 이미지

Dx.Dial(1, "025552222", 0, 1);

C#은 type checking이 더 엄격해서 그런지, 위와 같이 넣으면 다음과 같은 컴파일 에러가 뜹니다.

Argument 3: cannot convert from 'int' to 'ref Dialogic.Voice.DX_CAP'
byung82의 이미지

굳이 null을 하고 싶으시면 IntPtr로 작업을 하셔서 Marshal로 copy를 하시거나 아니면

C#버전을 몇을 사용하는지 모르겠지면 Nullable를 활용하는것도 한방법입니다.

DX_CAP? cap = new DX_CAP();
Dx.Dial(1, "025552222", ref cap, 1);

이런씩으로 오류가 발생할수도 있습니다 ^^;

그런데 ref 키워드로 하시면 그냥 null로 셋팅되지 않는가여 ^^?

꼭 널이 필요하시면 struct보다는 class로 설정하시기 바랍니다.

그럼

philos66의 이미지

C# 4.0을 사용하고 있고요, 지적하신 대로 nullable type을 이용해 이러 저러한 방법으로 시도해 보았습니다만, 여전히 안되는 군요.

제가 알기로는, C#의 null은 `아무런 값도 대입되어 있지 않다'는 뜻으로 알고 있습니다. 그런데 C의 NULL 포인터는 포인터 변수에 '0의 값을 대입'하는 것이이서, C#의 null이라는 개념과는 다른 개념으로 알고 있습니다.

C#의 nullable 변수에 null을 대입할 때, C# 내부적으로 어떻게 구현되어 있는지는 몰라도, NULL에 해당하는 0을 대입하는 것과는 다른 것으로 이해하고 있습니다. 혹시 저의 이해가 틀렸다면 지적해 주시기 바랍니다.

int? i = null;
int? j = 0;
 
if (i == j)
    Console.WriteLine("the same");
else
    Console.WriteLine("different");

실행 결과

different

philos66의 이미지

인터넷에서 정성태님의 도움을 받아. 일단은 해결이 되었습니다만, 더 좋은 방법이 없을까요?

다음은 정성태님이 제게 주신 해결책입니다.

=================================================================================
DllImport 는 사실 해당 메서드에 대해서 하나만 쓰라는 규칙은 없습니다. 따라서, 위와 같은 경우 NULL 포인터를 받아야 하는 상황에서는 다음과 같은 식으로 하나 더 정의(method overloading 이용)해두는 것도 방법일 수 있습니다.

[DllImport("libdxxmt", EntryPoint = "dx_dial",CallingConvention = CallingConvention.Cdecl)]
public static extern int Dial(int channel_device, string number, IntPtr pCap, int mode);

그래서, 호출 할 때는 Dx.Dial(0, "test", IntPtr.Zero, 0); 과 같이 해주시면 됩니다.
==================================================================================

그런데 문제는 이런 식으로 접근하는 경우에는, 만약 'NULL값 또는 포인터'를 요구하는 인수가 4개인 C 함수를 C# 함수로 연결해야 한다면, 총 2의 4승 = 16개의 C# 함수를 일일이 정의해 놓아야 한다는 이야기가 되어, 깔끔한 접근법은 아닌 듯 싶습니다.

특히 Win32 C API 의 경우에는 NULL 값을 선택적으로 줄 수 있는 함수가 굉징히 많은 것으로 알고 있는데, 좀 더 나은 접근법은 없는 것일까요?

byung82의 이미지

그냥 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 );

이렇게 하시면 바뀌는값에따라서 넘어오게 됩니다.

그럼

댓글 달기

Filtered HTML

  • 텍스트에 BBCode 태그를 사용할 수 있습니다. URL은 자동으로 링크 됩니다.
  • 사용할 수 있는 HTML 태그: <p><div><span><br><a><em><strong><del><ins><b><i><u><s><pre><code><cite><blockquote><ul><ol><li><dl><dt><dd><table><tr><td><th><thead><tbody><h1><h2><h3><h4><h5><h6><img><embed><object><param><hr>
  • 다음 태그를 이용하여 소스 코드 구문 강조를 할 수 있습니다: <code>, <blockcode>, <apache>, <applescript>, <autoconf>, <awk>, <bash>, <c>, <cpp>, <css>, <diff>, <drupal5>, <drupal6>, <gdb>, <html>, <html5>, <java>, <javascript>, <ldif>, <lua>, <make>, <mysql>, <perl>, <perl6>, <php>, <pgsql>, <proftpd>, <python>, <reg>, <spec>, <ruby>. 지원하는 태그 형식: <foo>, [foo].
  • web 주소와/이메일 주소를 클릭할 수 있는 링크로 자동으로 바꿉니다.

BBCode

  • 텍스트에 BBCode 태그를 사용할 수 있습니다. URL은 자동으로 링크 됩니다.
  • 다음 태그를 이용하여 소스 코드 구문 강조를 할 수 있습니다: <code>, <blockcode>, <apache>, <applescript>, <autoconf>, <awk>, <bash>, <c>, <cpp>, <css>, <diff>, <drupal5>, <drupal6>, <gdb>, <html>, <html5>, <java>, <javascript>, <ldif>, <lua>, <make>, <mysql>, <perl>, <perl6>, <php>, <pgsql>, <proftpd>, <python>, <reg>, <spec>, <ruby>. 지원하는 태그 형식: <foo>, [foo].
  • 사용할 수 있는 HTML 태그: <p><div><span><br><a><em><strong><del><ins><b><i><u><s><pre><code><cite><blockquote><ul><ol><li><dl><dt><dd><table><tr><td><th><thead><tbody><h1><h2><h3><h4><h5><h6><img><embed><object><param>
  • web 주소와/이메일 주소를 클릭할 수 있는 링크로 자동으로 바꿉니다.

Textile

  • 다음 태그를 이용하여 소스 코드 구문 강조를 할 수 있습니다: <code>, <blockcode>, <apache>, <applescript>, <autoconf>, <awk>, <bash>, <c>, <cpp>, <css>, <diff>, <drupal5>, <drupal6>, <gdb>, <html>, <html5>, <java>, <javascript>, <ldif>, <lua>, <make>, <mysql>, <perl>, <perl6>, <php>, <pgsql>, <proftpd>, <python>, <reg>, <spec>, <ruby>. 지원하는 태그 형식: <foo>, [foo].
  • You can use Textile markup to format text.
  • 사용할 수 있는 HTML 태그: <p><div><span><br><a><em><strong><del><ins><b><i><u><s><pre><code><cite><blockquote><ul><ol><li><dl><dt><dd><table><tr><td><th><thead><tbody><h1><h2><h3><h4><h5><h6><img><embed><object><param><hr>

Markdown

  • 다음 태그를 이용하여 소스 코드 구문 강조를 할 수 있습니다: <code>, <blockcode>, <apache>, <applescript>, <autoconf>, <awk>, <bash>, <c>, <cpp>, <css>, <diff>, <drupal5>, <drupal6>, <gdb>, <html>, <html5>, <java>, <javascript>, <ldif>, <lua>, <make>, <mysql>, <perl>, <perl6>, <php>, <pgsql>, <proftpd>, <python>, <reg>, <spec>, <ruby>. 지원하는 태그 형식: <foo>, [foo].
  • Quick Tips:
    • Two or more spaces at a line's end = Line break
    • Double returns = Paragraph
    • *Single asterisks* or _single underscores_ = Emphasis
    • **Double** or __double__ = Strong
    • This is [a link](http://the.link.example.com "The optional title text")
    For complete details on the Markdown syntax, see the Markdown documentation and Markdown Extra documentation for tables, footnotes, and more.
  • web 주소와/이메일 주소를 클릭할 수 있는 링크로 자동으로 바꿉니다.
  • 사용할 수 있는 HTML 태그: <p><div><span><br><a><em><strong><del><ins><b><i><u><s><pre><code><cite><blockquote><ul><ol><li><dl><dt><dd><table><tr><td><th><thead><tbody><h1><h2><h3><h4><h5><h6><img><embed><object><param><hr>

Plain text

  • HTML 태그를 사용할 수 없습니다.
  • web 주소와/이메일 주소를 클릭할 수 있는 링크로 자동으로 바꿉니다.
  • 줄과 단락은 자동으로 분리됩니다.
댓글 첨부 파일
이 댓글에 이미지나 파일을 업로드 합니다.
파일 크기는 8 MB보다 작아야 합니다.
허용할 파일 형식: txt pdf doc xls gif jpg jpeg mp3 png rar zip.
CAPTCHA
이것은 자동으로 스팸을 올리는 것을 막기 위해서 제공됩니다.