2011-11-04 17 views
31

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.Cómo agregar el elemento de menú al Finder de Mac OS en Delphi XE2

He leído Providing a Service documentación y he intentado con 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 Agregado 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 realiza esto en hungs aplicación de Mac OS y, a veces bloquea con ' Error de bus 'excepción.

¿Alguien puede ayudar con este problema?

¿O quizás Delphi XE2 no es compatible con este tipo de funcionalidad?

+3

Pregunta relacionada suponiendo que está utilizando Cocoa + ObjectiveC, podría ser adaptada, utilizando la capacidad de DelphiXE2/Firemonkey para invocar API basadas en mensajes de cacao/objetivoC: http://stackoverflow.com/questions/9420361/add-an-item -in-finders-contextual-menu-with-cocoa - Me sentiría tentado de escribir todo el bit de los servicios de creación usando Cocoa/ObjectiveC y encontrar la manera de invocar esa biblioteca nativa de objetivo C desde su aplicación delphi. –

+0

Creo que si es factible lo encontrará en la documentación o foros pascal gratuitos ya que XE2 usa pascal libre para OSX. Y dado que el pascal libre ha estado mucho tiempo en OSX, estoy seguro de que tendrá más que los foros de Delphi. – adrianj98

Respuesta

1

veo dos problemas potenciales

  1. se están asignando su propio NSApplication objeto. Dudo que esto sea correcto. ¿Delphi tampoco crea uno internamente? Y aunque no sea así, probablemente necesite ingresar el método NSApplicationrun en algún momento para que sea realmente capaz de manejar mensajes.

  2. Los proveedores de servicios deben registrarse en el método delegado applicationDidFinishLaunching:. Intenta registrarlo inmediatamente después de crear su instancia NSApplication.

Creo que se puede evitar ambos problemas si utiliza NSRegisterServicesProvider(id provider, NSString *portName) para registrar su servicio proporciona, en lugar de utilizar NSApplication 's setServicesProvider:.

+0

Tuve pensamientos similares sobre el primer artículo. Y, según recuerdo, estaba buscando alguna forma de obtener el objeto NSApplication de TApplication. Voy a probar el método NSRegisterServicesProvider cuando regrese a ese proyecto. Según tengo entendido, este método se debe llamar justo antes del método Application.Run? – GothAr

2

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

En primer lugar, traté de utilizar el método NSRegisterServicesProvider, pero no existe tal método en las fuentes de Macapi, así que busqué el delegado de applicationDidFinishLaunching. Usarlo Me he registrado 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 la interfaz de proveedor de servicios (creo que se requiere para el trabajo de 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 clase TOCLocal.

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

He compartido fuentes de mi proyecto. Here son ellos.

Cuestiones relacionadas