Sample Support DLL (C)

A Pascal version of this DLL is also available.

This code assumes that UNICODE is not defined when compiling your DLL. If it is defined, append a W to all function names except AllowInstallation3.

/*************************************************************
*                                                            *
*        DeployMaster Sample Support DLL                     *
*                                                            *
*************************************************************/

#include <stdio.h>
#include <windows.h>

HKEY IdentityKey;
BOOL DelphiInstalled[6];


/************************************************************
 ***                                                      ***
 ***                 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.
BOOL __export __stdcall AllowInstallation3(HWND DeployWindow, BOOL Portable, BOOL CurrentUser)
{
  // 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
  bool Result = True;
  while (Result && FindWindow('TAppBuilder', nil) != 0) {
    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);
  }
  return Result;
}


/************************************************************
 ***                                                      ***
 ***                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 0x8000 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
void __export __stdcall GetSystemFolders(LPTSTR Folders, int BufferSize)
{
  HKEY DelphiKey;
  TCHAR ZStr[256];
  DWORD BufType, BufSize;
  int i;
  // Try to find the folders into which Delphi 2 through 5 have been installed
  for (i = 2; i <= 5; i++) {
    sprintf(ZStr, "Software\\Borland\\Delphi\\%d.0", i);
    if (RegOpenKeyEx(HKEY_LOCAL_MACHINE, ZStr, 0, KEY_READ, &DelphiKey) == 0) {
      sprintf(ZStr, "%%DELPHI%d%%", i);
      strcat(Folders, ZStr);
      BufSize = 256;
      if (RegQueryValueEx(DelphiKey, "RootDir", NULL, &BufType, (LPBYTE)ZStr, &BufSize) != 0) {
        sprintf(ZStr, "C:TEST\\Program Files\\Borland\\Delphi%d", i);
      }
      strcat(Folders, ZStr);
      DelphiInstalled[i] = TRUE;
    } else {
      DelphiInstalled[i] = FALSE;
    }
  }
}

// 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)
void __export __stdcall GetInstallFolders(LPTSTR Folders, int BufferSize)
{
  int i;
  TCHAR ZStr[256];
  for (i = 2; i <= 5; i++) {
    if (DelphiInstalled[i] == TRUE) {
      // eg: '%D5VCL%|Delphi 5 binaries|%DELPHI5%\Lib|'
      sprintf(ZStr, "%%D%dVCL%%|Delphi%d binaries|%%DELPHI%d%%\\Lib|", i, i, i);
      strcat(Folders, ZStr);
    }
  }
}

// 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
void __export __stdcall GetComponentSelection(LPCTSTR ComponentName, LPBOOL Selectable, LPBOOL Selected, BOOL IsInstalled)
{
  // 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 (stricmp(ComponentName, "Delphi2") == 0) {
    *Selected = DelphiInstalled[2]; *Selectable = *Selected;
  }
  else if (stricmp(ComponentName, "Delphi3") == 0) {
    *Selected = DelphiInstalled[3]; *Selectable = *Selected;
  }
  else if (stricmp(ComponentName, "Delphi4") == 0) {
    *Selected = DelphiInstalled[4]; *Selectable = *Selected;
  }
  else if (stricmp(ComponentName, "Delphi5") == 0) {
    *Selected = DelphiInstalled[5]; *Selectable = *Selected;
  }
}


/************************************************************
 ***                                                      ***
 ***                  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 NULL, AppName will always have a value.
// The strings must not be modified by the DLL, and their length is arbitrary.
void __export __stdcall InitIdentity(LPCTSTR CompanyName, LPCTSTR AppName, LPCTSTR AppVersion)
{
  TCHAR ZStr[256];
  strcpy(ZStr, "Software");
  if (CompanyName != NULL) {
    strcat(ZStr, "\\");
    strcat(ZStr, CompanyName);
  }
  strcat(ZStr, "\\");
  strcat(ZStr, AppName);
  if (RegCreateKeyEx(HKEY_CURRENT_USER, &ZStr, 0, NULL, REG_OPTION_NON_VOLATILE, KEY_ALL_ACCESS, NULL, &IdentityKey, NULL) != 0)
    IdentityKey = 0;
}

// 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 NULL
// ValidIdentity() is allowed to modify the contents of the strings; e.g. to clear out an invalid registration code
BOOL __export __stdcall ValidIdentity(LPTSTR Name, LPTSTR Company, LPTSTR Serial, LPTSTR RegCode)
{
  return TRUE;
}

// 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 NULL
void __export __stdcall LoadIdentity(LPTSTR Name, LPTSTR Company, LPTSTR Serial, LPTSTR RegCode)
{
  DWORD BufType, BufSize;
  if (IdentityKey != 0) {
    BufSize = 128;
    if (Name != NULL) RegQueryValueEx(IdentityKey, "Name", NULL, &BufType, (LPBYTE)Name, &BufSize);
    BufSize = 128;
    if (Company != NULL) RegQueryValueEx(IdentityKey, "Company", NULL, &BufType, (LPBYTE)Company, &BufSize);
    BufSize = 128;
    if (Serial != NULL) RegQueryValueEx(IdentityKey, "Serial", NULL, &BufType, (LPBYTE)Serial, &BufSize);
    BufSize = 128;
    if (RegCode != NULL) RegQueryValueEx(IdentityKey, "RegCode", NULL, &BufType, (LPBYTE)RegCode, &BufSize);
  }
}

// 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 NULL
void __export __stdcall SaveIdentity(LPCTSTR Name, LPCTSTR Company, LPCTSTR Serial, LPCTSTR RegCode)
{
  if (IdentityKey != 0) {
    // Save data
    if (Name != NULL) RegSetValueEx(IdentityKey, "Name", 0, REG_SZ, (CONST BYTE*)Name, strlen(Name)+1);
    if (Company != NULL) RegSetValueEx(IdentityKey, "Company", 0, REG_SZ, (CONST BYTE*)Company, strlen(Company)+1);
    if (Serial != NULL) RegSetValueEx(IdentityKey, "Serial", 0, REG_SZ, (CONST BYTE*)Serial, strlen(Serial)+1);
    if (RegCode != NULL) RegSetValueEx(IdentityKey, "RegCode", 0, REG_SZ, (CONST BYTE*)RegCode, strlen(RegCode)+1);
    // Clean up
    RegCloseKey(IdentityKey);
  }
}


/************************************************************
 ***                                                      ***
 ***                  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).
void __export __stdcall FinishDeployment(LPCTSTR Log)
{
}