A C version of this DLL is also available.
{***************************************************************}
{ }
{ DeployMaster Sample Support DLL }
{ }
{***************************************************************}
library Support;
uses
Windows,
SysUtils;
{$R *.RES}
// These variables are needed by the sample routines, but are invisible to DeployMaster Setup
var
IdentityKey: HKey;
DelphiInstalled: array[2..5] of Boolean;
(************************************************************
*** ***
*** INSTALLATION STARTUP ***
*** ***
************************************************************)
// This routine, if present in the DLL, is the first one that is called by Setup
// It will be called after the user has clicked one of the buttons to start the install,
// and after the installer has been elevated to administrator privileges,
// but before anything has actually been installation.
// It gives you the chance to abort the installation early on if something is wrong with the user's system
// If AllowInstallation() returns False, the Setup will terminate right away.
// So it is the responsibility of AllowInstallation to inform the user of what is wrong (by means of a message box).
// If it returns True, it should keep quiet.
function AllowInstallation(DeployWindow: HWND): BOOL; stdcall;
begin
// Check if Borland Delphi is running and warn user that we don't like this.
// Give the user the chance to close it without having to stop and restart the setup application
Result := True;
while Result and (FindWindow('TAppBuilder', nil) <> 0) do
Result := MessageBox(DeployWindow, 'DeployMaster has detected that Delphi is still running.'#13 +
'Please close it (and any other open applications) and then click OK'#13 +
'To cancel the setup, click Cancel',
'DeployMaster', MB_ICONHAND or MB_OKCANCEL) = IDOK;
end;
(************************************************************
*** ***
*** FILE SELECTION SUPPORT ***
*** ***
************************************************************)
// This routine, if present in the DLL, is called after AllowInstallation() (if present) has returned True
// It should fill the Folders character array (which is pre-allocated by Setup),
// with any additional system folders that Setup may need
// System folders are folders that cannot be changed by the user.
// BufferSize is the number of bytes that have been allocated for Folders and is $8000 by default
// These are generally folders into which other software has already been installed,
// which your software will cooperate with.
// The format is %TAGNAME1%Fullpath1%TAGNAME2%Fullpath2 ...
// Fullpath must not contain any tags and may be preceded by an * to mark the folder as a shared one
// Files placed in shared folders have their reference counts updated in
// HKEY_LOCAL_MACHINE\Software\Microsoft\Windows\CurrentVersion\SharedDLLs
// Fullpath must not contain a trailing backslash
procedure GetSystemFolders(Folders: PChar; BufferSize: Integer); stdcall;
var
I: Integer;
DelphiKey: HKey;
ZStr: array[0..MAX_PATH] of Char;
BufType, BufSize: Integer;
begin
// Try to find the folders into which Delphi 2 through 5 have been installed
for I := 2 to 5 do begin
if RegOpenKeyEx(HKEY_LOCAL_MACHINE, PChar('Software\Borland\Delphi\' + IntToStr(I) + '.0'),
0, KEY_READ, DelphiKey) = 0 then begin
BufSize := SizeOf(ZStr);
StrCat(Folders, PChar('%DELPHI' + IntToStr(I) + '%'));
if RegQueryValueEx(DelphiKey, 'RootDir', nil, @BufType, @ZStr, @BufSize) = 0 then
StrCat(Folders, ZStr)
else
StrCat(Folders, PChar('C:\Program Files\Borland\Delphi' + IntToStr(I)));
DelphiInstalled[I] := True;
end
else DelphiInstalled[I] := False;
end;
end;
// This routine, if present in the DLL, is called after GetSystemFolders() is called
// It is called whether GetSystemFolders() is present or not
// It should fill the Folders character array (which is pre-allocated by Setup),
// with any additional installation folders that Setup may need.
// BufferSize is the number of bytes that have been allocated for Folders and is $8000 by default.
// These folders can be completely changed by the user by clicking on the Advanced Options
// button in Setup.
// The format is %TAGNAME1%|Description1|Fullpath1|%TAGNAME2%|Description2|Fullpath2| ...
// Fullpath may start with a tag defined in GetSystemFolders, or one of the following tags:
// %PROGRAMFILES%, %COMMONFILES%, %STARTMENU%, %PROGRAMSMENU%, %DESKTOP%, %SENDTO%, %STARTUP%, %WINDOWS%, %SYSTEM%
// Fullpath may be preceded with an * to mark the folder as a shared one.
// Files placed in shared folders have their reference counts updated in
// HKEY_LOCAL_MACHINE\Software\Microsoft\Windows\CurrentVersion\SharedDLLs
// Fullpath must not contain a trailing backslash
// If Folders is not empty, then the last character in the Folders string must be a | (pipe symbol)
procedure GetInstallFolders(Folders: PChar; BufferSize: Integer); stdcall;
var
I: Integer;
begin
for I := 2 to 5 do
if DelphiInstalled[I] then
// eg: '%D5VCL%|Delphi 5 binaries|%DELPHI5%\Lib|'
StrCat(Folders, PChar('%D' + IntToStr(I) + 'VCL%|Delphi ' + IntToStr(I) + ' binaries|%DELPHI' + IntToStr(I) + '%\Lib|'))
end;
// If present in the support DLL, GetComponentSelection() is called for each component in the setup package.
// These calls happen after the calls to GetSystemFolders() and GetInstallFolders()
// The first parameter points to the name of the component, and must not be modified by the routine
// Selectable determines whether the user can select whether this component will be installed or not
// Selected determines whether the component is selected by default or not
// If the user is freshly installing your software package, Selectable and Selected default to the settings you made
// in DeployMaster Builder when building the setup package, and IsInstalled is False
// If the user is updating this package, Selected equals to IsInstalled if the installation status could be determined,
// which indicates whether the component is currently installed or not. If the installation status could not be determined,
// IsInstalled is False and Selected is set to the setting you made in DeployMaster Builder
// The routine should set Selectable and Selected to meaningful values, depending on the configuration of the user's system
procedure GetComponentSelection(ComponentName: PChar; var Selectable, Selected: Bool; IsInstalled: Bool); stdcall;
begin
// Don't install files for a certain Delphi version, if that Delphi version is not installed.
// Setting Selectable to False as well, prevents the user from overriding our decision.
if StrIComp(ComponentName, 'Delphi2') = 0 then begin
Selected := DelphiInstalled[2]; Selectable := Selected;
end
else if StrIComp(ComponentName, 'Delphi3') = 0 then begin
Selected := DelphiInstalled[3]; Selectable := Selected;
end
else if StrIComp(ComponentName, 'Delphi4') = 0 then begin
Selected := DelphiInstalled[4]; Selectable := Selected;
end
else if StrIComp(ComponentName, 'Delphi5') = 0 then begin
Selected := DelphiInstalled[5]; Selectable := Selected;
end;
end;
(************************************************************
*** ***
*** IDENTITY SUPPORT ***
*** ***
************************************************************)
// This routine is called right before the identity screen is shown to the user.
// It is called before any of the other identity functions.
// It allows it to figure out where the processed information should be stored in the Windows registry.
// CompanyName and AppVersion may be nil, AppName will always have a value.
// The strings must not be modified by the DLL, and their length is arbitrary.
procedure InitIdentity(CompanyName, AppName, AppVersion: PChar); stdcall;
var
ZStr: array[0..255] of Char;
begin
ZStr := 'Software';
if CompanyName <> nil then begin
StrCat(ZStr, '\');
StrCat(ZStr, CompanyName);
end;
StrCat(ZStr, '\');
StrCat(ZStr, AppName);
if RegCreateKeyEx(HKEY_CURRENT_USER, ZStr, 0, nil, REG_OPTION_NON_VOLATILE, KEY_ALL_ACCESS, nil, IdentityKey, nil) <> 0 then
IdentityKey := 0;
end;
// ValidIdentity() is called when the user clicks on the Proceed button.
// Should return True if the information is valid and the user may proceed. If it returns False, the user will have to retry.
// The parameters for items the user is not requested to specify will be nil
// ValidIdentity() is allowed to modify the contents of the strings; e.g. to clear out an invalid registration code
function ValidIdentity(Name, Company, Serial, RegCode: PChar): Bool; stdcall;
begin
Result := True;
end;
// LoadIdentity() is called right before the user is allow to supply his information
// If (another version of) the application is already installed, it should set the strings to the previously entered data
// If not, the DLL has a chance to provide default data (e.g. a time-limited trial mode registration IdentityKey)
// The parameters for items the user is not requested to specify will be nil
procedure LoadIdentity(Name, Company, Serial, RegCode: PChar); stdcall;
var
BufType, BufSize: Integer;
begin
if IdentityKey <> 0 then begin
BufSize := 128;
if Name <> nil then RegQueryValueEx(IdentityKey, 'Name', nil, @BufType, PByte(Name), @BufSize);
BufSize := 128;
if Company <> nil then RegQueryValueEx(IdentityKey, 'Company', nil, @BufType, PByte(Company), @BufSize);
BufSize := 128;
if Serial <> nil then RegQueryValueEx(IdentityKey, 'Serial', nil, @BufType, PByte(Serial), @BufSize);
BufSize := 128;
if RegCode <> nil then RegQueryValueEx(IdentityKey, 'RegCode', nil, @BufType, PByte(RegCode), @BufSize);
end;
end;
// SaveIdentity() is called after the user clicked the proceed button and ValidIdentity() returned true.
// It should write the data to the Windows registry, so that the application, once installed, can use it.
// The parameters for items the user is not requested to specify will be nil
procedure SaveIdentity(Name, Company, Serial, RegCode: PChar); stdcall;
begin
if IdentityKey <> 0 then begin
// Save data
if Name <> nil then RegSetValueEx(IdentityKey, 'Name', 0, REG_SZ, Name, StrLen(Name)+1);
if Company <> nil then RegSetValueEx(IdentityKey, 'Company', 0, REG_SZ, Company, StrLen(Company)+1);
if Serial <> nil then RegSetValueEx(IdentityKey, 'Serial', 0, REG_SZ, Serial, StrLen(Serial)+1);
if RegCode <> nil then RegSetValueEx(IdentityKey, 'RegCode', 0, REG_SZ, RegCode, StrLen(RegCode)+1);
// Clean up
RegCloseKey(IdentityKey);
end;
end;
(************************************************************
*** ***
*** FINISHING TOUCHES ***
*** ***
************************************************************)
// FinishDeployment() is called after DeployMaster has finished its job.
// Log will contain the filename of the deployment log that DeployMaster has written to disk
// The most important task of FinishDeployment() is to update any configuration files the application uses,
// so it can find its own files in the case it does not use the deployment log itself for this purpose
// In case of a portable installation, there will be no log. In that case,
// the Log parameter will be the path to the RemovableDrive.sys file in the installation folder
// on the removable device (even if you disabled the option to create that file).
procedure FinishDeployment(Log: PChar); stdcall;
begin
end;
exports
// Make our support routines visible to the world
// If we're using Unicode, we need to add W to the names of the exported functions
AllowInstallation, { no Unicode version }
GetSystemFolders {$IFDEF UNICODE}name 'GetSystemFoldersW'{$ENDIF},
GetInstallFolders {$IFDEF UNICODE}name 'GetInstallFoldersW'{$ENDIF},
GetComponentSelection {$IFDEF UNICODE}name 'GetComponentSelectionW'{$ENDIF},
InitIdentity {$IFDEF UNICODE}name 'InitIdentityW'{$ENDIF},
ValidIdentity {$IFDEF UNICODE}name 'ValidIdentityW'{$ENDIF},
LoadIdentity {$IFDEF UNICODE}name 'LoadIdentityW'{$ENDIF},
SaveIdentity {$IFDEF UNICODE}name 'SaveIdentityW'{$ENDIF},
FinishDeployment {$IFDEF UNICODE}name 'FinishDeploymentW'{$ENDIF};
end.