Click here to Skip to main content
Email Password   helpLost your password?

Sample Image - vssprotocolhandler.gif

Introduction

Imagine that you could open a document in a Visual SourceSafe database with one mouse click.

No more opening the SourceSafe client, browsing to the correct project tree and choosing 'view latest version' from the document's context menu. In the screenshot above, you see three links to project documentation in a Word document; the links have the new VSS: protocol prefix. Clicking a VSS: link will fire up the handler presented below and open the designated document using shell association (.doc -> Word). In other words: "VSS://$/Projects/VSS ProtHandler/TD-VSSProtocolHandler.doc" will start Visual SourceSafe, find the TD-VSSProtocolHandler.doc in project "$/Projects/VSS ProtHandler" and attempt to open it using "shellexec". This is all done using Automation, you won't see the SourceSafe client at all!

You are of course familiar with the use of HTTP:, FTP: and other protocols. The VSS: protocol can be used in almost the same manner in a (intranet) webpage, on the Windows Run box, in a Word document or in a shortcut. All protocol requests are handled by URL.dll (a DLL installed by Internet Explorer). URL.dll will attempt to find a registration for the protocol and call the registered handler. For HTTP: it is most likely Internet Explorer, for VSS: it is VSSProtocolHandler.exe.

Please note that the user must have the SourceSafe client installed (to use its automation objects) and his/her machine must be able to reach the VSS database.

This article presents two principles:

Registering & hooking the "VSS:" protocol

Actually, the "VSS:" protocol is similar to the "MAILTO:" protocol. Researching this protocol is how I found out how to hook the protocol! A few lines in the registry and the protocol is registered.

[HKEY_CLASSES_ROOT]
  [vss]
    (Default) = "URL:VSS Protocol"
    URL Protocol = ""
    [DefaultIcon]
      (Default) = "VSSProtocolHandler.exe"
    [shell]
      [open]
        [command]
          (Default) = "c:\whatever\VSSProtocolHandler.exe "%1""

The secret is the string entry URL Protocol with an empty string. Now URL.dll recognizes "VSS" as a protocol.

Handling the protocol request

When the hook is registered, URL.dll will call VSSProtocolHandler.exe whenever it encounters "VSS:xxxx". The argument must be parsed by the handler.

VSS://$/Projects/VSS ProtHandler/TD-VSSProtocolHandler.doc

will eventually yield the next command line:

c:\whatever\VSSProtocolHandler.exe 
    "VSS://$/Projects/VSS ProtHandler/TD-VSSProtocolHandler.doc"

Note that the protocol prefix is still present in the argument. The handler needs to parse it and check for the "VSS:" or "VSS://" prefix. The remaining part of the argument is used to look up the document in the SourceSafe database.

The source archive contains a full Visual C++ 6 project for the handler. It's plain Win32 & Automation (no MFC). Note that the project settings automatically register the "VSS:" protocol once the project has compiled successfully, just like a COM component project does.

The code was developed on Windows 2000 and only tested on Windows 2000.

The first part is parsing the argument:

//////////////////////////////////////////////////////

// WinMain

int APIENTRY WinMain(HINSTANCE hInstance,
                     HINSTANCE hPrevInstance,
                     LPSTR     lpCmdLine,
                     int       nCmdShow)
{

    char szArgument[1024] = {0};
    LPSTR pszVSSFile = NULL;

    // Use a copy of the argument

    StrNCpy(szArgument, lpCmdLine, 1023);

    // Remove the quote from the string...

    PathUnquoteSpaces(szArgument);

    char *pszTemp = szArgument;
    while (*pszTemp)
    {
        if (*pszTemp == '\\')
            *pszTemp = '/';
        pszTemp++;
    }

    if (strlen(szArgument) == 0)
    {
        ReportError(pszErrorNoArgumentSpecified);
        exit(1);
    }
    // Check if the vss protocol string is present

    else if (_strnicmp(szArgument, "vss://$/", 8) != 0)
    {
        // Check if the slashslash is missing... that's ok too

        if (_strnicmp(szArgument, "vss:$/", 6) != 0)
        {
            // Check for "/register".

            if (_strnicmp(szArgument, "/register", 9) == 0)
            {
                RegisterVSSProtocol(_strnicmp(szArgument, 
                    "/registerq", 10) == 0? true: false);
                exit(0);
            }
            else if (_strnicmp(szArgument, "/?", 2) == 0)
            {
                ShowHelp();
                exit(0);
            }
            else
            {
                ReportError(pszErrorProtocolInvalidArgument, 
                                        szArgument, pszAbout);
                exit(1);
            }
        }
        else
            pszVSSFile = szArgument + 4;    // Point past the protocol

    }
    else
        pszVSSFile = szArgument + 6;        // Point past the protocol



    if (strlen(pszVSSFile) == 0)
    {
        MessageBox(NULL, pszErrorNoVSSFileSpecified, 
                               pszAppName, MB_ICONERROR);
        return 1;
    }

Next is firing up COM, instantiating a Visual SourceSafe Object instance, finding the current SourceSafe database in the registry and calling ViewVSSFile() to get the intended file:

    // Init COM Libraries

    HRESULT hr;
    if (FAILED(hr=CoInitialize(NULL)))
    {
        ReportError(pszErrorFailedToInitCOM, hr);
        exit(1);
    }

    CLSID clsid;

    // Create SourceSafe Automation object.

    if(SUCCEEDED(hr=CLSIDFromProgID(L"SourceSafe", &clsid)))
    {
        IVSSDatabase *pVSSDBObject = NULL;
        if (SUCCEEDED(hr=CoCreateInstance(clsid, NULL, 
          CLSCTX_ALL, IID_IVSSDatabase, (void**)&pVSSDBObject)))
        {
            long    lErr = 0;
            HKEY    hKey;
            if ((lErr = RegOpenKeyEx(HKEY_LOCAL_MACHINE,
                       _T("SOFTWARE\\Microsoft\\SourceSafe"),
                       0,
                       KEY_READ,
                       &hKey)) == ERROR_SUCCESS)
            {
                DWORD   dwType = REG_SZ;
                char    szVSSDatabasePath[512] = {0};
                DWORD   dwSize = 511;

                if ((lErr = RegQueryValueEx(hKey,
                            _T("Current Database"),
                            NULL,
                            &dwType,
                            (LPBYTE)szVSSDatabasePath,
                            &dwSize)) == ERROR_SUCCESS && dwType == REG_SZ)
                {

                    if (!ViewVSSFile(pVSSDBObject, 
                        szVSSDatabasePath, pszVSSFile))
                    {
                        // Opening the file from the

                        // current VSS database FAILED.

                        // Now try the other known databases.

                        // Exercise for the reader...



                    }
                }
                else
                    ReportError(pszErrorFindingVSSCurrentDatabase);

                RegCloseKey(hKey);
            }
            else
                ReportError(pszErrorOpeningVSSRegKey, lErr);

            pVSSDBObject->Release();
        }
        else
            ReportError(pszErrorCreatingVSSAutomationObject, hr);
    }
    else
        ReportError(pszErrorFindingVSSAutomationObject, hr);

    CoUninitialize();

ViewVSSFile() will open the designated database (srcsafe.ini), look up the designated item (file), test it if it is a file, which is not marked 'Deleted', and performs a 'Get' command on it, resulting in a file in the Temporary directory. This file is executed using ShellExecuteW (UNICODE version because the arguments (widestrings) are UNICODE and I was lazy at the time).

bool ViewVSSFile(IVSSDatabase *pVSSDBObject, 
       char *pszVSSDatabasePath, char *pszVSSFile)
{
  bool    bViewSucceeded = false;
  HRESULT hr = S_OK;
  // Note: pszDatabasePath is a BUFFER with sufficient space...


  PathRemoveBackslash(pszVSSDatabasePath);
  strcat(pszVSSDatabasePath, "\\srcsafe.ini");
  CComBSTR bsVSSIniFile(pszVSSDatabasePath);

  // Open the sourcesafe database under the current

  // logged on username and (cached) password

  // by entering empty strings.

  if(SUCCEEDED(hr=pVSSDBObject->Open(bsVSSIniFile, L"", L"")))
  {
    IVSSItem *pIVSSItem = NULL;
    // bsVSSFile("$/Courses/Cursus evaluatie.doc");

    CComBSTR bsVSSFile(pszVSSFile);

    //MessageBox(NULL, "DATABASE IS OPEN!", 

                           pszAppName, MB_ICONINFORMATION);
    if(SUCCEEDED(hr=pVSSDBObject->get_VSSItem(bsVSSFile, 
                                                0, &pIVSSItem)))
    {
      int nItemType = -1;
      // Test if the VSS item is a file and not a project.

      if (SUCCEEDED(hr = pIVSSItem->get_Type(&nItemType)))
      {
        if (nItemType == VSSITEM_FILE)
        {
          VARIANT_BOOL vbDeleted;
          if (SUCCEEDED(hr = 
            pIVSSItem->get_Deleted(&vbDeleted)))
          {
            if (vbDeleted == VARIANT_FALSE)
            {
              // Get the filename from

              // the specified SourceSafe filepath.

              char *pszTargetFileName= 
                  StrRChrA(pszVSSFile, NULL, '/');
              pszTargetFileName++;

              char szTempFile[_MAX_PATH] = {0};

              if (GetTempPath(_MAX_PATH, szTempFile) > 0)
              {
                StrCat(szTempFile, pszTargetFileName);

                CComBSTR bsLocal(szTempFile);

                if (SUCCEEDED(hr=pIVSSItem->Get(&bsLocal, 
                                         VSSFLAG_REPREPLACE))) 
                // VSSFLAG_USERROYES | VSSFLAG_REPREPLACE)))

                {
                  // bsLocal now contains a path

                  // to a file in the temp folder,

                  // which is the extracted file.

                  int hInst = (int)ShellExecuteW(NULL, L"open", 
                    (BSTR)bsLocal, NULL, NULL, SW_SHOWMAXIMIZED);
                  if (hInst <= 32)
                    ReportError(pszErrorOpeningTempDocument, 
                               hInst, szTempFile, pszVSSFile);
                  else
                    bViewSucceeded = true;
                }
                else
                  ReportError(pszErrorGettingVSSDocument, hr, 
                    pszVSSFile, pszVSSDatabasePath, szTempFile);
              }
              else
                ReportError(pszErrorCantDetermineTempDir);
            }
            else
              ReportError(pszErrorVSSFileMarkedDeleted, pszVSSFile);
          }
          else
            ReportError(pszErrorRetrievingVSSFileDeletedState, hr);
        }
        else
          ReportError(pszErrorVSSItemIsNotAFile, pszVSSFile);
      }
      else
        ReportError(pszErrorRetrievingVSSFileType, hr);

      pIVSSItem->Release();
    }
    else
      ReportError(pszErrorFindingVSSDocument, 
              hr, pszVSSFile, pszVSSDatabasePath);
  }
  else
    ReportError(pszErrorOpeningVSSDatabase, hr, pszVSSDatabasePath);

  return bViewSucceeded;
}

There is some extra code to handle registration of the protocol and handle error messaging; they're pretty straight forward.

Demo executable

The demo archive contains the (release version) executable of the project. Extract it somewhere and run it through the Windows Run box (Start | Run) using argument "/register", e.g.: "C:\path\VSSProtocolHandler.exe /register". The handler will register the "VSS:" protocol and set itself up to be the handler. You are now ready to use the protocol. You may want to hardcode your SourceSafe username and password in VSS Open command (pVSSDBObject->Open(bsVSSIniFile, L"", L"")) instead of the empty strings. Empty strings make SourceSafe use the current Windows username and cached password. You must also setup an argument line ("VSS://$/path_to_existing_file_in_VSS_database") in the project's Settings "Debug" tab before debugging.

Further

This project was a 'proof-of-concept', and was never intended to be an idiot proof, user ready application. I won't be doing any more development on it, but I still have some ideas that you might find interesting to implement:

By the way: MS Office applications do not recognize the "VSS:" protocol as a hyperlink and underline it automatically. You will have to use the "Insert Hyperlink" (CTRL+K) command to enter a Visual SourceSafe hyperlink.

An MSDN article describes the "Note:" protocol, which works in the same manner as the "VSS" protocol, but is hooked to notepad.exe. However, this example doesn't work, because notepad.exe receives "Note://file.ext" as argument, but can't handle the prefix "Note://" and fails to open the document.

References

You must Sign In to use this message board.
 
 
Per page   
 FirstPrevNext
Generalgetting error
kishore_kd
0:47 19 Aug '08  
Hi ,
Tanks for reply in advance ..

i want to open a document from the VSS directly by a hyperlink i.e. by just clicking on the hyperlink one should be able to open that document from the VSS .

i am using the VSS protocol and handler but i am getting error like::
Error 0x8004D6C2 Opening SourceSafe Database "Path to VSS\srcsafe.ini"

i dont know what is the problem , as i am new to VSS .

Smile
GeneralRe: getting error
Victor Vogelpoel
2:33 19 Aug '08  
Abandon VSS, now!

If you need to use a source control solution, go for subversion. You can find a great subversion-for-windows server on http://www.visualsvn.com.
Use TurtoiseSVN as client.

VictorV

GeneralWhen I insert hyperlink in word document as instructed with the VSS://$/projects/test.doc - doesn't open the document
Vasanth.vk
6:35 29 Oct '04  
Hi,
First of all thanks for this wonderful code. But when I insert hyperlink in word document as instructed with the VSS://$/projects/test.doc - doesn't open the document after click holding ctrl key. If anybody has faced same problem, please let me know the work around. I am using Microsoft word 2002.


Regards,
Vasu
GeneralRe: When I insert hyperlink in word document as instructed with the VSS://$/projects/test.doc - doesn't open the document
Victor Vogelpoel
8:26 29 Oct '04  
Office applications do not recognize other protocols than the regular protocols like HTTP, FTP, etc. Word autoconverts these texts to hyperlinks.

You'll have to insert your VSS:... link by using "Insert Hyperlink" command (CTRL+K).

VictorV
GeneralRe: When I insert hyperlink in word document as instructed with the VSS://$/projects/test.doc - doesn't open the document
Vasanth.vk
17:34 1 Nov '04  
Thank you Victor.

Vasanth
Generalssauterr.h
dubh
15:46 16 Aug '03  
Hi,

Do you have a copy of the ssauterr.h header file? I've been unable to find it anywhere on Microsoft's web site...

Thanks,

Brian
GeneralRe: ssauterr.h
Ashutosh R. Bhatikar
22:16 20 Aug '03  
Hi Brian,

You may try the following web link to download the VSS Automation Errors header file SSAutErr.h:
http://msdn.microsoft.com/ssafe/downloads/download.asp?ID=014

Hope this helps.

Regards,

Ashutosh.
GeneralRe: ssauterr.h
dubh@dubh.org
6:32 21 Aug '03  
It does Smile Many thanks. It's odd that a search for ssauterr.h didn't turn up this link on the Microsoft Site Smile

Thanks,

Brian
GeneralGreat stuff
Anthony_Yio
20:13 27 Nov '02  
Smile
GeneralChanging Comment of a VSSVersion or VSSItem
blair wagner
9:17 30 Sep '02  
I'm using the VSS 6.0 OLE Automation API for trapping SS
events, and for Driving VSS. I've had realtively good
success.

Short Description:
Using the VSS client from M$, I see that when I "Show
History" on a file, and then display "Details", I can
actually change the comments of a VSSVersion of that file.
However, I can't seem to accomplish this using the OLE
API. Everything is read only.
Can anyone out there help me?

Long Description:
I'm currently trying to improve the check-in process for
our programmers. We need to force the programmers to enter
reasonable comments at check-in. I trap the BeforeCheckIn
and the AfterCheckIn events using the IVSSEventHandler
interface. I display a nice interface when BeforeCheckIn
is called, to interactively prompt for information we want
in out comments. What I want to do, is replace the comment
of the file(s) checked in with my prompted comment. I've
tried many things - and usually end up with the VSS client
complaining about database collision, or not getting the
rest of the multiple selected files checked in. I don't
want to limit the programmers to checking in one file at a
time, so I need to always be able to return TRUE from
BeforeCheckIn.

Using the VSS client from M$, I see that when I "Show
History" on a file, and then display "Details", I can
actually change the comments of a VSSVersion of that file.
However, I can't seem to accomplish this using the OLE
API. Everything is read only.

Can anyone out there help me?

GeneralRe: Changing Comment of a VSSVersion or VSSItem
Victor Vogelpoel
21:08 30 Sep '02  
Can't help you with your question, sorry.

I've adopted another solution for storing comments about changes to the sources. CHANGE_LOG.TXT is a text file which contains all things I do, written down in reverse chronological order by date. This file is checked in along with the project.
Per line, I comment the changes, additions and deletions to source files, classes and resources (example in Dutch).

28-07-2002
- [JToWeb 1.00.01 VV] Logger verbeterd
- [JToWeb 1.00.01 VV] CReDirect uitgebreid met logger
- [JToWeb 1.00.01 VV] CQStringParser constructor bijgemaakt
- [JToWeb 1.00.01 VV] COptionsSheet: testen voor license code gemaakt
- [JToWeb 1.00.01 VV] LicenceCode packing en unpacking verbeterd (zat nog bug in)


23-07-2002
- [JToWeb 1.00.01 VV] CLogger is nu CDebugLogger geworden.
- [JToWeb 1.00.01 VV] CLogger, CTheWorker toegevoegd.
- [JToWeb 1.00.01 VV] Veel meeer.

I prefer this over writing comments when checking in. It's so much easier to read, search and change this file than to check in or extract comments from the project's history in SourceSafe. When releasing a version, I extract information from the CHANGE_LOG.TXT to create a "Release Notes.txt" file.

VictorV
GeneralRe: Changing Comment of a VSSVersion or VSSItem
Christian Ernst Rysgaard
18:51 3 Feb '03  
Searching the automation object documentation in vain, I ended up doing it by executing the ss.exe commandline tool which has the needed capability.

Comment (Command Line) - Changes the previously entered comment for a specific version of a file or project. Available only from the command line. (To change the comment from the Explorer, use the File Properties dialog box after selecting the appropriate file or project.)

ss "" comment -v

The important part is to make sure your does not contain any \l, \r or \" to mess up the commandline and that the size of the comment is within the commandline maximum.
GeneralRe: Changing Comment of a VSSVersion or VSSItem
Peter ritchie
12:15 18 Feb '03  
All the VSS Automation properties are read-only for comments. I'd be interested in seeing how you performed the comment change from the command-line.
GeneralUsing VSS file compare externally?
Fref
19:27 11 Sep '02  
I like SourceSafe's file comparison feature and the way it displays differences much better than other products such as WinDiff. Unfortunately, we'll be dropping SourceSafe for something else for our next project, and we'll have to use WinDiff or whatever else we can find that does an ok job.

My question is: if I leave my copy of SourceSafe on my computer, is there a way I could somehow use the VSS protocol (or whatever else) from a program that I would write in order to use SourceSafe's file comparison feature? Would it be possible to compare two local files or would I need to add the file to SourceSafe first?

Thanks for any information you can provide! Smile

GeneralRe: Using VSS file compare externally?
Victor Vogelpoel
21:54 11 Sep '02  
Using SourceSafe was just to prove a point with creating a protocol. I just demonstrated using a protocol to extract a file from a SourceSafe database. If you want more functionality, this article provides the basics for you to extent the demo application.
For example, I got an e-mail from a german guy who was adopting this idea for CVS (another source control system).Cool

If you are JUST using SourceSafe to compare files, take a look at Araxis Merge www.araxis.com[^]. This is an EXCELLENT folder and file comparison tool which has excellent automation facilities as well. WinDiff is pale by comparison.

VictorV
Generalhow to use VSS ssapi.dll in ASP
Duong Chi Nghia
17:54 15 Jul '02  
Hello !
i have a problem when create an object VSSDatabase in ASP
my code here:
set a = server.CreateObject("SSAPI.VSSDatabase");
but i can't access to these method of it.
please tell me how to use VSS in ASP.
thank you very much!
bye
nghiaduong
GeneralRe: how to use VSS ssapi.dll in ASP
Victor Vogelpoel
22:09 15 Jul '02  
This question has nothing to do with the article. It would have been more appropriate to ask it in one of the programming forums.

For more info on using VSS with ASP, see http://msdn.microsoft.com/library/default.asp?url=/library/en-us/dnmag00/html/source.asp.

VictorV
GeneralRe: how to use VSS ssapi.dll in ASP
SenKumarkathiresan
23:05 25 Jan '03  
Hi Victor
Hey i need a help from you friend ..
Iam trying to connect to VSS using ASP and
create website for viewing VSS files .
But i could not connect to VSS database by code ..
can u tell me the steps in doing that
i Registered the ssapi.dll also ..
so help me !!!!!
mail to my yahoo id mysenthilkumar@yahoo.com
thanx and regards
senthil
GeneralRe: how to use VSS ssapi.dll in ASP
Victor Vogelpoel
13:14 26 Jan '03  
Can't help you with this. Check out
http://msdn.microsoft.com/msdnmag/issues/0900/hood/default.aspx[^]

and

http://www.microsoft.com/mind/0999/sourcesafe/sourcesafe.asp[^]

VictorV
Generaljust one question
Ultras
4:43 23 Jan '02  
do you know what i have to do for automaticly support my own links in Microsoft Word, Outlook etc. I mean if i'll write in word "mailto:zzz" and press space in that case Word will automaticly convert entered text to a link. that's why question can word do it only for standard types or exists way for add own handler?
GeneralRe: just one question
VictorV
5:14 23 Jan '02  
As far as I know, the Office applications only recognise the currently supported protocols, like HTTP, FTP, Mailto, etc.

Three ways to insert an hyperlink for your own protocol:
1. Use Insert Hyperlink (CTRL-K) to insert the URL with your protocol.
2. Office XP only: create your own SmartTag recognizer and handler which autoconvert your URL to an hyperlink (a new CodeProject article?).
3. Create a VBS macro in office to search the document for your protocol and create an hyperlink for each one found.

VictorV
GeneralExtension idea
Victor Vogelpoel
22:23 10 Jul '01  
A German reader contacted me about his port of the protocol idea to another version control system, but he added a very useful feature: add a version number to the URI:
"VSS://$/Projects/VSS ProtHandler/TD-VSSProtocolHandler.doc"
will get the latest version of the file (as programmed in the article), but
"VSS://$/Projects/VSS ProtHandler/TD-VSSProtocolHandler.doc#1.6"
will get version 1.6 of the file (if existing).

Implementation is left to the enthousiastic reader.

VictorV
GeneralVSS
Anonymous
17:34 3 Jul '01  
It's so hard to find stuff on VSS, much thanks.



cypherljk
Generalthanks
Anonymous
2:27 30 Jun '01  
...perfect...


Last Updated 28 Jun 2001 | Advertise | Privacy | Terms of Use | Copyright © CodeProject, 1999-2010