从Delphi调用C#Dll-Export-以String作为参数进行回调-Robert Giesecke DLLExport

时间:2018-08-03 07:26:51

标签: c# delphi callback dllexport

我正在尝试从C#导出一个函数,并使用delphi应用程序调用此函数。 被调用的函数应获取一个回调作为参数。此回调将字符串作为参数。 csharp_export_function(callbackfct(str))

我设法调用一个C#函数,该函数编写一个字符串并在delphi中使用此字符串。 我还设法使用回调作为参数调用C#函数,并使用了该回调。

但是我无法获得带有字符串作为参数运行的回调。 在回调函数中使用字符串时,在Delphi中收到访问冲突异常。该字符串似乎在那里是空的。 因此,执行了callbak,但是无法使用该字符串。

我正在使用Robert Giesecke的DllExport for C#。 Delphi XE5和VS2012。

代码如下:

delphi:

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)
    Button1: TButton;
    Button2: TButton;
    Edit1: TEdit;
    Edit2: TEdit;
    Button4: TButton;
    Edit4: TEdit;
    procedure Button1Click(Sender: TObject);
    procedure Button2Click(Sender: TObject);
    procedure Button4Click(Sender: TObject);
  private

  public

  end;

  TStringCallback = procedure(out str:PAnsiChar);

  procedure strCallBack(fct: TStringCallback); cdecl; external 'csTest.dll';
var
  Form2: TForm2;

implementation

{$R *.dfm}

//*************************************************************
//callback with string
procedure writeEdit2(out str: PAnsiChar);
begin
  Form2.Edit2.Text := str;      //!! exception access violation !!
end;

procedure TForm2.Button2Click(Sender: TObject);
begin
  strCallBack(writeEdit2);
end;
//*************************************************************

end.

c#:

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
    {
        public delegate void strCB([MarshalAs(UnmanagedType.BStr)] String s);

        [DllExport("strCallBack", CallingConvention = CallingConvention.Cdecl)]
        public static void stringCallback(strCB fct)
        {
            String str = "hello from C#";
            fct(str);
        }
    }
}

谢谢。

2 个答案:

答案 0 :(得分:1)

您无需在此处传递参数使用out,并且调用约定与您的委托不匹配。委托的相关代码在C#端

public delegate void strCB(string s);

在Delphi方面

TStringCallback = procedure(str: PAnsiChar); stdcall;

我一如既往地坚持使用ANSI字符串,但是如果我的代码是我个人,则我会使用Unicode。

答案 1 :(得分:0)

该代码现在可以与David的建议一起使用。 不幸的是,我坚持使用cdecl调用约定,并在delphi端使用ansi字符串。

Delphi:

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#:

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);
        }
    }
}