Under The Microscope

Programmatically Executing Automator Workflows

Understanding The Problem
If you read Apple’s Automator developer documentation, you might notice a curious omission. There is no description of how you can have your own application execute a workflow, like the Finder does.

Devising A Plan
A little poking around in the system reveals that when the Finder runs a workflow, an application called “Automator Launcher” (/System/Library/CoreServices/Automator Launcher.app) is run. With a little help from AEDebug, we can see the Finder is sending an “Open Application” (“oapp”) AppleEvent to Automator Launcher, and specifying some pass-thru parameters. This is basically the MacOS analog of launching a process and supplying arguments via argv.

From the AEDebug dump, we can see what the Finder is passing along to Automator Launcher:

event data:
{ 1 } 'aevt':  - 1 items {
  key 'prdt' - 
	{ 1 } 'reco':  - 4 items {
	  key 'AMcn' - 
		{ 1 } 'long':  4 bytes {  1999 (0x7cf) }
	  key 'AMap' - 
		{ 1 } 'fsrf':  80 bytes {
				000: ff9c c000  0000 4370  0000 0cf5  0000 0000     ......Cp........
				001: 0000 0000  0000 0000  0000 0000  0000 0000     ................
				002: 0000 0000  0000 0000  0000 0000  0000 0000     ................
				003: 0000 0000  0000 0000  0000 0000  0000 0000     ................
				004: 0000 0000  0000 0000  0000 0000  0000 0000     ................
		}
	  key 'AMsm' - 
		{ 1 } 'fsrf':  80 bytes {
				000: ff9c c000  0008 e114  0008 e130  0000 0000     ...........0....
				001: 0000 0000  0000 0000  0000 0000  0000 0000     ................
				002: 0000 0000  0000 0000  0000 0000  0000 0000     ................
				003: 0000 0000  0000 0000  0000 0000  0000 0000     ................
				004: 0000 0000  0000 0000  0000 0000  0000 0000     ................
		}
	  key 'AMfs' - 
		{ 1 } 'list':  - 1 elements {
		  { 1 } 'fsrf':  80 bytes {
				  000: ff9c 8000  000a 46b8  0005 36ad  0000 0000     .....-F...6.....
				  001: 0000 0000  0000 0000  0000 0000  0000 0000     ................
				  002: 0000 0000  0000 0000  0000 0000  0000 0000     ................
				  003: 0000 0000  0000 0000  0000 0000  0000 0000     ................
				  004: 0000 0000  0000 0000  0000 0000  0000 0000     ................
		  }
		}
	}
}

And here are the same parameters, but in the more compact AEBuild-style representation:

{
  'AMsm':'fsrf'($FF9CC0000008E1140008E1300000000000000000000000000000000000000000...$),
  'AMfs':[ 'fsrf'($FF9C8000000A46B8000536AD00000000000000000000000000000000000000...$) ] 
  'AMap':'fsrf'($FF9CC0000000437000000CF50000000000000000000000000000000000000000...$),
  'AMcn':1999,
}

So then the question is, what are these paramters.

The first one is easy, “AMsm” is an FSRef (typeFSRef in AppleEvent-talk) pointing to the Workflow that is to be run.

The second one is also straight-forward, “AMfs” is a list of FSRef’s (AEDescList of typeFSRefs) that point to the files that should be passed to the Workflow.

“AMap”, the third paramter, appears to be an FSRef to the calling application. For example, when the Finder runs a workflow it provides an FSRef to itself. We aren’t quite clear what the point of this paramter is, and experimentation has shown that this parameter isn’t required. Our best guess currently is that it has something to do if Automator Launcher needs to interact with the user.

Finally the last paramter, “AMcn”, is an integer (typeSInt32) whose purpose is a complete mystery to us. In our experimentation we’ve found that passing any value less then 1999 causes Automator Launcher to not run the workflow. Passing bigger values don’t seem to cause any visible differences. It appears to be related to the Finder’s contextual menus, as the first item in the Automator contextual menu will send 1999, the second will send 2000, and so on. Why Automator Launcher would care about any of that however is unclear.

Carrying Out The Plan
With the specification above in hand, the actual code for running a workflow becomes almost trival. You create an AERecord which you then fill with two FSRefs, an AEDescList of FSRefs, and a integer. Then you hand it off to LSOpenURLSpec(), and you’re done.

Our implementation that we use in Audio Hijack Pro is avaliable here. It is just a single class, PTAutomatorWorkflow, which has the following interface:

@interface PTAutomatorWorkflow : NSObject
{
    NSString* mWorkflowPath;
}
+ (BOOL)automatorSupported;
+ (BOOL)isWorkflowFile: (NSString*)path;
+ (NSError*)executeWorkflow: (NSString*)workflowPath withFiles: (NSArray*)filePaths;
- (id)initWithWorkflowFile: (NSString*)workflowPath;
- (NSError*)executeWithFiles: (NSArray*)filePaths;
@end

Looking back
Although Apple doesn’t appear to be offically supporting executing Automator workflows, it’s easy enough to implement on your own anyway. Hopefully if enough developers get on board they will provide an offical API, or at the least document the existing Automator Launcher solution.

Updated (2007-12-02):
New PTAutomatorWorkflow.zip now contains code to use the 10.5 Automator framework API, if it is available.

Comments for this post have been closed. Thanks for reading!


Our Software