Say you want to associate a file type with a Windows application you are writing. Doing so takes two basic steps:
- Adding registration keys to the Windows Registry.
- When the application starts up, having it check to see whether a file name has been passed on the command line, and then take appropriate action when one has – if ParamCount > 0 then …
The first step is a bit tedious, though not difficult once you know what keys to write. Moreover, if an installation program is being used, then the installer should be able do it for you. As for the second step, the level of difficulty depends on whether the program is implemented using an SDI (Single Document Interface) model or not – an ‘SDI’ application being one in which each file the user opens has its own instance of the application.
If SDI is used, then you just need to read off the value of ParamStr(1) at start up and get on with it. If SDI isn’t used though, you will need to employ (a) some sort of mechanism (typically a mutex) to maintain only one running instance of the application and (b) another mechanism (e.g. the Windows messaging system) to notify the existing instance when the user attempts to open another file. If talk of mutexes and Windows messages sounds gibberish to you, it is something I cover in my book – check out the accompanying demo if you just want to see some code.
That said, the main topic of this post and its sequel is associating a file type on OS X, and on the Mac, things are a little different:
- OS X does not have a central registry like Windows that applications (or application installers) explicitly write to. Instead, each GUI program has a ‘plist’ (property list) file, roughly equivalent to a manifest on Windows, that (optionally) includes file type association information. The OS then periodically parses the plist files of applications on the hard drive, saving relevant settings in a private cache.
- A non-SDI approach of some sort is basically compulsory for a Mac GUI application, be it using Mac-style MDI (Multiple Document Interface, like TextEdit) or some for of TDI (Tab Document Interface, like a web browser). Nonetheless, compared to non-SDI scenarios on Windows, on the Mac the system implements for you the two mechanisms I mentioned earlier, of ensuring only a single instance of the application is ever running, and sending an ‘open file’ message to the existing instance when the user tries to open another file.
You may notice that I’ve used the term ‘message’ in both Windows and Mac contexts. Some may object that this elides how ‘messages’ in a Windows API sense and ‘messages’ in an OS X one are fundamentally different things. On one level that objection has merit – in particular, Windows messages involve a straight-C API directly callable by Delphi code, whereas messages on OS X concern method calls against Objective-C objects that aren’t directly controllable by Delphi code. However, the fact the fact the word ‘message’ is used in both worlds is no accident – ‘messages’ in the OS X sense are just a higher level realisation of the ‘messaging’ concept that is also implemented by the Windows API.
That said, at a practical level, OS X routes the ‘open file’ message through the NSApplication object. NSApplication is the Cocoa equivalent to the TApplication class in the VCL or FMX, and just like TApplication, you neither subclass nor explicitly instantiate it – instead, the Cocoa framework creates a singleton instance of NSApplication for you. Because of that, the ‘open file’ message effectively becomes an event of NSApplication, and handling this message means handling an event. Sounds easy!
Unlike Delphi however, events in Cocoa tend to be surfaced not as things any old object can handle, but as potential methods on a dedicated ‘delegate’ object. The practical problem of how to handle the ‘open file’ (or more exactly, application:openFile:) message therefore comes to this: we need to create a delegate object that implements a method for the application:openFile: message. As to how we actually go about doing that however, I’ve save until next time…