Auto-Executing an External Command

I had an extensive discussion on automatically driving Revit from outside to auto-execute a simple functionality with no user input, originally implemented by an external command.

Also, a big thank you to all for the numerous congratulations on The Building Coder's eleventh birthday:

Autorun an External Command

Question: I have an external command that I would prefer to execute automatically to avoid the need to manually start up Revit, open the RVT model, and launch the command. How can this be achieved?

Answer: Easy to solve, various approaches possible.

I would suggest starting out by trying to use a journal file as described for the IFC import and conversion script.

Another simple approach is to implement an event handler for the DocumentOpened event and automatically process the document immediately as soon as it is opened.

Can you provide a short description of the top-level user interaction, the top-level Revit add-in API architecture, and the top-level RVT model context of the functionality you wish to run?

Response: Currently, we just open the model and click our export button.

That launches the code, running on that specific model along with all the links, and writing everything to some external SQLite and JSON files. No user interaction is required besides opening the model and clicking the button.

It is fully synchronized (not async), so it blocks the GUI until it finishes.

The interface we implement for Revit looks like this:

  [Transaction(TransactionMode.ReadOnly)]
  class Main: IExternalCommand
  {
    public Result Execute(
      ExternalCommandData commandData,
      ref string message,
      ElementSet elements)
    {
      using (Document doc
        = commandData.Application.ActiveUIDocument.Document)
      {
        using (RevitExport exporter = new RevitExport(doc))
        {
          Stopwatch st = Stopwatch.StartNew();
          exporter.ExportEverything();
          Debug.Print($"Elapsed time: {st.Elapsed.TotalSeconds} seconds");
        }
      }
    }
  }

Answer: That sounds good. This can indeed easily be converted to autorun. The easiest solution might be to use the manual user interface and the Revit journal file functionality like this:

Now you have completed the system setup.

You can process a new model Y.rvt by executing the following:

copy Y.rvt input.rvt
"C:\Program Files\Autodesk\Revit 2020\Revit.exe" "C:\Users\...\Journals\process_input.txt"

These two lines can be placed into a Windows batch or command file, and the original input filename specified as an argument.

Besides the IFC conversion example mentioned above, here is another article on various aspects of journal file replay.

You should add some logging output to your external command, so that you have reliable information on whether the processing completed successfully.

The advantage of this approach is its simplicity.

The disadvantage is that you start up and close down Revit for each file processed.

However, since you can drive this automatically for any number of times, this is probably no problem if you have a couple of dozen files to process. If you have thousands, a more efficient approach would be needed.

More efficient approaches can easily be implemented inside your add-in code. For instance, you can implement another external command that processes multiple files by reading a text file listing the files to process. It can open them one by one programmatically and launch your process on each by calling a method taking a Document input argument. To prepare for this approach, rewrite your Execute method to extract the document from the command data, and pass that into a Process method taking the Document argument. With these two external commands in place, you have the choice of processing either one single file, the current open document, or an entire list of files, with one single click.

Since Revit is not built for processing hundreds of files in batch mode, processing will fail sooner or later when working on a large number of files. Therefore, logging your progress is important. If you want the process to be fully automatic, you can implement additional functionality to check that it is still working, kill Revit if it has stopped, and restart again to continue processing whatever remains to be done. This kind of approach is documented in several articles on batch processing:

Response: Sounds good, I'll go ahead with this. A few more questions:

Answer: Good questions.

The journal file is totally stupid. It will exactly reproduce what you did manually when it was recorded.

If something goes wrong, it will behave exactly as if you were sitting there manually typing and clicking in the user interface.

Therefore, the safest (and only possible) approach is to ensure that nothing does go wrong.

If anything fails to load, the process will fail.

Therefore the need to log each successful processing and check afterwards that everything worked as expected.

To answer your specific questions:

You can add such a check to your Process method and terminate gracefully if something is missing. Add the check to the external command first, ensure that it works and does something sensible in manual mode.

The warning message can be eliminated completely by digitally signing the DLL. This issue is discussed extensively in the forum thread on code signing of Revit add-ins. The solution is documented in the Revit online help section on digitally signing your Revit add-in.

Alternatively, every time the DLL is modified, load it manually once and click 'Always load'. From then on, the message will not appear again, as long as the DLL is not modified.

Thank you for your Eleventh Birthday Congratulations

Thank you very much for the lively response and numerous congratulations on The Building Coder's eleventh birthday!

Over a hundred LinkedIn reactions and over 4500 views there, over eighteen hundred Twitter impressions, almost a hundred Twitter 'engagements', and more, via other channels:

Matt Taylor in a comment:

Happy birthday TBC!

Adam Sheather on Twitter:

Congrats mate! You are still my go-to site for Revit API problems, and the wealth of knowledge and time you put into the blog has provided unimaginable benefit for the community! Thank you!

Amedeo Papi on LinkedIn:

Thank you, Jeremy Tammik, for everything you do for the #Autodesk users interested in development and programming!

Philippe Leefsma on LinkedIn:

It will remain useful to Revit developers across the entire galaxy for centuries   ;)

Thank you ever so much for all the good wishes!

Twitter engagements

LinkedIn Update 2019-08-28

156 LinkedIn reactions and 7 Comments: