首页 > 解决方案 > 无法注册类 TFMXApplicationDelegate

问题描述

我已经阅读了 Embarcadero 和其他文档,搜索了网络,显然有些东西并没有陷入困境。我有一个复杂得多的应用程序和 DLL/Dylib,但现在我只是使用这个简单的例子来尝试让它工作. 当我为 Win32 构建应用程序和 DLL 时,它工作正常,如果我不对 DLL 进行函数调用,它工作正常。一旦我调用 DLL,就会引发错误 Unable to register Class TFMXApplicationDelegate 并且应用程序终止。无论客户操作系统是在 VM(并行)还是物理设备(MacBook Pro 15 mid-2015)上,此行为都是相同的。

问题:如何确保TFMXApplicationDelegate 已注册,是否需要设置设置或权限。根据Apple文档,这似乎相当基本:

应用程序委托实际上是应用程序的根对象。

民主共和国:

Library  pTestDLL;

uses
  uTestDLL in 'uTestDLL.pas';

{$R *.res}

end.

这是简单的 PAS 文件(用于 Dylib):

unit uTestDLL;

interface

uses
  FMX.Dialogs;

// External functions and procedures
{$IFDEF MSWINDOWS}
function say_Hello(Hello: string): boolean; stdcall; forward;
{$ENDIF MSWINDOWS}
{$IFDEF MACOS}
function _say_Hello(Hello: string): boolean; cdecl; forward;
{$ENDIF MACOS}


exports
  {$IFDEF MSWINDOWS}
  say_Hello;
  {$ENDIF MSWINDOWS}
  {$IFDEF MACOS}
  _say_Hello;
  {$ENDIF MACOS}

Implementation

{$IFDEF MSWINDOWS}
function say_Hello(Hello: string): boolean; stdcall;
{$ENDIF MSWINDOWS}
{$IFDEF MACOS}
function _say_Hello(Hello: string): boolean; cdecl;
{$ENDIF MACOS}
begin
  Result := True;
  showmessage('In DLL: ' + Hello);
end;

end.

最后是简单的测试应用程序:

unit uDylibTest1;

interface

uses
  System.SysUtils, System.Types, System.UITypes, System.Classes, System.Variants,
  FMX.Types, FMX.Controls, FMX.Forms, FMX.Graphics, FMX.Dialogs, FMX.StdCtrls,
  FMX.Controls.Presentation;
const
  // Windows DLL Names
    {$IFDEF MSWINDOWS}
    TestDLL = 'pTestDLL.dll';
    {$ENDIF MSWINDOWS}

  // macOS DYLIB Names
    {$IFDEF MACOS}
    TestDLL = 'libpTestDLL.dylib';
    {$ENDIF MACOS}

type
  TfDylibTest = class(TForm)
    Button1: TButton;
    procedure Button1Click(Sender: TObject);
    procedure FormCreate(Sender: TObject);
    procedure FormShow(Sender: TObject);
  private
    { Private declarations }
  public
    { Public declarations }
  end;

type
  TuDylibTest = class(TForm)
  private
    { Private declarations }
  public
    { Public declarations }
  end;

{$IFDEF MSWINDOWS}
function say_Hello(Hello: string): boolean; stdcall; external TestDLL Delayed;
{$ENDIF MSWINDOWS}
{$IFDEF MACOS}
function _say_Hello(Hello: string): boolean; cdecl; external TestDLL;
{$ENDIF MACOS}



var
  fDylibTest: TfDylibTest;

implementation

{$R *.fmx}


procedure TfDylibTest.Button1Click(Sender: TObject);
var
 b:boolean;

begin
  showmessage('B4 function call);
  b := False;
  // Call the DLL Function
  {$IFDEF MSWINDOWS}
  b := say_Hello('The string passed to the DLL') then    
  {$ENDIF MSWINDOWS}
  {$IFDEF MACOS}
  b :=  _say_Hello('The string passed to the DLL');     
  {$ENDIF MACOS}

  if b then
    showmessage('Say Hello OK')
  else
    showmessage('Say Hello Failed');
end;

procedure TfDylibTest.FormCreate(Sender: TObject);
begin
  showmessage('onCreate');
end;

procedure TfDylibTest.FormShow(Sender: TObject);
begin
  showmessage('onShow');
end;

end.

标签: macosdelphifiremonkeydelphi-10.2-tokyo

解决方案


我代表 Alexander Brazda López 回答这个问题,他在 G+ Delphi 论坛上发布了这个问题(所以我不会把别人的回答归功于自己):

ShowMessage() 在 dll 中使用 FMX.Dialogs。我记得对此有一些限制,建议使用 bpl 代替 dll。我会尝试找到一些有关此的信息。只是为了检查,尝试使用反向字符串函数来测试打开和调用 dll 函数的工作。

我无法评论 WRT 下一部分回复的真实性,但公平地说,将包括它。然而,底线是使用子句中的 FMX.Dialogs 或 FMX.Forms,我得到了错误。删除这些并且没有发生 TFMXApplicationDelegate 错误。

在非平凡的“真实”示例中,我使用的单元 forshowmessage和 for application.processmessageswhich 在一个名为的跨平台函数WaitNoFreeze()中,顾名思义,它在主线程中放置一个等待,但不会停止所有其他活动,如sleep().

问题不在于找不到dylib,这可以通过调用dylib中的一个基本函数作为函数sum(a,b:integer)来检查:integer

问题是当我们通过某些函数调用 UI 或使用表单等嵌入式资源时。这是因为如果我们不使用 bpl,则会创建本地实例而不是共享全局实例,这会阻止 RegisterClass 或 GetMem 等函数共享数据。在 FMX 的情况下,由于 Kevin 公开的示例的 api 存在差异,在 Windows 中窗口的句柄不是必需的,因此 0 是有效值,在 MacOSX 中是必需的,但 dynlib 中的值是NULL 因为它没有被启动,虽然在应用程序中,但是因为 FMX 实例没有共享,所以不可能访问这个信息。当我们尝试在 Windows 中的 dll 中释放已由应用程序分配的内存块时,会发生同样的事情,


推荐阅读