A Simple Generic Wizard






4.50/5 (6 votes)
May 13, 2003
3 min read

67627

893
A custom AppWizard application to create simple CTreePropSheet-based wizards.
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
- Go to the resources section and select the "TEMPLATE" resource.
- Right-click and select Insert "TEMPLATE".
- 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.