【问题标题】:Translation from C# to Delphi从 C# 到 Delphi 的翻译
【发布时间】:2021-04-20 21:06:35
【问题描述】:

我需要帮助将部分 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;

【问题讨论】:

  • 你应该展示你所做的并告诉你如何验证它是否正确。
  • @fpiette,感谢您的评论,我很抱歉,这是我的第一篇文章。我已经更新了问题。
  • 这不是翻译服务。
  • 是的,谢谢,我知道这一点,但是我现在在超过 20000 行的项目中被困在这部分代码上 10 天。所以,我知道这不符合规则,我知道我的要求很高,但我真的需要在这个领域比我更有经验的人的帮助。
  • @Mark 您是否尝试过调试代码以查看其行为与您的预期有何不同?这是一个问答网站,而不是调试服务。您应该专注于具体问题

标签: c# delphi code-translation


【解决方案1】:

给定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;

在 Delphi 2007 及更早版本中:

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 中,buffchannels 变量可以使用 array of bytes,但在现代 Delphi 版本中更倾向于使用 TBytesTArray&lt;Byte&gt;

  • 使用 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

【讨论】:

  • 非常感谢您的回答。我知道我要求很多,但如果你能重新检查我到目前为止所做的事情,那就太棒了。谢谢。
  • 亲爱的@Remy,我无语了。我真的不能感谢你。我为此苦苦挣扎了很长时间,而您却轻而易举地解决了它。我将 dwUser 的类型更改为 IntPtr,将 pAlarmData 更改为 IntPtr,我将两个 CopyMemory 函数都更改为将 Pointer 转换为 1) CopyMemory(buff, Pointer(pAlarmInfo), dwBufLen); 2) CopyMemory(Channels, Pointer(dwDataAddress), len);在此更改之后,C# 和 Delphi 应用程序都重现了相同的输出。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2018-09-16
  • 2019-10-07
  • 1970-01-01
  • 1970-01-01
  • 2019-05-01
  • 2012-10-04
相关资源
最近更新 更多