September 2014

Sun Mon Tue Wed Thu Fri Sat
  1 2 3 4 5 6
7 8 9 10 11 12 13
14 15 16 17 18 19 20
21 22 23 24 25 26 27
28 29 30        










« Configuring AutoCAD's use of the .NET Framework via acad.exe.config | Main | Loading a partial CUI and making its toolbars visible through .NET »

October 31, 2006

Blocking AutoCAD commands from .NET

Thanks to Viru Aithal from the DevTech team in India team for this idea (he reminded me of this technique in a recent ADN support request he handled).

A quick disclaimer: the technique shown in this entry could really confuse your users, if implemented with inadequate care. Please use it for good, not evil.

I talked at some length in previous posts about MDI in AutoCAD, and how various commands lock documents when they need to work on them. When commands try to lock (or unlock) a document, an event gets fired. You can respond to this event in your AutoCAD .NET module, asking AutoCAD to veto the operation requesting the lock.

For some general background on events in .NET, I’d suggest checking out this information on MSDN, both from the Developer’s Guide and from MSDN Magazine. To see how they work in AutoCAD, take a look at the EventsWatcher sample on the ObjectARX SDK, under samples/dotNet/EventsWatcher. This is a great way to see what information is provided via AutoCAD events.

It seems that almost every command causes the DocumentLockModeChanged event to be fired – I would say every command, but I can imagine there being commands that don’t trigger it, even if the technique appears to work even for commands that have no reason to lock the current document, such as HELP.

As you can imagine, having something block commands that a user expects to use could result in a serious drop in productivity, but there are genuine cases where you might have a legitimate need to disable certain product functionality, such as to drive your users through a more automated approach to performing the same task. This is not supposed to act as a fully-fledged security layer – an advanced user could easily prevent a module from being loaded, which invalidates this technique – but it could still be used to help stop the majority of users from doing something that might (for instance) break the drawing standards implemented in their department.

So, let’s take a look at what needs to happen to define and register our event handler.

Firstly, we must declare a callback function somewhere in our code that we will register as an event handler. In this case we’re going to respond to the DocumentLockModeChanged event, and so will take as one of our arguments an object of type DocumentLockModeChangedEventArgs:

VB.NET:

Private Sub vetoLineCommand (ByVal sender As Object, _

  ByVal e As DocumentLockModeChangedEventArgs)

  If (e.GlobalCommandName = "LINE") Then

    e.Veto()

  End If

End Sub

C#:

private void vetoLineCommand(

  object sender,

  DocumentLockModeChangedEventArgs e)

{

  if (e.GlobalCommandName == "LINE")

  {

    e.Veto();

  }

}

This callback function, named vetoLineCommand(), simply checks whether the command that is requesting the change in document lock mode is the LINE command, and, if so, it then vetoes it. In our more complete sample, later on, we’ll maintain a list of commands to veto, which can be manipulated by the user using come commands we define (you will not want to do this in your application – this is for your own testing during development).

Next we need to register the command. This event belongs to the DocumentManager object, but the technique for registering events is different between VB.NET and C#. In VB.NET you use the AddHandler() keyword, referring to the DocumentLockModeChanged event from the DocumentManager object – in C# you add it directly to the DocumentLockModeChanged property. This could be done from a command or from the Initialize() function, as I’ve done in the complete sample further below.

VB.NET:

Dim dm As DocumentCollection = Application.DocumentManager()

AddHandler dm.DocumentLockModeChanged, AddressOf vetoLineCommand

C#:

DocumentCollection dm = Application.DocumentManager;

dm.DocumentLockModeChanged += new DocumentLockModeChangedEventHandler(vetoLineCommand);

That's really all there is to it... as mentioned, the complete sample maintains a list of commands that are currently being vetoed. I've made this shared/static, and so it will be shared across documents (so if you try to modify this in concurrent drawings, you might get some interesting results).

Here's the complete sample (just to reiterate - use this technique both at your own risk and with considerable caution).

VB.NET:

Imports Autodesk.AutoCAD.Runtime

Imports Autodesk.AutoCAD.ApplicationServices

Imports Autodesk.AutoCAD.EditorInput

Imports System.Collections.Specialized


Namespace VetoTest

  Public Class VetoCmds

    Implements IExtensionApplication


    Shared cmdList As StringCollection _

      = New StringCollection


    Public Sub Initialize() _

      Implements IExtensionApplication.Initialize

      Dim dm As DocumentCollection

      dm = Application.DocumentManager()

      AddHandler dm.DocumentLockModeChanged, _

        AddressOf vetoCommandIfInList

    End Sub


    Public Sub Terminate() _

      Implements IExtensionApplication.Terminate

      Dim dm As DocumentCollection

      dm = Application.DocumentManager()

      RemoveHandler dm.DocumentLockModeChanged, _

        AddressOf vetoCommandIfInList

    End Sub


    <CommandMethod("ADDVETO")> _

    Public Sub AddVeto()

      Dim ed As Editor _

        = Application.DocumentManager.MdiActiveDocument.Editor

      Dim pr As PromptResult

      pr = ed.GetString(vbLf + _

        "Enter command to veto: ")

      If (pr.Status = PromptStatus.OK) Then

        If (cmdList.Contains(pr.StringResult.ToUpper())) Then

          ed.WriteMessage(vbLf + _

            "Command already in veto list.")

        Else

          cmdList.Add(pr.StringResult.ToUpper())

          ed.WriteMessage( _

            vbLf + "Command " + _

            pr.StringResult.ToUpper() + _

            " added to veto list.")

        End If

      End If

    End Sub


    <CommandMethod("LISTVETOES")> _

    Public Sub ListVetoes()

      Dim ed As Editor _

        = Application.DocumentManager.MdiActiveDocument.Editor

      ed.WriteMessage( _

        "Commands currently on veto list: " + vbLf)

      For Each str As String In cmdList

        ed.WriteMessage(str + vbLf)

      Next

    End Sub


    <CommandMethod("REMVETO")> _

    Public Sub RemoveVeto()

      ListVetoes()

      Dim ed As Editor _

        = Application.DocumentManager.MdiActiveDocument.Editor

      Dim pr As PromptResult

      pr = ed.GetString( _

        "Enter command to remove from veto list: ")

      If (pr.Status = PromptStatus.OK) Then

        If (cmdList.Contains(pr.StringResult.ToUpper())) Then

          cmdList.Remove(pr.StringResult.ToUpper())

        Else

          ed.WriteMessage(vbLf + _

            "Command not found in veto list.")

        End If

      End If

    End Sub


    Private Sub vetoCommandIfInList(ByVal sender As Object, _

      ByVal e As DocumentLockModeChangedEventArgs)

      If (cmdList.Contains(e.GlobalCommandName.ToUpper())) Then

        e.Veto()

      End If

    End Sub

  End Class

End Namespace

C#:

using Autodesk.AutoCAD.EditorInput;

using Autodesk.AutoCAD.ApplicationServices;

using Autodesk.AutoCAD.Runtime;

using System;

using System.Collections.Specialized;


namespace VetoTest

{

  public class VetoCmds : IExtensionApplication

  {

    static StringCollection cmdList =

      new StringCollection();


    public void Initialize()

    {

      DocumentCollection dm =

        Application.DocumentManager;

      dm.DocumentLockModeChanged += new

        DocumentLockModeChangedEventHandler(

          vetoCommandIfInList

        );

    }


    public void Terminate()

    {

      DocumentCollection dm;

      dm = Application.DocumentManager;

      dm.DocumentLockModeChanged -= new

        DocumentLockModeChangedEventHandler(

          vetoCommandIfInList

        );

    }


    [CommandMethod("ADDVETO")]

    public void AddVeto()

    {

      Editor ed =

        Application.DocumentManager.MdiActiveDocument.Editor;

      PromptResult pr =

        ed.GetString("\nEnter command to veto: ");

      if (pr.Status == PromptStatus.OK)

      {

        if (cmdList.Contains(pr.StringResult.ToUpper()))

        {

          ed.WriteMessage(

            "\nCommand already in veto list."

          );

        }

        else

        {

          cmdList.Add(pr.StringResult.ToUpper());

          ed.WriteMessage(

            "\nCommand " +

            pr.StringResult.ToUpper() +

            " added to veto list.");

        }

      }

    }


    [CommandMethod("LISTVETOES")]

    public void ListVetoes()

    {

      Editor ed =

        Application.DocumentManager.MdiActiveDocument.Editor;

      ed.WriteMessage("Commands currently on veto list:\n");

      foreach (string str in cmdList)

      {

        ed.WriteMessage(str + "\n");

      }

    }


    [CommandMethod("REMVETO")]

    public void RemoveVeto()

    {

      ListVetoes();

      Editor ed =

        Application.DocumentManager.MdiActiveDocument.Editor;

      PromptResult pr;

      pr =

        ed.GetString(

          "Enter command to remove from veto list: "

        );

      if (pr.Status == PromptStatus.OK)

      {

        if (cmdList.Contains(pr.StringResult.ToUpper()))

        {

          cmdList.Remove(pr.StringResult.ToUpper());

        }

        else

        {

          ed.WriteMessage(

            "\nCommand not found in veto list."

          );

        }

      }

    }


    private void vetoCommandIfInList(

      object sender,

      DocumentLockModeChangedEventArgs e)

    {

      if (cmdList.Contains(e.GlobalCommandName.ToUpper()))

      {

        e.Veto();

      }

    }

  }

}

In terms of usage, it should be simple enough to work out while playing with it:

  • ADDVETO adds commands to the veto list
  • LISTVETOES lists the commands on the veto list
  • REMVETO removes commands from the veto list

These commands are really only intended for you to try out different commands on the veto list, to see what happens. If you need to control use of command(s) from your application, you should not allow your users to manipulate the list of blocked commands themselves.

TrackBack

TrackBack URL for this entry:
http://www.typepad.com/services/trackback/6a00d83452464869e200d834f696a669e2

Listed below are links to weblogs that reference Blocking AutoCAD commands from .NET:

blog comments powered by Disqus

Feed/Share

10 Random Posts