RhinoDoc.EndSaveDocument firing before save?

I’m trying to do something immediately after Rhino documents are saved. I figured that RhinoDoc.EndSaveDocument was the event to subscribe to, but it’s not working. I created a plugin with only this additional code (no commands):

protected override LoadReturnCode OnLoad(ref string errorMessage)
{
    Rhino.RhinoDoc.EndSaveDocument += (s, e) =>
    {
        try { System.IO.File.Copy(e.FileName, "C:/output.3dm", true); }
        catch (System.Exception ex)
        {
            Rhino.RhinoApp.WriteLine(
                "Could not copy file post-saving: {0}", 
                ex.Message);
        }
    };
    return base.OnLoad(ref errorMessage);
}

My expectation was that a copy of any saved Rhino document would appear as C:\output.3dm. Instead, creating a new document, adding a box or something, and then attempting to save as “C:\test.3dm” yields this output:

Command: _Save
Could not copy file post-saving: Could not find file ‘C:\test.3dm’.
File successfully written as C:\test.3dm

And sure enough, C:\test.3dm exists, but C:\output.3dm doesn’t. RhinoDoc.EndSaveDocument isn’t documented, but given the existence of RhinoDoc.BeginSaveDocument, I assumed it did what I wanted. However, it appears to fire before the document is saved, not after. Is there any way to do what I want?

Hi there,

Protected Overrides Function OnLoad(ByRef errorMessage As String) As Rhino.PlugIns.LoadReturnCode
    
AddHandler Rhino.RhinoDoc.EndSaveDocument, AddressOf SaveDocument
    
Return Rhino.PlugIns.LoadReturnCode.Success
    
End Function
    
Private Function SaveDocument(ByVal sender As Object, ByVal e As Rhino.DocumentSaveEventArgs)
    
 'Do what you want to do
 'For this to work first use a command thats in your plugin. Don't know how to load it on rhinoopening
 MsgBox("hi")
    
 Return Nothing
    
End Function

This is it for vb.net.
If you first use one of your own command to addhanddler it will work :slight_smile:

As you can see in my example code, I’m able to subscribe to EndSaveDocument, and it’s firing. The problem is that it’s firing before the document is saved, and I need to do something after the document is saved.

I guess one way around this would be to set up a file watcher in your EndSaveDocument event.

I see, sorry. Missed that one :slight_smile: Thought this was the problem.
Maybe have a background worker?

First when the file is opened have a variable that has current time.
Have another variable that keeps changing and checking if the save time is changed.
Compare these 2 and if they dont agree. Set your action to work.

System.IO.File.GetLastWriteTime(file & location)

I have tried to work around this with a filesystem watcher, and it’s sort of functional, but it definitely doesn’t work when the document save has been triggered by a user as a result of Rhino being closed; at some point, my filesystem watcher handler is going to be interrupted by the fact that the program has been unloaded. Or sometimes it doesn’t, and I have a ghost Rhino process hanging around, and some other cleanup code never gets run. I just don’t see any way of avoiding these unmanageable race conditions (via checking the filesystem directly) without a proper event firing after a document save. Is there any chance that this will get changed in a future RhinoCommon?

Maybe the RhinoApp.Closing event can help you out for the case of save-on-close that you describe above. Hopefully that event gets fired after the file has been saved…

I have to say though, it is not expected behaviour that EndSaveDocument is triggered before the file is written. With you, I hope that it gets changed in the future.

This issue was recently closed on Github (https://github.com/mcneel/rhinocommon/issues/168) as unreproducable by @dale, but it’s still affecting me (x64, SR11, Windows 8), and since he told me to start a thread here to discuss it, I’m just bumping my (super) old one. (I’ve been using the workaround @stevebaer suggested this past year.)

Hi Cody,

Try this:

1.) When you detect a EndSaveDocument event, set a flag indicating such.
2.) When you detect an Idle event - RhinoApp.Idle - check your flag (and check for the file in this case).

Does this help?

Here is a conversation on events that is worth reading.

Ok, using RhinoApp.Idle seems to be doing the trick, but I am still curious about RhinoDoc.EndSaveDocument’s behavior. If it’s not firing before the save is complete, then why doesn’t the file exist on disk during the handler’s execution?

Rhino writes to a temp file and at the very last moment moves that temp file to the actual location.

An update for anyone also trying to use this solution: You need to also check the flag in RhinoApp.Closing, because if a document is closed as part of Rhino closing, Idle will never fire again.