Thursday, January 19, 2006

Determining Name And Path Of Output File in VS.NET 2005 Automation

When implementing an extension, e.g. an addin for VS, you may want to determine the path (location) and name of the assembly that is being built as part of a project. One way would be to read the project file, e.g. *.csproj. As it happens to be an XML file it is easy to determine the correct node. A different approach though is using the Project automation object. Project has a set of properties and for C#/VB.NET/J# projects it contains a property named "OutputFileName". The value of that property is the assembly name. Next, you need to determine the path. First you need to know the path to the project, which you can determine using the directory part of Project.FileName. This gives you the location of the project file. In order to determine the output path for the assembly, you need the active configuration for the project, which you obtain using Project.ConfigurationManager.ActiveConfiguration. The ActiveConfiguration object has a property named "OutputPath", which is the relative path from the project file to the output folder. One might be tempted to use ActiveConfiguration.OutputGroups. For that to work the project needs to have been built successfully once, which might not always be the case. Furthermore, Configuration.OutputGroups doesn't work in a handler for the solutions event Opened. Therefore I settled on the following code for determining the path and the name of the target assembly:
string GetOutputPathAndFile(Project p) {
   string outputPath;
   string outputFileName;
   string outputPathAndFile;
   string projectLocation;
   try {
      Configuration activeConf = p.ConfigurationManager.ActiveConfiguration;
      projectLocation = (new FileInfo(p.FileName)).DirectoryName;
      outputFileName = p.Properties.Item("OutputFileName").Value.ToString();
      outputPath = activeConf.Properties.Item("OutputPath").Value.ToString();
      outputPath = Path.Combine(projectLocation, outputPath);
      outputPathAndFile = Path.Combine(outputPath, outputFileName);
   }
   catch(Exception ex) {
      System.Diagnostics.Debug.WriteLine(ex.Message);
   }
   return outputPathAndFile;
}
If you are aware of a better solution, please don't hesitate to comment! I'm eager to learn.

Saturday, January 14, 2006

Update: User Control in Tool Window of a Visual Studio Addin

After some more experimentation it seems that the last parameter of CreateToolWindow2() is null, if the hosted control is in a separate assembly / project. For instance: Suppose you have a solution containing two projects, let's call them MyAddIn and MyControls. The first one is your add-in itself and the second one contains some controls you want to have in a separate assembly as you want to use them also for other solutions, e.g. a stand-alone application. Now, if you have a UserControl in the project MyControls, let's call it MyUserControl1, then you can still host that control in your add-in. However, in this case the method CreateToolWindow2() returns null as the value of the last parameter. If on the other hand you add a UserControl, let's call it MyUserControl2, to the add-in project 'MyAddIn', and then host MyUserControl2 in the add-in, the last parameter of CreateToolWindow2() will contain a reference to your MyUserControl2 instance. Of course MyUserControl2 can in turn contain one or more instances of MyUserControl1. Strange that whether or not a UserControl is contained in the add-in assembly/project or not makes a difference regarding the last parameter of CreateToolWindow2(). Am I missing something?

Wednesday, January 04, 2006

The invoked member is not supported in a dynamic assembly - Reprise

Here is another workaround for the issue with the form designer: In some cases it is sufficient to just close and re-open the solution and/or Visual Studio. From my perspective this indicates a bug in the IDE. So it's back to Microsoft.