2011-11-04 77 views
31

我正在开发面向Mac OS和Windows的Delphi XE2应用程序。我想要集成到上下文菜单中。对于Windows来说,这是一件简单的事但对于Mac OS我不知道如何做到这一点。如何将菜单项添加到Delphi XE2中的Mac OS Finder

我读过Providing a Service文档,并在Delphi中尝试了类似的代码,但没有运气。

查看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. 

新增配置的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> 

当在Mac OS上应用hungs运行此有时用“崩溃总线错误“异常。

任何人都可以帮助解决这个问题吗?

或者Delphi XE2不支持这种功能?

+3

相关问题假设您使用Cocoa + ObjectiveC,可以使用DelphiXE2/Firemonkey调用基于cocoa/objectiveC消息的API来调整:http://stackoverflow.com/questions/9420361/add-an-item -in-finders-contextual-menu-with-cocoa - 我会试图用Cocoa/ObjectiveC编写整个制作服务位,然后找到一种方法,然后从你的delphi应用程序简单地调用本地的objectiveC共享库。 –

+0

我认为如果它是可行的,你会在免费的pascal文档或论坛中找到它,因为XE2使用免费的pascal for OSX。由于免费的pascal已经在OSX上很长时间了,我相信它会比Delphi论坛更多。 – adrianj98

回答

1

我看到两个潜在的问题

  1. 您分配自己的NSApplication对象。我怀疑这是否正确 - Delphi不是在内部创建一个?即使不这样做,您可能需要在某些时候输入NSApplicationrun方法以使其实际上能够处理消息。

  2. 服务提供商必须注册applicationDidFinishLaunching:委托方法。尝试在创建NSApplication实例后马上注册它。

我认为你能避免这两个问题,如果您使用NSRegisterServicesProvider(id provider, NSString *portName)注册您的服务提供,而不是使用NSApplicationsetServicesProvider:

+0

我对第一件物品有类似的想法。而且,正如我记得的那样,我正在寻找一些方法来从TApplication获取NSApplication对象。当我返回到该项目时,我会尝试使用NSRegisterServicesProvider方法。据我所知,这个方法应该在Application.Run方法之前调用? – GothAr

2

最后,我回到了这个项目,并成功注册了服务提供者并处理了服务请求。

首先,我尝试使用NSRegisterServicesProvider方法,但在Macapi源代码中没有这样的方法,所以我搜索了applicationDidFinishLaunching委托。使用它,我注册了我的服务提供商:

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; 

而且我已经创建的接口为服务提供商(我认为这是需要的ObjectiveC德尔福工作桥):

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

和继承TMessageProvider从这个接口和TOCLocal类。

之后,我的应用程序可以对来自上下文菜单的服务请求作出反应。

我已经分享了我的项目的来源。他们是Here

相关问题