Figure 3 CCustomAppWiz

  
class CCustomAppWiz : public CObject
{
public:
   CMapStringToString m_Dictionary;

   virtual void GetPlatforms(CStringList& rPlatforms) {}

   virtual CAppWizStepDlg* Next(CAppWizStepDlg* pDlg)
       { return NULL; }
   virtual CAppWizStepDlg* Back(CAppWizStepDlg* pDlg)
       { return NULL; }

   virtual void InitCustomAppWiz() { m_Dictionary.RemoveAll(); }
   virtual void ExitCustomAppWiz() {}

   virtual LPCTSTR LoadTemplate(LPCTSTR lpszTemplateName,
        DWORD& rdwSize, HINSTANCE hInstance = NULL);

   virtual void CopyTemplate(LPCTSTR lpszInput,
                             DWORD dwSize,
                             OutputStream* pOutput);
   virtual void ProcessTemplate(LPCTSTR lpszInput,
                                DWORD dwSize,
                                OutputStream* pOutput);
   virtual void PostProcessTemplate(LPCTSTR szTemplate) {}

   virtual void CustomizeProject(IBuildProject* pProject) {}
};

Figure 4 CDialogChooser

  
class CDialogChooser
{
public:
   CDialogChooser();
   ~CDialogChooser();

   // All calls by mfcapwz.dll to this AppWizard's Next
   // and Back functions are delegated to these member
   // functions. These functions keep track of what
   // the current state of the AppWizard and which
   // step we're on
   CAppWizStepDlg* Next(CAppWizStepDlg* pDlg);
   CAppWizStepDlg* Back(CAppWizStepDlg* pDlg);

protected:
   // Current step's index into the current track
   int m_nCurrDlg;

   // Internal array of pointers to the steps
   CAppWizStepDlg* m_pDlgs[LAST_DLG + 1];

   // Current track
   int m_nTrack;
};

Figure 5 Handling the Next Button

  
CAppWizStepDlg* CMyWizardAppWiz::Next(CAppWizStepDlg* pDlg)
{
   // CMyWizardAppWizard is derived from
   // Delegate to the dialog chooser
   return m_pChooser->Next(pDlg);
}

CAppWizStepDlg* CDialogChooser::Next(CAppWizStepDlg* pDlg)
{
   ASSERT(m_nTrack == 0 || m_nTrack == 1);
   ASSERT(0 <= m_nCurrDlg && m_nCurrDlg < nLast[m_nTrack]);
   ASSERT(pDlg == m_pDlgs[(pnTrack[m_nTrack])[m_nCurrDlg]]);

   m_nCurrDlg++;

   // If the new step is the "project type" step,
   // don't display the max number
   // of steps.
   if (m_nCurrDlg == 1)
      SetNumberOfSteps(-1);

   return m_pDlgs[(pnTrack[m_nTrack])[m_nCurrDlg]];
}

Figure 6 Including Text Files as Text Resources

NEWPROJ.INF
TEMPLATE DISCARDABLE
"template\\newproj.inf"
CONFIRM.INF
TEMPLATE DISCARDABLE
"template\\confirm.inf"
README.TXT
TEMPLATE DISCARDABLE
"template\\ReadMe.txt"
ROOT.ICO
TEMPLATE DISCARDABLE
"template\\res\\root.ico"
ROOT.RC2
TEMPLATE DISCARDABLE
"template\\res\\root.rc2"
RESOURCE.H
TEMPLATE DISCARDABLE
"template\\resource.h"
ROOT.CLW
TEMPLATE DISCARDABLE
"template\\root.clw"
ROOT.CPP
TEMPLATE DISCARDABLE
"template\\root.cpp"
ROOT.H
TEMPLATE DISCARDABLE
"template\\root.h"
ROOT.RC
TEMPLATE DISCARDABLE
"template\\root.rc"
DIALOG.CPP
TEMPLATE DISCARDABLE
"template\\Dialog.cpp"
DIALOG.H
TEMPLATE DISCARDABLE
"template\\Dialog.h"
STDAFX.CPP
TEMPLATE DISCARDABLE
"template\\StdAfx.cpp"
STDAFX.H
TEMPLATE DISCARDABLE
"template\\StdAfx.h"

Figure 7 Conditional Code Inclusion

  
$$IF (USEABOUT)
void C$$Safe_root$$Dlg::OnSysCommand(UINT nID, LPARAM lParam)
{
   if ((nID & 0xFFF0) == IDM_ABOUTBOX)
   {
      CAboutDlg dlgAbout;
      dlgAbout.DoModal();
   }
   else
   {
      CDialog::OnSysCommand(nID, lParam);
   }
}
$$ENDIF

Figure 8 Handling OnDismiss

  
BOOL CCustom1Dlg::OnDismiss()
{
   if (!UpdateData(TRUE))
      return FALSE;

   if (m_bUseAboutBox)
  {
      MyWizardaw.m_Dictionary[_T("ABOUTBOX")] = _T("1");
  }
  else
  {
     MyWizardaw.m_Dictionary.RemoveKey(_T("ABOUTBOX"));
  }

   return TRUE; // return FALSE if the dialog shouldn't be
                // dismissed
}

Figure 9 The IBuildProject Interface

  
interface IBuildProject: IGenericProject
{
    /* IUnknown methods Removed for clarity */

    /* IDispatch methods Removed for clarity */

    /* IGenericProject methods */
    HRESULT get_Name(BSTR FAR* Name);
    HRESULT get_FullName(BSTR FAR* Name);
    HRESULT get_Application(IDispatch * FAR* Application);
    HRESULT get_Parent(IDispatch * FAR* Parent);
    HRESULT get_Type(BSTR FAR* pType);
    HRESULT Reserved1();
    HRESULT Reserved2();
    HRESULT Reserved3();
    HRESULT Reserved4();
    HRESULT Reserved5();
    HRESULT Reserved6();
    HRESULT Reserved7();
    HRESULT Reserved8();
    HRESULT Reserved9();
    HRESULT Reserved10();

    /* IBuildProject Methods */
    HRESULT get_Configurations(IConfigurations
                               FAR* FAR* Configs);
    HRESULT AddFile(BSTR szFile, VARIANT Reserved);
    HRESULT AddConfiguration(BSTR szConfig, VARIANT Reserved);
};

Figure 10 RTTI option switch

  
void CMyWizardAppWiz::CustomizeProject(IBuildProject* pProject)
{
   // enumerate all build configurations
   // and adds compiler/linker options.
   // Requires including the "buildguid.h" 
   // file from VC\Include\Objects
   IConfigurations* pConfigs = NULL;

   pProject->get_Configurations(&pConfigs);
   ASSERT(pConfigs);
   CComPtr<IUnknown> pUnk;

   CComQIPtr<IEnumVARIANT, &IID_IEnumVARIANT> pNewEnum;

   if (SUCCEEDED(pConfigs->get__NewEnum(&pUnk)) && pUnk != NULL)
   {
      pNewEnum = pUnk;
      VARIANT varConfig;
      VARIANT reserved;
      VariantInit(&varConfig);
      VariantInit(&reserved);
      CComQIPtr<IConfiguration, &IID_IConfiguration> pConfig;

      while (pNewEnum->Next(1, &varConfig, NULL) == S_OK)
      {
         ASSERT (varConfig.vt == VT_DISPATCH);
         pConfig = varConfig.pdispVal;
         VariantClear(&varConfig);

         // add the RTTI option
         CComBSTR bstrTool = "cl.exe";
         CComBSTR bstrOption = "/GR";

         pConfig->AddToolSettings(bstrTool, 
bstrOption, 
reserved);
      }
   }

   if ( pConfigs )
      pConfigs->Release();
}