2008-10-09 13 views
25

Mam następujący struct w C++:marszałka C++ tablicy struct w C#

#define MAXCHARS 15 

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

i funkcję, że jestem p/powołując się dostać tablicę 3 z tych struktur:

void GetData(LPRData *data); 

w C++ byłoby po prostu zrobić coś takiego:

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

I to działa dobrze, ale w języku C# nie wydaje się uzyskać go do pracy. Utworzyłem C# struct tak:

public struct LPRData 
{ 

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

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

I jeśli zainicjować tablicę z 3 osób (i ich wszystkich sub-macierzy) i przekazać go w ten sposób:

GetData(LPRData[] data); 

IT zwraca z powodzeniem, ale dane w tablicy LPRData nie uległy zmianie.

ja nawet próbuje tworzyć tablicy bajtowej surowego rozmiarze 3 LPRData tych i które przechodzą do prototypu działają jak to:

GetData (bajt [] Dane);

Ale w takim przypadku otrzymam ciąg "data" od pierwszej struktury LPRData, ale nic poza tym, łącznie z tablicą "prob" z tych samych LPRData.

Jakieś pomysły, jak prawidłowo sobie z tym poradzić?

Odpowiedz

23

chciałbym spróbować dodać atrybuty do struct 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; 
} 

* Uwaga TotalBytesInStruct nie jest przeznaczony do reprezentowania zmiennej

JaredPar jest również prawdą, że za pomocą klasy IntPtr mogłyby być pomocne , ale minęło sporo czasu, odkąd użyłem PInvoke, więc jestem zardzewiały.

+1

Użyłem tego podejścia, ale dostaję wyjątki w Mono, że zmienne są ustawione na zerowe odniesienia. Na przykład "prob" ma wartość null, więc nie chce działać. Czy mam to w pewnym momencie wprowadzić na rynek, czy też powinno to w jakiś sposób być obsługiwane przez ramy? Dzięki – swinefeaster

13

Jedna z trików podczas pracy ze wskaźnikami polega na użyciu IntPtr. Następnie możesz użyć Marshal.PtrToStructure na wskaźniku i inkrementacji w zależności od wielkości struktury, aby uzyskać wyniki.

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

powinien być wiersz 11: zmienić '+ =' na '=' i 'ToInt32' na' ToInt64' jeśli działa 64-bit; lub, usuń 'wartość.ToInt32()'? – maxwellb

+0

@maxwellb, tak. Kod jak napisano nie jest bezpieczny w 64-bitowej wersji. – JaredPar

+4

to, w czym naprawdę się zajmuję, polega na tym, że przypisujesz inkrementację przyrostem wskaźnika pointer.toInt + sizeof (struct). Czy wzrost nie byłby tylko sizeof (struct)? – maxwellb

2

Czy oznaczyłeś parametr GetData na OutAttribute?

Połączenie InAttribute i OutAttribute jest szczególnie przydatna, gdy stosuje się tablic i sformatowanych nie blittable typów. Dzwoniący widzą zmiany dokonane przez osoby dokonujące zmian tylko dla tych typów, gdy zastosujesz oba atrybuty.

2

Podobny temat był omawiany na this question, a jeden z wniosków było to, że nazwał Parametr CharSet musi być ustawiony na CharSet.Ansi.W przeciwnym razie tworzylibyśmy tablicę wchar_t zamiast tablicy char. Tak więc poprawny kod byłby następujący:

[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; 
}