In spite of pretty mixed weather I went on a climb in the alps with my friend Robert on Saturday, the route Kurze Kombination (4c) on the mountain Schmalstöckli (2012 m) close to the Lidernenen Hütte.
Here I am after the climb, just below the summit:
And this is Robert on the summit itself:
We would made another climb on the same mountain if the weather had not been pretty grey and moist. Anyway, now it is Monday morning, and I am back again to Revit programming.
We mentioned the Revit journal file repeatedly in previous posts, but a basic introduction to this topic was still missing. There is a good reason for this, because Autodesk does not provide any official support for the usage of journal files as a means of automating a portion of the design or production process. The only official support for journal files is as a replay mechanism for testing or reporting issues. One can make use of the journaling mechanism totally at one's own risk, and there will almost certainly be changes, incompatibilities between versions, and other problems.
The testing and reporting mechanism provided by the journaling mechanism is fully accessible to Revit add-ins as well. This access is demonstrated by the Revit SDK Journaling sample. Anyone interested in making use of journaling for any purpose whatsoever should have a good look at this sample in order to understand the mechanism in more depth.
Being unsupported, the journaling mechanism should be used only as a last resort. One example of a preferable approach for some tasks is to prompt the user instead.
Still, with some imagination and due to the lack of automation support for driving Revit from outside or invoking Revit commands such as the IFC export programmatically, it does sometimes offer interesting possibilities.
All the uses mentioned above are related to driving Revit by replaying an existing or an automatically generated journal file. Another way of using the journal file is to read out its contents dynamically during an on-going session to find out what is going on. I mentioned an idea to determine the last Revit command from it, and Greg Wesner discussed getting the journal file path for other monitoring purposes.
Here are some recent questions on this topic, one of which lead to me finally putting together an example and proving to myself that a journal file can be used pretty reliably to drive a completely encapsulated sequence of commands, including Revit start up and shutdown. But first, let us look at a negative result.
Question: Is it possible to play back a Revit journal file while Revit is already running and a document is already opened?
Answer: Sorry, I am not aware of any way to play back a journal file in the middle of a running session, with an opened document. The only way I know of using journal files for programmatic purposes is to include the entire sequence of starting up Revit, opening the document, executing the desired action, and closing down Revit again within the journal file execution. You may possibly omit the closing down part, in which case Revit will be left open, if you are willing to give up control to the user at that point.
Here is the question that led me to test running Revit from a journal file and including steps in it which provide me API access for additional control during the replay process:
Question: Is it possible to use the Revit API to create a new family within the OnStartup method of an external application?
Answer: The argument provided to OnStartup is a ControlledApplication instance. This object provides methods to manipulate the ribbon, access the shared parameters file, access some application level properties and set up application level event handler.
It does not include access to the documents. That access is provided by the Documents collection on the Application class, which is provided as an argument to external commands, which are only active after OnStartup has completed and a document has been opened.
If you wish to start up Revit and immediately create a new family document, you can do so once manually and save the journal file that is generated by this interaction. The journal file can then later be used to restart Revit and re-execute this process.
If you wish to continue working programmatically with the new family document, you can set up an event handler for the DocumentCreated or DocumentOpened notification.
Some notes on external applications and document event handling are provided by the blog entries:
- External application OnStartup implementation in VB.
- External application implementing automatic synchronisation using document save and close events.
- Transactions and document modification in a DocumentOpened event handler.
- Document modification in the DocumentClosing event handler.
- Programmatic handling of dialogue box events.
Following this suggestion to implement an external application reacting to an event to programmatically process a newly created family file created by driving Revit from a journal file led to the following new question:
Question: I have created a journal file that opens a family document on Revit start up. However, it issues an error when calling my external application's OnStartup method saying "The journal file could not be run to completion."
Answer: I cannot reproduce the problem you describe. In my experience, the message that the journal file could not run to completion is due to other problems. I do not believe it is caused by the event handler registration. To test this, I implemented a new external application AutoExecuteOnOpen which does what you say, registering event handlers for the DocumentCreated and DocumentOpened events in the OnStartup method. Both of these simply print a message to the Visual Studio debug output window:
public IExternalApplication.Result OnStartup( ControlledApplication a ) { a.DocumentCreated += new EventHandler<DocumentCreatedEventArgs>( a_DocumentCreated ); a.DocumentOpened += new EventHandler<DocumentOpenedEventArgs>( a_DocumentOpened ); return IExternalApplication.Result.Succeeded; } public IExternalApplication.Result OnShutdown( ControlledApplication a ) { a.DocumentCreated -= new EventHandler<DocumentCreatedEventArgs>( a_DocumentCreated ); a.DocumentOpened -= new EventHandler<DocumentOpenedEventArgs>( a_DocumentOpened ); return IExternalApplication.Result.Succeeded; } void a_DocumentCreated( object sender, DocumentCreatedEventArgs e ) { Debug.Print( "DocumentCreated" ); } void a_DocumentOpened( object sender, DocumentOpenedEventArgs e ) { Debug.Print( "DocumentOpened" ); }
I registered this external application in Revit.ini.
I then ran through the following sequence and saved the resulting journal file:
- Start up Revit.
- Open a family document.
- Close the family document.
- Shut down Revit.
These steps resulted in a new journal file:
C:\Program Files\Autodesk Revit Architecture 2010\Journals\journal.0180.txt
I saved this journal file for replay and had no problem rerunning it. It executes all the following expected steps without problems:
- Start up Revit.
- Load the external application.
- Open a family document.
- Fire the DocumentOpened event.
- Print the message.
- Close the family document.
- Shut down Revit.
In the first attempt at implementing my external application event handlers, I displayed a message box. This did not work, at least not when run from the debugger, because clicking OK in the message box had no effect, so the journal file execution was blocked at that point. Replacing the message box by a simple Debug.Print statement solved that problem. This shows that the entire execution process is very sensitive and picky, though.
Here is a copy of my journal file and here the entire Visual Studio solution AutoExecuteOnOpen
Hi jeremy.
Once again, nice post.
Concerning Repeating Last Command, I can put a result of my research (thx to you). This is a video where you can see that I can repeat the last command (for the moment, only commands wich are in KeyBoardShortCuts. I use F4 to repeat last one.
Works on RAC2009..not yet in 2010
http://www.box.net/shared/t0bdghsxln
Cheers!
Posted by: Pierre NAVARRA | July 13, 2009 at 11:33
Dear Pierre,
Thanks for the appreciation, glad you like it!
Thank you also very much for the info on using the F4 key to repeat the last command.
I looked at your video, it looks impressively efficient.
I am really looking forward to a solution to send keystrokes or shortcut keys to Revit 2010.
Cheers, Jeremy.
Posted by: Jeremy Tammik | July 13, 2009 at 13:31
Hi jereremy,
For helping you, you must know that I had problem with sending KeyStrokes to Revit Handle Application. I used "PostMessage" in USER32.DLL.
Have a nice Day.
Cheers!
Posted by: Pierre NAVARRA | July 14, 2009 at 02:19
Dear Pierre,
Thank you for the info, I saw the sample code on the discussion forum:
http://discussion.autodesk.com/forums/thread.jspa?messageID=6214765
If I ever have any spare time I would love to try it out with 2010.
I wish you a nice day too!
Cheers, Jeremy.
Posted by: Jeremy Tammik | July 14, 2009 at 02:26
HI,
By the way, does the journals directory is the same with Revit2010. Cause, someone test my function in Revit2010 and had en error?
Cheers!
What time is it in the place you live?
Posted by: Pierre NAVARRA | July 14, 2009 at 02:38
Dear Pierre,
As far as I know, the journal file location is the same on all systems.
I live in Switzerland, with Central European Time CET, which is GMT+1.
Cheers, Jeremy.
Posted by: Jeremy Tammik | July 14, 2009 at 03:06
Ok Jeremy, so, my windows error is not in opening myu journal. Anyway, I'll install 2010 environment to debug it.
An other stuff I'd like to tell you, I've noticed, that I've got problem of refreshing your page in FireFox. I've to refresh it 3 ou 4 times before it works..no problem with Ie.
So, you can speach french, don't you?
N'est-ce pas?
Cheers!
Posted by: Pierre NAVARRA | July 14, 2009 at 03:17
Cher Pierre,
Oui, je parle un peu français, mauvaisement. J'utilise aussi le FireFox sans aucun problème.
Cheers, Jeremy.
Posted by: Jeremy Tammik | July 14, 2009 at 03:21
Dear Jeremy,
I am developping an application that should implement the OnDocumentOpened event when Revit starts Up.
It should retreive the links from the opened document and should get some data from inside the links and write these data into the opened document.
however, the OnstartUp takes a "ControlledApplication" as a parameter. I am not able to access the "Documents" from the "controlledApplication" instance.
Is there any way to access the "documents" or the "links" inside the opened document from the "ControlledApplication"?
or is there a way to cast or convert the "ControlledApplication" to an "Application"?
Posted by: Mira Saad | October 20, 2009 at 04:55
Dear Mira,
Basically, this is a very valid question which we have encountered a couple of times already in the past.
No, I am sorry to say that I do not know of any way to access the documents collection from the ControlledApplication instance, nor can you cast it to an Application instance.
Still, I do not quite see why this should be an issue for you?
In the OnStartup method, you can simply register to the DocumentOpened event. When the document is opened, this event is triggered and provides your application with a DocumentOpenedEventArgs instance, which provides the document that you need, doesn't it?
OnStartup is called at a point in time where no documents are yet open, so there are no links to analyse or document to update at that point.
Cheers, Jeremy.
Posted by: Jeremy Tammik | October 20, 2009 at 06:03
Hi Jeremy,
Nice blog. Congratulation.
I'm really new in this field. Is it possible to develop application without start up Revit?
The idea is user just need to key in the name and location of the revit file and the application will read the file to extract the information from revit file and insert into database.
Thanks a lot.
Abidah
Posted by: Abidah | September 17, 2010 at 03:11
Dear Abidah,
Thank you.
Sorry, no, the Revit API is only accessible within a running Revit application, and only within the context of certain call-back methods:
http://thebuildingcoder.typepad.com/blog/2010/04/asynchronous-api-calls-and-idling.html
Cheers, Jeremy.
Posted by: Jeremy Tammik | September 17, 2010 at 03:36
Thanks jeremy.
I read Revit 2011 Developer Guide and trying develop a sample code. Instead of using DocumentOpened I changed to DocumentSavedAs. It crash when I close Revit Software.
Is it any other way to debug why it crash(maybe using messagebox or try-catch)?
Thanks,
Abidah
Posted by: Abidah | September 20, 2010 at 06:16
Dear Abidah,
I use the Visual Studio debugger and set a breakpoint immediately before the problematic code, just as described in section 2.2.6 Debug the Add-in in the developer guide "Revit 2011 API Developer Guide.pdf". That always shows me exactly what is going on and is much more efficient than instrumenting the code with message boxes and stuff. Adding a top-level try-catch handler can also help, of course, but as soon as the exception has been thrown it takes you away from the problematic code location to the exception handler.
Cheers, Jeremy.
Posted by: Jeremy Tammik | September 24, 2010 at 05:25
Jeremy, here you said:
[quote]
The argument provided to OnStartup is a ControlledApplication instance...It does not include access to the documents
[/quote]
Evidently it still does not include this access in Revit 2012. And my question is, why not?
I've spent quite a few hours trying to find a way around this. The journal file replay method is giving me the error one of your readers mentioned above, and I can think of no way to trace the cause. Also opening the file via command line, and triggering my OnDocumentOpened callback doesn't work, because my callback appears to get invoked *before* Revit grabs its floating license from the server (and um... why??) so it is unable to save the work it's done on the .rvt file opened. So I'm resorting to third-party window automation tools.
I'd like to request that your developers reconsider this design decision. As Rod Howarth notes in his project that tries to provide this functionality at https://github.com/RodH257/RevitRemoteBoot, it would be nice if Revit would make this sort of thing easier to do.
(And unfortunately, it looks like Howarth's approach may suffer from the same problem that my own attempt did; the floating license will not be checked out yet when OnDocumentOpened is invoked)
Posted by: Dave | February 17, 2012 at 18:03
Dear Dave,
Are you an ADN member? If so, please submit a case for us to explore this in more detail. Otherwise, please ensure that your API wishes are properly logged, e.g. by AUGI or elsewhere. Thank you!
Cheers, Jeremy.
Posted by: Jeremy Tammik | February 23, 2012 at 06:54