#c# #delphi #code-translation
#c# #delphi #код-перевод
Вопрос:
Мне нужна помощь в переводе части кода C # на Delphi. Я был бы очень признателен за любую помощь или совет.
unsafe {
fixed (byte* bpt = amp;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 amp;amp; (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 amp;amp; nTotalElements <= CHCNetSDK.MAX_CHANNUM_V30) || (nTargetType == 2 amp;amp; nTotalElements <= CHCNetSDK.MAX_DISKNUM_V30))
{
int len = nTotalElements * 4;
byte[] channels = new byte[len];
unsafe
{
fixed (byte* bpt = amp;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;
Комментарии:
1. Вы должны показать, что вы сделали, и рассказать, как вы проверяете, правильно это или нет.
2. @fpiette, спасибо за ваш комментарий, я прошу прощения, это мой первый пост. Я обновил вопрос.
3. Это не служба перевода.
4. Да, спасибо, я в курсе этого, но я застрял на этой части кода уже 10 дней в проекте с более чем 20000 строками. Итак, я знаю, что это не по правилам, я знаю, что прошу многого, но мне действительно нужна помощь от кого-то, кто более опытен, чем я в этой области.
5. @Mark Вы пробовали отлаживать код, чтобы увидеть, где его поведение отличается от ваших ожиданий? Это сайт вопросов и ответов, а не служба отладки. Вы должны сосредоточиться на конкретных вопросах .
Ответ №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 вместо этого вы объявили параметр как aDWORD
. Это будет работать в 32-разрядной сборке, но не в 64-разрядной сборке. Если параметр когда-либо получит значение более 32 бит, например, адрес памяти, он будет усечен. ИспользуйтеDWORD_PTR
вместо этого, если нетIntPtr
. - в коде C #
pAlarmInfo
параметр объявляется какIntPtr
. Но в вашем коде на Delphi вместо этого вы объявили параметр как aPChar
. Хотя это может сработать, нетипизированныйPointer
был бы более подходящим, если нетIntPtr
. - в Delphi использование
array of bytes
buff
channels
переменных and допустимо, хотяTBytes
orTArray<Byte>
было бы более предпочтительным в современных версиях Delphi. - использование функции Win32
CopyMemory()
— это нормально, но вместо этого вам следует рассмотреть возможность использования DelphiSystem.Move()
. В любом случае, ваш 1-й вызовCopyMemory()
является правильным (хотя, еслиpAlarmInfo
он объявлен какIntPtr
, вам придется ввести его вPointer
). Однако ваш 2-й звонок неверен. Код C # копируетlen
байты из адреса памяти, хранящегося вdwDataAddress
, в то время как вы копируетеlen
байты из самого адресаdwDataAddress
. Вместо этого вам нужно ввести приведениеdwDataAddress
к указателю и скопировать с указанного адреса. - ваш перевод назначений
msgType
иnTotalElements
неверен. Код C # извлекает 4-байтовое целое число изbuff
индексов at0..3
и12..15
, соответственно. Ваш код Delphi считывает 1 байт в индексах12
15
и масштабирует их значения до anInteger
. Это не одно и то же. - вы полностью исключили случай
3
изcase msgType of
заявления. Вероятно, потому, что он не был настроенbAcceptedMsg = true
. Я подозреваю, что пропущенное назначение может быть ошибкой в коде C #. #10 #13
должно быть#13 #10
, или просто#13#10
. Или же вместо этого вам следует использоватьSystem.sLineBreak
константу Delphi.- ваш перевод чтения
channel
чисел неверен. Как и далее выше, код C # извлекает 4-байтовое целое число изchannels
индекса ati..i 3
соответственно. Ваш код Delphi считывает 1 байт по индексуi
и масштабирует его значение до anInteger
.
Комментарии:
1. большое вам спасибо за ваш ответ. Я знаю, что прошу о многом, но если бы вы могли перепроверить то, что я сделал до сих пор, это было бы потрясающе. Спасибо.
2. Дорогой @Remy, я потерял дар речи. Я действительно не знаю, как тебя отблагодарить. Я так долго боролся с этим, а ты все уладил, как будто это был легкий ветерок. Я изменил типы dwUser на IntPtr, pAlarmData на IntPtr, я изменил обе функции CopyMemory на приведение указателя как 1) CopyMemory(buff, Указатель (pAlarmInfo), dwBufLen); и 2) CopyMemory (каналы, указатель (dwDataAddress), len); После этого изменяются как C #, так и Delphi приложение воспроизводит один и тот же результат.