2017-11-06 3 views
2

에 포장 된 기록과 같은 방식으로 정렬 화 배열을 바이트 :는 C# 구조체는이 같은 바이트 배열을 생성 델파이 2007로 작성된 기존 응용 프로그램이 델파이

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; 

나는 C#에서이 부분을 다시 작성해야합니다. 지금까지이있어 :

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

나는 바이트 배열에 구조체를 변환하는 여러 가지 방법을 시도하지만, 그들 중 누구도 델파이 코드와 같은 결과를 재현하지 않습니다. C# performance - Using unsafe pointers instead of IntPtr and Marshal

가 나는 또한 SO에서 방법을 마샬링 일부 다른 시도했지만 아무 일하지 :

StructToBytes 방법은 여기에서 차용된다. 내가 뭘 잘못 했니?

+0

Delphi 2007 Char는 AnsiChar이고 C#은 유니 코드입니까? –

+0

C#의 Char는 2 바이트이며 C++에서는 1 바이트입니다. 그래서 C#에서 사용 : 새 바이트 [10]. 또한 배열은 '\ 0'(0x00)으로 끝나야합니다. 나는 보통 다음과 같이 사용한다 : Encoding.UTF8.GetBytes ("JohnSmith \ 0"); – jdweng

+1

** ** C#에서 this를 다시 작성해야한다면 interop 및 marshalling에 대해 왜 신경을 씁니까? 같은 바이트 수를 생성하면됩니다. 너무 어려울 수 없습니다. –

답변

2
[StructLayout(LayoutKind.Sequential, Pack = 1, CharSet = CharSet.Ansi)] 
struct command_data 
{ 
    public ushort direction; 
    [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 10)] 
    public string name; 
} 
+0

몇 가지 설명이 여기 좋을 것입니다. –