INSTWIZ.C


/******************************************************************************\
* This is a part of the Microsoft Source Code Samples.
* Copyright 1994 - 1998 Microsoft Corporation.
* All rights reserved.
* This source code is only intended as a supplement to
* Microsoft Development Tools and/or WinHelp documentation.
* See these sources for detailed information regarding the
* Microsoft samples programs.
\******************************************************************************/

//
//
// This wizard code is adapted from the mstools\win32\wizard
// sample, refer to the wizard sample and the online help for
// more information about wizards and property pages
//
//
// Functions:
// CreateWizard(HWND, HINSTANCE) - starts the wizard
// FillInPropertyPage() - Fills in a PROPSHEETPAGE structure
//
// Welcome(),License(),YourInfo(),Install_Type(),Install_Destination(),
// Custom_Options(),Install()
// - Process the respective Install pages
//
//

#include <windows.h>
#include "instwiz.h"
#include "infinst.h"

// global license flag
BOOL gLicenseAccepted = FALSE;

//
//
// FUNCTION: CreateWizard(HWND)
//
// PURPOSE: Create the Install control.
//
// COMMENTS:
//
// This function creates the install property sheet.
//
int CreateWizard(HWND hwndOwner, HINSTANCE hInst)
{
PROPSHEETPAGE psp[NUM_PAGES];
PROPSHEETHEADER psh;

FillInPropertyPage( &psp[0], IDD_WELCOME, TEXT("Welcome"), Welcome);
//FillInPropertyPage( &psp[1], IDD_LICENSE, TEXT("Software License Agreement"), License);
FillInPropertyPage( &psp[1], IDD_INFO, TEXT("Your Information"), YourInfo);
FillInPropertyPage( &psp[2], IDD_INSTALL_TYPE, TEXT("Installation Type"), Install_Type);
FillInPropertyPage( &psp[3], IDD_INSTALL_DESTINATION, TEXT("Installation Location"), Install_Destination);
FillInPropertyPage( &psp[4], IDD_CUSTOM_OPTIONS, TEXT("Custom Installation Options"), Custom_Options);
FillInPropertyPage( &psp[5], IDD_INSTALL, TEXT("Finish Installation"), Install);

psh.dwSize = sizeof(PROPSHEETHEADER);
psh.dwFlags = PSH_PROPSHEETPAGE | PSH_WIZARD | PSH_NOAPPLYNOW;
psh.hwndParent = hwndOwner;
psh.pszCaption = (LPSTR) TEXT("Product Install");
psh.nPages = sizeof(psp) / sizeof(PROPSHEETPAGE);
psh.nStartPage = 0;
psh.ppsp = (LPCPROPSHEETPAGE) &psp;

return (PropertySheet(&psh));
}


//
//
// FUNCTION: FillInPropertyPage(PROPSHEETPAGE *, int, LPSTR, LPFN)
//
// PURPOSE: Fills in the given PROPSHEETPAGE structure
//
// COMMENTS:
//
// This function fills in a PROPSHEETPAGE structure with the
// information the system needs to create the page.
//
void FillInPropertyPage( PROPSHEETPAGE* psp, int idDlg, LPSTR pszProc, DLGPROC pfnDlgProc)
{
psp->dwSize = sizeof(PROPSHEETPAGE);
psp->dwFlags = 0;
psp->hInstance = setupInfo.hInst;
psp->pszTemplate = MAKEINTRESOURCE(idDlg);
psp->pszIcon = NULL;
psp->pfnDlgProc = pfnDlgProc;
psp->pszTitle = pszProc;
psp->lParam = 0;

}

//////////////////////////////////////////
//
// Wizard procs
//
//////////////////////////////////////////

//
// FUNCTION: Welcome (HWND, UINT, UINT, LONG)
//
// PURPOSE: Processes messages for "Welcome" page
//
// MESSAGES:
//
// WM_INITDIALOG - intializes the page
// WM_NOTIFY - processes the notifications sent to the page
// WM_COMMAND - saves the id of the choice selected
//
BOOL APIENTRY Welcome(
HWND hDlg,
UINT message,
UINT wParam,
LONG lParam)
{

switch (message)
{
case WM_INITDIALOG:
setupInfo.iWelcome = 0;
SetWindowLong(hDlg,DWL_MSGRESULT, FALSE);
break;


case WM_NOTIFY:
switch (((NMHDR FAR *) lParam)->code)
{

case PSN_KILLACTIVE:
SetWindowLong(hDlg,DWL_MSGRESULT, FALSE);
return 1;
break;

case PSN_RESET:
// rest to the original values
setupInfo.iWelcome = 0;
SetWindowLong(hDlg,DWL_MSGRESULT, FALSE);
break;

case PSN_SETACTIVE:
PropSheet_SetWizButtons(GetParent(hDlg), PSWIZB_NEXT);
SendMessage(GetDlgItem(hDlg,0x3024 ), BM_SETSTYLE,
(WPARAM)BS_PUSHBUTTON, MAKELONG(FALSE, 0));
break;

case PSN_WIZNEXT:
//
// If they haven't accepted the license
// take them there, otherwise proceed with the wizard
//
if (TRUE != gLicenseAccepted)
{
int nUserResponse;

// Ask them to accept the license
nUserResponse = DialogBox
(setupInfo.hInst,
MAKEINTRESOURCE(IDD_LICENSE),
hDlg,
(DLGPROC) License);

if (IDC_LICENSE_ACCEPT == nUserResponse)
{
// They agreed, now we won't show them the
// license again
gLicenseAccepted = TRUE;
}
else
{
// the user just cancelled the install
// by declining the license agreement
// you could put dialog box here
// making sure they realize that this will
// cancel the installation
PostQuitMessage(0);
return 1;
}
}

break;

default:
return FALSE;

}
break;

default:
return FALSE;
}
return TRUE;
}

//
// FUNCTION: License (HWND, UINT, UINT, LONG)
//
// PURPOSE: Processes messages for "License Agreement" page
//
// MESSAGES:
//
// WM_INITDIALOG - intializes the page
// WM_NOTIFY - processes the notifications sent to the page
// WM_COMMAND - saves the id of the choice selected
//
BOOL APIENTRY License(
HWND hDlg,
UINT message,
UINT wParam,
LONG lParam)
{

switch (message)
{
case WM_INITDIALOG:
{
//Read in License fiel
char szLicenseFile[MAX_PATH], ReturnTextBuffer[MAX_PATH];

LPSTR lpszLicenseFile = (char *) &szLicenseFile ;
LPSTR lpszLicenseText;

HWND hEditCtl;
HANDLE hFile;

DWORD NumberOfBytesRead, dwFileSize;

//
// Determine where we are installing from
// and specific the license file there
//
GetModuleFileName(NULL, szLicenseFile, _MAX_PATH);
*(strrchr(szLicenseFile, '\\') + 1) = '\0'; // Strip setup.exe off path

strcat(szLicenseFile,TEXT("license.txt"));

// Open License file
hFile = CreateFile(
lpszLicenseFile, // pointer to name of the file
GENERIC_READ, // access (read-write) mode
FILE_SHARE_READ, // share mode
NULL, // pointer to security descriptor
OPEN_EXISTING, // how to create
FILE_ATTRIBUTE_NORMAL, // file attributes
NULL); // handle to file with attributes to copy

if(INVALID_HANDLE_VALUE == hFile)
{
wsprintf(ReturnTextBuffer, "Error accessing file: %s", szLicenseFile);

MessageBox(hDlg, ReturnTextBuffer,
"Sample Installation Critical Error", 0);

//install cannot proceed so go away

PostQuitMessage(0);
return FALSE;
}

// Read License file into string
// setup memory
dwFileSize = GetFileSize (hFile, NULL) ;

lpszLicenseText = malloc ((dwFileSize + 1));

if(NULL == lpszLicenseText)
{
wsprintf(ReturnTextBuffer, "Error allocating memory for license text.");
CloseHandle(hFile);

MessageBox(hDlg, ReturnTextBuffer,
"Sample Installation Critical Error", 0);

//install cannot proceed so go away

free(lpszLicenseText);
PostQuitMessage(0);
return FALSE;
}

//read file
if (!ReadFile(hFile, // handle of file to read
lpszLicenseText, // address of buffer that receives data
dwFileSize, // number of bytes to read
&NumberOfBytesRead, // address of number of bytes read
NULL)) // address of structure for data
{
wsprintf(ReturnTextBuffer, "Error reading license file: %s", szLicenseFile);

// clean up
free(lpszLicenseText);
CloseHandle(hFile);

MessageBox(hDlg, "Sample Installation Critical Error",
ReturnTextBuffer, 0);

//install cannot proceed so go away

PostMessage(hDlg, WM_DESTROY, 0, 0 );
return FALSE;
}

//Done with file
CloseHandle(hFile);
hFile = NULL;

// Be sure the file string is null terminated
lpszLicenseText[dwFileSize] = '\0';

SetDlgItemText(hDlg, LICENSE_TEXT, lpszLicenseText);

//set focus to license text
hEditCtl = GetDlgItem(hDlg, LICENSE_TEXT);
SetFocus(hEditCtl);

// the control now has the text
// so free the memory
free(lpszLicenseText);
return(FALSE);
}

break;

case WM_COMMAND:
//
// LOWORD added for portability
//
switch(LOWORD(wParam)) {
case IDC_LICENSE_ACCEPT:
EndDialog(hDlg, IDC_LICENSE_ACCEPT);
return 0;
case IDC_LICENSE_DECLINE:
EndDialog(hDlg, IDC_LICENSE_DECLINE);
return 0;
}
break;
}
return(FALSE);

UNREFERENCED_PARAMETER(lParam);
}

//
// FUNCTION: YourInfo(HWND, UINT, UINT, LONG)
//
// PURPOSE: Processes messages for "Your Information" page
//
// MESSAGES:
//
// WM_INITDIALOG - intializes the page
// WM_NOTIFY - processes the notifications sent to the page
//
BOOL APIENTRY YourInfo(
HWND hDlg,
UINT message,
UINT wParam,
LONG lParam)
{

switch (message)
{
case WM_INITDIALOG:
break;

case WM_NOTIFY:
switch (((NMHDR FAR *) lParam)->code)
{

case PSN_KILLACTIVE:
SetWindowLong(hDlg,DWL_MSGRESULT, FALSE);
return 1;
break;

case PSN_RESET:
// reset to the blank values
lstrcpy(setupInfo.pszUserName, TEXT(""));
lstrcpy(setupInfo.pszCompany,TEXT(""));
lstrcpy(setupInfo.pszProductIdString, TEXT(""));
lstrcpy(setupInfo.pszEmailAddress, TEXT(""));
SetWindowLong(hDlg,DWL_MSGRESULT, FALSE);
break;

case PSN_SETACTIVE:
PropSheet_SetWizButtons(GetParent(hDlg), PSWIZB_BACK |PSWIZB_NEXT);
SendMessage(GetDlgItem(hDlg,0x3024 ), BM_SETSTYLE, (WPARAM)BS_PUSHBUTTON, MAKELONG(FALSE, 0));
//SendMessage(GetParent(hDlg), DM_SETDEFID, (WPARAM)IDC_BUTTON1, 0);
SendMessage(GetDlgItem(hDlg, IDE_NAME),
WM_SETTEXT, 0, (LPARAM)setupInfo.pszUserName);
SendMessage(GetDlgItem(hDlg, IDE_COMPANY),
WM_SETTEXT, 0, (LPARAM)setupInfo.pszCompany);
SendMessage(GetDlgItem(hDlg, IDE_PRODUCT_ID),
WM_SETTEXT, 0, (LPARAM)setupInfo.pszProductIdString);
SendMessage(GetDlgItem(hDlg, IDE_EMAIL),
WM_SETTEXT, 0, (LPARAM)setupInfo.pszEmailAddress);
break;

case PSN_WIZBACK:
break;

case PSN_WIZNEXT:
// the Next button was pressed
SendDlgItemMessage(hDlg, IDE_NAME, WM_GETTEXT,
(WPARAM)MAX_PATH, (LPARAM) setupInfo.pszUserName);
SendDlgItemMessage(hDlg, IDE_COMPANY, WM_GETTEXT,
(WPARAM)MAX_PATH, (LPARAM)setupInfo.pszCompany);
SendDlgItemMessage(hDlg, IDE_PRODUCT_ID, WM_GETTEXT,
(WPARAM)MAX_PATH, (LPARAM)setupInfo.pszProductIdString);
SendDlgItemMessage(hDlg, IDE_EMAIL, WM_GETTEXT,
(WPARAM)MAX_PATH, (LPARAM)setupInfo.pszEmailAddress);
break;

default:
return FALSE;

}
break;

default:
return FALSE;
}
return TRUE;
}

//
// FUNCTION: Install_Type (HWND, UINT, UINT, LONG)
//
// PURPOSE: Processes messages for "Install_Type" page
//
// MESSAGES:
//
// WM_INITDIALOG - intializes the page
// WM_NOTIFY - processes the notifications sent to the page
// WM_COMMAND - saves the id of the choice selected
//
BOOL APIENTRY Install_Type(
HWND hDlg,
UINT message,
UINT wParam,
LONG lParam)
{

switch (message)
{
case WM_INITDIALOG:
// pick normal as the default
setupInfo.iInstall_Type = IDC_INSTALL_TYPE_NORMAL;
CheckRadioButton( hDlg, IDC_INSTALL_TYPE_NORMAL, IDC_INSTALL_TYPE_UNINSTALL,
IDC_INSTALL_TYPE_NORMAL);
setupInfo.iCustom_Options1 = 1;
setupInfo.iCustom_Options2 = 1;
setupInfo.iCustom_Options3 = 0;
setupInfo.iCustom_Options4 = 1;
break;

case WM_COMMAND:
if (HIWORD(wParam) == BN_CLICKED)
{
setupInfo.iInstall_Type = LOWORD(wParam);
CheckRadioButton( hDlg, IDC_INSTALL_TYPE_NORMAL, IDC_INSTALL_TYPE_UNINSTALL, LOWORD(wParam));

//TODO: you could change the wizard at this
// point with add and remove page.
// We will just set the options of custom options
// for simplicity

// change the NEXT to FINISH if they want to uninstall
if (IDC_INSTALL_TYPE_UNINSTALL == LOWORD(wParam))
{
//TODO: could check that the product is indeed
// installed and if not, don't let them select
// it--you could grey out the selection or
// you could just uninstall even though
// it won't do anything
PropSheet_SetWizButtons(GetParent(hDlg), PSWIZB_BACK | PSWIZB_FINISH);
}
else
{
PropSheet_SetWizButtons(GetParent(hDlg), PSWIZB_BACK | PSWIZB_NEXT);
}

// add in options according to what was seleced
switch LOWORD(wParam)
{
case IDC_INSTALL_TYPE_CUSTOM:
// first reset options to off
setupInfo.iCustom_Options1 = 0;
setupInfo.iCustom_Options2 = 0;
setupInfo.iCustom_Options3 = 0;
setupInfo.iCustom_Options4 = 0;
break;
case IDC_INSTALL_TYPE_NORMAL:
setupInfo.iCustom_Options1 = 1;
setupInfo.iCustom_Options2 = 1;
setupInfo.iCustom_Options3 = 0;
setupInfo.iCustom_Options4 = 1;
break;
case IDC_INSTALL_TYPE_MIN:
setupInfo.iCustom_Options1 = 1;
setupInfo.iCustom_Options2 = 1;
setupInfo.iCustom_Options3 = 0;
setupInfo.iCustom_Options4 = 0;
break;
default:
break;
}
}

break;

case WM_NOTIFY:
switch (((NMHDR FAR *) lParam)->code)
{

case PSN_KILLACTIVE:
SetWindowLong(hDlg,DWL_MSGRESULT, FALSE);
return 1;
break;

case PSN_RESET:
// rest to the original values
setupInfo.iInstall_Type = 0;
SetWindowLong(hDlg,DWL_MSGRESULT, FALSE);
break;

case PSN_SETACTIVE:
//if they have selected an install type, be sure
//it is checked
if (setupInfo.iInstall_Type)
SendMessage(GetDlgItem(hDlg, setupInfo.iInstall_Type),
BM_SETCHECK, 1, 0L);

// Set the correct button NEXT or FINISH
if (IDC_INSTALL_TYPE_UNINSTALL == setupInfo.iInstall_Type)
{
//TODO: could check that the product is indeed
// installed and if not, don't let them select
// it--you could grey out the selection or
// you could just uninstall even though
// it won't do anything
PropSheet_SetWizButtons(GetParent(hDlg), PSWIZB_BACK | PSWIZB_FINISH);
}
else
{
PropSheet_SetWizButtons(GetParent(hDlg), PSWIZB_BACK | PSWIZB_NEXT);
}
break;

case PSN_WIZBACK:
break;

case PSN_WIZNEXT:
break;

case PSN_WIZFINISH:
// They finished the wizard, now do
// what they said
break;

default:
return FALSE;

}
break;

default:
return FALSE;
}
return TRUE;
}
//
// FUNCTION: Install_Destination(HWND, UINT, UINT, LONG)
//
// PURPOSE: Processes messages for "Install Destination" page
//
// MESSAGES:
//
// WM_INITDIALOG - intializes the page
// WM_NOTIFY - processes the notifications sent to the page
//
BOOL APIENTRY Install_Destination(
HWND hDlg,
UINT message,
UINT wParam,
LONG lParam)
{

switch (message)
{
case WM_INITDIALOG:
//lstrcpy(setupInfo.pszDestPath, TEXT(""));
break;

case WM_NOTIFY:
switch (((NMHDR FAR *) lParam)->code)
{
//TODO: Add code here to check that the user entered
// path is valid and show the user disk space available
// You can also have more on disk space on the
// customer options page.
// So this sample does NOT verify the path and disk space
// requirements. Note the setupapi functions will gracefully
// let the user know there is no disk space avail--at which
// time the user can go clean up some space or cancel the install

case PSN_KILLACTIVE:
SetWindowLong(hDlg,DWL_MSGRESULT, FALSE);
return 1;
break;

case PSN_RESET:
// reset to the original values
lstrcpy(setupInfo.pszDestPath, TEXT(""));
SetWindowLong(hDlg,DWL_MSGRESULT, FALSE);
break;

case PSN_SETACTIVE:
PropSheet_SetWizButtons(GetParent(hDlg), PSWIZB_BACK |PSWIZB_NEXT);
SendMessage(GetDlgItem(hDlg,0x3024 ), BM_SETSTYLE, (WPARAM)BS_PUSHBUTTON, MAKELONG(FALSE, 0));
SendMessage(GetDlgItem(hDlg, IDE_PATH), WM_SETTEXT, 0, (LPARAM)setupInfo.pszDestPath);
break;

case PSN_WIZBACK:
break;

case PSN_WIZNEXT:
// the Next button was pressed
SendDlgItemMessage(hDlg, IDE_PATH, WM_GETTEXT, (WPARAM)MAX_PATH, (LPARAM) setupInfo.pszDestPath);
break;

default:
return FALSE;

}
break;

default:
return FALSE;
}
return TRUE;
}
//
// FUNCTION: Custom_Options (HWND, UINT, UINT, LONG)
//
// PURPOSE: Processes messages for "Custom options" page
//
// MESSAGES:
//
// WM_INITDIALOG - intializes the page
// WM_NOTIFY - processes the notifications sent to the page
// WM_COMMAND - saves the id of the choice selected
//
BOOL APIENTRY Custom_Options(
HWND hDlg,
UINT message,
UINT wParam,
LONG lParam)
{

switch (message)
{
case WM_INITDIALOG:
// these are initialized via the install type page
// so we don't need to initialize anything
break;

case WM_COMMAND:
if (HIWORD(wParam) == BN_CLICKED)
{
if (LOWORD(wParam) == IDC_CUSTOM_OPTION1) {
if (setupInfo.iCustom_Options1) {
setupInfo.iCustom_Options1 = 0;
} else {
setupInfo.iCustom_Options1 = 1;
}
}

if (LOWORD(wParam) == IDC_CUSTOM_OPTION2) {
if (setupInfo.iCustom_Options2) {
setupInfo.iCustom_Options2 = 0;
} else {
setupInfo.iCustom_Options2 = 1;
}
}

if (LOWORD(wParam) == IDC_CUSTOM_OPTION3) {
if (setupInfo.iCustom_Options3) {
setupInfo.iCustom_Options3 = 0;
} else {
setupInfo.iCustom_Options3 = 1;
}
}

if (LOWORD(wParam) == IDC_CUSTOM_OPTION4) {
if (setupInfo.iCustom_Options4) {
setupInfo.iCustom_Options4 = 0;
} else {
setupInfo.iCustom_Options4 = 1;
}
}
}
break;

case WM_NOTIFY:
switch (((NMHDR FAR *) lParam)->code)
{

case PSN_KILLACTIVE:
SetWindowLong(hDlg,DWL_MSGRESULT, FALSE);
return 1;
break;

case PSN_RESET:
// rest to the original values
setupInfo.iCustom_Options1 = 0;
setupInfo.iCustom_Options2 = 0;
setupInfo.iCustom_Options3 = 0;
setupInfo.iCustom_Options4 = 0;
SetWindowLong(hDlg,DWL_MSGRESULT, FALSE);
break;

case PSN_SETACTIVE:
CheckDlgButton (hDlg, IDC_CUSTOM_OPTION1,
setupInfo.iCustom_Options1);
CheckDlgButton (hDlg, IDC_CUSTOM_OPTION2,
setupInfo.iCustom_Options2);
CheckDlgButton (hDlg, IDC_CUSTOM_OPTION3,
setupInfo.iCustom_Options3);
CheckDlgButton (hDlg, IDC_CUSTOM_OPTION4,
setupInfo.iCustom_Options4);
PropSheet_SetWizButtons(GetParent(hDlg), PSWIZB_BACK | PSWIZB_NEXT);
break;

case PSN_WIZBACK:
break;

case PSN_WIZNEXT:
break;

default:
return FALSE;

}
break;

default:
return FALSE;
}
return TRUE;
}
//
// FUNCTION: Install(HWND, UINT, UINT, LONG)
//
// PURPOSE: Processes messages for "Installation" page
//
// MESSAGES:
//
// WM_INITDIALOG - intializes the page
// WM_NOTIFY - processes the notifications sent to the page
// WM_COMMAND - saves the id of the choice selected
//
//
BOOL APIENTRY Install(
HWND hDlg,
UINT message,
UINT wParam,
LONG lParam)
{

switch (message)
{
case WM_INITDIALOG:
setupInfo.iInstall = 0;
break;

case WM_NOTIFY:
switch (((NMHDR FAR *) lParam)->code)
{
case PSN_KILLACTIVE:
SetWindowLong(hDlg,DWL_MSGRESULT, FALSE);
return 1;
break;

case PSN_RESET:
// rest to the original values
setupInfo.iInstall = 0;
SetWindowLong(hDlg,DWL_MSGRESULT, FALSE);
break;

case PSN_SETACTIVE:
PropSheet_SetWizButtons(GetParent(hDlg), PSWIZB_BACK | PSWIZB_FINISH);
break;

case PSN_WIZBACK:
break;


case PSN_WIZFINISH:
// They finished the wizard, now do
// what they said
break;

default:
return FALSE;
}
break;

default:
return FALSE;
}
return TRUE;
}