Domanda

Ho il mio strumento personalizzato per Visual Studio 2008 SP1.Si compone di 5 gruppi:3 assembly con codice ampiamente utilizzato negli altri miei progetti, 1 wrapper di assembly sopra l'SDK VS2008 e un assembly con lo strumento.

Se eseguo il debug del mio strumento da Visual Studio, utilizzando l'opzione "Esegui programma esterno" con la riga di comando "C:\Programmi (x86)\Microsoft Visual Studio 9.0\Common7\IDE\devenv.exe" e argomenti "/ranu / rootsuffix Exp" funziona tutto perfettamente.

Dopodiché sto provando a distribuirlo sulla mia copia VS funzionante, non sull'hive sperimentale, facendo: gacutil /i Asm1.dll per tutte le mie assemblee e il mio fare RegAsm Asm1.dll solo per montaggio con utensile personalizzato.Nessuna delle utilità stampa alcun errore, tutto funziona come previsto, vengono visualizzate anche le chiavi di registro.Ma il mio strumento non funziona (si è verificato l'errore "Impossibile trovare lo strumento personalizzato 'TransportGeneratorTool' su questo sistema") anche dopo il riavvio del PC.Che cosa ho fatto di sbagliato?

Il wrapper si presenta così:

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

Il mio codice strumento:

[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());
        }
    }
}

Chiavi di registro risultanti:

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

Ecco il codice del mio attributo personalizzato (è nell'assembly wrapper):

[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
}
È stato utile?

Soluzione

La mia soluzione è quella di realizzare un progetto di configurazione. Ottengo le impostazioni del registro dal file PKGDEF aggiungendo quanto segue al file CSPROJ del pacchetto:

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

Quando si costruisce look nella directory di output è necessario trovare un file .reg che è possibile importare nel progetto di configurazione.

Ovviamente è possibile eseguire il regpkg.exe dalla riga di comando se la modifica del progetto non è un'opzione.

Altri suggerimenti

Questo è ciò che mi è successo l'ultima volta quando ho faticato a registrare il mio strumento personalizzato.Spero che queste istruzioni siano sufficientemente dettagliate e coprano tutto in modo da non perdere molto tempo a combatterle.Il seguente articolo MSDN è stato utilizzato come punto di partenza. http://msdn.microsoft.com/en-US/library/bb166527(v=vs.80).aspx Sfortunatamente non puoi usarlo da solo.Ciò che devi veramente fare è:

  1. Assicurati che l'assemblea sia firmata.Perché?Perché altrimenti non potrai inserirlo nel GAC al passaggio 6 di seguito.Per firmare la tua assemblea segui questi passaggi:

    1.1.Vai a Proprietà schermata del progetto.

    1.2.Una volta lì, vai al Firma scheda.

    1.3.Una volta lì, controlla il file Firma l'assemblea casella di controllo.

  2. Assicurati di conoscere il numero di versione del tuo assembly.Avrai bisogno di questo numero per specificare il ASSEMBLY_VERSIONE parametro più tardi.Per ottenere questo numero aprire il file AssemblyInfo.cs file nel Proprietà cartella del tuo progetto e cerca la riga che inizia con:[assemblea:Versioneassembly(

  3. Assicurati di conoscere il GUID della classe del generatore.Ne avrai bisogno per specificare il GENERATORE_GUID parametro più tardi.Per ottenere questo GUID aprire il file con la classe generator e cercare il file Guida attributo class che decora questa classe, qualcosa del tipo:[Guida("17799E85-421B-4684-B59E-650E34ECC718")]

  4. Costruisci il progetto

  5. Ottieni la chiave token pubblica dell'assembly.Per fare ciò dovrai eseguire il seguente comando:

    sn.exe -T ASSEMBLY_FILE

    Avrai bisogno di queste informazioni in seguito PUBLIC_TOKEN_KEY.IL sn.exe il file può essere trovato in C:\Programmi\Microsoft SDK\Windows\v8.0A\bin\sn.exePresta attenzione al numero di versione del framework (v8.0A) nel percorso file sopra.Deve essere coerente con la versione del framework utilizzato per compilare il progetto.

  6. Inserisci l'assembly nel GAC utilizzando il seguente comando:

    gacutil.exe/i ASSEMBLY_FILE /F

    La registrazione in GAC richiede autorizzazioni amministrative.IL gacutil.exe il file può essere trovato in C:\Programmi\Microsoft SDK\Windows\v8.0A\bin ETFX 4.0 Tools\gacutil.exePresta attenzione al numero di versione del framework (v8.0A) nel percorso file sopra.Deve essere coerente con la versione del framework utilizzato per compilare il progetto.

  7. Apportare le seguenti modifiche al file .REG (vedi sotto). NOTARE CHE:che sia GENERATOR_GUID che PROJECT_TYPE_GUID devono essere forniti CON parentesi graffe:{XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX}

    7.1.Viene utilizzato il numero di versione fisso di Visual Studio (ad esempio:10.0 o 9.0): VS_VERSIONE

    7.2.Correggi il GUID del generatore: GENERATORE_GUID

    7.3.Correggi lo spazio dei nomi dell'assembly: NAMESPACE_NAME

    7.4.Correggi il nome della classe del generatore: GENERATOR_TYPE_NAME

    7.5.Per registrare il generatore, Visual Studio deve sapere a quali tipi di progetto può essere applicato questo generatore.Quindi è necessario ottenere i GUID dei tipi di progetto corretti (C#, VB.NET, ecc.).Per individuare i GUID dei tipi di progetto è necessario aprire un file di progetto di Visual Studio (*.csproj) in un editor di testo e cercare i GUID nel file ProjectTypeGuid elemento XML.Per ognuno di questi GUID ripetere il blocco delle ultime 3 voci nel file .REG sostituendo il PROJECT_TYPE_GUID con il GUID appena trovato.

    7.6.Correggi l'estensione del file associato allo strumento personalizzato: ESTENSIONE_FILE

  8. Esegui il file .REG.Potrebbe essere necessario disporre di autorizzazioni amministrative per eseguire questa operazione.

File .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.Ci scusiamo per non essere in grado di distinguere i segnaposto nel file REG, sfortunatamente l'editor di testo utilizzato da StackOverflow non è in grado di distinguere i suoi elementi di markup dal contenuto.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top