Visual Studio 2008 と Visual Source Safe(VSS)のバインド情報を取得する。
サンプルコード
Visual Studio 2008 と Visual Source Safe はチェックイン・チェックアウトの操作をIDE上から実施できるように、プロジェクトとソリューションをVSSのプロジェクト(フォルダ)と対応付けして連携して処理ができるようにしています。このバインド情報は、ツールバーの「ソース管理」-[ソース管理の変更]から設定します。
今回は、このバインド情報を解析して整理した上で、以下のクラスに取り込む処理を記載します。
まずは、バインド情報がどのような形式でVisualStudioが記録しているかを見ていきます。調べてみると、バインド情報はソリューションファイル(.sln)とソースコードコントロールファイル(mssccprj.scc)に記録されています。mssccprj.sccファイルは、.slnと同じフォルダに存在します。
ソリューションファイル(GlobalSection(SourceCodeControl)セクションに該当情報が設定されています。)
Microsoft Visual Studio Solution File, Format Version 10.00
# Visual Studio 2008
Project("{F184B08F-C81C-45F6-A57F-5ABD9991F28F}") = "VssTest", "VssTest\VssTest.vbproj", "{75C5AB46-8C4F-4B56-8456-826462859A43}"
EndProject
Project("{F184B08F-C81C-45F6-A57F-5ABD9991F28F}") = "VssTest2", "VssTest2\VssTest2.vbproj", "{D671519E-B335-4AAD-AE3F-CB6B16CA48B9}"
EndProject
Project("{F184B08F-C81C-45F6-A57F-5ABD9991F28F}") = "WindowsApplication1", "WindowsApplication1\WindowsApplication1.vbproj", "{D7547178-6BD0-459C-A604-3963E72BD1D7}"
EndProject
Project("{F184B08F-C81C-45F6-A57F-5ABD9991F28F}") = "WindowsApplication2", "WindowsApplication2\WindowsApplication2.vbproj", "{8F29E98F-A144-428E-ADDD-E62E4B45B077}"
EndProject
GlobalGlobalSection(SolutionConfigurationPlatforms) = preSolution
GlobalSection(SourceCodeControl) = preSolution
SccNumberOfProjects = 5
SccLocalPath0 = .
SccProjectUniqueName1 = VssTest2\\VssTest2.vbproj
SccProjectName1 = \u0022$/VssEraser/VssTest2\u0022,\u0020QAAAAAAA
SccLocalPath1 = VssTest2
SccProjectUniqueName2 = VssTest\\VssTest.vbproj
SccProjectName2 = \u0022$/VssEraser/VssTest\u0022,\u0020CAAAAAAA
SccLocalPath2 = VssTest
SccProjectUniqueName3 = WindowsApplication1\\WindowsApplication1.vbproj
SccLocalPath3 = .
SccProjectFilePathRelativizedFromConnection3 = WindowsApplication1\\
SccProjectUniqueName4 = WindowsApplication2\\WindowsApplication2.vbproj
SccLocalPath4 = .
SccProjectFilePathRelativizedFromConnection4 = WindowsApplication2\\
EndGlobalSection
Debug|Any CPU = Debug|Any CPU
Release|Any CPU = Release|Any CPU
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{75C5AB46-8C4F-4B56-8456-826462859A43}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{75C5AB46-8C4F-4B56-8456-826462859A43}.Debug|Any CPU.Build.0 = Debug|Any CPU
{75C5AB46-8C4F-4B56-8456-826462859A43}.Release|Any CPU.ActiveCfg = Release|Any CPU
{75C5AB46-8C4F-4B56-8456-826462859A43}.Release|Any CPU.Build.0 = Release|Any CPU
{D671519E-B335-4AAD-AE3F-CB6B16CA48B9}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{D671519E-B335-4AAD-AE3F-CB6B16CA48B9}.Debug|Any CPU.Build.0 = Debug|Any CPU
{D671519E-B335-4AAD-AE3F-CB6B16CA48B9}.Release|Any CPU.ActiveCfg = Release|Any CPU
{D671519E-B335-4AAD-AE3F-CB6B16CA48B9}.Release|Any CPU.Build.0 = Release|Any CPU
{D7547178-6BD0-459C-A604-3963E72BD1D7}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{D7547178-6BD0-459C-A604-3963E72BD1D7}.Debug|Any CPU.Build.0 = Debug|Any CPU
{D7547178-6BD0-459C-A604-3963E72BD1D7}.Release|Any CPU.ActiveCfg = Release|Any CPU
{D7547178-6BD0-459C-A604-3963E72BD1D7}.Release|Any CPU.Build.0 = Release|Any CPU
{8F29E98F-A144-428E-ADDD-E62E4B45B077}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{8F29E98F-A144-428E-ADDD-E62E4B45B077}.Debug|Any CPU.Build.0 = Debug|Any CPU
{8F29E98F-A144-428E-ADDD-E62E4B45B077}.Release|Any CPU.ActiveCfg = Release|Any CPU
{8F29E98F-A144-428E-ADDD-E62E4B45B077}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
EndGlobal
ソースコードコントロールファイル(mssccprj.scc)
SCC = This is a Source Code Control file[VssTest.sln]
SCC_Aux_Path = "C:\Users\Administrator\Documents\vss"
SCC_Project_Name = "$/VssEraser", BAAAAAAA
後は上記の情報を抜き出して整理します。整理用のコードは以下となります。
Imports System.Collections.Generic
Imports System.Runtime.InteropServicesPublic Class VssBindInformation
Public SolutionFullName As String = String.Empty
Public SolutionVssSpecPath As String = String.Empty
Public SolutionVssSpec As String = String.Empty
Public Projects As New Dictionary(Of String, VssProjectBindInfo)Public Class VssProjectBindInfo
Public ProjectFullName As String = String.Empty
Public LocalPath As String = String.Empty
Public VssSpecPath As String = String.Empty
End Class
_
Private Shared Function GetPrivateProfileString(ByVal lpAppName As String, _
ByVal lpKeyName As String, _
ByVal lpDefault As String, _
ByVal lpReturnedString As System.Text.StringBuilder, _
ByVal nSize As Integer, _
ByVal lpFileName As String) As Integer
End FunctionPublic Sub New(ByVal solutionFileName As String)
Me.SolutionFullName = solutionFileName
' Solution 情報の抽出
Dim solutionFolder As String = System.IO.Path.GetDirectoryName(solutionFileName)
Dim solutionVssFile As String = System.IO.Path.Combine(solutionFolder, "mssccprj.scc")If System.IO.File.Exists(solutionVssFile) = True Then
Dim sb As New System.Text.StringBuilder
sb.Capacity = 255GetPrivateProfileString(solutionFileName, _
"SCC_Project_Name", _
String.Empty, _
sb, _
sb.Capacity, _
solutionVssFile)Me.SolutionVssSpecPath = GetSolutionVssSpecPath(sb.ToString) + "/"
Me.SolutionVssSpec = GetSolutionVssSpecPath(sb.ToString) + "/" + solutionFileNameEnd If
' Project 情報の抽出
Dim lines As String() = System.IO.File.ReadAllLines(solutionFileName)Dim isStart As Boolean = False
Dim sccSection As New Dictionary(Of String, String)
For i As Integer = 0 To lines.Length - 1Dim line As String = lines(i)
If line.IndexOf("GlobalSection(SourceCodeControl)", StringComparison.CurrentCultureIgnoreCase) > 0 Then
isStart = True
Continue For
End IfIf isStart = True AndAlso line.IndexOf("EndGlobalSection", StringComparison.CurrentCultureIgnoreCase) > 0 Then
Exit For
End IfIf isStart = True Then
Dim key As String = String.Empty
Dim value As String = String.EmptyDim splitPos As Integer = line.IndexOf("=")
If splitPos > 0 Thenkey = line.Substring(0, splitPos).TrimEnd.Replace(vbTab, String.Empty)
value = line.Substring(splitPos + 1).TrimStartsccSection.Add(key, value)
End If
End If
Next
If sccSection.ContainsKey("SccNumberOfProjects") = True Then
Dim projectCount As Integer = CInt(sccSection.Item("SccNumberOfProjects"))
For i As Integer = 0 To projectCount - 1
Dim projectKeyName As String = "SccProjectName" + i.ToString
Dim projectUniqueKeyName As String = "SccProjectUniqueName" + i.ToString
Dim projectRelativeKeyName As String = "SccProjectFilePathRelativizedFromConnection" + i.ToStringIf ((sccSection.ContainsKey(projectKeyName) = True OrElse sccSection.ContainsKey(projectRelativeKeyName))) AndAlso _
(sccSection.ContainsKey(projectUniqueKeyName)) = True ThenDim item As New VssProjectBindInfo
item.ProjectFullName = GetAbsolutePath(solutionFolder, sccSection.Item(projectUniqueKeyName).Replace("\\", "\"))
item.LocalPath = System.IO.Path.GetDirectoryName(item.ProjectFullName)If sccSection.ContainsKey(projectKeyName) = True Then
item.VssSpecPath = GetVssSpecPath(sccSection.Item(projectKeyName))
Else
item.VssSpecPath = Me.SolutionVssSpecPath + sccSection.Item(projectRelativeKeyName).Replace("\\", String.Empty)
End IfMe.Projects.Add(item.ProjectFullName.ToLower, item)
End If
Next
End If
End Sub
Private Function GetAbsolutePath(ByVal basePath As String, ByVal relatePath As String) As String
Dim targetBasePath As String = basePath
If basePath.Length > 0 Then
If (basePath.Substring(basePath.Length - 1, 1) <> "\") AndAlso (basePath.Substring(basePath.Length - 1, 1) <> "/") Then
targetBasePath += "\"
End If
End IfDim baseUri As New System.Uri(targetBasePath)
Dim absUri As New System.Uri(baseUri, relatePath)Return absUri.LocalPath
End Function
Private Function GetSolutionVssSpecPath(ByVal sccProjectName As String) As String
Dim line As String = sccProjectName
Dim pos As Integer = 0pos = sccProjectName.IndexOf(",")
If pos > 0 Then
line = line.Substring(0, pos)
End Ifline = line.Replace("""", String.Empty)
Return line
End Function
Private Function GetVssSpecPath(ByVal projectKeyName As String) As String
Dim line As String = projectKeyName
Dim pos As Integer = 0pos = projectKeyName.IndexOf(",")
If pos > 0 Then
line = line.Substring(0, pos)
End Ifpos = projectKeyName.IndexOf("$")
If pos > 0 Then
line = line.Replace(line.Substring(0, pos), String.Empty)
End IfReturn line
End Function
End Class