2 votes

C# Mise en forme de structures en tableaux d'octets de la même manière qu'avec des enregistrements emballés dans Delphi.

J'ai une ancienne application écrite en Delphi 2007 qui génère des tableaux d'octets comme celui-ci :

command_data = packed record
    direction     : word;
    name          : array [0..9] of char;
end;

command_header = packed record
    length      : word;
    data1       : word;
    data2       : cardinal;
end;

command_data_container = packed record
    data          : command_data;
    containerId   : word;
end;

function Generate(name: string)boolean;
var
  header  : command_header;
  container : command_data_container;
  charArrayName: array [0..9] of char;

begin
  charArrayName = array [0..9] of char;

  for I := 0 to Length(name) - 1 do begin
    charArrayName[i] := name[i+1];
  end;
  charArrayName[i+1] := #0;

  header.length := sizeof(header) + sizeof(container);
  header.data1 := 0;
  header.data2 := 1;

  container.data.direction := 1;
  container.data.name      := charArrayName;
  container.containerId    := 1;

  stream := TMemoryStream.Create;
  stream.WriteBuffer(header, SizeOf(header));
  stream.WriteBuffer(container, SizeOf(container));
  //...
 end;

Je dois réécrire cette partie en C#. J'ai obtenu ceci jusqu'à présent :

[StructLayout(LayoutKind.Sequential, Pack = 1)]
unsafe struct command_data
{
    public ushort direction;
    public fixed char name[10];
}

[StructLayout(LayoutKind.Sequential, Pack = 1)]
unsafe struct command_header
{
    public ushort length;
    public ushort data1;
    public ulong data2;
}    

[StructLayout(LayoutKind.Sequential, Pack = 1)]
struct command_data_container
{
    public command_data data;
    public ushort containerId;
} 

 public bool Generate(string name)
 {
    name = name + Char.MinValue; // Add null terminator.
    char[] charArrayName = agentId.ToCharArray();

    unsafe
    {
        command_header header;
        command_data_container command;

        header.data1 = 0;
        header.data2 = 1;
        header.length = (ushort)(sizeof(command_header) + sizeof(command_data_container));

        command.data.direction = 1;
        *command.data.name = charArrayName[0];

        for (int i = 1; i < charArrayName.Length; i++)
        {
            *(command.data.name + i) = charArrayName[i];
        }
        command.containerId = 1;

        var headerBytes = StructToBytes<command_header>(header);
        var commandBytes = StructToBytes<command_data_container>(command);

        byte[] combined = new byte[headerBytes.Length + commandBytes.Length];
        Buffer.BlockCopy(headerBytes, 0, combined, 0, headerBytes.Length);
        Buffer.BlockCopy(commandBytes, 0, combined, headerBytes.Length, commandBytes.Length);

        //combined should have the same data as the stream in the delphi code

    }
 }

public static byte[] StructToBytes<T>(T structure) where T : struct
{
    int size = Marshal.SizeOf(structure);
    byte[] rawData = new byte[size];
    GCHandle handle = GCHandle.Alloc(rawData, GCHandleType.Pinned);
    try
    {
        IntPtr rawDataPtr = handle.AddrOfPinnedObject();
        Marshal.StructureToPtr(structure, rawDataPtr, false);
    }
    finally
    {
        handle.Free();
    }
    return rawData;
}

J'ai essayé plusieurs méthodes pour convertir le struct en un tableau d'octets, mais aucune d'entre elles ne reproduit le même résultat que le code Delphi.

La méthode StructToBytes est empruntée à cet endroit : Performances en C# - Utilisation de pointeurs non sécurisés au lieu de IntPtr et Marshal

J'ai également essayé d'autres méthodes de marshalling de SO, mais rien n'a fonctionné. Qu'est-ce que j'ai fait de mal ?

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X