Add project menu option RRS feed

  • Question

  • Hi All,

    I have created a custom template and I need to access it same way we can access the "Class..." and "Components..." in the project menu option.

    Ex: C# class can be directly add by right clicking on project in the solution explore >> "Add" >> "Class"

    This will directly select to the "C#" class template in "Add New Item" dialog.

    First thing I want know is, how can I add menu option to the project menu >> "Add" sub menu?

    Finally, how can I select my template directly when I select menu option.



    Tuesday, October 13, 2009 4:01 AM


All replies

  • Hi, Dushantha
    Create a small vspackage with a menu could satisfy your needs.  You firstly create a small wizard with a menu command and then change the parent of the created menu Command ID in the VSCT file.
      <Group guid="guidVSPackage4CmdSet" id="MyMenuGroup" priority="0x0600">
            <Parent guid="guidSHLMainMenu" id="IDM_VS_CTXT_PROJNODE"/>
    MyMenuGroup is your own menu group, and IDM_VS_CTXT_PROJNODE is your Context Menu Identifier, when you right click the project Node.(Sorry for not finding the Add Sub menu, because it is really hard to find the Add Sub menu identifier). The follow two links describe the VSCT XML file very clearly, you could learn from it.
    For your second quesion. I think you can add your own item by using the EnvDTE.ProjectItems.AddFromTemplate method in the method CallBack funciton of your menu command.

    Wednesday, October 14, 2009 10:45 AM
  • Hi Chao,

    Menu can be added to the "Add" submenu by parenting the button to,

    <Parent guid="guidSHLMainMenu" id="IDM_VS_CSCD_PROJECT_ADD"/>

    Still I coundn't find a solution to my second quesion. But found a blog explaning how to do that. But the difficulty is to find correct parameters for "AddProjectItemDlg" method.

    If you have any clue let me know.



    • Marked as answer by Dushantha Saturday, October 17, 2009 8:11 AM
    Thursday, October 15, 2009 5:58 AM
  • Hi,

    in case you or someone else still needs a detailed solution to this problem here is what I've done based on the thread
    and some other resources such as

    I actually integrated the solution to this problem into the VS 2008 SDK example SampleDocViewEditor in order to create a new AddIn file based on the template provided by this example and you can download the code from here :

    The example did not originally contain a vsct file so it is pretty simple, just the code necessary for this Item
    - adding a vsct file to the project that does not contain it as another thing ... if you want to do that checkout this post first


    It applies to VS 2008 as well and explains how to manually edit the csproj file in order for the newly created vsct file to be processed by the compiler.
    You can also checkout a csproj file for an example that already contains a vsct file and make sure yours have the same ... I lost quite some time trying to figure out what's wrong before I noticed the BuildAction property on the vsct file :(
    And of course you need to add ProvideMenuResource attribute to your package.

    Anyway, the first thing to do is to add an item to the solution explorer context menu subgroup "Add", with your item name (I used "AddIn" from the example), and you do this by adding the appropriate tags to your vsct file.

    <?xml version="1.0" encoding="utf-8"?>
    <CommandTable xmlns="http://schemas.microsoft.com/VisualStudio/2005-10-18/CommandTable" xmlns:xs="http://www.w3.org/2001/XMLSchema">
    	<!--This is the file that defines the IDs for all the commands exposed by VisualStudio. -->
    	<Extern href="stdidcmd.h"/>
    	<!--This header contains the command ids for the menus provided by the shell. -->
    	<Extern href="vsshlids.h"/>
    	<!--Definition of some VSCT specific constants. In this sample we use it for the IDs inside the guidOfficeIcon group. -->
    	<Extern href="msobtnid.h"/>
    	<Commands package="guidSampleDocViewEditorPkg">
    			<!-- Add New AddIN -->
    			<!-- sln explorer context menu -->
    			<Group guid="guidCmdSet" id="SlnCntxMenuAddNewAddInGroup" priority="0x0102" >
    				<Parent guid="guidSolutionExplorer" id="AddGroup"/>
    			<!--Add -> New AddIn button--> 
    			<Button guid="guidCmdSet" id="cmdidAddAddIn" priority="0x100" type="Button">
    				<Parent guid="guidCmdSet" id="SlnCntxMenuAddNewAddInGroup"/>
    				<Icon guid="guidOfficeIcon" id="msotcidNewForm"/>
    					<ButtonText>Add In</ButtonText>
    		<!-- This is the package guid. -->
    		<GuidSymbol name="guidSampleDocViewEditorPkg" value="{9225FE25-D0F6-496b-9A0D-70136A98E890}" />
    		<!-- This is the guid used to group the menu commands together -->
    		<GuidSymbol name="guidCmdSet" value="{31323F46-02E5-4d12-B68A-71253CE97DE9}">
    			<IDSymbol name="SlnCntxMenuAddNewAddInGroup" value="0x1025" />
    			<IDSymbol name="cmdidAddAddIn" value="0x111" />
    		<!--Solution explorer context menu--> 
    		<GuidSymbol name ="guidSolutionExplorer" value ="{D309F791-903F-11D0-9EFC-00A0C911004F}" >
    			<IDSymbol name ="ContextMenuGroup" value="1072" />
    			<IDSymbol name ="AddGroup" value="850" />

    I presume that you are familiar with the vsct file ... we have here one group placed in the Solution Expolorer context menu subgroup "Add", and one button placed in the newly created group.
    So the catch was to get the right GUID:ID pair for the context menu and the "Add" subgroup.
    If you want to place your menu item directly in the context menu group you can use <IDSymbol name ="ContextMenuGroup" value="1072" />
    Or you can find any GUID:id pair you want using this approach:

    The next thing is to Add the command handler and use the IVsAddProjectItemDlg::AddProjectItemDlg method with the right parameters.

    	public class VSPackage : Package, IDisposable
    		// ...
    		protected override void Initialize()
    			Trace.WriteLine(string.Format(CultureInfo.CurrentCulture, "Entering Initialize() of: {0}", this.ToString()));
    			//Create Editor Factory
    			editorFactory = new EditorFactory();
    			// Create the command for the "Add -> AddIn" menu item.
    			System.ComponentModel.Design.CommandID addNewAddInID = new System.ComponentModel.Design.CommandID(GuidList.guidCmdSet, PkgCmdIDList.cmdidAddAddIn);
    			OleMenuCommand addNewAddInMenuCommand = DefineCommandHandler(new EventHandler(this.addNewAddIn), addNewAddInID);
    		/// <summary>
    		/// Define a command handler.
    		/// When the user press the button corresponding to the CommandID
    		/// the EventHandler will be called.
    		/// </summary>
    		/// <param name="id">The CommandID (Guid/ID pair) as defined in the .vsct file</param>
    		/// <param name="handler">Method that should be called to implement the command</param>
    		/// <returns>The menu command. This can be used to set parameter such as the default visibility once the package is loaded</returns>
    		internal OleMenuCommand DefineCommandHandler(EventHandler handler, CommandID id)
    			// if the package is zombied, we don't want to add commands
    			if (this.Zombied)
    				return null;
    			OleMenuCommandService menuService;
    			// Get the OleCommandService object provided by the MPF; this object is the one
    			// responsible for handling the collection of commands implemented by the package.
    			menuService = GetService(typeof(System.ComponentModel.Design.IMenuCommandService)) as OleMenuCommandService;
    			OleMenuCommand command = null;
    			if (null != menuService)
    				// Add the command handler
    				command = new OleMenuCommand(handler, id);
    			return command;
    		public void addNewAddIn(object sender, EventArgs e)
    			EnvDTE.DTE dte = GetGlobalService(typeof(EnvDTE.DTE)) as EnvDTE.DTE;
    			if (dte == null)
    			string strFilter = String.Empty;
    			int iDontShowAgain;
    			uint projectItemId;
    			IVsHierarchy hierarchy = getCurrentVSHierarchySelection(out projectItemId);
    			if (hierarchy == null)
    			Project project = ToDteProject(hierarchy);
    			if (project == null)
    			IVsProject vsProject = ToVsProject(project);
    			if (vsProject == null)
    			IVsAddProjectItemDlg addItemDialog = this.GetService(typeof(IVsAddProjectItemDlg)) as IVsAddProjectItemDlg;
    			if (addItemDialog == null)
    			uint uiFlags = (uint)(__VSADDITEMFLAGS.VSADDITEM_AddNewItems | __VSADDITEMFLAGS.VSADDITEM_SuggestTemplateName | __VSADDITEMFLAGS.VSADDITEM_AllowHiddenTreeView);
    			Guid projGuid = new Guid(project.Kind);//new Guid("FAE04EC0-301F-11D3-BF4B-00C04F79EFBC"); // c#
    			string projectDirectoryPath = "";
    			hierarchy.GetCanonicalName(projectItemId, out projectDirectoryPath);
    			string categoryNameInNewFileDialog = Resources._106;//"SampleDocViewEditor";
    			string itemNameInNewFileDialog = Resources._108; // "SampleDocViewEditor (AddIn) file";
    			addItemDialog.AddProjectItemDlg(projectItemId, ref projGuid, vsProject, uiFlags, categoryNameInNewFileDialog, itemNameInNewFileDialog, ref projectDirectoryPath, ref strFilter, out iDontShowAgain);
    		public IVsHierarchy getCurrentVSHierarchySelection(out uint projectItemId)
    			IntPtr hierarchyPtr, selectionContainerPtr;
    			projectItemId = 0;
    			IVsMultiItemSelect mis;
    			IVsMonitorSelection monitorSelection = (IVsMonitorSelection)Package.GetGlobalService(typeof(SVsShellMonitorSelection));
    			monitorSelection.GetCurrentSelection(out hierarchyPtr, out projectItemId, out mis, out selectionContainerPtr);
    			IVsHierarchy hierarchy = Marshal.GetTypedObjectForIUnknown(hierarchyPtr, typeof(IVsHierarchy)) as IVsHierarchy;
    			return hierarchy;
    		public EnvDTE.Project ToDteProject(IVsHierarchy hierarchy)
    			if (hierarchy == null) throw new ArgumentNullException("hierarchy");
    			object prjObject = null;
    			if (hierarchy.GetProperty(0xfffffffe, (int)__VSHPROPID.VSHPROPID_ExtObject, out prjObject) == VSConstants.S_OK)
    				return (EnvDTE.Project)prjObject;
    				throw new ArgumentException("Hierarchy is not a project.");
    		public IVsProject ToVsProject(EnvDTE.Project project)
    			if (project == null) 
    				throw new ArgumentNullException("project");
    			IVsProject vsProject = null;
    			IVsSolution vsSln = GetService(typeof(IVsSolution)) as IVsSolution;
    			if (vsSln != null)
    				IVsHierarchy vsHierarchy;
    				vsSln.GetProjectOfUniqueName(project.UniqueName, out vsHierarchy);
    				vsProject = vsHierarchy as IVsProject;
    				if (vsProject != null)
    					return vsProject;
    			throw new ArgumentException("Project is not a VS project.");
    		// ...

    Hope this helps someone :)

    Best regards,

    Wednesday, December 23, 2009 2:11 AM