Get pinned version of VSS through automation

I have a script that searches through a release branch of our software, and detects the difference from the branch to the common dev dir (diff on all files)

so i get the file... try to figure out the pinned version to diff it with the one in the other directory. There the problem starts. I cant figure out the pinned version. There is a MSDN KB article, but they say that the Action of the version starts with "Pinned" or "Unpinned".. this does not fit to our situation here. Those texts never appear in the Version.Action .

Can someone help


VSS 6.0d (Build 31222)


Answer this question

Get pinned version of VSS through automation

  • Timdog68

    In VSS 2005 a new property has been added to IVssItem: VSSItem.IsPinned.
    You can find if an item is pinned and the version to which is pinned at like this:


     
            Dim db As New SourceSafeTypeLib.VSSDatabase
            db.Open("\\server\vss_database_share\", "alinc")
            Dim x As SourceSafeTypeLib.VSSItem
            x = db.VSSItem("$/item.txt")

            MsgBox("IsPinned = " + x.IsPinned.ToString)
            If (x.IsPinned) Then
                For Each x1 As SourceSafeTypeLib.VSSItem In x.Links
                    If (x1.Parent.Spec = x.Parent.Spec) Then
                        MsgBox("Pinned in " + x.Parent.Spec + " at version " + x1.VersionNumber.ToString)
                    End If
                Next
            End If

     



    With VSS 6.0d where you don't have the IsPinned property, you can still use the Links collection to find out the version number to which an item is pinned, but you won't be able to distinguish between an item that's unpinned and an item that's pinned at a last databse version.

    Alin


  • Barry Lewis

    This is a marvelous hack of VSS data files, but is WRONG.
    Please do not use such code!

    The function's intent is to scan the files in data folder, starting from the root, like this
     $/Folder1
     $/Folder1/Folder2
     $/Folder1/Folder2/Folder3/Item
    until it locates the physical file for the item ($/Folder1/Folder2/Folder3/Item in this case).
    Then, it gets 2 bytes of this file which it ANDs between them, and conclude that is the pinned version

    Here are a couple of issues with the function I can see at a first look:

    a) The test "InStr(1, Mid(line, 15, Len(spath(i))), spath(i), vbTextCompare)" will incorrectly match longer entryies that have same beginning characters as the searched folder. For instance it will match "$/Folder12" with the searched "Folder1"
    b) Folder with long file names (longer than 32 charactes) have the names stored in names.dat, not in the data files.The attempt to locate the physical file of a folder named "$/A very long name for this folder that have more than 31 characters/"    will incorrectly match the folder with "$/A very long name for this folder too/", producing incorrect results.
    c) When a file or folder is deleted in a database, it is not actually deleted from the parent file, so you may actually have 2 entries in $/Folder1's physical file for 2 children named 'Folder2' (one of them deleted and one not). The function is incorrectly picking the deleted entry, giving incorrect results.
    d) The function may gives incorrect results on a database with orphanes files. It may be possible that both physical.a and physical.b files exists on disk (one orphan) and your function may pick the wrong one.
    e) The function concludes (lPinnedVersion = byte53 & byte54), which can only have max. 256 values. You surely can pin versions of files bigger than 256! What you probably wanted there was (256 * byte54 + byte53)...

    I'd strongly advise against using hack code like this, as it's likely you don't have a full understanding of proprietary VSS database structures, and will likely write code that apparently works but will eventually yield incorrect results. And, if the database structure will change in the future, your code will break again.
     
    Btw, to identify the physical file name of an item you could have used easier the "ss.exe physical" command line (in VSS 6.0), or the VssItem.Physical property in VSS2005.

    Alin


  • Jerry West

    thx for your responses. however, i just wanted a better overview what changed since the last "pinned" version. So i will not use one of those "hacks". So i wait till someone here wants to upgrade the vss :)

    someone was sleeping from the ms vss team

  • Danny Yoder

    Not every company has VSS2005 nor will move to VSS2005.
  • Stoober

    There is a better way!


    Public Function PinnedVersionNumber(oVSSItem As VSSItem) As Long
        Dim fso As FileSystemObject
        Dim ts As TextStream
        Dim line As String
        Dim sDataFileNameA As String
        Dim sDataFileNameB As String
        Dim spath() As String
        Dim i As Long
        Dim sletter As String
        Dim sKey As String
        Dim sLogFileName As String
        Dim lPinnedVersion As Long
        Dim ch1 As Byte
        Dim ch2 As Byte
        Dim fFound As Boolean
        Dim lRecordOffset As Long
       
        On Error GoTo Error_Handler
       
        ' set Pinned Version = -99 as default;
            lPinnedVersion = -99
        'Set the default start of the tree.  This is the "$" file;
        sletter = "a"
        sKey = "aaaaaaaa"
       
        'set the path for our VSSItem;
        spath = Split(Replace(oVSSItem.Spec, " ", "_", , , vbTextCompare),"/")
       
        'Parse through each data file to move through the VSS Tree;
        For i = 1 To UBound(spath)
            'Data files may end in .a or .b;
            'Make sure we are pointing to the current VSSDatabase;
            sDataFileNameA = "SouceSafe_Database\Data\" & sletter & "\" & sKey & ".a"
            sDataFileNameB = "SouceSafe_Database\Data\" & sletter & "\" & sKey & ".b"
       
            Set fso = New FileSystemObject
            'Find out if our data file ends in .a or .b;
            If fso.FileExists(sDataFileNameA) Then
                Set ts = fso.OpenTextFile(sDataFileNameA, ForReading)
                sLogFileName = sDataFileNameA
            Else
                Set ts = fso.OpenTextFile(sDataFileNameB, ForReading)
                sLogFileName = sDataFileNameB
            End If
           
            fFound = False
            lRecordOffset = -1 'Reset the number of records so we have a count of the "last" file
            Do While Not ts.AtEndOfStream
                line = ts.Read(64) 'Each record is 64 bytes
                lRecordOffset = lRecordOffset + 1 'Count the number of records
    '            Debug.Print Mid(line, 15, Len(spath(i)));
                If InStr(1, Mid(line, 15, Len(spath(i))), spath(i), vbTextCompare) Then 'Look at the the "Child" record;
                   ' Debug.Print line;
                   'Set the keys for the next file;
                    sKey = Mid(line, 55, 8)
                    sletter = Mid(line, 55, 1)
                    fFound = True
                    Exit Do
                End If
            Loop
            ts.Close
           
            'Check to see if our parsing worked;
            If Not fFound Then
         '       MsgBox "Parsing Failed";
                GoTo Exit_Routine
            End If
        Next
       
        'Open the Data file and look at specific bytes;
        'We wants bytes 54 and 53 for our record.;
        If fso.FileExists(sLogFileName) Then
            Open sLogFileName For Binary Access Read Lock Read As #1
                    Get 1, (lRecordOffset * 64) + 54, ch1 'We wants bytes 54 and 53 for our record.;
                    Get 1, (lRecordOffset * 64) + 53, ch2
            Close #1
            lPinnedVersion = ch1 & ch2
        End If
       
    Exit_Routine:
        PinnedVersionNumber = lPinnedVersion
    Exit Function
    Error_Handler:
        Call Err.Raise(Err.Number, Err.Source, Err.Description, Err.HelpFile, Err.HelpContext)
    End Function

     



    You may have to modify this code.  Another great ref to all of this is
    http://www.ezds.com/html/ssi_log_data_files.html  That is where I got some of the information that helped me write the above.  Also thanks goes to Dave Goodall.  Hope this will help everyone

  • nigeldude

    I ran into the same problem. Still don't know how to "fix" it but there is a work around. Here is the work around in my VB code

    Public Function PinnedVersionNumber(oVSSItem As VSSItem) As Long

    Dim oVSSTestItem As VSSItem

    Dim oVSSVersion As VSSVersion

    On Error GoTo Error_Handler

    PinnedVersionNumber = -99

    Set oVSSTestItem = PinnedItem(oVSSItem)

    Call oVSSTestItem.Checkout(, , VSSFlags.VSSFLAG_GETNO)

    Call oVSSTestItem.UndoCheckout(, VSSFlags.VSSFLAG_DELNOREPLACE)


    Exit_Routine:

    Exit Function

    Error_Handler:

    Select Case Err.Number

    Case PineedToSpecificVersionError '<file> is pinned to a specific version

    Err.Clear

    PinnedVersionNumber = oVSSTestItem.VersionNumber

    Exit Function

    Case FileCheckedOutError '< > is currently checked out by < >

    Err.Clear

    Exit Function

    Case Else

    Err.Raise Err.Number, Err.Source, Err.Description, Err.HelpFile, Err.HelpContext

    End Select

    End Function



    As you can see and I'm sure you've found there is no "pinned" property that is documented in the Object Model. However if you try to check a file out that is pinned you should recieve an error that "You may not check out a file that is pinned to a specific version". The wording might not be the exact same. But based on the error you recieve you may be able to tell if the file is pinned. If you get the pinned file error then when you try to get the VersionNumber on that file it should be the pinned version. However if you are able to check the file out then you will have to undo a checkout and you will know that the file is not pinned.

    If anyone finds a better way to find out if a file is pinned or what version it is pinned at please let me know.

    Steve H

  • mbothmer

    It would also be nice if this functionality was built into VSS 6.  Then we wouldn’t need to write “HACK” code to find out simple information.  < xml:namespace prefix = o ns = "urn:schemas-microsoft-com:office:office" />


  • Get pinned version of VSS through automation