Introduction
Visual Studio Custom Tools are an excellent feature of the IDE as Chris Sells points out (MSDN). Whenever you create a typed DataSet
from an XSD, you're using the Microsoft custom tool code generator MSDataSetGenerator
. Having written several Visual Studio Custom Tool Code Generators (articles to follow), I was looking for an easy way to register them both for the COM interop necessary as well as make the registry entry needed for Visual Studio. I also wanted to be able to perform this registration seamlessly in an installer package. This utility is the result.
By using a simple XML template or command line arguments, this executable will register the code generator for COM as well as a custom tool. You only need to supply 4 pieces of information:
- The name of the Assembly you are going to register.
- The name you want to use for your custom tool.
- The class ID GUID for the custom tool.
- Descriptive text to be put in the registry to describe your tool.
Given this, the registration tool will present you with a window of the current activity and its status.
XML Template
="1.0" ="utf-8"
<dotNetRegistration
xmlns="http://schemas.mckechney.com/DotNetRegistrationConfig.xsd">
<dllName>SimpleDataClassVSGenerator.dll</dllName>
<customToolName>SimpleDataClassGenerator</customToolName>
<guid>{34EAC568-72B1-439e-BE3F-C1D0ADF50CE9}</guid>
<prodDesc>Simple DataClass Generator by Michael McKechney</prodDesc>
</dotNetRegistration>
This is an example of a template file I've used to register a Custom Tool I wrote. By default, the app looks for a file named DotNetRegistrationConfig.xml, but you can specify a different name via a command line argument. It's fairly straightforward with the following definition:
dllName
- the name of the assembly to register (in its current version, the application assumes that the assembly is in the same directory as itself. Since this is usually run as an install package custom action, I haven't seen the need to change it).
customToolName
- what the end user will type into "Custom Tool" property of the project file.
guid
- the class ID GUID that you've assigned the generator (this is how the VS.NET registry entry finds the DLL).
prodDesc
- how the custom tool will be described in the VS.NET registry.
Registry Template File
Windows Registry Editor Version 5.00
[HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\VisualStudio\
7.1\Generators\{FAE04EC1-301F-11D3-BF4B-00C04F79EFBC}\<<G
eneratorName>>]
"CLSID"="<<guid>>"
"GeneratesDesignTimeSource"=dword:00000001
@="<<DefaultKeyValue>>"
This file (DotNetRegistration.reg, which should also be in the same directory as the executable) acts as the registry template for the custom tool. The items in double brackets are replaced with the XML values as it is processed. A couple of things to note: The 7.1
value specifies that this will be registered as a custom tool for Visual Studio .NET 2003. You'd want to change that for different versions. Second the GUID value {FAE04EC1-301F-11D3-BF4B-00C04F79EFBC}
is for a C# code generator. If you look at the Generators
key, you'll find several different GUIDs representing different languages. If you want to register a code generator for another language, you'll need to change this value.
Using The Code
The display for this tool is a simple Windows form with a ListView
, so I won't go into detail for that. All of the real action takes place in the CompleteRegistration
method. Using some reflection and RunTime methods, I first retrieve the running directory,
string full = System.Reflection.Assembly.GetExecutingAssembly().Location;
and the root directory for the .NET runtime being used:
string dotNetRoot =
System.Runtime.InteropServices.RuntimeEnvironment.GetRuntimeDirectory();
Next, I make sure everything is where it's supposed to be and fail if they're not:
if(!File.Exists(dotNetRoot + "regasm.exe"))
{
MakeListEntry("Unable to locate regasm.exe",false,true);
Thread.Sleep(new TimeSpan(0,0,5));
throw new ApplicationException("Install Failed");
}
if(!File.Exists(currentDir+dllName))
{
MakeListEntry("Unable to locate "+currentDir+dllName,false,true);
MakeListEntry("** Installation Failed **",true,true);
MessageBox.Show(currentDir+dllName);
Thread.Sleep(new TimeSpan(0,0,5));
throw new ApplicationException("Install Failed");
}
Then, using the System.Diagnostics.Process
class, I begin to run through the registration steps:
prc.StartInfo.FileName = dotNetRoot + "regasm.exe";
prc.StartInfo.Arguments = "/tlb \""+ currentDir+dllName+"\"";
prc.StartInfo.WindowStyle = ProcessWindowStyle.Hidden;
prc.StartInfo.WorkingDirectory = dir;
prc.Start();
prc.WaitForExit();
After each step succeeds or fails, the ListView
is updated with its status. Once complete, the window closes and returns a status code 0 for success, 100 for a failure. If successful, your Custom Tool is ready for use! As I prepare my article on code generation, you'll get to see how I've used this tool in installer packages as a custom action for a seamless installation of a custom tool code generator.