[GIS] Handling ArcMap closing event in AddIn to save edits automatically

arcmaparcobjectsceditingevents

I'm trying to handle the closing event of ArcMap (10.0 SP5) within an ESRI Addin Extension using C# and Arcobjects. Furthermore I would like to handle 'a closing event', that is fired BEFORE ArcMap tries to stop a started edit session. As background: I want to create an extension that does the database handling automatically without asking the user if he wants to save the changes in the database when closing ArcMap (this should happen programmatically).

At first I tried to handle the ESRI.ArcGIS.ArcMapUI.IDocumentEvents.BeforeCloseDocument, but this event will be fired AFTER ArcMap tries to stop an active edit session. The situation is not different with the ESRI.ArcGIS.Editor.IEditEvents2_Event.BeforeStopEditingevent. In both cases the user is asked if he wants to save the changes before one can handle the event. And at last I tried the ESRI.ArcGIS.Desktop.AddIns.Extension.OnShutdown event, but this is fired much more later after the user is asked for saving the changes in the Geodatabase and saving the MXD. Now I am at my wit’s end.

Does anyone else has an idea or a workaround? Have I missed another event? Is it possible to ‘cast’ the ArcMap application window to System.Windows.Forms.Form to wire the FormClosing event?

Best Answer

Try hooking IApplication.hWnd in OnStartup() and catching WM_CLOSE. This will fire before you are prompted to save edits. It will also fire regardless of whether the user selected "File - Exit" or the "X" in the top-right corner of the window.

Calling StopEditing(true) in WM_CLOSE does save the edits; however, the user may (will) still be prompted to save edits. You should also call StartEditing(ws) in case the user Cancels the ArcMap Close.

Note: Other extensions/addins may not be happy w/ this e.g. I tested (Save Design) w/ ArcFM Designer and it resulted in all design toolbar buttons being disabled; which is unacceptable if the user Cancels the Close. More fiddling w/ the code may be able to work around this.

e.g.

public class ArcAppWnd : global::System.Windows.Forms.NativeWindow
{
    public const int WM_CLOSE = 0x10;
    protected IntPtr hWnd;

    public ArcAppWnd( int HWND ) : base() 
    {
        hWnd = new IntPtr(HWND);
        AssignHandle(hWnd);
    }

    protected override void WndProc( ref Message MSG )
    {
        switch( MSG.Msg ) {
            case WM_CLOSE:
                if( App.Editor.HasEdits() ) {
                    var ws = App.Editor.EditWorkspace as IWorkspaceEdit;
                    ws.StopEditing(true);
                    ws.StartEditing(true);
                }
                break;
        }
        base.WndProc(ref MSG);
    }
}

and in the extension ...

ArcAppWnd appWnd;

public void Startup( ref object INITIALIZATIONDATA ) {
    ...
    var app = INITIALIZATIONDATA as IAppication;
    appWnd = new ArcAppWnd(app.hWnd);
    ...
}

(Replace App.Editor w/ whatever you use to get/track IEditor)