如何在 Delphi XE2 中将菜单项添加到 Mac OS Finder

Posted

技术标签:

【中文标题】如何在 Delphi XE2 中将菜单项添加到 Mac OS Finder【英文标题】:Howto add menu item to Mac OS Finder in Delphi XE2 【发布时间】:2011-12-22 05:19:57 【问题描述】:

我正在开发针对 Mac OS 和 Windows 的 Delphi XE2 应用程序。我想集成到上下文菜单中。对于 Windows,这是一个简单的任务。但是对于 Mac OS,我不知道该怎么做。

我已阅读 Providing a Service 文档并在 Delphi 中尝试过类似的代码,但没有成功。

查看 Finder 集成试验的简单代码。

应用程序.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 上运行此应用程序时,应用程序会挂起,有时会因“总线错误”异常而崩溃。

有人可以帮忙解决这个问题吗?

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

【问题讨论】:

相关问题假设您使用的是 Cocoa+ObjectiveC,可以调整,使用 DelphiXE2/Firemonkey 调用可可/objectiveC 基于消息的 API 的能力:***.com/questions/9420361/… - 我很想写整个制作服务位使用 Cocoa/ObjectiveC 并找到一种方法,然后从您的 delphi 应用程序中简单地调用本机 ObjectiveC 共享库。 我认为如果可行的话,您会在免费的 pascal 文档或论坛中找到它,因为 XE2 使用 OSX 的免费 pascal。而且由于免费的 pascal 在 OSX 上已经存在很长时间了,我相信它会比 Delphi 论坛拥有更多。 【参考方案1】:

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

首先我尝试使用 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-Delphi 桥接工作所必需的):

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

并从此接口和TOCLocal类继承了TMessageProvider。

在此之后,我的应用可以响应上下文菜单中的服务请求。

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

【讨论】:

【参考方案2】:

我发现了两个潜在的问题

    您正在分配自己的 NSApplication 对象。我怀疑这是正确的——德尔福不是也在内部创建一个吗?即使没有,您也可能需要在某个时候输入NSApplicationrun 方法才能使其真正能够处理消息。

    服务提供者必须在applicationDidFinishLaunching: 委托方法中注册。您尝试在创建 NSApplication 实例后立即注册它。

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

【讨论】:

我对第一个项目也有类似的想法。而且,我记得,我一直在寻找从 TApplication 获取 NSApplication 对象的方法。当我回到那个项目时,我会尝试 NSRegisterServicesProvider 方法。据我了解,应该在 Application.Run 方法之前调用此方法?

以上是关于如何在 Delphi XE2 中将菜单项添加到 Mac OS Finder的主要内容,如果未能解决你的问题,请参考以下文章

如何使用Delphi XE2覆盖WSDL中的服务名称?

如何在代码中将子菜单项添加到 ActionBar 操作?

如何在c ++ win32 API中将图标添加到菜单项[重复]

如何改变delphi xe2编程环境下所显示的源代码的字体大小

Delphi XE2 编译ralease版本,无法添加UAC解决方法

如何在 Android 中将选项菜单添加到 Fragment