29 votes

Comment ajouter un élément de menu au Finder de Mac OS en Delphi XE2 ?

Je travaille sur une application Delphi XE2 ciblant Mac OS et Windows. Et je veux avoir une intégration dans le menu contextuel. Pour Windows, c'est une tâche simple. Mais pour Mac OS, je ne sais pas comment faire.

J'ai lu Fournir un service et essayé un code similaire dans Delphi, mais sans succès.

Regardez le code simple pour les essais d'intégration du Finder.

App.dpr

program App;
uses
   SysUtils,
{$IFDEF MACOS}
  AppKit, CocoaTypes, CoreFoundation,
  CoreServices, Foundation, Mach, ObjCRuntime,
  ObjectiveC, OCMarshal, OpenGL, QuartzCore, Security,
  SystemConfiguration,
{$ENDIF}
  MessageProvider;
{$IFDEF MACOS}
var
  app: NSApplication;
  provider: TMessageProvider;
{$ENDIF}

begin
  Application.Initialize;

{$IFDEF MACOS}
  provider := TMessageProvider.Create();

  app := TNSApplication.Alloc();
  app.setServicesProvider(provider);
{$ENDIF}

  Application.CreateForm(TFormOSVersion, FormOSVersion);
  Application.Run;
end.

MessageProvider.pas

unit MessageProvider;

interface

uses
  FMX.Dialogs
{$IFDEF MACOS}
  , AppKit, CocoaTypes, CoreFoundation,
  CoreServices, Foundation, Mach, ObjCRuntime,
  ObjectiveC, OCMarshal, OpenGL, QuartzCore, Security,
  SystemConfiguration
{$ENDIF}
  ;

type
  TMessageProvider = class
  public
    procedure simpleMessage(var userData: string; var error: string);
  end;

implementation

procedure TMessageProvider.simpleMessage(var userData: string; var error: string);
begin
  ShowMessage('Simple message from service.');
  error := '';
end;

end.

Ajout de la configuration à info.plist

<key>NSServices</key>
<array>
  <dict>
     <key>NSKeyEquivalent</key>
     <dict>
         <key>default</key>
         <string>e</string>
     </dict>
     <key>NSMenuItem</key>
     <dict>
         <key>default</key>
         <string>App/Message</string>
     </dict>
     <key>NSMessage</key>
     <string>simpleMesage</string>
     <key>NSPortName</key>
     <string>App</string>            
  </dict>
</array>

Lorsqu'elle est exécutée sur Mac OS, l'application se bloque et se ferme parfois avec l'exception "Bus error".

Quelqu'un peut-il m'aider à résoudre ce problème ?

Ou peut-être que Delphi XE2 ne supporte pas ce genre de fonctionnalité ?

1voto

fgp Points 1949

Je vois deux problèmes potentiels

  1. Vous attribuez vos propres NSApplication objet. Je doute que cela soit correct - Delphi n'en crée-t-il pas un en interne également ? Et même si ce n'est pas le cas, vous devrez probablement entrer l'option NSApplication 's run à un moment donné pour qu'il soit réellement capable de traiter les messages.

  2. Les prestataires de services doivent être enregistrés dans le applicationDidFinishLaunching: La méthode du délégué. Vous tentez de l'enregistrer immédiatement après la création de votre NSApplication instance.

Je pense que vous pouvez éviter les deux problèmes si vous utilisez NSRegisterServicesProvider(id provider, NSString *portName) pour enregistrer votre prestation de service, au lieu d'utiliser NSApplication 's setServicesProvider: .

1voto

GothAr Points 221

Enfin, je suis revenu à ce projet et j'ai réussi à enregistrer le fournisseur de services et à traiter la demande de services.

Tout d'abord, j'ai essayé d'utiliser la méthode NSRegisterServicesProvider, mais cette méthode n'existe pas dans les sources Macapi, alors j'ai cherché le délégué applicationDidFinishLaunching. En l'utilisant, j'ai enregistré mon fournisseur de services :

procedure TApplicationDelegate.applicationDidFinishLaunching(Notification: Pointer);
var
  autoReleasePool: NSAutoreleasePool;
  app: NSApplication;
  provider: TMessageProvider;
begin
  autoReleasePool := TNSAutoreleasePool.Create;
  try
    autoReleasePool.init();

    app := TNSApplication.Wrap(TNSApplication.OCClass.sharedApplication);

    provider := TMessageProvider.Create();
    app.setServicesProvider(provider.ObjId);
  finally
    autoReleasePool.release();
  end;
end;

J'ai également créé une interface pour le fournisseur de services (je pense que c'est nécessaire pour que le pont ObjectiveC-Delphi fonctionne) :

IMessageProvider = interface(IObjectiveC)['{1EA9319A-8F99-4445-B435-48D5E73876FA}']
    procedure simpleMessage(pBoard: Pointer; userData: Pointer; error: PPointer); cdecl;
end;

et hérité TMessageProvider de cette interface et de la classe TOCLocal.

Après cela, mon application peut réagir à la demande de service à partir du menu contextuel.

J'ai partagé les sources de mon projet. Aquí ils le sont.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X