Click here to Skip to main content
15,883,749 members
Articles / Desktop Programming / MFC
Article

A Simple Generic Wizard

Rate me:
Please Sign up or sign in to vote.
4.50/5 (6 votes)
12 May 20033 min read 66.7K   893   26   8
A custom AppWizard application to create simple CTreePropSheet-based wizards.

Sample Image - genwiz.jpg

Introduction

This is an AppWizard created using the MSVC's built-in Custom AppWizard. It is called GenWiz and it can be used with MSVC to create simple generic wizard skeletons. It is based on the CTreePropSheet class developed by Sven Wiegand.

This wizard is basically a clone of the MSVC's Custom AppWizard in terms of creating application skeletons by using templates and macros. The main reason to develop such a wizard was because I wanted the wizards to be independent executables instead of AWX executables, which can only be executed under the MSVC IDE.

Before creating this simple generic wizard, I searched on the Internet for information on how to access the AppWizard's functionality, implemented in MFCAPWZ.DLL. I found no info and therefore I came up with my version on how to parse the templates and replace macros.

An example of a wizard created with GenWiz can be found in this other article: PIC C Wizard.

How to Install

Download the zip file containing the source code and extract the GenWiz.AWX file, included under the \release folder, to your Program Files\Microsoft Visual Studio\Common\MSDev98\Template folder. Next time you start up the MSVC IDE, the genwiz AppWizard should be listed in the New Projects tab.

The Important "Stuff" Within GenWiz

There's a lot of reference material on the Internet and MSDN itself about how the AppWizard works, so I'll focus mainly in the set of functions that I coded to implement this wizard. These functions are those that are going to be part of any GenWiz's generated wizards:

CMapStringToString m_Dictionary;
/**< Holds the macros that are later replaced by values.*/
/**
It creates each of the files found to be templates and
that are included in the wizard's project file. The files
are created in a folder with the same name as the project
name gave by the user. This function should be call by one
of the wizard's page OnOK() function.
*/
BOOL CreateProjectFiles();
/**
It processes the wizard's project file to determine
which templates to load into memory. It also calls the
function FileStatusInProject() to determine how the files
are going to be handled in the project.
This function should be the first one to be called by one
of the wizard's page OnOK() function.
*/
BOOL LoadProjectInfo();
/**
It retrieves the text information that is placed
in one the templates to provide the user project information
just before its creation. This text information could be
passed to a "project information" dialog box.
\param sText
 A reference to a CString object to hold the
text information.
*/
void GetConfirmText( CString& sText );
/**
It processes the templates that are going to be part of the
project and still contain the macros. It then replaces these
macros by the values given by the user through the wizard's
user interface. This function should be called before the
CreateProjectFiles() function.
*/
void ProcessTemplates();
protected:
CString m_sTemplatesFolder;
/**< Holds the macros that are later replaced by values.*/
CString m_sConfirmBuf;
/**< The information text displayed before the
project creation.*/
CStringArray m_saTemplates;
/**< The names of the templates to be included in the
project.*/
CStringArray m_saTemplatesBuf;
/**< The contents of the templates before and after
macros.*/
/**
It adds the macros in the macros dictionary. This function
is called by ProcessTemplates(). The user can add all the
wizard's macros in this function.
*/
void CreateAndFillMacros();
/**
It verifies if the wizard's project template file exists.
This function is called before showing the wizard GUI; if
the project file does not exist, it asks the user to create
default templates.
\return
 TRUE if file exists, FALSE if user did not want to
create default templates and wizard will abort execution.
*/
BOOL VerifyWizardConfigFile();
/**
It determines the status of a template file in the project.
The user should add code here if two or more different types
of files can be generated by the wizard. This function is
called by LoadProjectInfo().
*/
DWORD FileStatusInProject( CString& sFName );
/**
It reads the contents of a template file
\param lpszTemplateName
 It specifies the file name of the template
to load. This function is called by the LoadProjectInfo().
\return
 PTCHAR, a pointer to a char buffer where the file has
been loaded. NULL if the function failed.
*/
PTCHAR LoadTemplate( LPCTSTR lpszTemplateName );
/**
It adds a macro to the dictionary in which the value comes
from an integer type of variable.
\param lpszMacro
 Name of the new macro.
\param value
 Integer value that should be passed to the new macro.
*/
void AddMacroFromInt( LPCTSTR lpszMacro, int value );
/**
It adds a macro to the dictionary in which the value comes
from a floating point type of variable.
\param lpszMacro
 Name of the new macro.
\param value
 Floating point value that should be passed to
the new macro.
*/
void AddMacroFromDouble( LPCTSTR lpszMacro, double value );
/**
Callback function used to open "TEMPLATES" resources and
create the wizard's default templates. This function is called
when the wizard is re-creating the default templates.
See Window's API for more reference information.
\param hModule
 Module handle.
\param lpszType
 Pointer to resource type.
\param lpszName
 Pointer to resource name.
\param lParam
 Application-defined parameter.
*/
static BOOL MyEnumResNameProc(
 HANDLE hModule,
 LPCTSTR lpszType,
 LPTSTR lpszName,
 LONG lParam
 );
/**
It enumerates the "TEMPLATE" resources and setup
MyEnumResNameProc() as the callback function. This function
is called by LoadWizardConfigFile() when the wizard's project
file is not found in the users' folder.
\return
 TRUE if the resource "TEMPLATE" was found. FALSE otherwise.
*/
BOOL CreateDefaultTemplatesFromResources();
/**
It shows a dialog box asking the user to create or not the
default templates. This function is called by
LoadWizardConfigFile() when the wizard's project file is
not found in the user's folder.
\return
 TRUE if the user responded YES. FALSE otherwise.
*/
BOOL AskCreateDefaultTemplates();
/**
It asks the OS for the actual user logged in. It then creates
the templates folder for this user and set it as the current
folder. It is run in InitInstance() before showing the wizard.
*/
void InitTemplatesFolder();

The next section shows how a wizard will create a skeleton, based on your provided templates:

void CWizDlg1::OnOK() {
    // This is the function where all the macros
    // replacement is done and templates creation
    // takes place.
    if ( !pApp->LoadProjectInfo() ) {
        CPropertyPage::OnCancel();
    } pApp->ProcessTemplates();
    // this is the dialog where the text information about
    // the project will be displayed before its creation.
    CWizInfoDlg cdlg;
    pApp->GetConfirmText( cdlg.m_sText );
    int iRet = cdlg.DoModal();
    if ( IDOK == iRet ) {
        pApp->CreateProjectFiles();
        CPropertyPage::OnOK();
    }
    else {
        CPropertyPage::OnCancel();
    }
}

The following code is found in the wizard's InitInstance():

// make sure the user's folder exists
InitTemplatesFolder();
// TODO: determine if the configuration files exist under
// the user's folder.

if ( !VerifyWizardConfigFile() ) {
    return FALSE;
}
m_pMainWnd = &wizardWnd;
int iRes = wizardWnd.DoModal();
if ( IDOK == iRes ) {}
else {}

Override these two functions: CPropertyPage::OnKillActive() and CPropertyPage::OnSetActive() in every property page in your wizard. Add code in OnSetActive() to update the page's values from the WIZARDINFO data structure. Add code in OnKillActive() to enter the user's data into the WIZARDINFO data structure. See example code in the wizard.

The Templates

  • wizconfig.inf: this template is provided as an example on how the wizard could read information that goes directly into the WIZARDINFO structure.
  • wizproj.inf: it contains the list of templates files that will be part of the generated project. For every template file that you add to the wizard, and if this file is needed in the generated project, you should add a line in this file.
  • wizinfo.inf: contains text information that will be displayed just before your wizard is about to create a new project.

Remove the other three templates as they are provided as an example.

Adding New Templates

  1. Go to the resources section and select the "TEMPLATE" resource.
  2. Right-click and select Insert "TEMPLATE".
  3. A new TEMPLATE resource will be added and named as: IDR_TEMPLATE1. Change this name to something else, like the file name of the template, and make sure it is between quote marks, e.g.: "MYFILE.CPP". Also, change the location from res\ to template\.

Supported Directives

Your wizard will support the following directives that can be used in your templates:

  • $$IF
  • $$ENDIF
  • $$BEGINLOOP
  • $$ENDLOOP
  • $$//: Indicates a comment. It can only go at the beginning of a line and the whole line will be taken as comment.

Please check the MSDN documentation for more information on how to use these directives in your templates.

Notes:

The GenWiz will create a default skeleton having a CGridCtrl in the first dialog. It is just an example and it can be removed safely if not required in your wizard.

To add more dialogs or sub-sections to your wizard or modify the style of the property sheet, please refer to "Using CTreePropSheet" in this article.

History

05/14/2003: Initial release.

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here


Written By
Delphi
United States United States
Carlos Buelna works in the automotive industry.

Comments and Discussions

 
Questionhow to get user input from rich edit control of wizard and place it into CRichEditDocument ? Pin
bc05040015820-Oct-08 6:26
bc05040015820-Oct-08 6:26 
GeneralCustom Appwizard question Pin
wangxuan20056-Jun-05 23:01
wangxuan20056-Jun-05 23:01 
I'm making my own appwiz and the functionality is just fine.
it adds all neccesary files and all. But the solution explorer is a mess. I want my project neatly sorted in folders and subfolder, class by class.

I've managed to arrange it by file extension but how to I arrange the entries by filename?

e.g.

I have a folder named "WindowWrapper"
and subfolders "CBaseWindow", "CButton"... etc etc

in CBaseWindow I want to put CBaseWindow.cpp / CBaseWindow.h
in CButton I want to put CButton.cpp / CButton.h
etc.etc.

I can't find any info on doing this or another appwizard that makes use of it.

So does anyone know how to approach this?

GeneralRe: Custom Appwizard question Pin
Bob Flynn28-Oct-05 4:18
Bob Flynn28-Oct-05 4:18 
QuestionHow to Disable Maximise button in SDI application in MFC Pin
Member 57102125-Aug-04 19:48
Member 57102125-Aug-04 19:48 
GeneralProblem with IBuildProject Pin
Steven Carleton27-Jul-03 0:26
Steven Carleton27-Jul-03 0:26 
GeneralRe: Problem with IBuildProject Pin
Carlos Buelna29-Jul-03 15:51
Carlos Buelna29-Jul-03 15:51 
GeneralRe: Problem with IBuildProject Pin
joao pedro30-Nov-04 1:02
joao pedro30-Nov-04 1:02 
GeneralRe: Problem with IBuildProject Pin
joao pedro30-Nov-04 1:06
joao pedro30-Nov-04 1:06 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.