Introduction
This topic describes how to write simple New project wizard for Visual Studio, that will generate some data, such as code file, and attach it to the project.
Part One: Coding
Hello! Today we'll learn, how to create your own wizard, that will do some work for us and instead of us. Sounds good, isn't it?
First of all, I must say, that this wizard will be for VS 2005. So start it and create new Class Library Project. In generated project (it's generating from template, we'll speak about them later) open file Class1.cs (you may rename it) and erase every line of code in it, because we'll do everything with our own hands.
References
First we must specify "using" part. We'll use these namespaces:
using System;
using System.Text;
using System.Windows.Forms;
using System.IO;
using Microsoft.VisualStudio.TemplateWizard;
using EnvDTE;
You may notice some unfamiliar names. Last two are namespaces for VS 2005 developer team, so for little time we may feel ourself as IDE creators. Well, if we want to use these cool namespaces we must add proper references which have same names (Microsoft.VisualStudio.TemplateWizard
and EnvDTE
).
Main Class
As soon as we have "using
" part, we must create namespace and class in it. Let's do it – namespace must be the same as the default namespace of your solution (you may see it in solution properties). Class may have any name that you wish and what is most important: it must be inherited from the IWizard
interface, which will provide us needed wizard logic. For example:
namespace SampleWizard
{
public class WizardClass : IWizard
{
}
}
Implementing
Well, for now it will be great to implement methods of IWizard. Let's do this:
public void BeforeOpeningFile(ProjectItem projectItem)
{
}
public void ProjectFinishedGenerating(Project project)
{
}
public void ProjectItemFinishedGenerating(ProjectItem projectItem)
{
}
public void RunFinished()
{
}
public void RunStarted(object automationObject,
Dictionary<string, string> replacementsDictionary,
WizardRunKind runKind, object [] customParams)
{
}
public bool ShouldAddProjectItem(string filePath)
{
return true;
}
As we can see IWizard
provides us various ways to manage creating project. For us important only these methods: RunStarted
and ProjectFinishedGenerating
. Later, I think, you could add some additional code, that answers your needs.
User Interface
Let's find out our two methods closer. RunStarted
starts when VS finishing generating new project according to its template, so this is the main entry point for our wizard. Parameters of the method are:
automationObject
– may be casted as DTE
replacementsDictionary
– contains reserved words for template, that will be replaced with the values of the dictionary. Also, you may add your own in format %word%
. More information in MSDN runKind
– specify run kind of the wizard customParams
– custom params
Well, this method will be main for us. Next question is: how we imagine interface of our wizards. By the way, it may be invisible at all. For example, in this method we can only change project name by adding word "My" (using replacementsDictionary) at the beginning or something else. But in our case, we'll make a little bit more and add user interface to wizard. It's very easy. Just add new form in the solution. Let's call it UserInputForm
. Also let's place some controls on it, like textbox, label, button and any other stuff that you want. Our wizard will automatically add to project code file with generated empty class. So call textbox tbName, set label text to: "Enter name of new class" and make button an AcceptButton of the form, also set it text to OK.
In the code of form create new string property named ClassName and in get-section write:
return tbName.Text;
Next we must override the OnClosing event and write:
if (ClassName == "")
return;
base.OnClosing(e);
Well, I think it will be enough for our training sample. Let's go back to our WizardClass and write at the beginning:
private <code>UserInputForm newForm;
Then go to RunStarted
method and type:
newForm = new <code>UserInputForm();
newForm.ShowDialog();
Project Management
As you understand this will show our dialog as soon Visual studio will create new project. In this dialog user assumed to enter the name of new class, that we'll create in new file and add to the project. So next we want get an event where we can add some stuff to project. This is ProjectFinishedGenerating
method. Here we'll create new code using data from Input form, write this code to the file and attach file to the project. Something like this:
string dir = Path.GetDirectoryName(project.FullName);
string code =
<code>"using System;\nusing System.Collections.Generic;\nusing System.Text;\n\n" +
"namespace WizardGenerated\n{\n\r\tpublic class " +
newForm.ClassName + "\n\r\t{\n\r\t}\n}";
StreamWriter sw = new StreamWriter(dir + "\\" + newForm.ClassName + ".cs");
sw.Write(code);
sw.Close();
project.ProjectItems.AddFromFile(dir + "\\" + newForm.ClassName + ".cs");
I think everything is pretty clear. We just writing to the string template of new code file with the user-defined class name. Then we write it to the disk and add new project item from file.
Part Two: Installing
Congratulations!
If you have reached this section it means, that you already have created your own wizard. Just build the project and the dll with the wizard will appear.
But what we can do with this library? Well, installing of the wizard it's also difficult thing. First, you must add you assembly (eq. dll) to the GAC (General assembly cache). To do that, you must have a strong name for assembly and to do this you must sign your assembly. Sounds scaring? To battle!
Signing
Signing is very easy thing in VS 2005, because its developers add special button to the properties of the project and saved us from boring console stuff. So, go to the properties page of you project and switch to the Signing tab. Check "Sign the assembly" box and in the combo-box create new key file. That's all.
Adding to GAC
Next, we must add assembly to GAC. Very easy: just run SDK Command Prompt from your Start\Programs\Microsoft .NET Framework SDK v2.0. In appeared command window type: gacutil -i "<path to your compiled dll here>"
. This will install your dll to assembly cache and allow you to reference on it in templates. Also we must know token of assembly key. There is two ways to find it. First is to type in same command window: gacutil –l >> "some path to file here"
. This lists all installed assemblies with their properties including token to specified file. Using this way, you may also make sure, that assembly really was added to GAC. Simply find it by the name in the list and save it's token somewhere. It must be in hexadecimal form, something like: 2ee9fb161af32259. Other way to find token is to use sn.exe
tool from same FW 2.0 SDK. In the Command Prompt type: sn -T "<path to dll here>"
. This command will show you a token of assembly.
Into the Template
So, now you have assembly, installed in the cache, and its token in the hands. It's time to add reference of the wizard to some template. You can create your own template, but this time we'll use one of default Visual Studio templates. Go to the MyDocuments directory and find there folder named Visual Studio 2005\Templates\ProjectTemplates\Visual C#. You can see there a list of zip files. This is archived templates of the projects. Unzip Console.zip and open MyTemplate.vstemplate
file. We can see simple xml file. After the "template content" node we must add these lines:
<WizardExtension>
<Assembly>SampleWizard, Version=1.0.0.0, Culture=neutral,
PublicKeyToken=2ee9fb161af32259, Custom=null</Assembly>
<FullClassName>SampleWizard.WizardClass</FullClassName>
</WizardExtension>
Of course your values and names may be different. After saving this document just zip the folder back, and restart studio. If everything was done clear, when you'll try to create new console project our dialog form will appear and after closing wizard dialog code file will be added to project.
Restore Everything
If you want undo this things, just return template archive to it's original state and uninstall dll from GAC using gacutil
with –u
key. If you want to make some changes to wizard you must rebuild it, uninstall it from GAC and install again
Finally
So, for now you know how automatize some work that you do too often. Hope you'll enjoy this feature and find it useful.