Setting the properties of a reference programmatically

Sunday, May 22, 2011

I am currently exploring some of the Visual Studio automation possibilities. In this post I will describe how to set the properties of a reference programmatically and some of the issues I had to deal with.

All the project related classes, enumeration, interfaces are located in the VSLangProj.dll, VSLangProj2.dll, VSLangProj80.dll, VSLangProj90.dll and VSLangProj100.dll assemblies. These are usually located in the subdirectory “\Common7\IDE\PublicAssemblies\” of your Visual Studio installation directory.

With almost each new version of Visual Studio a new VSLangProj assembly is provided with new types that covers new project functionality of that Visual Studio version. A good example for this is the new “Embed Interop Types” property of a reference in Visual Studio 2010.

Before you can do anything with a project and the references of the project you have to get a reference to the VSProject2 type. Projects inside a solution can be accessed via the DTE/DTE2 object. This is the top-level object in the visual studio automation model. You can find this type inside the EnvDTE.dll or EnvDTE80.dll assembly.

   1: public void Example1(DTE2 instance)
   2: {
   3:    EnvDTE.Project project = instance.Solution.Projects.Item(0);
   4:  
   5:    var vsProject = project.Object as VSLangProj80.VSProject2;
   6:  
   7:     if (vsProject != null)
   8:     {
   9:         //do some stuff
  10:     }
  11: }

The VSProject2 object contains a property “References” with a collection of Reference4 types. This off course depends on the version of Visual Studio you are writing the automation for. Reference4 types can only be used in Visual Studio 2010. So if you are writing automation for Visual Studio 2008 you will have to use the Reference3 type.

Before we can use the Reference4 type we have to deal with the problem that we can’t find the definition of this interface anywhere. It should be located in the VSLangProj100.dll assembly but it isn’t. So this becomes a problem if we want to set the property “Embed Interop Types” of the reference. This is the only new property of the Reference4 interface. To handle this problem we have to create our own Reference4 interface with the exact same definition. The most important implementation aspect is that you use the right GUID and dispatch id’s. This must be exactly the same as the original definition. We have to use the OLE/COM Object Viewer tool to get this information.

image

The Reference4 interface should exists in the Interfaces node of the treeview.

olecomobjectvierwer2

If you double click on the Reference4 node and click on View Type Info you will get all the information you need.

clip_image004

The first red line is the guid of the interface and the second the dispatch id of a property in hex. You can also see that obviously Reference4 inherits Reference3 and so forth. Now with this information you can come with the following interface definition.

   1: [Guid("F71B6036-80F1-4F08-BC59-B5D92865F629")]
   2: public interface Reference4
   3: {        
   4:     // Reference        
   5:     [DispId(1)] DTE DTE { get; }        
   6:     [DispId(2)] References Collection { get; }        
   7:     [DispId(3)] Project ContainingProject { get; }        
   8:     [DispId(4)] void Remove();        
   9:     [DispId(5)] string Name { get; }        
  10:     [DispId(6)] prjReferenceType Type { get; }        
  11:     [DispId(7)] string Identity { get; }        
  12:     [DispId(8)] string Path { get; }        
  13:     [DispId(9)] string Description { get; }        
  14:     [DispId(10)] string Culture { get; }        
  15:     [DispId(11)] int MajorVersion { get; }        
  16:     [DispId(12)] int MinorVersion { get; }        
  17:     [DispId(13)] int RevisionNumber { get; }        
  18:     [DispId(14)] int BuildNumber { get; }        
  19:     [DispId(15)] bool StrongName { get; }       
  20:     [DispId(16)] Project SourceProject { get; }        
  21:     [DispId(17)] bool CopyLocal { get; set; }        
  22:     [DispId(18), TypeLibFunc(1088)] dynamic get_Extender(string ExtenderName);        
  23:     [DispId(19)] dynamic ExtenderNames { get; }        
  24:     [DispId(20)] string ExtenderCATID { get; }        
  25:     [DispId(21)] string PublicKeyToken { get; }        
  26:     [DispId(22)] string Version { get; }         
  27:     // Reference2        
  28:     [DispId(100)]string RuntimeVersion { get; }         
  29:     // Reference3       
  30:     [DispId(120)] bool SpecificVersion { get; set; }        
  31:     [DispId(121)] string SubType { get; set; }        
  32:     [DispId(122)] bool Isolated { get; set; }       
  33:     [DispId(123)] string Aliases { get; set; }        
  34:     [DispId(124)] uint RefType { get; }       
  35:     [DispId(125)] bool AutoReferenced { get; }     
  36:     [DispId(126)] bool Resolved { get; }        
  37:     // Reference4       
  38:     [DispId(127)] bool EmbedInteropTypes { get; set; }    
  39: }

Now you can use one of the following code snippets to get a reference to the Reference4 type and set anything you want.

   1: public void Example2(DTE2 instance)
   2: {
   3:     EnvDTE.Project project = instance.Solution.Projects.Item(0);
   4:  
   5:     var vsProject = project.Object as VSLangProj80.VSProject2;
   6:  
   7:     if (vsProject != null)
   8:     {
   9:         var firstReference = vsProject.References.Item(0) as Reference4;
  10:  
  11:         if (firstReference != null)
  12:         {
  13:             firstReference.SpecificVersion = true;
  14:             firstReference.CopyLocal = true;
  15:             firstReference.EmbedInteropTypes = true;
  16:         }
  17:                 
  18:     }
  19: }
  20:  
  21: public void Example3(DTE2 instance)
  22: {
  23:     EnvDTE.Project project = instance.Solution.Projects.Item(0);
  24:  
  25:     var vsProject = project.Object as VSLangProj80.VSProject2;
  26:  
  27:     if (vsProject != null)
  28:     {
  29:         VSLangProj.Reference foundRef = vsProject.References.Find("FoobarAssembly");
  30:  
  31:         if (foundRef != null)
  32:         {
  33:             foundRef.CopyLocal = true;
  34:         }
  35:  
  36:         Reference4 foundRef4 = foundRef as Reference4;
  37:  
  38:         if (foundRef4 != null)
  39:         {
  40:             foundRef4.EmbedInteropTypes = true;
  41:         }
  42:     }
  43: }
Comments are closed