locked
Deploying custom tool file generator via VSIX RRS feed

  • Question

  • Hello,
    I have my custom tool single file generator and would like to make it available for others through the extensions manager. Is there any tutorial available on how to pack the custom file generator in a VSIX package?

    Thank you,
    Jan

    Monday, October 31, 2011 8:19 AM

Answers

All replies

  • Hi Jan,

    Based on my understanding you are going to deploy a custom content using VSIX. Did you try to add a custom extension type to your VSIX project?

    You can add a custom extension type using VSIX manifest designer and add a content. We can select the content type as "Custom Extension Type" and select File as the source. When you deploy the VSIX, the custom content will also be deployed.

    If you'd like manage the VSIX using the XML editor, you can refer to http://msdn.microsoft.com/en-us/library/dd393737.aspx for more information about CustomExtension Element tag.

    Regards,

    Yi


    Yi Feng Li [MSFT]
    MSDN Community Support | Feedback to us
    Get or Request Code Sample from Microsoft
    Please remember to mark the replies as answers if they help and unmark them if they provide no help.

    Tuesday, November 1, 2011 3:53 AM
  • Does this mean VSIX has no support or understanding of the custom tools as defined in http://msdn.microsoft.com/en-us/library/bb166508.aspx?

    So I need to manually define the registry updates mentioned in http://msdn.microsoft.com/en-us/library/bb166527.aspx and manually define the assembly registration step? What's the point of using VSIX here then other than to have the extension in the extension manager?

    Jan

    Tuesday, November 1, 2011 8:55 AM
  • Hi Jan,

    I belive your understand is correct. We need to manually define the registry updates mentioned in http://msdn.microsoft.com/en-us/library/bb166527.aspx and manually define the assembly registration step.

    For deploying Custom Tool using VSIX, we can create a vspackage project and using its .pkgdef file to register.

    Regards,

    Yi


    Yi Feng Li [MSFT]
    MSDN Community Support | Feedback to us
    Get or Request Code Sample from Microsoft
    Please remember to mark the replies as answers if they help and unmark them if they provide no help.

    • Marked as answer by Jan Kučera Tuesday, November 1, 2011 1:18 PM
    Tuesday, November 1, 2011 9:19 AM
  • That's not entirely accurate.

    You only have to decorate your code generator with a CodeGeneratorRegistrationAttribute attibute, and you're done.

    The following works like a charm in my VSIX project:

    [ComVisible(true)]
    [Guid("my guid")]
    [CodeGeneratorRegistration(typeof(MyGenerator), "MyGenerator", vsLangProjContextGuids.vsContextGuidVCSProject, GeneratorRegKeyName=".myExtension")]
    [CodeGeneratorRegistration(typeof(MyGenerator), "MyGenerator", vsLangProjContextGuids.vsContextGuidVCSProject, GeneratesDesignTimeSource = true)]
    [ProvideObject(typeof(MyGenerator), RegisterUsing = RegistrationMethod.CodeBase)]
    public class MyGenerator : IVsSingleFileGenerator
    {
        // Implementation goes here //
    }

    Wednesday, July 4, 2012 1:04 PM
  • You only have to decorate your code generator with a CodeGeneratorRegistrationAttribute attibute, and you're done.

    I spoke too soon.

    Apparently I got a custom implementation for that attribute from somewhere:

    namespace Microsoft.VisualStudio.Shell
    {
    	/// <summary>
    	/// This attribute adds a custom file generator registry entry for specific file 
        /// type. 
    	/// For Example:
    	///   [HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\VisualStudio\9.0\Generators\
        ///		{fae04ec1-301f-11d3-bf4b-00c04f79efbc}\MyGenerator]
        ///			"CLSID"="{AAAA53CC-3D4F-40a2-BD4D-4F3419755476}"
        ///         "GeneratesDesignTimeSource" = d'1'
    	/// 
    	/// </summary>
    	[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;
    		/// <summary>
            /// Creates a new CodeGeneratorRegistrationAttribute attribute to register a custom
    		/// code generator for the provided context. 
    		/// </summary>
            /// <param name="generatorType">The type of Code generator. Type that implements IVsSingleFileGenerator</param>
            /// <param name="generatorName">The generator name</param>
            /// <param name="contextGuid">The context GUID this code generator would appear under.</param>
            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);
    		}
    	}
    }

    I honestly have no idea where I got that code from... Thanks to whoever thought this up.

    Wednesday, July 4, 2012 2:26 PM
  • Looks very promising, will give it a try, thanks for sharing!

    Wednesday, July 4, 2012 2:40 PM
  • I'm trying to start a new custom tool project, based on the one I mentioned above. But it doesn't seem to work quite right yet.

    I'll keep you posted.

    Thursday, July 5, 2012 9:15 AM
  • Finally got it back working. It turned out to be two different faults I introduced.

    With this code it is working:

    [ComVisible(true)]
    [ClassInterface(ClassInterfaceType.None)]
    [Guid(GuidList.TestGeneratorString)]
    [CodeGeneratorRegistration(typeof (TestGenerator), "Demo Generator", CodeGeneratorRegistrationAttribute.ContextGuidVCSProject, GeneratorRegKeyName = ".doml")]
    [CodeGeneratorRegistration(typeof(TestGenerator), "TestGenerator", CodeGeneratorRegistrationAttribute.ContextGuidVCSProject, GeneratorRegKeyName = "Demo Generator", GeneratesDesignTimeSource = true)]
    [ProvideObject(typeof (TestGenerator), RegisterUsing = RegistrationMethod.CodeBase)]
    public class TestGenerator : BaseCodeGeneratorWithSite
    {

    The troubles in my case were:

    • The name of the generator and the class name didn't match. Alternatively you can do it as above. The first attribute registers the file extension to the generator with the friendly name "Demo Generator". The second line maps the "Demo Generator" to the TestGenerator class.
    • The inherited class BaseCodeGeneratorWithSite isn't COM-visible. That's easily solved by adding the [ClassInterface(ClassInterfaceType.None)] line.

    Positive side effect: not the whole assembly needs to be COM-visible any more, only the generator type. And the experimental hive is working too!

     

    Thursday, July 5, 2012 12:04 PM
  • Joep,

    Thank you very much, after (too much) hours searching a solution for the error message "Cannot find custom tool '...' on this system " I found out that I was missing the following line of code:

    [ClassInterface(ClassInterfaceType.None)]

    Thursday, May 18, 2017 9:43 AM