Previous     Contents     Index     Next     
Setup Util Programmer's Guide



Appendix B   Sample Pre- and Post-Installation Programs


This appendix contains sample code for pre- and post-installation programs. It is divided into the following sections:



Sample UNIX Code

On UNIX, you must write and compile pre- and post-installation programs separately. You then specify the standalone executables in your package information files. For more information on using directives to specify UNIX pre- and post-installation programs, see Chapter 3 "Information Files."

Code Example B-1 and Code Example B-2 show parts of the Example Administrator pre- and post-installation programs for UNIX. Code Example B-3 and Code Example B-4 list the master and package information files for the software.

Code Example B-1 Sections of the Example Administrator pre-installation program.

/////////////////////////////////////////////////////////////////////////////
//
// ndapre.cc - Administration Installation (pre-installation program)
//

#include "stdio.h"

#include "string.h"
#if defined(AIX)
#include <strings.h>
#endif
#include "nsdefs.h"
#include "ldapu.h"
#include "setupldap.h"
#include "dialog.h"
#include "utf8.h"

// Global variables

InstallInfo *installInfo = NULL;
InstallLog *installLog = NULL;
Bool reConfig = False;
int installMode;
char *_infoFile = NULL;

// This procedure is use for writing NVPair to the
// installation cache which is used by other procedures
// in this program and also the post-installation program

void writeToInfo(const char *name, const char *value)
{
   NVPair *section;
   if (installInfo) {
      if ((section = installInfo->getSection("nda")) == NULL)
           section = installInfo->createSection("nda");
           section->set(name, value);
   }
}

// This procedure is use for reading NVPair from the
// installation cache

const char *getFromInfo(const char *name)
{
   NVPair *section;
   if (section = installInfo->getSection("nda")) {
      return section->get(name);
   }
   return NULL;
}

// LDAP Url dialog -- ask for directory server host name and port number
//
// This procedure is used for initialization of
// the curses dialog, such as setting the default
// answers for this dialog

DialogAction
askLdapDialogSetup(Dialog *me)
{
   NSString ldapURL;
   ldapURL = getFromInfo("ldapUrl");
   if (ldapURL != (char *)NULL) {
      me->setDefaultAns(ldapURL);
   }
   me->enable8BitInput();
   return DIALOG_SAME;
}
// This procedure is called when the user hit the "Return" key.
// Here you should verify the user input and pop up error messages
// if necessary.

DialogAction
askLdapDialogNext(Dialog *me)
{
   const char *buf = me->input();
   const char *ldapURL;
   char *ldapUrl = NULL;
   char *host = NULL;
   char *suffix = NULL;
   unsigned nPort;
   if (buf[0] == 0) {
      ldapURL = me->defaultAns();
   } else {
      ldapURL = buf;
   }
   if (ldapURL == NULL)
       return DIALOG_SAME;
   ldapUrl = setupStripConfigLdapURL(ldapURL);
   if(!setupParseLdapUrl(ldapUrl, &host, &nPort, &suffix)){
      DialogAlert *alert;
      alert = new DialogAlert("LDAP authentication failed. Possible cause:
                               invalid LDAP URL!");
      alert->execute();
      delete alert;
      }
   if (!setupIsValidLdapServer(host, nPort, NULL, NULL, NULL)||(nPort == 0)) {
      DialogAlert *alert;
      alert = new DialogAlert("LDAP authentication failed. Possible cause:
                               invalid LDAP URL!");
      alert->execute();
      delete alert;
      return DIALOG_SAME;
      }
   writeToInfo("ldapUrl", UTF8ToLocal(ldapUrl));
   return DIALOG_NEXT;
}

// This is the curses dialog that the user will see on the screen.

DialogInput
askLdapDialog
   ("Example Administrator uses an LDAP-based Directory\n"
   "Server for the administration of server configuration. This server is\n"
   "called the Configuration Directory. Enter the non-SSL URL for the\n"
   "directory server:\n\n"
   "       ldap://<host>:<port>\n",
   "Specify LDAP URL",
   NULL,
   askLdapDialogSetup,
   askLdapDialogNext);

// Ldap User and Password dialog
//
// This procedure is used for initialization of
// the curses dialog, such as setting the default
// answers for this dialog

DialogAction
askLdapUserAndPasswordSetup(Dialog *me)
{
   return DIALOG_SAME;
}

// This procedure is called when the user presses Return.
// Here you should verify the user input and pop up error messages
// if necessary.

DialogAction
askLdapUserAndPasswordNext(Dialog *me)
{
   const char *buf = me->input();
   NSString ldapUser;
   char *ldapPwd = NULL;
   const char *buf2;
   NSString ldapUrl;
   NSString host;
   NSString port;
   Ldap *ldap;
   LdapError ldapError;
   int err;
   LdapEntry *ldapEntry;
   if (buf[0] == 0) {
      ldapUser = me->defaultAns();
   } else {
      ldapUser = buf;
   }
   while (1) {
      me->showString("Password: ");
      if (me->getPassword () == 0) {
         return DIALOG_PREV;
      }
      else
      {
         ldapPwd = strdup(me->input());
         if (ldapPwd[0] == 0)
         {
            free(ldapPwd);
            continue;
         }
         else
         {
            writeToInfo("ldapPwd", ldapPwd);
            break;
         }
      }
   }
free(ldapPwd);
ldap = new Ldap (ldapError, getFromInfo("ldapUrl"), getFromInfo("ldapUser"),
                 getFromInfo("ldapPwd"), NULL, NULL);
if (ldapError != OKAY) {
   DialogAlert *alert;
   alert = new DialogAlert("Ldap authentication fail. Possible cause: wrong
   password.\nRetype username and password. \n");
   alert->execute();
   delete alert;
   return DIALOG_SAME;
   }
return DIALOG_NEXT;
}

// This is the curses dialog that the user will see on the screen.

DialogInput askLdapUserAndPasswordDialog
("In order to create the suffix for Example Administrator,\n"
"enter the base DN and password of the user who can access the \n"
"Directory Server.\n",
"Specify Directory Manager",
"cn=Directory Manager",
askLdapUserAndPasswordSetup,
askLdapUserAndPasswordNext);
#define NUM_PREINSTALL_DIALOGS 2

// This procedure control the dialog chain, such as which
// dialog to show up at which order. It also handles the Ctrl-B and
// Ctrl-C and the "Return" key.
//

void solPreInstall_run(void)
{
   int i = 0;
   DialogAction rc;
   DialogInput* dialogChain[] = { &askLdapDialog,
                                  &askLdapUserAndPasswordDialog
   };
   while (i < NUM_PREINSTALL_DIALOGS) {
      rc = dialogChain[i]->execute();
      if (rc == DIALOG_PREV) {
         i --;
         if ((i > 0) && dialogChain[i]->isHidden())
            i --;
      } else if (rc == DIALOG_NEXT) {
         i ++;
      } else if (dialogChain[i]->isHidden()) {
         i ++;
      }
      if (i < 0)
          i = 0;
   }
}

int
main(int argc, char **argv)
{
   const char *sroot;
   int opt;
   while ((opt = getopt(argc, argv, "m:sl:f:r")) != -1) {
      switch (opt) {
         case 'r':
            reConfig = True;
            break;
         case 's':
            installMode = Silent;
            break;
         case 'l':
            _logFile = strdup(optarg); /* Log file to use */
            installLog = new InstallLog(_logFile);
            break;
         case 'f':
            _infoFile = strdup(optarg); /* Install script */
            installInfo = new InstallInfo(_infoFile);
            break;
            default:
            break;
     }
   }

   if (installMode != Silent) {
      DialogManager::enableWinMode();
      Dialog::initDisplay("Example Administrator");
      solPreInstall_run();
      installInfo->setFormat(1);
      installInfo->write();
   }

   return 0;
}

Code Example B-2 Sections of the Example Administrator post-installation program.

//////////////////////////////////////////////////////////////////////
//
// ndapost.cc - Administration (post-installation program)
//

#include <stdio.h>

#include <string.h>
#if defined(AIX)
#include <strings.h>
#endif
#include <unistd.h>
#include "nsdefs.h"
#include "ldapu.h"
#include "setupapi.h"
#include "setupldap.h"
#include "dialog.h"
#include "utf8.h"
#include "uninstall.h"

// Global variables

InstallInfo *installInfo = NULL;
int installMode;
char *logFile = NULL;
char *_infoFile = NULL;

// This procedure imports the schema file into the directory server
//

void ImportSchemaFiles()
{
   const char *ldapURL;
   const char *userid;
   const char *userpwd;
   NSString serverRoot;
   NSString schemaFile;
   int imsSupport = 0;
   int err;
   ldapURL = localToUTF8(getFromInfo("ldapUrl"));
   userid = getFromInfo("ldapUser");
   userpwd = getFromInfo("ldapPwd");
   serverRoot = installInfo->get("ServerRoot");
   schemaFile = serverRoot + "/nda/ldif/schema.conf";

// setupInsertPluginSchemEntries is a Setup Util API
   err = setupInsertPluginSchemaEntries (ldapURL, userid, userpwd,
                                         schemaFile);
   if (err != OKAY) {
   printf("Error: fail to update schema entries in directory server\n");
   }
}
int
main(int argc, char **argv)
{
   const char *sroot;
   int opt;
   while ((opt = getopt(argc, argv, "m:sl:f:r")) != -1) {
      switch (opt) {
         case 'r':
            reConfig = True;
            break;
         case 's':
            installMode = Silent;
            break;
         case 'l':
            logFile = strdup(optarg); /* Log file to use */
            break;
         case 'f':
            _infoFile = strdup(optarg); /* Install script */
            installInfo = new InstallInfo(_infoFile);
            break;
         default:
            break;
         }
      }

   ImportFiles();

   // launch browser and connect to nda home
   launchBrowser();
   return 0;
}

Code Example B-3 The Example Administrator master information file for UNIX.

# sample Server Master Information File
#
# Components: lists the components to be installed as specified
# in subsequent sections. If the section or the ComponentInfoFile
# does note exist the setup program will ignore the component

[General]
Name = Example Administrator
Vendor = Example, Inc.
Description = Installation for Example Administrator
Version = 4.5
Components = svrcore~ nda
Mode = typical
DefaultInstallDirectory = /opt/serverrootname/nda45

[svrcore]
ComponentInfoFile = svrcore/svrcore.inf

[nda]
ComponentInfoFile = nda/nda.inf

Code Example B-4 The Example Administrator package information file for UNIX.

[General]
name=Example Administrator
components=nda

[nda]
name=Example Administrator
nickname=nda
version=4.5
archive=nda.zip
sourcepath=nda
checked=True
visible=True
ismcc=True
PreInstall=solpreinst
PostInstall=nda/solpostinst
PreUninstall=



Sample Windows NT Code



On Windows NT, pre- and post-installation programs are part of a single DLL. After preparing your resource files and compiling this library, you must specify specific functions in your package information files. For more information on using directives to specify these functions, see Chapter 3 "Information Files."

Code Example B-5 and Code Example B-6 show parts of the Example Administrator pre- and post-installation programs for Windows NT. Code Example B-7 and Code Example B-8 list the master and package information files for the software.

Code Example B-5 The Example Administrator pre- and post-installation DLL.

/////////////////////////////////////////////////////////////////////////////
// insnda.c - Administration Installation Plug-In Template
//

// All Rights Reserved.
//

#include <windows.h>
#include <nssetup.h>
#include <ldap.h>
#include <ldapu.h>
#include <global.h>
#include <setupldap.h>
#include <stdio.h>
#include "insnda.h"

/////////////////////////////////////////////////////////////////////////////
//
// The procedure is called right after the dll is loaded into memory during
// installation and uninstallation. You should
// initialize your control data here with default values.
//

static void _InitializeControlData(void)
{
   ZeroMemory(&cd, sizeof(CONTROLDATA));
   cd.szConfigDSHost = "localhost";
   cd.nConfigDSPort = 389;
   cd.szLdapUser= setupStrdup("cn=Directory Manager");
   cd.szLdapPWD= NULL;
}

///////////////////////////////////////////////////////////////////////////// /
// _DialogProc
//
// The procedure is for the property page that ask for configuration directory
// information, such as configuration host name and port number. This
// "refresh" procedure will get called during the property page
// initialization. You will need to create one of these for each property page
// used in the property sheet.

static void _RefreshConfigDSInfo(HWND hwndDlg)
{
   BOOL bResult = FALSE;
   if(!IsWindow(hwndDlg))
   {
      setupLogMessage("Error", "nda", "Calling RefreshConfigDSInfo with bad
     handle");
     return;
   }
   if(cd.szConfigDSHost)
   {
      bResult = SetDlgItemText(hwndDlg,
      IDC_LDAP_NAME,
      cd.szConfigDSHost);
      if(FALSE == bResult)
      {
         setupLogMessage("Error", "nda", "unable to set ldap server name");
      }
   }
   if(cd.nConfigDSPort)
   {
      bResult = SetDlgItemInt(hwndDlg,
      IDC_LDAP_PORT,
      cd.nConfigDSPort, TRUE);
      if(FALSE == bResult)
      {
         setupLogMessage("Error", "nda", "unable to set ldap port");
      }
   }
}

/////////////////////////////////////////////////////////////////////////////
// _DialogProc
//
// The procedure is for the property page that ask for configuration directory
// information, such as configuration host name and port number. This "save"
// procedure will get called whenever the user hits the "Next" button,
// saving all the datathat the user have entered. You will need
// to create one of these for each property page used in the property sheet.
//

static void _SaveConfigDSInfo(HWND hwndDlg)
{
   if(IsWindow(hwndDlg))
   {
      BOOL bSuccess = FALSE;
      int nPort = 0;
      char szTemp[MAX_PATH];
      char szLdapUrl[MAX_PATH];
      GetDlgItemText(hwndDlg, IDC_LDAP_NAME, szTemp, MAX_PATH);
      if(cd.szConfigDSHost)
         setupFree(cd.szConfigDSHost);
      cd.szConfigDSHost = setupStrdup(szTemp);
      SetDlgItemText(hwndDlg,IDC_LDAP_NAME, cd.szConfigDSHost);
      nPort = GetDlgItemInt(hwndDlg, IDC_LDAP_PORT, &bSuccess, FALSE);
      if(bSuccess)
      {
         cd.nConfigDSPort = nPort;
      }
      SetDlgItemInt(hwndDlg, IDC_LDAP_PORT, cd.nConfigDSPort, TRUE);
      wsprintf(szLdapUrl, "ldap://%s:%d/", cd.szConfigDSHost,
               cd.nConfigDSPort);
      cd.szLdapUrl = setupStrdup(szLdapUrl);
   }
}
/////////////////////////////////////////////////////////////////////////////
//
// The dialog procedure for a single property page. You will need to create
// one of these for each property page used in the property sheet. This
// procedure processes dialog messages sent to your property page by Windows.
//

static BOOL CALLBACK
_DialogProcConfigDSInfo(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
   BOOL bValueReturned = FALSE;
   BOOL bResult = TRUE;
   switch(uMsg)
   {
      case WM_INITDIALOG:
      {
         HGDIOBJ hGdiObj = GetStockObject(DEFAULT_GUI_FONT);
         HWND heditwnd;
         SendMessage(hwndDlg, WM_SETFONT, (WPARAM) ((struct HFONT__ *)hGdiObj)
                     , MAKELPARAM(TRUE, 0));
         heditwnd = GetDlgItem(hwndDlg, IDC_LDAP_NAME);
         SendMessage(heditwnd, WM_SETFONT, (WPARAM) ((struct HFONT__
                     *)hGdiObj) , MAKELPARAM(TRUE, 0));
         heditwnd = GetDlgItem(hwndDlg, IDC_LDAP_PORT);
         SendMessage(heditwnd, WM_SETFONT, (WPARAM) ((struct HFONT__
                     *)hGdiObj) , MAKELPARAM(TRUE, 0));
         cd.hwndPage[PG_FIFTH] = hwndDlg;
         _RefreshConfigDSInfo(hwndDlg);
      }
      break;

      case WM_COMMAND:
      // Windows sends WM_COMMAND messages whenever the user clicks on
      // a control in your property page. If you need to perform some
      // special action, such as validating data or responding to a
      // button click, do it here.

      break;

      case WM_NOTIFY:
      // Windows sends WM_NOTIFY messages to your property page whenever
      // something interesting happens to the page. This could be page
      // activation/deactivation, a button click, etc. The wParam parameter
      // contains a pointer to the property page. The lParam parameter
      // contains a pointer to an NMHDR structure. The code field of this
      // structure contains the notification message code being sent. The
      // property sheet API allows you to alter the behavior of these
      // messages by returning a value for each message. To return a value,
      // use the SetWindowLong Windows SDK function.

      switch(((NMHDR*)lParam)->code)
      {

         case PSN_SETACTIVE:
         {
            CenterWindow(GetParent(hwndDlg));
            PropSheet_SetWizButtons(GetParent(hwndDlg), PSWIZB_BACK |
                                    PSWIZB_NEXT);
            _RefreshConfigDSInfo(hwndDlg);
            break;

         }
         case PSN_KILLACTIVE:
         // This notification is sent upon deactivation of the property page.
         // Here you can do whatever might be necessary for this action, such
         // as saving the state of the controls. You should also reset the
         // the state of the wizard buttons here, as both the Back and Next
         // buttons should be active when you leave the AskOptions function.
         //
         // NOTE: If you do not want the page deactivated, return -1.

         PropSheet_SetWizButtons(GetParent(hwndDlg), PSWIZB_BACK |
                                 PSWIZB_NEXT);
         break;

         case PSN_WIZBACK:
         _SaveConfigDSInfo(hwndDlg);
         break;

         case PSN_WIZNEXT:
         {
            _SaveConfigDSInfo(hwndDlg);

            if(!IsValidLdapServer(cd.szConfigDSHost, cd.nConfigDSPort, NULL,
                                  NULL, NULL))
            {
               char szErrMsg[MAX_PATH];
               LoadString(mi.m_hModule, IDS_ERR_BAD_LDAPURL, szErrMsg,
               sizeof(szErrMsg));
               if(NsSetupMessageBox(GetParent(hwndDlg), szErrMsg, NULL,
               MB_ICONWARNING | MB_OK) == IDOK)
               {
                  SetFocus(GetDlgItem(hwndDlg, IDC_LDAPURL));
                  SetWindowLong(hwndDlg, DWL_MSGRESULT, -1);
                  bValueReturned = TRUE;
                  break;
               }
            }

            break;
         }
         case PSN_QUERYCANCEL:
         // This notification is sent when the user clicks the Cancel button.
         // It is also sent in response to the WM_CLOSE messages issued
         // by PSN_WIZBACK and PSN_WIZNEXT. Make sure that we only process
         // this message if the result is not back or next so that we don't
         // nuke the return value assigned by PSN_WIZBACK or PSN_WIZNEXT.
         //
         // NOTE: To prevent the cancel from occuring, return -1.

         if(mi.m_nResult != NS_WIZBACK && mi.m_nResult != NS_WIZNEXT)
         {
            if(QueryExit(hwndDlg))
            {
               mi.m_nResult = NS_WIZCANCEL;
            }
            else
            {
               SetWindowLong(hwndDlg, DWL_MSGRESULT, -1);
               bValueReturned = TRUE;
            }
         }
         break;
      }
      break;
   }

   return bValueReturned;
}

/////////////////////////////////////////////////////////////////////////////
//
// The procedure is for the property page that ask for configuration directory
// information, such as base dn (e.g cn=directory manager) and password. This
// "refresh" procedure will get called during the property page
// initialization. You will need to create one of these for each property page
// used in the property sheet.

static void _RefreshLdapUser(HWND hwndDlg)
{
   BOOL bResult = FALSE;
   if(!IsWindow(hwndDlg))
   {
      setupLogMessage("Error", "nda", "Calling RefreshLdapUser with bad
                      handle");
      return;
   }

   if(cd.szLdapUser)
   {
      bResult = SetDlgItemText(hwndDlg, IDC_USERID, cd.szLdapUser);

      if(FALSE == bResult)
      {
         setupLogMessage("Error", "nda", "unable to set ldap user");
      }
   }

   if(cd.szLdapPWD)
   {
      bResult = SetDlgItemText(hwndDlg, IDC_PASSWORD, cd.szLdapPWD);

      if(FALSE == bResult)
      {
         setupLogMessage("Error", "nda", "unable to set ldap password");
      }
   }
}

/////////////////////////////////////////////////////////////////////////////
//
// The procedure is for the property page that ask for configuration directory
// information, such as base dn (e.g cn=directory manager) and password. This
// "save" procedure will get called whenever the user hits the "Next" button,
// saving all the data that the user have entered. You will need
// to create one of these for each property page used in the property sheet.
//

static void _SaveLdapUser(HWND hwndDlg)
{
   BOOL bResult = FALSE;
   char szTemp[MAX_PATH];

   if(IsWindow(hwndDlg))
   {
      GetDlgItemText(hwndDlg, IDC_USERID, szTemp, MAX_PATH);

      if(cd.szLdapUser)
      setupFree(cd.szLdapUser);

      cd.szLdapUser = setupStrdup(szTemp);
      SetDlgItemText(hwndDlg, IDC_USERID, cd.szLdapUser);

      GetDlgItemText(hwndDlg, IDC_PASSWORD, szTemp, MAX_PATH);

      if(cd.szLdapPWD)
      setupFree(cd.szLdapPWD);

      cd.szLdapPWD = setupStrdup(szTemp);
      SetDlgItemText(hwndDlg, IDC_PASSWORD, cd.szLdapPWD);
   }
}

/////////////////////////////////////////////////////////////////////////////
//
// The dialog procedure for a single property page. You will need to create
// one of these for each property page used in the property sheet. This
// procedure processes dialog messages sent to your property page by Windows.
//

static BOOL CALLBACK
_DialogProcLdapUser(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
   BOOL bValueReturned = FALSE;
   BOOL bResult = TRUE;

   switch(uMsg)
   {
      case WM_INITDIALOG:
      {
         HGDIOBJ hGdiObj;
         HWND heditwnd;

         hGdiObj = GetStockObject(DEFAULT_GUI_FONT);
         SendMessage(hwndDlg, WM_SETFONT, (WPARAM) ((struct HFONT__ *)hGdiObj)
                     , MAKELPARAM(TRUE, 0));
         heditwnd = GetDlgItem(hwndDlg, IDC_USERID);
         SendMessage(heditwnd, WM_SETFONT, (WPARAM) ((struct HFONT__
                     *)hGdiObj) , MAKELPARAM(TRUE, 0));

         cd.hwndPage[PG_SIXTH] = hwndDlg;
         _RefreshLdapUser(hwndDlg);
      }
      break;


      case WM_COMMAND:
      // Windows sends WM_COMMAND messages whenever the user clicks on
      // a control in your property page. If you need to perform some
      // special action, such as validating data or responding to a
      // button click, do it here.

      break;

      case WM_NOTIFY:
      // Windows sends WM_NOTIFY messages to your property page whenever
      // something interesting happens to the page. This could be page
      // activation/deactivation, a button click, etc. The wParam parameter
      // contains a pointer to the property page. The lParam parameter
      // contains a pointer to an NMHDR structure. The code field of this
      // structure contains the notification message code being sent. The
      // property sheet API allows you to alter the behavior of these
      // messages by returning a value for each message. To return a value,
      // use the SetWindowLong Windows SDK function.

      switch(((NMHDR*)lParam)->code)
      {

         case PSN_SETACTIVE:
         {

            CenterWindow(GetParent(hwndDlg));
            PropSheet_SetWizButtons(GetParent(hwndDlg), PSWIZB_BACK |
                                    PSWIZB_NEXT);
            _RefreshLdapUser(hwndDlg);

            break;
         }
         case PSN_KILLACTIVE:
         // This notification is sent upon deactivation of the property page.
         // Here you can do whatever might be necessary for this action, such
         // as saving the state of the controls. You should also reset the
         // the state of the wizard buttons here, as both the Back and Next
         // buttons should be active when you leave the AskOptions function.
         //
         // NOTE: If you do not want the page deactivated, return -1.

         PropSheet_SetWizButtons(GetParent(hwndDlg), PSWIZB_BACK |
                                 PSWIZB_NEXT);

         break;

         case PSN_WIZBACK:
         _SaveLdapUser(hwndDlg);

         break;

         case PSN_WIZNEXT:
         {
            Ldap *ldap;
            LdapErrorCode err;

            UINT uLdapPort = 0;
            char *szLdapHost = NULL;
            char *szLdapSuffix = NULL;
            char *szLdapUser = NULL;


            _SaveLdapUser(hwndDlg);

            szLdapHost = setupStrdup(cd.szConfigDSHost);
            uLdapPort = cd.nConfigDSPort;
            szLdapUser = setupStrdup(cd.szLdapUser);

            if(!IsValidLdapUser(szLdapHost, uLdapPort, NULL, &szLdapUser,
               cd.szLdapPWD, TRUE))
            {
               char szErrMsg[MAX_PATH];

               LoadString(mi.m_hModule, IDS_ERR_BAD_USER, szErrMsg,
                          sizeof(szErrMsg));

               if(NsSetupMessageBox(GetParent(hwndDlg), szErrMsg, NULL,
                                    MB_ICONWARNING | MB_OK) == IDOK)
               {
                  bValueReturned = TRUE;
                  SetFocus(GetDlgItem(hwndDlg, IDC_USERID));
                  SetWindowLong(hwndDlg, DWL_MSGRESULT, -1);

                  break;
               }
            }

            if(szLdapHost)
            setupFree(szLdapHost);
            if(szLdapUser)
            setupFree(szLdapUser);

            break;
         }
         case PSN_QUERYCANCEL:
         // This notification is sent when the user clicks the Cancel button.
         // It is also sent in response to the WM_CLOSE messages issued
         // by PSN_WIZBACK and PSN_WIZNEXT. Make sure that we only process
         // this message if the result is not back or next so that we don't
         // nuke the return value assigned by PSN_WIZBACK or PSN_WIZNEXT.
         //
         // NOTE: To prevent the cancel from occuring, return -1.

         if(mi.m_nResult != NS_WIZBACK && mi.m_nResult != NS_WIZNEXT)
         {
            if(QueryExit(hwndDlg))
            {
               mi.m_nResult = NS_WIZCANCEL;
            }
            else
            {
               SetWindowLong(hwndDlg, DWL_MSGRESULT, -1);
               bValueReturned = TRUE;
            }
         }
         break;
      }
      break;
   }

   return bValueReturned;
}


/////////////////////////////////////////////////////////////////////////////
//
// This procedure is called by the NDA_PostInstall API after the binaries
// are laid down as part of the post installation configuration.
// In this example, post-installation will import a schema file
// into the configuration directory server
//

void ImportFiles()
{
   char *ldapURL;
   char *dcroot;
   char *userid;
   char *userpwd;
   char schemaFile[MAX_PATH];
   int err;

   ldapURL = localToUTF8(getFromInfo(NDA_LDAPURL));
   userid = getFromInfo(NDA_LDAPUSER);
   userpwd = getFromInfo(NDA_LDAPPWD);

   wsprintf(schemaFile, "%s/ldif/schema.conf", serverRoot);

   err = setupInsertPluginSchemaEntries(ldapURL, userid, userpwd, schemaFile);

   if(err != OKAY) {
      setupLog(NULL, "Fail to update schema entries");
   }
}



/////////////////////////////////////////////////////////////////////////////
// NDA_PreInstall
//
// This function is called by the installation framework before asking the
// user any questions. Here you should determine if all of the requisites
// for installing this component are being met. If this operation succeeds
// return TRUE, otherwise display an error message and return FALSE to abort
// installation.
//

BOOL __declspec(dllexport)
NDA_PreInstall(void)
{
   return TRUE;
}


/////////////////////////////////////////////////////////////////////////////
// NDA_AskOptions
//
// This function is called by the installation framework to query the user for
// information about your component. Here you should ask all of the questions
// required to install your component as a series of wizard property sheets.
//

INT __declspec(dllexport)
NDA_AskOptions(HWND hwndParent, INT nDirection)
{

   PROPSHEETPAGE psp[NUM_PROP_PAGES];
   int nPages = 1;
   int nStartPage = 0;

   mi.m_nResult = NS_WIZERROR;
   nStartPage = (nDirection == NS_WIZNEXT) ? PG_FIRST : PG_SECOND;


   AddWizardPage(mi.m_hModule, &psp[PG_FIRST], IDD_LDAP_INFO,
                 _DialogProcConfigDSInfo);
   nPages++;
   AddWizardPage(mi.m_hModule, &psp[PG_SECOND], IDD_LDAPUSER,
                 _DialogProcLdapUser);
   nPages++;

   if(WizardDialog(mi.m_hModule, hwndParent, psp, nPages, nStartPage) < 0)
   {
      mi.m_nResult = NS_WIZERROR;
   }

   return mi.m_nResult;
}

/////////////////////////////////////////////////////////////////////////////
// NDA_GetSummary
//
// This function is called by the installation framework after all questions,
// for all components, have been asked. Here you should provide a detailed
// summary explaining all of the choices selected by the user.
//
// IMPORTANT NOTE: Each line MUST end in a carriage return/line feed
// combination ("\r\n") as this string is placed in an edit control. Edit
// controls do not properly handle single "\n" end-of-line characters.
//

VOID __declspec(dllexport)
NDA_GetSummary(char * lpszSummary)
{
   char* psz = lpszSummary;
   if(cd.szLdapUrl)
   {
      psz += sprintf(psz, NDA_INFO_LDAPURL, cd.szLdapUrl);
   }
}

/////////////////////////////////////////////////////////////////////////////
// NDA_ReadLocalCache
//
// This function is called by the installation framework during silent install
// to intialize your data from the local section of the cache created above.
// Here you should read any information stored in the installation cache's
// local section that you need. If this operation succeeds return TRUE,
// otherwise display an error message and return FALSE to indicate an error.
//

BOOL __declspec(dllexport)
NDA_ReadLocalCache(LPCSTR lpszCacheFileName, LPCSTR lpszSectionName)
{
   if (_infoFile == NULL)
   {
      _infoFile = strdup(lpszCacheFileName);
   }

   cd.szLdapUrl = setupGetInfString(lpszSectionName, NDA_LDAPURL , NULL,
                                    lpszCacheFileName);
   cd.szLdapUser = setupGetInfString(lpszSectionName, NDA_LDAPUSER , NULL,
                                     lpszCacheFileName);
   cd.szLdapPWD = setupGetInfString(lpszSectionName, NDA_LDAPPWD , NULL,
                                      lpszCacheFileName);

   return TRUE;
}

/////////////////////////////////////////////////////////////////////////////
// NDA_PostInstall
//
// The framework calls this function to perform post-installation
// configuration. Here you should set values in any product configuration
// files, install services, add registry keys, start servers, and anything
// else that can only be done once the binaries are layed down on the disk.
// If the function succeeds return TRUE, otherwise return FALSE to indicate
// an error.
//

BOOL __declspec(dllexport)
NDA_PostInstall(VOID)
{
   char url[1024];

   ImportFiles();

   wsprintf(url, "http://www.example.com");
   StartNavigator((char *)url);
   return TRUE;
}

/////////////////////////////////////////////////////////////////////////////
// NDA_PreUnInstall
//
// The framework calls this function to perform pre-uninstallation
// configuration. Here you should delete registry keys, stop services etc.
// If the function succeeds return TRUE, otherwise return FALSE to indicate
// an error.
//

BOOL __declspec(dllexport)
NDA_PreUnInstall(LPCSTR pszServerRoot)
{
   return TRUE;
}

/////////////////////////////////////////////////////////////////////////////
// NDA_PostUnInstall
//
// The framework calls this function to perform post-uninstallation
// configuration. Here you should restart services etc.
// If the function succeeds return TRUE, otherwise return FALSE to indicate
// an error.
//
BOOL __declspec(dllexport)
NDA_PostUnInstall(LPCSTR pszServerRoot)
{
   return TRUE;
}


/////////////////////////////////////////////////////////////////////////////
// NDA_WriteLocalCache
//
// This function is called by the installation framework when the user clicks
// Next at the summary screen. Here you should write all information entered
// by the user into the installation cache for use during silent installation.
// Data written to this file is not interpreted by the framework, and may
// consist of any values that you will need to perform the installation (not
// just values entered by the user). If this operation succeeds return TRUE,
// otherwise display an error message and return FALSE to indicate an error.
//

BOOL __declspec(dllexport)
NDA_WriteLocalCache(LPCSTR lpszCacheFileName, LPCSTR lpszSectionName)
{

   if (_infoFile == NULL)
   {
      _infoFile = strdup(lpszCacheFileName);
   }

   setupWriteInfString(lpszSectionName, NDA_LDAPURL, cd.szLdapUrl, lpszCacheFileName);
   setupWriteInfString(lpszSectionName, NDA_LDAPUSER, cd.szLdapUser, lpszCacheFileName);
   setupWriteInfString(lpszSectionName, NDA_LDAPPWD, cd.szLdapPWD, lpszCacheFileName);

   return TRUE;
}


/////////////////////////////////////////////////////////////////////////////
// DllMain
//
// The Windows DLL main entry point. Called upon loading the DLL into memory.
// Perform all initialization in the DLL_PROCESS_ATTACH reason handler, and
// release any resources that you have allocated in the DLL_PROCESS_DETACH
// message handler. See the Windows SDK documentation for more information
// on this function.
//

BOOL WINAPI
DllMain(HANDLE hModule, ULONG ulReasonForCall, LPVOID lpReserved)
{
   switch(ulReasonForCall)
   {
      case DLL_PROCESS_ATTACH:
         ZeroMemory(&mi, sizeof(MODULEINFO));
         mi.m_hModule = hModule;
         _InitializeControlData();
         break;
      case DLL_PROCESS_DETACH:
         break;
      case DLL_THREAD_ATTACH:
         break;
      case DLL_THREAD_DETACH:
         break;
   }
   return TRUE;
}

Code Example B-6 The Example Administrator header for Windows NT.

/////////////////////////////////////////////////////////////////////////////
// insnda.h - Administration Installation Plug-In Template Header
//

// All Rights Reserved.
//

#ifndef __INSNDA_H
#define __INSNDA_H

// Number of property pages that will show up during pre-installation

#define NUM_PROP_PAGES 2
#define PG_FIRST 0
#define PG_SECOND 1

// A global structure shared between the pre- and post-installation programs

typedef struct tagCONTROLDATA
{
   HWND hwndPage[NUM_PROP_PAGES];
   char *szLdapUser;
   char *szLdapPWD;
   char *szLdapUrl;
   int nConfigDSPort;
   } CONTROLDATA;

CONTROLDATA cd;

#define NDA_INFO_LDAPURL  "Directory URL: %s\r\n"
#define NDA_LDAPURL       "LDAPUrl"
#define NDA_LDAPUSER      "ldapUser"
#define NDA_LDAPPWD       "ldapPwd"

extern __declspec(dllexport) INT __cdecl NDA_AskOptions(HWND hwndParent, INT
                  nDirection);
extern __declspec(dllexport) VOID __cdecl NDA_GetSummary(LPSTR lpszSummary);
extern __declspec(dllexport) BOOL __cdecl NDA_WriteCacheGlobal(LPCSTR
                  lpszCacheFileName, LPCSTR lpszSection);
extern __declspec(dllexport) BOOL __cdecl NDA_WriteCacheLocal(LPCSTR
                  lpszCacheFileName, LPCSTR lpszSection);
extern __declspec(dllexport) BOOL __cdecl NDA_ReadCacheGlobal(LPCSTR
                  lpszCacheFileName, LPCSTR lpszSection);
extern __declspec(dllexport) BOOL __cdecl NDA_ReadCacheLocal(LPCSTR
                  lpszCacheFileName, LPCSTR lpszSection);
extern __declspec(dllexport) BOOL __cdecl NDA_Install(LPCSTR lpszInstallPath);
extern __declspec(dllexport) BOOL __cdecl NDA_PreInstall(void);
extern __declspec(dllexport) BOOL __cdecl NDA_PostInstall(void);
extern __declspec(dllexport) BOOL __cdecl NDA_PreUnInstall(LPCSTR
                  szServerRoot);
extern __declspec(dllexport) BOOL __cdecl NDA_PostUnInstall(LPCSTR
                  szServerRoot);

typedef struct tagMODULEINFO {
   HINSTANCE m_hModule;
   HWND m_hwndParent;
   INT m_nResult;
   } MODULEINFO;

#endif // __INSNDA_H

Code Example B-7 The Example Administrator master information file for Windows NT.

#
# Sample Server Master Information File
#
# Components: lists the components to be installed as specified
# in subsequent sections. If the section or the ComponentInfoFile
# does note exist the setup program will ignore the component

[General]
Name = Example Administrator
Vendor = Example, Inc.
Description = Installation for Example Administrator
Version = 4.5
Components = svrcore, nda
Mode = Typical
DefaultInstallDirectory = c:\serverrootname\nda45

# Package Contents
[svrcore]
ComponentInfoFile = svrcore/svrcore.inf

[nda]
ComponentInfoFile = nda/nda.inf


Code Example B-8 The Example Administrator package information file for Windows NT.

[General]
name=Example Administrator
components=nda
mandatory=True
Description=Example Administrator

[nda]
name=Example Administrator
nickname=nda
Description=Example Administrator
version=4.5
checked=True
visible=True
mandatory=True
PlugIn=insnda.dll
PreInstall=NDA_PreInstall
AskOptions=NDA_AskOptions
GetSummary=NDA_GetSummary
WriteLocalCache=NDA_WriteLocalCache
ReadLocalCache=NDA_ReadLocalCache
PostInstall=NDA_PostInstall
PreUnInstall=NDA_PreUnInstall
PostUnInstall=NDA_PostUnInstall
archive=nda.z


Previous     Contents     Index     Next     
Copyright (C) 2001 Sun Microsystems, Inc. Used by permission. Copyright (C) 2005 Red Hat, Inc. All rights reserved.
This material may be distributed only subject to the terms and conditions set forth in the Open Publication License, v1.0 or later (the latest version is presently available at http://www.opencontent.org/openpub/

Last Updated April 11, 2000