home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Tricks of the Windows Gam…ming Gurus (2nd Edition)
/
Disc2.iso
/
msdn_vcb
/
samples
/
vc98
/
appwiz
/
customwz
/
zapdlg.cpp
< prev
next >
Wrap
C/C++ Source or Header
|
1998-03-05
|
16KB
|
484 lines
// zapdlg.cpp : implementation file
//
// Copyright (c) 1985-1998, Microsoft Corporation. All rights reserved.
//
#include "stdafx.h"
#include "customwz.h"
#include "zapdlg.h"
#include "sampleaw.h"
#include "zap.h"
#include "paint.h"
#ifdef _PSEUDO_DEBUG
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif
//static CTypedPtrMap<CMapStringToPtr, CString, int> g_TemplateNameCollisions;
static CMapStringToPtr g_TemplateNameCollisions;
CStringList g_TemplateNames;
static BOOL FindDuplicateFileNames(LPTSTR pstrPath, CMapStringToPtr &rmapFileNamesFound);
void MakeTemplateName(CString& strTemplateName, LPCTSTR szFileName)
{
// Make template name upper-case
strTemplateName = szFileName;
strTemplateName.MakeUpper();
// See if this template name collides with others we're using
int nNextDigit;
if (g_TemplateNameCollisions.Lookup(strTemplateName, (void *&)nNextDigit))
{
// There is a collision, so append a digit to the name & update
// collisions map
CString strOldTemplateName = strTemplateName;
strTemplateName.Format("%s%d", (LPCTSTR) strOldTemplateName, nNextDigit);
g_TemplateNameCollisions[strOldTemplateName] = (void *) ++nNextDigit;
// Call self recusively to make sure the new name doesn't collide
MakeTemplateName(strTemplateName, strTemplateName);
}
else
{
// No collision, so update collision map for the future.
g_TemplateNameCollisions[strTemplateName] = (void *)2;
}
}
// This determines what type of project we're zapping. The heuristic used:
// if no TARGTYPE line in the project makefile (or it doesn't fit criteria below), type is unknown
// TARGTYPE line has 1 as low byte of the value, type is projExe
// TARGTYPE line has 2 as low byte of the value, type is projDLL
// TARGTYPE line has 8 as high byte of the value, type is projJava
enProjType GetProjectType(LPCTSTR lpszProjName)
{
#define SIZEBUF 256
char szBuf[SIZEBUF];
DWORD dwTargType = 0;
CStdioFile file(lpszProjName, CFile::modeRead | CFile::typeText);
// Read through makefile line by line
while (file.ReadString(szBuf, SIZEBUF-1) != NULL)
{
// Is this line a "# TARGTYPE" line? If so, grab the TARGTYPE value
if (sscanf(szBuf, _T("# TARGTYPE \"%*[^\"]\" 0x%lx"), &dwTargType) == 1)
break;
}
// Check the TARGTYPE value to see what it is
if ((dwTargType & 0xFF00) == 0x800)
return projJava;
else if ((dwTargType & 0x00FF) == 1)
return projExe;
else if ((dwTargType & 0x00FF) == 2)
return projDLL;
else
return projUnknown;
}
// This helper (used in TraverseDirectory) doubles occurrences of the backslash
// character in szPath, so the path can be enclosed in double-quotes in the
// resource file.
void DoubleSlashes(CString& strPathDblSlashes, LPCTSTR szPath)
{
strPathDblSlashes.Empty();
while (*szPath != '\0')
{
if (*szPath == '\\')
strPathDblSlashes += "\\\\";
else
strPathDblSlashes += *szPath;
szPath = _tcsinc(szPath);
}
}
// This helper (used in TraverseDirectory) determines whether we should skip
// zapping files in the given directory based on its name.
inline BOOL ShouldSkipDirectory(LPCTSTR szDir)
{
return (!_tcscmp(szDir, _T(".")) || !_tcscmp(szDir, _T(".."))
|| !_tcsicmp(szDir, _T("debug")) || !_tcsicmp(szDir, _T("release"))
|| !_tcsicmp(szDir, _T("windebug")) || !_tcsicmp(szDir, _T("winrel"))
|| !_tcsicmp(szDir, _T("pmcdebug")) || !_tcsicmp(szDir, _T("pmcrel"))
|| !_tcsicmp(szDir, _T("macdebug")) || !_tcsicmp(szDir, _T("macrel")));
}
// This helper (used in TraverseDirectory) determines whether we should skip
// zapping a file based on its extension.
inline BOOL ShouldSkipFile(LPCTSTR szExt)
{
return (szExt != NULL &&
(!_tcsicmp(szExt, _T(".mak")) || !_tcsicmp(szExt, _T(".vcp")) || !_tcsicmp(szExt, _T(".aps"))
|| !_tcsicmp(szExt, _T(".sbr")) || !_tcsicmp(szExt, _T(".plg")) || !_tcsicmp(szExt, _T(".obj"))
|| !_tcsicmp(szExt, _T(".pch")) || !_tcsicmp(szExt, _T(".res")) || !_tcsicmp(szExt, _T(".ilk"))
|| !_tcsicmp(szExt, _T(".rsc")) || !_tcsicmp(szExt, _T(".bsc")) || !_tcsicmp(szExt, _T(".exe"))
|| !_tcsicmp(szExt, _T(".bld")) || !_tcsicmp(szExt, _T(".opt")) || !_tcsicmp(szExt, _T(".pjx"))
|| !_tcsicmp(szExt, _T(".dll")) || !_tcsicmp(szExt, _T(".pdb")) || !_tcsicmp(szExt, _T(".ncb"))
|| !_tcsicmp(szExt, _T(".mdp")) || !_tcsicmp(szExt, _T(".dsw")) || !_tcsicmp(szExt, _T(".dsp"))));
}
// This recursive function is called from SetProjectFilesMacros with references
// to CStrings that correspond to template macros we're setting. It
// traverses the given directory and updates these strings with names of
// files it will zap into templates for the generated custom AppWizard.
void TraverseDirectory(const CString& strProjDir, const CString& strSubdir, CString& strProjFiles,
CString& strTemplateSubdirs, CString& strTemplateRsc, CString& strGeneratedNewProjInfoDirs)
{
WIN32_FIND_DATA ffd;
HANDLE hSearch = ::FindFirstFile(strProjDir + strSubdir + _T("*.*"), &ffd);
if (hSearch == INVALID_HANDLE_VALUE) // Bad search handle
{
if (strSubdir.IsEmpty())
// We've hit a bad search handle immediately after being called--
// the project directory is invalid. Throw exception.
ReportAndThrow(IDP_BAD_PROJDIR, strProjDir + strSubdir);
else
// We've hit a bad search handle in a recursive call--
// empty project subdirectory. Just ignore it.
return;
}
do
{
if (ffd.dwFileAttributes == FILE_ATTRIBUTE_DIRECTORY)
{
// If it's a directory, recursively call self with the directory,
// and note the directory structure in the custom AppWizard's newproj.inf
if (ShouldSkipDirectory(ffd.cFileName))
continue;
CString strNewSubdir = (strSubdir + ffd.cFileName) + _T('\n');
strGeneratedNewProjInfoDirs += _T('/') + strNewSubdir;
strTemplateSubdirs += _T('/') + (_T("template\\") + strNewSubdir);
CString strNewDir = strSubdir;
strNewDir += ffd.cFileName;
strNewDir += _T('\\');
TraverseDirectory(strProjDir, strNewDir, strProjFiles, strTemplateSubdirs,
strTemplateRsc, strGeneratedNewProjInfoDirs);
continue;
}
// Skip if it's a file we know we shouldn't copy (e.g., the makefile, .vcp file,
// .aps file, etc.).
LPCTSTR lpch = _tcsrchr(ffd.cFileName, _T('.'));
if (ShouldSkipFile(lpch))
continue;
// Skip if it has no length
if (ffd.nFileSizeLow == 0 && ffd.nFileSizeHigh == 0)
continue;
// Zap the file's name
CString strRootFile;
sampleaw.m_Zap.ZapFileName(ffd.cFileName, strRootFile, 1);
// Now that we have the info we need, update the strings we were passed
// First, the string used in CUSTMWZ.DLL's newproj.inf:
// The original project file...
strProjFiles += (_T("#") + strProjDir + strSubdir + ffd.cFileName)
// File to emit as custom AppWizard's template...
+ (_T("\ttemplate\\") + strSubdir + strRootFile + _T('\n'));
// Next, the string used in CUSTMWZ.DLL's root.rc (i.e., the
// generated custom AppWizard's resource file).
CString strSubdirDblSlashes;
DoubleSlashes(strSubdirDblSlashes, strSubdir);
CString strTemplateName;
MakeTemplateName(strTemplateName, strRootFile);
strTemplateRsc += strTemplateName +
_T("\tTEMPLATE DISCARDABLE\t\"template\\\\") + strSubdirDblSlashes + strRootFile +
_T("\"\n");
// Remember the template name for later, when we're generating lines in
// CUSTMWZ.DLL's newnwprj.inf (i.e., the generated custom AppWizard's
// newproj.inf).
g_TemplateNames.AddTail(strTemplateName);
}
while (::FindNextFile(hSearch, &ffd));
::FindClose(hSearch);
}
// This function drives it all. It's called just before the zap dialog is
// dismissed, and coordinates setting the template macros that correspond
// with the set of files to be zapped.
void SetProjectFilesMacros(LPCTSTR lpszSrcProjName)
{
// In order to allow the user to click "Finish" from the first step,
// we should gracefully handle the case that no project was named to zap.
if (lpszSrcProjName == NULL || *lpszSrcProjName == _T('\0'))
{
// If project name not specified, empty out the zapper macros
DefineBoolMacro(_T("ZAP_FULL_PATH"), FALSE);
DefineBoolMacro(_T("PROJECT_FILES"), FALSE);
DefineBoolMacro(_T("GENERATED_NEWPROJ_INF_FILES"), FALSE);
DefineBoolMacro(_T("GENERATED_NEWPROJ_INF_DIRS"), FALSE);
DefineBoolMacro(_T("TEMPLATE_RSC"), FALSE);
return;
}
// Here, we have a valid, non-NULL project name to zap. First, get its
// full path name
CString strFullPath;
_tfullpath(strFullPath.GetBuffer(_MAX_PATH), lpszSrcProjName, _MAX_PATH);
strFullPath.ReleaseBuffer();
DefineStringMacro(_T("ZAP_FULL_PATH"), strFullPath);
// Divide the path name into the various components.
CString strDrive, strDir, strName, strExt;
_tsplitpath(strFullPath, strDrive.GetBuffer(_MAX_DRIVE), strDir.GetBuffer(_MAX_DIR),
strName.GetBuffer(_MAX_FNAME), strExt.GetBuffer(_MAX_EXT));
strDrive.ReleaseBuffer();
strDir.ReleaseBuffer();
strName.ReleaseBuffer();
strExt.ReleaseBuffer();
sampleaw.m_Zap.SetRoot(strDir, strName);
DefineStringMacro(_T("ZAP_SRC_PROJ"), strName + strExt);
strDir = strDrive + strDir;
// Now, declare the strings that will be passed to TraverseDirectory, and
// filled with lists of the files we'll zap. These strings will later
// be used as template macros.
CString strProjFiles; // Will be $$PROJECT_FILES$$ in newproj.inf
CString strTemplateSubdirs; // Will be $$PROJECT_DIRS$$ in newproj.inf
CString strGeneratedNewProjInfoDirs;// Will be $$GENERATED_NEWPROJ_INF_DIRS$$
CString strTemplateRsc; // Will be $$TEMPLATE_RSC$$ in root.rc
// Set their values
g_TemplateNameCollisions.RemoveAll(); // Initialize g_TemplateNameCollisions
g_TemplateNameCollisions[_T("NEWPROJ.INF")] = (void *)2; // w/ the two canned template names
g_TemplateNameCollisions[_T("CONFIRM.INF")] = (void *)2;
g_TemplateNames.RemoveAll();
TraverseDirectory(strDir, _T(""), strProjFiles, strTemplateSubdirs, strTemplateRsc, strGeneratedNewProjInfoDirs);
// Set the template macros to their values
DefineStringMacro(_T("PROJECT_FILES"), strProjFiles);
DefineStringMacro(_T("TEMPLATE_SUBDIRS"), strTemplateSubdirs);
DefineStringMacro(_T("GENERATED_NEWPROJ_INF_DIRS"), strGeneratedNewProjInfoDirs);
DefineStringMacro(_T("TEMPLATE_RSC"), strTemplateRsc);
}
/////////////////////////////////////////////////////////////////////////////
// CZapDlg dialog
CZapDlg::CZapDlg()
: CAppWizStepDlg(CZapDlg::IDD)
{
//{{AFX_DATA_INIT(CZapDlg)
m_strProjName = _T("");
//}}AFX_DATA_INIT
}
void CZapDlg::DoDataExchange(CDataExchange* pDX)
{
CAppWizStepDlg::DoDataExchange(pDX);
//{{AFX_DATA_MAP(CZapDlg)
DDX_Text(pDX, IDC_PROJ_NAME, m_strProjName);
//}}AFX_DATA_MAP
}
BEGIN_MESSAGE_MAP(CZapDlg, CAppWizStepDlg)
//{{AFX_MSG_MAP(CZapDlg)
ON_BN_CLICKED(IDC_BROWSE, OnBrowse)
ON_WM_PAINT()
//}}AFX_MSG_MAP
END_MESSAGE_MAP()
/////////////////////////////////////////////////////////////////////////////
// CZapDlg message handlers
// Validate the name of the project to zap, and set zap-related template
// macros before dismissing
BOOL CZapDlg::OnDismiss()
{
UpdateData(TRUE);
// If the user specifies a nonempty, nonexistent path, balk
if (!m_strProjName.IsEmpty()
&& GetFileAttributes(m_strProjName) == 0xffffffff)
return ReportError(IDP_ZAP_CANT_OPEN_FILE, m_strProjName);
else if (m_strProjName.IsEmpty()) // no project name, no checking we can do
return TRUE;
// WARNING: continuing past this point with an empty project name could yield
// unpredictable actions as _splitpath doesn't check for a non-NULL path
// before trying to break it up into drive and directory.
CHAR rgchPathBuffer[_MAX_PATH];
CHAR rgchDrive[_MAX_DRIVE];
CHAR rgchDirectory[_MAX_DIR];
_splitpath(m_strProjName, rgchDrive, rgchDirectory, NULL, NULL);
_makepath(rgchPathBuffer, rgchDrive, rgchDirectory, NULL, NULL);
CMapStringToPtr map;
BOOL fFoundDuplicate = FindDuplicateFileNames(rgchPathBuffer, map);
if (fFoundDuplicate)
return ReportError(IDP_ZAP_BAD_PROJECT, m_strProjName);
if (m_strProjName.IsEmpty())
return ReportError(IDP_ZAP_CANT_OPEN_FILE, m_strProjName);
// Now set the macros corresponding to the files we zap into templates.
// This may throw an exception if it runs into an error. In that
// case, we'll return FALSE.
TRY
{
enProjType projType = GetProjectType(m_strProjName);
if (projType != projExe && projType != projDLL)
return ReportError(IDP_ZAP_NOT_CPP, m_strProjName);
DefineBoolMacro(_T("CREATE_DLL_PROJECT"), projType == projDLL);
SetProjectFilesMacros(m_strProjName);
}
CATCH(CFileException, e)
{
return ReportError(IDP_ZAP_CANT_OPEN_FILE, m_strProjName);
}
AND_CATCH(CException, e)
{
return FALSE;
}
END_CATCH
// If we got this far, we've successfully built our list of files
// to zap. We're ready to continue.
return TRUE;
}
#define BROWSE_DLG_HELP_ID 17304
// Handle the "Browse..." button by popping up a file navigator.
void CZapDlg::OnBrowse()
{
CString strBrowseTitle, strFilterString;
strBrowseTitle.LoadString(IDS_BROWSE_TITLE);
strFilterString.LoadString(IDS_BROWSE_FILTER);
CFileDialog dlg(
TRUE, // Open File Dialog
_T("dsp"), // Default extension
NULL, // No default filename
OFN_HIDEREADONLY | OFN_OVERWRITEPROMPT, // OPENFILENAME flags
strFilterString); // Filter strings
dlg.m_ofn.lpstrTitle = strBrowseTitle;
dlg.SetHelpID(BROWSE_DLG_HELP_ID);
if (dlg.DoModal() == IDOK)
m_strProjName = dlg.GetPathName();
UpdateData(FALSE);
}
#define STEP2_LEFT 8
#define STEP2_TOP 40
#define STEP2_WIDTH 179
#define STEP2_HEIGHT 224
// Override OnPaint to draw the one static picture on the left side
void CZapDlg::OnPaint()
{
CPaintDC dc(this); // device context for painting
PaintBackground(&dc, this);
CDC dcMem;
if (!dcMem.CreateCompatibleDC(&dc))
return;
// Picture
PaintBitmap(IDB_STEP2, STEP2_LEFT, STEP2_TOP, STEP2_WIDTH, STEP2_HEIGHT, &dc, &dcMem);
}
BOOL FindDuplicateFileNames(LPTSTR ptstrPath, CMapStringToPtr &rmap)
{
WIN32_FIND_DATA wfd;
BOOL fResult = FALSE; // Assume no duplicates
size_t cchOldLength;
#if defined(_UNICODE)
cchOldLength = wcslen(ptstrPath);
#else
cchOldLength = strlen(ptstrPath);
#endif
TCHAR *ptchOldNull = &ptstrPath[cchOldLength];
_tcscpy(ptchOldNull, TEXT("*.*"));
HANDLE hFind = ::FindFirstFile(ptstrPath, &wfd);
if (hFind != INVALID_HANDLE_VALUE)
{
// We started a good search. Let's handle each file now.
for (;;)
{
if ((_tcscmp(wfd.cFileName, TEXT(".")) != 0) &&
(_tcscmp(wfd.cFileName, TEXT("..")) != 0))
{
if ((wfd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) != 0)
{
// We've got a subdirectory. Recurse.
_tcscpy(ptchOldNull, wfd.cFileName);
_tcscat(ptchOldNull, TEXT("\\"));
if (FindDuplicateFileNames(ptstrPath, rmap))
{
fResult = TRUE;
break;
}
}
else
{
// First, canonicalize the case of the file...
_tcsupr(wfd.cFileName);
VOID *pvTemp;
// If it's in the map, look out!
if (rmap.Lookup(wfd.cFileName, pvTemp))
{
fResult = TRUE;
break;
}
// It wasn't there and it isn't a generated file we don't care about; put a NULL in the list.
CString strName = wfd.cFileName;
CString strExt;
int index = strName.ReverseFind('.');
if( index != -1 ){
strExt = strName.Right( strName.GetLength() - index );
}
if( strExt != ".EXE" && strExt != ".OBJ" && strExt != ".RES" && strExt != ".CNT" && strExt != ".HLP" ) {
rmap.SetAt(wfd.cFileName, NULL);
}
}
}
// I hate to lose status if something more erroneous occurred
// here, but it seems harmless. -mgrier 6/12/96
if (!::FindNextFile(hFind, &wfd))
break;
}
::FindClose(hFind);
}
ptchOldNull = TEXT('\0');
return fResult;
}