Marc wrote:
Know anybody, how to associate a file type with a FMX/OS X
application? I try to translate the Delphi-Code in C++
[https://delphihaven.wordpress.com/2012/08/14/associating-a-file-type-on-osx-part3/]
but it does not work:
Define "does not work". Is there a compile-time error? A run-time error?
bool __fastcall application(void *theApplication, CFStringRef openFile)
You don't need the b[] array. The original Delphi code was not using such
an array, it was passing the UnicodeString's memory block directly to CFStringGetCharacters(),
eg:
bool __fastcall application(void *theApplication, CFStringRef openFile)
{
if (OnOpenFile == NULL) return false;
UnicodeString S;
CFRange Range;
Range.location = 0;
Range.length = CFStringGetLength(openFile);
S.SetLength(Range.length);
CFStringGetCharacters(openFile, Range, S.c_str());
try {
OnOpenFile(S);
}
catch(...) {return false;}
return true;
}
class TCppClass : public TInterfacedObject
Why do you need two aggregate classes? The original Delphi code only uses
1 class. You are doing a lot more work. Now, I am not an OSX developer,
or even an FMX developer, but it seems to me that you should be able to get
rid of TCppClass and use TCppNSApplicationDelegate by itself as the sharedApplication
delegate.
If nothing else, your initAggregatee() function looks broken to me.
You are creating an TCppNSApplicationDelegate object and assigning it to
the local _di_NSApplicationDelegate2 variable, thus increasing its reference
count to 1. Then you are assigning that _di_NSApplicationDelegate2 to your
NSApplicationDelegate2* member pointer. The reference count is not increased.
When initAggregatee() exits, the _di_NSApplicationDelegate2 variable goes
out of scope, decrementing the reference count to 0, thus freeing the object,
leaving both the TCppNSApplicationDelegate* and NSApplicationDelegate2* members
pointers pointing at invalid memory.
If you fix that so the TCppNSApplicationDelegate object is not freed prematurely,
then you have a new problem. TCppNSApplicationDelegate woud be holding a
reference-counted interface to the TCppObject object, and TCppObject would
be holding a reference-counted interface to the TCppNSApplicationDelegate
object, thus their respective reference counts would never fall to 0 and
both objects would be leaked.
I think you need to get rid of the 2-class approach and do something more
like the following, which is closer to what the original Delphi code was
doing:
#include <Macapi.ObjectiveC.hpp>
#include <Macapi.CoreFoundation.hpp>
#include <Macapi.CocoaTypes.hpp>
#include <Macapi.AppKit.hpp>
#include <FMX.Forms.hpp>
__interface INTERFACE_UUID("{BE9AEDB7-80AC-49B1-8921-F226CC9310F4}")
NSApplicationDelegate2 : public NSApplicationDelegate
{
virtual bool __fastcall application(void *theApplication, CFStringRef
openFile) = 0;
};
typedef System::DelphiInterface<NSApplicationDelegate2> _di_NSApplicationDelegate2;
typedef void __fastcall (__closure *TOpenFileEvent) (const String FileName);
class TNSApplicationDelegate2 : public TOCLocal, public NSApplicationDelegate2
{
private:
TOpenFileEvent FOnOpenFile;
public:
__fastcall TNSApplicationDelegate2(const TOpenFileEvent AOnOpenFile)
: TOCLocal(), FOnOpenFile(AOnOpenFile)
{
}
void __cdecl applicationDidFinishLaunching(void *Notification);
{
/* The default FMX delegate doesn't do anything here, so nor will we.
*/
}
void _cdecl applicationWillTerminate(void *Notification)
{
delete Fmx::Forms::Application;
Fmx::Forms::Application = NULL;
}
bool __cdecl application(void *theApplication, CFStringRef openFile)
{
if (!FOnOpenFile) return false;
CFRange Range;
Range.location = 0;
Range.length = CFStringGetLength(openFile);
String S;
S.SetLength(Range.length);
CFStringGetCharacters(openFile, Range, S.c_str());
try
{
FOnOpenFile(S);
}
catch (const Exception &e)
{
Fmx::Forms::Application->HandleException(&e);
return false;
}
return true;
}
};
_di_NSApplicationDelegate2 Delegate;
void InstallApplicationDelegate2(const TOpenFileEvent AOnOpenFile)
{
NSApplication *NSApp = TNSApplication::Wrap(TNSApplication::OCClass->sharedApplication());
Delegate = (NSApplicationDelegate2*) new TNSApplicationDelegate2(AOnOpenFile);
NSApp->setDelegate(Delegate);
}
__fastcall TForm1::TForm1(TComponent* Owner)
: TForm(Owner)
{
InstallApplicationDelegate(&OnOpenFile);
}
void __fastcall TForm1::OnOpenFile(const String FileName)
{
// Do something with the File...
}
--
Remy Lebeau (TeamB)
Connect with Us