web-dev-qa-db-fra.com

Comment enregistrer un "outil personnalisé" avec Visual Studio 2017 pour le faire fonctionner?

Background: Nous avons un outil personnalisé qui prend l’entrée XML et génère la sortie cs. Un outil personnalisé doit être enregistré avec Visual Studio pour le faire fonctionner avec cette version de Visual Studio.

Ce que nous avons fait: Nous avons effectué l'enregistrement de l'outil personnalisé avec Visual Studio 2015, qui fonctionne correctement. Mais maintenant, le problème est avec Visual Studio 2017.

Problème: Jusqu’à présent, dans mes recherches, jusqu’à Visual Studio 2015, VS possédait les entrées de registre directes permettant d’enregistrer l’outil, mais à partir de VS 2017, Microsoft a modifié la manière dont les entrées de registre sont enregistrées. stocké ( une bonne lecture pour comprendre les changements dans VS2017 ).

Si j'ouvre le VS 2017 et essaie d'exécuter l'outil personnalisé, j'obtiens l'erreur

Impossible de trouver l'outil personnalisé "Nom de l'outil" sur ce système.

 enter image description here

Cela est évident car l'outil personnalisé n'est pas encore enregistré avec VS 2017 pour fonctionner.

J'ai essayé de suivre ce gars qui dit de charger le fichier .bin dans les registres, mais il dit également que cela désactive le lancement du VS 2017. Pour lancer le VS, nous devons décharger Hive. La recherche indique que le fichier .bin peut se trouver à un emplacement différent, en fonction du type de VS installé (entreprise, professionnel, etc.).

Est-ce que quelqu'un a déjà fait ça?

TIA

5
Amnesh Goel

Vous devrez peut-être suivre une approche différente ici en créant une extension Visual Studio (VSIX). Je l’ai expliqué ci-dessous en détail. J'espère que cela vous aidera.

Comment créer un outil personnalisé ou un générateur de fichier unique dans Visual Studio 2017:

Avant VS2017, la création d'un outil personnalisé nécessitait la mise en œuvre d'Interface IVsSingleFileGenerator et d'un code permettant d'enregistrer et de désenregistrer l'outil personnalisé dans le registre système, mais dans VS2017, Microsoft a modifié l'ensemble de la structure du registre. Le changement est que VS fera des entrées de registre dans un registre privé afin que le registre du système ne soit pas perturbé. Auparavant, les entrées de registre étaient entrées dans le registre système, mais maintenant elles sont faites pour:

C:\Utilisateurs\xyz\AppData\Local\Microsoft\VisualStudio\15.0_xx\privateregistry.bin

Visual studio 2017 prend également en charge le test de votre outil directement en l'exécutant à partir de Visual Studio lui-même (F5), ce qui démarre une autre instance de Visual Studio appelée Instance expérimentale de Visual Studio et votre outil peut y être testé car il crée des entrées de registre. à 

C:\Utilisateurs\xyz\AppData\Local\Microsoft\VisualStudio\15.0_xxExp\privateregistry.bin

Suivez les étapes ci-dessous pour créer un outil personnalisé dans VS2017:

  1. Nous devons créer une extension VSIX
  2. Ajouter un nouveau package Visual Studio
  3. Implémenter IVsSingleFileGenerator
  4. Ajouter le code d'entrée du registre
  5. Compiler et tester l'outil en l'exécutant dans VS2017
  6. Installez l'outil en double-cliquant sur le fichier .VSIX généré.

Nous allons créer un outil d'extension/personnalisé nommé "CountLines" qui lira un fichier (dont la propriété Custom Tool sera définie sur CountLines) et générera un fichier XML contenant le nombre de lignes qu'il contient. par exemple. <LineCount>1050</LineCount>

1. Créez une extension VSIX Pour créer une extension, vous devez avoir installé les outils d'extensibilité de Visual Studio, inclus en tant que fonctionnalité facultative dans la configuration de Visual Studio. S'il n'est pas installé, vous pouvez également l'installer en modifiant la configuration de VS 2017. Créez un nouveau projet VSIX (Visual Studio Extension) en sélectionnant 

Nouveau projet -> Extensibilité -> Projet VSIX 

donnez-lui un nom comme "CountLinesVSIX". 

2. Ajouter un nouveau package Visual Studio Une fois le projet VSIX créé, ajoutez-y un nouveau package Visual Studio en sélectionnant 

Ajouter -> Nouvel élément -> Extensibilité -> Package Visual Studio 

nommez-le "CountLines.cs". Dans CountLines.cs, nous devons supprimer le code existant et le remplacer par notre code pour la mise en œuvre de IVsSingleFileGenerator.

3. Implement IVsSingleFileGenerator Ecrivez votre implémentation personnalisée pour l'interface IVsSingleFileGenerator, notre exemple de code est le suivant

using System;
using System.Runtime.InteropServices;
using Microsoft.VisualStudio;
using Microsoft.VisualStudio.Shell;
using Microsoft.VisualStudio.Shell.Interop;
using System.Text;

namespace CountLinesVSIX
    {
    [PackageRegistration(UseManagedResourcesOnly = true)]
    [InstalledProductRegistration( "CountLines", "Generate XML with line count", "1.0")] 
    [Guid("202E7E8B-557E-46CB-8A1D-3024AD68F44A")]
    [ComVisible(true)]
    [ProvideObject(typeof(CountLines))]
    [CodeGeneratorRegistration(typeof(CountLines), "CountLines", "{FAE04EC1-301F-11D3-BF4B-00C04F79EFBC}", GeneratesDesignTimeSource = true)]
    public sealed class CountLines : IVsSingleFileGenerator
    {

        #region IVsSingleFileGenerator Members

        public int DefaultExtension(out string pbstrDefaultExtension)
        {
            pbstrDefaultExtension = ".xml";
            return pbstrDefaultExtension.Length;
        }

        public int Generate(string wszInputFilePath, string bstrInputFileContents,
          string wszDefaultNamespace, IntPtr[] rgbOutputFileContents,
          out uint pcbOutput, IVsGeneratorProgress pGenerateProgress)
        {
            try
            {
                int lineCount = bstrInputFileContents.Split('\n').Length;
                byte[] bytes = Encoding.UTF8.GetBytes("<LineCount>" + lineCount.ToString() + "</LineCount>" );
                int length = bytes.Length;
                rgbOutputFileContents[0] = Marshal.AllocCoTaskMem(length);
                Marshal.Copy(bytes, 0, rgbOutputFileContents[0], length);
                pcbOutput = (uint)length;
            }
            catch (Exception ex)
            {
                pcbOutput = 0;
            }
            return VSConstants.S_OK;
        }

        #endregion
    }
}

Nous devons fournir un GUID unique pour notre extension, par exemple l'un des codes ci-dessus [Guid("202E7E8B-557E-46CB-8A1D-3024AD68F44A")]. GUID peut être créé à partir de VS2017 en sélectionnant "Outils -> Créer un GUID" . Sélectionnez le format GUID en tant que format de registre. Notez que le code GUID mentionné ci-dessus est sans accolades.

[ComVisible(true)] est requis pour COM Interops

[CodeGeneratorRegistration(typeof(CountLines), "CountLines", "{FAE04EC1-301F-11D3-BF4B-00C04F79EFBC}", GeneratesDesignTimeSource = true)] est un attribut de classe avec un code pour enregistrer l'outil. Les paramètres étant GeneratorType, GeneratorName et le GUID du langage C #

Vous pouvez également dériver de "TemplatedCodeGenerator" qui prend en charge le formatage TextTemplate personnalisé, ce qui peut nécessiter une implémentation de code supplémentaire.

4. Ajoutez le code d'entrée du registre Créez un nouveau fichier de classe avec le code ci-dessous, nommez-le CodeGeneratorRegistrationAttribute.cs.

using System;
using System.Globalization;
using Microsoft.VisualStudio.Shell;

namespace CountLinesVSIX
{

    [AttributeUsage(AttributeTargets.Class, AllowMultiple = true, Inherited = true)]
    public sealed class CodeGeneratorRegistrationAttribute : RegistrationAttribute
    {
        private string _contextGuid;
        private Type _generatorType;
        private Guid _generatorGuid;
        private string _generatorName;
        private string _generatorRegKeyName;
        private bool _generatesDesignTimeSource = false;
        private bool _generatesSharedDesignTimeSource = false;

        public CodeGeneratorRegistrationAttribute(Type generatorType, string generatorName, string contextGuid)
        {
            if (generatorType == null)
                throw new ArgumentNullException("generatorType");
            if (generatorName == null)
                throw new ArgumentNullException("generatorName");
            if (contextGuid == null)
                throw new ArgumentNullException("contextGuid");

            _contextGuid = contextGuid;
            _generatorType = generatorType;
            _generatorName = generatorName;
            _generatorRegKeyName = generatorType.Name;
            _generatorGuid = generatorType.GUID;
        }

        /// <summary> 
        /// Get the generator Type 
        /// </summary> 
        public Type GeneratorType
        {
            get { return _generatorType; }
        }

        /// <summary> 
        /// Get the Guid representing the project type 
        /// </summary> 
        public string ContextGuid
        {
            get { return _contextGuid; }
        }

        /// <summary> 
        /// Get the Guid representing the generator type 
        /// </summary> 
        public Guid GeneratorGuid
        {
            get { return _generatorGuid; }
        }

        /// <summary> 
        /// Get or Set the GeneratesDesignTimeSource value 
        /// </summary> 
        public bool GeneratesDesignTimeSource
        {
            get { return _generatesDesignTimeSource; }
            set { _generatesDesignTimeSource = value; }
        }

        /// <summary> 
        /// Get or Set the GeneratesSharedDesignTimeSource value 
        /// </summary> 
        public bool GeneratesSharedDesignTimeSource
        {
            get { return _generatesSharedDesignTimeSource; }
            set { _generatesSharedDesignTimeSource = value; }
        }


        /// <summary> 
        /// Gets the Generator name  
        /// </summary> 
        public string GeneratorName
        {
            get { return _generatorName; }
        }

        /// <summary> 
        /// Gets the Generator reg key name under  
        /// </summary> 
        public string GeneratorRegKeyName
        {
            get { return _generatorRegKeyName; }
            set { _generatorRegKeyName = value; }
        }

        /// <summary> 
        /// Property that gets the generator base key name 
        /// </summary> 
        private string GeneratorRegKey
        {
            get { return string.Format(CultureInfo.InvariantCulture, @"Generators\{0}\{1}", ContextGuid, GeneratorRegKeyName); }
        }
        /// <summary> 
        ///     Called to register this attribute with the given context.  The context 
        ///     contains the location where the registration inforomation should be placed. 
        ///     It also contains other information such as the type being registered and path information. 
        /// </summary> 
        public override void Register(RegistrationContext context)
        {
            using (Key childKey = context.CreateKey(GeneratorRegKey))
            {
                childKey.SetValue(string.Empty, GeneratorName);
                childKey.SetValue("CLSID", GeneratorGuid.ToString("B"));

                if (GeneratesDesignTimeSource)
                    childKey.SetValue("GeneratesDesignTimeSource", 1);

                if (GeneratesSharedDesignTimeSource)
                    childKey.SetValue("GeneratesSharedDesignTimeSource", 1);

            }
        }

        /// <summary> 
        /// Unregister this file extension. 
        /// </summary> 
        /// <param name="context"></param> 
        public override void Unregister(RegistrationContext context)
        {
            context.RemoveKey(GeneratorRegKey);
        }
    }
}

Le code ci-dessus garantira que vos entrées sont effectuées dans le registre privé VS

5. Compilez et testez l'outil en l'exécutant dans VS2017 Vous pouvez ajouter "Installer les cibles" dans "source.extension.vsixmanifest" pour vous assurer que différentes éditions de VS2017 sont prises en charge par votre extesion. Exécutez votre outil dans VS 2017 pour vérifier s’il fonctionne comme prévu. Une fois que vous exécutez VSIX, l'instance expérimentale de Visual Studio installera l'extension et l'enregistrera dans le registre "C:\Utilisateurs\xyz\AppData\Local\Microsoft\VisualStudio\15.0_xxExp\privateregistry.bin". Vous pouvez voir l'extension installée en sélectionnant "Outils -> Extensions et mises à jour". Pour tester l'outil, nous devrons ouvrir un projet factice, sélectionner un fichier dans l'explorateur de solutions, accéder à ses propriétés et mettre à jour la propriété de l'outil personnalisé sur "CountLines". Une fois que cela est fait, VS exécutera l'outil en arrière-plan et générera la sortie. Dans notre exemple, il générera un fichier xml sous le fichier sélectionné. Sinon, une fois la propriété de l'outil personnalisé définie, vous pouvez cliquer avec le bouton droit sur le fichier et sélectionner "Exécuter l'outil personnalisé".

6. Installez l'outil en double-cliquant sur le fichier .VSIX généré Une fois le test réussi, essayez d'installer VSIX, qui se trouve à l'emplacement "projectName/bin/debug". Installez le VSIX en double-cliquant sur le fichier, suivez les étapes d'installation. Maintenant, votre outil sera disponible pour une utilisation dans VS2017. L'utilisation de l'outil est similaire, cliquez avec le bouton droit sur le fichier sur lequel vous souhaitez exécuter l'outil personnalisé et sélectionnez "Exécuter l'outil personnalisé".

Si vous souhaitez désinstaller l’extension, allez dans "Outils -> Extensions et mises à jour -> sélectionnez votre extension" et cliquez sur désinstaller. Notez que cet outil ne sera pas désinstallé jusqu'à ce que VS soit fermé. Une fois fermé, vous obtiendrez une fenêtre contextuelle pour désinstaller, sélectionnez "Modifier" pour désinstaller. 

10
Siddhesh Parab

Pendant les recherches, j’ai eu la réponse à ce problème. 

Solution:  

  1. Nous devons charger le fichier .bin (via load hiv). 
  2. Apportez les modifications ou modifiez le bac pour enregistrer votre outil. 
  3. Décharger la ruche.

Étape n ° 1: Charger la ruche.  

a) Registre ouvert (regedit). Sélectionnez le noeud HKEY_LOCAL_MACHINE

b) Allez à | Fichier -> Charger la ruche

c) Sélectionnez le fichier bin disponible à -> %LocalAppData%\ Microsoft\ VisualStudio\ 15.0_'instance_id'\privateregistry.bin.

d) Donnez un nom de clé. Cela créera une nouvelle entrée de clé dans HKEY_LOCAL_MACHINE avec votre nom de clé. 

e) Vous pouvez vérifier le fichier .bin à HKEY_LOCAL_MACHINE\YourKeyName\Software\Microsoft\VisualStudio\

 enter image description here

Étape n ° 2: Éditez le bac : Vous pouvez maintenant enregistrer votre outil personnalisé en suivant la même procédure que pour les autres versions du VS. En réalité, le seul problème était d'obtenir les clés VS2017 dans le registre mondial, ce qui est résolu à l'étape 1 ci-dessus. 

Étape 3: Déchargez la ruche.

a) sélectionnez votre clé sous HKEY_LOCAL_MACHINE.

b) Allez à | Menu Fichier 

c) Décharger la ruche. 

 enter image description here

1
Amnesh Goel