December 2, 2019

Run additional programs inside a WorkItem

The main purpose of using Design Automation API's is to run various Autodesk products on the cloud. However, you may have some existing programs that are needed in order to implement a required workflow. Fortunately, it's likely you can run most of those utilities on our servers if they do not require installation or specific resources that might not be available on a VM instance.

In order to run your utility, you can just include it in your AppBundle's zip file and run it from your Activity by adding it to the commandLine which can take multiple lines that will be executed sequentially:

"commandLine": [
  "$(engine.path)\\InventorCoreConsole.exe /al $(appbundles[ObjUpdater].path)",
  "$(appbundles[ObjUpdater].path)\\ObjUpdaterPlugin.bundle\\Contents\\MyUtility.exe input.obj output.obj"
]

One problem I ran into is that the sandboxer on our servers will add an additional command line argument when running the utility. If your utility is fussy about that (e.g. simply exits saying "input parameter not recognized") then you need a workaround. I found two of those:

a) Use a batch file (*.bat)

This is probably the simplest workaround. The only "trick" you need is to get the full path to the utility. Since the *.bat and *.exe files should be next to each other in the AppBundle zip's Contents folder, you can use the batch file's parent folder path: 
https://stackoverflow.com/questions/2730643/how-to-execute-programs-in-the-same-directory-as-the-windows-batch-file

Content of MyUtility.bat:

%~dp0MyUtility.exe input.obj output.obj

Now you can call the *.bat file instead of the *.exe from the commandLine argument of the Activity

"commandLine": [
  "$(engine.path)\\InventorCoreConsole.exe /al $(appbundles[ObjUpdater].path)",
  "$(appbundles[ObjUpdater].path)\\ObjUpdaterPlugin.bundle\\Contents\\MyUtility.bat"
]

b) Run the utility from your AppBundle code

In case of a .NET AppBundle you can simply use the Process object to run your utility from inside your code:

public void Run(Document doc)
{
  LogTrace("Run called");
  string codeBase = Assembly.GetExecutingAssembly().CodeBase;
  UriBuilder uri = new UriBuilder(codeBase);
  string path = Uri.UnescapeDataString(uri.Path);
  string dir = System.IO.Path.GetDirectoryName(path);
  LogTrace("Assembly folder: " + dir);
  string utilityPath = System.IO.Path.Combine(dir, "MyUtility.exe");
  if (System.IO.File.Exists(utilityPath))
  {
    LogTrace(utilityPath + " found");
    ProcessStartInfo psi = new ProcessStartInfo(
      utilityPath,
      "input.obj output.obj"
    );
    psi.RedirectStandardOutput = true;
    psi.UseShellExecute = false;
    Process p = Process.Start(psi);
    LogTrace("Waiting for utility to finish");
    p.WaitForExit();
    LogTrace("Utility finished");
  } 
  else
  {
    LogTrace(utilityPath + " not found");
  }
}

This solution is more than just a workaround for the above mentioned issue, because it also enables you to
- run the same utility multiple times from a loop
- change the command line parameters if needed

In this scenario the commandLine of your Activity needs no direct reference to the utility:

"commandLine": [
  "$(engine.path)\\InventorCoreConsole.exe /al $(appbundles[ObjUpdater].path)"
]

 

 

 

 

 

 

Related Posts