macos delphi delphi-xe2 finder
Here

macos - Cómo agregar elementos de menú al Finder de Mac OS en Delphi XE2



delphi-xe2 (2)

Estoy trabajando en la aplicación Delphi XE2 dirigida a Mac OS y Windows. Y quiero tener integración en el menú contextual. Para Windows, esta es una tarea simple. Pero para Mac OS no sé cómo hacer esto.

He leído Proporcionar una documentación de servicio e intenté un código similar en Delphi pero sin suerte.

Mire el código simple para las pruebas de integración de 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.

Configuración agregada a 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>

Cuando se ejecuta esto, la aplicación Mac OS cuelga y algunas veces se bloquea con la excepción ''Error de bus''.

¿Alguien puede ayudar con este problema?

¿O tal vez Delphi XE2 no admite este tipo de funcionalidad?


Finalmente, volví a este proyecto y registré con éxito el proveedor de servicios y tramité la solicitud de servicio.

Antes que nada intenté utilizar el método NSRegisterServicesProvider, pero no existe tal método en las fuentes de Macapi, así que busqué el delegado applicationDidFinishLaunching. Utilizándolo registré mi proveedor de servicios:

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;

También he creado una interfaz para el proveedor de servicios (creo que se requiere para el trabajo en el puente ObjectiveC-Delphi):

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

y heredó TMessageProvider de esta interfaz y la clase TOCLocal.

Después de esto, mi aplicación puede reaccionar a la solicitud de servicio del menú contextual.

He compartido fuentes de mi proyecto. Here están.


Veo dos problemas potenciales

  1. Está asignando su propio objeto NSApplication . Dudo que esto sea correcto. ¿Delphi tampoco crea uno internamente? E incluso si no lo hace, probablemente necesite ingresar el método de run NSApplication en algún momento para que sea realmente capaz de manejar mensajes.

  2. Los proveedores de servicios deben estar registrados en la applicationDidFinishLaunching: delegar el método. NSApplication registrarlo inmediatamente después de crear su instancia NSApplication .

Creo que puede evitar ambos problemas si usa NSRegisterServicesProvider(id provider, NSString *portName) para registrar su servicio, en lugar de utilizar el NSApplication de setServicesProvider: