Saturday, September 15, 2012

Make Change/Restore System Variable Easy

It is common practice in AutoCAD programming, regardless of what supporting language/API you use, that if your process must change AutoCAD's system variables, the changed system variables should be restored back to its original value before your process begins.

Typically, to achieve this, one has to

1. Save a system variable's current value to variable that is value in the entire scope of the process;
2. Change then system variable's value as desired before the process begins;
3. Right after the process ends, reset the changed system variable to its previously saved original value.

As one can see if the custom process requires change a few variables, writing code to do this would be quite tedious.

We can make this changing/restoring system variable process a lot easier by encapsulating system variable value change in a class.

Here is an fairly simple way to do it:

Code Snippet
  1. using System.Collections.Generic;
  2. using Autodesk.AutoCAD.ApplicationServices;
  3. using Autodesk.AutoCAD.EditorInput;
  4.  
  5. namespace SysVariables
  6. {
  7.     public class SysVariableSetter : Dictionary<string, object>
  8.     {
  9.         public void SetSysVariable(string varName, object varValue)
  10.         {
  11.             if (!this.ContainsKey(varName))
  12.             {
  13.                 object originalValue = Application.GetSystemVariable(varName);
  14.                 this.Add(varName, originalValue);
  15.             }
  16.  
  17.             Application.SetSystemVariable(varName, varValue);
  18.         }
  19.  
  20.         public void RestoreSysVariables()
  21.         {
  22.             //Debugging/Demo only code (next 1 line)
  23.             Editor ed = Application.DocumentManager.MdiActiveDocument.Editor;
  24.             
  25.             foreach (KeyValuePair<string, object> varItem in this)
  26.             {
  27.                 //Debugging/demo only code (next 2 lines)
  28.                 ed.WriteMessage("\n{0} original value: {1}",
  29.                     varItem.Key, varItem.Value);
  30.                 ed.WriteMessage("\n{0} current value: {1}",
  31.                     varItem.Key, Application.GetSystemVariable(varItem.Key));
  32.  
  33.                 Application.SetSystemVariable(varItem.Key, varItem.Value);
  34.  
  35.                 //Debug/demo code (next 2 lines)
  36.                 ed.WriteMessage("\n{0} current value has been restored to {1}",
  37.                     varItem.Key, varItem.Value);
  38.                 ed.WriteMessage("\n");
  39.             }
  40.         }
  41.     }
  42. }

Note, Editor referred in the code is purely for the purpose of demo.

Here is the sample code of how to use this class:

Code Snippet
  1. using Autodesk.AutoCAD.ApplicationServices;
  2. using Autodesk.AutoCAD.EditorInput;
  3. using Autodesk.AutoCAD.Runtime;
  4.  
  5. [assembly: CommandClass(typeof(SysVariables.MyCommands))]
  6.  
  7. namespace SysVariables
  8. {
  9.     public class MyCommands
  10.     {
  11.         [CommandMethod("DoTest")]
  12.         public void DoMyTest()
  13.         {
  14.             Document dwg = Application.DocumentManager.MdiActiveDocument;
  15.             Editor ed = dwg.Editor;
  16.  
  17.             SysVariableSetter varSetter = new SysVariableSetter();
  18.  
  19.             try
  20.             {
  21.                 //Change sys variable FILEDIA
  22.                 varSetter.SetSysVariable("FILEDIA", 0);
  23.  
  24.                 //Do some work here
  25.                 //....................
  26.  
  27.                 //Change sys variable BACKGROUNDPLOT
  28.                 varSetter.SetSysVariable("BACKGROUNDPLOT", 0);
  29.  
  30.                 //Do plotting here
  31.                 //.................
  32.  
  33.             }
  34.             catch(System.Exception ex)
  35.             {
  36.                 ed.WriteMessage("\nError: {0}", ex.ToString());
  37.             }
  38.             finally
  39.             {
  40.                 //Restore changed system variables
  41.                 varSetter.RestoreSysVariables();
  42.             }
  43.         }
  44.     }
  45. }

As you can see, instead of using Application.SetSystmVariable() method, one can now change system variables with SysVariableSetter class with the same. one line of code. But there is no need to worry about to save system variable's original value to later restoration.

As long as the custom process is wrapped in a try{...} finally{...} block, a call to SysVariableSetter.RestoreSysVariables() in the finally{...} block will always be executed, thus changed system variables will be restored to their original values.

Update on September 17th, 2012

There is situation that during the execution of our custom developed process, we may want to change a system variable and restore (or even change and restore multiple times) before the process end. For example, we may want to change Object Snap Mode a few times whe we ask user to select someting in the editor and we may not want to just keep change OSMODE syatem variable and only restore it at the finally{...} block at the end of process.

Anyway to make the SysVariableSetter class a bit more flexible to use, I added a method to allow it to restore any changed system variable at any time:

Code Snippet
  1. public void RestoreVariable(string variableName)
  2.         {
  3.             if (this.ContainsKey(variableName.ToUpper()))
  4.             {
  5.                 Application.SetSystemVariable(variableName, this[variableName]);
  6.                 this.Remove(variableName.ToUpper());
  7.             }
  8.         }

Now, we can call SetVariable() method at any time and restore any system variable at any time without bothering to save the system variable's original value.

No comments:

Post a Comment