如何:在外接程序按钮上显示自定义图标

更新:2007 年 11 月

您可以将显示在外接程序命令旁边的默认图标(笑脸)替换为如何:更改外接程序的默认图标中所列出预定义标准图标以外的某个图标。

具体方法为:

  • 将图标位图作为资源放置在附属 DLL 文件中。

  • AddNamedCommand2 方法中的 MSOButton 参数设置为 false(此设置通知该方法在附属 DLL 中查找图标位图)。

  • 在外接程序项目的命令栏部分中引用该资源的 ID 号。

下面的过程演示如何将自定义图标添加到外接程序按钮。

ms228771.alert_note(zh-cn,VS.90).gif说明:

显示的对话框和菜单命令可能会与“帮助”中的描述不同,具体取决于您现用的设置或版本。这些过程是使用“常规开发设置”开发的。若要更改设置,请在“工具”菜单上选择“导入和导出设置”。有关更多信息,请参见 Visual Studio 设置

将自定义位图作为外接程序按钮图标添加到外接程序项目

  1. 打开一个现有的外接程序解决方案,或者在 Visual Studio 中创建一个新的外接程序解决方案。

    如果创建一个新的外接程序,请确保选中“要为您的外接程序创建命令栏用户界面吗?”选项。

  2. 将新的资源文件添加到您的外接程序项目。具体方法为:

    1. 在“解决方案资源管理器”中右击该外接程序项目。

    2. 在“添加”菜单上选择“新建项”。

    3. 在“模板”列表中选择“资源文件”,然后单击“添加”按钮。保留其默认名称 (Resources1.resx)。

      这将启动 Visual Studio“资源编辑器”。

  3. 在“解决方案资源管理器”的工具栏上单击“显示所有文件”按钮。

  4. 在 Resource1.resx 的属性中,将“生成操作”属性设置为“无”。

    外接程序需要一个整数值作为位图参数。设置此属性使您可以编辑资源文件并使用数字标识符命名其位图资源(如果 .resx 文件是外接程序项目的一部分则无法执行某些操作)。

  5. 在“资源编辑器”中,单击“添加资源”,然后在“新建图像”菜单上选择“BMP 图像”。现在,保留其默认名称 (Image1.bmp)。

    或者,您可以选择一幅现有的 16 x 16 像素的位图图像(16 色或真彩皆可)。外接程序的自定义图标必须是 16 x 16 像素,并且必须是 16 色或真彩色。

  6. 在位图属性窗口中,将“高度”和“宽度”属性都更改为 16。将“颜色”属性设置为 16 色或真彩色。

  7. 如果您创建了新的位图,则可在“资源编辑器”中编辑该图片。

  8. 在“解决方案资源管理器”中右击 Resource1.resx 文件,然后选择“从项目中排除”。

    执行此操作可避免不必要的编译器错误。该文件无需位于项目中。这就允许您使用内置的“资源编辑器”。

  9. 打开外接程序的 Connect 类。在 AddNamedCommand2 行的 OnConnection 方法中,将 MSOButton 参数值从 true 更改为 false,将 Bitmap 参数值从 59 更改为 1。例如:

    command = commands.AddNamedCommand2(_addInInstance, "MyAddin1", " 
    MyAddin1", "Executes the command for MyAddin1", False, 1, Nothing, 
    CType(vsCommandStatus.vsCommandStatusSupported, Integer) + 
    CType(vsCommandStatus.vsCommandStatusEnabled, Integer), 
    vsCommandStyle.vsCommandStylePictAndText, 
    vsCommandControlType.vsCommandControlTypeButton)
    
    Command command = commands.AddNamedCommand2(_addInInstance, 
    "MyAddin1", "MyAddin1", "Executes the command for MyAddin1", false, 
    1, ref contextGUIDS, 
    (int)vsCommandStatus.vsCommandStatusSupported+(int)vsCommandStatus.
    vsCommandStatusEnabled, (int)vsCommandStyle.vsCommandStylePictAndText, 
    vsCommandControlType.vsCommandControlTypeButton);
    

    将 MSOButton 参数设置为 false 会强制外接程序通过查找资源文件来获得其按钮位图。数字 1 将是该位图的标识符。(它是在稍后的步骤中设置的。)

  10. 完成此操作后,在“文件”菜单上选择“全部保存”,在“生成”菜单上选择“生成解决方案”,然后关闭该解决方案。

  11. 在“Windows 资源管理器”中,使用“记事本”编辑 Resource1.resx 文件。

  12. 搜索“Image1”的所有实例,并将它们更改为“1”。完成此操作后,保存该文件。

  13. 在外接程序的 \Resources 文件夹中,将位图文件名从 Image1.bmp 更改为 1.bmp。

  14. 使用 ResGen 和程序集链接器 (AL) 生成附属 DLL。具体方法为:

    1. 在“开始”菜单上,指向“所有程序”,指向“Microsoft Visual Studio 2005”,指向“Visual Studio 工具”,然后单击“Visual Studio 命令提示”。

      这将设置某些环境变量,以便您可以更轻松地引用 Visual Studio 工具。

    2. 在命令提示符下,转到包含 .resx 文件的文件夹并键入 Resgen Resource1.resx

      Resgen 是将指定的 .resx 文件编译为 .resources 文件的实用工具。有关更多信息,请参见资源文件生成器 (Resgen.exe)

    3. 再次在命令提示符下,键入下列命令:Al.exe /embed:Resource1.resources /culture:en-US /out:<Add-In Name>.resources.dll

      将 <Add-In Name> 替换为您的外接程序的名称。例如,如果您的外接程序项目命名为 MyAddin1,则 /out: 开关将为 /out:MyAddin1.resources.dll。如果 /out: 名称与您的项目名称不匹配,则将找不到资源 DLL。

      程序集链接器 (Al.exe) 将指定的 .resources 文件转换为可以在外接程序中引用的附属资源 DLL。(您可以将 /culture 开关更改为英语以外的一种语言。)有关更多信息,请参见程序集链接器 (Al.exe)

  15. 使用“Windows 资源管理器”,浏览到外接程序的 DLL 目录(通常为 \bin 文件夹)并创建一个名为 en-US(表示美国英语,因为您键入了 en-US 作为 Al 中的区域性的值)的文件夹。

  16. 将 <Add-In Name>.resources.dll 文件复制到新的 en-US 文件夹。

  17. 在 Visual Studio 中,再次打开外接程序项目并运行它。

  18. 单击“工具”菜单。

    外接程序即显示在“工具”菜单上,并带有您的自定义图标。

将一个自定义位图作为外接程序按钮图标添加到本机 Visual C++ 外接程序

  1. 按照上述的相同过程执行操作,但更改下列项。

  2. 创建新的 Visual C++ Win32 DLL 项目。

  3. 添加资源文件 (.rc)。

  4. 在资源视图中,添加一个位图 (16 x 16) 并为它指定一个数值 ID。

    该位图必须是 16 x 16 像素并且为 16 色或真彩色。

  5. 在 Connect.cpp 中更新 AddNamedCommand2 方法,方法是将 MSOButton 设置为 VARIANT_FALSE,并将 Bitmap 设置为以前指定的位图 ID。

  6. 生成 DLL。

  7. 在本机外接程序 DLL 目录中创建子文件夹“1033”(用于“英语”区域设置)。

  8. 将附属 DLL 复制到“1033”目录。

  9. 打开 AddIn.rgs 并添加两个注册表项值“SatelliteDllName”和“SatelliteDllPath”。例如:

    HKCU
    {
       NoRemove 'SOFTWARE'
       {
          NoRemove 'Microsoft'
          {
             NoRemove 'VisualStudio'
             {
                NoRemove '8.0'
                {
                   NoRemove 'AddIns'
                   {
                      ForceRemove 
                        'NativeAddinCustBitmap.Connect'
                         {
                           val LoadBehavior = d 0
                           val CommandLineSafe = d 0
                           val CommandPreload = d 1
                           val FriendlyName = s 'NativeAddinCustBitmap'
                           val Description = s 'NativeAddinCustBitmap 
                             Description'
                           val SatelliteDllName = s  
                             'NativeAddinCustBitmapUI.dll'
                           val SatelliteDllPath = s 
                             'C:\Test\CustomBitmap\NativeAddinCustBitmap
                             \NativeAddinCustBitmap\Debug'
                         }
                      }
                   }
                }
             }
          }
       }
    

    在“SatelliteDllPath”中,不要在路径中添加区域设置 ID。它将在运行时自动追加。

  10. 重新生成外接程序以注册更新后的信息。

示例

下面是 Visual Basic/Visual C#/Visual J# 外接程序的一个完整的外接程序代码示例,它引用了包含在附属资源 DLL 中的自定义图标。

Imports System
Imports Microsoft.VisualStudio.CommandBars
Imports Extensibility
Imports EnvDTE
Imports EnvDTE80

Public Class Connect

    Implements IDTExtensibility2
Implements IDTCommandTarget

    Dim _applicationObject As DTE2
    Dim _addInInstance As AddIn

    Public Sub New()

    End Sub

    Public Sub OnConnection(ByVal application As Object, _
      ByVal connectMode As ext_ConnectMode, ByVal addInInst _
      As Object, ByRef custom As Array) Implements _
      IDTExtensibility2.OnConnection
        _applicationObject = CType(application, DTE2)
        _addInInstance = CType(addInInst, AddIn)
        If connectMode = ext_ConnectMode.ext_cm_UISetup Then

            Dim commands As Commands2 = CType(_applicationObject. _
              Commands, Commands2)
            Dim toolsMenuName As String
            Try

                ' To move the command to a different 
                ' menu, change the word, Tools, to the English version 
                ' of the menu. This code will take the culture, append 
                ' the name of the menu, and then add the command to 
                ' that menu. A list of all the top-level menus is 
                ' in the file, CommandBar.resx.
                Dim resourceManager As System.Resources. _
                  ResourceManager = New System.Resources. _
                  ResourceManager("MyAddin3.CommandBar", _
                  System.Reflection.Assembly.GetExecutingAssembly())

                Dim cultureInfo As System.Globalization.CultureInfo _
                  = New System.Globalization. _
                  CultureInfo(_applicationObject.LocaleID)
                toolsMenuName = resourceManager.GetString(String. _
                  Concat (cultureInfo.TwoLetterISOLanguageName, _
                  "Tools"))

            Catch e As Exception
                ' We tried to find a localized version of the word, 
                ' Tools, but one was not found. Default to the en-US 
                ' word, which may work for the current culture.
                toolsMenuName = "Tools"
            End Try

            ' Place the command on the Tools menu.
            ' Find the MenuBar command bar, which is the top-level 
            ' command bar holding all the main menu items:
            Dim commandBars As CommandBars = _
              CType(_applicationObject.CommandBars, _
              CommandBars)
            Dim menuBarCommandBar As CommandBar = _
              commandBars.Item("MenuBar")

            ' Find the Tools command bar on the MenuBar command bar.
            Dim toolsControl As CommandBarControl = _
              menuBarCommandBar.Controls.Item(toolsMenuName)
            Dim toolsPopup As CommandBarPopup = CType(toolsControl, _
              CommandBarPopup)

            Try
                ' Add a command to the Commands collection.
                Dim command As Command = _
                  commands.AddNamedCommand2(_addInInstance, _
                  "MyAddin3", "MyAddin3", "Executes the command for _
                  MyAddin3", False, 1, Nothing, _
                  CType(vsCommandStatus.vsCommandStatusSupported, _
                  Integer) + CType(vsCommandStatus. _
                  vsCommandStatusEnabled, Integer), _
                  vsCommandStyle.vsCommandStylePictAndText, _
                  vsCommandControlType.vsCommandControlTypeButton)

                ' Find the appropriate command bar on the MenuBar 
                ' command bar.
                command.AddControl(toolsPopup.CommandBar, 1)
            Catch argumentException As System.ArgumentException
                ' If we are here, then the exception is probably 
                ' because a command with that name already exists. If 
                ' so there is no need to recreate 
                ' the command and we can safely ignore the exception.
            End Try
        End If
    End Sub

    Public Sub OnDisconnection(ByVal disconnectMode As _
      ext_DisconnectMode, ByRef custom As Array) Implements _
      IDTExtensibility2.OnDisconnection
    End Sub

    Public Sub OnAddInsUpdate(ByRef custom As Array) Implements _
      IDTExtensibility2.OnAddInsUpdate
    End Sub

    Public Sub OnStartupComplete(ByRef custom As Array) Implements _
      IDTExtensibility2.OnStartupComplete
    End Sub

    Public Sub OnBeginShutdown(ByRef custom As Array) Implements _
      IDTExtensibility2.OnBeginShutdown
    End Sub

    Public Sub QueryStatus(ByVal commandName As String, ByVal _
      neededText As vsCommandStatusTextWanted, ByRef status As _
      vsCommandStatus, ByRef commandText As Object) Implements _
      IDTCommandTarget.QueryStatus
        If neededText = vsCommandStatusTextWanted. _
          vsCommandStatusTextWantedNone Then
            If commandName = "MyAddin3.Connect.MyAddin3" Then
                status = CType(vsCommandStatus.vsCommandStatusEnabled _
                  + vsCommandStatus.vsCommandStatusSupported, _
                  vsCommandStatus)
            Else
                status = vsCommandStatus.vsCommandStatusUnsupported
            End If
        End If
    End Sub

    Public Sub Exec(ByVal commandName As String, ByVal executeOption _
      As vsCommandExecOption, ByRef varIn As Object, ByRef varOut As _
      Object, ByRef handled As Boolean) Implements _
      IDTCommandTarget.Exec
        handled = False
        If executeOption = vsCommandExecOption. _
          vsCommandExecOptionDoDefault Then
            If commandName = "MyAddin3.Connect.MyAddin3" Then
                handled = True
                MsgBox("Add-in is running.")
                Exit Sub
            End If
        End If
    End Sub
End Class
using System;
using Extensibility;
using EnvDTE;
using EnvDTE80;
using Microsoft.VisualStudio.CommandBars;
using System.Resources;
using System.Reflection;
using System.Globalization;

namespace MyAddin1
{
    public class Connect : Object, IDTExtensibility2, IDTCommandTarget
    {
        public Connect()
        {
        }

    public void OnConnection(object application, ext_ConnectMode 
    connectMode, object addInInst, ref Array custom)
    {
        _applicationObject = (DTE2)application;
        _addInInstance = (AddIn)addInInst;
        if(connectMode == ext_ConnectMode.ext_cm_UISetup)
        {
            object []contextGUIDS = new object[] { };
            Commands2 commands = 
             (Commands2)_applicationObject.Commands;
            string toolsMenuName;

            try
            {
                ResourceManager resourceManager = new 
                ResourceManager("MyAddin1.CommandBar", 
                Assembly.GetExecutingAssembly());
                CultureInfo cultureInfo = new 
                  System.Globalization.CultureInfo
                  (_applicationObject.LocaleID);
                string resourceName =  String.Concat(cultureInfo.
                TwoLetterISOLanguageName, "Tools");
                toolsMenuName = 
                resourceManager.GetString(resourceName);
            }
            catch
            {
                toolsMenuName = "Tools";
            }

            CommandBar menuBarCommandBar = 
            ((CommandBars)_applicationObject.CommandBars)["MenuBar"];

            CommandBarControl toolsControl = 
            menuBarCommandBar.Controls[toolsMenuName];
            CommandBarPopup toolsPopup = (CommandBarPopup)toolsControl;

            try
            {
                Command command = 
                  commands.AddNamedCommand2(_addInInstance, "MyAddin1", 
                  "MyAddin1", "Executes the command for MyAddin1", 
                  false, 1, ref contextGUIDS, 
                  (int)vsCommandStatus.vsCommandStatusSupported+(int)
                  vsCommandStatus.vsCommandStatusEnabled,  
                  (int)vsCommandStyle.vsCommandStylePictAndText, 
                  vsCommandControlType.vsCommandControlTypeButton);

                if((command != null) && (toolsPopup != null))
                {
                    command.AddControl(toolsPopup.CommandBar, 1);
                }
            }
            catch
            {
            }
        }
    }

    public void OnDisconnection(ext_DisconnectMode disconnectMode, ref 
      Array custom)
    {
    }

    public void OnAddInsUpdate(ref Array custom)
    {
    }

    public void OnStartupComplete(ref Array custom)
    {
    }

    public void OnBeginShutdown(ref Array custom)
    {
    }
            
    public void QueryStatus(string commandName, 
      vsCommandStatusTextWanted neededText, ref vsCommandStatus status, 
      ref object commandText)
    {
        if(neededText == 
        vsCommandStatusTextWanted.vsCommandStatusTextWantedNone)
        {
            if(commandName == "MyAddin1.Connect.MyAddin1")
            {
                status = 
                (vsCommandStatus)vsCommandStatus.
                vsCommandStatusSupported|vsCommandStatus.
                vsCommandStatusEnabled;
            return;
            }
        }
    }

    public void Exec(string commandName, vsCommandExecOption 
    executeOption, ref object varIn, ref object varOut, ref bool 
    handled)
    {
        handled = false;
        if(executeOption == 
          vsCommandExecOption.vsCommandExecOptionDoDefault)
        {
            if(commandName == "MyAddin1.Connect.MyAddin1")
            {
                handled = true;
                System.Windows.Forms.MessageBox.Show("Add-in ran.");
                return;
            }
        }
    }
    private DTE2 _applicationObject;
    private AddIn _addInInstance;
    }
}

请参见

任务

如何:更改外接程序的默认图标

如何:将外接程序公开为工具栏上的按钮

概念

在工具栏和菜单上显示外接程序