从 C# 到 Delphi 的翻译

Translation from C# to Delphi

我需要帮助将部分 C# 代码翻译成 Delphi。 如果有任何帮助或建议,我将不胜感激。

unsafe {
    fixed (byte* bpt = &buff[140]) {
        byte b1 = bpt[0];
        byte b2 = bpt[1];
        byte b3 = bpt[2];
        byte b4 = bpt[3];
    }
}

我尝试了几种方法,用 4 字节变量定义记录,定义 tbytearray,但似乎都不对。

对此有什么想法吗?

谢谢。

更新

看来我的问题没有定义好,因为这是我的第一个问题,这里是C#上的完整函数。

        private void ProcessCommAlarm_V40(ref CHCNetSDK.NET_DVR_ALARMER pAlarmer, IntPtr pAlarmInfo, uint dwBufLen, IntPtr pUser)
        {
            MyDebugInfo AlarmInfo = new MyDebugInfo(DebugInfo);

            byte[] buff = new byte[dwBufLen];
            System.Runtime.InteropServices.Marshal.Copy(pAlarmInfo, buff, 0, (int)dwBufLen);           

            string sBuff = "";

            if (dwBufLen - 140 > 0 && (dwBufLen - 140) % 4 == 0)
            {
                int msgType = BitConverter.ToInt32(buff, 0);
                string sMsgType = "";
                bool bAcceptedMsg = false;
                int nTargetType = 0; 

                switch (msgType)
                {
                    case 2:
                        sMsgType = "Video Loss"; bAcceptedMsg = true; nTargetType = 1; break;

                    case 3:
                        sMsgType = "Motion"; nTargetType = 1; break;
                }                

                if (bAcceptedMsg)
                {
                    int nTotalElements = BitConverter.ToInt32(buff, 12);

                    if ((nTargetType == 1 && nTotalElements <= CHCNetSDK.MAX_CHANNUM_V30) || (nTargetType == 2 && nTotalElements <= CHCNetSDK.MAX_DISKNUM_V30))
                    {
                        
                        int len = nTotalElements * 4;
                        byte[] channels = new byte[len];

                        unsafe
                        {
                            fixed (byte* bpt = &buff[140])
                            {
                                byte b1 = bpt[0];
                                byte b2 = bpt[1];
                                byte b3 = bpt[2];
                                byte b4 = bpt[3];

                                IntPtr dwDataAddress = new IntPtr(b1 + b2 * (1 << 8) + b3 * (1 << 16) + b4 * (1 << 24));
                                System.Runtime.InteropServices.Marshal.Copy(dwDataAddress, channels, 0, len);
                            }
                        }

                        for (int i = 0; i <= len - 4; i += 4)
                        {                            
                            sBuff += string.Format("Channel No: {0}", BitConverter.ToInt32(channels, i));
                            sBuff += Environment.NewLine;
                        }
                    }
                }
            }
        }

现在,这就是我到目前为止所做的,其中包括给我的 @remy-lebeau 所做的更改。

procedure ProcessCommAlarm_V40(pAlarmer: LPNET_DVR_ALARMER; pAlarmInfo: PChar; dwBufLen: DWORD; dwUser: DWORD);
var
  buff: array of byte;
  msgType: Integer;
  sMsgType: String;
  bAcceptedMsg: Boolean;
  nTargetType: Integer;
  sBuff: String;
  nTotalElements: Integer;
  channels: array of byte;
  len: Integer;
  b1,b2,b3,b4:byte;
  bpt: pbyte;
  dwDataAddress: IntPtr;
  I: Integer;
begin
  sBuff := '';

  SetLength(buff, dwBufLen);
  CopyMemory(buff, pAlarmInfo, dwBufLen);

  if (dwBufLen - 140 > 0) and ((dwBufLen - 140) mod 4 = 0) then begin
    msgType := Integer(buff[0]);
    sMsgType := '';
    bAcceptedMsg := false;
    nTargetType := 0;

    case (msgType) of
      2:
        begin
          sMsgType := 'Video loss';
          bAcceptedMsg := true;
          nTargetType := 1;
        end;
    end;

    if (bAcceptedMsg) then
    begin
      nTotalElements := buff[12];
      if ((nTargetType = 1) and (nTotalElements <= MAX_CHANNUM_V30)) or ((nTargetType = 2) and (nTotalElements <= MAX_DISKNUM_V30)) then begin
        len := nTotalElements * 4;
        SetLength(channels,len);

        bpt := @buff[140];
        b1 := bpt[0];
        b2 := bpt[1];
        b3 := bpt[2];
        b4 := bpt[3];

        dwDataAddress := IntPtr(b1 + b2 * (1 shl 8) + b3 * (1 shl 16) + b4 * (1 shl 24));

        sBuff := sBuff + IntToStr(dwDataAddress);
        sBuff := sBuff + #10 + #13;

        CopyMemory(Channels, @dwDataAddress, len);

        I:=0;
        while (i <= len - 4) do begin
          sBuff := sBuff + 'Channel No: ' + IntToStr(channels[i]);
          sBuff := sBuff + #13 + #10;
          i:= i + 4;
        end;
      end;
    end
  end;
end;

有人可以重新检查翻译,因为 Delphi 代码没有重现与 C# 相同的结果。

更新:

阅读下面@Remy 写下的详细解释后,我能够在 C# 和 Delphi.

中的两个应用程序上重现相同的结果

现在可以使用的代码如下。

procedure ProcessCommAlarm_V40(pAlarmer: LPNET_DVR_ALARMER; pAlarmInfo: IntPtr; dwBufLen: DWORD; dwUser: IntPtr);
var
  buff: array of byte;
  channels: array of byte;
  msgType: Integer;
  sMsgType: String;
  bAcceptedMsg: Boolean;
  nTargetType: Integer;
  sBuff: String;
  nTotalElements: Integer;
  len: Integer;
  b1,b2,b3,b4:byte;
  bpt: pbyte;
  dwDataAddress: IntPtr;
  I: Integer;
  x:pbyte;
begin
  Form1.Memo1.Lines.Add(FormatDateTime('H:m:s',now));
  sBuff := '';

  SetLength(buff, dwBufLen);
  CopyMemory(buff, Pointer(pAlarmInfo), dwBufLen);

  if (dwBufLen - 140 > 0) and ((dwBufLen - 140) mod 4 = 0) then begin
    msgType := Integer(buff[0]);
    sMsgType := '';
    bAcceptedMsg := false;
    nTargetType := 0;

    case (msgType) of
      2:
        begin
          sMsgType := 'Video loss';
          bAcceptedMsg := true;
          nTargetType := 1;
        end;
    end;

    if (bAcceptedMsg) then
    begin
      nTotalElements := buff[12];
      if ((nTargetType = 1) and (nTotalElements <= MAX_CHANNUM_V30)) or ((nTargetType = 2) and (nTotalElements <= MAX_DISKNUM_V30)) then begin
        len := nTotalElements * 4;
        SetLength(channels,len);

        bpt := @buff[140];
        b1 := bpt[0];
        b2 := bpt[1];
        b3 := bpt[2];
        b4 := bpt[3];

        dwDataAddress := IntPtr(b1 + b2 * (1 shl 8) + b3 * (1 shl 16) + b4 * (1 shl 24));
        CopyMemory(Channels, Pointer(dwDataAddress), len);

        I:=0;
        while (i <= len - 4) do begin
          sBuff := sBuff + 'Channel No: ' + IntToStr(channels[i]);
          sBuff := sBuff + #13 + #10;
          i:= i + 4;
        end;
      end;
    end
  end;
end;

给定 buff: array[0..MaxLimit] of Byte; 其中 MaxLimit >= 143;

在 Delphi 2009 年及以后:

var
  bpt: PByte;
  b1, b2, b3, b4: Byte;
begin
  bpt := @buff[140];
  b1 := bpt[0];
  b2 := bpt[1];
  b3 := bpt[2];
  b4 := bpt[3];
end;

2007 年 Delphi 及更早版本:

var
  bpt: PChar;
  b1, b2, b3, b4: Byte;
begin
  bpt := PChar(@buff[140]);
  b1 := Byte(bpt[0]);
  b2 := Byte(bpt[1]);
  b3 := Byte(bpt[2]);
  b4 := Byte(bpt[3]);
end;

或者:

var
  bpt: PByte;
  b1, b2, b3, b4: Byte;
begin
  bpt := @buff[140];
  b1 := bpt^; Inc(bpt);
  b2 := bpt^; Inc(bpt);
  b3 := bpt^; Inc(bpt);
  b4 := bpt^; Inc(bpt);
end;

更新:话虽如此,我发现您的翻译存在一些问题。

  • 在C#代码中,dwUser参数被声明为IntPtr,这是一个指针大小的整数。 Delphi 还有 IntPtr。但是在您的 Delphi 代码中,您已将参数声明为 DWORD。这将适用于 32 位版本,但不适用于 64 位版本。如果参数收到超过 32 位的值,如内存地址,它将被截断。如果不是 IntPtr.

    ,请改用 DWORD_PTR
  • 在C#代码中,pAlarmInfo参数声明为IntPtr。但是在您的 Delphi 代码中,您已将参数声明为 PChar。虽然 可以 工作,但如果不是 IntPtr.

    ,则无类型的 Pointer 会更合适
  • 在Delphi中,使用array of bytes对于buffchannels变量是可以的,尽管TBytesTArray<Byte> 在现代 Delphi 版本中更受欢迎。

  • 使用 Win32 CopyMemory() 函数没问题,但您应该考虑使用 Delphi 的 System.Move()。在任何情况下,您对 CopyMemory() 的第一次调用都是正确的(但是,如果 pAlarmInfo 被声明为 IntPtr,您将必须将其类型转换为 Pointer)。但是,您的第二次通话是错误的。 C# 代码正在从 dwDataAddress 中保存的内存地址复制 len 字节,而您正在从 dwDataAddress 本身的地址复制 len 字节。您需要将 dwDataAddress 类型转换为指针并从指向的地址复制。

  • 你对msgTypenTotalElements赋值的翻译是错误的。 C# 代码分别从索引 0..312..15 处的 buff 中提取 4 字节整数 。您的 Delphi 代码正在读取索引 1215 处的 1 字节 ,并将它们的值扩展到 Integer。不是一回事。

  • 您完全省略了 case msgType of 语句中的 3 大小写。可能是因为它没有设置 bAcceptedMsg = true。我怀疑缺少赋值可能是 C# 代码中的错误。

  • #10 + #13 应该是 #13 + #10,或者只是 #13#10。或者,您应该改用 Delphi 的 System.sLineBreak 常量。

  • 你对 channel 数字的翻译是错误的。如上文所述,C# 代码分别从索引 i..i+3 处的 channels 中提取 4 字节整数 。您的 Delphi 代码正在读取索引 i 处的 1 字节 并将其值扩展到 Integer.