Advertisement
Guest User

Untitled

a guest
Oct 21st, 2015
893
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Delphi 9.00 KB | None | 0 0
  1. {
  2.    Модуль содержит обработчик сообщения открытия файла для MAC OS GUI приложедля.
  3.  
  4.    При открытии файла приложением на MAC OS имя файла передается не через
  5.    командную строку, как это делается в Windows, а посылается сообщение application:openFile:
  6.    объектом NSApplication.
  7.  
  8.    Для того что бы обработать данное сообщение, нужно назначить делегат объекту
  9.    NSApplication приложения, в котором и произвести всю работу.
  10.  
  11.    Подробнее https://delphihaven.wordpress.com/2012/08/14/associating-a-file-type-on-osx-part3/
  12.  
  13.    code by: Victor Fedorenkov
  14.    mail: victor.fedorenkov[at]gmail.com
  15. }
  16. unit suNSApplicationOpenFileDelegateUnit.Mac;
  17.  
  18. interface
  19.  
  20. type
  21.   TOpenURLEvent = reference to procedure (const AURL: string);
  22.   TOpenFileEvent = reference to procedure (const AFileName: string);
  23.  
  24. procedure InstallApplicationOpenFileDelegate(AOnOpenFile: TOpenFileEvent;
  25.   AOpenURLEvent: TOpenURLEvent = nil);
  26.  
  27. implementation
  28.  
  29. uses
  30.   System.SysUtils, System.RTLConsts, System.Messaging, System.Classes,
  31.   Macapi.ObjectiveC, Macapi.CoreFoundation, Macapi.CocoaTypes, Macapi.AppKit, Macapi.Foundation, FMX.Forms,
  32.   Macapi.ObjCRuntime,
  33.  
  34.   FMX.Platform, FMX.Platform.Mac, FMX.Helpers.Mac,
  35.  
  36.   suStringUtilsUnit;
  37.  
  38. type
  39.   IFMXApplicationDelegate = interface(NSApplicationDelegate)
  40.    ['{A54E08CA-77CC-4F22-B6D9-833DD6AB696D}']
  41.     procedure onMenuClicked(sender: NSMenuItem); cdecl;
  42.   end;
  43.  
  44.   NSApplicationDelegate2 = interface(IFMXApplicationDelegate)
  45.     ['{BE9AEDB7-80AC-49B1-8921-F226CC9310F4}']
  46.     procedure applicationWillFinishLaunching(Notification: NSNotification); cdecl;
  47.     function application(theApplication: Pointer; openFile: CFStringRef): Boolean; cdecl;
  48.   end;
  49.  
  50.   IURLEventHandler = interface(IObjectiveC)
  51.     ['{29B79998-AB68-4694-93D7-AA09A1BF08F7}']
  52.     procedure Handle(Event, ReplyEvent: NSAppleEventDescriptor); cdecl;
  53.   end;
  54.  
  55.   TURLEventHandler = class(TOCLocal, IURLEventHandler)
  56.     FOpenURLEvent: TOpenURLEvent;
  57.   public
  58.     constructor Create(AOpenURLEvent: TOpenURLEvent);
  59.  
  60.     procedure Handle(Event, ReplyEvent: NSAppleEventDescriptor); cdecl;
  61.   end;
  62.  
  63.   TNSApplicationDelegate2 = class(TOCLocal, NSApplicationDelegate2)
  64.   private
  65.     FOnOpenFile: TOpenFileEvent;
  66.     FURLEventHandler: TURLEventHandler;
  67.   public
  68.     constructor Create(AOnOpenFile: TOpenFileEvent; AOpenURLEvent: TOpenURLEvent = nil);
  69.     destructor Destroy; override;
  70.  
  71.     procedure applicationDidFinishLaunching(Notification: NSNotification); cdecl;
  72.     procedure applicationWillTerminate(Notification: NSNotification); cdecl;
  73.     function applicationShouldTerminate(Notification: NSNotification): NSInteger; cdecl;
  74.     function applicationDockMenu(sender: NSApplication): NSMenu; cdecl;
  75.     procedure onMenuClicked(sender: NSMenuItem); cdecl;
  76.     procedure applicationWillFinishLaunching(Notification: NSNotification); cdecl;
  77.  
  78.     function application(theApplication: Pointer; openFile: CFStringRef): Boolean; cdecl;
  79.   end;
  80.  
  81. var
  82.   Delegate: NSApplicationDelegate2;
  83.  
  84. procedure InstallApplicationOpenFileDelegate(AOnOpenFile: TOpenFileEvent;
  85.   AOpenURLEvent: TOpenURLEvent = nil);
  86. var
  87.   NSApp: NSApplication;
  88.   AutoReleasePool: NSAutoreleasePool;
  89. begin
  90.   AutoReleasePool := TNSAutoreleasePool.Alloc;
  91.   try
  92.     AutoReleasePool.init;
  93.     NSApp := TNSApplication.Wrap(TNSApplication.OCClass.sharedApplication);
  94.     Delegate := TNSApplicationDelegate2.Create(AOnOpenFile, AOpenURLEvent);
  95.     NSApp.setDelegate(NSApplicationDelegate2(Delegate));
  96.   finally
  97.     AutoReleasePool.release;
  98.   end;
  99. end;
  100.  
  101. //Функция скопирована из FMX.Platform.Mac
  102. function SendOSXMessage(const Sender: TObject; const OSXMessageClass: TOSXMessageClass;
  103.   const NSSender: NSObject): NSObject;
  104. var
  105.   MessageObject: TOSXMessageObject;
  106. begin
  107.   if OSXMessageClass = nil then
  108.     raise EArgumentNilException.Create(SArgumentNil);
  109.   MessageObject := TOSXMessageObject.Create(NSSender);
  110.   try
  111.     TMessageManager.DefaultManager.SendMessage(Sender, OSXMessageClass.Create(MessageObject, False), True);
  112.     Result := MessageObject.ReturnValue;
  113.   finally
  114.     MessageObject.Free;
  115.   end;
  116. end;
  117.  
  118. //Проверка, занилена ли глобальная переменная PlatformCocoa из FMX.Platform.Mac
  119. function PlatformCocoaIsNil: Boolean;
  120. begin
  121.  //но так как оно нам недоступно, то проверим по последнему элементу созданному
  122.  //в конструкторе
  123.   Result := (@System.Classes.WakeMainThread = nil);
  124. end;
  125.  
  126. function PlatformCocoaTerminating: Boolean;
  127. begin
  128.   Result := IFMXApplicationService(TPlatformServices.Current.GetPlatformService(IFMXApplicationService)).Terminating;
  129. end;
  130.  
  131. //Эмуляция PlatformCocoa.DefaultAction('Q', [ssCommand])
  132. function PlatformCocoa_DefaultAction_Commad_Q: Boolean;
  133. begin
  134.   //Копия ветки кода из TPlatformCocoa.DefaultAction выполняющаяся при входящих параметрах
  135.   //PlatformCocoa.DefaultAction('Q', [ssCommand])
  136.   Result := False;
  137.   try
  138.     if FMX.Forms.Application.MainForm <> nil then
  139.     begin
  140.       FMX.Forms.Application.MainForm.Close;
  141.         if not PlatformCocoaTerminating then
  142.           Exit;
  143.     end
  144.     else
  145.       begin
  146.         if Screen <> nil then
  147.           Screen.ActiveForm := nil;
  148.         Application.Terminate;
  149.       end;
  150.   except
  151.     HandleException(Application);
  152.   end;
  153.  
  154.   Result := True;
  155. end;
  156.  
  157. { TNSApplicationDelegate2 }
  158.  
  159. constructor TNSApplicationDelegate2.Create(AOnOpenFile: TOpenFileEvent;
  160.   AOpenURLEvent: TOpenURLEvent = nil);
  161. begin
  162.   inherited Create;
  163.  
  164.   FOnOpenFile := AOnOpenFile;
  165.  
  166.   if Assigned(AOpenURLEvent) then
  167.     FURLEventHandler := TURLEventHandler.Create(AOpenURLEvent);
  168. end;
  169.  
  170. destructor TNSApplicationDelegate2.Destroy;
  171. begin
  172.   FreeAndNil(FURLEventHandler);
  173.  
  174.   inherited;
  175. end;
  176.  
  177. procedure TNSApplicationDelegate2.onMenuClicked(sender: NSMenuItem);
  178. begin
  179.   SendOSXMessage(Self, TApplicationMenuClickedMessage, sender);
  180. end;
  181.  
  182. procedure TNSApplicationDelegate2.applicationDidFinishLaunching(
  183.   Notification: NSNotification);
  184. begin
  185.   SendOSXMessage(Self, TApplicationDidFinishLaunchingMessage, Notification);
  186. end;
  187.  
  188. function TNSApplicationDelegate2.applicationShouldTerminate(
  189.   Notification: NSNotification): NSInteger;
  190. begin
  191.   if (FMX.Forms.Application = nil) or PlatformCocoaIsNil or PlatformCocoaTerminating
  192.     or PlatformCocoa_DefaultAction_Commad_Q then
  193.     Result := NSTerminateNow
  194.   else
  195.     Result := NSTerminateCancel;
  196. end;
  197.  
  198. //Перед загрузкой приложения попадаем сюда
  199. procedure TNSApplicationDelegate2.applicationWillFinishLaunching(
  200.   Notification: NSNotification);
  201. const
  202.   kAEGetURL: Integer = Ord('G') shl 24 + Ord('U') shl 16 + Ord('R') shl 8 + Ord('L'); //'GURL'
  203.   kInternetEventClass: Integer = Ord('G') shl 24 + Ord('U') shl 16 + Ord('R') shl 8 + Ord('L'); //'GURL'
  204. var
  205.   selector: SEL;
  206.   sharedAppleEventManager: NSAppleEventManager;
  207. begin
  208.   if Assigned(FURLEventHandler) then
  209.   begin
  210.     sharedAppleEventManager := TNSAppleEventManager.Wrap(
  211.       TNSAppleEventManager.OCClass.sharedAppleEventManager);
  212.  
  213.     selector := sel_registerName(PAnsiChar('Handle:ReplyEvent:'));
  214.     sharedAppleEventManager.setEventHandler(FURLEventHandler.GetObjectID, selector,
  215.       kInternetEventClass, kAEGetURL);
  216.   end;
  217. end;
  218.  
  219. procedure TNSApplicationDelegate2.applicationWillTerminate(
  220.   Notification: NSNotification);
  221. begin
  222.   SendOSXMessage(Self, TApplicationWillTerminateMessage, Notification);
  223.   Halt;
  224. end;
  225.  
  226. function TNSApplicationDelegate2.applicationDockMenu(
  227.   sender: NSApplication): NSMenu;
  228. var
  229.   ReturnValue: NSObject;
  230. begin
  231.   ReturnValue := SendOSXMessage(Self, TApplicationDockMenuMessage, sender);
  232.   if ReturnValue <> nil then
  233.     Result := ReturnValue as NSMenu
  234.   else
  235.     Result := nil;
  236. end;
  237.  
  238. function TNSApplicationDelegate2.application(theApplication: Pointer;
  239.   openFile: CFStringRef): Boolean;
  240. var
  241.   Range: CFRange;
  242.   S: string;
  243. begin
  244.   Result := Assigned(FOnOpenFile);
  245.   if not Result then
  246.     Exit;
  247.  
  248.   Range.location := 0;
  249.   Range.length := CFStringGetLength(openFile);
  250.   SetLength(S, Range.length);
  251.   CFStringGetCharacters(openFile, Range, PChar(S));
  252.   try
  253.     FOnOpenFile(S);
  254.   except
  255.     FMX.Forms.Application.HandleException(ExceptObject);
  256.     Result := False;
  257.   end;
  258. end;
  259.  
  260. { TURLEventHandler }
  261.  
  262. constructor TURLEventHandler.Create(AOpenURLEvent: TOpenURLEvent);
  263. begin
  264.   inherited Create;
  265.  
  266.   FOpenURLEvent := AOpenURLEvent;
  267. end;
  268.  
  269. procedure TURLEventHandler.Handle(Event, ReplyEvent: NSAppleEventDescriptor);
  270. const
  271.   keyDirectObject: Integer = Ord('-') shl 24 + Ord('-') shl 16 + Ord('-') shl 8 + Ord('-'); //'----'
  272. begin
  273.   FOpenURLEvent(NSToString(
  274.     event.paramDescriptorForKeyword(keyDirectObject).stringValue));
  275. end;
  276.  
  277. end.
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement