问题描述
我需要帮助将部分 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,(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,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,b4:byte;
bpt: pbyte;
dwDataAddress: IntPtr;
I: Integer;
x:pbyte;
begin
Form1.Memo1.Lines.Add(FormatDateTime('H:m:s',Now));
sBuff := '';
SetLength(buff,Pointer(pAlarmInfo),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;
在 Delphi 2007 及更早版本中:
var
bpt: PChar;
b1,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,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 位的值,例如内存地址,它将被截断。如果不是DWORD_PTR
,请改用IntPtr
。 -
在 C# 代码中,
pAlarmInfo
参数声明为IntPtr
。但是在您的 Delphi 代码中,您已将参数声明为PChar
。尽管 可以 工作,但如果不是Pointer
,无类型的IntPtr
会更合适。 -
在 Delphi 中,对
array of bytes
和buff
变量使用channels
是可以的,尽管TBytes
或TArray<Byte>
在现代更受欢迎Delphi 版本。 -
使用 Win32
CopyMemory()
函数没问题,但您应该考虑使用 Delphi 的System.Move()
代替。在任何情况下,您对CopyMemory()
的第一次调用都是正确的(不过,如果pAlarmInfo
被声明为IntPtr
,则您必须将其类型转换为Pointer
)。但是,您的第二个电话是错误的。 C# 代码从len
中保存的内存地址复制dwDataAddress
字节,而您从len
本身的地址复制dwDataAddress
字节。您需要将dwDataAddress
类型转换为指针并从指向的地址复制。 -
您对
msgType
和nTotalElements
的赋值的翻译是错误的。 C# 代码分别从索引buff
和0..3
处的12..15
中提取 4 字节整数。您的 Delphi 代码正在索引12
和15
处读取 1 个字节,并将它们的值缩放到Integer
。不是一回事。 -
您在
3
语句中完全省略了 casecase msgType of
。可能是因为它没有设置bAcceptedMsg = true
。我怀疑缺少赋值可能是 C# 代码中的错误。 -
#10 + #13
应该是#13 + #10
,或者只是#13#10
。或者,您应该改用 Delphi 的System.sLineBreak
常量。 -
您对
channel
数字的翻译是错误的。与上面进一步类似,C# 代码分别从索引channels
处的i..i+3
中提取 4 字节整数。您的 Delphi 代码正在索引i
处读取 1 个字节并将其值缩放到Integer
。