1

我正在尝试创建 VSIX 包以在单击分支时扩展 TFS 2012 源代码控制右键单击上下文菜单的功能。我不想使用加载项。这必须是其他开发人员可以直接安装的包。安装扩展后,自定义菜单项需要出现在源代码管理资源管理器上下文菜单中。我无法获得任何满足此要求的样本或无法获得适当的文档来源。我找到的示例之一是“TFS 社区分支工具”,这是我正在寻找的类似功能,但我无法获得它的源代码。

感谢你的帮助。

4

3 回答 3

4

我假设您熟悉 .vsct 文件、命令/菜单/组 Guids/Id 的东西(所有这些都记录在 MSDN 中)。所以,问题是哪个是源代码管理资源管理器上下文菜单中组的 Guid/Id。

猜测您可能希望您的命令位于文件上下文菜单的“获取最新版本”菜单项下方,代码将是:

 <Commands package="guidVSMyPackagePkg">

     <Buttons>
      <Button guid="guidVSMyPackageCmdSet" id="cmdidMyCommand" priority="0x0100" type="Button">
         <Parent guid="guidSourceControlExplorerMenuGroup" id="SourceControlExplorerMenuGroupId"/>
        <Strings>
          <ButtonText>My Command</ButtonText>
        </Strings>
      </Button>
    </Buttons>
  </Commands>

  <Symbols>
    <GuidSymbol name="guidVSMyPackagePkg" value="{...}" />

    <GuidSymbol name="guidVSMyPackageCmdSet" value="{...}">
      <IDSymbol name="cmdidMyCommand" value="0x0100" />
    </GuidSymbol>

     <GuidSymbol name="guidSourceControlExplorerMenuGroup" value="{ffe1131c-8ea1-4d05-9728-34ad4611bda9}">
         <IDSymbol name="SourceControlExplorerMenuGroupId" value="0x1111" />
     </GuidSymbol>
   </Symbols>
于 2015-04-24T10:00:49.370 回答
2

基于 Carlos Quintero 的回答:如果您需要将命令放在 Source Control Explorers 上下文菜单中的任何其他位置,则需要正确的 Id。使用 EnableVSIPLogging,您只能找到命令及其父菜单的信息,而不是组。

为了找到源代码管理资源管理器中使用的组 ID(或任何其他 ID),您可以按照以下步骤操作(对于 VS2015):

  1. 反编译Microsoft.VisualStudio.TeamFoundation.VersionControl.dll(例如使用 JetBrains dotPeek)。
  2. 打开Resources\HatPackage.resources.
  3. 查找1000.ctmenu并复制 Base64 数据。
  4. 将数据从 Base64 转换为字节。
  5. 将文件中的字节另存为TfsMenu.cto(扩展名需要为 .cto 并且需要位于具有写入权限的位置,以便下一步工作)。
  6. 运行"C:\Program Files (x86)\Microsoft Visual Studio 14.0\VSSDK\VisualStudioIntegration\Tools\Bin\vsct.exe" TfsMenu.cto TfsMenu.vsct以反编译文件。

现在您有了用于制作 TFS 插件的原始 .vsct 文件。在这里,您可以查找所有 ID。

为了让您开始在 TfsMenu.vsct 中查找菜单项,您可以启用 EnableVSIPLogging:
Add HKEY_CURRENT_USER\SOFTWARE\Microsoft\VisualStudio\14.0\General\EnableVSIPLoggingas DWORD32with value 1
现在,在 Visual Studio 中,当在源代码管理资源管理器中悬停菜单或单击菜单项时按住Ctrl+Shift时,会弹出一个消息框,其中包含有关该项目的信息,包括该菜单/菜单项的 GUID 和 ID

于 2016-03-14T11:15:42.450 回答
0

@Erik 我很高兴看到您对提取 vsct 的解释,因为我非常努力地想知道如何做这件事。只是为了说明您的答案,我将其转换为代码。在这里分享,以防有人感兴趣。

static void Main(string[] args)
{
    /*
        Extract menus from extensions
        http://stackoverflow.com/questions/29831181/creating-vsix-package-for-tfs-source-control-explorer-context-menu-extension
     */

    try
    {
        string vsctPath = ConfigurationManager.AppSettings["VSCTPath"];
        if (!File.Exists(vsctPath))
        {
            WriteConsole("The path to the vsct.exe could not be found. Please edit the app.config to set the right executable path.", ConsoleColor.Yellow);
            return;
        }

        //TODO: Convert to a command line argument
        string dllPath = @"C:\Program Files (x86)\Microsoft SQL Server\130\Tools\Binn\ManagementStudio\Extensions\Application\Microsoft.SqlServer.Management.SqlStudio.Explorer.dll";


        var assembly = Assembly.LoadFrom(dllPath);

        if (assembly == null)
        {
            WriteConsole("Could not load assembly.", ConsoleColor.Yellow);
            return;
        }

        var resourceName = assembly.GetManifestResourceNames().FirstOrDefault(n => Regex.IsMatch(n, @"VSPackage\.resources", RegexOptions.IgnoreCase));

        if (String.IsNullOrWhiteSpace(resourceName))
        {
            WriteConsole("Could find VSPackage.resources in assembly.", ConsoleColor.Yellow);
            return;
        }

        var resourceManager = new ResourceManager(Path.GetFileNameWithoutExtension(resourceName), assembly);

        if (resourceManager == null)
        {
            WriteConsole("Could find load the resource " + resourceName + ".", ConsoleColor.Yellow);
            return;
        }

        var menus = resourceManager.GetObject("Menus.ctmenu") as byte[];

        if (menus == null)
        {
            WriteConsole("Could find Menus.ctmenu resource in VSPackage.resources.", ConsoleColor.Yellow);
            return;
        }

        string dir = Path.Combine(Path.GetTempPath(), "PackageMenus");
        string fileName = Path.GetFileNameWithoutExtension(dllPath) + ".cto";

        Directory.CreateDirectory(dir);
        Directory.SetCurrentDirectory(dir);

        File.WriteAllBytes(Path.Combine(dir, fileName), menus);

        string processArgs = String.Format(@"{0} {1}.vsct", fileName, fileName);
        var pi = new ProcessStartInfo(vsctPath, processArgs);

        pi.UseShellExecute = false;
        pi.RedirectStandardError = true;
        pi.RedirectStandardOutput = true;
        var ret = Process.Start(pi);

        var output = ret.StandardOutput.ReadToEnd();
        var errors = ret.StandardError.ReadToEnd();

        Console.WriteLine(output);

        if (!string.IsNullOrWhiteSpace(errors))
        {
            Console.Write("Errors: ");
            WriteConsole(errors, ConsoleColor.Red);
        }
        else
        {
            Console.WriteLine("New files written to: " + dir);
        }
    }
    catch(Exception ex)
    {
        WriteConsole(ex.ToString(), ConsoleColor.Red);
    }
    finally
    {
        Console.WriteLine("\r\nPress any key to continue.");
        Console.ReadKey(true);
    }

}

private static void WriteConsole(string message, ConsoleColor color = ConsoleColor.White)
{
    Console.ForegroundColor = color;
    Console.WriteLine(message);
    Console.ResetColor();
}
于 2016-08-09T19:41:34.863 回答