Creating a Custom Project Templates with IWizard interface using Extensibility Project of VS2010 SDK

Niladri.Biswas
Posted by in Visual Studio category on for Beginner level | Points: 250 | Views : 6620 red flag
Rating: 5 out of 5  
 1 vote(s)

In this article we will learn creating a Custom Project Templates with IWizard interface using Extensibility Project of VS2010 SDK


 Download source code for Creating a Custom Project Templates with IWizard interface using Extensibility Project of VS2010 SDK

Introduction

This is an extension of my previous article Creating a new category for Custom Templates with a new entry to Install Templates for Visual Studio using Extensibility Project of VS2010 SDK. In this article we will go a step ahead and will look into a little advance feature of the VS Extensibility project where we will explore as how to

  1. Add dlls to Reference folder dynamically.
  2. Create a folder dynamically (say "TheRuntimeFolder") and add a normal .cs file to it.
  3. Add a Linked file ("Add As Link") to Project folder dynamically.

based on the values being passed from the wizard provided (we will create a wizard using WindowsForm) and attached to the already exisitng one as shown in the previous article.

So, what I mean is

When the user chooses that then a custom project template will appear in the VS IDE similar to the already existing ones.(we already covered in the previous article)

When the user click on the "OK" button, a wizard appears from where the user needs to provide the needed values  and click on the "OK" button.

How to do it?

We will use Custom Templates with IWizard interface using Extensibility Project of Visual Studio 2010 SP1 SDK for solving this problem.

Steps needed to create the IWizard and to accomplish the rest of the operation

Step 1:Follow Step 1 to Step 8 from the previous article

Step 2:Create a "Windows Forms Application" project(say ApplicationWizard) in the solution file and design a form as under

In the Form1.cs file, let us create public property for LinkedFilePath,NormalFilePath and DllPath that will hold value of form fields(Linked File Path,Normal File Path and Dll Path).

using System;
using System.Windows.Forms;

namespace ApplicationWizard
{
public partial class FormWizard : Form
{
public string LinkedFilePath;
public string NormalFilePath;
public string DLLPath;

public FormWizard()
{
InitializeComponent();
}

private void btnLinkedFile_Click(object sender, EventArgs e)
{
OpenFileDialog fDialog = new OpenFileDialog();
fDialog.Title = "Open only C# files(.cs)";
fDialog.Filter = "C# Files|*.cs";
fDialog.InitialDirectory = @"D:\";
if (fDialog.ShowDialog() == DialogResult.OK)
txtLinkedFilePath.Text = fDialog.FileName;
}

private void btnNormalFile_Click(object sender, EventArgs e)
{
OpenFileDialog fDialog = new OpenFileDialog();
fDialog.Title = "Open only C# files(.cs)";
fDialog.Filter = "C# Files|*.cs";
fDialog.InitialDirectory = @"D:\";
if (fDialog.ShowDialog() == DialogResult.OK)
txtNormalFilePath.Text = fDialog.FileName;
}

private void btnChooseDll_Click(object sender, EventArgs e)
{
OpenFileDialog fDialog = new OpenFileDialog();
fDialog.Title = "Open only DLL(.dll)";
fDialog.Filter = "Assembly Files|*.dll";
fDialog.InitialDirectory = @"D:\";
if (fDialog.ShowDialog() == DialogResult.OK)
txtDllPath.Text = fDialog.FileName;
}

private void btnOK_Click(object sender, EventArgs e)
{
//Set the property values
LinkedFilePath = txtLinkedFilePath.Text;
NormalFilePath = txtNormalFilePath.Text;
DLLPath = txtDllPath.Text;

//dispose the form object once the operation is over
this.Dispose();
}

#region Get the property values

public string GetNormalFilePath()
{
return NormalFilePath;
}

public string GetLinkedFilePath()
{
return LinkedFilePath;
}

public string GetDllPath()
{
return DLLPath;
}
#endregion
}
}

Next sign in the assembly (Windows for project i.e. ApplicationWizard) and add to gac.

Step 3:

Add a class library project (say WizardLibrary) and add the below references from .Net tab

  1. Microsoft.VisualStudio.TemplateWizardInterface
  2. System.Windows.Forms
  3. envdte
  4. VSLangProj

Also add the Windows Form Application project reference.So, the class library project (i.e. WizardLibrary) will have the following references

Now let us create a class say "CustomWizardClass.cs" that will implement the IWizard interface that contains the following methods which we need to override in the application

Our code will be confined to RunStarted and ProjectFinishedGenerating methods only for accomplishing the task.

using System;
using System.Collections.Generic;
using System.Windows.Forms;
using ApplicationWizard;
using EnvDTE;
using Microsoft.VisualStudio.TemplateWizard;
using VSLangProj;

namespace CustomWizardLibrary
{
public class CustomWizardClass : IWizard
{
private FormWizard wizardFrm;

public string _normalfilePath;
public string _linkedfilePath;
public string _dLLPath;

public void BeforeOpeningFile(ProjectItem projectItem)
{
}

public void ProjectFinishedGenerating(Project project)
{
#region Add dll to References folder dynamically

var appProject = project.Object as VSProject;

//Add dll to the References folder at runtime
appProject.References.Add(_dLLPath);

#endregion

#region Create a folder at runtime and Add a normal and linked files to it

//Create folder at runtime
project.ProjectItems.AddFolder("Add Runtime Folder");

//Access the folder
ProjectItem folderItem = project.ProjectItems.Item(1);

//Add a linked file
//folderItem.ProjectItems.AddFromFile(_linkedfilePath);

//Add Add a normal .cs file to it
folderItem.ProjectItems.AddFromFileCopy(_normalfilePath);

#endregion

#region Add a normal and linked files to the Properties folder at runtime

ProjectItem propertiesItem = project.ProjectItems.Item(3);

//Add a linked file
folderItem.ProjectItems.AddFromFile(_linkedfilePath);

//Add Add a normal .cs file to it
//folderItem.ProjectItems.AddFromFileCopy(_normalfilePath);

#endregion
}

public void ProjectItemFinishedGenerating(ProjectItem projectItem)
{
}

public void RunFinished()
{
//MessageBox.Show("End of operation");
}

public void RunStarted(object automationObject, Dictionary replacementsDictionary, WizardRunKind runKind, object[] customParams)
{
try
{
//Call win form created in the project to accept user input
wizardFrm = new FormWizard();
wizardFrm.ShowDialog();

//call property from wizardForm to read user input values
_linkedfilePath = wizardFrm.GetLinkedFilePath();
_normalfilePath = wizardFrm.GetNormalFilePath();
_dLLPath = wizardFrm.GetDllPath();
}
catch (Exception ex)
{
MessageBox.Show(ex.ToString());
}
}

public bool ShouldAddProjectItem(string filePath)
{
return true;
}
}
}

In the RunStarted method,first we are first creating an instance of the WindowsForm (wizardFrm = new FormWizard();) and then using the ShowDialog() method we are opening the custom Form Wizard.

Finally we are setting the property values being passed at runtime

//call property from wizardForm to read user input values
_linkedfilePath = wizardFrm.GetLinkedFilePath();
_normalfilePath = wizardFrm.GetNormalFilePath();
_dLLPath = wizardFrm.GetDllPath();

But we are doing the main work in the ProjectFinishedGeneratingmethod.

For adding dll to References folder dynamically, we are using the below code

 var appProject = project.Object as VSProject;
//Add dll to the References folder at runtime
appProject.References.Add(_dLLPath);

Here first we are accessing the "Object" of the EnvDte.Project interface and then typecasting to VSProject and finally accessing the References property which will give the control over the "References" folder.Once done, then we are using the Add method to add the assembly(.dll) dynamically to it.

For creating a folder at runtime and adding a .cs file to it dynamically, we are using the below code

//Create folder at runtime 
project.ProjectItems.AddFolder("Add Runtime Folder");

//Access the folder
ProjectItem folderItem = project.ProjectItems.Item(1);

//Add Add a normal .cs file to it
folderItem.ProjectItems.AddFromFileCopy(_normalfilePath);

The AddFolder method of ProjectItems property helps us to create the folder dynamically.By using the AddFromFileCopy, we can copy a file to it.

For adding a normal file and a linked file to the "Properties" folder, we use the below code

ProjectItem propertiesItem = project.ProjectItems.Item(3);

//Add a linked file
folderItem.ProjectItems.AddFromFile(_linkedfilePath);

//Add Add a normal .cs file to it
folderItem.ProjectItems.AddFromFileCopy(_normalfilePath);
For adding a normal file, we need to use AddFromFileCopy while for adding a linked file we need to use AddFromFile method

N.B.~Item(n) where n=1,2.... needs to have some words.It's value depends on the folder name being given e.g. if the folder names are "A new folder" (n = 1), "Property"(n=2), "Some other Folder "(n=3).So as per the need we need to set the value of "n" appropriately.

Next build the solution.Sign-in the assembly and add to gac.Next we need to get the assembly information for the "CustomWizardLibrary" project(we will see shortly the usefulness of this).For this issue the below command in the commandline

gacutil -l "CustomWizardLibrary"

The output will be

C:\Windows\system32>gacutil -l "CustomWizardLibrary"
Microsoft (R) .NET Global Assembly Cache Utility. Version 4.0.30319.1
Copyright (c) Microsoft Corporation. All rights reserved.

The Global Assembly Cache contains the following assemblies:
CustomWizardLibrary, Version=1.0.0.0, Culture=neutral, PublicKeyToken=33475154
8fd2ffc8, processorArchitecture=MSIL

Number of items = 1

Step 4:

Visit the "SampleProject" and open the ".vstemplate" (ProjectTemplate1.vstemplate) file and add the below after the closing </TemplateContent> tag

<WizardExtension>
<Assembly>
CustomWizardLibrary, Version=1.0.0.0, Culture=neutral, PublicKeyToken=334751548fd2ffc8
</Assembly>
<FullClassName>CustomWizardLibrary.CustomWizardClass</FullClassName>
</WizardExtension>

The information in the assembly has been obtained from the command gacutil -l "CustomWizardLibrary".That's it.Now build the solution.

And build the VSIX project after again adding the "Sample Project" in the Project Source.

Reference

  1. Visual Studio Templates
  2. Authoring an F#/C# VSIX Project Template
  3. How to: Use Wizards with Project Templates
  4. Developing Visual Studio Project Wizards

Conclusion

Hope this article has helped all of us to create a Custom Template with IWizard interface using Extensibility Project of VS2010 SDK in VS environment.Zipped file is attached

Page copy protected against web site content infringement by Copyscape

About the Author

Niladri.Biswas
Full Name: Niladri Biswas
Member Level: Platinum
Member Status: Member
Member Since: 10/25/2010 11:04:24 AM
Country: India
Best Regards, Niladri Biswas
http://www.dotnetfunda.com
Technical Lead at HCL Technologies

Login to vote for this post.

Comments or Responses

Login to post response

Comment using Facebook(Author doesn't get notification)