000

Index Labels

About Terminate() Method of IExtensionApplication

.
IExtensionApplication interface allows chances for AutoCAD .NET developers to do some initializing task when their custom AutoCAD .NET assemblies are loaded and do some necessary clean-up tasks when AutoCAD is terminating.

In this post, I use some code to show what happen when AutoCAD is closed by user (via clicking "Exit" menu, click "x" on AutoCAD main window, or issue command "quit").

In order to track what happen during the AutoCAD closing process, various event handlers are attached to drawings that were open when AutoCAD starts closing, drawing databases and AutoCAD application itself. Because AutoCAD is closing, AutoCAD test window cannot be used to show message regarding the closing process, I created a TextLogger class that holds all closing messages captured in various event handlers and save them to a text file at the end of Terminate() call.

Here is the code of class TextLogger:

Code Snippet
  1. using System.Text;
  2. using System.IO;
  3.  
  4. namespace IExtensionApp.Terminate
  5. {
  6.     public class TextLogger
  7.     {
  8.         private StringBuilder _textToWrite;
  9.         private string _logFile;
  10.  
  11.         public TextLogger(string fileName)
  12.         {
  13.             _logFile = fileName;
  14.             _textToWrite = new StringBuilder();
  15.         }
  16.  
  17.         public void AddMessageText(string text)
  18.         {
  19.             //Append new text message at the end of StringBuilder
  20.             //with "|" for separating from previous
  21.             _textToWrite.Append(text + "|");
  22.         }
  23.  
  24.         public void SaveToFile()
  25.         {
  26.             //remove "|" at the end
  27.             if (_textToWrite.Length > 1) _textToWrite.Length -= 1;
  28.  
  29.             //Split message into array
  30.             string[] output=_textToWrite.ToString().Split(new char[]{'|'});
  31.  
  32.             //Write to file
  33.             File.WriteAllLines(_logFile,output);
  34.         }
  35.     }
  36. }

Here is the code that runs an AutoCAD:

Code Snippet
  1. using System;
  2. using Autodesk.AutoCAD.ApplicationServices;
  3. using Autodesk.AutoCAD.DatabaseServices;
  4. using Autodesk.AutoCAD.EditorInput;
  5. using Autodesk.AutoCAD.Runtime;
  6.  
  7. [assembly: CommandClass(typeof(IExtensionApp.Terminate.MyCommands))]
  8. [assembly: ExtensionApplication(typeof(IExtensionApp.Terminate.MyCommands))]
  9.  
  10. namespace IExtensionApp.Terminate
  11. {
  12.     public class MyCommands : IExtensionApplication
  13.     {
  14.         private static TextLogger _logger = null;
  15.         private const string LOG_FILE_NAME=@"E:\Temp\AcadClosingEvents.txt";
  16.         private static DocumentCollection _dwgs = null;
  17.  
  18.         private static Form1 _disposedForm = null;
  19.         private static Form2 _hiddenForm = null;
  20.  
  21.         public void Initialize()
  22.         {
  23.             Document dwg = Application.DocumentManager.MdiActiveDocument;
  24.             Editor ed = dwg.Editor;
  25.  
  26.             try
  27.             {
  28.                 _logger = new TextLogger(LOG_FILE_NAME);
  29.  
  30.                 _dwgs = Application.DocumentManager;
  31.  
  32.                 //Add event handler on DocumentCollection object
  33.                 _dwgs.DocumentToBeDestroyed +=
  34.                     new DocumentCollectionEventHandler(_dwgs_DocumentToBeDestroyed);
  35.                 _dwgs.DocumentDestroyed +=
  36.                     new DocumentDestroyedEventHandler(_dwgs_DocumentDestroyed);
  37.                 _dwgs.DocumentCreated +=
  38.                     new DocumentCollectionEventHandler(_dwgs_DocumentCreated);
  39.  
  40.                 //Add application event handler
  41.                 Application.QuitWillStart +=
  42.                     new EventHandler(Application_QuitWillStart);
  43.                 Application.BeginQuit +=
  44.                     new EventHandler(Application_BeginQuit);
  45.             }
  46.             catch (System.Exception ex)
  47.             {
  48.                 ed.WriteMessage("\nAcad Addin initializing error: {0}\n", ex.Message);
  49.             }
  50.         }
  51.  
  52.         
  53.         void _dwgs_DocumentCreated(object sender, DocumentCollectionEventArgs e)
  54.         {
  55.             Document dwg = e.Document;
  56.  
  57.             //Add event handler on Document to track document closing
  58.             dwg.CloseWillStart += new EventHandler(dwg_CloseWillStart);
  59.             dwg.BeginDocumentClose +=
  60.                 new DocumentBeginCloseEventHandler(dwg_BeginDocumentClose);
  61.  
  62.             //Database events
  63.             Database db = dwg.Database;
  64.  
  65.             //Add event handler to track when database is to be removed from momery
  66.             db.DatabaseToBeDestroyed += new EventHandler(db_DatabaseToBeDestroyed);
  67.         }
  68.  
  69.         void db_DatabaseToBeDestroyed(object sender, EventArgs e)
  70.         {
  71.             Database db = sender as Database;
  72.             string msg =
  73.                 "Database in document " + db.Filename + " is about to be destroyed";
  74.             _logger.AddMessageText(msg);
  75.         }
  76.  
  77.         void dwg_BeginDocumentClose(object sender, DocumentBeginCloseEventArgs e)
  78.         {
  79.             Document d = sender as Document;
  80.             string msg = "Document " + d.Name + " closing begins";
  81.             _logger.AddMessageText(msg);
  82.         }
  83.  
  84.         void dwg_CloseWillStart(object sender, EventArgs e)
  85.         {
  86.             Document d=sender as Document;
  87.             string msg = "Document " + d.Name + " is abount to be closed";
  88.             _logger.AddMessageText(msg);
  89.         }
  90.  
  91.         void Application_QuitWillStart(object sender, EventArgs e)
  92.         {
  93.             string msg = "Autodesk is about to quit";
  94.             _logger.AddMessageText(msg);
  95.         }
  96.  
  97.         void Application_BeginQuit(object sender, EventArgs e)
  98.         {
  99.             string msg = "Quiting Autodesk begins";
  100.             _logger.AddMessageText(msg);
  101.         }
  102.  
  103.         void _dwgs_DocumentToBeDestroyed(object sender, DocumentCollectionEventArgs e)
  104.         {
  105.             string msg = "Document " + e.Document.Name + " is about to be destroyed";
  106.             _logger.AddMessageText(msg);
  107.         }
  108.         void _dwgs_DocumentDestroyed(object sender, DocumentDestroyedEventArgs e)
  109.         {
  110.             string msg = "Document " + e.FileName + " has been destroyed";
  111.             _logger.AddMessageText(msg);
  112.         }
  113.  
  114.         public void Terminate()
  115.         {
  116.             string msg;
  117.  
  118.             //Log the beginning of Terminate() call
  119.             msg = "Terminate() is called";
  120.             _logger.AddMessageText(msg);
  121.  
  122.             //Log if there is still Document open when Terminate() begins
  123.             msg = "Document count is " + _dwgs.Count;
  124.             _logger.AddMessageText(msg);
  125.  
  126.             //Proves that although the form itself is disposed,
  127.             //its reference is still in scope when Terminate() runs
  128.             if (_disposedForm.IsDisposed)
  129.             {
  130.                 msg = "Form1 is disposed, but its reference is still alive";
  131.                 _logger.AddMessageText(msg);
  132.             }
  133.  
  134.             //Proves that the hidden form object is still alive
  135.             //when terminate() executed.
  136.             if (_hiddenForm != null)
  137.             {
  138.                 if (!_hiddenForm.IsDisposed)
  139.                 {
  140.                     msg = "Form2 has not been disposed";
  141.                     _logger.AddMessageText(msg);
  142.  
  143.                     //Calling Dispose() is not necessary in most cases,
  144.                     //after all it will be gone with the hosting AutoCAD
  145.                     //process. However, if the form object holds other
  146.                     //resources outside AutoCAD open, such as files, data
  147.                     //connections, graphic devices...(which could be bad
  148.                     //practice in most cases, if a form holds these kind
  149.                     //of resources open for entire AutoCAD session), then
  150.                     //you may want to call Dispose() here  with the
  151.                     //appropriate overridden Form.Dispose().
  152.                     _hiddenForm.Dispose();
  153.                 }
  154.             }
  155.  
  156.             //Log Terminate() completion
  157.             msg = "Terminate() call is completed";
  158.             _logger.AddMessageText(msg);
  159.  
  160.             //Save logs into log file.
  161.             _logger.SaveToFile();
  162.         }
  163.  
  164.         /// <summary>
  165.         /// Open 2 modeless forms. Close one (i.e. disposed), so that its
  166.         /// reference is still in scope in the Acad session, but the form
  167.         /// object itself is gone (disposed); Close the other
  168.         /// one as invisible (i.e. handling Form_Closing event, and cancel
  169.         /// its closing, set it to invisible instead, so that the form object
  170.         /// and its reference variable stays alive in the Acad session
  171.         /// </summary>
  172.         [CommandMethod("ShowForms")]
  173.         public static void ShowForms()
  174.         {
  175.             if (_disposedForm == null)
  176.             {
  177.                 _disposedForm = new Form1();
  178.             }
  179.             else if (_disposedForm.IsDisposed)
  180.             {
  181.                 _disposedForm = new Form1();
  182.             }
  183.  
  184.             Application.ShowModelessDialog(_disposedForm);
  185.  
  186.             if (_hiddenForm == null)
  187.             {
  188.                 _hiddenForm = new Form2();
  189.             }
  190.  
  191.             Application.ShowModelessDialog(_hiddenForm);
  192.         }
  193.     }
  194. }

I used 2 forms, which are shown in AutoCAD as modeless dialog box. Both forms are very simple with only one button "Close" on the forms. Clicking the button triggers this.Close() method.

In order to make a point in Terminate() process, I let one form to be closed normally (i.e. when call Form.Close() on a modeless form, the form is disposed). I let the other form change to invisible when Form.Close() is called by handling Form_Closing event, like this:

Code Snippet
  1. private void Form2_FormClosing(object sender, FormClosingEventArgs e)
  2.         {
  3.             e.Cancel = true;
  4.             this.Visible = false;
  5.         }

Build the code into an assembly (dll file) with VS. Now it is ready to run the code and see what happen during AutoCAD closing process. I do these steps:

1. Start AutoCAD;
2. Netload the DLL file;
3. Open a few drawing. In my case, I open 3 saved drawing: drawing1, drawing 2 and drawing 3 from a folder;
4. Execute command "ShowForms" to bring up the 2 modeless forms, then cloce them by clicking their "Close" button;
5. Close AutoCAD without closing drawing first by going to big "A" button->Exit AutoCAD, or simply click "x" on main AutoCAD window;
6. Open the log file ("E:\Temp\AcadClosingEvents.txt") in NotePad to see what have been logged.

Here is the content of the log file:

Document C:\Users\norm\Documents\Drawing3.dwg closing begins
Document C:\Users\norm\Documents\Drawing3.dwg closing begins
Document C:\Users\norm\Documents\Drawing3.dwg is about to be destroyed
Database in document C:\Users\norm\Documents\Drawing3.dwg is about to be destroyed
Document C:\Users\norm\Documents\Drawing3.dwg has been destroyed
Document C:\Users\norm\Documents\Drawing2.dwg closing begins
Document C:\Users\norm\Documents\Drawing2.dwg closing begins
Document C:\Users\norm\Documents\Drawing2.dwg is about to be destroyed
Database in document C:\Users\norm\Documents\Drawing2.dwg is about to be destroyed
Document C:\Users\norm\Documents\Drawing2.dwg has been destroyed
Document C:\Users\norm\Documents\Drawing1.dwg closing begins
Document C:\Users\norm\Documents\Drawing1.dwg closing begins
Document C:\Users\norm\Documents\Drawing1.dwg is about to be destroyed
Database in document C:\Users\norm\Documents\Drawing1.dwg is about to be destroyed
Document C:\Users\norm\Documents\Drawing1.dwg has been destroyed
Quiting Autodesk begins
Autodesk is about to quit
Terminate() is called
Document count is 0
Form1 is disposed, but its reference is still alive
Form2 has not been disposed
Terminate() call is completed
 
Form the messages logged in various event handlers we can see:

1. After AutoCAD receives "quit" command, if there is open drawing, AutoCAD will attempt to close all open drawings, which may trigger prompting message asking user to save changes. The quiting process can be cancelled if user click "Cancel" button in the message box.

2. After all open drawing documents are closed, AutoCAD starts quiting, it is only then the IExtensionApplication.Terminate() is called. That is, one cannot do any document/database related clean-up task in Terminate(), because all document is gone. However, DocumentCollection object is still reachable, but it does not contain document any more.

3. Custom object declared at command class level may or may not exist when Terminate() is executed. In my example, since the 2 forms is called in a static command method, thus, they are instantiated at AutoCAD session level, not per document level. Since they are instantiated in static method, they also has to be declared as "static". About the difference of "static" command method and "non-static" command method, one of my previous post discussed it in more details here.

4. As I commented in the code, what clean-up tasks we need to do in the Terminate() method depends on what our custom AutoCAD Addin does, what external (to AutoCAD) resources the code uses and how they are used. If your code have to do some clean-up in Terminate(), such as opened database connection, opened data file...You may want to look back to the code to answer the question: why your code holds those resource until the end of AutoCAD session? In most cases, it might not be a good practice. So, in real practice, there aren't many cases one has to stuff Terminate() method with a lot of code, if things are done correctly.

Blog Archive

Labels

.NET Programming 2D Drafting 3D design 3D Modeling 3D models 3D Printing 3D rendering 3D scanning 3D Sketch Inventor 3D visualization 3D Web App 3ds Max ACC Add-in Development Additive Manufacturing AEC Technology affordable Autodesk tools AI Design AI in CAD AI in Manufacturing AI Tools AR architectural design architectural modeling architectural preservation architectural visualization Architecture architecture design Architecture Engineering Architecture Firm Architecture Productivity architecture software Artificial Intelligence As-Built Model augmented reality AutoCAD AutoCAD advice AutoCAD API AutoCAD Basics AutoCAD Beginners AutoCAD Civil 3D AutoCAD Civil3D AutoCAD commands AutoCAD efficiency AutoCAD features AutoCAD File Management AutoCAD Layer AutoCAD learning AutoCAD print settings AutoCAD productivity AutoCAD Teaching AutoCAD Techniques AutoCAD tips AutoCAD tools AutoCAD training. AutoCAD tricks AutoCAD Tutorial AutoCAD workflow AutoCAD Xref Autodesk Autodesk 2025 Autodesk 2026 Autodesk 3ds Max Autodesk AI Autodesk AI Tools Autodesk Alias Autodesk AutoCAD Autodesk BIM Autodesk BIM 360 Autodesk Certification Autodesk Cloud Autodesk Construction Cloud Autodesk Docs Autodesk Dynamo Autodesk features Autodesk Forge Autodesk FormIt Autodesk Fusion 360 Autodesk InfraWorks Autodesk Inventor Autodesk Inventor Frame Generator Autodesk Inventor iLogic Autodesk License Autodesk Navisworks Autodesk news Autodesk plugins Autodesk Recap Autodesk Revit Autodesk Software Autodesk Takeoff Autodesk Tips Autodesk training Autodesk update Autodesk Upgrade Autodesk Vault Autodesk Video Autodesk Viewer Automation Automation Tutorial automotive design automotive visualization Backup Basic Commands Basics Beginner Beginner Tips Big Data BIM BIM 360 BIM collaboration BIM Compliance BIM Coordination BIM Data BIM for Infrastructure BIM Implementation BIM Library BIM Management BIM modeling BIM software BIM Standards BIM technology BIM tools BIM Trends BIM workflow Block Editor Building Maintenance Building Systems Building Technology ByLayer CAD CAD API CAD Automation CAD commands CAD comparison CAD Customization CAD Data Management CAD Design CAD Evolution CAD File Size Reduction CAD Integration CAD line thickness CAD management CAD modeling CAD Optimization CAD plugins CAD Productivity CAD Security CAD Skills CAD software CAD software 2026 CAD software training CAD technology CAD Tips CAD Tools CAD workflow car design software Case Study CGI design Civil 3D civil engineering Clash Detection Class-A surfacing clean CAD file cleaning command client engagement Cloud CAD Cloud Collaboration Cloud design platform Cloud Engineering Cloud Management Cloud Storage Cloud-First collaboration command abbreviations Complex Renovation concept car conceptual workflow construction Construction Analytics Construction BIM Construction Cloud Construction Planning Construction Technology contractor tools Contractor Workflow Contraints Cost Effective Design cost estimation Create resizable blocks CTB STB Cybersecurity Data Backup data management Data Protection Data Reference Data Security Data Shortcut Design Automation Design Collaboration Design Comparison Design Coordination design review Design Rules design software design software tips Design Technology Design Tools Design Workflow design-to-construction Designer Tools Digital Construction Digital Construction Technology Digital Design Digital engineering digital fabrication Digital Manufacturing digital marketing digital takeoff Digital Twin Digital Twins digital workflow Drafting Standards Drawing Automation Dref Dynamic Block Dynamic Block AutoCAD Dynamic Blocks Dynamic doors Dynamic windows Dynamo automation early stage design eco design editing commands Energy Analysis energy efficiency Engineering Engineering Automation engineering data Engineering Design Engineering Innovation Engineering Productivity engineering software Engineering Technology engineering tools Engineering Tools 2025 Engineering Workflow Excel Export Workflow Express Tools External Reference Facility Management Fast Structural Design Field Documentation File Optimization File Recovery Forge Development Forge Viewer FreeCAD Fusion 360 Fusion 360 API Fusion 360 tutorial Future Skills Generative Design Geospatial Data GIS Global design teams green building Green Technology Grips Handoff heavy CAD file Heavy CAD Files heritage building conservation HVAC Design Tools HVAC Engineering Hydraulic Modeling iLogic Import Workflow Industry 4.0 infrastructure design Infrastructure Monitoring Infrastructure Planning Infrastructure Technology InfraWorks Insight interactive presentation Interior Design Inventor Inventor API Inventor Drawing Template Inventor Frame Generator Inventor Graphics Issues Inventor IDW Inventor Tips Inventor Tutorial IoT ISO 19650 Keyboard Shortcuts Large Projects Laser Scan Learn AutoCAD Licensing Linked Models Machine Learning in CAD maintenance command Management Manufacturing Innovation Mapping Technology marketing visuals Mechanical Design Mechanical Engineering MEP Modeling Mesh-to-BIM Metal Structure Model Management Model Optimization Modular Housing Multi Office Workflow Multi-User Environment Navisworks Best Practices Net Zero Design ObjectARX .NET API Open Source CAD Organization OVERKILL OVERKILL AutoCAD Palette parametric design parametric family PDF PDM system PlanGrid Plot Style AutoCAD Plugin Tutorial point cloud Post Construction Practice Drawing preconstruction workflow Predictive Maintenance Prefabrication Printing Quality Product Design Product Development product lifecycle product rendering Productivity productivity tools professional printing Professional Tips project management Project Management Tools PTC Creo PURGE PURGE AutoCAD realistic rendering ReCap reduce CAD file size rendering engine rendering software Renovation Project Renovation Workflow Resizable Block restoration workflow Revit Revit add-ins Revit API Revit automation Revit Best Practices Revit Family Revit integration Revit MEP Revit Performance Revit Phasing Revit Scripting Revit skills Revit Tips Revit tutorial Revit Workflow Ribbon ROI Scale Autodesk screen Secure Collaboration Sensor Data Sheet Metal Design Sheet Metal Tricks shortcut keys Shortcuts Siemens NX Simulation Sketch Small Firms Smart Architecture Smart Block Smart Building Design Smart City Smart Factory Smart Infrastructur Software Compliance Software Management Software Update SolidWorks Startup Design Steel Structure Design Structural Optimization Subscription Value sustainability sustainable design Sustainable Manufacturing team training guide Technical Drawing time saving tools toolbar Troubleshooting Tutorial urban planning User Interface (UI) Vault Best Practices Vault Lifecycle Vault Mistakes vehicle modeling virtual reality visualization workflow VR VR Tools VRED Water Infrastructure Water Management What’s New in Autodesk Workbook workflow Workflow Automation Workflow Optimization Worksets Worksharing Workspace XLS Xref