visual-studiovisual-studio-2022visual-studio-extensionsvsix

Add submenu to existing Visual Studio extension menu


I created a Visual Studio menu extension that I deploy via a VSIX package; now I need to create a new VSIX package to add submenus to the previous one.

I have created a Visual Studio extension menu (A) via a VSIX project, that contains a button.

First extension result:

First extension result

Now I'm trying to create a second VSIX project, and my goal is to create a submenu (B) that is child of (A), by preserving all the pre-existing buttons; I need to create a sort of modular behavior, so I cannot create just a single VSIX project.

However, when I try and install the second VSIX package, it seems that it overwrites the first extension, and I see only the second.

Second extension result:

Second extension result

My wanted goal is as shown in the following picture:

Expected result

I already found this other question and I tried what it suggested, but with no luck.

The file *.vsct of the first project is

<?xml version="1.0" encoding="utf-8"?>
<CommandTable ...>

    <Extern href="stdidcmd.h" />
    <Extern href="vsshlids.h" />

    <Commands package="guidMyTestVSPackage">

        <Menus>
            <Menu guid="guidMyTestPackageCmdSet" id="TopMenu" priority="0x100" type="Menu">
                <Parent guid="guidSHLMainMenu" id="IDG_VS_MM_TOOLSADDINS" />
                <Strings>
                    <ButtonText>MyApp</ButtonText>
                </Strings>
            </Menu>
        </Menus>

        <Groups>
            <Group guid="guidAboutPackageCmdSet" id="MyTestAboutMenuGroup" priority="0x0E00">
                <Parent guid="guidMyTestPackageCmdSet" id="TopMenu" />
            </Group>
        </Groups>

        <Buttons>
            <Button guid="guidAboutPackageCmdSet" id="cmdidAboutCommand" priority="0x0100" type="Button">
                <Parent guid="guidAboutPackageCmdSet" id="MyTestAboutMenuGroup" />
                <Strings>
                    <ButtonText>About</ButtonText>
                </Strings>
            </Button>
        </Buttons>

    </Commands>

    <Symbols>
        <!-- This is the package guid. -->
        <GuidSymbol name="guidMyTestVSPackage" value="{212cdc15-f054-46cf-8db5-a4e2a75c0d1e}" />

        <GuidSymbol name="guidMyTestPackageCmdSet" value="{2ca5942d-9e0f-48cb-9eb8-a979358ff308}">
            <IDSymbol name="TopMenu" value="0x1022" />
        </GuidSymbol>

        <GuidSymbol name="guidAboutPackageCmdSet" value="{4b9c6cc9-e54e-4ded-84ff-161c3bde5ad7}">
            <IDSymbol value="4128" name="MyTestAboutMenuGroup" />
            <IDSymbol value="256" name="cmdidAboutCommand" />
        </GuidSymbol>

    </Symbols>

</CommandTable>

The file *.vsct of the second project is

<?xml version="1.0" encoding="utf-8"?>
<CommandTable ...>

    <Extern href="stdidcmd.h" />
    <Extern href="vsshlids.h" />

    <Commands package="guidMyTestVSPackage">

        <Menus>
            <Menu guid="guidMyTestPackageCmdSet" id="TopMenu" priority="0x100" type="Menu">
                <Parent guid="guidSHLMainMenu" id="IDG_VS_MM_TOOLSADDINS" />
                <Strings>
                    <ButtonText>MyApp</ButtonText>
                </Strings>
            </Menu>
            <Menu guid="guidMyTestPackageCmdSet2" id="testMenu" priority="0x100" type="Menu">
                <Parent guid="guidMyTestPackageCmdSet2" id="MyAppMenuGroup" />
                <Strings>
                    <ButtonText>MyTest 2023</ButtonText>
                </Strings>
            </Menu>
        </Menus>

        <Groups>
            <Group guid="guidMyTestPackageCmdSet2" id="MyAppMenuGroup" priority="0x0000">
                <Parent guid="guidMyTestPackageCmdSet" id="TopMenu"/>
            </Group>
            <Group guid="guidMyTestPackageCmdSet2" id="testMenuGroup" priority="0x0000">
                <Parent guid="guidMyTestPackageCmdSet2" id="testMenu"/>
            </Group>
            <Group guid="guidMyTestPackageCmdSet2" id="MyTestMenuGroup" priority="0x0600">
                <Parent guid="guidMyTestPackageCmdSet2" id="testMenu" />
            </Group>
    </Groups>

        <Buttons>
            <Button guid="guidMyTestPackageCmdSet2" id="MyTestCommandId" priority="0x0100" type="Button">
                <Parent guid="guidMyTestPackageCmdSet2" id="MyTestMenuGroup" />
                <Strings>
                    <ButtonText>Add MyTest NuGet Package</ButtonText>
                </Strings>
            </Button>
        </Buttons>

    </Commands>

    <Symbols>
        <!-- This is the package guid. -->
        <GuidSymbol name="guidMyTestVSPackage" value="{212cdc15-f054-46cf-8db5-a4e2a75c0d1f}" />

        <GuidSymbol name="guidMyTestPackageCmdSet" value="{2ca5942d-9e0f-48cb-9eb8-a979358ff308}">
            <IDSymbol name="TopMenu" value="0x1022" />
        </GuidSymbol>

        <GuidSymbol name="guidMyTestPackageCmdSet2" value="{2ca5942d-9e0f-48cb-9eb8-a979358ff309}">
            <IDSymbol name="testMenu" value="0x1021" />
            <IDSymbol name="testMenuGroup" value="0x1026" />
            
            <IDSymbol name="MyAppMenuGroup" value="0x1023" />
            <IDSymbol name="MyTestMenuGroup" value="0x1020" />
            <IDSymbol name="MyTestCommandId" value="0x0100" />
        </GuidSymbol>

    </Symbols>

</CommandTable>

Solution

  • I managed to achieve what I wanted, I post the details, in case someone will have the same issue.

    I create the first .vsct as described in the original question, where I defined the main menu MyMenu and the common menu items.

    In the second .vsct I added the references to the Menu and MenuGroup and use them. I shouldn't also add MyMenu to Menus in this .csvt. Another mistake I took is to set MyMenu as parent of the new menu items, instead of its group MyMenuGroup.

    For completeness sake, the first .vsct is as follows:

    <?xml version="1.0" encoding="utf-8"?>
    <CommandTable xmlns="..." xmlns:xs="...">
        <Extern href="stdidcmd.h"/>
        <Extern href="vsshlids.h"/>
        <Commands package="guidCommonPackage">
            <Menus>
                <Menu guid="guidCommonPackageCmdSet" id="MyMenu" priority="0x100">
                    <Parent guid="guidSHLMainMenu" id="IDG_VS_MM_TOOLSADDINS"/>
                    <Strings>
                        <ButtonText>Common Menu</ButtonText>
                    </Strings>
                </Menu>
            </Menus>
            <Groups>
                <Group guid="guidCommonPackageCmdSet" id="MyMenuGroup" priority="0x0600">
                    <Parent guid="guidCommonPackageCmdSet" id="MyMenu"/>
                </Group>
            </Groups>
            <Buttons>
                <Button guid="guidCommonPackageCmdSet" id="AboutId" priority="0x0100" type="Button">
                    <Parent guid="guidCommonPackageCmdSet" id="MyMenuGroup"/>
                    <Icon guid="guidImages" id="bmpPic1"/>
                    <Strings>
                        <ButtonText>About</ButtonText>
                    </Strings>
                </Button>
            </Buttons>
            <Bitmaps>
                <Bitmap guid="guidImages" href="Resources\About.png" usedList="bmpPic1, bmpPic2, bmpPicSearch, bmpPicX, bmpPicArrows, bmpPicStrikethrough"/>
            </Bitmaps>
        </Commands>
        <Symbols>
            <!-- This is the package guid. -->
            <GuidSymbol name="guidCommonPackage" value="{cd573a98-a4dc-4c94-abc9-44ff2f1d3485}"/>
            <GuidSymbol name="guidCommonPackageCmdSet" value="{a984ac26-be55-44b2-bc4e-ab1e79b6e875}">
                <IDSymbol name="MyMenu" value="0x1010"/>
                <IDSymbol name="MyMenuGroup" value="0x1020"/>
                <IDSymbol name="AboutId" value="0x0100"/>
            </GuidSymbol>
            <GuidSymbol name="guidImages" value="{9ef0bc86-5032-4135-b94e-bd4bc76112ed}">
                <IDSymbol name="bmpPic1" value="1"/>
                <IDSymbol name="bmpPic2" value="2"/>
                <IDSymbol name="bmpPicSearch" value="3"/>
                <IDSymbol name="bmpPicX" value="4"/>
                <IDSymbol name="bmpPicArrows" value="5"/>
                <IDSymbol name="bmpPicStrikethrough" value="6"/>
            </GuidSymbol>
        </Symbols>
    </CommandTable>
    

    The second .vsct is:

    <?xml version="1.0" encoding="utf-8"?>
    <CommandTable xmlns="..." xmlns:xs="...">
        <Extern href="stdidcmd.h"/>
        <Extern href="vsshlids.h"/>
        <Commands package="guidModule3Package">
            <Menus>
                <Menu guid="guidModule3PackageCmdSet" id="SubMenu" priority="0x1000">
                    <Parent guid="guidCommonPackageCmdSet" id="MyMenuGroup"/>
                    <Strings>
                        <ButtonText>Sub Menu</ButtonText>
                    </Strings>
                </Menu>
            </Menus>
            <Groups>
                <Group guid="guidModule3PackageCmdSet" id="SubMenuGroup" priority="0x0600">
                    <Parent guid="guidModule3PackageCmdSet" id="SubMenu"/>
                </Group>
            </Groups>
            <Buttons>
                <Button guid="guidModule3PackageCmdSet" id="Command3Id" priority="0x0100" type="Button">
                    <Parent guid="guidModule3PackageCmdSet" id="SubMenuGroup"/>
                    <Icon guid="guidImages" id="bmpPic1"/>
                    <Strings>
                        <ButtonText>Invoke Command3</ButtonText>
                    </Strings>
                </Button>
            </Buttons>
            <Bitmaps>
                <Bitmap guid="guidImages" href="Resources\Command3.png" usedList="bmpPic1, bmpPic2, bmpPicSearch, bmpPicX, bmpPicArrows, bmpPicStrikethrough"/>
            </Bitmaps>
        </Commands>
        <Symbols>
            <GuidSymbol name="guidModule3Package" value="{8e7e1e97-c2a2-4bff-bc8f-788088b4f349}"/>
            <GuidSymbol name="guidCommonPackageCmdSet" value="{a984ac26-be55-44b2-bc4e-ab1e79b6e875}">
                <IDSymbol name="MyMenu" value="0x1010"/>
                <IDSymbol name="MyMenuGroup" value="0x1020"/>
            </GuidSymbol>
            <GuidSymbol name="guidModule3PackageCmdSet" value="{614f17f3-962b-4cbd-a34d-aaf0346d5ec7}">
                <IDSymbol name="SubMenu" value="0x1110"/>
                <IDSymbol name="SubMenuGroup" value="0x1120"/>
                <IDSymbol name="Command3Id" value="0x0100"/>
            </GuidSymbol>
            <GuidSymbol name="guidImages" value="{7c725fe5-b35f-438a-a637-daeea16254a4}">
                <IDSymbol name="bmpPic1" value="1"/>
                <IDSymbol name="bmpPic2" value="2"/>
                <IDSymbol name="bmpPicSearch" value="3"/>
                <IDSymbol name="bmpPicX" value="4"/>
                <IDSymbol name="bmpPicArrows" value="5"/>
                <IDSymbol name="bmpPicStrikethrough" value="6"/>
            </GuidSymbol>
        </Symbols>
    </CommandTable>
    

    The final result, as expected: FinalResult