FreePascal 64-битная DLL и вызов приложения C # - PullRequest
6 голосов
/ 13 июня 2011

Я пытаюсь скомпилировать 64-битную DLL для использования с 64-битным приложением C #.У меня есть простой класс и простое приложение, чтобы попробовать и протестировать его, и оно падает независимо от того, что я пытаюсь сделать.Вот код:

Delphi

library project1;

{$mode objfpc}{$H+}

uses
  Classes;


function Encrypt(aName:PChar):PChar;stdcall;
begin
  Result := aName;
end;


exports Encrypt;

begin
end.

C #

 [DllImport("project1.dll")]
    [return: MarshalAs(UnmanagedType.LPStr)]
    public static extern String Encrypt([MarshalAs(UnmanagedType.LPStr)] String aName);

Может кто-нибудь увидеть в этом что-то не так, и если не интересно, создать такой же простой сценарий, чтобы попробоватьЗаставь это работать, я на пределе!

1 Ответ

10 голосов
/ 13 июня 2011

Проблема в том, что маршаллер C # передает временный блок памяти в функцию как aName.Эта память уничтожается, когда функция возвращается.Но вы также просите маршаллера C # упаковать этот же блок памяти в строку C #.

В любом случае не рекомендуется возвращать строку с нулевым символом в конце из встроенной функции DLL.У вас есть пара опций:

  1. Используйте StringBuilder на стороне C #, чтобы предварительно выделить память для строки.Это требует, чтобы вы как-то овладели нужным размером.Это наиболее распространенный способ взаимодействия строк.
  2. Возвращает строку как COM BSTR, и маршаллер C # знает, как маршалировать и располагать BSTR, и для этого имеет доступ к распределителю COM.,Я не знаю, как использовать BSTR во FreePascal, но в Delphi вы просто используете WideString.Вы также должны сообщить маршаллеру C #, что вы возвращаете BSTR.

У меня лично есть предпочтение для варианта 2. Хотя есть один недостаток, и это то, что разные компиляторы используют разные ABIдля возвращаемых значений функции, как обсуждалось в этом вопросе: Почему WideString не может использоваться как возвращаемое значение функции для взаимодействия? Простой способ - вернуть строку в параметре, а не использовать функциювозвращаемое значение.

Код выглядит следующим образом:

Pascal

procedure Encrypt(Input: WideString; out Output: WideString); stdcall;
begin
  Output := Input;
end;

C #

[DllImport("project1.dll")]
public static extern void Encrypt(
    [MarshalAs(UnmanagedType.BStr)] string input;
    [MarshalAs(UnmanagedType.BStr)] out string output
);
...