Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- {
- Модуль содержит обработчик сообщения открытия файла для MAC OS GUI приложедля.
- При открытии файла приложением на MAC OS имя файла передается не через
- командную строку, как это делается в Windows, а посылается сообщение application:openFile:
- объектом NSApplication.
- Для того что бы обработать данное сообщение, нужно назначить делегат объекту
- NSApplication приложения, в котором и произвести всю работу.
- Подробнее https://delphihaven.wordpress.com/2012/08/14/associating-a-file-type-on-osx-part3/
- code by: Victor Fedorenkov
- mail: victor.fedorenkov[at]gmail.com
- }
- unit suNSApplicationOpenFileDelegateUnit.Mac;
- interface
- type
- TOpenURLEvent = reference to procedure (const AURL: string);
- TOpenFileEvent = reference to procedure (const AFileName: string);
- procedure InstallApplicationOpenFileDelegate(AOnOpenFile: TOpenFileEvent;
- AOpenURLEvent: TOpenURLEvent = nil);
- implementation
- uses
- System.SysUtils, System.RTLConsts, System.Messaging, System.Classes,
- Macapi.ObjectiveC, Macapi.CoreFoundation, Macapi.CocoaTypes, Macapi.AppKit, Macapi.Foundation, FMX.Forms,
- Macapi.ObjCRuntime,
- FMX.Platform, FMX.Platform.Mac, FMX.Helpers.Mac,
- suStringUtilsUnit;
- type
- IFMXApplicationDelegate = interface(NSApplicationDelegate)
- ['{A54E08CA-77CC-4F22-B6D9-833DD6AB696D}']
- procedure onMenuClicked(sender: NSMenuItem); cdecl;
- end;
- NSApplicationDelegate2 = interface(IFMXApplicationDelegate)
- ['{BE9AEDB7-80AC-49B1-8921-F226CC9310F4}']
- procedure applicationWillFinishLaunching(Notification: NSNotification); cdecl;
- function application(theApplication: Pointer; openFile: CFStringRef): Boolean; cdecl;
- end;
- IURLEventHandler = interface(IObjectiveC)
- ['{29B79998-AB68-4694-93D7-AA09A1BF08F7}']
- procedure Handle(Event, ReplyEvent: NSAppleEventDescriptor); cdecl;
- end;
- TURLEventHandler = class(TOCLocal, IURLEventHandler)
- FOpenURLEvent: TOpenURLEvent;
- public
- constructor Create(AOpenURLEvent: TOpenURLEvent);
- procedure Handle(Event, ReplyEvent: NSAppleEventDescriptor); cdecl;
- end;
- TNSApplicationDelegate2 = class(TOCLocal, NSApplicationDelegate2)
- private
- FOnOpenFile: TOpenFileEvent;
- FURLEventHandler: TURLEventHandler;
- public
- constructor Create(AOnOpenFile: TOpenFileEvent; AOpenURLEvent: TOpenURLEvent = nil);
- destructor Destroy; override;
- procedure applicationDidFinishLaunching(Notification: NSNotification); cdecl;
- procedure applicationWillTerminate(Notification: NSNotification); cdecl;
- function applicationShouldTerminate(Notification: NSNotification): NSInteger; cdecl;
- function applicationDockMenu(sender: NSApplication): NSMenu; cdecl;
- procedure onMenuClicked(sender: NSMenuItem); cdecl;
- procedure applicationWillFinishLaunching(Notification: NSNotification); cdecl;
- function application(theApplication: Pointer; openFile: CFStringRef): Boolean; cdecl;
- end;
- var
- Delegate: NSApplicationDelegate2;
- procedure InstallApplicationOpenFileDelegate(AOnOpenFile: TOpenFileEvent;
- AOpenURLEvent: TOpenURLEvent = nil);
- var
- NSApp: NSApplication;
- AutoReleasePool: NSAutoreleasePool;
- begin
- AutoReleasePool := TNSAutoreleasePool.Alloc;
- try
- AutoReleasePool.init;
- NSApp := TNSApplication.Wrap(TNSApplication.OCClass.sharedApplication);
- Delegate := TNSApplicationDelegate2.Create(AOnOpenFile, AOpenURLEvent);
- NSApp.setDelegate(NSApplicationDelegate2(Delegate));
- finally
- AutoReleasePool.release;
- end;
- end;
- //Функция скопирована из FMX.Platform.Mac
- function SendOSXMessage(const Sender: TObject; const OSXMessageClass: TOSXMessageClass;
- const NSSender: NSObject): NSObject;
- var
- MessageObject: TOSXMessageObject;
- begin
- if OSXMessageClass = nil then
- raise EArgumentNilException.Create(SArgumentNil);
- MessageObject := TOSXMessageObject.Create(NSSender);
- try
- TMessageManager.DefaultManager.SendMessage(Sender, OSXMessageClass.Create(MessageObject, False), True);
- Result := MessageObject.ReturnValue;
- finally
- MessageObject.Free;
- end;
- end;
- //Проверка, занилена ли глобальная переменная PlatformCocoa из FMX.Platform.Mac
- function PlatformCocoaIsNil: Boolean;
- begin
- //но так как оно нам недоступно, то проверим по последнему элементу созданному
- //в конструкторе
- Result := (@System.Classes.WakeMainThread = nil);
- end;
- function PlatformCocoaTerminating: Boolean;
- begin
- Result := IFMXApplicationService(TPlatformServices.Current.GetPlatformService(IFMXApplicationService)).Terminating;
- end;
- //Эмуляция PlatformCocoa.DefaultAction('Q', [ssCommand])
- function PlatformCocoa_DefaultAction_Commad_Q: Boolean;
- begin
- //Копия ветки кода из TPlatformCocoa.DefaultAction выполняющаяся при входящих параметрах
- //PlatformCocoa.DefaultAction('Q', [ssCommand])
- Result := False;
- try
- if FMX.Forms.Application.MainForm <> nil then
- begin
- FMX.Forms.Application.MainForm.Close;
- if not PlatformCocoaTerminating then
- Exit;
- end
- else
- begin
- if Screen <> nil then
- Screen.ActiveForm := nil;
- Application.Terminate;
- end;
- except
- HandleException(Application);
- end;
- Result := True;
- end;
- { TNSApplicationDelegate2 }
- constructor TNSApplicationDelegate2.Create(AOnOpenFile: TOpenFileEvent;
- AOpenURLEvent: TOpenURLEvent = nil);
- begin
- inherited Create;
- FOnOpenFile := AOnOpenFile;
- if Assigned(AOpenURLEvent) then
- FURLEventHandler := TURLEventHandler.Create(AOpenURLEvent);
- end;
- destructor TNSApplicationDelegate2.Destroy;
- begin
- FreeAndNil(FURLEventHandler);
- inherited;
- end;
- procedure TNSApplicationDelegate2.onMenuClicked(sender: NSMenuItem);
- begin
- SendOSXMessage(Self, TApplicationMenuClickedMessage, sender);
- end;
- procedure TNSApplicationDelegate2.applicationDidFinishLaunching(
- Notification: NSNotification);
- begin
- SendOSXMessage(Self, TApplicationDidFinishLaunchingMessage, Notification);
- end;
- function TNSApplicationDelegate2.applicationShouldTerminate(
- Notification: NSNotification): NSInteger;
- begin
- if (FMX.Forms.Application = nil) or PlatformCocoaIsNil or PlatformCocoaTerminating
- or PlatformCocoa_DefaultAction_Commad_Q then
- Result := NSTerminateNow
- else
- Result := NSTerminateCancel;
- end;
- //Перед загрузкой приложения попадаем сюда
- procedure TNSApplicationDelegate2.applicationWillFinishLaunching(
- Notification: NSNotification);
- const
- kAEGetURL: Integer = Ord('G') shl 24 + Ord('U') shl 16 + Ord('R') shl 8 + Ord('L'); //'GURL'
- kInternetEventClass: Integer = Ord('G') shl 24 + Ord('U') shl 16 + Ord('R') shl 8 + Ord('L'); //'GURL'
- var
- selector: SEL;
- sharedAppleEventManager: NSAppleEventManager;
- begin
- if Assigned(FURLEventHandler) then
- begin
- sharedAppleEventManager := TNSAppleEventManager.Wrap(
- TNSAppleEventManager.OCClass.sharedAppleEventManager);
- selector := sel_registerName(PAnsiChar('Handle:ReplyEvent:'));
- sharedAppleEventManager.setEventHandler(FURLEventHandler.GetObjectID, selector,
- kInternetEventClass, kAEGetURL);
- end;
- end;
- procedure TNSApplicationDelegate2.applicationWillTerminate(
- Notification: NSNotification);
- begin
- SendOSXMessage(Self, TApplicationWillTerminateMessage, Notification);
- Halt;
- end;
- function TNSApplicationDelegate2.applicationDockMenu(
- sender: NSApplication): NSMenu;
- var
- ReturnValue: NSObject;
- begin
- ReturnValue := SendOSXMessage(Self, TApplicationDockMenuMessage, sender);
- if ReturnValue <> nil then
- Result := ReturnValue as NSMenu
- else
- Result := nil;
- end;
- function TNSApplicationDelegate2.application(theApplication: Pointer;
- openFile: CFStringRef): Boolean;
- var
- Range: CFRange;
- S: string;
- begin
- Result := Assigned(FOnOpenFile);
- if not Result then
- Exit;
- Range.location := 0;
- Range.length := CFStringGetLength(openFile);
- SetLength(S, Range.length);
- CFStringGetCharacters(openFile, Range, PChar(S));
- try
- FOnOpenFile(S);
- except
- FMX.Forms.Application.HandleException(ExceptObject);
- Result := False;
- end;
- end;
- { TURLEventHandler }
- constructor TURLEventHandler.Create(AOpenURLEvent: TOpenURLEvent);
- begin
- inherited Create;
- FOpenURLEvent := AOpenURLEvent;
- end;
- procedure TURLEventHandler.Handle(Event, ReplyEvent: NSAppleEventDescriptor);
- const
- keyDirectObject: Integer = Ord('-') shl 24 + Ord('-') shl 16 + Ord('-') shl 8 + Ord('-'); //'----'
- begin
- FOpenURLEvent(NSToString(
- event.paramDescriptorForKeyword(keyDirectObject).stringValue));
- end;
- end.
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement