2008-10-09 7 views
25

나는 C++에서 다음과 같은 구조체가 :원수 C++ 구조체 배열

void GetData(LPRData *data); 
: 이러한 구조의 3의 배열을 얻기 위해 내가으로 호출/P이야

#define MAXCHARS 15 

typedef struct 
{ 
    char data[MAXCHARS]; 
    int prob[MAXCHARS]; 
} LPRData; 

그리고 기능을 C에서

는 ++ 나는이 같은 다만 것 :

LPRData *Results; 
Results = (LPRData *)malloc(MAXRESULTS*sizeof(LPRData)); 
GetData(Results); 

을 그리고 그것은 잘 작동,하지만 C#에서 내가 그것을 얻이 수없는 것. 내가 만든이 같은 C#을 구조체 :

public struct LPRData 
{ 

    /// char[15] 
    [MarshalAsAttribute(UnmanagedType.ByValTStr, SizeConst = 15)] 
    public string data; 

    /// int[15] 
    [MarshalAsAttribute(UnmanagedType.ByValArray, SizeConst = 15)] 
    public int[] prob; 
} 

을 그리고 나는 그 3 (및 모든 하위 배열)의 배열을 초기화하고이에 전달할 경우 :

GetData(LPRData[] data); 

그것을 성공하면 반환되지만 LPRData 배열의 데이터는 변경되지 않습니다.

는 심지어 원시 바이트 배열 3 LPRData 년대의 크기를 생성하고이 같은 함수 원형으로 되었 시도한 :

GetData의 (바이트 [] 데이터);

하지만 그 경우에는 첫 번째 LPRData 구조에서 "데이터"문자열을 가져 오지만 그 뒤에는 동일한 LPRData의 "prob"배열을 포함하여 아무 것도 없습니다.

제대로 처리하는 방법에 대한 아이디어가 있으십니까?

답변

23

나는 당신의 구조체 decloration에 몇 가지 속성을 추가하려고 할 것이다

[StructLayout(LayoutKind.Sequential, Size=TotalBytesInStruct),Serializable] 
public struct LPRData 
{ 
/// char[15] 
[MarshalAsAttribute(UnmanagedType.ByValTStr, SizeConst = 15)] 
public string data; 

/// int[15] 
[MarshalAsAttribute(UnmanagedType.ByValArray, SizeConst = 15)] 
public int[] prob; 
} 

* TotalBytesInStruct 변수

JaredPar를 나타 내기 위해 의도을 IntPtr 클래스를 사용하는 것이 도움이 될 수도 정확하지 않습니다 참고 ,하지만 나는 PInvoke를 사용하여 녹슨 느낌이 들었습니다.

+1

이 방법을 사용했지만 Mono에서 변수가 null 참조로 설정된다는 예외가 발생합니다. 예를 들어 "prob"는 null이므로 작동하지 않습니다. 나는 이것을 어떤 시점에서 새 것으로 만들어야 하는가, 아니면 어떻게 든 프레임 워크에 의해 다루어지기로되어있는가? 감사 – swinefeaster

13

포인터를 처리 할 때 트릭 하나는 IntPtr을 사용하는 것입니다. 그런 다음 Marshal.PtrToStructure를 포인터에 사용하고 구조의 크기에 따라 증가시켜 결과를 얻을 수 있습니다.

static extern void GetData([Out] out IntPtr ptr); 

LPRData[] GetData() 
{ 
    IntPtr value; 
    LPRData[] array = new LPRData[3]; 
    GetData(out value); 
    for (int i = 0; i < array.Length; i++) 
    { 
     array[i] = Marshal.PtrToStructure(value, typeof(LPRData)); 
     value += Marshal.SizeOf(typeof(LPRData)); 
    } 
    return array; 
} 
+2

11 중 라인해야 ToInt64' '행'및 '='로 변경 ToInt32' '+'= 64 비트를 실행하는 경우; 또는, value.ToInt32()를 제거 하시겠습니까? – maxwellb

+0

@maxwellb, 예. 작성된 코드는 64 비트 안전하지 않습니다. – JaredPar

+4

내가 실제로 얻는 것은 pointer.toInt + sizeof (struct)의 증가분만큼 증분 할당한다는 것입니다. 증분 만 sizeof (struct)가되지 않습니까? – maxwellb

2

OutAttribute으로 GetData 매개 변수를 표시 했습니까? 어레이에 적용되고, 비 blittable 유형 포맷시 InAttribute 및 OutAttribute 결합

은 특히 유용하다. 호출자는 두 가지 특성을 모두 적용 할 때만 호출자가 이러한 유형의 변경을 참조하십시오.

2

유사한 주제 this question 논의되었고, 결론의 하나는 CharSet라는 이름의 매개 변수가 CharSet.Ansi로 설정해야합니다이었다.그렇지 않으면 char 배열 대신 wchar_t 배열을 만들 것입니다. 이와 같은 것이 올바른 코드는 다음과

[Serializable] 
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi)] 
public struct LPRData 
{ 
    [MarshalAsAttribute(UnmanagedType.ByValTStr, SizeConst = 15)] 
    public string data; 

    [MarshalAsAttribute(UnmanagedType.ByValArray, SizeConst = 15)] 
    public int[] prob; 
}