Find the filename that launched your OS X app

373 Views Asked by At

Setting the info of a file you can associate an app with a particular file type so that when clicked the application is launched. My question is how the app can discover the full filename of the file that caused it to be launched.

1

There are 1 best solutions below

2
On

Mac apps are not launched every time an associated file is opened. They may be launched, but if they're already running, then they're just asked to open another file. So the path doesn't come to the app via the commandline. It's sent as a message to the application, which needs to process a run loop (NSRunLoop) to receive it.

In a regular Cocoa program, you implement an NSApplicationDelegate, and implement the method (in ObjC naming):

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

If you only support 10.13+, the preferred method has changed to:

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

The OS will call this when your application needs to open a file if there's an NSApplication object running to accept it. Typically you create an NSApplication object by calling NSApplicationMain(), but you can implement your own version of NSApplicationMain() if you need to (see the NSApplication docs for details).

It is possible to respond to these open requests without an NSApplication, or any Objective-C, by implementing Apple Events yourself and responding to the odoc (open document; { kCoreEventClass, kAEOpenDocuments }) message. To attack that, see The Apple Events Programming Guide.

You should expect to write some piece of code that installs an event handler like:

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

And then you would actually handle the message in OpenDocumentsAE (taken from "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
}