Click here to Skip to main content
15,117,095 members
Articles / Web Development / HTML
Posted 27 Jun 2001


85 bookmarked

VSS: protocol handler for Visual SourceSafe

Rate me:
Please Sign up or sign in to vote.
4.33/5 (9 votes)
27 Jun 20016 min read
This article describes how to hook up a protocol, in the example "vss:", to a custom handler to open a document from a Visual SourceSafe repository using automation.

Sample Image - vssprotocolhandler.gif


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 up the "VSS:" protocol to the handler VSSProtocolHandler.exe,
  • Handling the protocol request: letting the handler open the indicated document on the protocol line from the Visual SourceSafe database, using automation.

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.

    (Default) = "URL:VSS Protocol"
    URL Protocol = ""
      (Default) = "VSSProtocolHandler.exe"
          (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:

    "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...

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

    if (strlen(szArgument) == 0)
    // 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)
                    "/registerq", 10) == 0? true: false);
            else if (_strnicmp(szArgument, "/?", 2) == 0)
                                        szArgument, pszAbout);
            pszVSSFile = szArgument + 4;    // Point past the protocol
        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
if (FAILED(hr=CoInitialize(NULL)))
    ReportError(pszErrorFailedToInitCOM, hr);

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,
                   &hKey)) == ERROR_SUCCESS)
            DWORD   dwType = REG_SZ;
            char    szVSSDatabasePath[512] = {0};
            DWORD   dwSize = 511;

            if ((lErr = RegQueryValueEx(hKey,
                        _T("Current Database"),
                        &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...


            ReportError(pszErrorOpeningVSSRegKey, lErr);

        ReportError(pszErrorCreatingVSSAutomationObject, hr);
    ReportError(pszErrorFindingVSSAutomationObject, hr);


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...

  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);
                                                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 = 
            if (vbDeleted == VARIANT_FALSE)
              // Get the filename from
              // the specified SourceSafe filepath.
              char *pszTargetFileName= 
                  StrRChrA(pszVSSFile, NULL, '/');

              char szTempFile[_MAX_PATH] = {0};

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

                CComBSTR bsLocal(szTempFile);

                if (SUCCEEDED(hr=pIVSSItem->Get(&bsLocal, 
                  // 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)
                               hInst, szTempFile, pszVSSFile);
                    bViewSucceeded = true;
                  ReportError(pszErrorGettingVSSDocument, hr, 
                    pszVSSFile, pszVSSDatabasePath, szTempFile);
              ReportError(pszErrorVSSFileMarkedDeleted, pszVSSFile);
            ReportError(pszErrorRetrievingVSSFileDeletedState, hr);
          ReportError(pszErrorVSSItemIsNotAFile, pszVSSFile);
        ReportError(pszErrorRetrievingVSSFileType, hr);

              hr, pszVSSFile, pszVSSDatabasePath);
    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.


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:

  • Better "logging on" code for the SourceSafe database. The current code assumes that you are using your Windows logon name to log on into the SourceSafe database. It also assumes that you have logged on to the database at least once; the logon/password is cached by Windows and is provided automatically in this case.
  • If one uses more than one SourceSafe database, and the document cannot be found in the current SourceSafe database, then the handler could open up the other databases until the file is found (or not). SourceSafe stores all used databases in the registry, so this shouldn't be hard to find.
    • Search for srcsafe.ini in the directory where ssapi.dll is located.
    • Search for srcsafe.ini in each directory of the path to ssapi.dll. In other words, if ssapi.dll is located in C:\Folder1\Folder2\Folder3\SSAPI.DLL, then Folder3, Folder2, Folder1 and C:\ are searched (in that order).
    • Search for srcsafe.ini in the location indicated by the named value "API Current Database" in the registry key HKEY_LOCAL_MACHINE\Software\Microsoft\SourceSafe.
    • Search for srcsafe.ini in the location indicated by the named value "SCCProviderPath" in the registry key HKEY_LOCAL_MACHINE\Software\Microsoft\SourceSafe.

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.


  • Q167134 - HOWTO Open Visual SourceSafe to a Specific Project
  • Q169928 - HOWTO Open a SourceSafe Database with OLE Automation
  • Q175758 - HOWTO Trap Visual SourceSafe OLE Errors
  • Q176350 - HOWTO Open Visual SourceSafe to a Specific Database
  • Q201431 - HOWTO Write Automation for Visual SourceSafe 5_0-6_0
  • Microsoft Visual SourceSafe OLE Automation (Ken Felder, October 1995)
  • ssauterr - SourceSafe Automation errors
  • ssauto - Visual C++ Header File for Visual SourceSafe
  • Visual SourceSafe Frequently Asked Questions
  • vsstree - VSS OLE Sample Code Written in Visual C


This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here


About the Author

Victor Vogelpoel
Software Developer (Senior)
Netherlands Netherlands
Victor is consulting in The Netherlands.

His interests include Windows and web application development using .NET technologies and even some Apache/PHP/MySQL...

Comments and Discussions

Generalgetting error Pin
kishore_kd19-Aug-08 0:47
Memberkishore_kd19-Aug-08 0:47 
GeneralRe: getting error Pin
Victor Vogelpoel19-Aug-08 2:33
MemberVictor Vogelpoel19-Aug-08 2:33 
GeneralWhen I insert hyperlink in word document as instructed with the VSS://$/projects/test.doc - doesn't open the document Pin
Vasanth.vk29-Oct-04 6:35
MemberVasanth.vk29-Oct-04 6:35 
GeneralRe: When I insert hyperlink in word document as instructed with the VSS://$/projects/test.doc - doesn't open the document Pin
Victor Vogelpoel29-Oct-04 8:26
MemberVictor Vogelpoel29-Oct-04 8:26 
GeneralRe: When I insert hyperlink in word document as instructed with the VSS://$/projects/test.doc - doesn't open the document Pin
Vasanth.vk1-Nov-04 17:34
MemberVasanth.vk1-Nov-04 17:34 
Generalssauterr.h Pin
dubh16-Aug-03 15:46
Memberdubh16-Aug-03 15:46 
GeneralRe: ssauterr.h Pin
Ashutosh R. Bhatikar20-Aug-03 22:16
MemberAshutosh R. Bhatikar20-Aug-03 22:16 
GeneralRe: ssauterr.h Pin
dubh@dubh.org21-Aug-03 6:32
sussdubh@dubh.org21-Aug-03 6:32 
GeneralGreat stuff Pin
Anthony_Yio27-Nov-02 20:13
MemberAnthony_Yio27-Nov-02 20:13 
GeneralChanging Comment of a VSSVersion or VSSItem Pin
blair wagner30-Sep-02 9:17
sussblair wagner30-Sep-02 9:17 
GeneralRe: Changing Comment of a VSSVersion or VSSItem Pin
Victor Vogelpoel30-Sep-02 21:08
MemberVictor Vogelpoel30-Sep-02 21:08 
GeneralRe: Changing Comment of a VSSVersion or VSSItem Pin
Christian Ernst Rysgaard3-Feb-03 18:51
MemberChristian Ernst Rysgaard3-Feb-03 18:51 
GeneralRe: Changing Comment of a VSSVersion or VSSItem Pin
Peter Ritchie18-Feb-03 12:15
MemberPeter Ritchie18-Feb-03 12:15 
QuestionUsing VSS file compare externally? Pin
fferland11-Sep-02 19:27
Memberfferland11-Sep-02 19:27 
AnswerRe: Using VSS file compare externally? Pin
Victor Vogelpoel11-Sep-02 21:54
MemberVictor Vogelpoel11-Sep-02 21:54 
Questionhow to use VSS ssapi.dll in ASP Pin
Member 15205715-Jul-02 17:54
MemberMember 15205715-Jul-02 17:54 
AnswerRe: how to use VSS ssapi.dll in ASP Pin
Victor Vogelpoel15-Jul-02 22:09
MemberVictor Vogelpoel15-Jul-02 22:09 
GeneralRe: how to use VSS ssapi.dll in ASP Pin
SenKumarkathiresan25-Jan-03 23:05
sussSenKumarkathiresan25-Jan-03 23:05 
GeneralRe: how to use VSS ssapi.dll in ASP Pin
Victor Vogelpoel26-Jan-03 13:14
MemberVictor Vogelpoel26-Jan-03 13:14 
Generaljust one question Pin
23-Jan-02 4:43
suss23-Jan-02 4:43 
GeneralRe: just one question Pin
Victor Vogelpoel23-Jan-02 5:14
MemberVictor Vogelpoel23-Jan-02 5:14 
GeneralExtension idea Pin
Victor Vogelpoel10-Jul-01 22:23
MemberVictor Vogelpoel10-Jul-01 22:23 
GeneralVSS Pin
3-Jul-01 17:34
suss3-Jul-01 17:34 
Generalthanks Pin
30-Jun-01 2:27
suss30-Jun-01 2:27 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.