【问题标题】:Marshaling C# caller for Delphi procedure of object为对象的 Delphi 过程编组 C# 调用者
【发布时间】:2021-08-31 05:47:09
【问题描述】:

我找到了答案,但对我正在尝试做的事情是否定的:

Passing method pointer from C# to Delphi DLL

是否有可能在 C# 中从 Delphi 调用对象委托?因为上面示例中的所有 Delphi 调用者都是静态的并且是导出的。我正在使用 OleVariant,并希望使用 GetDelegateForFunctionPointer 从 C# 中的 Delphi 对象调用调用者。但是当我尝试时,Delphi 事件中的调试器在该方法中中断,然后我得到“尝试读取或写入受保护的内存”。

德尔福代码:

TOnEvent = procedure() of object;
TOnEventStdCall = procedure() of object; stdcall;

TSimpleClass = class
  FUserControl: OleVariant;
  FOnEventHandler : TOnEvent;
  FOnEventStdCallHandler : TOnEventStdCall;
  constructor Create();  
  procedure ProcOnEventStdCall(); stdcall;
end;    
...
constructor TSimpleClass.Create();
begin
  FHost := TJclClrHost.Create('v4.0.30319');
  FHost.Start;
  FUserControl := FHost.DefaultAppDomain.CreateInstance('CSharpLibrary','CSharpLibrary.Init').Unwrap;
  FOnEventHandler := nil;
  FOnEventStdCallHandler := ProcOnEventStdCall;
  FUserControl.SetEvent(LongInt(@FOnEventStdCallHandler), LongInt(self));
end;

procedure TSimpleClass.ProcOnEventStdCall; stdcall;
begin
    ShowMessage('Invoked');
    if Assigned(FOnEventHandler) then 
      FOnEventHandler();               // !!! exception here
end;

和 C# 代码:

 struct TMethod
 {
    IntPtr pMethod;
    IntPtr pInstance;  
 }
 [UnmanagedFunctionPointer(CallingConvention.StdCall)]
 public delegate void TEvent(IntPtr instance);
 private TOnEventStdCall _delphiHandler;

 public void SetEvent(Int32 method, Int32 instance)
 {
      m.pMethod = new IntPtr(method);
      m.pInstance = new IntPtr(instance);
      _delphiHandler += (TEvent)Marshal.GetDelegateForFunctionPointer(m.pMethod, typeof(TEvent));
 }
...
_delphiHandler.Invoke(m.pInstance);

我相信有类似的问题,但没有得到答案:

c# equivalent of pascal/delphi procedure of object

【问题讨论】:

  • 这里不够详细,我们需要minimal reproducible example。但是,对 SetDocumentCompleatedEvent 的调用不能做任何有用的事情,因为它只传递了一半的方法,即代码而不是数据。
  • 我已经纠正了这个问题,并将尝试准备适当的可执行代码。我正在使用 JCL 在 Delphi 中执行 C# 代码,并尝试削减所有不必要的代码行。
  • 仍然遇到同样的问题。你只通过了一半的方法。一个方法是两个指针。你只通过一个。
  • 我不明白你写了什么。哪个方法有两个指针?有两种方法。一个“SetEvent”将指针传递给我想在 C# 中调用的 Delphi 中的过程。第二个是不带参数的调用过程。
  • @PawełKępiński FUserControl.SetEvent 是什么意思 - 还有什么?根据第一条评论,您无处传递方法的数据,只传递其代码。

标签: c# delphi marshalling


【解决方案1】:

我还没有测试过代码。然而,在 Delphi 中,它必须如下所示:

type
  TOnEvent = procedure() of object;
  TSimpleClass = class
     FUserControl: OleVariant;
     constructor Create();
     procedure ProcOnEvent();
  end;

  procedure EventStdCall(AObj: TObject); stdcall;
  var
    r   : TMethod;
    func: TOnEvent;
  begin
    r.Data := AObj;
    r.Code := @TSimpleClass.ProcOnEvent;
    func   := TOnEvent(r);
    func(); //Execute
  end;

  constructor TSimpleClass.Create();
  begin
    FHost := TJclClrHost.Create('v4.0.30319');
    FHost.Start;
    FUserControl := FHost.DefaultAppDomain.CreateInstance('CSharpLibrary','CSharpLibrary.Init').Unwrap;
    FUserControl.SetEvent(LongInt(@EventStdCall), LongInt(Self));
 end;

 procedure TSimpleClass.ProcOnEvent;
 begin
   ShowMessage('Invoked');
 end;

对于“Self”,可以在 C# 中使用 Int32。这同样适用于EventStdCall方法中TObject类型的参数,

【讨论】:

  • 好的。 Olivier 还给了我在你的例子中注意到的建议——“LongInt(Self)”——现在我的例子工作了——看起来很纯粹。感谢您的建议。
猜你喜欢
  • 2021-07-15
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2010-12-18
  • 1970-01-01
  • 2011-06-28
  • 1970-01-01
  • 2019-05-11
相关资源
最近更新 更多