Adding to AutoCAD’s Application Menu and Quick Access Toolbar using .NET

I received this question from Vikas Hajela a few days ago:

I am developing a plugin in C#, which will add a link in Quick Access Toolbar in AutoCAD. […] My problem is that I don't know how to add a link into existing Quick Access Toolbar and Menu Bar in AutoCAD using ObjectARX SDK and C#. Also I want that on click of that link it should open a new window.

We're going to look at some code that – on initialization of the application – adds an item to AutoCAD's "Big A" Application Menu and to the Quick Access Toolbar (the "quick launch" toolbar towards the left of the main application window's title bar). To solve this I borrowed some code and techniques from a couple of DevNotes on the ADN site: Use the .NET API to add a menu Item to Application Menu (big A) and The arrow of the Dialog Launcher button on my Ribbon panel does not show. It should be noted that this code will need at least AutoCAD 2010 to execute.

Here's the C# code. To make it work you will need to place a couple of .ico files in your DLL's folder (these could very easily be stored as resources in your application's project, which is left as an exercise for the reader).

using Autodesk.AutoCAD.ApplicationServices;

using Autodesk.AutoCAD.EditorInput;

using Autodesk.AutoCAD.Runtime;

using Autodesk.Windows;

using System.Windows.Media.Imaging;

using System.Reflection;

using System.IO;

using System.Collections.Generic;

using System;

 

namespace AppMenus

{

  public class ExtApp : IExtensionApplication

  {

    // String constants

 

    const string appText = "Browse Photosynth";

    const string appDesc =

      "Browse the Photosynth site and import point " +

      "clouds into AutoCAD.";

    const string smallFile = "Browser-16x16.ico";

    const string largeFile = "Browser-32x32.ico";

    const string bpCmd = "_.BP";

 

    public void Initialize()

    {

      // We defer the creation of our Application Menu to when

      // the menu is next accessed

 

      ComponentManager.ApplicationMenu.Opening +=

        new EventHandler<EventArgs>(ApplicationMenu_Opening);

 

      // We defer the creation of our Quick Access Toolbar item

      // to when the application is next idle

 

      Application.Idle += new EventHandler(Application_OnIdle);

    }

 

    public void Terminate()

    {

      // Assuming these events have fired, they have already

      // been removed

 

      ComponentManager.ApplicationMenu.Opening -=

        new EventHandler<EventArgs>(ApplicationMenu_Opening);

 

      Application.Idle -= new EventHandler(Application_OnIdle);

    }

 

    void Application_OnIdle(object sender, EventArgs e)

    {

      // Remove the event when it is fired

 

      Application.Idle -= new EventHandler(Application_OnIdle);

 

      // Add our Quick Access Toolbar item

 

      AddQuickAccessToolbarItem();

    }

 

    void ApplicationMenu_Opening(object sender, EventArgs e)

    {

      // Remove the event when it is fired

 

      ComponentManager.ApplicationMenu.Opening -=

        new EventHandler<EventArgs>(ApplicationMenu_Opening);

 

      // Add our Application Menu

 

      AddApplicationMenu();

    }

 

    private void AddApplicationMenu()

    {

      ApplicationMenu menu = ComponentManager.ApplicationMenu;

      if (menu != null && menu.MenuContent != null)

      {

        // Create our Application Menu Item

 

        ApplicationMenuItem mi = new ApplicationMenuItem();

        mi.Text = appText;

        mi.Description = appDesc;

        mi.LargeImage = GetIcon(largeFile);

 

        // Attach the handler to fire out command

 

        mi.CommandHandler = new AutoCADCommandHandler(bpCmd);

 

        // Add it to the menu content

 

        menu.MenuContent.Items.Add(mi);

      }

    }

 

    private void AddQuickAccessToolbarItem()

    {

      Autodesk.Windows.ToolBars.QuickAccessToolBarSource qat =

        ComponentManager.QuickAccessToolBar;

      if (qat != null)

      {

        // Create our Ribbon Button

 

        RibbonButton rb = new RibbonButton();

        rb.Text = appText;

        rb.Description = appDesc;

        rb.Image = GetIcon(smallFile);

 

        // Attach the handler to fire out command

 

        rb.CommandHandler = new AutoCADCommandHandler(bpCmd);

 

        // Add it to the Quick Access Toolbar

 

        qat.AddStandardItem(rb);

      }

    }

 

    private System.Windows.Media.ImageSource GetIcon(string ico)

    {

  &#
160;  
// We'll look for our icons in the folder of the assembly

      // (we could also use a resources, of course)

 

      string path =

        Path.GetDirectoryName(

          Assembly.GetExecutingAssembly().Location

        );

 

      // Check our .ico file exists

 

      string fileName = path + "\\" + ico;

      if (File.Exists(fileName))

      {

        // Get access to it via a stream

 

        Stream fs =

          new FileStream(

            fileName,

            FileMode.Open,

            FileAccess.Read,

            FileShare.Read

          );

        using (fs)

        {

          // Decode the contents and return them

 

          IconBitmapDecoder dec =

            new IconBitmapDecoder(

              fs,

              BitmapCreateOptions.PreservePixelFormat,

              BitmapCacheOption.Default

            );

          return dec.Frames[0];

        }

      }

      return null;

    }

  }

 

  // A class to fire commands to AutoCAD

 

  public class AutoCADCommandHandler

    : System.Windows.Input.ICommand

  {

    private string _command = "";

 

    public AutoCADCommandHandler(string cmd)

    {

      _command = cmd;

    }

 

#pragma warning disable 67

    public event EventHandler CanExecuteChanged;

#pragma warning restore 67

 

    public bool CanExecute(object parameter)

    {

      return true;

    }

 

    public void Execute(object parameter)

    {

      if (!String.IsNullOrEmpty(_command))

      {

        Document doc =

          Application.DocumentManager.MdiActiveDocument;

        doc.SendStringToExecute(

          _command + " ", false, false, false

        );

      }

    }

  }

}

A few comments on the code:

  • We delay the creation of both the Application Menu and Quick Access Toolbar items, but for different reasons:
    • The Application Menu only gets created when it's first accessed, so we need to wait for that to happen before adding our item
    • The Quick Access Toolbar item cannot be created on Initialize(), as our module may have been loaded on AutoCAD startup and the QAT may not yet be ready
  • We have temporarily disabled a warning (CS0067) which tells us that an event handler – which we need to implement to complete the ICommand interface – is not used in our code

Now let's see it in action. As you can probably tell from the code, it's basically adding a "launch" UI to the application I showed in the last post.

When we NETLOAD the application (or auto-load it on AutoCAD start-up), we see our Quick Access Toolbar icon gets added:

Quick Access Toolbar icon added

We get more information when we hover over it:

Hovering over our new QAT icon

We also have our new Application Menu item:

And our new Application Menu item When we select either item, our BP command – as implemented previously – gets launched. Vikas had requested a dialog be shown, but I strongly recommend that this is implemented via a command rather than being displayed directly in the code. This just helps AutoCAD synchronise its user interface appropriately and will avoid lots of subtle issues you might otherwise hit.

44 responses to “Adding to AutoCAD’s Application Menu and Quick Access Toolbar using .NET”

  1. Thanks Kean for the great help....

    Can we do the same by saving the settings in parital CUIX. Because when we re-open the Autocad, the added controls are removed.

  2. It should be, although that's another question. If you're auto-loading your UI customization module on AutoCAD startup then the items will always be there, but I can understand why you'd want to use CUI, as this would allow your users to customize your app's UI.

    Kean

  3. Francois Dauberlieu Avatar
    Francois Dauberlieu

    To the risk of sounding dumb as dumb can be:
    How do you add a separator before the new menu entry ? Couldn't find anything about that....

  4. That's far from being a dumb question, Francois. 🙂

    If you add this line before the line adding your menu item, you'll get a separator:

    menu.MenuContent.Items.Add(new RibbonSeparator());

    Regards,

    Kean

  5. Francois Dauberlieu Avatar
    Francois Dauberlieu

    Works great. Thanx

  6. Francois Dauberlieu Avatar
    Francois Dauberlieu

    Kean,

    Another question: Is it possible (and how if it is) to access the Icon resources from autoCAd itself ? There are a few Icons I'd like to reuse if feasible

    Cheers

  7. I don't know - I suggest asking via ADN, if you're a member.

    Kean

  8. Hey Kean,

    thanks for the code. However, I keep crashing autocad by adding the qucikaccesstoolbar button. The scenario is:
    1. Execture AddQuickAccessToolbarItem(), as you have suggested.
    2. Try to reorganize the quick access buttons in autocad, by turning them on and off. As it happens if I turn on a couple of other buttons after the cusom one I added, and then try to turn one off, it crashes autocad with a fatal error.
    3. The same fatal error crash occurs if I run the wssave command after the custom quick access button was added.

    Any help will be appriciated.

    Thanks

  9. Hi Kean,

    sorry for the double post. I figured out what the problem is. The Id and UID properties for the RibbonButton need to be set before adding it, otherwise when autocad tries to refer to that button by the Id, causes a fatal crash since it is not set. Thanks again for the code.

  10. Hi Kean, thanks again for another very helpful article!

    I just have one complication with the code. I'm trying to use it with my own application, and everything works fine except the image part. I have my own images, which are saved to the correct Icon (.ico) format. Yet everytime i try to startup autoCAD (my application is demand-loading) I run into an error:

    System.IO.FileFormatException: The codec cannot use the type of stream provided

    I'm catching the error now so autocad doesn't freeze up, and after those the buttons are added, just without images. What do I need to do differently from your code? I'm at a loss for ideas. Also if it matters i'm using primariy autocad 2010/11

  11. Kean Walmsley Avatar

    Hi Andrew,

    I expect there's something about the specific datatype stored in the ICO files. I suggest loading the ones I've provided into Visual Studio next to your own and checking things like resolution and colour depth.

    Regards,

    Kean

  12. Hi Kean,
    still having no luck with this. I've tried pulling the ones you used as well as trying to use icons directly taken from other commands in the CUI. My icon in the Application Menu shows up but the icon for the QAT is still invisible. For now I'm just giving up on using the QAT icon and just sticking with the one that works, but I can't figure out at all what's wrong with the .ico file for the small image

  13. Kean Walmsley Avatar

    Hi Andrew,

    Have you posted a project via the ADN site (if you're an ADN member) or to the AutoCAD .NET Discussion Group?

    Let me know when you have, and if I get the time I'll take a look.

    Kean

  14. I've got it figured out now. I don't understand why exactly but after using about a dozen online icon converter programs one of them worked, so all is well again.
    Thanks for your help, and this article!

  15. Now I've got another question for you Kean; I've been trying to add regular buttons to the ribbon using this code, and running into issues with different versions. 2011 Autocad works just fine loading the ribbonButtons in the Idle event, but that does not work for 2010 and I have yet to find a different event that fires that allows it to work. Any ideas what event I should do or is the code need to be changed based on if the user is using 2010 or 2011? Thanks for all the help

  16. Kean Walmsley Avatar

    Hi Andrew,

    When you can, CUI is probably the safest way to go for UI customization.

    Other than that, I don't really have any advice to give...

    I suggest posting your question to the ADN team, if you're a member, or otherwise the AutoCAD .NET Discussion Group.

    Regards,

    Kean

  17. I wonder if an additional menu can be added to the normal Menu bar as well (The bar that is hidden by default in AutoCAD 2010+)

  18. Kean Walmsley Avatar

    You'd probably be better off using CUI to modify this menu.

    If there's nothing directly relevant on the blog, I suggest posting your question to the ADN team, if you're a member, or otherwise the AutoCAD .NET Discussion Group.

    Kean

  19. You can check ComponentManager.Ribbon:

    void Application_OnIdle(object sender, EventArgs e)
    {
    if (ComponentManager.Ribbon == null)
    return;

    Application.Idle -= new EventHandler(Application_OnIdle);
    AddQuickAccessToolbarItem();
    }

  20. Hi Kean
    great post i have a issue with applicationmenu recent documents open event handler i hope you will be able to help or point me to right direction.

    I want to validate the file path of dwg before openning it, when i use the DocumentCreateStarted event of DocumentCollection and try to access the e.Document.Name for validation it shows an empty string. and if document is not available Autocad shows a message "Cannot find the specified drawing file....". i want to handle the event before this message and if file not avialble perform some other action rather than showing a messagebox.

    any idea how i can access file path in DocumentCreateStarted?
    thanks

  21. Hi Nav,

    This isn't a forum for support.

    Your comment doesn't appear to relate to this post, so please submit your question to the ADN team, if you're a member, or otherwise the AutoCAD .NET Discussion Group.

    Regards,

    Kean

  22. Hi,thanks for your help and code
    I have tried this example , everything ran good , but in the function "private void AddApplicationMenu()" , the last sentence is "menu.MenuContent.Items.Add(mi);" , where the "Items" is "Autodesk.Windows.RibbonItemCollection" , but the compiler told
    me "Autodesk.Windows.RibbonItemCollection don't include the definition of Add"

    could you tell me how to solve this ?

    I use visual studio 2010 with .net 3.5 and autocad 2010
    I have add the references to AcCui.dll acdbmgd.dll acdbmgdbrep.dll AcDx.dll acmgd.dll AcTcMgd.dll AcWindows.dll AdWindows.dll Autodesk.AutoCAD.Interop.dll Autodesk.AutoCAD.Interop.Common.dll

  23. I don't know why you're you're seeing this error (I don't have it on my system - it worked with AutoCAD 2010 when I wrote it and I just checked the code also compiled against the AutoCAD 2012 assemblies, too).

    Could it be you're somehow building against assemblies for versions prior to AutoCAD 2010?

    Kean

  24. Thanks for this input. I'd love to try building on this, but I can't get it to run in VS 2010 ultimate. I've got autocad 2012 as well. It looks like the IconBitmapDecoder is missing. Could you tell me which assemblies I need for this and where I might get them?

    Grateful for any help.

    Nathan

  25. It sounds as though you're missing PresentationCore.dll (and may also need PresentationFramework).

    msdn.microsoft.com/en-us/library/system.windows.media.imaging.iconbitmapdecoder.aspx

    Any non-AutoCAD assemblies will be part of the .NET Framework.

    Kean

  26. I am always grateful for your posting. They helped me alot.
    But when I tried the above code, my VS says ComponentManager is not in the context.
    It seems like it's in the AutoCAD.Windows namespace, but even the namespace does not exist for me. 🙁
    I am currently using ObjectARX 2011 SDK.

    Any idea?

    Grateful for any help.

    Jake

  27. Hi Jake,

    Do you have a project reference to AdWindows.dll? That should be enough to resolve the problem.

    Cheers,

    Kean

  28. zoltan.torok@tzi.hu Avatar
    zoltan.torok@tzi.hu

    Hello Kean,

    Life saving post.
    Is it possible to add a button to the zero-doc-state Quick Access toolbar?

  29. Kean Walmsley Avatar

    Hi Zoltan,

    Not that I'm aware of...

    Kean

  30. hello Kean,

    How can I have a RibbonButton created in the cuix through the CUI user interface, so that it is loaded as not enabled? I seem not to find any where a property that can be set for this behaviour.
    I appreciate if you have any pointers on this.
    Thanks!

  31. Hello wagdu,

    I don't know, off the top of my head. Please post your question via ADN or to the AutoCAD .NET Discussion Group.

    Regards,

    Kean

  32. Hi Kean,

    I want to remove\hide the Big A Image ICON from application menu browser.How i will do from Code.Please let me know so i am thankful to you.

    autodesk.windows.Applicationmenu menu= autodesk.windows.componentmanager.Applicationmenu;

    menu.Isopen=false;
    it is allowing to open the menubrowser.But i want to hide/Remove from code BigA image ICON of applicationmenu.so i am thankful to you.

  33. it is not allowing to open the menubrowser.But i want to hide/Remove from code BigA image ICON of applicationmenu.so i am thankful to you.

  34. Kean Walmsley Avatar

    Hi Mani,

    Please submit your question to the ADN team or post it to the AutoCAD .NET Discussion Group.

    Regards,

    Kean

  35. Hi,

    can you please provide the same code in VB.net ?

  36. I tested your code for QuickAccessToolBar on Acad from 2010 till 2014 and basic scenario works. Unfortunately on Acad 2015 it does not work. My button indeed appear in QuickAccessToolBar when Acad is started, but it can not be used because by default no document is opened. If I open a new document then new Acad buttons appear in QuickAccessToolBar and my button disappear. Command behind the button works fine.

    I have also another issue: if I try to configure QuickAccessToolBar and I hide/show any Acad button then Acad is crashing. This crash happens also on older versions of Acad (from 2010 till 2014).

    Does anybody encountered the same issues? Do you have any advice how to fix them?

    1. At the very least you should be checking whether Application.DocumentManager.MdiActiveDocument is non-null before trying to use it to call a command (you might also check whether it's null and choose not to add the menu item at all is that's the case).

      Kean

  37. Thanks Kean But I am Already done with this...I am looking for adding my custom toolbar on autocad drawing's screen.

  38. Sharveen Umasangkar Avatar
    Sharveen Umasangkar

    Hi Kean, how do I create a customised toolbar in autocad 2018 using vs 2015 vb.net?
    Thank you.

    1. Kean Walmsley Avatar

      Please post your support questions to the AutoCAD .NET forum.

      Kean

      1. Sharveen Umasangkar Avatar
        Sharveen Umasangkar

        Noted. Thank you

  39. Hi Kean, is there a way to create a new toolbar instead of adding to the quick access toolbar. I am searching through this blog and cannot find one.

    Thanks for your help in advance.
    -Ron.

    1. Hi Ron,

      I'm sorry - unfortunately I don't provide technical support (and am no longer working regularly with AutoCAD). Please post your questions to the AutoCAD .NET forum.

      Best,

      Kean

Leave a Reply

Your email address will not be published. Required fields are marked *