Marco Web Center |
Delphi Developers' HandbookChapter 15: Other Delphi ExtensionsCopyright Marco Cantu' 1997The Version Control System InterfaceA version control system (VCS for short) is a tool that can help several programmers work on a single project in an organized manner. Typically such a tool keeps track of who changed a file, and what changes occurred within each version, and it prevents two programmers from modifying a given file at the same time. The Client/Server Suite Edition of Delphi ships with a limited version of Intersolv�s PVCS source control software. Other tools are available, such as MKS�s Source Integrity and the shareware ViCiouS originally developed by Bob Swart and now published by SureHand Software. Professional version control systems are typically built upon the concept of storing the various files and revisions in a database. Some systems save just the changes to a file (such as added or deleted text), while others save the full content of the previous versions. This makes it possible to build several versions of a project with a given set of source files, but it also allows programmers toenables rolling back changes to a more stable version in case of problems. More advanced systems can track different sets of changes and can integrate them. Delphi�s version control system interface is something of an alternative to the expert/wizard interface, but it works in a distinctive way, using the the VCS Manager DLL. This results in two subtle differences between a Delphi VCS and a Delphi wizard. The first is that you can install only one VCS at a time, while you can install many wizardexperts. Second, a Delphi VCS must reside in a DLL (you can�t create a DCU-based VCS). You can specify a preferred VCS by setting a Registry entry that identifies the filename of an appropriate DLL: HKEY_CURRENT_USER\Software\Borland\Delphi\3.0\Version Control\VCSManager A more visible difference is that a VCS displays its own a pull-down menu, which can contain many items. This is much easier than adding menu items via one or more add-in wizards. The TIVCSClient InterfaceThe ToolsAPI�s VcsIntf unit defines the base class for Delphi�s standard version control system interface. By default, this unit isn�t part of the Delphi library, so you�ll need to copy it into your project directory (and add it to the uses clause of the main form�s source file). Here is the class declaration (which resembles the component editor interface class because of the GetVerbCount, GetVerb, and ExecuteVerb methods): type TIVCSClient= class(TInterface) function GetIDString: string; virtual; stdcall; abstract; procedure ExecuteVerb(Index: Integer); virtual; stdcall; abstract; function GetMenuName: string; virtual; stdcall; abstract; function GetVerb(Index: Integer): string; virtual; stdcall; abstract; function GetVerbCount: Integer; virtual; stdcall; abstract; function GetVerbState(Index: Integer): Word; virtual; stdcall; abstract; procedure ProjectChange; virtual; stdcall; abstract; end; This declares an abstract interface class, which is necessary whenever you implement a class in an external DLL. Accordingly, you simply build a DLL to create your own version control system. However, before we build a VCS, let�s examine the TIVCSClient class�s methods:
As with DLL wizards, to install a VCS you have to define a specific entry-point function in the DLL. Within this function you need to return a pointer to the newly created TIVCSClient object. This time, however, there is no need to call a registration function (since you can have only one VCS at a time). Here is the declaration of the entry-point function: TVCSManagerInitProc = function ( VCSInterface: TIToolServices): TIVCSClient stdcall; When Delphi calls this function, it passes the global ToolServices object as the only parameter. Project Information in a VCSWe can now start building our own VCS. Actually, we�ll start using the VCS interface to build a tool that is not a true VCS. The code will be quite simple, but we�ll still be able to create a program that does something meaningful. In this last chapter, we built a project information wizard. The main form of our simple VCS tool is the same, and it displays the same information. However, here the form is modeless, so it can remain open while we work on the project. The VCS will receive notification for any change to the project, so we�ll be able to update the window appropriately. Here is the initial part of the DLL�s source code. In the uses statement, you�ll notice that we refer to the VcsIntf unit. However this unit isn�t normally part of the VCL or standard libraries (and therefore isn�t in the normal path), so you should add its path (�C:\Program Files\Borland\Delphi 3\Source\ToolsAPI� in the default installation) to the Search Path in the Project Options dialog box.
library VcsPrj; uses Sharemem, SysUtils, Classes, ExptIntf, Forms, ToolIntf, Dialogs, Windows, VcsIntf, VirtIntf, PrjForm in 'PrjForm.pas' {PrjInfoForm}; type TDdhProjectVcs = class (TIVCSClient) public function GetIDString: string; override; procedure ExecuteVerb(Index: Integer); override; function GetMenuName: string; override; function GetVerb(Index: Integer): string; override; function GetVerbCount: Integer; override; function GetVerbState(Index: Integer): Word; override; procedure ProjectChange; override; destructor Destroy; override; end; Next comes the source code of the various methods. Most of these methods are quite simple, and require no further explanation. The only moderately complex code is in the GetVerbState and ExecuteVerb methods. GetVerbState will enable the VCS menu items only if a project is active (except for the About menu item, which is always enabled ). The ExecuteVerb method updates and displays the VCS form, which contains the project information. function TDdhProjectVcs.GetIDString: string; begin Result := 'DDHandbook.DDHProjectVCS'; end; function TDdhProjectVcs.GetMenuName: string; begin Result := 'DHH Project VCS'; end; function TDdhProjectVcs.GetVerbCount: Integer; begin Result := 3; end; function TDdhProjectVcs.GetVerb(Index: Integer): string; begin case Index of 0: Result := '&Project Information...'; 1: Result := ''; // separator 2: Result := '&About DDH Project VCS...'; end; end; function TDdhProjectVcs.GetVerbState(Index: Integer): Word; begin // disable all but the last if no project is active if (ToolServices.GetProjectName <> '') or (Index = GetVerbCount - 1) then Result := vsEnabled else Result := 0; end; procedure TDdhProjectVcs.ExecuteVerb(Index: Integer); begin case Index of 0: try PrjInfoForm.UpdateTree; PrjInfoForm.Show; except ToolServices.RaiseException(ReleaseException); end; 21: MessageDlg ('DDH Project Version Control System'#13#13 + 'From the "Delphi Developer''s Handbook"'#13 + 'by Marco Cantù and Tim Gooch', mtInformation, [mbOK], 0); end; end; procedure TDdhProjectVcs.ProjectChange; begin PrjInfoForm.UpdateTree; {Application.MessageBox (PChar( 'The project ' + ToolServices.GetProjectName + ' is changing'), 'DDH Project VCS', mb_OK);} end; The last method of the class, ProjectChange, simply calls the form�s UpdateTree method to update the output of the project information form. To help you see when Delphi is callings this method, we also display a message box (we�ve disabled this code in the disk version). Unfortunately, this forces the user to close this message box fairly often (since the event occurs frequently). Studying the code above, you might wonder when Delphi creates the project information form, and when it destroys the form. We could have used a constructor and a destructor of the VCS class to illustrate this, but since we already have a VCS initialization function, we have used it to perform the form�s creation. However, we�ve created also a destructor to perform the form�s destruction. Here is the code of the destructor and of the initialization function: destructor TDDHDemoVCS.Destroy; begin PrjInfoForm.Free; end; function VCSInit (VCSInterface: TIToolServices): TIVCSClient; stdcall; begin ToolServices := VCSInterface; Application.Handle := ToolServices.GetParentHandle; PrjInfoForm := TPrjInfoForm.Create (Application); Result := TDdhProjectVcs.Create; end; exports VCSInit name VCSManagerEntryPoint; By the way, you�ll notice that before returning the new VCS client object, the VCSInit function stores the ToolServices object and the handle of the Application object in the proper global variables, and then creates the output form.
Now we�re ready to install our new VCS into Delphi. To do so, simply launch RegEdit in Windows 95 or RegEdt32 in Windows NT, locate the Delphi 3.0 section, and edit or add the Version Control key, as specified earlier and shown in Figure 15.3. Then, exit from Delphi (if it is open) and load it again to see the effect of the changes. You�ll see a new menu that contains a few items, as shown in Figure 15.4. Figure 15.3: The information added to the Windows Registry to activate the new VCS DLL in the Delphi environment.Figure 15.4: The new pull-down menu added by the VcsPrj DLL to Delphi�s own main menu.If you want to test your VCS and modify it, we strongly suggest you copy and rename the DLL first (using a name such as VcsPrj1.DLL), and then reinstall the DLL under this new filename. Using this approach, you�ll be able to compile the DLL. Windows won�t let the Delphi compiler overwrite a DLL that�s currently in use by Delphi itself! Using the same filename, you cannot simply update the VCS DLL without uninstalling and reinstalling it. (This is the same problem we have with DLL-based wizards.) In contrast, by using a different filename, you can edit and recompile the DLL, exit from Delphi, delete the older DLL, rename the newly compiled one, and finally launch Delphi again.
|
||
© Copyright Marco Cantù, 1995-2020, All rights reserved |