Visual studio 2012 为TFS源代码管理资源管理器上下文菜单扩展创建VSIX包
我试图创建VSIX包来扩展TFS 2012源代码管理的功能,在单击分支时右键单击上下文菜单。 我不想使用加载项。这必须是其他开发人员可以直接安装的包。 安装扩展后,自定义菜单项需要出现在源代码管理资源管理器上下文菜单中。我无法获得此要求的任何样本,或者无法获得适当的文档来源。我找到的一个示例是“TFS社区分支工具”,这是我正在寻找的类似功能,但我无法获得它的源代码Visual studio 2012 为TFS源代码管理资源管理器上下文菜单扩展创建VSIX包,visual-studio-2012,vsix,vsixmanifest,Visual Studio 2012,Vsix,Vsixmanifest,我试图创建VSIX包来扩展TFS 2012源代码管理的功能,在单击分支时右键单击上下文菜单。 我不想使用加载项。这必须是其他开发人员可以直接安装的包。 安装扩展后,自定义菜单项需要出现在源代码管理资源管理器上下文菜单中。我无法获得此要求的任何样本,或者无法获得适当的文档来源。我找到的一个示例是“TFS社区分支工具”,这是我正在寻找的类似功能,但我无法获得它的源代码 感谢您的帮助。我假定您熟悉.vsct文件、命令/菜单/组Guids/Id内容(所有这些都在MSDN中有文档记录)。因此,问题是在源代
感谢您的帮助。我假定您熟悉.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>
我的命令
我假设您熟悉.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>
我的命令
基于卡洛斯·昆特罗的回答:
如果需要将命令放置在源代码管理资源管理器上下文菜单中的任何其他位置,则需要正确的Id。使用EnableVSIPLogging,您只能找到命令及其父菜单的信息,而不能找到组的信息
要查找源代码管理资源管理器中使用的组ID(或任何其他ID),您可以执行以下步骤(对于VS2015):
Microsoft.VisualStudio.TeamFoundation.VersionControl.dll
(例如使用JetBrains dotPeek)Resources\HatPackage.Resources
1000.ctmenu
并复制Base64数据TfsMenu.cto
(扩展名必须是.cto,并且必须位于具有写入权限的位置,以便下一步工作)“C:\Program Files(x86)\Microsoft Visual Studio 14.0\VSSDK\VisualStudioIntegration\Tools\Bin\vsct.exe”TfsMenu.cto TfsMenu.vsct
以反编译该文件将
HKEY\u CURRENT\u USER\SOFTWARE\Microsoft\VisualStudio\14.0\General\EnableVSIPLogging
添加为DWORD32
,值为1
现在,在Visual Studio中,当按住Ctrl+Shift键同时悬停菜单或在源代码管理资源管理器中单击菜单项时,会弹出一个消息框,其中包含有关该项的信息,包括该菜单/menuitem的GUID和ID,这是基于Carlos Quintero的回答: 如果需要将命令放置在源代码管理资源管理器上下文菜单中的任何其他位置,则需要正确的Id。使用EnableVSIPLogging,您只能找到命令及其父菜单的信息,而不能找到组的信息 要查找源代码管理资源管理器中使用的组ID(或任何其他ID),您可以执行以下步骤(对于VS2015):
Microsoft.VisualStudio.TeamFoundation.VersionControl.dll
(例如使用JetBrains dotPeek)Resources\HatPackage.Resources
1000.ctmenu
并复制Base64数据TfsMenu.cto
(扩展名必须是.cto,并且必须位于具有写入权限的位置,以便下一步工作)“C:\Program Files(x86)\Microsoft Visual Studio 14.0\VSSDK\VisualStudioIntegration\Tools\Bin\vsct.exe”TfsMenu.cto TfsMenu.vsct
以反编译该文件将
HKEY\u CURRENT\u USER\SOFTWARE\Microsoft\VisualStudio\14.0\General\EnableVSIPLogging
添加为DWORD32
,值为1
现在,在VisualStudio中,当按住Ctrl+Shift键同时悬停菜单或在源代码管理资源管理器中单击菜单项时,会弹出一个消息框,其中包含有关该项的信息,包括菜单的GUID和ID/menuitem@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();
}
@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();
}
你好,卡洛斯,感谢您提供的信息,我可以在源代码管理资源管理器上添加命令。现在单击该命令,我可以打开我的自定义表单,我只需要从右键单击并单击命令的位置获取TFS路径。如何在那里获取TFS路径。请参阅:@CarlosQuintero:这很有效。但是,您假设新命令应该出现在