locked
Change Toolbar image at runtime in Visual Stduio Package RRS feed

  • Question

  • Hello guys,

    I created a VS Package project to extend VS.

    The project creates new toolbar in VS with 3 buttons.

    One of the button is Activate\Deactivate button, I would like to change the image of the toolbar button on click.

    I did not find a way to change it from within MenuCommand class in the Initialize method:

    CommandID menuCommandSActivate = new CommandID(GuidList.guidVSSuperActionsCmdSet, (int)PkgCmdIDList.cmdidCommandSuperActivate);
    m_menuItemActivate = new MenuCommand(SuperActivateCallback, menuCommandSActivate);
    mcs.AddCommand(m_menuItemActivate);

    The only way I managed this is by using the "old fusion" way of add-in:

    CommandBar menuBarCommandBar = ((CommandBars)m_devEnv2.CommandBars)["Super Build Toolbar"];
    CommandBarControl toolsControl = menuBarCommandBar.Controls["Activate/Deactivate"];
    CommandBarButton activate = toolsControl as CommandBarButton;

    I just find the toolbar object and the toolbar button and then with CommandBarButton object I change the image:

    f (m_activated)
                {
                    //activate                
                    activate.Picture = m_picGreen;
                }
                else
                {
                    //deactivate
                    activate.Picture = m_picRed;
                }

    It is working except one thing: After testing the project (which opens the VS) I close VS and it brings an error message: "Visual Studio is Restarting"

    I guess it started after I added the code that change the image button at runtime.

    My questions are is there a better way of changing a VS toolbar button at runtime?

    if not, is there a problem with my code above?

    Thanks!

    Roy


    R.R

    Wednesday, October 10, 2012 7:08 AM

All replies

  • There is no way to change the image dynamically via the normal methods (QueryStatus), because the interface does not allow for a way to express that (apparently at the time it was designed (i.e. LONG ago), no one thought that might be a use case :().

    Changing via DTE should work, the crash at shutdown would be unexpected. Do you have a repro or a crash dump?

    Ryan

    Wednesday, October 10, 2012 4:06 PM
  • Can you post the minimal code of the following?

    - How do you get the m_picGreen and m_picRed pictures

    - The cleanup code executed when your extension is unloaded

    Also, FWIW, for activate/deactivate buttons you can use checked/unchecked buttons keeping the same image in both cases. Visual Studio adds a rectangle around the icon in the checked state. You have to use the vsCommandStatusLatched status. For add-in it would be HOWTO: Create a checked/unchecked command in a Visual Studio add-in


    MZ-Tools: Productivity add-ins for Visual Studio: http://www.mztools.com. My blog about developing add-ins: http://msmvps.com/blogs/carlosq/

    Wednesday, October 10, 2012 6:26 PM
  • hello,

    here is some code

    first, I declare the images at class level:
    private stdole.StdPicture m_picRed, m_picGreen;

    private stdole.StdPicture m_picRed, m_picGreen;


    while loding the package, I init the images objects:

    private void SetImages()
            {
                m_picGreen = (stdole.StdPicture)IconConverter.GetIPictureDispFromImage(Resources.star_green);
                m_picRed = (stdole.StdPicture)IconConverter.GetIPictureDispFromImage(Resources.star_red);
            }


    I have the png files as resources, the IconConverter is a code to convert image to StdPicture object. it has only one static method:

    public static stdole.IPictureDisp GetIPictureDispFromImage(System.Drawing.Image image)
            {
    
                return (stdole.IPictureDisp)GetIPictureDispFromPicture(image);
            }  
    


    the method that replace the icons (that you saw it my first post):

    private void ChangeActivateButton()
            {
                CommandBar menuBarCommandBar = ((CommandBars)m_devEnv2.CommandBars)["Super Build Toolbar"];
                CommandBarControl toolsControl = menuBarCommandBar.Controls["Activate/Deactivate"];
                CommandBarButton activate = toolsControl as CommandBarButton;
    
                if (m_activated)
                {
                    //activate                
                    activate.Picture = m_picGreen;
                }
                else
                {
                    //deactivate
                    activate.Picture = m_picRed;
                }
            }
    

     


    about error log, well, the VS does not brings any logs to collect... only the "VS is now restarting" message, The event viewer has this message:


    Faulting application name: devenv.exe, version: 10.0.40219.1, time stamp: 0x4d5f2a73

    Faulting module name: unknown, version: 0.0.0.0, time stamp: 0x00000000

    Exception code: 0xc0000005

    Fault offset: 0x0073006f

    Faulting process id: 0x4d0

    Faulting application start time: 0x01cda892eb9bc623

    Faulting application path: C:\Program Files (x86)\Microsoft Visual Studio 10.0\Common7\IDE\devenv.exe

    Faulting module path: unknown

    Report Id: 9139a60f-1486-11e2-b96b-642737d4def6
     if you need anything else, let me know

    Thanks


    R.R

    Friday, October 12, 2012 4:16 PM
  • You need to run VS under a debugger and get it to crash in order to collect a crash dump, what you are seeing is the default Watson behavior for unhandled exceptions.

    Ryan

    Friday, October 12, 2012 7:11 PM
  • I would need an actual crash dump, the logs are not helpful.

    Ryan

    Monday, October 15, 2012 2:41 PM
  • here's a dump from the "do you want to send more information  about this problem" window:

    http://wikisend.com/download/934688/WER4789.tmp.mdmp

    "the thread tried to read from or write to a virtual address to which it does not have access"


    R.R

    Monday, October 15, 2012 10:15 PM
  • Can you share the extension causing this? The dump shows that it is the OS (ole32) throwing the exception when we try to free a string. This kind of thing generally means some kind of corruption has occured and the thing we are trying to free is foobar. Do you have any other extensions installed in the VS instance that is running your extension or is it an empty Experimental Instance with just your extension installed?

    Ryan

    Monday, October 15, 2012 10:55 PM
  • Ryan,

    Thanks for helping me.

    When debugging a package the instance of VS loaded without any other packages\addons.

    the code you see above is not the latest code, I also changed the toolbar button tooltip... I did not think that this is my problem but here's the latest code sample:

    private void ChangeActivateButton()
            {
    if(activate == null) //declared at class level
    {
                CommandBar menuBarCommandBar = ((CommandBars)m_devEnv2.CommandBars)["Super Build Toolbar"];
                CommandBarControl toolsControl = menuBarCommandBar.Controls["Activate/Deactivate"];
                activate = toolsControl as CommandBarButton;
                m_prevPic = activate.Picture;//save the default old object of the picture
    }
                if (m_activated)
                {
                    //activate                
                    activate.Picture = m_picGreen;
                    activate.TooltipText ="Addon is enable";
                }
                else
                {
                    //deactivate
                    activate.Picture = m_picRed;
                    activate.TooltipText ="Addin is disable";
                }
            }


    basically, I moved the declaration of the CommandBarButton to the class level and I also save the old image of the button, When closing the addon I replace the images to the default:

    protected override int QueryClose(out bool canClose)
            {
                m_picGreen = null;
                m_picRed = null;
                activate.Picture = m_oldPic;
                return base.QueryClose(out canClose);
            } 

     I thought the problem was the deallocation of the image but you say the problem is the deallocation of a string.. maybe the tooltipText that changed during the run?

    Let me check by commenting the update of the tooltipText and I'll get back to you.

    Thanks!

    Roy 


    R.R


    Tuesday, October 16, 2012 7:00 AM
  • Changing the image back likely wouldn't help, we don't do any kind of bit differencing to detect that it is the 'original' image, so we would save it as a customized image just the same. From the crash I can't tell what is going on, it claims OLE is crashing on a string free, but this is RET optimized C++ so the debugger could also be confused. Reproing it on a CHK build would be preferable, which is why I wondered if you had a stand alone repro including images you are using, etc..

    Ryan

    Tuesday, October 16, 2012 8:46 PM
  • Hi,

    I have some progress on this, that might help:

    I refactored the following code to a new method:

    CommandBar menuBarCommandBar = ((CommandBars)m_devEnv2.CommandBars)["Super Build Toolbar"];
    CommandBarControl toolsControl = menuBarCommandBar.Controls["Activate/Deactivate"];
    activate = toolsControl as CommandBarButton;

    I realized that if the this new method is not called, the VS closed without the crash, and if the method is called, it crahses the VS on close.

    when I changed the code to this:

    CommandBar menuBarCommandBar = ((CommandBars)m_devEnv2.CommandBars)["Super Build Toolbar"];
    return;
    CommandBarControl toolsControl = menuBarCommandBar.Controls["Activate/Deactivate"];
    activate = toolsControl as CommandBarButton;
    

    it also crashes the VS!
    meaning the problem is getting the CommandBar object...

    so it's not the iomage problem at all...

    Roy


    R.R

    Wednesday, November 14, 2012 5:02 PM
  • I would need a full repro project, guessing from code snippets will not be fruitful.

    Also this is 2010 SP1 correct?

    Ryan

    Wednesday, November 14, 2012 5:35 PM