windows-nt/Source/XPSP1/NT/base/ntsetup/opktools/setupmgr/main/adddirs.c
2020-09-26 16:20:57 +08:00

3650 lines
102 KiB
C
Raw Permalink Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

//----------------------------------------------------------------------------
//
// Copyright (c) 1997-1999 Microsoft Corporation
// All rights reserved.
//
// File Name:
// adddirs.c
//
// Description:
// This file contains the dlgproc and friends of the additional
// dirs page.
//
//----------------------------------------------------------------------------
#include "pch.h"
#include "resource.h"
//
// These are the names of our special roots in the tree-view. They are
// loaded from the resource.
//
static TCHAR *StrOemRootName;
static TCHAR *StrSysDriveName;
static TCHAR *StrSysDirName;
static TCHAR *StrOtherDrivesName;
static TCHAR *StrPnpDriversName;
static TCHAR *StrTempFilesName;
static TCHAR *StrSysprepFilesName;
static TCHAR *StrTextmodeFilesName;
//
// The below types and vars support the extra data that we put on tree-view
// items (the lParam in a TVITEM).
//
// We ONLY put this data on our special keys.
//
// All other tree-view entries must have NULL for the lParam.
//
// This extra data on these special tree-view keys supports a number of
// activities. It helps ComputeFullPathOfItem() figure out the diskpath.
// It helps OnSelectionChange() figure out whether to grey buttons (e.g.
// you can't delete "User Supplied Files", etc...)
//
// The on-disk pathname is computed at run-time (init-time) because we
// don't know where the dist folder is until run-time.
//
enum {
KEY_OEMROOT,
KEY_SYSDRIVE,
KEY_SYSDIR,
KEY_OTHERDRIVES,
KEY_PNPDRIVERS,
KEY_TEMPFILES,
KEY_LANGFILES,
KEY_SYSPREP,
KEY_TEXTMODE
};
typedef struct {
UINT iSpecialKeyId; // which special key?
TCHAR OnDiskPathName[MAX_PATH]; // the disk-path the key maps to
TCHAR *Description; // description to display on the ui
} SPECIAL_KEY_DATA;
SPECIAL_KEY_DATA gOemRootData = { KEY_OEMROOT,
_T(""),
_T("") };
SPECIAL_KEY_DATA gSysDriveData = { KEY_SYSDRIVE,
_T(""),
_T("") };
SPECIAL_KEY_DATA gSysDirData = { KEY_SYSDIR,
_T(""),
_T("") };
SPECIAL_KEY_DATA gOtherDrivesData = { KEY_OTHERDRIVES,
_T(""),
_T("") };
SPECIAL_KEY_DATA gPnpDriversData = { KEY_PNPDRIVERS,
_T(""),
_T("") };
SPECIAL_KEY_DATA gTempFilesData = { KEY_TEMPFILES,
_T(""),
_T("") };
SPECIAL_KEY_DATA gSysprepData = { KEY_SYSPREP,
_T(""),
_T("") };
SPECIAL_KEY_DATA gTextmodeData = { KEY_TEXTMODE,
_T(""),
_T("") };
//
// The below variable is used to keep track of some info about the current
// selection on the tree-view.
//
// Each time the user changes the current selection, we update the below
// variable. Later, when the user pushes the ADD or REMOVE buttons, these
// fields are read. This isolates all of the goo about figuring out disk
// paths to the OnSelectionChange() event.
//
// We set a "Current Item" and a "Current Folder" derived from the current
// tree-view selection. User deletes the current item, and copies go into
// the current folder. CurrentItem == CurrentFolder if user selects a
// directory on the tree-view.
//
typedef struct {
TCHAR lpCurItemPath[MAX_PATH];
TCHAR lpCurFolderPath[MAX_PATH];
HTREEITEM hCurItem;
HTREEITEM hCurFolderItem;
} ADDDIRS_CURSEL_INF;
ADDDIRS_CURSEL_INF gCurSel;
//
// This type and the vars are used to cache info about the shell icons
// associated with files and dirents.
//
// As we walk directory trees, we query the shell to get the icons
// associated with that file or directory. Since we don't know how many
// icons we need before-hand, we cache unique icons onto the linked list
// below. When we're done walking trees, we make the Image_List and
// repaint the tree-view control.
//
typedef struct icon_info_tag {
HIMAGELIST hSysImageList;
int iSysIdx;
int iOurIdx;
HICON hIcon;
struct icon_info_tag *next;
} ICON_INFO;
static ICON_INFO *pHeadOfIconList = NULL;
static int gCurIconIdx = 0;
//
// This array is used by CreateSkeletonOemTree() to build an empty
// $oem$ tree.
//
TCHAR *DefaultOemTree[] = {
_T("$$"),
_T("$$\\system32"),
_T("$1"),
_T("$1\\drivers"),
_T("C"),
_T("D"),
_T("Textmode")
};
//
// Sysprep string constants
//
static TCHAR const SYSPREP_EXE[] = _T("sysprep.exe");
static TCHAR const SETUPCL_EXE[] = _T("setupcl.exe");
static TCHAR SYSPREP_FILE_EXTENSION[] = _T("exe");
static TCHAR* StrExecutableFiles;
static TCHAR* StrAllFiles;
static TCHAR g_szSysprepFileFilter[MAX_PATH + 1];
static TCHAR* StrSelectFileOrFolderToCopy = NULL;
//
// Variables to pass data between the SetupIterateCabinet function and its callback
//
static TCHAR szFileSearchingFor[MAX_PATH + 1];
static TCHAR szDestinationPath[MAX_PATH + 1];
static BOOL bFileCopiedFromCab = FALSE;
#define SIZE_DEFAULT_OEM_TREE ( sizeof(DefaultOemTree) / sizeof(TCHAR*) )
//
// The below type is needed for WalkTreeAndAddItems() which walks the
// distribution folder and populates the tree-view at init time.
//
// In the case of the TempFiles key, it maps to distfold\$oem$. When
// we look at the disk to populate this tree we must not recurse down
// into $$ $1 C D ... We only want the remainder.
//
// In the case of System Drive, we must not recurse down $oem$\$1\drivers
// because those files should appear under the special key PnPDrivers.
//
// The other special keys are safe and use INIT_NORMAL when calling
// WalkTreeAndAddItems().
//
typedef enum {
INIT_NORMAL,
INIT_SYSDRIVE,
INIT_TEMPFILES
} INIT_FLAG;
//
// Keeps track of what product they had chosen when they last got to
// this page. It is initialized to NO_PREVIOUS_PRODUCT_CHOSEN because the
// first time they get to this page they were never here before. This is
// used to determine if we should redraw the entire tree or not. The tree
// view is different for NT work/serv than it is for Sysprep.
//
#define NO_PREVIOUS_PRODUCT_CHOSEN -1
static INT g_iLastProductInstall = NO_PREVIOUS_PRODUCT_CHOSEN;
//---------------------------------------------------------------------------
//
// This section of code is the support for queuing icons.
//
// Notes:
// - Currently, there is only support for queueing icons obtained
// from the shell. Some engineering will be required to add
// fixed IDI_* icons onto the list. Please delete this comment
// if you do this work.
//
// - None of the icon routines report errors to the user. The caller
// should do that if they want to report errors.
//
//---------------------------------------------------------------------------
//---------------------------------------------------------------------------
//
// Function: FindCachedIcon
//
// Purpose: This is a support routine for cacheing icons. Don't call it,
// use LoadShellIcon().
//
// This function searches our global list of shell icon info
// and returns a pointer to that node. If we have not yet
// cached info about this icon, this function creates the node.
//
// Arguments:
// HIMAGELIST hSysImageList - the system image list where icon resides
// int SysIdx - index on the give list of icon
//
// Returns:
// Pointer to ICON_INFO node or NULL if out of memory
//
//---------------------------------------------------------------------------
ICON_INFO *FindCachedIcon(HIMAGELIST hSysImageList,
int SysIdx)
{
ICON_INFO *p = pHeadOfIconList;
//
// See if we've ever seen this icon before. We detect uniqueness
// by the imagelist,idx pair.
//
while ( p ) {
if ( p->hSysImageList == hSysImageList && p->iSysIdx == SysIdx )
break;
p = p->next;
}
//
// If we haven't cached any info about this icon yet, do so now
//
if ( ! p ) {
if ( (p = malloc(sizeof(ICON_INFO))) == NULL )
return NULL;
p->hSysImageList = hSysImageList;
p->iSysIdx = SysIdx;
p->iOurIdx = gCurIconIdx++;
p->hIcon = ImageList_GetIcon(hSysImageList, SysIdx, 0);
p->next = pHeadOfIconList;
pHeadOfIconList = p;
}
return p;
}
//---------------------------------------------------------------------------
//
// Function: LoadShellIcon
//
// Purpose: Given the full pathname of a file or directory, this function
// will query the shell and find out the icon associatted with
// that file or directory.
//
// Arguments:
// LPTSTR lpPath - full path of item
// UINT iWhichIcon - pass either SHGFI_SMALLICON or SHGFI_OPENICON
//
// Notes:
// - Since we only make 1 image list, this routine will only work
// to query small icons (either the normal or the open). It won't
// work for icons that are not 16X16.
//
//---------------------------------------------------------------------------
int LoadShellIcon(LPTSTR lpPath, UINT iWhichIcon)
{
SHFILEINFO FileInfo;
ICON_INFO *pIconInfo;
HIMAGELIST hSysImageList;
hSysImageList =
(HIMAGELIST) SHGetFileInfo(lpPath,
0,
&FileInfo,
sizeof(FileInfo),
SHGFI_SYSICONINDEX | iWhichIcon);
if ( hSysImageList == NULL )
return -1;
pIconInfo = FindCachedIcon(hSysImageList, FileInfo.iIcon);
if ( pIconInfo == NULL )
return -1;
return pIconInfo->iOurIdx;
}
//---------------------------------------------------------------------------
//
// Function: SetOurImageList
//
// Purpose: Whenever more items have been added to the tree, this function
// is called to update the icon list.
//
// Arguments:
// HWND hTv - Handle to the tree-view control
//
// Returns:
// void
//
//---------------------------------------------------------------------------
void SetOurImageList(HWND hTv)
{
HIMAGELIST hNewImageList, hCurImageList;
ICON_INFO *p = pHeadOfIconList;
int i;
//
// Make the image list now that we know how big it needs to be.
//
hNewImageList = ImageList_Create(GetSystemMetrics(SM_CXSMICON),
GetSystemMetrics(SM_CYSMICON),
ILC_MASK,
gCurIconIdx,
0);
if ( hNewImageList == NULL )
return;
//
// Add a dummy icon in each spot. This is necessary becase
// ImageList_ReplaceIcon() will only work if an icon has already been
// added to the offset in question.
//
if ( p == NULL )
return;
for ( i=0; i<gCurIconIdx; i++ )
ImageList_AddIcon(hNewImageList, p->hIcon);
//
// Now walk our list of unique icons and put them at the correct
// offset in the image_list.
//
// Note that when we walked the tree, LoadShellIcon() returned the
// index that each tree-view entry should use for it's icons. Thus,
// we must ensure that the correct icon is at the correct offset
// in the tree-view's image_list.
//
for ( p=pHeadOfIconList; p; p=p->next )
ImageList_ReplaceIcon(hNewImageList, p->iOurIdx, p->hIcon);
//
// If there is an old image_list on the tree-view, free it first
//
if ( (hCurImageList = TreeView_GetImageList(hTv, TVSIL_NORMAL)) != NULL )
ImageList_Destroy(hCurImageList);
TreeView_SetImageList(hTv, hNewImageList, TVSIL_NORMAL);
}
//---------------------------------------------------------------------------
//
// This section of code is some miscellaneous low-level support.
//
//---------------------------------------------------------------------------
//---------------------------------------------------------------------------
//
// Function: InsertSingleItem
//
// Purpose: Adds a single item to the tree view. It will be a child
// of the given hParentItem.
//
// This function lives only to support UpdateTreeViewDisplay()
// and should not be called otherwise.
//
// Arguments:
// HWND hwnd - current window
// LPTSTR lpItemName - name to display
// int SmallIconIdx - idx into the image_list
// int OpenIconIdx - idx into the image_list
// SPECIAL_KEY_DATA *lpExtraData - data to keep on the tree-view item
// HTREEITEM hParentItem - parent on the display
//
// Returns:
// HTREEITEM, NULL if it fails
//
// Notes:
// - pass NULL for lpExtraData unless it is one of our pre-defined
// special keys.
//
//---------------------------------------------------------------------------
HTREEITEM InsertSingleItem(HWND hwnd,
LPTSTR lpItemName,
int SmallIconIdx,
int OpenIconIdx,
SPECIAL_KEY_DATA *lpExtraData,
HTREEITEM hParentItem)
{
HTREEITEM hItem;
TVINSERTSTRUCT TvInsert;
UINT ItemMask = TVIF_TEXT | TVIF_PARAM;
if ( SmallIconIdx >= 0 )
{
ItemMask |= TVIF_IMAGE;
}
if ( OpenIconIdx >= 0 )
{
ItemMask |= TVIF_SELECTEDIMAGE;
}
TvInsert.hParent = hParentItem;
TvInsert.hInsertAfter = TVI_LAST;
TvInsert.item.mask = ItemMask;
TvInsert.item.pszText = lpItemName;
TvInsert.item.iImage = SmallIconIdx;
TvInsert.item.iSelectedImage = OpenIconIdx;
TvInsert.item.lParam = (LPARAM) lpExtraData;
hItem = TreeView_InsertItem(GetDlgItem(hwnd, IDC_FILETREE), &TvInsert);
if ( hItem == NULL ) {
ReportErrorId(hwnd, MSGTYPE_ERR, IDS_ERR_ADDING_TVITEM);
}
return hItem;
}
//---------------------------------------------------------------------------
//
// Function: GetItemlParam
//
// Purpose: Gets the lParam off a tree-view item. In this app, it is
// null unless it's one of our special keys.
//
// Arguments:
// HWND hTv
// HTREEITEM hItem
//
// Returns:
// Value of the lParam. In this app, it is SPECIAL_KEY_DATA*. It
// is generally null except for our few special keys.
//
//---------------------------------------------------------------------------
SPECIAL_KEY_DATA *GetItemlParam(HWND hTv, HTREEITEM hItem)
{
TVITEM TvItem;
TvItem.hItem = hItem;
TvItem.mask = TVIF_PARAM;
if ( ! TreeView_GetItem(hTv, &TvItem) )
return NULL;
return (SPECIAL_KEY_DATA*) TvItem.lParam;
}
//---------------------------------------------------------------------------
//
// Function: GetItemName
//
// Purpose: Retrieves the display name of a tree-view item given its handle.
//
// Arguments:
// HWND hTv
// HTREEITEM hItem
// LPTSTR NameBuffer - output
//
// Returns: BOOL - success
//
//---------------------------------------------------------------------------
BOOL GetItemName(HWND hTv, HTREEITEM hItem, LPTSTR NameBuffer)
{
TVITEM TvItem;
TvItem.hItem = hItem;
TvItem.mask = TVIF_TEXT;
TvItem.pszText = NameBuffer;
TvItem.cchTextMax = MAX_PATH;
return TreeView_GetItem(hTv, &TvItem);
}
//---------------------------------------------------------------------------
//
// Function: FindItemByName
//
// Purpose: Searches the children of a given tree-view item and returns
// a handle to the one with the given name.
//
// Arguments:
// HWND hTv
// HTREEITEM hItem
// LPTSTR lpName
//
// Returns:
// HTREEITEM, null if not found
//
//---------------------------------------------------------------------------
HTREEITEM FindItemByName(HWND hTv,
HTREEITEM hItem,
LPTSTR lpName)
{
HTREEITEM hChildItem;
TCHAR NameBuffer[MAX_PATH];
hChildItem = TreeView_GetChild(hTv, hItem);
while ( hChildItem != NULL ) {
if ( ! GetItemName(hTv, hChildItem, NameBuffer) )
return NULL;
if ( lstrcmpi(NameBuffer, lpName) == 0 )
break;
hChildItem = TreeView_GetNextSibling(hTv, hChildItem);
}
return hChildItem;
}
//
// The below functions build the on-disk pathname for each of our special
// root names.
//
// SysDrive maps to $oem$\$1
// SysDir maps to $oem$\$$
// OtherDrives maps to $oem$\%c (where %c is a fixed drive letter)
// PnpDrivers maps to $oem$\$1\drivers
// TempFiles maps to $oem$ (and must skip $$, $1, etc)
//
//----------------------------------------------------------------------------
//
// Function: MakeSysprepSetupFilesPath
//
// Purpose: Computes the path to where sysprep.exe and setupcl.exe are to be
// copied.
//
// Arguments: TCHAR* szSysprepPath - returns the sysprep path, assumed to be
// able to hold MAX_PATH chars
//
// Returns: VOID
//
//----------------------------------------------------------------------------
static VOID
MakeSysprepSetupFilesPath( TCHAR* szSysprepPath )
{
if (0 == ExpandEnvironmentStrings( _T("%SystemDrive%"),
szSysprepPath,
MAX_PATH ))
{
TerminateTheWizard(IDS_ERROR_OUTOFMEMORY);
}
lstrcatn( szSysprepPath, _T("\\sysprep"), MAX_PATH );
}
//----------------------------------------------------------------------------
//
// Function: MakeSysprepPath
//
// Purpose: Computes the path to where the language files for sysprep are to
// be copied.
//
// Arguments: TCHAR* szSysprepPath - returns the sysprep path
//
// Returns: VOID
//
//----------------------------------------------------------------------------
VOID
MakeSysprepPath( TCHAR* szSysprepPath )
{
MakeSysprepSetupFilesPath( szSysprepPath );
lstrcatn( szSysprepPath, _T("\\i386"), MAX_PATH );
}
//----------------------------------------------------------------------------
//
// Function: MakeTempFilesName
//
// Purpose: Computes the path to where the temp files are to be copied.
//
// Arguments: TCHAR* Buffer - returns the temp files path
//
// Returns: VOID
//
//----------------------------------------------------------------------------
VOID
MakeTempFilesName( TCHAR* Buffer )
{
lstrcpyn( Buffer,
WizGlobals.OemFilesPath, AS(Buffer) );
}
//----------------------------------------------------------------------------
//
// Function: MakePnpDriversName
//
// Purpose: Computes the path to where the Plug and Play drivers are to be
// copied.
//
// Arguments: TCHAR* Buffer - returns the path to where the PnP files go
//
// Returns: VOID
//
//----------------------------------------------------------------------------
VOID
MakePnpDriversName( TCHAR* Buffer )
{
HRESULT hrPrintf;
if( WizGlobals.iProductInstall == PRODUCT_SYSPREP )
{
ExpandEnvironmentStrings( _T("%SystemDrive%"),
Buffer,
MAX_PATH );
lstrcatn( Buffer, _T("\\drivers"), MAX_PATH );
}
else
{
hrPrintf=StringCchPrintf( Buffer, AS(Buffer),
_T("%s\\$1\\drivers"),
WizGlobals.OemFilesPath );
}
}
//----------------------------------------------------------------------------
//
// Function: MakeOemRootName
//
// Purpose: Computes the path to where the OEM files are to be copied.
//
// Arguments: TCHAR* Buffer - returns the path to where the OEM files go
//
// Returns: VOID
//
//----------------------------------------------------------------------------
VOID
MakeOemRootName( TCHAR* Buffer )
{
lstrcpyn( Buffer,
WizGlobals.OemFilesPath, AS(Buffer) );
}
//----------------------------------------------------------------------------
//
// Function: MakeSysDriveName
//
// Purpose: Computes the path to the System drive files are to be copied
//
// Arguments: TCHAR* Buffer - returns the path to the where the System drive
// files are to be copied.
//
// Returns: VOID
//
//----------------------------------------------------------------------------
VOID
MakeSysDriveName( TCHAR* Buffer )
{
HRESULT hrPrintf;
hrPrintf=StringCchPrintf( Buffer, AS(Buffer),
_T("%s\\$1"),
WizGlobals.OemFilesPath );
}
//----------------------------------------------------------------------------
//
// Function: MakeSysDirName
//
// Purpose: Computes the path to the System Directory files are to be copied
//
// Arguments: TCHAR* Buffer - returns the path to the where the System
// Directory files are to be copied.
//
// Returns: VOID
//
//----------------------------------------------------------------------------
VOID
MakeSysDirName( TCHAR* Buffer )
{
HRESULT hrPrintf;
hrPrintf=StringCchPrintf( Buffer, AS(Buffer),
_T("%s\\$$"),
WizGlobals.OemFilesPath );
}
//----------------------------------------------------------------------------
//
// Function: MakeOtherDriveName
//
// Purpose: Computes the path to the Other Drive files are to be copied
//
// Arguments: TCHAR* Buffer - returns the path to the where the Other
// Drive files are to be copied.
// TCHAR c - the drive we are making the path for
//
// Returns: VOID
//
//----------------------------------------------------------------------------
VOID
MakeOtherDriveName( TCHAR* Buffer, TCHAR c )
{
HRESULT hrPrintf;
hrPrintf=StringCchPrintf( Buffer, AS(Buffer),
c ? _T("%s\\%c") : _T("%s"),
WizGlobals.OemFilesPath, c );
}
//----------------------------------------------------------------------------
//
// Function: MakeLangFilesName
//
// Purpose: Computes the path to where the language files are to be copied.
//
// Arguments: TCHAR* Buffer - returns the path to where the language files go
//
// Returns: VOID
//
//----------------------------------------------------------------------------
VOID
MakeLangFilesName( TCHAR* Buffer )
{
if( WizGlobals.iProductInstall == PRODUCT_SYSPREP )
{
MakeSysprepPath( Buffer );
}
else
{
lstrcpyn( Buffer,
WizGlobals.OemFilesPath, AS(Buffer) );
}
}
//----------------------------------------------------------------------------
//
// Function: MakeSysprepLangFilesGroupName
//
// Purpose: Computes the path to where the language dirs are to be copied for
// the language groups.
//
// Arguments: TCHAR* Buffer - returns the path to where the language files go
//
// Returns: VOID
//
//----------------------------------------------------------------------------
VOID
MakeSysprepLangFilesGroupName( TCHAR* Buffer )
{
MakeSysprepPath( Buffer );
lstrcatn( Buffer, _T("\\lang"), MAX_PATH );
}
//----------------------------------------------------------------------------
//
// Function: MakeTextmodeFilesName
//
// Purpose: Computes the path to where the OEM boot files are to be copied
//
// Arguments: TCHAR* Buffer - returns the path to the where the textmode
// (HAL and SCSI) files are to be copied.
//
// Returns: VOID
//
//----------------------------------------------------------------------------
VOID
MakeTextmodeFilesName( TCHAR* Buffer )
{
HRESULT hrPrintf;
hrPrintf=StringCchPrintf( Buffer, AS(Buffer),
_T("%s\\Textmode"),
WizGlobals.OemFilesPath );
}
//----------------------------------------------------------------------------
//
// This section of code is for WM_INIT
//
//----------------------------------------------------------------------------
//----------------------------------------------------------------------------
//
// Function: CreateSkeletonOemTree
//
// Purpose: This function creates a skeleton OEM tree. The directories
// created are based on the global array DefaultOemTree[].
//
// If the tree already exists, this function becomes a no-op.
//
// This is called at init-time and is a support routine for
// the OnInit() routine. Don't call it otherwise.
//
// Returns:
// TRUE - no errors, proceed
// FALSE - errors making tree
//
// Notes:
// - Errors are reported to the user.
//
//----------------------------------------------------------------------------
BOOL CreateSkeletonOemTree(HWND hwnd)
{
int i;
TCHAR PathBuffer[MAX_PATH];
//
// Ensure the $oem$ dir exists
//
if ( ! EnsureDirExists(WizGlobals.OemFilesPath) ) {
ReportErrorId(hwnd,
MSGTYPE_ERR | MSGTYPE_WIN32,
IDS_ERR_CREATE_FOLDER,
WizGlobals.OemFilesPath);
return FALSE;
}
//
// Now make all of the default sub-dirs in the $oem$ tree if it is not
// a sysprep
//
if( WizGlobals.iProductInstall != PRODUCT_SYSPREP )
{
for ( i=0; i<SIZE_DEFAULT_OEM_TREE; i++ )
{
lstrcpyn(PathBuffer, WizGlobals.OemFilesPath, AS(PathBuffer));
ConcatenatePaths(PathBuffer, DefaultOemTree[i], NULL);
if ( ! EnsureDirExists(PathBuffer) )
{
ReportErrorId(hwnd,
MSGTYPE_ERR | MSGTYPE_WIN32,
IDS_ERR_CREATE_FOLDER,
PathBuffer);
return FALSE;
}
}
}
return( TRUE );
}
//---------------------------------------------------------------------------
//
// Function: WalkTreeAndAddItems
//
// Purpose: This function walks a tree on the disk and inserts each
// dirent and file found into the tree-view display.
//
// The directory tree will become a child of the given tree-view
// item as hParent.
//
// This function supports OnInitAddDirs() and should not be
// called otherwise.
//
// Arguments:
// HWND hwnd - parent window
// LPTSTR RootBuffer - tree to recurse down
// HTREEITEM hParent - the parent tree view item
// BOOL bTempFiles - special case for "Temp Files"
//
// Returns: VOID
//
// Notes:
//
// - RootBuffer must be MAX_PATH wide.
//
// - Any paths that this routine encounters that are >= MAX_PATH in
// length are silently skipped.
//
// - Always pass bTempFiles=FALSE except when filling in the TempFiles
// root in the tree-view. TempFiles maps to $oem$ on disk, but the
// other special locations are sub-dirs of this. Thus, this findfirst/
// findnext loop must skip those special cases ($1, $$, etc...)
//
//---------------------------------------------------------------------------
VOID WalkTreeAndAddItems(HWND hwnd,
LPTSTR RootBuffer,
HTREEITEM hParent,
INIT_FLAG iInitFlag)
{
LPTSTR RootPathEnd = RootBuffer + lstrlen(RootBuffer);
HANDLE FindHandle;
WIN32_FIND_DATA FindData;
HTREEITEM hItem;
int iSmallIcon;
int iOpenIcon;
TCHAR szOriginalPath[MAX_PATH] = _T("");
//
// Backup the original path so it can be restored later
//
lstrcpyn( szOriginalPath, RootBuffer, AS(szOriginalPath) );
//
// Look for * in this dir
//
if ( ! ConcatenatePaths(RootBuffer, _T("*"), NULL) ) {
//
// Restore the original path before returning
//
lstrcpyn( RootBuffer, szOriginalPath, AS(RootBuffer) );
return;
}
FindHandle = FindFirstFile(RootBuffer, &FindData);
if ( FindHandle == INVALID_HANDLE_VALUE ) {
//
// Restore the original path before returning
//
lstrcpyn( RootBuffer, szOriginalPath, AS(RootBuffer) );
return;
}
do {
*RootPathEnd = _T('\0');
//
// skip over the . and .. entries
//
if (0 == lstrcmp(FindData.cFileName, _T(".")) ||
0 == lstrcmp(FindData.cFileName, _T("..")))
continue;
//
// TempFiles maps to %distfold%\$oem$, but the others map to a
// sub-directory of $oem$, (e.g. SysDrive maps to $oem$\$1).
//
// By definition, TempFiles is anything under $oem$ that is not
// a special name. So, in the case that we are building the
// Temporary Files tree, be sure we don't recurse down into a
// special $oem$ sub-dir.
//
// Note that we do this check based on fully qualified pathnames
// else comparisons would be ambiguous.
//
if ( iInitFlag == INIT_TEMPFILES ) {
TCHAR Buffer1[MAX_PATH], Buffer2[MAX_PATH], c;
BOOL bContinue;
lstrcpyn(Buffer1, RootBuffer, AS(RootBuffer));
if ( ! ConcatenatePaths(Buffer1, FindData.cFileName, NULL) )
continue;
//
// skip %distfold%\$oem$\$1
//
MakeSysDriveName(Buffer2);
if ( _wcsicmp(Buffer1, Buffer2) == 0 )
continue;
//
// skip %distfold%\$oem$\$$
//
MakeSysDirName(Buffer2);
if ( _wcsicmp(Buffer1, Buffer2) == 0 )
continue;
//
// skip %distfold%\$oem$\textmode
//
MakeTextmodeFilesName(Buffer2);
if ( _wcsicmp(Buffer1, Buffer2) == 0 )
continue;
//
// skip %distfold%\$oem$\%c where %c is any drive letter
//
for ( bContinue=FALSE, c=_T('A'); c<=_T('Z'); c++ ) {
MakeOtherDriveName(Buffer2, c);
if ( _wcsicmp(Buffer1, Buffer2) == 0 ) {
bContinue = TRUE;
break;
}
}
if ( bContinue )
continue;
}
//
// The other special case is SYSDRIVE which maps to $oem$\$1.
//
// Whe must skip $oem$\$1\drivers because that is the root for the
// special key PnPDrivers.
//
else if ( iInitFlag == INIT_SYSDRIVE ) {
TCHAR Buffer1[MAX_PATH], Buffer2[MAX_PATH];
lstrcpyn(Buffer1, RootBuffer, AS(RootBuffer));
if ( ! ConcatenatePaths(Buffer1, FindData.cFileName, NULL) )
continue;
//
// Skip %distfold%\$oem$\$1\drivers
//
MakePnpDriversName(Buffer2);
if ( _wcsicmp(Buffer1, Buffer2) == 0 )
continue;
}
//
// Build the full pathname, if >= MAX_PATH, skip it
//
if ( ! ConcatenatePaths(RootBuffer, FindData.cFileName, NULL) )
continue;
//
// Get the shell icons associated with this file/dir
//
iSmallIcon = LoadShellIcon(RootBuffer, SHGFI_SMALLICON);
iOpenIcon = LoadShellIcon(RootBuffer, SHGFI_OPENICON);
//
// Add this item as a child of the given parent.
//
if ( (hItem = InsertSingleItem(hwnd,
FindData.cFileName,
iSmallIcon,
iOpenIcon,
NULL,
hParent)) == NULL ) {
continue;
}
//
// If this is a dirent, recurse.
//
if ( FindData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY )
WalkTreeAndAddItems(hwnd, RootBuffer, hItem, iInitFlag);
} while ( FindNextFile(FindHandle, &FindData) );
*RootPathEnd = _T('\0');
FindClose(FindHandle);
//
// Restore the original path
//
lstrcpyn( RootBuffer, szOriginalPath, AS(RootBuffer) );
}
//---------------------------------------------------------------------------
//
// Function: OnInitAddDirs
//
// Purpose: Called before the dialog first displays. We ensure that
// OemFilesPath and OemPnpDriversPath have good defaults and
// that the skeleton OEM tree exists.
//
//---------------------------------------------------------------------------
VOID OnInitAddDirs(HWND hwnd)
{
HRESULT hrPrintf;
//
// Create the $oem$, $oem$\$1, etc in %distfold%
//
// If there's any errors creating this skeleton distfolder tree, it's
// hopeless. CreateSkeletonOemTree() already reported an error, skip
// this page.
//
//
// ISSUE-2002/02/28-stelo- The fact that the user gets this error before we even
// initialize means there is no good context. Currently,
// the error message is generic.
//
// Go down this path by connecting to a share that you
// only have read access to. This is a good edit scenario.
// OemFilesPath should get computed. User could select
// Oem Branding files directly from a read-only dist folder.
// In that case, I think we no-op the copy.
//
// It must be tested what EnsureDirExists() does in this
// context.
//
if ( ! CreateSkeletonOemTree(hwnd) ) {
return;
}
//
// Load the hard-coded special root names that you see initially
// on the tree-view and their descriptions
//
StrOemRootName = MyLoadString( IDS_OEMROOT_NAME );
StrSysDriveName = MyLoadString( IDS_SYSDRIVE_NAME );
StrSysDirName = MyLoadString( IDS_SYSDIR_NAME );
StrOtherDrivesName = MyLoadString( IDS_OTHERDRIVES_NAME );
StrPnpDriversName = MyLoadString( IDS_PNPDRIVERS_NAME );
StrTempFilesName = MyLoadString( IDS_TEMPFILES_NAME );
StrSysprepFilesName = MyLoadString( IDS_SYSPREPFILES_NAME );
StrTextmodeFilesName = MyLoadString( IDS_TEXTMODE_NAME );
gOemRootData.Description = MyLoadString( IDS_ADD_DESCR_ROOT );
gSysDriveData.Description = MyLoadString( IDS_ADD_DESCR_SYSDRIVE );
gSysDirData.Description = MyLoadString( IDS_ADD_DESCR_WINNT );
gOtherDrivesData.Description = MyLoadString( IDS_ADD_DESCR_OTHER );
gPnpDriversData.Description = MyLoadString( IDS_ADD_DESCR_PNP );
gTempFilesData.Description = MyLoadString( IDS_ADD_DESCR_TEMP );
gSysprepData.Description = MyLoadString( IDS_ADD_DESCR_SYSPREP );
gTextmodeData.Description = MyLoadString( IDS_ADD_DESCR_TEXTMODE );
//
// Compute the on-disk path names for each of our special keys.
//
MakeOemRootName( gOemRootData.OnDiskPathName );
MakeSysDriveName( gSysDriveData.OnDiskPathName );
MakeSysDirName( gSysDirData.OnDiskPathName );
MakeOtherDriveName( gOtherDrivesData.OnDiskPathName, _T('\0') );
//
// Load and tweak the browse strings
//
StrExecutableFiles = MyLoadString( IDS_EXECUTABLE_FILES );
StrAllFiles = MyLoadString( IDS_ALL_FILES );
//
// The question marks (?) are just placehoders for where the NULL char
// will be inserted.
//
hrPrintf=StringCchPrintf( g_szSysprepFileFilter, AS(g_szSysprepFileFilter),
_T("%s (*.exe)?*.exe?%s (*.*)?*.*?"),
StrExecutableFiles,
StrAllFiles );
ConvertQuestionsToNull( g_szSysprepFileFilter );
//
// ISSUE-2002/02/28-stelo- leave this comment in, but move it to a more appropriate place
//
// Currently, all of our special keys use the shell folder icon
// and the shell open_folder icon. So load these icons now and
// use the same idx for all of the special keys.
//
// Note that if we make our own IDI_* for these special keys,
// you'll have to write a new routine in the icon_queing support
// to load an IDI_ and you'll need to fiddle with the icon_info
// type and call the new routine from here. You'll need to fix
// these comments too, (unless you're too much of a wimp to
// delete things that should be deleted).
//
}
//---------------------------------------------------------------------------
//
// Function: DrawSysprepTreeView
//
// Purpose:
//
// Arguments: HWND hwnd - handle to the dialog box
//
// Returns: VOID
//
//
//---------------------------------------------------------------------------
VOID
DrawSysprepTreeView( IN HWND hwnd )
{
HWND hTv = GetDlgItem(hwnd, IDC_FILETREE);
TCHAR c;
INT iSmallIcon;
INT iOpenIcon;
TCHAR szLangFilesPath[MAX_PATH + 1];
HTREEITEM hRoot,
hPnpDrivers,
hSysprepFiles,
hLangFiles;
//
// Delete the old tree so we can build it up fresh
//
TreeView_DeleteAllItems( hTv );
//
// Compute the on-disk path names for the special keys that change on
// a sysprep tree view.
//
MakePnpDriversName(gPnpDriversData.OnDiskPathName);
MakeSysprepSetupFilesPath(gSysprepData.OnDiskPathName);
MakeSysprepLangFilesGroupName(szLangFilesPath);
//
// Make sure the language files dir gets created
//
EnsureDirExists( szLangFilesPath );
iSmallIcon = LoadShellIcon(gOemRootData.OnDiskPathName, SHGFI_SMALLICON);
iOpenIcon = LoadShellIcon(gOemRootData.OnDiskPathName, SHGFI_OPENICON);
//
// The drivers dir is outside the rest of the tree so ensure it gets
// created here.
//
EnsureDirExists( gPnpDriversData.OnDiskPathName );
//
// Insert each of our special locations into the tree-view.
//
hRoot = InsertSingleItem(hwnd,
StrOemRootName,
iSmallIcon,
iOpenIcon,
&gOemRootData,
TVI_ROOT);
hPnpDrivers = InsertSingleItem(hwnd,
StrPnpDriversName,
iSmallIcon,
iOpenIcon,
&gPnpDriversData,
hRoot);
hSysprepFiles = InsertSingleItem(hwnd,
StrSysprepFilesName,
iSmallIcon,
iOpenIcon,
&gSysprepData,
hRoot);
//
// Now go out and read from the disk and populate each of these
// special trees.
//
// Note that there is nothing but special keys under OEM_ROOT,
// so there is no tree walking to do for OEM_ROOT, we've already
// added all of it's children above.
//
WalkTreeAndAddItems(hwnd,
gPnpDriversData.OnDiskPathName,
hPnpDrivers,
INIT_NORMAL);
WalkTreeAndAddItems(hwnd,
gSysprepData.OnDiskPathName,
hSysprepFiles,
INIT_TEMPFILES);
//
// Set the imagelist (the icons on the tree-view)
//
SetOurImageList(GetDlgItem(hwnd, IDC_FILETREE));
//
// All buttons are grey to start with
//
EnableWindow(GetDlgItem(hwnd, IDC_REMOVEFILE), FALSE);
EnableWindow(GetDlgItem(hwnd, IDC_ADDFILE), FALSE);
//
// Expand our special keys
//
TreeView_Expand(hTv, hRoot, TVE_EXPAND);
}
//---------------------------------------------------------------------------
//
// Function: DrawStandardTreeView
//
// Purpose:
//
// Arguments: HWND hwnd - handle to the dialog box
//
// Returns: VOID
//
//
//---------------------------------------------------------------------------
VOID
DrawStandardTreeView( IN HWND hwnd )
{
HWND hTv = GetDlgItem(hwnd, IDC_FILETREE);
TCHAR c;
INT iSmallIcon;
INT iOpenIcon;
HTREEITEM hRoot,
hSysDrive,
hSysDir,
hOtherDrives,
hPnpDrivers,
hTempFiles,
hTextmodeFiles;
//
// Delete the old tree so we can build it up fresh
//
TreeView_DeleteAllItems( hTv );
//
// Compute the on-disk path names for the special keys that change on
// a standard tree view.
//
MakePnpDriversName(gPnpDriversData.OnDiskPathName);
MakeTempFilesName(gTempFilesData.OnDiskPathName);
MakeTextmodeFilesName(gTextmodeData.OnDiskPathName);
iSmallIcon = LoadShellIcon(gOemRootData.OnDiskPathName, SHGFI_SMALLICON);
iOpenIcon = LoadShellIcon(gOemRootData.OnDiskPathName, SHGFI_OPENICON);
//
// Insert each of our special locations into the tree-view.
//
hRoot = InsertSingleItem(hwnd,
StrOemRootName,
iSmallIcon,
iOpenIcon,
&gOemRootData,
TVI_ROOT);
hSysDrive = InsertSingleItem(hwnd,
StrSysDriveName,
iSmallIcon,
iOpenIcon,
&gSysDriveData,
hRoot);
hSysDir = InsertSingleItem(hwnd,
StrSysDirName,
iSmallIcon,
iOpenIcon,
&gSysDirData,
hSysDrive);
hOtherDrives = InsertSingleItem(hwnd,
StrOtherDrivesName,
iSmallIcon,
iOpenIcon,
&gOtherDrivesData,
hRoot);
hPnpDrivers = InsertSingleItem(hwnd,
StrPnpDriversName,
iSmallIcon,
iOpenIcon,
&gPnpDriversData,
hSysDrive);
hTempFiles = InsertSingleItem(hwnd,
StrTempFilesName,
iSmallIcon,
iOpenIcon,
&gTempFilesData,
hRoot);
hTextmodeFiles = InsertSingleItem(hwnd,
StrTextmodeFilesName,
iSmallIcon,
iOpenIcon,
&gTextmodeData,
hTempFiles);
//
// Now go out and read from the disk and populate each of these
// special trees.
//
// Note that there is nothing but special keys under OEM_ROOT,
// so there is no tree walking to do for OEM_ROOT, we've already
// added all of it's children above.
//
WalkTreeAndAddItems(hwnd,
gSysDriveData.OnDiskPathName,
hSysDrive,
INIT_SYSDRIVE);
WalkTreeAndAddItems(hwnd,
gSysDirData.OnDiskPathName,
hSysDir,
INIT_NORMAL);
for ( c=_T('A'); c<=_T('Z'); c++ ) {
HTREEITEM hDrive;
TCHAR DriveLetterBuff[2];
TCHAR PathBuffer[MAX_PATH];
HRESULT hrPrintf;
MakeOtherDriveName(PathBuffer, c);
if ( DoesFolderExist(PathBuffer) ) {
hrPrintf=StringCchPrintf(DriveLetterBuff,AS(DriveLetterBuff), _T("%c"), c);
hDrive = InsertSingleItem(hwnd,
DriveLetterBuff,
iSmallIcon,
iOpenIcon,
NULL,
hOtherDrives);
WalkTreeAndAddItems(hwnd,
PathBuffer,
hDrive,
INIT_NORMAL);
}
}
WalkTreeAndAddItems(hwnd,
gPnpDriversData.OnDiskPathName,
hPnpDrivers,
INIT_NORMAL);
WalkTreeAndAddItems(hwnd,
gTempFilesData.OnDiskPathName,
hTempFiles,
INIT_TEMPFILES);
WalkTreeAndAddItems(hwnd,
gTextmodeData.OnDiskPathName,
hTextmodeFiles,
INIT_TEMPFILES);
//
// Set the imagelist (the icons on the tree-view)
//
SetOurImageList(GetDlgItem(hwnd, IDC_FILETREE));
//
// All buttons are grey to start with
//
EnableWindow(GetDlgItem(hwnd, IDC_REMOVEFILE), FALSE);
EnableWindow(GetDlgItem(hwnd, IDC_ADDFILE), FALSE);
//
// Expand our special keys
//
TreeView_Expand(hTv, hRoot, TVE_EXPAND);
}
//---------------------------------------------------------------------------
//
// Function: OnSetActiveAddDirs
//
// Purpose: Determines if the tree view needs to be redrawn and if it does,
// redraws it.
//
// Arguments: HWND hwnd - handle to the dialog box
//
// Returns: VOID
//
//---------------------------------------------------------------------------
VOID
OnSetActiveAddDirs( IN HWND hwnd )
{
if( g_iLastProductInstall == NO_PREVIOUS_PRODUCT_CHOSEN )
{
//
// This is their first time seeing this page, so draw the approprate
// tree view.
//
if( WizGlobals.iProductInstall == PRODUCT_SYSPREP )
{
DrawSysprepTreeView( hwnd );
}
else
{
DrawStandardTreeView( hwnd );
}
}
else if( g_iLastProductInstall == PRODUCT_SYSPREP && WizGlobals.iProductInstall != PRODUCT_SYSPREP )
{
DrawStandardTreeView( hwnd );
}
else if( g_iLastProductInstall != PRODUCT_SYSPREP && WizGlobals.iProductInstall == PRODUCT_SYSPREP )
{
DrawSysprepTreeView( hwnd );
}
g_iLastProductInstall = WizGlobals.iProductInstall;
}
//----------------------------------------------------------------------------
//
// This section of code implements OnTreeViewSelectionChange() which
// is called whenever the user selects a different tree-view item.
//
// On this event, we query the currently selected tree-view item and
// do some processing to figure out where this tree-view item maps to
// on disk storage. Once we figure out all we want to know about the
// current selection, we update all of the fields of gCurSel.
//
//----------------------------------------------------------------------------
//----------------------------------------------------------------------------
//
// Function: ComputeFullPathOfItem
//
// Purpose: We continually query the parent of the given tree view item
// until we get to one of our specially defined roots. Then
// we fill in the buffer with the full path name of where
// to copy files to.
//
// This function supports OnTreeViewSelectionChange() and should
// not be called otherwise. That is, we only did this processing
// when the user picks a new destination. We scribble the info
// we might need later into globals.
//
// Arguments:
// HTREEITEM hItem - handle to tree item
// LPTSTR PathBuffer - output, caller must pass a MAX_PATH buffer
// SPECIAL_KEY_DATA **SpecialRoot - output
//
// Returns: VOID
//
// Notes:
// - check PathBuffer[0] == _T('\0') for success
//
//----------------------------------------------------------------------------
VOID
ComputeFullPathOfItem(IN HWND hwnd,
IN HTREEITEM hItem,
OUT LPTSTR PathBuffer,
OUT SPECIAL_KEY_DATA **pSpecialRoot)
{
TVITEM TvItemData;
HTREEITEM hParent;
TCHAR ItemName[MAX_PATH], TempBuffer[MAX_PATH];
int NumCharsReplace;
SPECIAL_KEY_DATA *pSpecialKeyData;
PathBuffer[0] = _T('\0');
//
// The TvItemData is used to query the name of the hItem. We
// receive the name in ItemName[]. Set the fields that won't
// change in the loop.
//
TvItemData.mask = TVIF_TEXT | TVIF_PARAM;
TvItemData.pszText = ItemName;
TvItemData.cchTextMax = MAX_PATH;
//
// Now continually query the name of the parent and keep prefixing
// the parent's name to build the on-disk pathname. Stop when we
// get to one of our special root keys.
//
// We detect hitting a special key because the lParam will be
// non-null. Once we get there, we know the on-disk prefix.
//
do {
TvItemData.hItem = hItem;
TreeView_GetItem(GetDlgItem(hwnd, IDC_FILETREE), &TvItemData);
if ( TvItemData.lParam != (LPARAM) NULL )
break;
TempBuffer[0] = _T('\0');
ConcatenatePaths(TempBuffer, ItemName, PathBuffer, NULL);
lstrcpyn(PathBuffer, TempBuffer, AS(PathBuffer));
hParent = TreeView_GetParent(GetDlgItem(hwnd, IDC_FILETREE), hItem);
if ( hParent == NULL )
break;
hItem = hParent;
} while ( TRUE );
//
// The final item queried in the above loop should have a non-null
// lParam i.e. the loop should only terminate when it encounters
// a special key.
//
pSpecialKeyData = (SPECIAL_KEY_DATA*) TvItemData.lParam;
Assert(pSpecialKeyData != NULL);
//
// Prefix the disk path of our special root key onto the PathBuffer
// we computed in the loop above.
//
TempBuffer[0] = _T('\0');
ConcatenatePaths(TempBuffer,
pSpecialKeyData->OnDiskPathName,
PathBuffer,
NULL);
lstrcpyn(PathBuffer, TempBuffer, AS(PathBuffer));
//
// Give the caller the address of the special key data. This is how
// caller knows what description to display on the ui
//
(*pSpecialRoot) = pSpecialKeyData;
}
//----------------------------------------------------------------------------
//
// Function: OnTreeViewSelectionChange
//
// Purpose: This function is called when the user changes the file/dir
// selected on the tree-view.
//
// We compute the full path of the tree-view item now selected
// and update the global gCurSel.
//
//----------------------------------------------------------------------------
VOID OnTreeViewSelectionChange(HWND hwnd)
{
HWND hTv = GetDlgItem(hwnd, IDC_FILETREE);
TCHAR PathBuffer[MAX_PATH], *pEnd;
HTREEITEM hItem;
DWORD dwAttribs;
LPTSTR lpFileNamePart;
BOOL bEnableCopy;
SPECIAL_KEY_DATA *pCurItemlParam,
*pCurFolderlParam;
SPECIAL_KEY_DATA *RootSpecialData = NULL;
//
// Get the currently selected item and figure out the on-disk pathname
// for it and figure out which of the 6 special roots this item is under
// (RootSpecialData, that is).
//
hItem = TreeView_GetSelection(hTv);
ComputeFullPathOfItem(hwnd, hItem, PathBuffer, &RootSpecialData);
//
// Save this info in the global gCurSel
//
gCurSel.hCurItem = hItem;
lstrcpyn(gCurSel.lpCurItemPath, PathBuffer, AS(gCurSel.lpCurItemPath));
//
// If the CurItem is a directory, the CurFolder should be the same.
// If the CurItem is a file, the CurFolder should be the parent.
//
// Copy & NewFolder goes into the CurFolder, deletes use the CurItem.
//
lstrcpyn(gCurSel.lpCurFolderPath, gCurSel.lpCurItemPath,AS(gCurSel.lpCurFolderPath));
gCurSel.hCurFolderItem = gCurSel.hCurItem;
if ( DoesFileExist(gCurSel.lpCurItemPath) ) {
lpFileNamePart = MyGetFullPath(gCurSel.lpCurFolderPath);
if ( lpFileNamePart == NULL || *(lpFileNamePart-1) != _T('\\') )
{
AssertMsg(FALSE,
"Could not parse filename. This should not happen.");
TerminateTheWizard(IDS_ERROR_OUTOFMEMORY);
}
*(lpFileNamePart-1) = _T('\0');
gCurSel.hCurFolderItem =
TreeView_GetParent(hTv, gCurSel.hCurFolderItem);
}
//
// Grey/ungrey the buttons.
//
// If an lParam is non-null, then it's one of our special keys.
//
// User cannot delete any special keys.
//
// User can copy, unless the current dest folder is KEY_OEMROOT or
// KEY_OTHERDRIVES.
//
pCurItemlParam = GetItemlParam(hTv, gCurSel.hCurItem);
pCurFolderlParam = GetItemlParam(hTv, gCurSel.hCurFolderItem);
EnableWindow(GetDlgItem(hwnd, IDC_REMOVEFILE), pCurItemlParam == NULL);
bEnableCopy = ( pCurFolderlParam == NULL ||
( pCurFolderlParam->iSpecialKeyId != KEY_OEMROOT &&
pCurFolderlParam->iSpecialKeyId != KEY_OTHERDRIVES) );
EnableWindow(GetDlgItem(hwnd, IDC_ADDFILE), bEnableCopy);
//
// Set the description on the ui.
//
Assert(RootSpecialData != NULL);
SetDlgItemText(hwnd, IDC_ADDDIRS_DESCR, RootSpecialData->Description);
}
//---------------------------------------------------------------------------
//
// This section of code implements OnAddFileDir() which is called when
// the user pushes the ADD button. We have to allow the user to Browse
// for the source file/dir, then do the copy/tree-copy and update the
// tree-view display.
//
//---------------------------------------------------------------------------
//---------------------------------------------------------------------------
//
// Function: BrowseForSourceDir
//
// Purpose: This function pulls up the SHBrowseForFolder dialog and allows
// the user to select a directory to copy NT binaries into.
//
// Arguments:
// HWND hwnd - owning window
// LPTSTR PathBuffer - MAX_PATH buffer to receive results
//
// Returns: BOOL - TRUE if the user entered a path
// FALSE if the user canceled out of the dialog
//
// Notes:
//
//---------------------------------------------------------------------------
BOOL
BrowseForSourceDir(HWND hwnd, LPTSTR PathBuffer)
{
BROWSEINFO BrowseInf;
UINT ulFlags = BIF_BROWSEINCLUDEFILES |
BIF_RETURNONLYFSDIRS |
BIF_EDITBOX;
LPITEMIDLIST lpIdList;
if( StrSelectFileOrFolderToCopy == NULL )
{
StrSelectFileOrFolderToCopy = MyLoadString( IDS_SELECT_FILE_OR_FOLDER );
}
//
// ISSUE-2002/02/28-stelo-
// - No initial root, should go back where it was last time
// - Need a callback to grey out root of drive
//
//
// Go browse
//
BrowseInf.hwndOwner = hwnd;
BrowseInf.pidlRoot = NULL; // root == desktop
BrowseInf.pszDisplayName = PathBuffer; // output (useless)
BrowseInf.lpszTitle = StrSelectFileOrFolderToCopy;
BrowseInf.ulFlags = ulFlags;
BrowseInf.lpfn = NULL; // no callback
BrowseInf.lParam = (LPARAM) 0; // no callback
BrowseInf.iImage = 0; // no image
lpIdList = SHBrowseForFolder(&BrowseInf);
//
// Get the pathname out of this idlist returned and free up the memory
//
if ( lpIdList == NULL )
{
PathBuffer[0] = _T('\0');
return( FALSE );
}
else
{
SHGetPathFromIDList(lpIdList, PathBuffer);
MyGetFullPath(PathBuffer);
ILFreePriv(lpIdList);
return( TRUE );
}
}
//----------------------------------------------------------------------------
//
// Function: AdditionalDirsCopyTree
//
// Purpose: Copies a directory tree to the given folder. The tree-view
// display is not updated or anything of the sort. It simply
// copies the tree.
//
// This is a support routine for OnAddFileDir() and should
// not be called otherwise.
//
// Arguements:
// HWND hwnd - owning window
// LPTSTR lpSource - MAX_PATH buffer
// LPTSTR lpDest - MAX_PATH buffer
// LPTSTR lpFileNamePart - if d:\foo\bar, this should be "bar"
// HTREEITEM hParentItem - parent item on the display
//
// Returns: VOID
//
// Notes:
// - Both lpSource and lpDest must be directories, and each must
// be a MAX_PATH buffer.
//
// - Any paths >= MAX_PATH in length are silently skipped.
//
// - lpFileNamePart can point to any buffer anywhere, it does not
// have to point into lpSource or lpDest buffers. It just has to
// have the right data.
//
//----------------------------------------------------------------------------
VOID AdditionalDirsCopyTree(HWND hwnd,
LPTSTR lpSource,
LPTSTR lpDest,
LPTSTR lpFileNamePart,
HTREEITEM hParentItem)
{
LPTSTR SrcPathEnd = lpSource + lstrlen(lpSource);
LPTSTR DestPathEnd = lpDest + lstrlen(lpDest);
HANDLE FindHandle;
WIN32_FIND_DATA FindData;
int iSmallIcon, iOpenIcon;
HTREEITEM hItem;
//
// Create the folder
//
if ( ! CreateDirectory(lpDest, NULL) ) {
ReportErrorId(hwnd,
MSGTYPE_ERR | MSGTYPE_WIN32,
IDS_ERR_CREATE_FOLDER,
lpDest);
return;
}
//
// Add the tree-view item for this folder
//
iSmallIcon = LoadShellIcon(lpSource, SHGFI_SMALLICON);
iOpenIcon = LoadShellIcon(lpSource, SHGFI_OPENICON);
if ( (hItem = InsertSingleItem(hwnd,
lpFileNamePart,
iSmallIcon,
iOpenIcon,
NULL,
hParentItem)) == NULL ) {
return;
}
//
// loop over lpSource\*
//
if ( ! ConcatenatePaths(lpSource, _T("*"), NULL) )
return;
FindHandle = FindFirstFile(lpSource, &FindData);
if ( FindHandle == INVALID_HANDLE_VALUE )
return;
do {
*SrcPathEnd = _T('\0');
*DestPathEnd = _T('\0');
//
// skip over the . and .. entries
//
if (0 == lstrcmp(FindData.cFileName, _T(".")) ||
0 == lstrcmp(FindData.cFileName, _T("..")))
continue;
//
// Build the new source and dest names
//
if ( ! ConcatenatePaths(lpSource, FindData.cFileName, NULL) ||
! ConcatenatePaths(lpDest, FindData.cFileName, NULL) )
continue;
//
// If the source is a file, copy it. If it's a directory, create
// the directory at the destination and recurse.
//
if ( ! (FindData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) ) {
if ( ! CopyFile(lpSource, lpDest, TRUE) ) {
ReportErrorId(hwnd,
MSGTYPE_ERR | MSGTYPE_WIN32,
IDS_ERR_COPY_FILE,
lpSource, lpDest);
continue;
}
SetFileAttributes(lpDest, FILE_ATTRIBUTE_NORMAL);
//
// Add the tree-view item for this file
//
iSmallIcon = LoadShellIcon(lpSource, SHGFI_SMALLICON);
iOpenIcon = LoadShellIcon(lpSource, SHGFI_OPENICON);
if ( InsertSingleItem(hwnd,
FindData.cFileName,
iSmallIcon,
iOpenIcon,
NULL,
hItem) == NULL ) {
continue;
}
}
else {
AdditionalDirsCopyTree(hwnd,
lpSource,
lpDest,
FindData.cFileName,
hItem);
}
} while ( FindNextFile(FindHandle, &FindData) );
*SrcPathEnd = _T('\0');
*DestPathEnd = _T('\0');
FindClose(FindHandle);
}
//----------------------------------------------------------------------------
//
// Function: OnAddFileDir
//
// Purpose: This function is called when the AddFile button is pushed.
//
// Arguments:
// HWND hwnd - owning window
//
// Returns: VOID
//
//----------------------------------------------------------------------------
VOID OnAddFileDir(HWND hwnd)
{
TCHAR SrcPathBuffer[MAX_PATH];
TCHAR DestPathBuffer[MAX_PATH];
HTREEITEM hItem;
TCHAR *lpFileNamePart;
BOOL bSrcIsDir;
//
// Browse for the source path. User can cancel on the source, so
// be sure to check.
//
BrowseForSourceDir(hwnd, SrcPathBuffer);
if ( SrcPathBuffer[0] == _T('\0') )
return;
//
// Get the simple filename out of the src. e.g. d:\foo\bar, we want
// the "bar".
//
// Note:
//
// If there's no "bar" there, then the user probably selected the
// root of a drive (c:\ or d:\ etc.) In that case we'll give a
// generic stop message "Setup Manager cannot copy path %s". We
// can't assume in the error text that it was the root the user
// tried to copy. (although I don't know of another cause, there
// might be one).
//
// ISSUE-2002/02/28-stelo- Turn this into an assert when SHBrowseForFolder call is fixed.
//
lpFileNamePart = MyGetFullPath(SrcPathBuffer);
if ( lpFileNamePart == NULL ) {
ReportErrorId(hwnd,
MSGTYPE_ERR,
IDS_ERR_CANNOT_COPY_PATH,
SrcPathBuffer);
return;
}
//
// We will always copy into the current folder, cat the simple name
// of source onto the destination folder.
//
lstrcpyn(DestPathBuffer, gCurSel.lpCurFolderPath, AS(DestPathBuffer));
if ( ! ConcatenatePaths(DestPathBuffer, lpFileNamePart, NULL) )
return;
//
// Copy it
//
if ( DoesFolderExist(SrcPathBuffer) ) {
AdditionalDirsCopyTree(hwnd,
SrcPathBuffer,
DestPathBuffer,
lpFileNamePart,
gCurSel.hCurFolderItem);
}
else {
int iSmallIcon = LoadShellIcon(SrcPathBuffer, SHGFI_SMALLICON);
int iOpenIcon = LoadShellIcon(SrcPathBuffer, SHGFI_OPENICON);
if ( ! CopyFile(SrcPathBuffer, DestPathBuffer, TRUE) ) {
ReportErrorId(hwnd,
MSGTYPE_ERR | MSGTYPE_WIN32,
IDS_ERR_COPY_FILE,
SrcPathBuffer, DestPathBuffer);
return;
}
SetFileAttributes(DestPathBuffer, FILE_ATTRIBUTE_NORMAL);
if ( (hItem = InsertSingleItem(hwnd,
lpFileNamePart,
iSmallIcon,
iOpenIcon,
NULL,
gCurSel.hCurFolderItem)) == NULL ) {
return;
}
}
//
// We have to update the tree-view's image list because we added
// files and we may have encountered icons we haven't seen before.
//
SetOurImageList(GetDlgItem(hwnd, IDC_FILETREE));
}
//----------------------------------------------------------------------------
//
// This section of code implements OnRemoveFileDir() which is called
// when the user pushes the REMOVE button.
//
//----------------------------------------------------------------------------
//----------------------------------------------------------------------------
//
// Function: AddDirsDeleteNode
//
// Purpose: Function to delete a node from a disk. This function is
// support for OnRemoveFileDir() and should not be called
// otherwise.
//
// Arguments:
// HWND hwnd - owning window
// LPTSTR lpRoot - fully qualified root path
// LPTSTR lpFileNamePart - if lpRoot==d:\foo\bar, pass "bar"
// HTREEITEM hItem - item for lpRoot
//
// Returns:
// VOID
//
// Notes:
// - lpRoot must be a buffer MAX_PATH wide
// - Paths >= MAX_PATH in length are silently skipped
//
//----------------------------------------------------------------------------
VOID AddDirsDeleteNode(HWND hwnd,
LPTSTR lpRoot,
LPTSTR lpFileNamePart,
HTREEITEM hItem)
{
LPTSTR lpRootEnd = lpRoot + lstrlen(lpRoot);
HWND hTv = GetDlgItem(hwnd, IDC_FILETREE);
HANDLE FindHandle;
WIN32_FIND_DATA FindData;
HTREEITEM hCurItem;
//
// loop over lpRoot\*
//
if ( ! ConcatenatePaths(lpRoot, _T("*"), NULL) )
return;
FindHandle = FindFirstFile(lpRoot, &FindData);
if ( FindHandle == INVALID_HANDLE_VALUE )
return;
do {
*lpRootEnd = _T('\0');
//
// skip over the . and .. entries
//
if (0 == lstrcmp(FindData.cFileName, _T(".")) ||
0 == lstrcmp(FindData.cFileName, _T("..")))
continue;
//
// Build the new path name
//
if ( ! ConcatenatePaths(lpRoot, FindData.cFileName, NULL) )
continue;
//
// Find the corresponding tree-view item for this file/dir
//
hCurItem = FindItemByName(hTv, hItem, FindData.cFileName);
//
// If the source is a file, delete it, else recurse.
//
if ( ! (FindData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) ) {
if ( ! DeleteFile(lpRoot) ) {
ReportErrorId(hwnd,
MSGTYPE_ERR | MSGTYPE_WIN32,
IDS_ERR_DELETE_FILE,
lpRoot);
continue;
}
if ( hCurItem != NULL )
TreeView_DeleteItem(hTv, hCurItem);
}
else {
AddDirsDeleteNode(hwnd, lpRoot, FindData.cFileName, hCurItem);
}
} while ( FindNextFile(FindHandle, &FindData) );
*lpRootEnd = _T('\0');
FindClose(FindHandle);
//
// Remove the root directory
//
if ( ! RemoveDirectory(lpRoot) ) {
ReportErrorId(hwnd,
MSGTYPE_ERR | MSGTYPE_WIN32,
IDS_ERR_DELETE_FOLDER,
lpRoot);
return;
}
//
// Only delete the tree-view entry if there are no children left.
//
// There could be children left in this dir because a DeleteFile()
// could have failed on a recursive call. e.g. a read-only file.
//
if ( TreeView_GetChild(hTv, hItem) == NULL )
TreeView_DeleteItem(hTv, hItem);
}
//----------------------------------------------------------------------------
//
// Function: OnRemoveFileDir
//
// Purpose: This function is called when the RemoveFile button is pushed.
//
//----------------------------------------------------------------------------
VOID OnRemoveFileDir(HWND hwnd)
{
LPTSTR lpPath = gCurSel.lpCurItemPath;
HTREEITEM hItem = gCurSel.hCurItem;
HWND hTv = GetDlgItem(hwnd, IDC_FILETREE);
int iRet;
//
// Look at the current selection, and delete the file or delete
// the node.
//
if ( DoesFolderExist(lpPath) ) {
iRet = ReportErrorId(hwnd,
MSGTYPE_YESNO,
IDS_DELETE_FOLDER_CONFIRM,
lpPath);
if ( iRet == IDYES ) {
AddDirsDeleteNode(hwnd,
lpPath,
MyGetFullPath(lpPath),
hItem);
}
}
else {
iRet = ReportErrorId(hwnd,
MSGTYPE_YESNO,
IDS_DELETE_FILE_CONFIRM,
lpPath);
if ( iRet == IDYES ) {
if ( ! DeleteFile(lpPath) ) {
ReportErrorId(hwnd,
MSGTYPE_ERR | MSGTYPE_WIN32,
IDS_ERR_DELETE_FILE,
lpPath);
}
TreeView_DeleteItem(hTv, hItem);
}
}
}
//----------------------------------------------------------------------------
//
// This section of code is for Sysprep functions
//
//----------------------------------------------------------------------------
//----------------------------------------------------------------------------
//
// Function: CopySysprepFileLow
//
// Purpose: Copies one file to the destination specified. Handles any errors
// that occur during the copy.
//
// Arguments:
// HWND hwnd - handle to the dialog box
// TCHAR *szSysprepPathandFileNameSrc - path and file name of source file to copy
// TCHAR *szSysprepPathandFileNameDest - path and file name of where to copy the file
// TCHAR *szSysprepPath - the path to the sysprep dir
// TCHAR *szDirectory - directory to begin the search for the file
// TCHAR const * const szFileName - the file name to copy
//
// Returns: VOID
//
//----------------------------------------------------------------------------
static VOID
CopySysprepFileLow( IN HWND hwnd,
IN TCHAR *szSysprepPathandFileNameSrc,
IN TCHAR *szSysprepPathandFileNameDest,
IN TCHAR *szSysprepPath,
IN TCHAR *szDirectory,
IN TCHAR const * const szFileName )
{
BOOL bCopyRetVal = FALSE;
INT iRetVal;
//
// Only do the copy if the file isn't already there
//
if( ! DoesFileExist( szSysprepPathandFileNameDest ) )
{
//
// If the file is in the current dir, just copy it,
// else prompt the user for the location
//
if( DoesFileExist( szSysprepPathandFileNameSrc ) )
{
bCopyRetVal = CopyFile( szSysprepPathandFileNameSrc,
szSysprepPathandFileNameDest,
TRUE );
}
else
{
BOOL bCopyCompleted = FALSE;
do
{
ReportErrorId( hwnd,
MSGTYPE_ERR,
IDS_ERR_SPECIFY_FILE,
szFileName );
iRetVal = ShowBrowseFolder( hwnd,
g_szSysprepFileFilter,
SYSPREP_FILE_EXTENSION,
OFN_HIDEREADONLY | OFN_PATHMUSTEXIST,
szDirectory,
szSysprepPathandFileNameSrc );
if( ! iRetVal )
{ // user pressed cancel on the Browse dialog
ReportErrorId( hwnd,
MSGTYPE_ERR,
IDS_ERR_UNABLE_TO_COPY_SYSPREP_FILE,
szFileName,
szSysprepPath );
break;
}
if( szSysprepPathandFileNameSrc && ( lstrcmpi( MyGetFullPath( szSysprepPathandFileNameSrc ), szFileName ) == 0 ) )
{
bCopyRetVal = CopyFile( szSysprepPathandFileNameSrc,
szSysprepPathandFileNameDest,
TRUE );
bCopyCompleted = TRUE;
}
} while( ! bCopyCompleted );
}
if( ! bCopyRetVal && iRetVal )
{
ReportErrorId( hwnd,
MSGTYPE_ERR,
IDS_ERR_UNABLE_TO_COPY_SYSPREP_FILE,
szFileName,
szSysprepPath );
}
SetFileAttributes( szSysprepPathandFileNameDest,
FILE_ATTRIBUTE_NORMAL );
}
}
//----------------------------------------------------------------------------
//
// Function: CopySysprepFiles
//
// Purpose: Copies sysprep.exe and setupcl.exe to the sysprep dir on the
// system drive. Handles any errors that occur during the copy.
//
// Arguments: HWND hwnd - handle to the dialog box
//
// Returns: VOID
//
//----------------------------------------------------------------------------
static VOID
CopySysprepFiles( IN HWND hwnd )
{
BOOL bCancel;
TCHAR szSysprepPath[MAX_PATH] = _T("");
TCHAR szCurrentDirectory[MAX_PATH+1] = _T("");
TCHAR szSysprepPathandFileNameSrc[MAX_PATH] = _T("");
TCHAR szSysprepPathandFileNameDest[MAX_PATH] = _T("");
MakeSysprepSetupFilesPath( szSysprepPath );
EnsureDirExists( szSysprepPath );
// GetModuleFileName may not terminate path if path is truncated in the case
// of the file spec using the //?/ format and exceeding MAX_PATH. This should
// never happen in our case, but we will make the check and NULL terminate
if (GetModuleFileName( NULL, szCurrentDirectory, MAX_PATH) >= MAX_PATH)
szCurrentDirectory[MAX_PATH]='\0';
//
// Copy sysprep.exe to the sysprep dir
//
ConcatenatePaths( szSysprepPathandFileNameSrc,
szCurrentDirectory,
SYSPREP_EXE,
NULL );
ConcatenatePaths( szSysprepPathandFileNameDest,
szSysprepPath,
SYSPREP_EXE,
NULL );
CopySysprepFileLow( hwnd,
szSysprepPathandFileNameSrc,
szSysprepPathandFileNameDest,
szSysprepPath,
szCurrentDirectory,
SYSPREP_EXE );
//
// Store the path where the 1st file was found
//
GetPathFromPathAndFilename( szSysprepPathandFileNameSrc,
szCurrentDirectory,
AS(szCurrentDirectory));
//
// Copy setupcl.exe to the sysprep dir
//
szSysprepPathandFileNameSrc[0] = _T('\0');
szSysprepPathandFileNameDest[0] = _T('\0');
ConcatenatePaths( szSysprepPathandFileNameSrc,
szCurrentDirectory,
SETUPCL_EXE,
NULL );
ConcatenatePaths( szSysprepPathandFileNameDest,
szSysprepPath,
SETUPCL_EXE,
NULL );
CopySysprepFileLow( hwnd,
szSysprepPathandFileNameSrc,
szSysprepPathandFileNameDest,
szSysprepPath,
szCurrentDirectory,
SETUPCL_EXE );
}
//----------------------------------------------------------------------------
//
// Function: CopyAllFilesInDir
//
// Purpose:
//
// Arguments: HWND hwnd - handle to the dialog box
// TCHAR *szSrcDir - dir of all the files to copy
// TCHAR *szDestDir - dest where the files are to be copied to
//
// Returns: BOOL
// TRUE - if all the files in the dir were successfully copied
// FALSE - if there were errors during the copy
//
//----------------------------------------------------------------------------
static BOOL
CopyAllFilesInDir( IN HWND hwnd, IN TCHAR *szSrcDir, IN TCHAR *szDestDir )
{
HANDLE FindHandle;
WIN32_FIND_DATA FindData;
TCHAR szSrcRootPath[MAX_PATH];
TCHAR szDestRootPath[MAX_PATH];
TCHAR szDirectoryWithTheFiles[MAX_PATH] = _T("");
lstrcpyn( szDirectoryWithTheFiles, szSrcDir, AS(szDirectoryWithTheFiles) );
lstrcatn( szDirectoryWithTheFiles, _T("\\*"), MAX_PATH );
FindHandle = FindFirstFile( szDirectoryWithTheFiles, &FindData );
// ISSUE-2002/02/28-stelo- on the returns should I signal an error?
// ISSUE-2002/02/28-stelo- test to make sure this will copy a subdirectory if one exists
if ( FindHandle == INVALID_HANDLE_VALUE )
return( FALSE );
do {
szSrcRootPath[0] = _T('\0');
szDestRootPath[0] = _T('\0');
if( lstrcmp( FindData.cFileName, _T(".") ) == 0 ||
lstrcmp( FindData.cFileName, _T("..") ) == 0 )
continue;
if( ! ( FindData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY ) ) {
BOOL test;
ConcatenatePaths( szSrcRootPath,
szSrcDir,
FindData.cFileName,
NULL );
ConcatenatePaths( szDestRootPath,
szDestDir,
FindData.cFileName,
NULL );
CopyFile( szSrcRootPath, szDestRootPath, FALSE );
SetFileAttributes( szDestRootPath, FILE_ATTRIBUTE_NORMAL );
} else {
//
// Create the dir and recurse
//
if ( ! EnsureDirExists( szDestDir ) ) {
UINT iRet;
iRet = ReportErrorId( hwnd,
MSGTYPE_RETRYCANCEL | MSGTYPE_WIN32,
IDS_ERR_CREATE_FOLDER,
szDestDir );
return( FALSE );
}
if ( ! CopyAllFilesInDir( hwnd, szSrcRootPath, szDestDir ) ) {
return( FALSE );
}
}
} while ( FindNextFile( FindHandle, &FindData ) );
return( TRUE );
}
//----------------------------------------------------------------------------
//
// Function: FindFileInWindowsSourceFiles
//
// Purpose: To look through the windows source files for a particular file.
//
// Arguments: IN HWND hwnd - handle to the dialog box
// IN TCHAR *pszFile - the file to search for
// IN TCHAR *pszSourcePath - path to the Windows source files
// OUT TCHAR *pszFoundPath - path to the found file, if found
//
// pszFoundPath is assumed to be able to hold a string of MAX_PATH chars
//
// Returns: BOOL - TRUE if the file is found, FALSE if not
//
//----------------------------------------------------------------------------
static BOOL
FindFileInWindowsSourceFiles( IN HWND hwnd,
IN TCHAR *pszFile,
IN TCHAR *pszSourcePath,
OUT TCHAR *pszFoundPath )
{
HANDLE FindHandle;
WIN32_FIND_DATA FindData;
TCHAR szOriginalPath[MAX_PATH + 1];
TCHAR szPossiblePath[MAX_PATH + 1] = _T("");
TCHAR szPossiblePathAndFileName[MAX_PATH + 1] = _T("");
ConcatenatePaths( szPossiblePathAndFileName,
pszSourcePath,
pszFile,
NULL );
if( DoesFileExist( szPossiblePathAndFileName ) )
{
lstrcpyn( pszFoundPath, pszSourcePath, MAX_PATH );
return( TRUE );
}
//
// Look through the sub-directories for it
//
//
// Save the original path so it can be restored later
//
lstrcpyn( szOriginalPath, pszSourcePath, AS(szOriginalPath) );
//
// Look for * in this dir
//
if ( ! ConcatenatePaths( pszSourcePath, _T("*"), NULL ) )
{
//
// Restore the original path before returning
//
lstrcpyn( pszSourcePath, szOriginalPath, MAX_PATH );
return( FALSE );
}
FindHandle = FindFirstFile( pszSourcePath, &FindData );
if( FindHandle == INVALID_HANDLE_VALUE )
{
return( FALSE );
}
do {
//
// skip over the . and .. entries
//
if (0 == lstrcmp(FindData.cFileName, _T(".")) ||
0 == lstrcmp(FindData.cFileName, _T("..")))
{
continue;
}
//
// If this is a dirent, recurse.
//
if ( FindData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY )
{
BOOL bFoundStatus;
pszSourcePath[0] = _T('\0');
if ( ! ConcatenatePaths( pszSourcePath, szOriginalPath, FindData.cFileName, NULL ) )
continue;
bFoundStatus = FindFileInWindowsSourceFiles( hwnd,
pszFile,
pszSourcePath,
pszFoundPath );
if( bFoundStatus )
{
return( TRUE );
}
}
} while( FindNextFile( FindHandle, &FindData ) );
FindClose( FindHandle );
//
// Restore the original path
//
lstrcpyn( pszSourcePath, szOriginalPath, MAX_PATH );
lstrcpyn( pszFoundPath, _T(""), MAX_PATH );
return( FALSE );
}
//----------------------------------------------------------------------------
//
// Function: CabinetCallback
//
// Purpose:
//
// Arguments:
//
// Returns: LRESULT
//
//----------------------------------------------------------------------------
UINT WINAPI
CabinetCallback( IN PVOID pMyInstallData,
IN UINT Notification,
IN UINT_PTR Param1,
IN UINT_PTR Param2 )
{
UINT lRetVal = NO_ERROR;
FILE_IN_CABINET_INFO *pInfo = NULL;
switch( Notification )
{
case SPFILENOTIFY_FILEINCABINET:
pInfo = (FILE_IN_CABINET_INFO *) Param1;
lstrcpyn( pInfo->FullTargetName, szDestinationPath, AS(pInfo->FullTargetName) );
if( lstrcmpi( szFileSearchingFor, pInfo->NameInCabinet) == 0 )
{
lRetVal = FILEOP_DOIT; // Extract the file.
bFileCopiedFromCab = TRUE;
}
else
{
lRetVal = FILEOP_SKIP;
}
break;
default:
lRetVal = NO_ERROR;
break;
}
return( lRetVal );
}
//----------------------------------------------------------------------------
//
// Function: CopyFromDriverCab
//
// Purpose:
//
// Arguments:
//
// Returns: BOOL
//
//----------------------------------------------------------------------------
static BOOL
CopyFromDriverCab( TCHAR *pszCabPathAndFileName, TCHAR* pszFileName, TCHAR* pszDest )
{
lstrcpyn( szFileSearchingFor, pszFileName, AS(szFileSearchingFor) );
lstrcpyn( szDestinationPath, pszDest, AS(szDestinationPath) );
if( ! SetupIterateCabinet( pszCabPathAndFileName, 0, CabinetCallback, 0 ) )
{
return( FALSE );
}
//
// See if the file was actually found and copied.
//
if( bFileCopiedFromCab )
{
bFileCopiedFromCab = FALSE;
return( TRUE );
}
else
{
return( FALSE );
}
}
//----------------------------------------------------------------------------
//
// Function: AddCompressedFileUnderscore
//
// Purpose: Given a filename it converts it to its compressed name.
//
// Arguments:
// IN OUT TCHAR *pszFileName - the file name to change into its
// compressed file name
//
// Returns: VOID
//
//----------------------------------------------------------------------------
static VOID
AddCompressedFileUnderscore( IN OUT TCHAR *pszFileName )
{
TCHAR *pCurrentChar;
pCurrentChar = pszFileName;
while( *pCurrentChar != _T('\0') && *pCurrentChar != _T('.') )
{
pCurrentChar++;
}
if( *pCurrentChar == _T('\0') )
{
AssertMsg( FALSE,
"Filename does not contain a period(.)." );
}
else
{
pCurrentChar = pCurrentChar + 3;
*pCurrentChar = _T('_');
*(pCurrentChar + 1) = _T('\0');
}
}
//----------------------------------------------------------------------------
//
// Function: CopyAdditionalLangFiles
//
// Purpose: Copies the additional lang files that are specified in the
// intl.inf for the language groups being installed.
//
// Arguments: IN HWND hwnd - handle to the dialog box
// IN TCHAR *pszSourcePath - source path - must be at least size MAX_PATH
//
// Returns: VOID
//
//----------------------------------------------------------------------------
static VOID
CopyAdditionalLangFiles( IN HWND hwnd, IN TCHAR *pszSourcePath )
{
INT i;
INT j;
INT nEntries;
TCHAR *pszLangGroup;
INT nLangGroup;
INT nNumFilesToCopy;
TCHAR szOriginalPath[MAX_PATH + 1];
TCHAR szLangBaseDir[MAX_PATH + 1] = _T("");
TCHAR szSrc[MAX_PATH + 1] = _T("");
TCHAR szDest[MAX_PATH + 1] = _T("");
TCHAR *pFileName;
BOOL bFoundFile;
//
// Save the original path so it can be restored later
//
lstrcpyn( szOriginalPath, pszSourcePath, AS(szOriginalPath) );
MakeLangFilesName( szLangBaseDir );
if( ! EnsureDirExists( szLangBaseDir ) )
{
// ISSUE-2002/02/28-stelo- report an error
}
nEntries = GetNameListSize( &GenSettings.LanguageGroups );
for( i = 0; i < nEntries; i++ )
{
pszLangGroup = GetNameListName( &GenSettings.LanguageGroups, i );
nLangGroup = _ttoi( pszLangGroup );
nNumFilesToCopy = GetNameListSize( &FixedGlobals.LangGroupAdditionalFiles[ nLangGroup - 1 ] );
AssertMsg( nNumFilesToCopy >= 0,
"Bad value for the number of lang files to copy." );
for( j = 0; j < nNumFilesToCopy; j++ )
{
szSrc[0] = _T('\0');
szDest[0] = _T('\0');
//
// Restore the original path as it might have changed on the last iteration
//
lstrcpyn( pszSourcePath, szOriginalPath, MAX_PATH );
pFileName = GetNameListName( &FixedGlobals.LangGroupAdditionalFiles[ nLangGroup - 1 ], j );
ConcatenatePaths( szDest,
szLangBaseDir,
pFileName,
NULL );
bFoundFile = FindFileInWindowsSourceFiles( hwnd,
pFileName,
pszSourcePath,
szSrc );
ConcatenatePaths( szSrc, pFileName, NULL );
if( ! bFoundFile )
{
TCHAR szFileName[MAX_PATH + 1];
//
// If the file doesn't exist, look for the compressed form
//
lstrcpyn( szFileName, pFileName, AS(szFileName) );
AddCompressedFileUnderscore( szFileName );
bFoundFile = FindFileInWindowsSourceFiles( hwnd,
szFileName,
pszSourcePath,
szSrc );
if( bFoundFile )
{
TCHAR *pszFileName;
ConcatenatePaths( szSrc, szFileName, NULL );
pszFileName = MyGetFullPath( szDest );
AddCompressedFileUnderscore( pszFileName );
}
else
{
TCHAR szCabPathAndFileName[MAX_PATH + 1] = _T("");
ConcatenatePaths( szCabPathAndFileName,
pszSourcePath,
_T("driver.cab"),
NULL );
if( ! CopyFromDriverCab( szCabPathAndFileName, pFileName, szDest ) )
{
//
// If the compressed form isn't found either, print an error
// message and move on to the next file
//
ConcatenatePaths( szSrc,
pszSourcePath,
pFileName,
NULL );
ReportErrorId( hwnd,
MSGTYPE_ERR,
IDS_ERR_CANNOT_FIND_LANG_FILE,
szSrc );
}
continue;
}
}
CopyFile( szSrc, szDest, FALSE );
SetFileAttributes( szDest, FILE_ATTRIBUTE_NORMAL );
}
}
//
// Restore the original path
//
lstrcpyn( pszSourcePath, szOriginalPath, MAX_PATH );
}
//----------------------------------------------------------------------------
//
// Function: CopyLanguageFiles
//
// Purpose:
//
// Arguments: IN HWND hwnd - handle to the dialog box
//
// Returns: BOOL - TRUE if a path was specified to the Windows Setup files
// FALSE if not path was specifed, the user canceled the dialog
//
//----------------------------------------------------------------------------
static BOOL
CopyLanguageFiles( IN HWND hwnd )
{
INT iLangCount;
INT iNumLangsToInstall;
INT iCurrentLang = 0;
BOOL bCopySuccessful;
TCHAR *pszLangPartialPath;
TCHAR PathBuffer[MAX_PATH + 1];
TCHAR WindowsSetupPath[MAX_PATH + 1];
TCHAR szLangBaseDir[MAX_PATH + 1] = _T("");
TCHAR szLangPathAndFilesSrc[MAX_PATH + 1] = _T("");
TCHAR szLangPathAndFilesDest[MAX_PATH + 1] = _T("");
MakeLangFilesName( szLangBaseDir );
// ISSUE-2002/02/28-stelo- what if they copied they lang files by hand, then I don't
// want any pop-ups here
iNumLangsToInstall = GetNameListSize( &GenSettings.LanguageGroups );
//
// See if they are any lang files to copy
//
if( iNumLangsToInstall == 0 )
{
return( TRUE );
}
if( ! EnsureDirExists( szLangBaseDir ) )
{
// ISSUE-2002-02-28-stelo- report an error
}
do
{
BOOL bUserProvidedPath;
PathBuffer[0] = _T('\0');
WindowsSetupPath[0] = _T('\0');
ReportErrorId( hwnd,
MSGTYPE_ERR,
IDS_ERR_SPECIFY_LANG_PATH );
bUserProvidedPath = BrowseForSourceDir( hwnd, PathBuffer );
if( ! bUserProvidedPath )
{
return( FALSE );
}
ConcatenatePaths( WindowsSetupPath,
PathBuffer,
DOSNET_INF,
NULL );
} while( ! DoesFileExist( WindowsSetupPath ) );
//
// Copy the language files needed but that are not in each language groups sub-dir
//
CopyAdditionalLangFiles( hwnd, PathBuffer );
iLangCount = GetNameListSize( &GenSettings.LanguageFilePaths );
//
// Advance until we find a language that we need to copy files over for or
// we run out of languages
//
for( iCurrentLang = 0;
iCurrentLang < iLangCount;
iCurrentLang++ )
{
pszLangPartialPath = GetNameListName( &GenSettings.LanguageFilePaths,
iCurrentLang );
//
// If there is actually a lang sub-dir to copy
//
if( lstrcmp( pszLangPartialPath, _T("") ) != 0 )
{
szLangPathAndFilesSrc[0] = _T('\0');
szLangPathAndFilesDest[0] = _T('\0');
ConcatenatePaths( szLangPathAndFilesSrc,
PathBuffer,
pszLangPartialPath,
NULL );
ConcatenatePaths( szLangPathAndFilesDest,
szLangBaseDir,
pszLangPartialPath,
NULL );
//
// Copy the lang files over
//
EnsureDirExists( szLangPathAndFilesDest );
bCopySuccessful = CopyAllFilesInDir( hwnd,
szLangPathAndFilesSrc,
szLangPathAndFilesDest );
if( ! bCopySuccessful )
{
ReportErrorId( hwnd,
MSGTYPE_ERR,
IDS_ERR_UNABLE_TO_COPY_LANG_DIR,
szLangPathAndFilesSrc,
szLangPathAndFilesDest );
}
}
}
return( TRUE );
}
//----------------------------------------------------------------------------
//
// This section of code supports the WIZ_NEXT event
//
//----------------------------------------------------------------------------
//----------------------------------------------------------------------------
//
// Function: ComputePnpDriverPathR
//
// Purpose: This is support to compute OemPnpDriversPath. Every dir in
// $oem$\$1\drivers that we find a .inf file in, we add it to the
// OemPnPDriversPath.
//
// ComputePnpDriverPath() is the real entry, not this one.
//
//----------------------------------------------------------------------------
VOID ComputePnpDriverPathR(HWND hwnd, LPTSTR lpRoot)
{
LPTSTR lpRootEnd = lpRoot + lstrlen(lpRoot);
HANDLE FindHandle;
WIN32_FIND_DATA FindData;
BOOL bAddToSearchPath = FALSE;
HRESULT hrCat;
//
// loop over lpRoot\*
//
if ( ! ConcatenatePaths(lpRoot, _T("*"), NULL) )
return;
FindHandle = FindFirstFile(lpRoot, &FindData);
if ( FindHandle == INVALID_HANDLE_VALUE )
return;
//
// If it is a sysprep
//
if( WizGlobals.iProductInstall == PRODUCT_SYSPREP ) {
}
do {
*lpRootEnd = _T('\0');
//
// skip over the . and .. entries
//
if (0 == lstrcmp(FindData.cFileName, _T(".")) ||
0 == lstrcmp(FindData.cFileName, _T("..")))
continue;
//
// Build the new path name
//
if ( ! ConcatenatePaths(lpRoot, FindData.cFileName, NULL) )
continue;
//
// If we have a .inf file, mark this directory to be included
// in the search path.
//
{
int len = lstrlen(FindData.cFileName);
if ( ( len > 4 ) &&
( LSTRCMPI( &FindData.cFileName[len - 4], _T(".inf") ) == 0 ) )
{
bAddToSearchPath = TRUE;
}
}
//
// If a dirent, recurse.
//
if ( FindData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY ) {
ComputePnpDriverPathR(hwnd, lpRoot);
}
} while ( FindNextFile(FindHandle, &FindData) );
*lpRootEnd = _T('\0');
FindClose(FindHandle);
//
// If we found a .inf in this dir, add it to the PnpDriver search path
//
// Note, we don't want c:\win2000dist\$oem$\$1\drivers\foo. We only want
// part of it. We want \drivers\foo. So jump past the SysDrive portion.
//
// Note that this code assumes that \drivers is a sub-dir of the SysDir.
//
if ( bAddToSearchPath ) {
TCHAR Buffer[MAX_PATH];
int len;
if ( WizGlobals.OemPnpDriversPath[0] != _T('\0') )
hrCat=StringCchCat(WizGlobals.OemPnpDriversPath, AS(WizGlobals.OemPnpDriversPath), _T(";"));
MakeSysDriveName(Buffer);
len = lstrlen(Buffer);
hrCat=StringCchCat(WizGlobals.OemPnpDriversPath,AS(WizGlobals.OemPnpDriversPath), lpRoot + len);
}
}
//----------------------------------------------------------------------------
//
// Function: ComputeSysprepPnpPath
//
// Purpose: Determines the path to the sysprep PnP drivers.
//
// The path will always be %systemdrive%\drivers so all we have to do is
// check to see if there are any files there. If there are set the path, if
// not, then do not set the path.
//
//----------------------------------------------------------------------------
VOID
ComputeSysprepPnpPath( TCHAR* Buffer )
{
HANDLE FindHandle;
WIN32_FIND_DATA FindData;
INT iFileCount = 0;
TCHAR szDriverFiles[MAX_PATH] = _T("");
if ( ! ConcatenatePaths(szDriverFiles, Buffer, _T("*"), NULL) )
return;
FindHandle = FindFirstFile(szDriverFiles, &FindData);
if( FindHandle == INVALID_HANDLE_VALUE )
{
return;
}
do
{
iFileCount++;
} while( FindNextFile( FindHandle, &FindData ) && iFileCount < 3 );
//
// every directory contains 2 files, "." and "..", so we have to check
// for 3 or more to determine if there are any real files there.
//
if( iFileCount >= 3)
{
lstrcpyn( WizGlobals.OemPnpDriversPath, Buffer, AS(WizGlobals.OemPnpDriversPath) );
}
}
//----------------------------------------------------------------------------
//
// Function: ComputePnpDriverPath
//
// Purpose: When user hits the NEXT button, we compute the OemPnpDriversPath
// based on what we find in $oem$\$1\drivers.
//
// Every sub-dir that has a .inf in it, gets put on the path.
//
//----------------------------------------------------------------------------
VOID ComputePnpDriverPath(HWND hwnd)
{
TCHAR Buffer[MAX_PATH] = NULLSTR;
WizGlobals.OemPnpDriversPath[0] = _T('\0');
MakePnpDriversName(Buffer);
//
// If it is a sysprep, then we know the drivers are in %systemdrive%\drivers.
// Just check to see if there are any files there.
// If it is not a sysprep, then we need to cat together the paths to the
// driver directories.
//
if( WizGlobals.iProductInstall == PRODUCT_SYSPREP )
{
ComputeSysprepPnpPath( Buffer );
}
else
{
ComputePnpDriverPathR(hwnd, Buffer);
}
}
//----------------------------------------------------------------------------
//
// Function: OnWizNextAddDirs
//
// Purpose:
//
// Arguments: IN HWND hwnd - handle to the dialog box
//
// Returns: VOID
//
//----------------------------------------------------------------------------
BOOL
OnWizNextAddDirs( IN HWND hwnd )
{
BOOL bUserCanceled = TRUE;
ComputePnpDriverPath(hwnd);
//
// If it is a sysprep, make sure the sysprep directory exists
// and the appropriate files are copied
//
if( WizGlobals.iProductInstall == PRODUCT_SYSPREP )
{
TCHAR szBuffer[MAX_PATH + 1] = _T("");
//
// Make the necessary sysprep directories
//
MakeLangFilesName( szBuffer );
if ( szBuffer[0] )
{
CreateDirectory( szBuffer, NULL );
MakePnpDriversName( szBuffer );
CreateDirectory( szBuffer, NULL );
CopySysprepFiles( hwnd );
bUserCanceled = CopyLanguageFiles( hwnd );
}
}
//
// See if we need to copy the IE Branding file and if we do then copy it.
//
if( ( GenSettings.IeCustomizeMethod == IE_USE_BRANDING_FILE ) &&
( GenSettings.szInsFile[0] != _T('\0') ) )
{
if( DoesFileExist( GenSettings.szInsFile ) )
{
TCHAR szDestPathAndFileName[MAX_PATH + 1] = _T("");
TCHAR *pszFileName = NULL;
pszFileName = MyGetFullPath( GenSettings.szInsFile );
ConcatenatePaths( szDestPathAndFileName,
WizGlobals.OemFilesPath,
pszFileName,
NULL );
CopyFile( GenSettings.szInsFile, szDestPathAndFileName, FALSE );
}
else
{
ReportErrorId( hwnd,
MSGTYPE_ERR,
IDS_ERR_INS_FILE_NO_COPY,
WizGlobals.OemFilesPath );
}
}
else
{
}
//
// Route the wizard
//
return (!bUserCanceled);
}
//----------------------------------------------------------------------------
//
// This section of code is the skeleton of a dialog procedure for
// this page.
//
//----------------------------------------------------------------------------
//----------------------------------------------------------------------------
//
// Function: DlgAdditionalDirsPage
//
// Purpose: This is the dialog procedure the additional dirs page
//
//----------------------------------------------------------------------------
INT_PTR CALLBACK DlgAdditionalDirsPage(
IN HWND hwnd,
IN UINT uMsg,
IN WPARAM wParam,
IN LPARAM lParam)
{
BOOL bStatus = TRUE;
switch (uMsg) {
case WM_INITDIALOG:
OnInitAddDirs(hwnd);
break;
case WM_COMMAND:
{
int nButtonId;
switch ( nButtonId = LOWORD(wParam) ) {
case IDC_ADDFILE:
if ( HIWORD(wParam) == BN_CLICKED )
OnAddFileDir(hwnd);
break;
case IDC_REMOVEFILE:
if ( HIWORD(wParam) == BN_CLICKED )
OnRemoveFileDir(hwnd);
break;
default:
bStatus = FALSE;
break;
}
}
break;
case WM_NOTIFY:
{
LPNMHDR pnmh = (LPNMHDR) lParam;
LPNMTREEVIEW pnmtv = (LPNMTREEVIEW) lParam;
LPNMTVDISPINFO pnmdisp = (LPNMTVDISPINFO) lParam;
LPNMTVKEYDOWN pnmkey = (LPNMTVKEYDOWN) lParam;
if ( pnmh->idFrom == IDC_FILETREE ) {
switch( pnmh->code ) {
case TVN_SELCHANGED:
OnTreeViewSelectionChange(hwnd);
break;
default:
bStatus = FALSE;
break;
}
}
else {
switch( pnmh->code ) {
case PSN_QUERYCANCEL:
CancelTheWizard(hwnd);
break;
case PSN_SETACTIVE:
OnSetActiveAddDirs( hwnd );
PropSheet_SetWizButtons(GetParent(hwnd),
PSWIZB_BACK | PSWIZB_NEXT);
break;
case PSN_WIZBACK:
break;
case PSN_WIZNEXT:
if ( !OnWizNextAddDirs( hwnd ) )
WIZ_FAIL(hwnd);
break;
default:
bStatus = FALSE;
break;
}
}
}
break;
default:
bStatus = FALSE;
break;
}
return bStatus;
}