2009-09-21 16 views
5

Robię niektóre prace interakcji C#. Mam następujące struct:C#: uporządkowanie struktury zawierającej tablice

#pragma pack(push,1) 
typedef struct 
{ 
    unsigned __int64 Handle; 
    LinkType_t Type; 
    LinkState_t State; 
    unsigned __int64 Settings; 
    signed __int8 Name[MAX_LINK_NAME]; 
    unsigned __int8 DeviceInfo[MAX_LINK_DEVINFO]; 
    unsigned __int8 Reserved[40]; 
} LinkInfo_t; 

To jest mój próbę przekształcenia go w C# struct:

[StructLayout(LayoutKind.Sequential, Pack = 1)] 
public struct LinkInfo_t 
{ 
    [MarshalAs(UnmanagedType.U8)] 
    public UInt64 Handle; 
    MarshalAs(UnmanagedType.I4)] 
    public LinkType_t Type; 
    [MarshalAs(UnmanagedType.I4)] 
    public LinkState_t State; 
    [MarshalAs(UnmanagedType.U8)] 
    public UInt64 Settings; 
    [MarshalAs(UnmanagedType.LPStr, SizeConst = MAX_LINK_NAME)] 
    public string Name; 
    [MarshalAs(UnmanagedType.ByValArray, SizeConst = MAX_LINK_DEVINFO, ArraySubType = UnmanagedType.U1)] 
    public byte[] DeviceInfo; 
    [MarshalAs(UnmanagedType.ByValArray, SizeConst = 40, ArraySubType = UnmanagedType.U1)] 
    public byte[] Reserved; 
} 

Jednak ilekroć zainicjować struct nazwa, DeviceInfo i Reserved pola są cały zestaw do wartości null. Jak to naprawić?

Odpowiedz

7

Dla tablic, spróbuj użyć fixed modyfikator:

public fixed byte DeviceInfo[MAX_LINK_DEVINFO]; 
    public fixed byte Reserved[40]; 
+0

Działa to dla tablic. Jednak poprawna składnia to publiczny stały bajt DeviceInfo [MAX_LINK_DEVINFO]; Muszę również zadeklarować strukturę jako niebezpieczną. –

+0

Masz rację, naprawiłem to –

3

ilekroć zainicjować struct Nazwa, DeviceInfo i Reserved pola są ustawione na null

To jest poprawne, a twoja definicja wygląda dla mnie dobrze (BTW, nie potrzebujesz [MarshalAs] na prymitywnych polach, domyślnym zachowaniem jest robienie tego, co tam podałeś). Ponieważ twoje pola tablicowe to null, marshaler nie zrobi nic na ich temat, gdy utworzy strukturę do niezarządzanej pamięci, ale stworzy niepotrzebne łańcuchy i tablice.

+1

zamiast niebezpiecznych i naprawionych, kod powinien przydzielić tablice bajtów przed jego użyciem. Zwykle mam konstruktor na strukturach dla p/invoke, gdzie dowolne tablice są automatycznie przydzielane. – erict

0

To, co mówi Anton Tykhyy, jest poprawne. Chcę tylko wyjaśnić kilka przykładów. Używanie "naprawionych" utworów, ale także zmusza do użycia "niebezpiecznych". Lubię unikać niebezpieczeństwa, gdy tylko jest to możliwe. Używanie Marszałka jest sposobem na obejście tego.

Po pierwsze, załóżmy, że mam bibliotekę, która została utworzona w C z następującymi definicjami.

typedef struct { 
    int messageType; 
    BYTE payload[60]; 
} my_message; 

/** 
* \param[out] msg Where the message will be written to 
*/ 
void receiveMessage(my_message *msg); 

/* 
* \param[in] msg The message that will be sent 
*/ 
void sendMessage(my_message *msg); 

C# następującą strukturę będzie równoważny do pokazanego na C

[StructLayout(LayoutKind.Sequential, Size = 64), Serializable] 
struct my_message 
{ 
    int messageType; 
    [MarshalAs(UnmanagedType.ByValArray,SizeConst = 60)] 
    byte[] payload; 

    public initializeArray() 
    { 
     //explicitly initialize the array 
     payload = new byte[60]; 
    } 
} 

Ponieważ msg w receiveMessage() jest udokumentowana [z], nie trzeba wykonywać cokolwiek specjalnego dla tablicy w strukturze przed przekazaniem jej do funkcji. tj .:

my_message msg = new my_message(); 
receiveMessage(ref msg); 
byte payload10 = msg.payload[10]; 

Ponieważ MSG w sendMessage() jest udokumentowana jako [w], trzeba będzie wypełnić tablicę przed wywołaniem funkcji. Przed wypełnieniem tablicy, tablica musi być jawnie utworzona, zanim z niej skorzystasz. tj .:

my_message msg = new my_message(); 
msg.initializeArray(); 
msg.payload[10] = 255; 
sendMessage(ref msg); 

Wywołanie initializeArray() powinna instancji tablicy w uprzednio przydzielonej przestrzeni stworzonej w ramach struktury dla tej tablicy.

Powiązane problemy