Delphi记录转换为C#struct并从socket读取

时间:2012-05-12 11:09:23

标签: c# delphi struct record

我从套接字中读取Delphi代码:

type
   RegbusReq2=packed record 
     Funct:char;             
     Device:char;            
     Device1:char;
     Starting:integer;       
     Quantity:smallint;      
     _CRC:Word;              
     stroka:char;            
   end;

   type                         
     crcReg=packed record
     buf:array[0..2] of byte;
     value:array[0..5] of byte;
   end;

   type                          
   myRB=record                       
   case byte of
    0:(data:RegbusReq2);
    1:(Buff:crcReg);
   end;

   type
   outVal=packed record
    cap:array[0..8] of byte;
    val:array[0..3] of single;
   end;

   type
   outValBuff=record
   case byte of
    0:(val:outVal);
    1:(Buff:array [1..25] of byte);
   end;


var
  Form1: TForm1;
  hCommFile:THandle;  
  typeCon:byte;       
  cs1: TClientSocket;
...

读取数据的计时器:

Procedure TForm1.Timer1Timer(Sender: TObject);
var
  DataReq:myRB;
  output:outValbuff;
  Wr,Rd:Cardinal;
  i:integer;
  st:string;
begin
    //çàïîëíåíèå çàïðîñà
  DataReq.data.Funct:=chr(63);    //êîìàíäà "?"
  DataReq.data.Device:=chr(48);     //íîìåð ïðèáîðà ñò
  DataReq.data.Device1:=chr(49);    //íîìåð ïðèáîðà ìëàäøèé
  DataReq.data.Starting:=2088;     //àäðåñ â äåñ ôîðì
  DataReq.data.Quantity:=16;       //ðàçìåð äàííûõ
  DataReq.data._CRC:=CRC2(@DataReq.Buff.value,6);      //ÊÑ
  DataReq.data.stroka:=chr(13);             //ïåðåâîä ñòðîêè

PurgeComm(hCommFile,PURGE_RXCLEAR or PURGE_TXCLEAR);
if typecon=1 then begin   //COM-ïîðò
 WriteFile(hCommFile,DataReq.data,SizeOf(DataReq.data),Wr,nil);
 ReadFile(hCommFile,Output.buff,SizeOf(Output.Buff),Rd,nil);
end;
if typecon=2 then begin    //ethernet
  cs1.Active:=true;
  cs1.Socket.SendBuf(DataReq.data,SizeOf(DataReq.data));
  cs1.Socket.ReceiveBuf(output.buff,SizeOf(Output.Buff));
  cs1.Active:=false;
 end;

 for i:=1 to 25 do
 st:=st + '_' + inttostr(output.buff[i]);
 memo1.Lines.Add(st);

 edit1.Text:=FloatToStr(Round(output.val.val[0]
 *exp(2*ln(10)))/(exp(2*ln(10))));
 edit2.Text:=FloatToStr(Round(output.val.val[1]
 *exp(2*ln(10)))/(exp(2*ln(10))));
 edit3.Text:=FloatToStr(Round(output.val.val[2]
 *exp(2*ln(10)))/(exp(2*ln(10))));
 edit4.Text:=FloatToStr(Round(output.val.val[3]
 *exp(2*ln(10)))/(exp(2*ln(10))));

end;

我关注C#代码:

[StructLayout(LayoutKind.Sequential, Pack = 1, CharSet = CharSet.Ansi)]        
        public struct RegBusRec
        {
            public char Funct;
            public char Device;
            public char Device1;
            public int Starting;
            public short Quantity;
            public ushort _CRC;
            public char Message;
        }
...
private void timer1_Tick(object sender, EventArgs e)
        {
            byte[] CRCc = new byte[6];
            byte[] tmp;
            byte[] output = new byte[25];
            RegBusRec req2 = new RegBusRec();
            Crc16 crc16 = new Crc16();
            req2.Funct = '?';
            req2.Device = '0';
            req2.Device1 = '1';
            req2.Starting = 2088;
            req2.Quantity = 16;
            req2.Message = '\r';
            tmp = BitConverter.GetBytes(req2.Starting);
            CRCc[0] = tmp[0];
            CRCc[1] = tmp[1];
            CRCc[2] = tmp[2];
            CRCc[3] = tmp[3];
            tmp = BitConverter.GetBytes(req2.Quantity);
            CRCc[4] = tmp[0];
            CRCc[5] = tmp[1];
            req2._CRC = crc16.ComputeChecksum(CRCc);
            textBox6.Text += Environment.NewLine;
            textBox6.Text += "CRC: " + req2._CRC;
            cl.Client.Send(StructureToByteArray(req2));
            cl.Client.Receive(output);
            byte[] val = new byte[4];
            val[0] = output[15];
            val[1] = output[16];
            val[2] = output[17];
            val[3] = output[18];
            textBox6.Text += Environment.NewLine;
            textBox6.Text += "Query: ";
            for (int i = 0; i < StructureToByteArray(req2).Length; i++)
            {
                textBox6.Text += StructureToByteArray(req2)[i] + "_";
            }
            textBox2.Text = BitConverter.ToSingle(val,0).ToString();
            textBox6.Text += Environment.NewLine;
            textBox6.Text += "Data: ";
            for (int i = 0; i < output.Length; i++)
            {
                textBox6.Text += output[i] + "_";
            }
        }
...
static byte[] StructureToByteArray(object obj)
        {

            int len = Marshal.SizeOf(obj);
            byte[] arr = new byte[len];
            IntPtr ptr = Marshal.AllocHGlobal(len);
            Marshal.StructureToPtr(obj, ptr, true);
            Marshal.Copy(ptr, arr, 0, len);
            Marshal.FreeHGlobal(ptr);
            return arr;
        }

CRC计算正确。但我得到的textBox2.Text数字错误 - 随机数。我怎么能正确得到这个数字?提前谢谢。

Delphi调试器的Scrrenshot:

enter image description here

1 个答案:

答案 0 :(得分:2)

好吧,我想我可能已经破译了它,但我不会指望它。

您似乎在说{C#代码在textBox2中显示意外值。查看C#代码,textBox2显示来自val的数据。 val的分配方式如下:

val[0] = output[15];
val[1] = output[16];
val[2] = output[17];
val[3] = output[18];

请注意,output是一个C#字节数组,因此使用从零开始的索引。

在您的Delphi代码中,匹配的数据结构是:

outVal=packed record
  cap:array[0..8] of byte;
  val:array[0..3] of single;
end;

outValBuff=record
  case byte of
  0:(val:outVal);
  1:(Buff:array [1..25] of byte);
end;

因此,cap消耗前9个字节,然后接下来的16个是4个单精度值。就C#字节数组而言:

  • cap output[0]output[8]
  • val[0] output[9]output[12]
  • val[1] output[13]output[16]
  • val[2] output[17]output[20]
  • val[3] output[21]output[24]

但您正在阅读output[15]output[18],因此将val[1]的一半与val[2]的一半结合起来。

简而言之,您只需要修改索引。


现在,你正在使它变得更加复杂。您可以执行以下操作来获取所有4个单值:

single[] val = new single[4];
int byteIndex = 9;
for (int i=0; i<4; i++)
{
    val[i] = BitConverter.ToSingle(val, byteIndex);
    byteIndex += 4;
}

而不是将字节逐字节地复制到CRCc中,请执行以下操作:

Buffer.BlockCopy(BitConverter.GetBytes(req2.Starting), 0, CRCc, 0, 4);
Buffer.BlockCopy(BitConverter.GetBytes(req2.Quantity), 0, CRCc, 4, 2);