Introduction

In order to extend the first article I wrote about a simple AppWizard for Screen Savers, I would like to contribute with this other article about a more complex AppWizard to generate the skeleton of a Win32 Application (without MFC) that lets the user choose between a Window based Win32 application and a Dialog based Win32 application, featuring the possibility of integrating the Common Controls Library (commctl32.lib) and/or the Winsock Library (ws2_32.lib).

Background

It will be useful reading the first article I wrote: Screen Saver AppWizard, to get the general idea of working with the Custom AppWizard that the Visual C++ 6.0 exports, and to get the hints for a correct compilation of the Wizard.

Using the code

As said before, this is a little more complex wizard than the Screen Saver one. In fact, this one features a step dialog needed by the wizard to determine the type of application the user requests and the types of libraries needed. Let's start creating the wizard, selecting the Custom AppWizard from the VC++ Projects tab:

Here you can notice that we specify that we'll need 1 step to configure our wizard.

Initial Environment

The initial environment after the creation of our Wizard project comes like the pane snapshots below:

The Class View Pane

The File View Pane

The Resource View Pane

As you can see in the figures, there's quite more files than the Screen Saver Wizard. This is because we indicated that we need one step configuration: this is obtained using a Dialog Resource (IDD_CUSTOM1) mapped to Dialog class CCustom1Dlg:

Customizing the Step 1 Dialog

In order to get to our goal, we need to customize the IDD_CUSTOM1 resource to feature our application's needs:

Choosing between two types of applications (Window Based or Dialog Based).

Letting specify the use of Common Controls Library.

Letting specify the use of the Winsock Library.

So, the final result of our customization will be something like:

Keep in mind that this approach is valid for any number of steps (dialogs) you specify. And you do not have to mind about the switch (to next or to previous) between step dialogs in your wizard because this behavior is handled by a specific class that the AppWizard framework supplies: the CDialogChooser class (see Class Pane figure).

Implementing the Step 1 Dialog

All the controls included in the dialog must be mapped to methods or to instance variables of the Dialog itself. So, we'll map the selection of the radio buttons (that specifies the type of application) to two relative class methods (using the ClassWizard) that will set a boolean value to indicate the application type, BOOL m_bWindowBased:

In the same way, we have to map checkboxes that indicate the type of library we want to include and initialize for the application. So, we map every checkbox resource, still using the ClassWizard, to two boolean values:

Done with the initial implementations, we can now concentrate in the logic part of creating the wizard. The CCustom1Dlg method needed to be implemented to let the wizard know the selections made by the user on what kind of application he wants, is OnDismiss():

This part needs a little attention, even if it is extremely easy to understand. Every wizard uses variables to understand what kind of decisions must be made, and it achieves this through a particular member of the main AppWizard (SimpleApplicationWizardAw) class that is a 'dictionary'. That keeps trace of the variables needed by the wizard.

These variables are set by this method:

SimpleApplicationWizardaw.m_Dictionary.SetAt("<SOME VARIABLE TO BE SET>","Yes");

and removed by this other method:

SimpleApplicationWizardaw.m_Dictionary.RemoveKey("<SOME VARIABLE TO BE REMOVED>");

These variables are then got by the framework during the creation of an application in order to do something or not to do.

The variables are useful even during the compiler/linker configuration in the main AppWizard class method void CSimpleAppWizardAppWiz::CustomizeProject(IBuildProject* pProject):

Template Files

As seen for the Screen Saver AppWizard, the Wizard needs files as templates to create the appropriate application. There are two files that are always present: confirm.inf and newproj.inf; and some others that must be added and that describe and implement the application the Wizard will create:

The files:

root.cpp

root.rc

resource.h

Safx.h

Safx.cpp

are the template files that implement the Win32 application the Wizard will create, and must be registered in the file newproj.inf.

Let's analyze the root.cpp file that is the main program of the target application:

There are some points of interest here: first, for sure you'll have noticed those strange macros $$IF ... $$ELSE ... $$ENDIF; these ones are needed by the AppWizard framework to check if some variables are present in the dictionary, and the Wizard will decide to include or not blocks of code relatively to these variables. In fact, the wizard will specify DLGWINDOWEXTRA only in the case the user selected the radio button for the Dialog Based application (and the CCustom1Dlg::OnDismiss() will create the variable in the dictionary); or again the initialization of the common controls will be included only if the checkbox in the Wizard Step Dialog will be checked. Same for the initialization code for the Winsock Library. This approach is done even in the Safx.h:

Only the header files of the appropriate kind of application will be included.

Macros are even in the newproj.inf to decide the inclusion of the .rc file (only in the case of a Dialog App):

$$// newproj.inf = template for list of template files
$$// format is 'sourceResName' \t 'destFileName'
$$// The source res name may be preceded by any
$$// combination of '=', '-', '!', '?', ':', '#', and/or '*'
$$// '=' => the resource is binary
$$// '-' => the file should not be added to the project
$$// (all files are added to the project by default)
$$// '!' => the file should be marked exclude from build
$$// '?' => the file should be treated as a help file
$$// ':' => the file should be treated as a resource
$$// '#' => the file should be treated as a template (implies '!')
$$// '*' => bypass the custom AppWizard's resources when loading
$$// if name starts with / => create new subdir
ROOT.CPP $$Root$$.cpp
RESOURCE.H resource.h
$$IF(DIALOG_BASED)
ROOT.RC $$Root$$.rc
$$ENDIF // DIALOG_BASED
SAFX.CPP StdAfx.cpp
SAFX.H StdAfx.h

Notice that the SAfx.h and SAfx.cpp files will be remapped to their normal names here.

And even in confirm.inf to describe the files that will be created by the wizard:

These files will be created:
$$Root$$.cpp
StdAfx.h
Stdafx.cpp
resource.h
$$IF(DIALOG_BASED)
$$Root$$.rc
$$ENDIF
$$IF(INIT_COMMON_CONTROLS)
This application will use the Common Controls Library
$$ENDIF
$$IF(USE_WINSOCK)
This application will use the Winsock 2 Library
$$ENDIF

Building and Running the Wizard

Building the Wizard

During compilation, the compiler could complain about not recognizing the IBuildProject interface. Three header files are then needed to be included in your Stdafx.h Custom AppWizard Project:

Running the Wizard

After compilation, the Wizard files produced are automatically copied into the Visual Studio Template directory. So, the only thing you have to do is open a new instance of Visual Studio (even if it is not needed to open a new one) and see if the 'SimpleApplicationWizard AppWizard' is present. If yes, choose it and try it:

Conclusion

Hope this article could be useful for those who want to get more from the VC++ IDE. Comments and hints are welcome, thanks.

History

22 June 2004 v1.0.

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.

Hello,
when you say intermediate files you mean .obj files?
Intermediate files are written to the output location associated to the relative configuration. Say, if you specified a "Debug" configuration your intermediate files will be stored in the "\Debug" directory, for a Release configuration in the "\Release" directory.

However all the custom configuration yout wish to provide to your project must be specified in the CSimpleApplicationWizardAppWiz::CustomizeProject(IBuildProject* pProject) method.

If you carefully read the article, you will realize that any file you wish to add, has to be specified in the newprof.inf and confirm.inf files, that contain even the macros and rules on what to add under what conditions.

I can't find these files in my Visual Studio 6 directories, where would I find them. I did a search, but was unable to find them. So, I used the
replacement AfxCore.rtf and AfxPrint.rtf files on this website. Now, I get a dialog box asking for the name of an executable file name for debug session. What does this mean?

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.

first of all very nice article. It has helped me a lot to create my first custom AppWizard.

Second... I have a question, I want to include a default icon for my application, but I'm not able to do it. I've try to add it as a TEMPLATE, but it is always imported as an ICON. Is there any way to add an icon to my (by the appwizard) generated application?

By the way, I'm trying to do a custom DLL app-wizard myself. As usual, 80% of the project was trivial, and then I met the hard part:
I'd like the debug builds of the generated DLL to call RUNDLL32, in order to enable automated 'unit testing' (of sorts).

IBuildProject::AddCustomBuildStep will add the desired commands to the 'Custom Build' tab of the project settings.

Hi Pablo,
unfortunately, I see no other chance to achieve the post build step but using the IBuildProject::AddCustomBuildStep.

For what the VS documentation asserts, that method is also used to run post build commands after the custom build itself. But as a matter of fact, the VS 6.0 documentation lacks of the VC++ part regarding the VS automation objects and their use

Try to use the AddCustomBuildStep to achive your target, I will be pleased if you can keep me informed on your enhancements in your project.

I would like to get into this some more since it appears to be a solid stepping stone for those who might want to go further into creating other types of 'applications'. IOW, by extending the performance of this tool (alias, wizard), someone would be able to generate code, classes (new, as well as existing ones from which to inherit and extend, before using), and even DLL's.

I like what your tool offers (a lot), for the possibilities I see in it. However, right now I'm getting an error stating that it cannot open a file which I KNOW exists (because I did a search and found it). Here's the error message.

Your code at first was using drive 'E' which I changed to 'C' because that's where the 'afxhelp.hm' file (for me) is located. However, even after checking to make sure the file is present, I am still getting the error when I do a compile.

It happens when compiling the Help System.
If you open with a text editor the file 'hlp\SimpleApplicationWizard.hpj' you'll see an absolute path like #include <E:\Microsoft Visual Studio\VC98\MFC\include\afxhelp.hm> inside it, so
change the path where you currently have installed Visual Studio, save and Rebuild the project.

Unfortunately the help compiler seems not to recognize the #include directive the same way the C/C++ preprocessor does: looking for files in standard directories for those surrounded by <>, and in current directory if surrounded by "".

Your suggestion worked, and following a clean compile and link, I was able to test your Wizard.

I'm happy to say, "The sample does work for both Dialog-based and Windows-based applications!" And while there is no denying that what you have provided, is a definite 'heads up' to someone wanting to write either of those type of applications from scratch, what you delivered, is exactly that, "A no frills starter application (which does compile, link, and runs properly, BTW)." However, the user better be a Win32 expert, because from that point onward, EVERYTHING will be up to him/her, with regards to 'controls', 'menus', 'child windows', 'pop-up windows', (etc.) ... EVERYTHING!

I see this tool, not as a rival to VC++ AppWizard, but more as an opportunity to create SPECIALIZED type of Windows-based (etc.) kind of applications that would avoid someone from having to go through all the various steps of AppWizard in order to get a good start on the type of application the person might want. IOW, if the person is into Artificial Intelligence, or Neural Networks type applications, this wizard would be an EXCELLENT tool to customize, in providing you with that kind of "Starter" samples, that best suit your needs.

It's a good start, and I would encourage the author to add functionalities to it (e.g. like automatically create certain 'Controls' [ready for use] that users would only have to customize, also 'read' and 'write' routines to files and certain databases.) IOW, if the user is going to be adding 'Controls' to the sample application, why not write it into the Wizard to create it automatically?