KnowDotNet

Using ActiveSolutionProjects and ProjectItem.FileCodeModel to determine if a Window is a Designer or CodeWindow.

by Les Smith

How do I determine if the Active Code Window is associated with a WinForm or just simply a class without examining the code or using the CodeModel in an add-in?  This is not rocket science, and may seem like a kludge, but it works. Make the following call to the method shown in Figure 1.


   If IsProjectItemAForm(s) Then
      ' code window is code behind a form
  
Else
      ' code is not a forms code
  
End If

There are several ways to determine the type of window that is currently active and the type language that was used to create that window.  The following code will return True if the passed Window Caption is code behind a WinForm.  The following code is the easiest way to determine whether the ActiveWindow is a Form Designer or a CodeWindow, if in fact, the ActiveWindow is either.  In all of the code examples,
oVB is the application object pointing to the IDE.  If you use the code in a macro instead of an add-in, change oVB to DTE.

   ''' <summary>
   ''' Returns True if IDE ActiveWindow is a Form Designer
   '''
   ''' <returns>Boolean
   Public Function IsProjectItemAForm() As Boolean
      Dim oWin As Window = Connect.oVB.ActiveWindow
      
Return TypeOf oWin.Object Is System.ComponentModel.Design.IDesignerHost

      
If TypeOf oWin.Object Is System.ComponentModel.Design.IDesignerHost Then
         Return True
      ElseIf TypeOf oWin.Object Is TextWindow Then
         If Not oVB.ActiveDocument.ProjectItem Is Nothing Then
            If Not oVB.ActiveDocument.ProjectItem.FileCodeModel Is Nothing Then
               MsgBox("Code Window")
            
End If
         End If
      End If
   End Function

   ''' <summary>
   ''' Returns True if IDE ActiveWindow is a Code Window.
   '''
   ''' <returns>Boolean
   Public Function IsProjectItemACodeWindow() As Boolean
      Dim oWin As Window = Connect.oVB.ActiveWindow
      
If TypeOf oWin.Object Is TextWindow AndAlso _
        
Not Connect.oVB.ActiveDocument.ProjectItem Is Nothing AndAlso _
        
Not Connect.oVB.ActiveDocument.ProjectItem.FileCodeModel Is Nothing Then
         Return True
      Else
         Return False
      End If
   End Function

Alternate methods are shown below.  Every WinForm, whether it be for C# (.cs) or VB.NET (.vb), has an associated .RESX file.  The .RESX file is analogous in its use to the .FRX file in VB6.  It is an XML representation of the form.  Without examining the code of the code window, or possibly using the CodeModel, you can check for the existence of the associated .RESX file.  The IsProjectItemAForm method is used to perform this functionality.  It calls a helper method, GetActiveSolutionProject, to get the path to the form file and its .RESX file, if extant.  This method will work for both VB.NET and C# projects.

   Friend Function IsProjectItemAForm(ByVal sName As String) _
      
As Boolean
      ' This method returns True if the passed name
      ' represents a form, otherwise false.
      Dim prj As Project
      
Dim s3 As String

      Try
         prj = GetActiveSolutionProject()
        
Dim sln As String = prj.FullName
        
Dim slnPath As String = IO.Path.GetDirectoryName(sln) & "\"
        
If sName.ToUpper.EndsWith(".VB") Then
            s3 = slnPath & Replace(sName, ".vb", ".resx", _
               Compare:=CompareMethod.Text)
        
ElseIf sName.ToUpper.EndsWith(".CS") Then
            s3 = slnPath & Replace(sName, ".cs", ".resx", _
               Compare:=CompareMethod.Text)
        
Else
            Return False
         End If
         Dim fi As New System.IO.FileInfo(s3)
        
If fi.Exists Then
            Return True
         Else
            Return False
         End If
      Catch ex As System.Exception
         StructuredErrorHandler(ex.ToString)
      
End Try
   End Function

This method returns the active project in the current Solution.

   Public Function GetActiveSolutionProject() As Project
      
' Sets global miPrj = currently selected project and
      ' return the project to the caller.
      Dim projs As System.Array
      
Dim proj As Project
      
Dim projects As Projects

      
Try
         projs = Connect.oVB.ActiveSolutionProjects()
        
If projs.Length > 0 Then
            proj = CType(projs.GetValue(0), EnvDTE.Project)
            mPrj = proj
            
Return proj
        
End If
      Catch ex As System.Exception
         StructuredErrorHandler(ex.ToString)
      
End Try
   End Function

Determining the language, by which the active window was created can also be accomplished a couple of ways, as shown below.

   Public Function GetProjectItemLanguage() As Short
      Dim oWin As Window = Connect.oVB.ActiveWindow
      
If IsProjectItemACodeWindow() OrElse _
         IsProjectItemAForm()
Then
         Select Case oWin.ProjectItem.FileCodeModel.Language
            
Case "{B5E9BD33-6D3E-4B5D-925E-8A43B79820B4}"
              
Return 8 ' VB
            Case "{B5E9BD34-6D3E-4B5D-925E-8A43B79820B4}" 'C#
               Return 9 ' C#
            Case "{B5E9BD32-6D3E-4B5D-925E-8A43B79820B4}"
              
Return 1 ' c related VC++
            Case "{B5E9BD36-6D3E-4B5D-925E-8A43B79820B4}"
              
Return 1 ' c related (managed VC++
            Case Else
               Return 0
        
End Select
      End If
   End Function

The only problem with function shown above is that there are not as many strings defined as there are languages in .NET.  Secondly, the use of a GUID type string is a little strange to me.  An alternate method of getting the language type of a file is shown below.  Also this method does not require that you have an active document; it works with a passed Document object.

   Public Function GetFileType(ByRef doc As Document) As Integer
      ' Pass this function the document that you wish to get information for.
      ' Return value:
      ' 0 Unknown file type
      ' 1 C-related file, this includes .c, .cpp, .cxx, .h, hpp, .hxx
      ' 2 Java-related file, this includes .jav, .java
      ' 3 ODL-style file, .odl, .idl
      ' 4 Resource file, .rc, .rc2
      ' 7 Def-style file, .def
      ' 8 VB, .vb
      ' 9 C#, .cs
      ' 10 Batch, .bat
      Dim pos As Integer
      Dim ext As String
      Try
         ext = doc.Name.ToUpper
        
If ext.EndsWith(".RC") Or ext.EndsWith(".RC2") Then
            Return 4
        
ElseIf ext.EndsWith(".CPP") Or _
                ext.EndsWith(".C")
Or _
                ext.EndsWith(".H")
Or _
                ext.EndsWith(".HPP")
Then
            Return 1
        
ElseIf ext.EndsWith(".JAV") Or ext.EndsWith(".JAVA") Then
            Return 2
        
ElseIf ext = ".DEF" Then
            Return 7
        
ElseIf ext.EndsWith(".VB") Or ext.EndsWith(".BAS") Then
            Return 8
        
ElseIf ext.EndsWith(".CS") Then
            Return 9
        
ElseIf ext.EndsWith(".BAT") Then
            Return
10
         Else
            Return 0
        
End If
      Catch ex As System.Exception
        
Return 0
      
End Try
   End Function