Добрый.
Как известно, в Visual Studio можно создавать шаблоны проекта только для C#, любители C++ в пролете. Нижеприведенный макрос позволяет решить проблему. С его помощью можно создавать полностью настроенные проекты в течении полуминуты, экономя кучу времени и нервных клеток.
Как это работает. Создается solution ProjectTemplates, в нем плодятся проекты, которые в будущем будут использоваться в качестве шаблонов. В них добавляются исходники, ресурсы, property sheets и т.д. После этого создается пустое solution или открывается существующее и запускается макрос AddCppProjectFromTemplate(). В нем задается имя добавляемого проекта, выбирается нужный шаблон и файлы из него копируются в текущее solution. Файлы при необходимости переименовываются, а в их содержимом имя шаблона меняется на имя создаваемого проекта. В файле vcxproj так же меняется GUID проекта.
Замечания.
Имя шаблона должно быть уникальным, что бы в тексте случайно не заменить чтонить лишнего. Например подойдет $$$WinApp$$$, а если выбрать wchar_t, то будут проблемы.
Все файлы шаблона должны находиться в папке с файлом проекта vcxproj, т.е. содержимое подпапок (если оно есть) не копируется.
Файлы с кодировкой отличной от ANSI (unicode, utf-8) должны содержать BOM.
Solution с шаблонами и solution, в которое добавляется проект, должны находится в одной папке. Если это не так, то нужно изменить константу conTemplateSolutionFolder в тексте макроса.
Для поддержки Visual Studio 2008 нужно изменить conProjectExtension, astrSkipExtensions и conProjectGuidPattern.
Что бы переименовать шаблон, нужно открыть solution ProjectTemplates и создать проект под новым именем из шаблона со старым именем, после чего старый шаблон удалить. Имена проектов в макросе не используются, только имена vcxproj файлов!
Option Strict Off
Option Explicit On
Imports System
Imports EnvDTE
Imports System.Diagnostics
Public Module MegaCoolModule
'
' AddCppProjectFromTemplate()
' Revision: 1
'
Private Const conVisualCPlusPlusProject As String = "{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}"
Private Const conTemplateSolutionFolder As String = "..\ProjectTemplates"
Private Const conProjectExtension As String = ".vcxproj"
Private Function GetTemplateProjectFile() As String
Dim astrProjectFiles() As String = IO.Directory.GetFiles( _
IO.Path.Combine(IO.Path.GetDirectoryName(DTE.Solution.FullName), conTemplateSolutionFolder), _
"*" & conProjectExtension, IO.SearchOption.AllDirectories)
If astrProjectFiles.Length = 0 Then
Return ""
End If
Dim strMenu As String = ""
For i As Integer = 0 To astrProjectFiles.Length - 1
strMenu &= vbCrLf & i + 1 & ": " & IO.Path.GetFileNameWithoutExtension(astrProjectFiles(i))
Next
Dim strProjectFile As String = ""
Do
Dim strProjectIndex As String = InputBox("Введите номер шаблона." & strMenu)
If Len(strProjectIndex) = 0 Then
Exit Do
End If
Try
strProjectFile = astrProjectFiles(CInt(strProjectIndex) - 1)
Catch
End Try
Loop While Len(strProjectFile) = 0
Return strProjectFile
End Function
Private Function GetProjectName(ByVal strPrompt As String) As String
Dim strProjectName As String = ""
Do
strProjectName = InputBox(strPrompt, , strProjectName)
If Len(strProjectName) = 0 Then
Return strProjectName
End If
Dim achrInvalidChars() As Char = {"&"c, "#"c, "%"c}
If strProjectName.IndexOfAny(IO.Path.GetInvalidFileNameChars()) >= 0 _
Or strProjectName.IndexOfAny(achrInvalidChars) >= 0 Then
MsgBox("Имя проекта содержит недопустимые символы", MsgBoxStyle.Exclamation)
Continue Do
End If
Dim astrReservedNames() As String = {".", "..", "CON", "COM1", "COM2", "COM3", "AUX", "LPT1", "LPT2", "PRN", "NUL"}
If Array.IndexOf(astrReservedNames, strProjectName) >= 0 Then
MsgBox("Вы ввели зарезервированное имя", MsgBoxStyle.Exclamation)
Continue Do
End If
For Each objProject As Project In DTE.Solution.Projects
If String.Compare(objProject.Name, strProjectName, True) = 0 Then
MsgBox("Solution уже содержит проект с указанным именем", MsgBoxStyle.Exclamation)
Continue Do
End If
Next
Return strProjectName
Loop
End Function
Private Sub ParseAndCopyFile(ByVal strSourceFile As String, ByVal strDestinationFile As String, ByVal strTemplateProjectName As String, ByVal strNewProjectName As String)
Const conProjectGuidPattern As String = "(?!<ProjectGuid>\{).{36}(?=\}</ProjectGuid>)"
' Если в файле нет BOM, то будет использована кодировка ANSI
Dim objEncoding As Text.Encoding = Text.Encoding.GetEncoding(0, New Text.EncoderExceptionFallback, New Text.DecoderExceptionFallback)
Trace.WriteLine("ParseAndCopyFile() file: " & strSourceFile)
Dim objReader As New IO.StreamReader(strSourceFile, objEncoding, True)
Dim strFileContent As String = objReader.ReadToEnd()
objEncoding = objReader.CurrentEncoding
Trace.WriteLine(String.Format("ParseAndCopyFile() encoding: {0} ({1})", objEncoding.EncodingName, objEncoding.CodePage))
objReader.Close()
strFileContent = strFileContent.Replace(strTemplateProjectName, strNewProjectName)
If IO.Path.GetExtension(strSourceFile) = conProjectExtension Then
Dim strModifiedFileContent As String = Text.RegularExpressions.Regex.Replace(strFileContent, _
conProjectGuidPattern, UCase(Guid.NewGuid().ToString()), _
Text.RegularExpressions.RegexOptions.IgnoreCase)
Trace.Assert(strModifiedFileContent <> strFileContent)
strFileContent = strModifiedFileContent
End If
Dim objWriter As New IO.StreamWriter(strDestinationFile, False, objEncoding)
objWriter.Write(strFileContent)
objWriter.Close()
End Sub
Public Sub AddCppProjectFromTemplate()
' Файлы с указанными расширениями не будет добавлены в создаваемый проект
Dim astrSkipExtensions() As String = {".aps", ".sdf", ".opensdf", ".ipch", ".sln", ".suo"}
' В файлах с указанными расширениями будет производиться замена текста
Dim astrParseExtensions() As String = {conProjectExtension, ".filters", ".user", ".manifest", ".c", ".cpp", ".h", ".inc", ".inl", ".rc", ".rc2", ".def", ".asm", ".cmd", ".bat", ".txt", ".ini"}
If Not DTE.Solution.IsOpen() Then
MsgBox("Перед вызовом макроса необходимо открыть solution, в которое будет добавлен проект", MsgBoxStyle.Critical)
Return
End If
Dim strTemplateProjectFile As String = GetTemplateProjectFile()
If Len(strTemplateProjectFile) = 0 Then
Return
End If
Dim strTemplateProjectName As String = IO.Path.GetFileNameWithoutExtension(strTemplateProjectFile)
Dim strNewProjectName As String = GetProjectName("Введите имя создаваемого проекта.")
If Len(strNewProjectName) = 0 Then
Return
End If
Dim idMBResult As MsgBoxResult = MsgBox("Создать для проекта папку? Нажмите «Нет» что бы использовать папку solution.", MsgBoxStyle.Question + MsgBoxStyle.YesNoCancel)
If idMBResult = MsgBoxResult.Cancel Then
Return
End If
Dim strSourceFolder As String = IO.Path.GetDirectoryName(strTemplateProjectFile)
Dim strDestinationFolder As String = IO.Path.GetDirectoryName(DTE.Solution.FullName)
If idMBResult = MsgBoxResult.Yes Then
strDestinationFolder = IO.Path.Combine(strDestinationFolder, strNewProjectName)
IO.Directory.CreateDirectory(strDestinationFolder)
End If
For Each strSourceFile As String In IO.Directory.GetFiles(strSourceFolder)
Dim strSourceExtension As String = LCase(IO.Path.GetExtension(strSourceFile))
If Array.IndexOf(astrSkipExtensions, strSourceExtension) >= 0 Then
Continue For
End If
Dim strDestinationFile As String = IO.Path.Combine(strDestinationFolder, _
IO.Path.GetFileNameWithoutExtension(strSourceFile).Replace(strTemplateProjectName, strNewProjectName) & _
strSourceExtension)
If Array.IndexOf(astrParseExtensions, strSourceExtension) >= 0 Then
ParseAndCopyFile(strSourceFile, strDestinationFile, strTemplateProjectName, strNewProjectName)
Else
IO.File.Copy(strSourceFile, strDestinationFile, True)
End If
Next
Try
DTE.Solution.AddFromFile(IO.Path.Combine(strDestinationFolder, strNewProjectName & conProjectExtension), False)
Catch ex As Exception
MsgBox("Файлы проекта были успешно скопированы в папку " & strDestinationFolder & ", но во время добавления проекта в solution возникла ошибка. Попробуйте добавить проект вручную. Описание ошибки: " & ex.Message, MsgBoxStyle.Critical)
End Try
End Sub
End Module