Best Practices for Implementing a Source Control Plug-in
The following technical details can help you reliably implement a source control plug-in in Visual Studio.
When an array of files is passed, it is not passed as a contiguous array of file names. It is passed as an array of pointers to file names. For example, in the SccGet Function, the file names are passed by the lpFileNames parameter, where lpFileNames is actually a pointer to a char **. lpFileNames is a pointer to the first name, lpFileNames is a pointer to the second name, and so on.
The IDE no longer loads DLLs from relative paths (for example, .\NewProvider.dll). A full path of the DLL must be specified (for example, C:\Providers\NewProvider.dll). This requirement strengthens the security of the IDE by preventing the loading of unauthorized or impersonated source control DLLs.
A user who plans to install your source control plug-in may already have an existing source control plug-in installed on the computer. The installation (setup) program for the plug-in that you create should determine whether there are existing values for the relevant registry keys. If these keys are already set, your installation program should ask the user whether to register your plug-in as the default source control plug-in and replace the one that is already installed.
The SCC_OK return code for a source control function indicates that the operation has succeeded for all files. If the operation fails, it is expected to return the last error code encountered.
The rule for reporting is that if an error occurs in the IDE, the IDE is responsible for reporting it. If an error occurs in the source control system, the source control plug-in is responsible for reporting it. For instance, "No files are currently selected" would be reported by the IDE, whereas "This file is already checked out" would be reported by the plug-in.
During the call to the SccInitialize Function, the caller passes the ppvContext parameter, which is an uninitialized handle to a void. The source control plug-in can ignore this parameter or it can allocate a structure of any kind and put a pointer to that structure into the passed pointer. The IDE does not understand this structure, but it passes a pointer to this structure into every other call in the plug-in. This provides valuable context cache information to the plug-in that it can use to maintain global state information that persists across function calls without using global variables. The plug-in is responsible for freeing the structure on a call to the SccUninitialize Function.
If the plug-in sets the SCC_CAP_REENTRANT bit in the SccInitialize Function (specifically, in the lpSccCaps parameter), multiple context structures are used to track all the projects that are open.
For each command, such as the SccGet Function, the IDE can specify many options that change the behavior of the command.
The API supports the setting of certain options by the IDE through the fOptions parameter. These options are described in Bitflags Used by Specific Commands together with the commands that they affect. In general, these are options for which the user would not be prompted.
Most user-configurable setting options are not defined in this manner, because they vary widely among source control plug-ins. Therefore, the recommended mechanism is an Advanced button. For instance, in the Get dialog box, the IDE displays only information that it understands, but it also displays an Advanced button if the plug-in has options for this command. When the user clicks the Advanced button, the IDE calls the SccGetCommandOptions Function to enable the source control plug-in to prompt the user for information, such as bitflags or a date/time. The plug-in returns this information in a structure that is passed back during the SccGet command.