【问题标题】:Find the filename that launched your OS X app查找启动 OS X 应用程序的文件名
【发布时间】:2019-05-17 03:39:19
【问题描述】:

设置文件信息,您可以将应用程序与特定文件类型相关联,以便在单击时启动应用程序。 我的问题是应用程序如何发现导致它启动的文件的完整文件名。

【问题讨论】:

  • 您使用什么语言工作?这是 Cocoa 应用程序,还是更不寻常的东西?还有,你需要支持哪个版本的macOS?
  • 我在 Mojave 上使用 GNAT Ada,所以我想它是基于 Cocoa 的。
  • 到目前为止,尽管我调用 _NSGetExecutablePath 来获取应用程序的完整文件名,但我几乎没有办法访问 OSX 的特定功能。我希望有一个类似的调用会返回启动文件的名称。

标签: macos launch-services


【解决方案1】:

并非每次打开关联文件时都会启动 Mac 应用程序。它们可能已启动,但如果它们已经在运行,那么它们只会被要求打开另一个文件。所以路径不会通过命令行到达应用程序。它作为消息发送给应用程序,应用程序需要处理一个运行循环(NSRunLoop)来接收它。

在常规的 Cocoa 程序中,您实现一个 NSApplicationDelegate,并实现方法(以 ObjC 命名):

- (BOOL)application:(NSApplication *)sender openFile:(NSString *)filename;

如果你只支持 10.13+,首选方法已更改为:

- (void)application:(NSApplication *)application openURLs:(NSArray<NSURL *> *)urls;

当您的应用程序需要打开一个文件时,如果有一个 NSApplication 对象正在运行以接受它,操作系统将调用它。通常,您通过调用 NSApplicationMain() 创建一个 NSApplication 对象,但如果需要,您可以实现自己的 NSApplicationMain() 版本(有关详细信息,请参阅 NSApplication 文档)。

通过自己实现 Apple 事件并响应 odoc(打开文档;{ kCoreEventClass, kAEOpenDocuments })消息,可以在没有 NSApplication 或任何 Objective-C 的情况下响应这些打开请求。要攻击它,请参阅The Apple Events Programming Guide

您应该期望编写一些安装事件处理程序的代码,例如:

err     = AEInstallEventHandler(kCoreEventClass, kAEOpenDocuments,
            NewAEEventHandlerUPP(OpenDocumentsAE), 0, false);
require_noerr(err, CantInstallAppleEventHandler);

然后您将实际处理OpenDocumentsAE 中的消息(取自“A Handler for the Open Documents Apple Event”):

static pascal OSErr OpenDocumentsAE(const AppleEvent *theAppleEvent, AppleEvent *reply, long handlerRefcon)
{
    AEDescList  docList;
    FSRef       theFSRef;
    long        index;
    long        count = 0;
    OSErr       err = AEGetParamDesc(theAppleEvent,
                            keyDirectObject, typeAEList, &docList);// 1
    require_noerr(err, CantGetDocList);// 2

    err = AECountItems(&docList, &count);// 3
    require_noerr(err, CantGetCount);

    for(index = 1; index <= count; index++)// 4
    {
        err = AEGetNthPtr(&docList, index, typeFSRef,
                        NULL, NULL, &theFSRef, sizeof(FSRef), NULL);// 5
        require_noerr(err, CantGetDocDescPtr);

        err = OpenDocument(&theFSRef);// 6
    }
    AEDisposeDesc(&docList);// 7

CantGetDocList:
CantGetCount:
CantGetDocDescPtr:
    if (err != noErr)// 8
    {
        // For handlers that expect a reply, add error information here.
    }
    return(err);// 9
}

【讨论】:

  • 亲爱的 Rob,感谢您的回复。我的一些应用程序使用 Gtk。我假设为了运行 Gtk 将创建和处理主 NsApplication 循环。如果应用程序是从关联文件启动的,那么我的理解(现在)是应用程序已启动,然后发送了一个需要打开文件的事件。但是这里没有竞争条件吗?如果我创建一个委托来处理该事件,我是否有可能错过该事件?
  • 否;消息将排队,直到它们被应用程序对象使用。当您看到一个应用程序“沙滩球”时,这意味着操作系统已向应用程序发送了至少 500 毫秒未使用的消息。但他们通常仍然在排队。
猜你喜欢
  • 2017-07-29
  • 2011-04-11
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多