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) { }