Как развернуть пользовательский инструмент Visual Studio? - PullRequest
6 голосов
/ 06 апреля 2010

У меня есть собственный инструмент для Visual Studio 2008 SP1. Он состоит из 5 сборок: 3 сборки с кодом, которые интенсивно используются в других моих проектах, 1 сборка-обертка над SDK VS2008 и сборка с инструментом.

Если бы я отлаживал свой инструмент в Visual Studio, используя параметр «Запускать внешнюю программу» с командной строкой «C: \ Program Files (x86) \ Microsoft Visual Studio 9.0 \ Common7 \ IDE \ devenv.exe» и аргументы » / ranu / rootsuffix Exp "все работает отлично.

После этого я пытаюсь развернуть его в моей рабочей копии VS, а не в экспериментальном кусте, выполняя: gacutil /i Asm1.dll для всех моих сборок и выполняя RegAsm Asm1.dll только для сборки с помощью специального инструмента. Ни одна из утилит не выводит никаких ошибок, все работает как запланировано, даже появляются ключи реестра. Но мой инструмент не работает (произошла ошибка «Не удается найти пользовательский инструмент« TransportGeneratorTool »в этой системе») даже после перезагрузки компьютера. Что я сделал не так?

Оболочка выглядит так:

[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
}

Ответы [ 2 ]

6 голосов
/ 09 апреля 2010

Мое решение - создать проект установки. Я получаю параметры реестра из файла pkgdef, добавив в файл csproj пакета следующее:

<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 из командной строки, если изменение проекта невозможно.

4 голосов
/ 14 октября 2012

Это то, с чем я столкнулся в прошлый раз, когда пытался зарегистрировать свой инструмент. Я надеюсь, что эта инструкция достаточно подробна и охватывает все, поэтому вы не будете тратить много времени на борьбу с ней. Следующая статья MSDN была использована в качестве отправной точки. http://msdn.microsoft.com/en-US/library/bb166527(v=vs.80).aspx К сожалению, вы не можете использовать его в одиночку. Что вам действительно нужно сделать, это:

  1. Убедитесь, что сборка подписана. Зачем? Потому что иначе вы не сможете поместить его в GAC на шаге 6 ниже. Чтобы подписать вашу сборку, выполните следующие действия:

    1,1. Перейдите на экран Свойства проекта.

    1.2. После этого перейдите на вкладку Signing .

    1,3. После этого установите флажок Подпись сборки .

  2. Убедитесь, что вы знаете номер версии вашей сборки. Этот номер понадобится вам для указания параметра ASSEMBLY_VERSION позже. Чтобы получить это число, откройте файл AssemblyInfo.cs в папке Properties вашего проекта и найдите строку, начинающуюся с: [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

    * 1 094 * 7.5. Чтобы зарегистрировать генератор, Visual Studio необходимо знать, к каким типам проектов этот генератор может быть применен. Поэтому вам нужно получить GUID правильных типов проектов (C #, VB.NET и т. Д.). Чтобы выяснить GUID типов проектов, вам нужно открыть файл проекта Visual Studio (* .csproj) в текстовом редакторе и найти GUID в XML-элементе ProjectTypeGuids . Для каждого из этих идентификаторов GUID повторите блок из трех последних записей в файле .REG, заменив 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, но, к сожалению, используемый в StackOverflow текстовый редактор не может отличить элементы разметки от содержимого.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...