A while back, we received a suggestion via our product feedback website. The site lets anyone log bugs and/or suggestions for our product, which feed directly into our internal bug tracking mechanism. In other words, the site is not simply a façade but a direct input into our development, supplementing our internal testing (it’s hard to find every bug in a piece of code as large as Visual Studio) and helping us prioritize issues.

The upside of this website is that we have received valuable feedback, fixed real customer bugs (many of these fixes will be in our upcoming service pack) and identified certain features that are lacking and others that are slowly becoming superfluous. For example, many users voted on the fact that we lack support for code snippets in C++, a feature I would love to have and we are investigating providing this support in Orcas (our next release). When so many customers show their desire for the feature, it helps us allocate resources, something which is always in scarce supply

The downside of the product feedback is the simple fact that we can’t handle the quantity of bugs and suggestions that people submit (my personal opinion) and we’ve had to make some tough decisions with prioritization. While we fight to keep our product bug-free, we also understand the inescapable need to implement our customers’ suggestions. It’s one of the most simultaneously loathsome and attractive aspects of being a program manager at Microsoft. After all, few people in the industry can say they decide whether some feature will make it into a product used by millions

All this rambling has me straying from this post’s purpose. Yet another piece of (macro) code. Today’s macro was inspired by a suggestion we received via product feedback, which I deemed unworthy due to how easy it is to add using our extensibility model. Without further ado, here is a macro to preprocess the current file and bring it up in the editor.

 

    Sub RunPreprocessor()

 

        Dim doc As Document = DTE.ActiveDocument

        Dim docname As String = doc.Name.ToLower

        Dim project As Project = doc.ProjectItem.ContainingProject

 

        If doc.Language = "C/C++" Then

            ' not the most accurate way of identifying a cpp file

            If docname.EndsWith(".cpp") Then

 

                Dim vcproj As VCProject = project.Object

                Dim projfiles As IVCCollection = vcproj.Files

                Dim vcfile As VCFile = Nothing

 

                ' find the file in current project

                For Each f As VCFile In projfiles

                    If f.Name = doc.Name Then

                        vcfile = f

                        Exit For

                    End If

                Next

 

                Dim activeconfigname As String = DTE.Solution.SolutionBuild.ActiveConfiguration.Name

                Dim fileconfig As VCFileConfiguration = vcfile.FileConfigurations(activeconfigname)

                Dim filecompiler As VCCLCompilerTool = fileconfig.Tool

 

                ' toggle preprocessing on, compile, toggle preprocessing

                filecompiler.GeneratePreprocessedFile = preprocessOption.preprocessNoLineNumbers

                fileconfig.Compile(True, True)

                filecompiler.GeneratePreprocessedFile = preprocessOption.preprocessNo

 

                Dim preprocessedpath = doc.Path + docname.Replace(".cpp", ".i")

                ClearEmptyLines(preprocessedpath)

                DTE.ItemOperations.OpenFile(preprocessedpath + ".cpp")

 

            End If

        End If

 

    End Sub

And the required helper function:

    Sub ClearEmptyLines(ByVal filepath As String)

        Dim line As String

 

        ' iterate through a file and write out non-empty lines into a new file

        Using sr As New IO.StreamReader(filepath)

            ' out file name is <filename>.i.cpp (for highlighting)

            Using sw As New IO.StreamWriter(New IO.FileStream(filepath + ".cpp", IO.FileMode.Create))

                While Not sr.EndOfStream

                    line = sr.ReadLine()

                    If line.Length > 0 Then

                        sw.WriteLine(line)

                    End If

                End While

            End Using

        End Using

    End Sub

The implementation has two issues in its current form. The first is that changing the compiler property on the file causes the project file to change, which in turn requires checking out the project file and probably re-linking the project. The second is that the macro always rebuilds the preprocessed file even when there is no need to. I will post a follow-up, solving both of these issues.