簡體   English   中英

如何部署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="&quot;$(VSSDK90Install)VisualStudioIntegration\Tools\Bin\RegPkg.exe&quot; /root:Software\Microsoft\VisualStudio\9.0 /codebase &quot;$(TargetPath)&quot; /regfile:&quot;$(OutDir)$(TargetName).reg&quot;" />
</Target>
<PropertyGroup> 
  <BuildDependsOn>$(BuildDependsOn);GeneratePackageRegistryFiles;</BuildDependsOn>
</PropertyGroup>

在輸出目錄中構建外觀時,您應該找到一個.reg文件,您可以在安裝項目中導入該文件。

顯然,如果不能選擇修改項目,則可以從命令行運行regpkg.exe。

這是我上次最后一次努力讓我的自定義工具注冊時的結果。 我希望這條指令足夠詳細並涵蓋所有內容,這樣你就不會花太多時間來對抗它。 以下MSDN文章用作起點。 http://msdn.microsoft.com/en-US/library/bb166527(v=vs.80).aspx不幸的是你不能單獨使用它。 你真正需要做的是:

  1. 確保程序集已簽名。 為什么? 因為否則您將無法在下面的第6步將其置於GAC中。 要為程序集簽名,請執行以下步驟:

    1.1。 轉到項目的“ 屬性”屏幕。

    1.2。 進入“ 簽名”選項卡后。

    1.3。 在那里檢查簽署程序集復選框。

  2. 確保您知道裝配的版本號。 稍后您將需要此編號來指定ASSEMBLY_VERSION參數。 為了得到這個數字,打開項目的Properties文件夾中的AssemblyInfo.cs文件,並查找以下開頭的行:[assembly:AssemblyVersion(

  3. 確保您知道生成器類的GUID。 稍后您將需要它來指定GENERATOR_GUID參數。 為了讓這個GUID打開帶有生成器類的文件,並查找裝飾這個類的Guid類屬性,例如:[Guid(“17799E85-421B-4684-B59E-650E34ECC718”)]

  4. 建立項目

  5. 獲取程序集的公共令牌密鑰。 為此,您必須運行以下命令:

    sn.exe -T ASSEMBLY_FILE

    對於PUBLIC_TOKEN_KEY,稍后您將需要此信息。 sn.exe文件可以在C:\\ Program Files \\ Microsoft SDKs \\ Windows \\ v8.0A \\ bin \\ sn.exe中找到。請注意上面文件路徑中框架的版本號(v8.0A)。 它需要與用於編譯項目的框架版本一致。

  6. 使用以下命令將程序集放入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)以上。 它需要與用於編譯項目的框架版本一致。

  7. 對.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

  8. 運行.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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM