2009-08-06 3 views
0

저는 네이티브 C++ dll을 호출하는 C# 프로그램이 있습니다.C++에서 struct를 C#으로 다시 반환 할 수 없습니다.

는 C#은 다음 구조체 가지고

[StructLayout(LayoutKind.Sequential)] 
public struct Phenomenon 
{ 
    [MarshalAs(UnmanagedType.U1)] public char Type; 
    [MarshalAs(UnmanagedType.R8)] public double Jd; 
    [MarshalAs(UnmanagedType.R8)] public double Loc_jd; 
    [MarshalAs(UnmanagedType.R8)] public double Angle; 
    [MarshalAs(UnmanagedType.U1)] public char Tran_dir; 
    [MarshalAs(UnmanagedType.I2)] public Int16 Warning; 
} 

는 C++ 프로그램은 다음 구조체 정의 가지고

typedef struct 
    { 
     char type; 
     double jd; 
     double loc_jd; 
     double angle; 
     char tran_dir; 
     short int warning; 
    } phenomenon; 

는 C# 프로그램은 C의 다음 호출을 갖는 한 현상 객체를 인스턴스화를 ++ 방법 :

Phenomenon[] phenomena = new Phenomenon[6]; 
short status = rsttwi_temp(phenomena); 

C++은 단순히 struct를 업데이트하고 반환합니다. 다음은 C++ 기능입니다 : 내가 구조체가 업데이트되지 않은 C++ 함수 호출 후 구조체의 값을 출력 할 때 C# 프로그램에서

__declspec(dllexport) short int rsttwi_temp (phenomenon phen[1]) 
{ 
    phen[0].type = 'Z'; 
    phen[0].jd = 1.1; 
    phen[0].loc_jd = 2.2; 
    phen[0].angle = 3.3; 
    phen[0].tran_dir = 4.4; 
    phen[0].warning = '0'; 

    return 0; 
} 

(즉, 그것은 C 이전과 동일 ++ 함수가 호출되었습니다). C++ 프로그램은 값을보고 업데이트 할 수 있지만 반환시 C#은 구조체의 값에 대한 업데이트를 보지 못합니다. 그것이 값 대 참조 문제라고 생각하면서도 구조체 대신 C# 프로그램의 클래스를 사용하여이 작업을 수행하려고했습니다. 아직도 운이 없다.

질문 : 호출 된 C++ 함수가 전달 된 실제 구조체를 업데이트 할 수 있도록하려면 어떤 마샬링이 필요합니까?

감사합니다. -Greg Edwards 토탈 집중 소프트웨어

답변

2

C# 함수의 정의를 보지 않으면 이것이 작동하지 않는 이유는 이해하기 쉽지 않습니다. 나는 고정 된 크기 기본 배열을 pinvoking 작업 많은 경험이없는이

[DllImport("somedll.dll")] 
public static extern Int16 rsttwi_temp(Phenomenon[] array); 

하지만이 같이 보입니다 같은데요. 하지만 C++ 서명을 고정 크기 배열 대신 포인터로 가져와 관리 코드를 참조로 전달하도록 전환 할 수 있습니다. 예 :

[DllImport("somedll.dll")] 
public static extern Int16 rsttwi_temp(ref Phenomenon value); 

__declspec(dllexport) short int rsttwi_temp (phenomenon* phen) 
+0

제라드, 나는 심판을 사용 할 수 있었지만 C++ 코드를 사용하여 크게 수정해야 할 것이기 때문에, 나는 그것을 사용하지 않는 것을 시도하고 있었다. 제안 해 주셔서 감사합니다. 나는 궁극적으로 이렇게 할 수 있습니다. -Greg –

+0

@Greg, 다른 옵션은 내가 지정한 서명이있는 두 번째 메소드를 만들고 첫 번째 메소드를 호출하는 것입니다. 그렇게하면 기존 코드를 변경하지 않고도 여전히 Parevoke 작업의 이점을 얻을 수 있습니다. – JaredPar

-1

C# char! = C++ char. 이 방법으로 사용

C#을 문자 == C++

C++의 char == C#을 바이트

1

wchar_t를 작동 :

C++

__declspec(dllexport) short int rsttwi_temp (phenomenon* phen) 
{ 
    phen->jd = 1.1; 
    phen->loc_jd = 2.2; 
    phen->angle = 3.3; 
    phen->warning = 0; 
    return 0; 
} 

typedef struct 
     { 
      double jd; 
      double loc_jd; 
      double angle; 
      short int warning; 
     } phenomenon; 

C#

[DllImport("somedll.dll", CallingConvention = CallingConvention.Cdecl)] 
public static extern Int16 rsttwi_temp(ref Phenomenon value); 

[StructLayout(LayoutKind.Sequential)] 
     public struct Phenomenon 
     { 
      [MarshalAs(UnmanagedType.R8)] 
      public double Jd; 
      [MarshalAs(UnmanagedType.R8)] 
      public double Loc_jd; 
      [MarshalAs(UnmanagedType.R8)] 
      public double Angle; 
      [MarshalAs(UnmanagedType.I2)] 
      public Int16 Warning; 
     } 

C# 호출

Phenomenon phenomena = new Phenomenon(); 
short status = rsttwi_temp(ref phenomena); 
+0

Jared가 중요하다고 생각했던 구조체 멤버를 제거한 경우를 제외하고는 Jared가 이미 제안한 방식입니다. 당신의 공헌은 정확히 무엇입니까? –

+0

죄송합니다.이 질문을 발견했기 때문에이 예제를 작성 했으므로 구현하는 것과 비슷한 것이 필요했지만 모든 스레드를 읽었을 때 테스트하지 않으려 고 시도했습니다. 그래서 나는 바꿨다. 내 의도가 코드로 변경되었으므로 구현 및 구조화가 필요한 사람은 이해하기 위해 1 시간을 잃지 않아도됩니다. 네가 원한다면 나는 이것을 거절 할 수있다. – Joaquin

관련 문제