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
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 derun
NSApplication
en algún momento para que sea realmente capaz de manejar mensajes.Los proveedores de servicios deben estar registrados en la
applicationDidFinishLaunching:
delegar el método.NSApplication
registrarlo inmediatamente después de crear su instanciaNSApplication
.
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: