C # Dllimport Delphi Pointer

1

Я новичок в программировании, может ли кто-нибудь помочь мне вызвать функцию указателя из dll delphi в Visual С#.

Вот функция Delphi, хранящаяся в DLL. // Код Delphi, хранящийся в DLL

function DeviceName(Size : Integer; Msg : Pointer) : Integer stdcall;
var
  i: Integer;
  TempByte : PByte;
  TempName : string;
begin
  if DLLClass.DevList.HidDevices.Count > 0 then
  begin
    TempName := (DLLClass.DevList.HidDevices.Name[DLLClass.HIDTool.CurrentDeviceIndex]);
    if Length(TempName) <= Size then
    begin
      try
        TempByte := Msg;
        for i := 0 to Length(TempName) - 1 do
        begin
          TempByte^ := Ord(TempName[i+1]);
          Inc(TempByte)
        end;
        Result := Length(TempName);
      except
        Result := -2;
      end;
    end
    else
    begin
      Result := -3;
    end;
  end
  else
  begin
    Result := -1;
  end;
end;

//С# Code '//Импортировать указатель на функцию

[DllImport("HID_DLL.dll", CallingConvention= CallingConvention.StdCall,  CharSet = CharSet.Ansi)]
public unsafe static extern int DeviceName(IntPtr Size, [MarshalAs(UnmanagedType.LPStr)] string Msg);



unsafe static void Main()
{
byte[] buffer = new byte[32768];

       DeviceName(255, &**buffer);

            Console.WriteLine("%s\n" + buffer);
}

'

  • 0
    Это компилирует, то, что я получаю в строке cmd, не то, что я ожидаю. Конечным результатом было бы то, что мой код обнаружил, что USB HID-устройство прикрепило распечатку своего имени на экране в качестве кода delphi.
Теги:
pinvoke
dllimport

1 ответ

2

Эта функция Delphi довольно грязная. Его задача - скопировать строку в буфер, предоставленный вызывающим. Обычно это выполняется с использованием строк с нулевым символом, но код Delphi этого не делает.

Предполагая, что код Delphi не может быть изменен, здесь, как вызвать его из С#. Обратите внимание, что здесь вам не нужен небезопасный код, и я рекомендую вам прекратить использование небезопасного кода.

Прежде всего объявление p/invoke:

[DllImport("Azoteq_HID_DLL.dll", CallingConvention= CallingConvention.StdCall]
public static extern int DeviceName(int Size, byte[] Msg);

Параметр Size имеет тип Integer в Delphi. Это 32-битное целое число в С#. Поэтому используйте int, как и для возвращаемого значения. Не используйте IntPtr который является целым числом, размер которого равен числу указателя. Это неверно в 64-битном процессе. Параметр Msg должен быть выделен как массив байтов, поскольку вы не добавляете нулевой ограничитель. И это, в свою очередь, означает, что нет необходимости указывать CharSet.

Теперь вызов:

byte[] Msg = new byte[256];
int retval = DeviceName(Msg.Length, Msg);
if (retval < 0)
{
    // handle error
}
else
{
    string name = Encoding.Default.GetString(Msg, 0, retval);
}

Однако ваша функция Delphi плохо разработана. Как уже упоминалось, в этом сценарии принято использовать строки с нулевым завершением. Это позволяет разрешить маршаллерам p/invoke обрабатывать код плиты котла. Ваши коды ошибок также плохи. Если пользователь передает размер, который недостаточно для хранения строки, вы должны сообщить им, сколько места требуется.

Реализация функции Delphi также неоптимальна. Вместо того, чтобы копировать байт, вы должны скопировать весь буфер за один снимок.

Один последний совет. Ваша функция возвращает значения, указывающие, удалось или нет. Ваш код С# просто игнорирует эти возвращаемые значения. Как правило, если функция возвращает значение, вы должны ее прислушиваться. Особенно, когда вы выполняете interop, а возвращаемое значение указывает на успех или неудачу.

Ещё вопросы

Сообщество Overcoder
Наверх
Меню