При работе с межъязыковыми вызовами функций, важно учитывать соглашения о вызовах (calling conventions), которые определяют, как функции получают параметры. В случае синхронизации делегатов между C# и Delphi, особенно важно правильно установить соглашение о вызовах, чтобы обеспечить корректный обмен данными.
Проблема
При попытке вызвать делегат из C# кода в Delphi, наблюдается несоответствие соглашений о вызовах. В C# используется делегат strCB, который принимает строку:
public delegate void strCB(string s);
В то время как в Delphi определено соглашение stdcall для обработки строк:
Чтобы решить проблему, необходимо использовать соглашение о вызовах cdecl в Delphi, соответствующее соглашению CALLCONV_CDECL в C#. Это позволит корректно передавать строки между языками. Вот пример кода на Object Pascal (Delphi), который использует cdecl:
unit Main;
interface
uses
Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants, System.Classes, Vcl.Graphics,
Vcl.Controls, Vcl.Forms, Vcl.Dialogs, Vcl.StdCtrls;
type
TForm2 = class(TForm)
Button2: TButton;
Edit2: TEdit;
procedure Button2Click(Sender: TObject);
private
public
end;
TStringCallback = procedure(str: PAnsiChar); cdecl;
procedure strCallBack(fct: TStringCallback); cdecl; external 'csTest.dll';
var
Form2: TForm2;
implementation
{$R *.dfm}
//*************************************************************
//callback with string
procedure writeEdit2(str: PAnsiChar); cdecl;
begin
Form2.Edit2.Text := str;
end;
procedure TForm2.Button2Click(Sender: TObject);
begin
strCallBack(writeEdit2);
end;
//*************************************************************
end.
И C# код, использующий CALLCONV_CDECL:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using RGiesecke.DllExport;
using System.Runtime.InteropServices;
namespace cs_dcsSrv
{
public class Class1
{
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
public delegate void strCB(String s);
[DllExport("strCallBack", CallingConvention = CallingConvention.Cdecl)]
public static void stringCallback(strCB fct)
{
String str = "hello from C#";
fct(str);
}
}
}
Подтвержденный ответ
Изменение соглашения о вызовах на cdecl в Delphi и использование соответствующего соглашения в C# позволяет успешно синхронизировать делегаты между языками. Это подтверждается рабочим кодом, предоставленным в комментариях.
Альтернативный ответ
Хотя использование Unicode строк может быть предпочтительным, в данном случае приведенный выше код работает с ANSI строками и соглашением о вызовах cdecl, что является необходимым для синхронизации с C# кодом, использующим аналогичное соглашение.
Заключение
При работе с межъязыковыми вызовами функций важно внимательно следить за соглашениями о вызовах. В данном случае, изменение соглашения на cdecl позволило успешно синхронизировать делегат между C# и Delphi, обеспечивая передачу строк без ошибок.
Контекст описывает проблему синхронизации делегатов между C# и Delphi, связанную с несоответствием соглашений вызова функций, и предлагает решение путем использования соглашения о вызовах `cdecl` в Delphi для соответствия с C#.
Комментарии и вопросы
Получайте свежие новости и обновления по Object Pascal, Delphi и Lazarus прямо в свой смартфон. Подпишитесь на наш Telegram-канал delphi_kansoftware и будьте в курсе последних тенденций в разработке под Linux, Windows, Android и iOS
Материалы статей собраны из открытых источников, владелец сайта не претендует на авторство. Там где авторство установить не удалось, материал подаётся без имени автора. В случае если Вы считаете, что Ваши права нарушены, пожалуйста, свяжитесь с владельцем сайта.