Processing Wizard Notifications

The information the WIZARD sample gathers to generate the review is kept in a global structure named REVIEWINFO, which resides in the WIZARD.H file. The MAX_PATH constant in the following code is defined to be 256 characters.

typedef struct tagREVIEWINFO
{
HINSTANCE hInst; // current instance
int iWorkHabits;
int iTeamWork;
int iReliability;
int iGoals;
int iAdaptation;
char pszName [MAX_PATH];
char pszTitle [MAX_PATH];
char pszProject [MAX_PATH];
char pszDepartment [MAX_PATH];
} REVIEWINFO;

The following code from the WIZARD sample demonstrates how an application can trap the notifications that are sent to a wizard. In this code, the dialog procedure initializes the text buffers with NULL strings upon the first entrance into the wizard and whenever the dialog box receives a PSN_RESET notification. When this dialog box receives the PSN_WIZNEXT notification, it saves the information that the user entered in the text fields. If this dialog box is called again and receives a PSN_SETACTIVE notification, the text buffers are reinitialized with the information that was previously entered in the text fields. This dialog box also sets the Next button as the only enabled function when it receives the PSN_SETACTIVE notification. Since this is the first dialog box entered in the wizard, the Back button should not be enabled.

// FUNCTION: YourInfo (HWND, UINT, UINT, LONG)
//
// PURPOSE: Processes messages for "Your Information" page
//
// MESSAGES:
//
// WM_INITDIALOG initializes 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:
// Initialize the text buffers with NULL.
strcpy (rvInfo.pszName, "");
strcpy (rvInfo.pszTitle, "");
strcpy (rvInfo.pszProject, "");
strcpy (rvInfo.pszDepartment, "");
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 original values.
strcpy (rvInfo.pszName, "");
strcpy (rvInfo.pszTitle, "");
strcpy (rvInfo.pszProject, "");
strcpy (rvInfo.pszDepartment, "");
SetWindowLong (hDlg, DWL_MSGRESULT, FALSE);
break;

case PSN_SETACTIVE:
PropSheet_SetWizButtons (GetParent (hDlg), PSWIZB_NEXT);
SendMessage (GetDlgItem (hDlg, IDE_NAME), WM_SETTEXT,
0, (LPARAM)rvInfo.pszName);
SendMessage (GetDlgItem (hDlg, IDE_TITLE), WM_SETTEXT,
0, (LPARAM)rvInfo.pszTitle);
SendMessage (GetDlgItem (hDlg, IDE_PROJECT), WM_SETTEXT,
0, (LPARAM)rvInfo.pszProject);
SendMessage (GetDlgItem (hDlg, IDE_DEPARTMENT), WM_SETTEXT,
0, (LPARAM)rvInfo.pszDepartment);
break;

case PSN_WIZNEXT:
// The Next button was clicked; get the text info entered.
SendDlgItemMessage (hDlg, IDE_NAME, WM_GETTEXT,
(WPARAM)MAX_PATH, (LPARAM)rvInfo.pszName);
SendDlgItemMessage (hDlg, IDE_TITLE, WM_GETTEXT,
(WPARAM)MAX_PATH, (LPARAM)rvInfo.pszTitle);
SendDlgItemMessage (hDlg, IDE_PROJECT, WM_GETTEXT,
(WPARAM)MAX_PATH, (LPARAM)rvInfo.pszProject);
SendDlgItemMessage (hDlg, IDE_DEPARTMENT, WM_GETTEXT,
(WPARAM)MAX_PATH, (LPARAM)rvInfo.pszDepartment);
break;

default:
return FALSE;
}
break;

default:
return FALSE;
}

return TRUE;
}

When you build and run this sample, you'll see the first page of the wizard, shown in Figure 4-5.

 

Figure 4-5.

The first page of the performance review wizard.

In the WIZARD sample, information is gathered to produce text for a performance review. While the wizard is running, the results the user enters are kept in the REVIEWINFO structure, as shown previously, and used to create the review. The review is generated through indexes into a string table, and the resulting buffer is displayed in a multiline edit box in the client area of the main window. The WIZARD sample uses the following code to generate the final text buffer:

// FUNCTION: GenerateReview (HWND)
//
// PURPOSE: Generates the review
//
// COMMENTS:
// This function generates the review based on the answers
// given to the wizard. The function translates lame reality into
// impressive-sounding managerspeak via a string table.

void GenerateReview (HWND hDlg)
{
char lpBuf1 [MAX_LINE]; // buffers for lines in review
char lpBuf2 [MAX_LINE];
char lpBuf3 [MAX_LINE];
char lpBuf4 [MAX_LINE];
char lpBuf5 [MAX_LINE];

wsprintf (lpReview, "Name: %s%C%C%C%CTitle: %s%C%C%C%CDepartment: "
"%s%C%C%C%CMain Project: %s%C%C%C%C",
rvInfo.pszName, 0x0d, 0x0a, 0x0d, 0x0a,
rvInfo.pszTitle, 0x0d, 0x0a, 0x0d, 0x0a,
rvInfo.pszDepartment, 0x0d, 0x0a, 0x0d, 0x0a,
rvInfo.pszProject, 0x0d, 0x0a, 0x0d, 0x0a);

// Add a line describing work habits.
if (LoadString (rvInfo.hInst, rvInfo.iWorkHabits, lpBuf1,
sizeof (lpBuf1)) == 0)
MessageBox (hDlg, “Error loading string!”, NULL, MB_OK);
else
strcat (lpReview, lpBuf1);

// Add a line describing teamwork.
if (LoadString (rvInfo.hInst, rvInfo.iTeamWork, lpBuf2,
sizeof (lpBuf2)) == 0)
MessageBox (hDlg, “Error loading string!”, NULL, MB_OK);
else
strcat (lpReview, lpBuf2);

// Add a line describing reliability.
if (LoadString (rvInfo.hInst, rvInfo.iReliability, lpBuf3,
sizeof (lpBuf3)) == 0)
MessageBox (hDlg, “Error loading string!”, NULL, MB_OK);
else
strcat (lpReview, lpBuf3);

// Add a line describing goals.
if (LoadString (rvInfo.hInst, rvInfo.iGoals, lpBuf4,
sizeof (lpBuf4)) == 0)
MessageBox (hDlg, “Error loading string!”, NULL, MB_OK);
else
strcat (lpReview, lpBuf4);

// Add a line describing adaptability.
if (LoadString (rvInfo.hInst, rvInfo.iAdaptation, lpBuf5,
sizeof (lpBuf5)) == 0)
MessageBox (hDlg, “Error loading string!”, NULL, MB_OK);
else
strcat (lpReview, lpBuf5);
}

If you build and run the sample now, you can fill in the appropriate information, check the boxes that most accurately reflect your skills and work habits, and have a review generated for you. Just for grins, I used the wizard and picked the last option in the list for each question asked. You can see the result in Figure 4-6.

 

Figure 4-6.

The review generated by the performance review wizard.