{"id":205,"date":"2009-01-12T16:24:34","date_gmt":"2009-01-12T21:24:34","guid":{"rendered":"http:\/\/vgable.com\/blog\/2009\/01\/12\/stopping-an-amworkflow-workaround\/"},"modified":"2009-01-12T16:24:36","modified_gmt":"2009-01-12T21:24:36","slug":"stopping-an-amworkflow-workaround","status":"publish","type":"post","link":"https:\/\/vgable.com\/blog\/2009\/01\/12\/stopping-an-amworkflow-workaround\/","title":{"rendered":"Stopping an AMWorkflow Workaround"},"content":{"rendered":"<p><strong><code> -[AMWorkflowController stop:]<\/code> does <em>not<\/em> stop a workflow from executing<\/strong> (<a href=\"http:\/\/vgable.com\/blog\/2008\/12\/18\/automator-bugs\/\">more info<\/a>).  Here is <strong>a workaround that will stop <em>all<\/em> workflows your application is be running.<\/strong><\/p>\n<p>When you execute a worklfow using Automator.framework, the workflow is run in its own process, which insulates it from the invoking application, and vica verca <sup><a href=\"#AutomatorAppFootnote1\">1<\/a><\/sup><\/p><\/blockquote>\n<p>.  At least on Leopard, the program that runs the workflow is <code>\/System\/Library\/CoreServices\/Automator Runner.app\/Contents\/MacOS\/Automator Runner<\/code> . It has the bundle-identifier <code>com.apple.AutomatorRunner<\/code> , and it will be a sub-process of your application, since your application kicked it off.<\/p>\n<p>That gives us enough information to kill just the instances of <code>Automator Runner<\/code> that are running your worklfows.  This will stop workflow execution dead in it&#8217;s tracks.<\/p>\n<p><code><br \/>\n- (void) killAutomatorRunnerSubprocesses; {<br \/>\n&nbsp;&nbsp;&nbsp;ProcessSerialNumber&nbsp;&nbsp;&nbsp;PSN = {kNoProcess};<br \/>\n&nbsp;&nbsp;&nbsp;while(GetNextProcess(&PSN) == noErr) {<br \/>\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;NSDictionary *info = (NSDictionary*)ProcessInformationCopyDictionary(&PSN,kProcessDictionaryIncludeAllInformationMask);<br \/>\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if(info) {<br \/>\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;NSString *theirBundleID = [info objectForKey:@\"CFBundleIdentifier\"];<br \/>\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if([theirBundleID isEqualTo:@\"com.apple.AutomatorRunner\"] && [self processWasLaunchedByUs:PSN]){<br \/>\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;NSLog(@\"Killing AutomatorRunner sub-process: PSN={high=%u low=%u}\", PSN.highLongOfPSN, PSN.lowLongOfPSN);<br \/>\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;KillProcess(&PSN);<br \/>\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br \/>\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;CFRelease((CFDictionaryRef)info);<br \/>\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br \/>\n&nbsp;&nbsp;&nbsp;}<br \/>\n}<\/p>\n<p>- (BOOL) processWasLaunchedByUs:(ProcessSerialNumber)PSN; {<br \/>\n&nbsp;&nbsp;&nbsp;ProcessInfoRec processInfo = {0};<br \/>\n&nbsp;&nbsp;&nbsp;\/\/we use GetProcessInformation(), and not the more modern ProcessInformationCopyDictionary()<br \/>\n&nbsp;&nbsp;&nbsp;\/\/because ProcessInformationCopyDictionary stores the \"ParentPSN\" as a 32 or 64-bit number,<br \/>\n&nbsp;&nbsp;&nbsp;\/\/and it is not clear to me what the endian-safe way to transform it into a ProcessSerialNumber<br \/>\n&nbsp;&nbsp;&nbsp;\/\/structure is, see http:\/\/lists.apple.com\/archives\/carbon-dev\/2007\/Mar\/msg00283.html<br \/>\n&nbsp;&nbsp;&nbsp;if(GetProcessInformation(&PSN,&processInfo) != noErr)<br \/>\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return NO;<br \/>\n&nbsp;&nbsp;&nbsp;Boolean&nbsp;&nbsp;&nbsp;theyAreOurChild = FALSE;<br \/>\n&nbsp;&nbsp;&nbsp;ProcessSerialNumber ourPSN  = {0,kCurrentProcess};<br \/>\n&nbsp;&nbsp;&nbsp;OSStatus err = SameProcess(&processInfo.processLauncher, &ourPSN, &theyAreOurChild);<br \/>\n&nbsp;&nbsp;&nbsp;return !err && theyAreOurChild;<br \/>\n}<br \/>\n&nbsp;&nbsp;&nbsp;<br \/>\n<\/code><\/p>\n<p>Please let me know if this works for you, of if you have a better solution.<\/p>\n<hr>\n<p><a name=\"#AutomatorAppFootnote1\"><sup>1<\/sup><\/a><small><br \/>\nAutomator.app does <em>not<\/em> appear to spawn an <code>Automator Runner<\/code> when it runs a workflow.  I&#8217;m not sure why. But since the stop button works in Automator.app, understanding why might lead to a better work around.  Or not.<\/small><\/p>\n","protected":false},"excerpt":{"rendered":"<p>-[AMWorkflowController stop:] does not stop a workflow from executing (more info). Here is a workaround that will stop all workflows your application is be running. When you execute a worklfow using Automator.framework, the workflow is run in its own process, which insulates it from the invoking application, and vica verca 1 . At least on [&hellip;]<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[6,3,5,4,13],"tags":[257,258,73,299],"class_list":["post-205","post","type-post","status-publish","format-standard","hentry","category-cocoa","category-macosx","category-objective-c","category-programming","category-sample-code","tag-amworkflow","tag-amworkflowcontroller","tag-automator","tag-process-manager"],"_links":{"self":[{"href":"https:\/\/vgable.com\/blog\/wp-json\/wp\/v2\/posts\/205","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/vgable.com\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/vgable.com\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/vgable.com\/blog\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/vgable.com\/blog\/wp-json\/wp\/v2\/comments?post=205"}],"version-history":[{"count":0,"href":"https:\/\/vgable.com\/blog\/wp-json\/wp\/v2\/posts\/205\/revisions"}],"wp:attachment":[{"href":"https:\/\/vgable.com\/blog\/wp-json\/wp\/v2\/media?parent=205"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/vgable.com\/blog\/wp-json\/wp\/v2\/categories?post=205"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/vgable.com\/blog\/wp-json\/wp\/v2\/tags?post=205"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}