FMX.TMSCLOUDxxx Causes Runtime Error 230 macOS

Hi,


I am trying to get the FMX Cloud Pack to work on macOS with no success. I need it to work in a DYLIB to reflect the DLL version I have working. Whilst the actual DYLIB is quite complex, I have commented out almost everything and still cannot get it to work. I have built a simple test harness that works perfectly. 

However IF I add any FMX.TMSCloudxxxx units, the Application will not load, the PAServer shows this error:

/BuildRoot/Library/Caches/com.apple.xbs/Sources/AppleFSCompression/AppleFSCompression-96.60.1/Common/ChunkCompression.cpp:49: Error: unsupported compressor 8

/BuildRoot/Library/Caches/com.apple.xbs/Sources/AppleFSCompression/AppleFSCompression-96.60.1/Libraries/CompressData/CompressData.c:353: Error: Unknown compression scheme encountered for file '/System/Library/CoreServices/CoreTypes.bundle/Contents/Resources/Exceptions.plist'

/BuildRoot/Library/Caches/com.apple.xbs/Sources/AppleFSCompression/AppleFSCompression-96.60.1/Common/ChunkCompression.cpp:49: Error: unsupported compressor 8

/BuildRoot/Library/Caches/com.apple.xbs/Sources/AppleFSCompression/AppleFSCompression-96.60.1/Libraries/CompressData/CompressData.c:353: Error: Unknown compression scheme encountered for file '/System/Library/CoreServices/CoreTypes.bundle/Contents/Library/AppExceptions.bundle/Exceptions.plist'

Runtime error 230 at 001A5A03


The code is detailed below. Again, IF I remove the FMX.TMSCloudXXX units, it works perfectly, by just including even one of the units, it fails. Now that could be (in this instance) some other dependency, but it builds fine so I have no idea.


Have the TMS people run the FMX.Cloudxxx units ins A macOS DYLIB, if so, what am I missing, if NOT can you please do so and let me know how to do it. This is a big deal and the REASON we purchased the FMX Cloud Pack. Here is the unit for the DYLIB, the DPR file simply USES that unit:


unit uTestDLL;


interface


// External functions and procedures

function say_Hello(Hello: PChar; out ReturnString: PChar): boolean; {$IFDEF MSWINDOWS}stdcall{$ELSE}cdecl{$ENDIF}; forward;

procedure free_String(S: PChar); {$IFDEF MSWINDOWS}stdcall{$ELSE}cdecl{$ENDIF}; forward;



exports

  say_Hello {$IFNDEF MSWINDOWS} name '_say_Hello'{$ENDIF},

  free_String{$IFNDEF MSWINDOWS} name '_free_String'{$ENDIF};


Implementation


uses

  System.SysUtils,

  System.Diagnostics,

  System.Classes,


  // INCLUDE ANY OF THESE UNITS AND IT GIVES RUNTIME ERROR 230

  FMX.TMSCloudBase,

  FMX.TMSCloudBaseFMX,

  FMX.TMSCloudWebBrowser.Mac,

  FMX.TMSCloudWebBrowser,

  FMX.TMSCloudDropBox,

  FMX.TMSCloudCustomDropBox;


var

  sType: string;


function say_Hello(Hello: PChar; out ReturnString: PChar): boolean; {$IFDEF MSWINDOWS}stdcall{$ELSE}cdecl{$ENDIF};

begin

  try

    try

      Result := True;

      ReturnString := StrAlloc(Length(sType));

      StrPCopy(ReturnString, sType);

    except

      on E: Exception do

      begin

        free_String(ReturnString);

        Result := False;

      end;

    end;

  finally


  end;


end;


procedure free_String(S: PChar); {$IFDEF MSWINDOWS}stdcall{$ELSE}cdecl{$ENDIF};

begin

  StrDispose(S);

end;


initialization

  {$IFDEF MSWINDOWS}sType := 'Windows DLL'; {$ENDIF}

  {$IFDEF MACOS}sType := 'macOS DYLIB'; {$ENDIF}

finalization


end.

AND just for the record, if I put the FMX.TMSCloudxxxxx units in the calling program, there is no problem, it works fine and the DYLIB function is called with the correct return values, BUT I need the FMX.TMSCloudxxxx units to function in a DLL/DYLIB, they get called by external programs. and for completeness here is the HOST application:


unit uDylibTest1;

interface

uses
  System.SysUtils,
  System.Types,
  System.Diagnostics,
  System.UITypes,
  System.Classes,
  System.Variants,

  FMX.TMSCloudBase,
  FMX.TMSCloudBaseFMX,
  FMX.TMSCloudWebBrowser.Mac,
  FMX.TMSCloudWebBrowser,
  FMX.TMSCloudDropBox,
  FMX.TMSCloudCustomDropBox,

  FMX.Types,
  FMX.Controls,
  FMX.Forms,
  FMX.Graphics,
  FMX.Dialogs,
  FMX.StdCtrls,
  FMX.Platform,
  FMX.Controls.Presentation;

type
  TfDylibTest = class(TForm)
    Button1: TButton;
    Button2: TButton;
    procedure Button1Click(Sender: TObject);
    procedure Button2Click(Sender: TObject);
    procedure FormCreate(Sender: TObject);
    procedure FormCloseQuery(Sender: TObject; var CanClose: Boolean);
    procedure FormClose(Sender: TObject; var Action: TCloseAction);
  private
    { Private declarations }
  public
    { Public declarations }
  end;

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

// Windows DLL
{$IFDEF MSWINDOWS}
const
  TestDLL = 'pTestDLL.dll';

function say_Hello(Hello: PChar; out ReturnString: PChar): boolean; stdcall; external TestDLL Delayed;
procedure free_String(Mem: PChar); stdcall; external TestDLL Delayed;
{$ENDIF}

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

function say_Hello(Hello: PChar; out ReturnString: PChar): boolean; cdecl; external TestDLL name '_say_Hello';
procedure free_String(Mem: PChar); cdecl; external TestDLL name '_free_String';
{$ENDIF}

function local_say_hello(Hello: string): boolean; forward;

var
  fDylibTest: TfDylibTest;

implementation

function local_say_hello(Hello: string): boolean;
begin
  Result := True;
  showmessage(Hello);
end;

{$R *.fmx}
{$R *.Macintosh.fmx MACOS}
{$R *.Windows.fmx MSWINDOWS}

procedure TfDylibTest.Button1Click(Sender: TObject);
var
 b: boolean;
 sType: PChar;
 sDLLString: string;

begin
  try
    try
      b := False;
      sType := nil;

      // Call the DLL Function
      sDLLString := 'The string passed to the ' + {$IFDEF MSWINDOWS}'Windows DLL'{$ELSE}'macOS DYLIB'{$ENDIF};
      b := say_Hello(PChar(sDLLString), sType);

      if b then
        ShowMessage('Returned From: ' + string(sType) + ': TRUE')
      else
        ShowMessage('Return was: FALSE');
    except
      on E: Exception do
      begin
        ShowMessage('Error: ' + E.Message);
      end;
    end;
  finally
    free_String(sType);
  end;

end;

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

begin
  b := False;
  // Call the local Function
  b := local_say_Hello('The string passed to the LOCAL function');

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

procedure TfDylibTest.FormClose(Sender: TObject; var Action: TCloseAction);
begin
  showmessage('[Test App] onClose');
end;

procedure TfDylibTest.FormCloseQuery(Sender: TObject; var CanClose: Boolean);
begin
  canClose := True;
  showmessage('[Test App] onCloseQuery');
end;

procedure TfDylibTest.FormCreate(Sender: TObject);
begin
  showmessage('[Test App] onCreate');
end;

initialization
  showmessage('[Test App] Initialization');

end.

OK Problem #1:   Near as I can tell, and from my testing, if you have FMX.Forms in a DYLIB, the DYLIB just will not load and you application is dead in the water. 

 Of course there is a healthy smattering of FMX.Forms throughout the FMX.TMSCloudxxxx units. 

Symptoms (100% repeatable):
  1. Start application on MAC
  2. Application 'flashes' in taskbar (obviously now the DYLIB is loading)
  3. Application terminates
  4. No error message in PAServer window and no error report
Again, has anyone at TMS actually tried this? 

Is there a workaround other than hunting down every TMS Unit that has FMX.Forms in it and removing it and all the references (very messy I suspect)?

I'd edit my comments rather than reCommenting, but I cannot see a way to do that.


In relation to Problem #1 above....

OK, so in FMX.TMSCkloudbase the ONLY reason that you have FMX.Forms included is so that you can put an Application.Processmessages After an onDownloadProgress and onUploadProgress. 

Apart from the fact that there is a school of thought that believes Application.Processmessages is the root of all evil, is this really necessary? I have commented out same and app builds OK.

So I've looked at what I would need to fix/get rid of FMX.Forms in your code and it doesn't seem practical, it seems to be everywhere.


FMX.Forms is used by FMX.Dialogs, you pop messages all over the place and it is certainly used by your internal browser for signing (which isn't allowed by Dropbox as you point out). But I don't really want to get into an in-depth code-ectomy of your stuff, that's why I bought it so I wouldn't need to do this. 

Other guys in the team are suggesting we just throw the lot and do our own Dropbox manipulation using the V2 API in C++. I'm loathe to do that, I have a lot invested in Delphi and TMS, not just in money, but in many hours of time and effort, and it's a lot of effort to recode. 

But logically if there is no way to (reasonably) get your code working in a cross-platform manner (as it is in Windows) then it's useless.

So really the BIG question is: Can your FMX Cloud Pack code (specifically for Dropbox) work in a macOS DYLIB?

And the minor (although probably crucial) question is:  Can FMX.Forms by used in a DYLIB on macOS (because all of your TMS code uses this unit)?


AND come the full circle. I have run the application on a hard device (not parallels VM) and I now get the error 'Unable to Register Class TFMXApplicationDelegate'.


I've had this before, asked for advice before, got no real answers so the workaround was to remove FMX.Forms which is EXACTLY what I don't want to do because TMS has FMX.Forms scattered throughout the FMX Cloud Pack units.

So again, have you EVER had FMX Cloud Pack (units) running from a DYLIB?


Hi,


Unfortunately the TMS FMX Cloud Pack does not include support to be used in DYLIB.
The product has indeed not been tested in this scenario.
We are currently not aware if there is even support to use any FMX application in this scenario, as like you mentioned using FMX.Forms is already causing issues.
Unfortunately even only researching if it would be possible to use TMS FMX Cloud Pack in a DYLIB could take a significant amount of development time let alone implementing the required changes which could likely be technically challenging.
Please also note that we haven't noticed any demand from other customers for the TMS FMX Cloud Pack in this scenario.


Thanks for responding, I appreciate it. I will post this on the forum also for closure.

The actual error is "Cannot Register Class TFMXApplicationDelegate". This appears when I use a HARD system as the GUEST. When I use a Virtual Machine (Parallels) as the GUEST, I get the Runtime error. So I'm guessing the more accurate error is the one regarding TFMXApplicationDelegate.

WRT to your response:

That is very disappointing. You have not tested your product in a DLL (which kinda seems obvious) and haven?t even considered a DYLIB with a cross platform component suite?

WRT your statement:

We are currently not aware if there is even support to use any FMX application in this scenario, as like you mentioned using FMX.Forms is already causing issues.

​That is simply not true. The fact that FMX.Forms causes issues has does not preclude or negate the ability to create a DYLIB and use it. In fact, it may suggested keeping visual elements (Dialogs, forms etc) out of the DLL/DYLIB might actually ​be good coding practice. And for the record, there are numerous examples within the Embarcadero documentation about creating and using DLLs and DYLIBs. It would seem to me that was fairly fundamental to getting most (slightly sophisticated) applications to work on either platform, ie. you would 'expect' to see DLLs/DYLIBs). I am surprised that there has been no demand.

It is what it is I guess.

Regards,
Kevin

And just to add some support to my previous statements, from one of the developers of INDY:


Cirrus22 Wrote:  It appears than anything with the FMX Forms unit in it blows up the application with the DYLIB with "Could not Register TFMXApplicationDelegate".

That is something that needs to be taken up with Embarcadero. The only issue I see in Quality Portal that is related to TFMXApplicationDelegate is RSP-18580: Firemonkey applications don't terminate normally on macOS.

(10-29-2018, 11:08 PM)Cirrus22 Wrote:  when I queried them about using it in a DYLIB actually told me they doubted that you could use FMS application / DYLIB (actually, I though that was the whole point of FMX, maybe I should just look at some other language)

FMX can consume, and create, dylibs for OSX. Just because the TMS folks didn't test it doesn't mean it can't be done at all.

We need the forms already for the authentication / authorization part, so, that is already the first complexity that is encountered. It is far from trivial as such.  
Bruno Fierens2018-11-01 20:28:18