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 AllowInstallation3() returns False, the Setup will terminate right away. // So it is the responsibility of AllowInstallation3 to inform the user of what is wrong (by means of a message box). // If it returns True, it should keep quiet. function AllowInstallation3(DeployWindow: HWND; Portable, CurrentUser: BOOL): 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; if Portable then IdentityKey := 0 else if CurrentUser then IdentityKey := HKEY_CURRENT_USER else IdentityKey := HKEY_LOCAL_MACHINE end; (************************************************************ *** *** *** FILE SELECTION SUPPORT *** *** *** ************************************************************) // This routine, if present in the DLL, is called after AllowInstallation3() (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 Installation // 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 if IdentityKey <> 0 then 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; 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 AllowInstallation3, { 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.