![](/img/trans.png)
[英]How to display custom tool window at the first position, programmatically in visual studio
[英]How to deploy a visual studio custom tool?
我有自己的Visual Studio 2008 SP1自定义工具。 它由5个程序集组成:3个程序集,其中包含在我的其他项目中大量使用的代码,1个VS2008 SDK上的程序集包装程序以及使用该工具的程序集。
如果我从visual studio调试我的工具,使用命令行“C:\\ Program Files(x86)\\ Microsoft Visual Studio 9.0 \\ Common7 \\ IDE \\ devenv.exe”和参数“/ ranu /”使用“运行外部程序”选项rootsuff Exp“一切都很完美。
在那之后,我正在尝试将它部署到我的工作VS副本,而不是实验配置单元,执行: gacutil /i Asm1.dll
用于我的所有程序集并执行RegAsm Asm1.dll
仅用于使用自定义工具进行装配。 utils都没有打印任何错误,所有工作都按计划进行,甚至出现了注册表项。 但是我的工具不起作用(发生错误“在此系统上找不到自定义工具'TransportGeneratorTool'”)即使在PC重启后也是如此。 我做错了什么?
Wrapper看起来像那样:
[ComVisible(true)]
public abstract class CustomToolBase : IVsSingleFileGenerator, IObjectWithSite
{
#region IVsSingleFileGenerator Members
int IVsSingleFileGenerator.DefaultExtension(out string pbstrDefaultExtension)
{
pbstrDefaultExtension = ".cs";
return 0;
}
int IVsSingleFileGenerator.Generate(string wszInputFilePath, string bstrInputFileContents, string wszDefaultNamespace, IntPtr[] rgbOutputFileContents, out uint pcbOutput, IVsGeneratorProgress pGenerateProgress)
{
GenerationEventArgs gea = new GenerationEventArgs(
bstrInputFileContents,
wszInputFilePath,
wszDefaultNamespace,
new ServiceProvider(Site as Microsoft.VisualStudio.OLE.Interop.IServiceProvider)
.GetService(typeof(ProjectItem)) as ProjectItem,
new GenerationProgressFacade(pGenerateProgress)
);
if (OnGenerateCode != null)
{
OnGenerateCode(this, gea);
}
byte[] bytes = gea.GetOutputCodeBytes();
int outputLength = bytes.Length;
rgbOutputFileContents[0] = Marshal.AllocCoTaskMem(outputLength);
Marshal.Copy(bytes, 0, rgbOutputFileContents[0], outputLength);
pcbOutput = (uint)outputLength;
return VSConstants.S_OK;
}
#endregion
#region IObjectWithSite Members
void IObjectWithSite.GetSite(ref Guid riid, out IntPtr ppvSite)
{
IntPtr pUnk = Marshal.GetIUnknownForObject(Site);
IntPtr intPointer = IntPtr.Zero;
Marshal.QueryInterface(pUnk, ref riid, out intPointer);
ppvSite = intPointer;
}
void IObjectWithSite.SetSite(object pUnkSite)
{
Site = pUnkSite;
}
#endregion
#region Public Members
public object Site { get; private set; }
public event EventHandler<GenerationEventArgs> OnGenerateCode;
[ComRegisterFunction]
public static void Register(Type type)
{
using (var parent = Registry.LocalMachine.OpenSubKey(@"Software\Microsoft\VisualStudio\9.0", true))
foreach (CustomToolRegistrationAttribute ourData in type.GetCustomAttributes(typeof(CustomToolRegistrationAttribute), false))
ourData.Register(x => parent.CreateSubKey(x), (x, name, value) => x.SetValue(name, value));
}
[ComUnregisterFunction]
public static void Unregister(Type type)
{
using (var parent = Registry.LocalMachine.OpenSubKey(@"Software\Microsoft\VisualStudio\9.0", true))
foreach (CustomToolRegistrationAttribute ourData in type.GetCustomAttributes(typeof(CustomToolRegistrationAttribute), false))
ourData.Unregister(x => parent.DeleteSubKey(x, false));
}
#endregion
}
我的工具代码:
[ComVisible(true)]
[Guid("55A6C192-D29F-4e22-84DA-DBAF314ED5C3")]
[CustomToolRegistration(ToolName, typeof(TransportGeneratorTool))]
[ProvideObject(typeof(TransportGeneratorTool))]
public class TransportGeneratorTool : CustomToolBase
{
private const string ToolName = "TransportGeneratorTool";
public TransportGeneratorTool()
{
OnGenerateCode += GenerateCode;
}
private static void GenerateCode(object s, GenerationEventArgs e)
{
try
{
var serializer = new XmlSerializer(typeof (Parser.System));
using (var reader = new StringReader(e.InputText))
using (var writer = new StringWriter(e.OutputCode))
{
Generator.System = (Parser.System) serializer.Deserialize(reader);
Generator.System.Namespace = e.Namespace;
Generator.GenerateSource(writer);
}
}
catch (Exception ex)
{
e.Progress.GenerateError(ex.ToString());
}
}
}
生成的注册表项:
Windows Registry Editor Version 5.00
[HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\VisualStudio\9.0\Generators]
[HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\VisualStudio\9.0\Generators\{FAE04EC1-301F-11D3-BF4B-00C04F79EFBC}]
[HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\VisualStudio\9.0\Generators\{FAE04EC1-301F-11D3-BF4B-00C04F79EFBC}\TransportGeneratorTool]
@="TransportGeneratorTool"
"CLSID"="{55a6c192-d29f-4e22-84da-dbaf314ed5c3}"
"GeneratesDesignTimeSource"=dword:00000001
"GeneratesSharedDesignTimeSource"=dword:00000001
这是我的自定义属性的代码(它在包装程序集中):
[AttributeUsage(AttributeTargets.Class, AllowMultiple = true, Inherited = true)]
public class CustomToolRegistrationAttribute : RegistrationAttribute
{
public CustomToolRegistrationAttribute(string name, Type customToolType)
{
Name = name;
CustomToolType = customToolType;
}
/// <summary>
/// The type that implements the custom tool. This starts
/// as MyCustomTool by default in the template.
/// </summary>
public Type CustomToolType { get; set; }
public string Name { get; set; }
#region RegistrationAttribute abstract member implementations
public override void Register(RegistrationContext context)
{
Register(x => context.CreateKey(x), (x, key, value) => x.SetValue(key, value));
}
public void Register<T>(Func<string, T> keyCreator, Action<T, string, object> valueCreator)
{
var keyName = CreateKeyName(Name);
var key = keyCreator(keyName);
valueCreator(key, string.Empty, Name);
valueCreator(key, "CLSID", CustomToolType.GUID.ToString("B"));
valueCreator(key, "GeneratesDesignTimeSource", 1);
valueCreator(key, "GeneratesSharedDesignTimeSource", 1);
var disposable = key as IDisposable;
if (disposable != null)
disposable.Dispose();
}
private static string CreateKeyName(string name)
{
return string.Format(@"Generators\{0}\{1}", vsContextGuids.vsContextGuidVCSProject, name);
}
public override void Unregister(RegistrationContext context)
{
Unregister(context.RemoveKey);
}
public void Unregister(Action<string> keyRemover)
{
keyRemover(CreateKeyName(Name));
}
#endregion
}
我的解决方案是制作一个安装项目。 我通过将以下内容添加到包的csproj文件中来获取pkgdef文件中的注册表设置:
<Target Name="GeneratePackageRegistryFiles">
<Exec Command=""$(VSSDK90Install)VisualStudioIntegration\Tools\Bin\RegPkg.exe" /root:Software\Microsoft\VisualStudio\9.0 /codebase "$(TargetPath)" /regfile:"$(OutDir)$(TargetName).reg"" />
</Target>
<PropertyGroup>
<BuildDependsOn>$(BuildDependsOn);GeneratePackageRegistryFiles;</BuildDependsOn>
</PropertyGroup>
在输出目录中构建外观时,您应该找到一个.reg文件,您可以在安装项目中导入该文件。
显然,如果不能选择修改项目,则可以从命令行运行regpkg.exe。
这是我上次最后一次努力让我的自定义工具注册时的结果。 我希望这条指令足够详细并涵盖所有内容,这样你就不会花太多时间来对抗它。 以下MSDN文章用作起点。 http://msdn.microsoft.com/en-US/library/bb166527(v=vs.80).aspx不幸的是你不能单独使用它。 你真正需要做的是:
确保程序集已签名。 为什么? 因为否则您将无法在下面的第6步将其置于GAC中。 要为程序集签名,请执行以下步骤:
1.1。 转到项目的“ 属性”屏幕。
1.2。 进入“ 签名”选项卡后。
1.3。 在那里检查签署程序集复选框。
确保您知道装配的版本号。 稍后您将需要此编号来指定ASSEMBLY_VERSION参数。 为了得到这个数字,打开项目的Properties文件夹中的AssemblyInfo.cs文件,并查找以下开头的行:[assembly:AssemblyVersion(
确保您知道生成器类的GUID。 稍后您将需要它来指定GENERATOR_GUID参数。 为了让这个GUID打开带有生成器类的文件,并查找装饰这个类的Guid类属性,例如:[Guid(“17799E85-421B-4684-B59E-650E34ECC718”)]
建立项目
获取程序集的公共令牌密钥。 为此,您必须运行以下命令:
sn.exe -T ASSEMBLY_FILE
对于PUBLIC_TOKEN_KEY,稍后您将需要此信息。 sn.exe文件可以在C:\\ Program Files \\ Microsoft SDKs \\ Windows \\ v8.0A \\ bin \\ sn.exe中找到。请注意上面文件路径中框架的版本号(v8.0A)。 它需要与用于编译项目的框架版本一致。
使用以下命令将程序集放入GAC:
gacutil.exe / i ASSEMBLY_FILE / f
在GAC中注册需要管理权限。 gacutil.exe文件可以在C:\\ Program Files \\ Microsoft SDKs \\ Windows \\ v8.0A \\ bin \\ NETFX 4.0 Tools \\ gacutil.exe中找到。注意文件路径中框架的版本号(v8.0A)以上。 它需要与用于编译项目的框架版本一致。
对.REG(见下文)文件进行以下更改。 请注意:GENERATOR_GUID和PROJECT_TYPE_GUID都需要提供大括号:{XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX}
7.1。 修复了使用Visual Studio的版本号(例如:10.0或9.0): VS_VERSION
7.2。 修复生成器的GUID: GENERATOR_GUID
7.3。 修复程序集的命名空间: NAMESPACE_NAME
7.4。 修复生成器类名称: GENERATOR_TYPE_NAME
7.5。 为了注册生成器,Visual Studio需要知道可以将这个生成器应用于哪些项目类型。 因此,您需要获取正确项目类型的GUID(C#,VB.NET等)。 要弄清楚项目类型的GUID,您需要在文本编辑器中打开visual studio项目文件(* .csproj),并在ProjectTypeGuids XML元素中查找GUID。 对于每个GUID,重复.REG文件中最后3个条目的块,将PROJECT_TYPE_GUID替换为刚刚找到的GUID。
7.6。 修复与自定义工具关联的文件的扩展名: FILE_EXTENSTION
运行.REG文件。 您可能需要具有管理权限才能执行此操作。
.REG文件:
Windows Registry Editor Version 5.00
[HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\VisualStudio\VS_VERSION\CLSID\GENERATOR_GUID]
@="COM+ class: NAMESPACE_NAME.GENERATOR_TYPE_NAME"
"InprocServer32"="C:\\WINDOWS\\system32\\mscoree.dll"
"ThreadingModel"="Both"
"Class"="NAMESPACE_NAME.GENERATOR_TYPE_NAME"
"Assembly"="NAMESPACE_NAME, Version=ASSEMBLY_VERSION, Culture=Neutral, PublicKeyToken=PUBLIC_TOKEN_KEY"
[HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\VisualStudio\VS_VERSION\Generators]
[HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\VisualStudio\VS_VERSION\Generators\PROJECT_TYPE_GUID]
[HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\VisualStudio\VS_VERSION\Generators\PROJECT_TYPE_GUID\\.FILE_EXTENSTION]
@="GENERATOR_TYPE_NAME"
[HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\VisualStudio\VS_VERSION\Generators\PROJECT_TYPE_GUID\GENERATOR_TYPE_NAME]
@="Code generator for whatever you like"
"CLSID"="GENERATOR_GUID"
"GeneratesDesignTimeSource"=dword:00000001
PS。 很抱歉无法在REG文件中使placehoders与众不同,遗憾的是StackOverflow使用的文本编辑器无法将其标记元素与内容区分开来。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.