사용자 도구

사이트 도구


kb:visualstudiomacro

:!: 2012 버전부터 더 이상 매크로를 사용할 수 없다. VSPackage를 사용해야 한다.


에러 리스트에 아이템 추가하기

Imports EnvDTE
 
Dim window As Window
Dim outputWindow As OutputWindow
Dim outputWindowPane As OutputWindowPane
 
window = DTE.Windows.Item(EnvDTE.Constants.vsWindowKindOutput)
window.Visible = True
 
outputWindow = window.Object
 
Try
    outputWindowPane = outputWindow.OutputWindowPanes.Item("Build")
Catch ex As Exception
    outputWindowPane = outputWindow.OutputWindowPanes.Add("Build")
End Try
 
Dim file As String = "Source.cpp"
Dim line As Integer = 15
Dim msg As String = "Blar Blar"
 
outputWindowPane.OutputTaskItemString( _
    file & "(" & line & ")" & ": " & msg & vbCrLf, _
    EnvDTE.vsTaskPriority.vsTaskPriorityHigh, "", EnvDTE.vsTaskIcon.vsTaskIconCompile, file, line, msg _
    )

현재 문서를 포함하고 있는 프로젝트 이름 가져오기

Dim currentItem As ProjectItem = ActiveDocument().ProjectItem
If Not currentItem Is Nothing Then
    Dim project As Project = currentItem.ContainingProject
    Dim name = project.Name
End

타이틀에 솔루션 경로 표시하기

기본적으로 “솔루션이름 - Microsoft Visual Studio” 으로만 표시가 되는데, 매크로를 이용해 좀 더 자세히 표시할 수 있다. 아래의 매크로를 EnvironmentEvents 모듈에다 등록하면 된다.

Option Strict Off
Option Explicit Off
Imports System
Imports EnvDTE
Imports EnvDTE80
Imports System.Diagnostics
 
Public Module EnvironmentEvents
 
#Region "Automatically generated code, do not modify"
'Automatically generated code, do not modify
'Event Sources Begin
	<System.ContextStaticAttribute()> Public WithEvents DTEEvents As EnvDTE.DTEEvents
	<System.ContextStaticAttribute()> Public WithEvents DocumentEvents As EnvDTE.DocumentEvents
	<System.ContextStaticAttribute()> Public WithEvents WindowEvents As EnvDTE.WindowEvents
	<System.ContextStaticAttribute()> Public WithEvents TaskListEvents As EnvDTE.TaskListEvents
	<System.ContextStaticAttribute()> Public WithEvents FindEvents As EnvDTE.FindEvents
	<System.ContextStaticAttribute()> Public WithEvents OutputWindowEvents As EnvDTE.OutputWindowEvents
	<System.ContextStaticAttribute()> Public WithEvents SelectionEvents As EnvDTE.SelectionEvents
	<System.ContextStaticAttribute()> Public WithEvents BuildEvents As EnvDTE.BuildEvents
	<System.ContextStaticAttribute()> Public WithEvents SolutionEvents As EnvDTE.SolutionEvents
	<System.ContextStaticAttribute()> Public WithEvents SolutionItemsEvents As EnvDTE.ProjectItemsEvents
	<System.ContextStaticAttribute()> Public WithEvents MiscFilesEvents As EnvDTE.ProjectItemsEvents
	<System.ContextStaticAttribute()> Public WithEvents DebuggerEvents As EnvDTE.DebuggerEvents
	<System.ContextStaticAttribute()> Public WithEvents ProjectsEvents As EnvDTE.ProjectsEvents
	<System.ContextStaticAttribute()> Public WithEvents TextDocumentKeyPressEvents As EnvDTE80.TextDocumentKeyPressEvents
	<System.ContextStaticAttribute()> Public WithEvents CodeModelEvents As EnvDTE80.CodeModelEvents
	<System.ContextStaticAttribute()> Public WithEvents DebuggerProcessEvents As EnvDTE80.DebuggerProcessEvents
	<System.ContextStaticAttribute()> Public WithEvents DebuggerExpressionEvaluationEvents As EnvDTE80.DebuggerExpressionEvaluationEvents
'Event Sources End
'End of automatically generated code
#End Region
 
    Declare Auto Function SetWindowText Lib "user32" (ByVal hWnd As System.IntPtr, ByVal lpstring As String) As Boolean
 
    Private MyTimer As System.Threading.Timer
 
    Public Sub DTEEvents_OnBeginShutdown() Handles DTEEvents.OnBeginShutdown
        If Not MyTimer Is Nothing Then
            MyTimer.Dispose()
            MyTimer = Nothing
        End If
    End Sub
 
    Public Sub SetIdeTitle()
        Try
            Dim title As String = DTE.Solution.FullName
            Dim objRegex As New Text.RegularExpressions.Regex("")
 
            ' 이 부분의 문자열 표시 방법은 사용자마다 입맛에 맞게 적당히 바꿔줘야 한다.
            If objRegex.IsMatch(title, "^.+Main.+Server.sln$") Then
                title = "Main (" + title + ")"
            ElseIf objRegex.IsMatch(title, "^.+Develop.+Server.sln$") Then
                title = "Develop (" + title + ")"
            ElseIf objRegex.IsMatch(title, "^.+ReleaseIDC.+Server.sln$") Then
                title = "ReleaseIDC (" + title + ")"
            ElseIf objRegex.IsMatch(title, "^.+Renewal.+Server.sln$") Then
                title = "Renewal (" + title + ")"
            End If
 
            SetWindowText(New System.IntPtr(DTE.MainWindow.HWnd), title & " - " & DTE.Name)
        Catch ex As System.Exception
        End Try
    End Sub
 
    Public Sub MyTimerInstall()
        Try
            If MyTimer Is Nothing Then
                Dim autoEvent As New System.Threading.AutoResetEvent(False)
                Dim timerDelegate As System.Threading.TimerCallback = AddressOf MyTimerTick
                MyTimer = New System.Threading.Timer(timerDelegate, autoEvent, 0, 200)
            End If
 
            SetIdeTitle()
        Catch ex As System.Exception
        End Try
    End Sub
 
    Public Sub MyTimerTick(ByVal state As Object)
        Try
            SetIdeTitle()
        Catch ex As System.Exception
        End Try
    End Sub
 
 
    'Private Sub WindowEvents_WindowActivated(ByVal GotFocus As EnvDTE.Window, ByVal LostFocus As EnvDTE.Window) Handles WindowEvents.WindowActivated
    '    MyTimerInstall()
    'End Sub

    Private Sub SolutionEvents_Opened() Handles SolutionEvents.Opened
        MyTimerInstall()
    End Sub
 
    Private Sub SolutionEvents_BeforeClosing() Handles SolutionEvents.BeforeClosing
        If Not MyTimer Is Nothing Then
            MyTimer.Dispose()
            MyTimer = Nothing
        End If
    End Sub
End Module

솔루션을 열 때, 타이머를 설치해서 주기적으로 타이틀을 업데이트하는 방식인데, 이는 Visual Studio IDE 자체에서 이런저런 이벤트가 있을 때마다 타이틀을 자꾸 원래대로 바꿔버리는 문제 때문이다. 자세한 사항은 http://www.helixoft.com/blog/archives/32 페이지를 참고하기 바란다.

선택된 라인들에서 중복된 라인들은 삭제하고 나머지를 정렬하기

include 구문들을 정리하기 위해서 사용하면 좋다.

Function Strip(ByVal strLine As String)
    If Len(strLine) > 0 Then
        nBegin = 1
        nEnd = Len(strLine)
        For i = 1 To Len(strLine)
            c = Mid(strLine, i, 1)
            If c <> " " And c <> Tab And c <> Lf And c <> Cr Then
                nBegin = i
                Exit For
            End If
        Next
        For i = 1 To Len(strLine)
            c = Mid(strLine, Len(strLine) - i + 1, 1)
            If c <> " " And c <> Tab And c <> Lf And c <> Cr Then
                nEnd = Len(strLine) - i + 1
                Exit For
            End If
        Next
        Return Mid(strLine, nBegin, nEnd - nBegin + 1)
    Else
        Return ""
    End If
End Function
 
Sub SortCollection(ByRef oCollection As Collection, Optional ByVal bSortAscending As Boolean = True)
    Dim lSort1 As Integer
    Dim lSort2 As Integer
    Dim vTempItem1 As Object
    Dim vTempItem2 As Object
    Dim bSwap As Boolean
 
    For lSort1 = 1 To oCollection.Count - 1
        For lSort2 = lSort1 + 1 To oCollection.Count
            If bSortAscending Then
                If oCollection(lSort1) > oCollection(lSort2) Then
                    bSwap = True
                Else
                    bSwap = False
                End If
            Else
                If oCollection(lSort1) < oCollection(lSort2) Then
                    bSwap = True
                Else
                    bSwap = False
                End If
            End If
            If bSwap Then
                vTempItem1 = oCollection(lSort1)
                vTempItem2 = oCollection(lSort2)
                oCollection.Add(vTempItem1, Nothing, lSort2)
                oCollection.Add(vTempItem2, Nothing, lSort1)
                oCollection.Remove(lSort1 + 1)
                oCollection.Remove(lSort2 + 1)
            End If
        Next
    Next
End Sub
 
Sub SortAndRemoveDuplicatedLine()
    Dim objLines As New Collection
    Dim objSel As TextSelection = ActiveDocument().Selection
    Dim objRanges As TextRanges = objSel.TextRanges
    Dim objStartPt As EditPoint = objRanges.Item(1).StartPoint.CreateEditPoint()
    Dim objStream As New StringBuilder
 
    For Each strLine In objSel.Text.Split(Lf)
        strLine = Strip(strLine)
        If objLines.Contains(strLine) = False Then
            objLines.Add(strLine, strLine)
        End If
    Next
 
    SortCollection(objLines)
 
    For Each strLine In objLines
        objStream.AppendLine(strLine)
    Next
 
    objSel.Text = ""
    objStartPt.Insert(objStream.ToString())
End Sub

활성화된 아이템 추적하기

“도구 → 옵션 → 프로젝트 및 솔루션 → 일반 → 솔루션 탐색기에서 활성화된 항목 추적” 옵션을 켜두면 현재 편집 중인 파일을 솔루션 탐색기에서 쉽게 찾아볼 수 있다. 문제는 이 옵션을 항상 켜두면 상당히 난잡하다는 점이다. 그러므로 이 옵션 자체는 끄고, 매크로를 통해 필요할 때만 추적하도록 해두는 것이 좋다.

Sub FindInSolution()
    ' 현재 편집 중인 파일을 솔루션 익스플로러에서 찾아서 하이라이트시킨다.
    p = DTE.Properties("Environment", "ProjectsAndSolution").Item("TrackFileSelectionInExplorer")
    p.value = 1
    p.value = 0
End Sub

단축키를 등록해두는 것이 좋다. ALT+Q 추천 :)

주석 칸 맞추기

DoxyGen 형태의 주석을 컬럼에 맞게 워드랩해주는 매크로다. 약간 수정하면 일반 주석에 쓸 수도 있을 터.

Before

//////////////////////////////////////////////////////////////////////////////////////////
/// \brief 글자가 
/// 처음으로 
/// 나타나는 위치를 
/// 반환한다.
/// \param caseSensitive 대소문자 구별을 하는가?
/// \return size_t 음 이것은 그냥 붙여보는 주석이란다.
//////////////////////////////////////////////////////////////////////////////////////////

After

//////////////////////////////////////////////////////////////////////////////////////////
/// \brief 글자가 처음으로 나타나는 위치를 반환한다. 
/// \param text 검색 대상 문자열 
/// \return size_t 음 이것은 그냥 붙여보는 주석이란다.
//////////////////////////////////////////////////////////////////////////////////////////
Function Strip(ByVal strLine As String)
    ' 문자열 좌우의 공백을 제거한다.
    If Len(strLine) > 0 Then
        nBegin = 1
        nEnd = Len(strLine)
        For i = 1 To Len(strLine)
            c = Mid(strLine, i, 1)
            If c <> " " And c <> Tab And c <> Lf And c <> Cr Then
                nBegin = i
                Exit For
            End If
        Next
        For i = 1 To Len(strLine)
            c = Mid(strLine, Len(strLine) - i + 1, 1)
            If c <> " " And c <> Tab And c <> Lf And c <> Cr Then
                nEnd = Len(strLine) - i + 1
                Exit For
            End If
        Next
        Return Mid(strLine, nBegin, nEnd - nBegin + 1)
    Else
        Return ""
    End If
End Function
 
Function GetAsciiLength(ByVal str As String)
    Return Encoding.Default.GetBytes(str).Length
End Function
 
Sub WrapDoxygenComment()
    Dim nMaxLength As Integer = 90 - 4 - 1 ' -4는 주석 앞에 붙는 "/// " 문자열의 길이, -1은 딱 붙어있는 거 찝찝해서
    Dim nLineLength As Integer = 0
    Dim objRegex As RegularExpressions.Regex
    Dim objMatch As RegularExpressions.Match
    Dim objStream As New StringBuilder
    Dim objLines As New Collection
    Dim objSel As TextSelection = ActiveDocument().Selection
    Dim objRanges As TextRanges = objSel.TextRanges
    Dim objStartPt As EditPoint = objRanges.Item(1).StartPoint.CreateEditPoint()
 
    For Each strLine In objSel.Text.Split(CrLf)
        strLine = Strip(strLine)
        If objRegex.IsMatch(strLine, "^////+$") Then
        Else
            objMatch = objRegex.Match(strLine, "^///")
            If objMatch.Success Then
                strLine = Strip(strLine.SubString(objMatch.Length))
            End If
        End If
        objLines.Add(strLine)
    Next
 
    For i = 1 To objLines.Count
        strLine = objLines.Item(i)
 
        If strLine.Length = 0 Then
            objStream.Append(CrLf)
            objStream.Append("/// ")
            nLineLength = 0
        ElseIf objRegex.IsMatch(strLine, "^////+$") Then
            objStream.Append(CrLf)
            objStream.Append(strLine)
            nLineLength = 0
        Else
            For Each match As RegularExpressions.Match In RegularExpressions.Regex.Matches(strLine, "\S+\s*")
                If nLineLength = 0 Or match.Value.StartsWith("\") Or nLineLength + GetAsciiLength(match.Value) > nMaxLength Then
                    objStream.Append(CrLf)
                    objStream.Append("/// ")
                    nLineLength = 4
                End If
 
                objStream.Append(Strip(match.Value) + " ")
                nLineLength += GetAsciiLength(Strip(match.Value)) + 1
            Next
        End If
    Next
    objStream.Append(CrLf)
 
    ' 현재 선택된 문자열을 주어진 문자열로 치환한다.
    objSel.Text = ""
    objStartPt.Insert(objStream.ToString().Substring(2))
End Sub

복사 생성자 및 대입 연산자 자동으로 생성하기

Sub MakeCopyAndAssignment()
    Dim objSel As TextSelection
    Dim objRanges As TextRanges
    Dim objStartPt As EditPoint
    Dim colTypes As New Collection
    Dim colNames As New Collection
    Dim colComments As New Collection
    Dim objStream As New System.Text.StringBuilder
    Dim strFileName As String
    Dim strClassName As String
    Dim strVarName As String
 
    strFileName = ActiveDocument().Name
    If strFileName = "" Then
        MsgBox("처리 중인 파일에 확장자가 없습니다." + CrLf + "C/C++ 소스 파일이 맞습니까?")
        Exit Sub
    End If
 
    ' 파일 이름으로 클래스 이름을 추정한다.
    strClassName = "c" + Left(strFileName, InStrRev(strFileName, ".") - 1)
 
    ' 실제 클래스 이름을 입력받는다.
    strClassName = InputBox("Type class name", "Class name required", strClassName)
    If Len(strClassName) > 0 Then
        objSel = ActiveDocument().Selection
        objRanges = objSel.TextRanges
        objStartPt = objRanges.Item(1).StartPoint.CreateEditPoint()
 
        ' 변수 파싱
        ParseVariableDeclarations(Trim(objSel.Text), colTypes, colNames, colComments)
 
        ' 복사 생성자
        objStream.Append(Tab + "/// \brief 복사 생성자" + CrLf)
        objStream.Append(Tab + strClassName + "(const " + strClassName + "& rhs)" + CrLf)
        objStream.Append(Tab + Tab + ": ")
        For i = 1 To colNames.Count
            strVarName = colNames.Item(i)
            If i > 1 Then
                objStream.Append(Tab + Tab)
            End If
            objStream.Append(strVarName + "(rhs." + strVarName + ")")
            If i < colNames.Count Then
                objStream.Append(", ")
            End If
            objStream.Append(CrLf)
        Next
        objStream.Append(Tab + "{" + CrLf + Tab + "}" + CrLf + CrLf)
 
        ' 대입 연산자
        objStream.Append(Tab + "/// \brief 대입 연산자" + CrLf)
        objStream.Append(Tab + strClassName + "& operator = (const " + strClassName + "& rhs)" + CrLf)
        objStream.Append(Tab + "{" + CrLf)
        For i = 1 To colNames.Count
            strVarName = colNames.Item(i)
            objStream.Append(Tab + Tab + strVarName + " = rhs." + strVarName + ";" + CrLf)
        Next
        objStream.Append(Tab + Tab + "return *this; " + CrLf + Tab + "}" + CrLf + CrLf)
 
        ' 생성한 문자열 대입
        objSel.Text = ""
        objStartPt.Insert(objStream.ToString())
    End If
End Sub

아름다운 변수 선언문 만들기

-_ -

Sub MakePrettyVariableDeclaration()
    Dim objSel As TextSelection
    Dim objRanges As TextRanges
    Dim objStartPt As EditPoint
    Dim colTypes As New Collection
    Dim colNames As New Collection
    Dim colComments As New Collection
    Dim nMaxTypeLength As Integer
    Dim nMaxNameLength As Integer
    Dim objStream As New System.Text.StringBuilder
 
    objSel = ActiveDocument().Selection
    objRanges = objSel.TextRanges
    objStartPt = objRanges.Item(1).StartPoint.CreateEditPoint()
 
    ParseVariableDeclarations(Trim(objSel.Text), colTypes, colNames, colComments)
 
    nMaxTypeLength = 0
    For Each line In colTypes
        nMaxTypeLength = System.Math.Max(nMaxTypeLength, Len(line))
    Next
 
    nMaxNameLength = 0
    For Each line In colNames
        nMaxNameLength = System.Math.Max(nMaxNameLength, Len(line))
    Next
 
    For i = 1 To colTypes.Count
        vtype = colTypes.Item(i)
        vname = colNames.Item(i)
        vcomment = colComments.Item(i)
 
        typeSpaces = nMaxTypeLength - Len(vtype)
        nameSpaces = nMaxNameLength - Len(vname)
 
        For t = 1 To typeSpaces
            vtype += " "
        Next
 
        vname += ";"
        For n = 1 To nameSpaces
            vname += " "
        Next
 
        line = vtype + " " + vname + " " + vcomment
        objStream.Append(Trim(line) + CStr(Lf))
    Next
 
    objStartPt.Delete(objSel.Text.Length)
    objStartPt.Insert(objStream.ToString())
End Sub

문자열 _T() 매크로로 감싸기

문자열을 선택할 필요 없이 문자열 가운데에서, 그냥 매크로를 실행하면 된다. 문자열을 선택한 상태에서 사용해도 동작에는 별 차이가 없다. 단축키는 Ctrl+K, Ctrl+T 추천. :)

Sub WrapStringWithTcharMacro()
    Dim objRanges As TextRanges
    Dim objStartPt As EditPoint
    Dim objEndPt As EditPoint
 
    objRanges = ActiveDocument().Selection.TextRanges
    objStartPt = objRanges.Item(1).StartPoint.CreateEditPoint()
    objEndPt = objRanges.Item(objRanges.Count).EndPoint.CreateEditPoint()
 
    ' 문자열의 처음을 찾는다.
    While objStartPt.GetText(-1) <> """" Or objStartPt.GetText(-2) = "\"""
        objStartPt.CharLeft(1)
    End While
    objStartPt.CharLeft(1)
 
    ' 문자열의 끝을 찾는다.
    While objEndPt.GetText(1) <> """" Or objEndPt.GetText(-1) = "\"
        objEndPt.CharRight(1)
    End While
    objEndPt.CharRight(1)
 
    ' 이미 _T 매크로로 감싸여 있는 문자열이 아니라면 감싸준다.
    If objStartPt.GetText(-3) <> "_T(" Then
        objStartPt.Insert("_T(")
        objEndPt.Insert(")")
    End If
End Sub

현재 편집 중인 문서 솔루션 익스플로러에서 찾기

Sub FindInSolution()
    p = DTE.Properties("Environment", "ProjectsAndSolution").Item("TrackFileSelectionInExplorer")
    p.value = 1
    p.value = 0
End Sub

솔루션 익스플로러 트리 접기

from [http://www.codeproject.com/macro/collapseall.asp?df=100&forumid=7565&exp=0&select=396167]

툴바에다가 버튼으로 등록해두고 쓰자. :)

Sub CollapseNode(ByRef item As UIHierarchyItem)
 
    Dim subitem As UIHierarchyItem
    For Each subitem In item.UIHierarchyItems
        If (subitem.UIHierarchyItems.Expanded = True) Then
            CollapseNode(subitem)
            subitem.UIHierarchyItems.Expanded = False
        End If
    Next
 
End Sub
 
Sub CollapseAll()
 
    ' Get the the Solution Explorer tree
    Dim UIHSolutionExplorer As UIHierarchy
    UIHSolutionExplorer = DTE.Windows.Item(EnvDTE.Constants.vsext_wk_SProjectWindow).Object()
 
    ' Check if there is any open solution
    If (UIHSolutionExplorer.UIHierarchyItems.Count = 0) Then
        ' MsgBox("Nothing to collapse. You must have an open solution.")
        Return
    End If
 
    ' Get the top node (the name of the solution)
    Dim UIHSolutionRootNode As UIHierarchyItem
    UIHSolutionRootNode = UIHSolutionExplorer.UIHierarchyItems.Item(1)
 
    CollapseNode(UIHSolutionRootNode)
 
    ' Select the solution node, or else when you click on the solution window
    ' scrollbar, it will synchronize the open document with the tree and pop
    ' out the corresponding node which is probably not what you want.
    UIHSolutionRootNode.Select(vsUISelectionType.vsUISelectionTypeSelect)
 
End Sub

소스 파일 기본 구문 집어넣기

새로운 헤더/소스 파일에다 기본 구문 집어넣기

Sub DecorateSourceFile()
    ' 설명: doxygen 스타일의 파일 설명과 클래스 선언을 헤더/소스 파일에다 추가한다.

    Dim fileName As String
    Dim fileExt As String
    Dim includeGuard As String
    Dim selection As TextSelection
    Dim pos As Integer
    Dim className As String
 
    Dim author As String
    Dim dateString As String
    Dim commentLine As String
    Dim usePragmaOnce As Boolean
    Dim classNamePrefix As String
    Dim pchName As String
 
    ' 수정 사항들. 필요에 따라 수정한다.
    author = "excel96"
    dateString = CStr(Year(Now())) + "." + CStr(Month(Now())) + "." + CStr(Day(Now()))
    commentLine = "////////////////////////////////////////////////////////////////////////////////"
    usePragmaOnce = True
    classNamePrefix = "c"
    pchName = "PCH.h"
 
    ' 파일 이름을 확인한다.
    fileName = ActiveDocument().Name
    If fileName = "" Then
        If MsgBox("처리 중인 파일에 확장자가 없습니다." + Lf + _
        "C/C++ 소스 파일이 맞습니까?", 4) = MsgBoxResult.Cancel Then
            Exit Sub
        End If
        fileName = "NoFileNameGiven.h"
    End If
 
    ' 파일 이름을 분리하고, 클래스 이름을 생성한다.
    fileExt = UCase(Right(fileName, Len(fileName) - InStrRev(fileName, ".")))
    fileName = Left(fileName, Len(fileName) - Len(fileExt) - 1)
    className = classNamePrefix + fileName
 
    ' 파일의 확장자에 따라 알맞은 처리를 해준다.
    If fileExt = "H" Or fileExt = "HPP" Then
        ActiveDocument().Selection.StartOfDocument(False)
        selection = ActiveDocument().Selection
 
        includeGuard = "__" + UCase(fileName) + "_" + fileExt + "__" + Lf
 
        ' 파일 헤더 추가.
        selection.Text = commentLine + CStr(Lf)
        selection.Text += "/// \file " + ActiveDocument().Name + CStr(Lf)
        selection.Text += "/// \author " + author + CStr(Lf)
        selection.Text += "/// \date " + dateString + CStr(Lf)
        selection.Text += commentLine + CStr(Lf) + CStr(Lf)
 
        ' 인클루드 가드 추가.
        If usePragmaOnce Then
            selection.Text += "#pragma once" + CStr(Lf) + CStr(Lf)
        Else
            selection.Text += "#ifndef " + includeGuard + "#define " + includeGuard + CStr(Lf) + CStr(Lf)
        End If
 
        ' 클래스 설명문 추가.
        selection.Text += commentLine + CStr(Lf)
        selection.Text += "/// \class " + className + CStr(Lf)
        selection.Text += "/// \brief " + CStr(Lf)
        selection.Text += commentLine + CStr(Lf) + CStr(Lf)
 
        ' 클래서 선언 및 생성자 & 소멸자 추가.
        selection.Text += "class " + className + CStr(Lf)
        selection.Text += "{" + CStr(Lf)
        selection.Text += "private:" + CStr(Lf) + CStr(Lf)
        selection.Text += "public:" + CStr(Lf)
        selection.Text += "/// \brief 생성자" + CStr(Lf)
        selection.Text += className + "();" + CStr(Lf) + CStr(Lf)
        selection.Text += "/// \brief 소멸자" + CStr(Lf)
        selection.Text += "virtual ~" + className + "();" + CStr(Lf) + CStr(Lf) + CStr(Lf)
        selection.Text += "public:" + CStr(Lf) + CStr(Lf)
        selection.Text += "};" + CStr(Lf)
 
        ' 인클루드 가드 마무리.
        If Not usePragmaOnce Then
            ActiveDocument().Selection.EndOfDocument(False)
            selection.Text = CStr(Lf) + "#endif //" + includeGuard
        End If
    ElseIf fileExt = "C" Or fileExt = "CPP" Or fileExt = "CC" Then
        ActiveDocument().Selection.StartOfDocument(False)
        selection = ActiveDocument().Selection
 
        ' 파일 헤더 추가.
        selection.Text = commentLine + CStr(Lf)
        selection.Text += "/// \file " + ActiveDocument().Name + CStr(Lf)
        selection.Text += "/// \author " + author + CStr(Lf)
        selection.Text += "/// \date " + dateString + CStr(Lf)
        selection.Text += commentLine + CStr(Lf) + CStr(Lf)
 
        ' 인클루드 파일 추가.
        selection.Text += "#include " + CStr(Quote) + pchName + CStr(Quote) + CStr(Lf)
        selection.Text += "#include " + CStr(Quote) + fileName + ".h" + CStr(Quote) + CStr(Lf)
        selection.Text += CStr(Lf)
 
        ' 생성자 추가.
        selection.Text += commentLine + CStr(Lf)
        selection.Text += "/// \brief 생성자" + CStr(Lf)
        selection.Text += commentLine + CStr(Lf)
        selection.Text += className + "::" + className + "()" + CStr(Lf)
        selection.Text += "{" + CStr(Lf)
        selection.Text += "}" + CStr(Lf) + CStr(Lf)
 
        ' 소멸자 추가.
        selection.Text += commentLine + CStr(Lf)
        selection.Text += "/// \brief 소멸자" + CStr(Lf)
        selection.Text += commentLine + CStr(Lf)
        selection.Text += className + "::~" + className + "()" + CStr(Lf)
        selection.Text += "{" + CStr(Lf)
        selection.Text += "}" + CStr(Lf) + CStr(Lf)
 
        ActiveDocument().Selection.EndOfDocument(False)
    Else
        MsgBox("이 매크로는 C/C++ 소스 파일에서만 동작합니다.")
    End If
End Sub

함수 설명 집어넣기

DoxyGen 형태의 함수 설명 집어넣기

Sub AddFunctionDescriptionEx()
    ' 설명: doxygen 스타일의 함수 설명문을 추가한다.

    Dim header, prms As String
    Dim functionName, description As String
    Dim iPrm, iPrmA As Integer
    Dim selection As TextSelection
    Dim returnType As String
    Dim commentLine As String
    Dim p, l As Integer
 
    If (ActiveDocument() Is Nothing) Then
        Exit Sub
    End If
 
    commentLine = "////////////////////////////////////////////////////////////////////////////////"
 
    If ActiveDocument().Language = EnvDTE.Constants.dsCPP Or ActiveDocument().Language = "CSharp" Then
        selection = DTE.ActiveDocument.Selection()
        Trim(selection.Text)
        header = ""
 
        If selection.Text <> "" Then
            header = StripTabs(Trim(selection.Text))
        End If
 
        'Get the function return type. 
        If header <> "" Then
            If ActiveDocument().Language = "CSharp" Then
                'skip the protection info (public/private ...) 
                header = Right(header, Len(header) - InStr(header, " "))
            End If
            Reti = InStr(header, " ")
            Loc1 = InStr(header, "(")
            If Reti < Loc1 Then
                returnType = Left(header, Loc1 - 1)
                header = Right(header, Len(header) - Reti)
            End If
            returnType = Left(returnType, InStr(returnType, " "))
 
            'Get the function name. 
            Loc1 = InStr(header, "(") - 1
            Loc2 = InStr(header, ")")
 
            If Loc1 > 0 And Loc2 > 0 Then 'make sure there is a '(' and a ')' 
                functionName = Left(header, Loc1)
                header = Right(header, Len(header) - Len(functionName))
 
                'Do we have storage type on the return type? 
                Trim(functionName)
                If InStr(functionName, " ") <> 0 Then
                    returnType = returnType + Left(functionName, InStr(functionName, " "))
                    functionName = Right(functionName, Len(functionName) - InStr(functionName, " "))
                End If
 
                'Get the function parameters. 
                iPrm = 0
                iPrmA = 0
                prms = header
 
                'Count the number of parameters. 
                Do While InStr(prms, ",") <> 0
                    iPrm = iPrm + 1
                    prms = Right(prms, Len(prms) - InStr(prms, ","))
                Loop
 
                'Store the parameter list in the array. 
                If iPrm > 0 Then ' If multiple params. 
                    iPrm = iPrm + 1
                    iPrmA = iPrm
                    ReDim ParamArr(iPrm)
 
                    Do While InStr(header, ",") <> 0
                        ParamArr(iPrm - 1) = Left(header, InStr(header, ",") - 1)
                        'Remove brace from first parameter. 
                        If InStr(ParamArr(iPrm - 1), " (") <> 0 Then
                            p = iPrm - 1
                            l = Len(ParamArr(p))
                            ParamArr(p) = Right(ParamArr(p), (l - (l - (l - InStr(ParamArr(p), " (")))))
                            Trim(ParamArr(iPrm))
                        End If
                        header = Right(header, Len(header) - InStr(header, ","))
                        iPrm = iPrm - 1
                    Loop
                    ParamArr(iPrm - 1) = header
 
 
                    'Remove trailing brace from last parameter. 
                    If InStr(ParamArr(iPrm - 1), ")") <> 0 Then
                        ParamArr(iPrm - 1) = Left(ParamArr(iPrm - 1), InStr(ParamArr(iPrm - 1), ")") - 1)
                        Trim(ParamArr(iPrm - 1))
                    End If
                Else 'Possibly one param. 

                    ReDim ParamArr(1)
                    header = Right(header, Len(header) - 1) ' Strip the first brace. 
                    Trim(header)
                    ParamArr(0) = StripTabs(header)
                    If InStr(ParamArr(0), ")") <> 1 Then
                        ParamArr(0) = Left(ParamArr(0), InStr(ParamArr(0), ")") - 1)
                        Trim(ParamArr(0))
                        iPrmA = 1
                    End If
                End If
 
                'Position the cursor one line above the selected text. 
                DTE.ActiveDocument.Selection.LineUp()
                DTE.ActiveDocument.Selection.LineDown()
                DTE.ActiveDocument.Selection.StartOfLine()
                selection = DTE.ActiveDocument.Selection()
                'selection.text = Lf 

                description = commentLine + CStr(Lf)
                description += "/// \brief " + CStr(Lf)
 
                If (iPrmA <> 0) Then
                    description += "/// " + CStr(Lf)
                End If
 
                'Print the parameter list. 
                Last = iPrmA
                Do While iPrmA <> 0
                    'Remove a line feed from any of the arguments. 
                    If InStr(ParamArr(iPrmA - 1), CStr(Lf)) <> 0 Then
                        p = iPrmA - 1
                        l = Len(ParamArr(p))
                        ParamArr(p) = Right(ParamArr(p), (l - (l - (l - InStr(ParamArr(p), CStr(Lf))))))
                        Trim(ParamArr(iPrmA - 1))
                    End If
 
                    ParamArr(iPrmA - 1) = StripTabs(ParamArr(iPrmA - 1))
 
                    'If there are 2+ parameters, the first parameter will 
                    'have a '(' prepended to it, remove it here: 
                    If iPrmA = Last And Last <> 1 Then
                        ParamArr(iPrmA - 1) = Right(ParamArr(iPrmA - 1), Len(ParamArr(iPrmA - 1)) - 1)
                    End If
 
                    SpaceIndex = InStrRev(ParamArr(iPrmA - 1), " ")
                    StarIndex = InStrRev(ParamArr(iPrmA - 1), "*")
                    AmpIndex = InStrRev(ParamArr(iPrmA - 1), "&")
 
                    RealIndex = System.Math.Max(SpaceIndex, StarIndex)
                    RealIndex = System.Math.Max(RealIndex, AmpIndex)
 
                    RealParam = Trim(Right(ParamArr(iPrmA - 1), Len(ParamArr(iPrmA - 1)) - RealIndex))
 
                    If (Len(RealParam) > 0 And InStr(RealParam, "void") = 0) Then
                        description = description + "/// \param " + RealParam + " " + CStr(Lf)
                    End If
 
                    iPrmA = iPrmA - 1
                Loop
 
                returnType = Trim(returnType)
 
                If (Len(returnType) > 0 And InStr(returnType, "void") = 0) Then
                    description += "/// \return " + returnType + CStr(Lf)
                End If
 
                description += commentLine + CStr(Lf)
 
                selection = DTE.ActiveDocument.Selection()
                selection.Text = description
            Else
                MsgBox("It is possible that the function you are trying to work with has a syntax error.")
            End If
        End If
 
    Else
        MsgBox("You need to have an active C/C++ document open" + CStr(Lf) + "with the function prototype selected.")
    End If
 
End Sub

H <-> CPP 전환하기

'DESCRIPTION: Opens the corresponding .h / .cpp file 
Sub GetFriendFile()
 
    currentFileName = Application.ActiveDocument.FullName
    newFileName = ""
 
    If (UCase(Right(currentFileName, 2)) = ".H") Then
        newFileName = Left(currentFileName, Len(currentFileName) - 2) + ".CPP"
    ElseIf (UCase(Right(currentFileName, 4)) = ".CPP") Then
        newFileName = Left(currentFileName, Len(currentFileName) - 4) + ".H"
    End If
 
    On Error Resume Next
    If newFileName <> "" Then
        Application.Documents.Open(newFileName)
        If (Err.Number <> 0) Then
            MsgBox("Error opening corresponding file - " & Err.Description)
        End If
    End If
 
End Sub

그룹 구문 집어넣기

DoxyGen 형태의 그룹 구문 집어넣기

Sub AddMemberGroupDescription()
    'DESCRIPTION: Adds memver group description template for doxygen. 
    Dim selection As TextSelection
 
    selection = ActiveDocument().Selection
    selection.Text = selection.Text + "/// \name " + CStr(Lf)
    selection.Text = selection.Text + "/// \{ " + CStr(Lf)
    selection.Text = selection.Text + "/// \brief " + CStr(Lf)
    selection.Text = selection.Text + "/// \} " + CStr(Lf)
 
End Sub

자동으로 Accessor 생성하기

Getter/Setter 자동으로 생성하기

Function ParseVariableDeclarations( _
    ByVal strText As String, ByRef colTypes As Collection, ByRef colNames As Collection, ByRef colComments As Collection)
    ' 다음과 같은 형태의 구문을 읽어들여서 타입과 변수 이름의 배열을 생성한다.
    '
    ' SkillId_t    m_SkillId;        ///< 스킬의 종류.
    ' cTraitDataEx m_CasterData;     ///< 스킬로 인해 변한 시전자의 파라미터.
    ' ObjectId_t   m_PrimaryTarget;  ///< 주 대상의 OID.
    '
    ' types[1] = "SkillId_t", names[1] = "m_SkillId"
    ' types[2] = "cTraitDataEx", names[2] = "m_CasterData"
    ' types[3] = "ObjectId_t", names[3] = "m_PrimaryTarget"

    arrLines = strText.Split(Lf)
    For Each line In arrLines
        strLine = line
 
        ' 좌우 공백 제거
        strLine = Trim(strLine)
        If Len(strLine) = 0 Then Continue For
 
        ' 문자열 안에 있는 2개 이상의 스페이스를 하나로 만든다.
        Do
            nSpacePos = InStr(strLine, "  ")
            If nSpacePos <> 0 Then
                strLine = Replace(strLine, "  ", " ")
            Else
                Exit Do
            End If
        Loop
 
        ' 라인 제일 처음 나오는 ';' 글자와 ';' 글자 앞에서 제일 처음 나타나는 ' ' 글자를 찾는다.
        bSuccess = False
        nSemicolonPos = InStr(strLine, ";")
        If nSemicolonPos <> 0 Then
            nSpacePos = InStrRev(strLine, " ", nSemicolonPos)
            If nSpacePos <> 0 Then
                bSuccess = True
            End If
        End If
 
        ' 두 글자 모두를 찾았다면, 변수 선언문이라고 할 수 있다.
        If bSuccess Then
            strVarType = Trim(Mid(strLine, 1, nSpacePos))
            strVarName = Trim(Mid(strLine, nSpacePos, nSemicolonPos - nSpacePos))
            strVarComment = ""
 
            If nSemicolonPos <> 0 Then
                strVarComment = Trim(Mid(strLine, nSemicolonPos + 1, Len(strLine) - nSemicolonPos))
            End If
 
            strVarType = Trim(Replace(strVarType, vbTab, " "))
            strVarName = Trim(Replace(strVarName, vbTab, " "))
            strVarComment = Trim(Replace(strVarComment, vbTab, " "))
 
            If strVarType <> "" And strVarName <> "" Then
                colTypes.Add(strVarType)
                colNames.Add(strVarName)
                colComments.Add(strVarComment)
            End If
        End If
    Next
 
End Function
 
Function GenerateAccessor(ByVal strVarType As String, ByVal strVarName As String, ByVal strMode As String)
    Dim strResult As String
 
    If strVarType <> "" And strVarName <> "" Then
        Dim objRegex As New System.Text.RegularExpressions.Regex("")
        Dim colBasicTypes As New System.Collections.Generic.Dictionary(Of String, String)
        Dim objStream As New System.Text.StringBuilder
 
        ' 대문자로만 이루어졌지만, 구조체로 취급하지 않을 타입들 생성
        colBasicTypes.Add("DWORD", "")
        colBasicTypes.Add("BOOL", "")
        colBasicTypes.Add("BYTE", "")
        colBasicTypes.Add("WORD", "")
        colBasicTypes.Add("FLOAT", "")
        colBasicTypes.Add("PFLOAT", "")
        colBasicTypes.Add("PBOOL", "")
        colBasicTypes.Add("LPBOOL", "")
        colBasicTypes.Add("PBYTE", "")
        colBasicTypes.Add("LPBYTE", "")
        colBasicTypes.Add("PINT", "")
        colBasicTypes.Add("LPINT", "")
        colBasicTypes.Add("PWORD", "")
        colBasicTypes.Add("LPWORD", "")
        colBasicTypes.Add("LPLONG", "")
        colBasicTypes.Add("PDWORD", "")
        colBasicTypes.Add("LPDWORD", "")
        colBasicTypes.Add("LPVOID", "")
        colBasicTypes.Add("LPCVOID", "")
        colBasicTypes.Add("INT", "")
        colBasicTypes.Add("UINT", "")
        colBasicTypes.Add("PUINT", "")
        colBasicTypes.Add("WPARAM", "")
        colBasicTypes.Add("LPARAM", "")
        colBasicTypes.Add("LRESULT", "")
 
        ' 필드 이름 생성
        Dim strFieldName As String
        strFieldName = strVarName
        If Left(strFieldName, 2) = "m_" Then
            strFieldName = Right(strFieldName, Len(strFieldName) - 2)
        End If
        If objRegex.IsMatch(strFieldName, "^[a-z]+[^a-z].+$") Then
            strFieldName = objRegex.Replace(strFieldName, "^([a-z]+)([^a-z].+)$", "$2")
        End If
 
        ' POD인지 아닌지 체크
        Dim bComplexType = False
        If objRegex.IsMatch(strVarType, "^c[A-Z][A-Za-z0-9]+[^\*\&]$") Then
            ' cDateTime, cTokenizer
            bComplexType = True
        ElseIf objRegex.IsMatch(strVarType, "^[A-Z0-9_]+[^\*\&]$") And Not colBasicTypes.ContainsKey(strVarType) Then
            ' D3DXVECTOR, OVERLAPPED
            bComplexType = True
        ElseIf objRegex.IsMatch(strVarType, "^.+<.+>$") Then
            ' std::vector<int>, cMyTemplate<bool>
            bComplexType = True
        End If
 
        ' 몇 가지 타입은 따로 처리
        If strVarType = "std::string" Then strVarType = "const std::string&"
        If strVarType = "tstring" Then strVarType = "const tstring&"
 
        ' Getter? Setter?
        If strMode = "Getter" Then
            If bComplexType Then
                strResult += strVarType + "& Get" + strFieldName + "() { return " + strVarName + "; }" + CStr(Lf)
                strResult += "const " + strVarType + "& Get" + strFieldName + "() const { return " + strVarName + "; }" + CStr(Lf)
            ElseIf strVarType = "bool" Or strVarType = "BOOL" Then
                strResult += strVarType + " Is" + strFieldName + "() const { return " + strVarName + "; }" + CStr(Lf)
            Else
                strResult += strVarType + " Get" + strFieldName + "() const { return " + strVarName + "; }" + CStr(Lf)
            End If
        Else
            If bComplexType Then
                strResult += "void Set" + strFieldName + "(const " + strVarType + "& value) { " + strVarName + " = value; }" + CStr(Lf) + CStr(Lf)
            ElseIf strVarType = "bool" Or strVarType = "BOOL" Then
                strResult += "void Set" + strFieldName + "(" + strVarType + " value) { " + strVarName + " = value; }" + CStr(Lf) + CStr(Lf)
            Else
                strResult += "void Set" + strFieldName + "(" + strVarType + " value) { " + strVarName + " = value; }" + CStr(Lf) + CStr(Lf)
            End If
        End If
    End If
 
    Return strResult
End Function
 
Sub MakeSimpleGetterSetter()
    Dim objSel As TextSelection
    Dim colTypes As New Collection
    Dim colNames As New Collection
    Dim colComments As New Collection
    Dim objStream As New System.Text.StringBuilder
 
    objSel = ActiveDocument().Selection
    ParseVariableDeclarations(Trim(objSel.Text), colTypes, colNames, colComments)
 
    For i = 1 To colNames.Count
        objStream.Append(GenerateAccessor(colTypes.Item(i), colNames.Item(i), "Getter"))
        objStream.Append(GenerateAccessor(colTypes.Item(i), colNames.Item(i), "Setter"))
    Next
 
    objSel.Text = objStream.ToString()
End Sub

문자열 검색

뭔가 좀 이상한데…

Sub QuickFind()
    ' 현재 선택된 단어가 있다면 다음에 있는 해당 단어를 찾고, 
    ' 선택된 단어가 없다면 찾기 대화창을 띄운다.
    Dim doc
    doc = ActiveDocument()
 
    If doc Is Nothing Then
        Exit Sub
    ElseIf doc.Type <> "Text" Then
        Exit Sub
    End If
 
    lookFor = doc.Selection.Text
 
    curLine = doc.Selection.CurrentLine
    curCol = doc.Selection.CurrentColumn
 
    If Len(lookFor) = 0 Then
        ExecuteCommand("Edit.FindNext")
        If Len(doc.Selection.Text) = 0 Then
            ExecuteCommand("Edit.Find")
        End If
    Else
        doc.Selection.Cancel()
        doc.Selection.MoveTo(curLine, curCol)
        doc.Selection.FindText(lookFor)
    End If
End Sub

kb/visualstudiomacro.txt · 마지막으로 수정됨: 2014/11/10 17:53 저자 excel96