My favorites | Sign in
Logo
             
Search
for
Updated Oct 29, 2009 by maruelatchromium
WindowsVisualStudioMacros  
Visual Studio macros to help debug Chromium

Random Visual Studio macros

Note: Syntax highlighting is wrong, there's nothing to do about it.

How to install one

How to bind

Once you've added a macro, you can double click it in the Macro Explorer to execute it, but it's often convenient to bind it.

Automatically grab chromium child processes

Hint: Bind AttachChromium() to a toolbar button and enable the "Debug Location" toolbar to navigate between processes.

Public Sub AttachToProcesses(ByVal process_name As String, ByVal AttachIfCmdLineContains As String)
	' Attaches to a process by its name. If a command line argument is needed, looks for it.'
	Dim pids As New System.Collections.Generic.List(Of Integer)
	Dim pids_debugged As New System.Collections.Generic.List(Of Integer)
	For Each debugged As EnvDTE.Process In DTE.Debugger.DebuggedProcesses
		pids_debugged.Add(debugged.ProcessID)
	Next
	Dim processes As System.Diagnostics.Process() = System.Diagnostics.Process.GetProcessesByName(process_name)
	For Each proc As System.Diagnostics.Process In processes
		If proc.MainModule.FileName().ToLower().Contains(AttachIfCmdLineContains.ToLower()) Then
			pids.Add(proc.Id)
		End If
	Next
	For Each proc As EnvDTE.Process In DTE.Debugger.LocalProcesses
		If Not pids_debugged.Contains(proc.ProcessID) And pids.Contains(proc.ProcessID) Then
			proc.Attach()
		End If
	Next
End Sub

Sub AttachChromium()
	' Attaches to the chrome.exe processes that has \code\ in their command line'
	' argument or binary path.'
	AttachToProcesses("chrome", System.IO.Path.GetDirectoryName(DTE.Solution.FullName) & "\")
End Sub

Format comments to 80 cols

Hint: Bind FormatComment() to Alt-F.

Sub FormatComment()
	' Make comments fit 80 cols.'
	Dim sel As TextSelection = CType(DTE.ActiveDocument.Selection, TextSelection)
	Dim text As String = sel.Text
	Dim CommentMarker As String = "//"

	' InStr() is one-based'
	Dim commentColumn As Integer = InStr(text, CommentMarker)
	' Substring() is zero-based'
	Dim prefix As String = text.Substring(0, commentColumn - 1) + CommentMarker + " "
	' Take in account the length of the comment marker and the space. The maximum is 81'
	' and not 80; column starts at 1 and not 0. InStr() is 1 based too.'
	Dim maxline As Integer = 81 - commentColumn - CommentMarker.Length

	' Remove comment marker'
	text = System.Text.RegularExpressions.Regex.Replace(text, "^ *// *", "", System.Text.RegularExpressions.RegexOptions.Multiline)
	' Remove \r\n to put all the text on one line'
	text = System.Text.RegularExpressions.Regex.Replace(text, " *[" + vbLf + "]+ *", " ")
	text = text.Trim()

	Dim newtext As String = ""

	While text <> ""
		' InStrRev() is one-based'
		Dim pos As Integer = InStrRev(text, " ", maxline)
		If pos = 0 Then
			pos = text.Length
		End If

		' Substring() is zero-based'
		Dim line As String = text.Substring(0, pos).Trim()
		newtext += prefix + line + vbLf
		text = text.Substring(pos)
	End While

	sel.Insert(newtext, vsInsertFlags.vsInsertFlagsContainNewText)
End Sub

Alternate between source and header file

Hint: Bind SwitchOfSourceFile() to Alt-O.

Function TryOpenProjectItem(ByVal project_items As ProjectItems, ByVal item As String) As Boolean
	TryOpenProjectItem = False
	If project_items Is Nothing Then
		Exit Function
	End If
	For Each project_item As EnvDTE.ProjectItem In project_items
		If Strings.StrComp(project_item.Name, item, CompareMethod.Text) = 0 Then
			' Found!'
			project_item.Open().Activate()
			TryOpenProjectItem = True
		End If
		If project_item.SubProject Is Nothing Then
			TryOpenProjectItem = TryOpenProjectItem(project_item.ProjectItems, item)
		Else
			TryOpenProjectItem = TryOpenProjectItem(project_item.SubProject.ProjectItems, item)
		End If
		If TryOpenProjectItem = True Then
			Exit Function
		End If
	Next
End Function

' Will find the file if it is:'
' - beside in the same directory,'
' - in "opened documents",'
' - in the same project'
' - TODO(maruel): Try in includes?'
Public Function TryOpen(ByVal FileName As String, ByVal Path As String, ByVal project As EnvDTE.Project) As Boolean
	TryOpen = False
	' Try to open the file in same folder.'
	Try
		DTE.Documents.Open(Path + FileName, "Text")
		TryOpen = True
		Exit Function
	Catch
	End Try

	' Search document in the same project.'
	If Not project Is Nothing Then
		TryOpen = TryOpenProjectItem(project.ProjectItems, FileName)
	End If

	' Search opened documents.'
	For Each myDocument As EnvDTE.Document In DTE.Documents
		If Strings.StrComp(myDocument.Name, FileName, CompareMethod.Text) = 0 Then
			Try
				myDocument.Activate()
				TryOpen = True
				Exit Function
			Catch
			End Try
		End If
	Next
End Function

' Shortcut.'
Public Function TryOpen(ByVal FilePathName As String) As Boolean
	TryOpen = TryOpen(System.IO.Path.GetFileName(FilePathName), System.IO.Path.GetFullPath(FilePathName), Nothing)
End Function

' Will cycle thru .cc, .cpp, .h and .inl file extensions'
Public Sub SwitchOfSourceFile()
	' For source looping. It\'s not extension in the true meaning.'
	Dim supportedExts As String() = {"-inl.h", ".cc", ".cpp", ".h", ".hpp", ".inl"}

	Dim origFile As String
	Dim origFilePath As String
	Dim project As EnvDTE.Project
	Try
		origFile = DTE.ActiveDocument.Name
		origFilePath = DTE.ActiveDocument.Path
		project = DTE.ActiveDocument.ProjectItem.ContainingProject
	Catch
		Exit Sub
	End Try

	' This is touchy here because we want to support both ".h" and "-inl.h" so we have to find the right extension first.'
	For indexExt As Integer = 0 To supportedExts.Length - 1
		Dim ext As String = supportedExts(indexExt)
		If origFile.Length > ext.Length Then
			If origFile.Substring(origFile.Length - ext.Length) = ext Then
				Dim FileToOpen As String = origFile.Substring(0, origFile.Length - ext.Length)
				' Try the rest'
				For indexTry As Integer = 0 To supportedExts.Length - 2
					Dim trueIndex As Integer = (indexExt + indexTry + 1) Mod supportedExts.Length
					If TryOpen(FileToOpen + supportedExts(trueIndex), origFilePath, project) Then
						' We succeeded'
						Exit Sub
					End If
				Next
				' We failed.'
				Exit For
			End If
		End If
	Next
	' We failed.'
End Sub

Run the currently selected google test

See the function's description.

Sub RunCurrentGTest()
	' From the active source file, find the test that the user wants to run'
	' based on the current cursor position. Set the project containing this'
	' source file as the startup project, changes the command line to run'
	' only this test, compile the project and starts it under the debugger.'
	' Doesn\'t change any breakpoint.'
	Dim ActiveDoc As Document = DTE.ActiveDocument

	' Try to guess the test to run.'
	Dim TestGroup As String = ""
	Dim TestName As String = ""
	Dim selection As TextSelection = CType(ActiveDoc.Selection(), TextSelection)
	Dim toppoint As EditPoint = selection.TopPoint.CreateEditPoint()
	Dim bottompoint As EditPoint = selection.BottomPoint.CreateEditPoint()
	Dim ranges As TextRanges = selection.TextRanges
	Dim line As Integer = selection.TopPoint.Line
	' selection.FindPattern() is crummy.'
	While line <> 0
		selection.GotoLine(line)
		selection.SelectLine()
		Dim match As System.Text.RegularExpressions.Match = System.Text.RegularExpressions.Regex.Match(selection.Text, "TEST[_F]*\((.*),(.*)\)")
		If Not match Is System.Text.RegularExpressions.Match.Empty Then
			TestGroup = match.Groups.Item(1).Value.Trim()
			TestName = match.Groups.Item(2).Value.Trim()
			Exit While
		End If
		line = line - 1
	End While
	' Cheap way to try to restore the old selection. Isn\'t 100% correct.'
	selection.MoveToLineAndOffset(toppoint.Line, toppoint.LineCharOffset)
	selection.MoveToLineAndOffset(bottompoint.Line, bottompoint.LineCharOffset, True)

	' From the current active document, find the project and the active configuration.'
	Dim Proj As Project = ActiveDoc.ProjectItem.ContainingProject
	Dim config As Configuration = Proj.ConfigurationManager.ActiveConfiguration

	' Fix the command line argument.'
	Dim CmdLine As EnvDTE.Property = config.Properties.Item("CommandArguments")
	If TestGroup <> "" Then
		CmdLine.Value = "--gtest_filter=" & TestGroup & "." & TestName
	Else
		' Run all'
		CmdLine.Value = ""
	End If

	' Set it as startup project.'
	Dim SoluBuild As SolutionBuild = DTE.Solution.SolutionBuild
	Dim StartupProject As String
	StartupProject = Proj.UniqueName
	SoluBuild.StartupProjects = StartupProject

	' Build it.'
	SoluBuild.BuildProject(config.ConfigurationName, Proj.UniqueName, True)

	' Start it.'
	DTE.Debugger.Go()
End Sub

Add a definition in a .cc file for the currently selected method/variable declarations.

Select a class method or member variable declaration, then run this macro to add empty definitions in the corresponding .cc file. Hint: Bind AddDefinitionForSelectedDeclaration() to Alt-D

Public Sub AddDefinitionForSelectedDeclaration()
    ' Get the function declaration text.'
    Dim sel As TextSelection = DTE.ActiveDocument.Selection
    Dim text = sel.Text.Trim()

    Dim className = ClassNameFinder()

    Dim funcDef = text
    ' Remove comments first, since they mess up the rest of the regexes.'
    funcDef = Regex.Replace(funcDef, "//.*$", "", RegexOptions.Multiline)
    ' Try to put declarations all on the same line.'
    funcDef = Regex.Replace(funcDef, "([^;]) *\n *", "$1 ", RegexOptions.Singleline)
    ' Replace the identifier with ClassName::identifier.'
    funcDef = Regex.Replace(funcDef, "^(.*) ([^ ()]+;|[^ ()]+ *\()", _
                                "$1 " + className + "::$2", RegexOptions.Multiline)
    ' Convert ; to {} for functions.'
    funcDef = Regex.Replace(funcDef, "\) *;", ") {" + vbLf + "}" + vbLf)
    ' Remove leading whitespace, static/virtual.'
    funcDef = Regex.Replace(funcDef, "^ *", "", RegexOptions.Multiline)
    funcDef = Regex.Replace(funcDef, "static *", "// static" + vbLf)
    funcDef = Regex.Replace(funcDef, "virtual *", "")
    ' Collapse empty lines.'
    funcDef = Regex.Replace(funcDef, vbLf + vbLf + "+", vbLf + vbLf)

    ' Switch to source file and append defs at the end.'
    GoToCCFile()
    sel = DTE.ActiveDocument.Selection
    sel.EndOfDocument()
    sel.Insert(funcDef)
End Sub

' If the current document is an .h file, try to switch to the .cc file of the same name.'
Sub GoToCCFile()
    Dim origFile = DTE.ActiveDocument.FullName()
    If Regex.IsMatch(origFile, "\.h$") Then
        Dim altFile = Regex.Replace(origFile, "\.h$", ".cpp")
        If Not My.Computer.FileSystem.FileExists(altFile) Then
            altFile = Regex.Replace(origFile, "\.h$", ".cc")
        End If
        DTE.Documents.Open(altFile, "Text")
    End If
End Sub

' Finds which class the cursor is inside of, and returns the class name.'
' Note: This is indent based.  Your class bodies must be indented, and the closing'
' "};" must line up with the initial "class".'
' ex: class Foo {\nclass Bar {\n <cursor>...'
' returns: "Foo::Bar"''
Private Function ClassNameFinder() As String
    Dim sel As TextSelection = DTE.ActiveDocument.Selection
    Dim origPos = sel.ActivePoint.AbsoluteCharOffset
    Dim endLine = sel.CurrentLine

    sel.MoveToAbsoluteOffset(1, True)
    Dim pos = 0
    Dim text = sel.Text
    Dim className = ClassNameFinderInternal(text)
    sel.MoveToAbsoluteOffset(origPos)

    If className.Length > 0 Then
        className = className.Substring(2)
    End If
    Return className
End Function

' Helper function for ClassNameFinder.  Returns the full class name that doesn\'t'
' have matching close braces in the given text string.'
Private Function ClassNameFinderInternal(ByRef text As String) As String
    Dim className = ""
    While text.Length > 0
        Dim match = Regex.Match(text, "^( *)class ([^ \n\r{:;]+)[^\n\r;]*$", RegexOptions.Multiline)
        If match.Success Then
            Dim indentString = match.Groups.Item(1).Value
            Dim newClass = "::" + match.Groups.Item(2).Value
            text = text.Substring(match.Index + match.Length)

            match = Regex.Match(text, "^" + indentString + "};", RegexOptions.Multiline)
            If match.Success Then
                text = text.Substring(match.Index + match.Length)
            Else
                className += newClass + ClassNameFinderInternal(text)
            End If
        Else
            text = ""
            Exit While
        End If
    End While

    Return className
End Function

Open all the files of a given change list.

Specify which change list you want to open all files of, and this macro will find it if it lies in the same svn repository as the currently opened solution. If it can't find it there, it will prompt you to specify the path of the root of your client view.

Sub OpenChangeListFiles()
    ' Open all the files of a given change list.'
    Dim change_list_name As String = InputBox("Enter the change list name")
    If String.IsNullOrEmpty(change_list_name) Then
        Exit Sub
    End If
    Dim solution As Solution = DTE.Solution
    ' Try to get the source root path starting from the solution path and search upward in the folder hierarchy.'
    Dim source_root_path As String
    If Not solution Is Nothing And Not String.IsNullOrEmpty(solution.FullName) Then
        source_root_path = GetRepositoryRootFolder(solution.FullName)
    End If
    If source_root_path Is Nothing Or String.IsNullOrEmpty(source_root_path) Then
        ' We couldn\'t find the root ourselves, ask the user.'
        source_root_path = InputBox("Can't find a solution file path." + vbNewLine + "Please specify the root of your source tree.")
        If String.IsNullOrEmpty(source_root_path) Then
            Exit Sub
        End If
    End If
    ' Look for the CL file in the appropriate folder.'
    Dim change_list_file As String = source_root_path + "\.svn\gcl_info\changes\" + change_list_name
    If Not IO.File.Exists(change_list_file) Then
        ' OK, give one last chance to the user to specify the appropriate path for the CL.'
        source_root_path = InputBox("Can't find CL: '" + change_list_name + "', under " + source_root_path + vbNewLine + "Specify the proper root folder one last time:")
        If String.IsNullOrEmpty(source_root_path) Then
            Exit Sub
        End If
        change_list_file = source_root_path + "\.svn\gcl_info\changes\" + change_list_name
        If Not IO.File.Exists(change_list_file) Then
            MsgBox("Can't find CL: '" + change_list_name + "', under " + source_root_path)
            Exit Sub
        End If
    End If
    ' Now load its content.'
    Dim change_list_content As String
    Try
        change_list_content = IO.File.ReadAllText(change_list_file, Text.Encoding.GetEncoding(1252))
    Catch e As Exception
        MsgBox("Exception: " + e.Message())
        Exit Sub
    End Try
    ' Match the lines where the paths of the opened files can be found.'
    Dim pattern As String = "M\s*(.*)$"
    Dim regex As New Text.RegularExpressions.Regex(pattern, Text.RegularExpressions.RegexOptions.Multiline)
    Dim matches As Text.RegularExpressions.MatchCollection = regex.Matches(change_list_content)
    Dim match
    For Each match In matches
        ' And now we can open each and everyone of them.'
        Dim file_path As String = match.Groups(1).ToString()
        Dim full_path As String = source_root_path + "\" + Left(file_path, file_path.Length() - 1)
        If IO.File.Exists(full_path) Then
            DTE.ItemOperations.OpenFile(full_path)
        End If
    Next
End Sub

Private Function GetRepositoryRootFolder(ByVal solution_path As String) As String
    Try
        ' We look for a change in the svn: root path in the .svn/entries file.'
        ' This means we have reached view root or changed repo.'
        Dim solution_folder As String = IO.Directory.GetParent(solution_path).ToString()
        Dim svn_root_path As String = GetSvnRootPath(solution_folder)
        If String.IsNullOrEmpty(svn_root_path) Then
            ' We don'\t seem to be within a repo if we can\'t get the SVN root path.'
            Return ""
        End If
        ' We need to keep the previous path, since we need to stop once we found a bad parent.'
        Dim previous_path As String = solution_folder
        While True
            Dim next_path As String = IO.Directory.GetParent(previous_path).ToString()
            Dim current_svn_root_path As String = GetSvnRootPath(next_path)
            ' As long as we have the same svn root path, we are in the same repo, continue.'
            If current_svn_root_path = svn_root_path Then
                previous_path = next_path
            Else
                Exit While
            End If
        End While
        Return previous_path
    Catch e As Exception
        MsgBox("Exception: " + e.Message())
    End Try
    Return Nothing
End Function

Private Function GetSvnRootPath(ByVal client_path As String) As String
    ' First make sure we are within a repo.'
    Dim svn_folder As String = client_path + "\.svn"
    If Not IO.Directory.Exists(svn_folder) Then
        Return ""
    End If
    ' Then there MUST be an entries file in there.'
    Dim entries_file As String = svn_folder + "\entries"
    If Not IO.File.Exists(entries_file) Then
        Return ""
    End If
    ' Read the content of the file and find the svn root, and return it.'
    Dim entries_content As String = IO.File.ReadAllText(entries_file, Text.Encoding.GetEncoding(1252))
    Dim pattern As String = "svn:(.*)$"
    Dim regex As New Text.RegularExpressions.Regex(pattern, Text.RegularExpressions.RegexOptions.Multiline)
    Dim matches As Text.RegularExpressions.MatchCollection = regex.Matches(entries_content)
    Return matches.Item(1).ToString()
End Function

Only build startup project

Stolen from Boris, thanks!

Sub BuildStartupProject()
    Dim sb As SolutionBuild = DTE.Solution.SolutionBuild
    Dim projName As String = sb.StartupProjects(0)
    sb.BuildProject(sb.ActiveConfiguration.Name, projName, False)
End Sub

Use WinDbg as your debugger

I fully regret writing this macro as it didn't pass the "time wasted to write it"/"utility" ratio. But I'm really too proud.

Sub WinbgStartupProject()
    ' Use the right one:
    Dim windbg As String = "C:\program files\Debugging Tools for Windows (x86)\windbg.exe"
    'Dim windbg As String = "C:\program files\Debugging Tools for Windows (x64)\windbg.exe"

    Dim project_name As String = CType(DTE.Solution.SolutionBuild.StartupProjects(0), String)
    Dim project As EnvDTE.Project = FindProjects(DTE.Solution.Projects, project_name)
    Dim config As Configuration = project.ConfigurationManager.ActiveConfiguration
    ' Hack to remove file:///
    Dim target_path As String = config.OutputGroups.Item(1).FileURLs(0).ToString().Remove(0, 8)
    Dim arguments As String = config.Properties.Item("CommandArguments").Value
    'MsgBox(windbg & " -o " & target_path & " " & arguments)
    System.Diagnostics.Process.Start(windbg, "-o " & target_path & " " & arguments)
End Sub

Function FindProjectItems(ByVal project_items As EnvDTE.ProjectItems, ByVal project_name As String) As EnvDTE.Project
    FindProjectItems = Nothing
    For Each project_item As EnvDTE.ProjectItem In project_items
        If Not project_item.SubProject Is Nothing Then
            FindProjectItems = FindProject(project_item.SubProject, project_name)
            If Not FindProjectItems Is Nothing Then Exit Function
        End If
    Next
End Function

Function FindProject(ByVal project As EnvDTE.Project, ByVal project_name As String) As EnvDTE.Project
    If project.UniqueName = project_name Then
        FindProject = project
        Exit Function
    End If
    If Not project.ProjectItems Is Nothing Then
        FindProject = FindProjectItems(project.ProjectItems, project_name)
        If Not FindProject Is Nothing Then Exit Function
    End If
End Function

Function FindProjects(ByVal projects As EnvDTE.Projects, ByVal project_name As String) As EnvDTE.Project
    ' You never thought it'd be so complex to find a project. The VS extensibility team
    ' stole me an hour of my life I will never get back.
    FindProjects = Nothing
    For Each project As EnvDTE.Project In projects
        FindProjects = FindProject(project, project_name)
        If Not FindProjects Is Nothing Then Exit Function
    Next
End Function

Add other useful macros here

Feel free to edit this page to add other useful macros.