Перевод с C # на Delphi

#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 вместо этого вы объявили параметр как a DWORD . Это будет работать в 32-разрядной сборке, но не в 64-разрядной сборке. Если параметр когда-либо получит значение более 32 бит, например, адрес памяти, он будет усечен. Используйте DWORD_PTR вместо этого, если нет IntPtr .
  • в коде C # pAlarmInfo параметр объявляется как IntPtr . Но в вашем коде на Delphi вместо этого вы объявили параметр как a PChar . Хотя это может сработать, нетипизированный Pointer был бы более подходящим, если нет IntPtr .
  • в Delphi использование array of bytes buff channels переменных and допустимо, хотя TBytes or TArray<Byte> было бы более предпочтительным в современных версиях Delphi.
  • использование функции Win32 CopyMemory() — это нормально, но вместо этого вам следует рассмотреть возможность использования Delphi System.Move() . В любом случае, ваш 1-й вызов CopyMemory() является правильным (хотя, если pAlarmInfo он объявлен как IntPtr , вам придется ввести его в Pointer ). Однако ваш 2-й звонок неверен. Код C # копирует len байты из адреса памяти, хранящегося в dwDataAddress , в то время как вы копируете len байты из самого адреса dwDataAddress . Вместо этого вам нужно ввести приведение dwDataAddress к указателю и скопировать с указанного адреса.
  • ваш перевод назначений msgType и nTotalElements неверен. Код C # извлекает 4-байтовое целое число из buff индексов at 0..3 и 12..15 , соответственно. Ваш код Delphi считывает 1 байт в индексах 12 15 и масштабирует их значения до an Integer . Это не одно и то же.
  • вы полностью исключили случай 3 из case msgType of заявления. Вероятно, потому, что он не был настроен bAcceptedMsg = true . Я подозреваю, что пропущенное назначение может быть ошибкой в коде C #.
  • #10 #13 должно быть #13 #10 , или просто #13#10 . Или же вместо этого вам следует использовать System.sLineBreak константу Delphi.
  • ваш перевод чтения channel чисел неверен. Как и далее выше, код C # извлекает 4-байтовое целое число из channels индекса at i..i 3 соответственно. Ваш код Delphi считывает 1 байт по индексу i и масштабирует его значение до an Integer .

Комментарии:

1. большое вам спасибо за ваш ответ. Я знаю, что прошу о многом, но если бы вы могли перепроверить то, что я сделал до сих пор, это было бы потрясающе. Спасибо.

2. Дорогой @Remy, я потерял дар речи. Я действительно не знаю, как тебя отблагодарить. Я так долго боролся с этим, а ты все уладил, как будто это был легкий ветерок. Я изменил типы dwUser на IntPtr, pAlarmData на IntPtr, я изменил обе функции CopyMemory на приведение указателя как 1) CopyMemory(buff, Указатель (pAlarmInfo), dwBufLen); и 2) CopyMemory (каналы, указатель (dwDataAddress), len); После этого изменяются как C #, так и Delphi приложение воспроизводит один и тот же результат.