Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

1039 lines
25 KiB

//----------------------------------------------------------------------------
//
// Copyright (c) 1997-1999 Microsoft Corporation
// All rights reserved.
//
// File Name:
// pathsup.c
//
// Description:
// Some path support routines.
//
//----------------------------------------------------------------------------
#include "pch.h"
static TCHAR g_szSetupMgrFileExtensions[MAX_PATH + 1] = _T("");
//---------------------------------------------------------------------------
//
// Function: CleanTrailingSlashes
//
// Purpose: Cleans up trailing slashes off pathnames. This is a support
// routine for ConcatenatePaths().
//
// Arguments:
// LPTSTR lpBuffer - MAX_PATH buffer
//
// Returns: VOID
//
//---------------------------------------------------------------------------
static VOID CleanTrailingSlashes(LPTSTR lpBuffer)
{
TCHAR *p = lpBuffer + lstrlen(lpBuffer) - 1;
while ( p >= lpBuffer && *p == _T('\\') )
*p-- = _T('\0');
}
//---------------------------------------------------------------------------
//
// Function: CleanLeadingSlashes
//
// Purpose: Removes leading slashes from the given string.
//
// Arguments:
// LPTSTR lpStr - str to clean
//
// Returns:
// A pointer to the character after the run of back-slashes.
//
//---------------------------------------------------------------------------
static LPTSTR CleanLeadingSlashes(LPTSTR lpStr)
{
TCHAR *p=lpStr;
while ( *p && *p == TEXT('\\') )
p++;
return p;
}
//---------------------------------------------------------------------------
//
// Function: ConcatenatePaths
//
// Purpose: This function cats path components together. It makes sure
// that there are not multiple slashes separating each item, and
// that there isn't a trailing back-slash.
//
// The last string passed must be NULL.
//
// Arguments:
// LPTSTR lpBuffer - MAX_PATH buffer
// ...
//
// Returns:
// TRUE if all is ok
// FALSE if resultant string is >= MAX_PATH chars
//
//---------------------------------------------------------------------------
BOOL __cdecl ConcatenatePaths(LPTSTR lpBuffer, ...)
{
LPTSTR lpString;
va_list arglist;
HRESULT hrCat;
va_start(arglist, lpBuffer);
lpString = va_arg(arglist, LPTSTR);
while ( lpString != NULL ) {
if ( lstrlen(lpBuffer) + lstrlen(lpString) >= MAX_PATH )
return FALSE;
lpString = CleanLeadingSlashes(lpString);
CleanTrailingSlashes(lpString);
CleanTrailingSlashes(lpBuffer);
if ( lpBuffer[0] ) {
hrCat=StringCchCat(lpBuffer, MAX_PATH, _T("\\"));
hrCat=StringCchCat(lpBuffer, MAX_PATH, lpString);
} else {
lstrcpyn(lpBuffer, lpString, MAX_PATH);
}
lpString = va_arg(arglist, LPTSTR);
}
va_end(arglist);
return TRUE;
}
//---------------------------------------------------------------------------
//
// Function: ParseDriveLetterOrUnc
//
// Purpose: Will parse past the \\srv\share\ or D:\ and return a pointer
// to the character after that mess.
//
// Returns: Pointer to the pathname 1 char past the volume descriptor,
// NULL if errors. GetLastError() will be valid when NULL
// is returned.
//
// Notes:
// - Only pass in fully qualified pathnames. Use MyGetFullPath().
//
//---------------------------------------------------------------------------
LPTSTR ParseDriveLetterOrUnc(LPTSTR lpFileName)
{
TCHAR *p=NULL;
//
// If path is of form \\srv\share\, get a pointer past the whole mess.
//
// Note we start at lpFileName+3 because "srv" (in this example) must
// be at least 1 character.
//
if ( lpFileName[0] == _T('\\') && lpFileName[1] == _T('\\') ) {
//
// Move past the computer name
//
p = lpFileName + 2;
while( *p != _T('\\') )
{
if( *p == _T('\0') )
{
SetLastError( ERROR_BAD_PATHNAME );
return( NULL );
}
p++;
}
p++;
//
// Scan past the share name
//
while( *p != _T('\\') )
{
if( *p == _T('\0') )
{
SetLastError( ERROR_BAD_PATHNAME );
return( NULL );
}
p++;
}
p++;
}
//
// Get past the D:\ if path is of that form
//
if ( towupper(lpFileName[0]) >= _T('A') &&
towupper(lpFileName[0]) <= _T('Z') &&
lpFileName[1] == _T(':') &&
lpFileName[2] == _T('\\') ) {
p = lpFileName + 3;
}
//
// If we never set *p, then the path is not in a valid form.
//
if ( p == NULL ) {
SetLastError(ERROR_BAD_PATHNAME);
return NULL;
}
return p;
}
//---------------------------------------------------------------------------
//
// Function: GetComputerNameFromUnc
//
// Purpose: To strip out the computer name from a full UNC path.
//
// Example: \\computername\sharename\dir1\dir2 would return
// \\computername
//
// Arguments:
//
// szComputerName is assumed to be MAX_PATH length
//
// Returns: VOID
//
// Notes:
// - Only pass in fully qualified pathnames. Use MyGetFullPath().
//
//---------------------------------------------------------------------------
VOID
GetComputerNameFromUnc( IN TCHAR *szFullUncPath,
OUT TCHAR *szComputerName,
IN DWORD cbSize) {
TCHAR *pString;
AssertMsg( szFullUncPath[0] == _T('\\') && szFullUncPath[1] == _T('\\'),
"szFullUncPath is not a well formed net path" );
lstrcpyn( szComputerName, szFullUncPath, cbSize );
pString = &(szComputerName[2]);
//
// Scan past the computer name
//
while( *pString != _T('\\') )
{
if( *pString == _T('\0') )
{
AssertMsg( FALSE,
"Bad UNC path");
return;
}
pString++;
}
*pString = _T('\0');
}
//---------------------------------------------------------------------------
//
// Function: GetComputerAndShareNameFromUnc
//
// Purpose: To strip out the computer and share name from a full UNC path.
//
// Example: \\computername\sharename\dir1\dir2 would return
// \\computername\sharename
//
// Arguments:
//
// szComputerAndShareName is assumed to be MAX_PATH length
//
// Returns: VOID
//
// Notes:
// - Only pass in fully qualified pathnames. Use MyGetFullPath().
//
//---------------------------------------------------------------------------
VOID
GetComputerAndShareNameFromUnc( IN TCHAR *szFullUncPath,
OUT TCHAR *szComputerAndShareName,
IN DWORD cbSize) {
TCHAR *pString;
AssertMsg( szFullUncPath[0] == _T('\\') && szFullUncPath[1] == _T('\\'),
"szFullUncPath is not a well formed net path");
lstrcpyn( szComputerAndShareName, szFullUncPath, cbSize );
pString = &(szComputerAndShareName[2]);
//
// Scan past the computer name
//
while( *pString != _T('\\') )
{
if( *pString == _T('\0') )
{
AssertMsg( FALSE,
"Bad UNC path");
return;
}
pString++;
}
pString++;
//
// Scan past the share name
//
while( *pString != _T('\\') )
{
if( *pString == _T('\0') )
{
//
// already just the computer and share name so just return
//
return;
}
pString++;
}
*pString = _T('\0');
}
//---------------------------------------------------------------------------
//
// Function: MyGetFullPath
//
// Purpose: Small wrapper on GetFullPathName(). It assumes the buffer
// is MAX_PATH.
//
// Returns:
// Pointer to filename part in the buffer, NULL if errors. The
// Win32 error code will be valid if fails.
//
// Notes:
// - This function should be called whenever obtaining a pathname
// from the user. Some of the other routines in this file
// require a fully qualified and cleaned up pathname (i.e. no
// trailing space and such).
//
//---------------------------------------------------------------------------
LPTSTR MyGetFullPath(LPTSTR lpFileName)
{
TCHAR Buffer[MAX_PATH], *lpFilePart;
lstrcpyn(Buffer, lpFileName, AS(Buffer));
if ( ! GetFullPathName(Buffer,
MAX_PATH,
lpFileName,
&lpFilePart) ) {
lpFilePart = NULL;
return NULL;
}
return lpFilePart;
}
//---------------------------------------------------------------------------
//
// Function: GetPathFromPathAndFilename
//
// Purpose: To obtain the just the path from a string that contains a path
// and a filename.
//
// Arguments: LPTSTR lpPathAndFileName - the full path and filename
// TCHAR *szPath - buffer the path is to be returned in, it is
// assumed to be of MAX_PATH length
//
// Returns:
// Inside szBuffer is just the path from the input of the path and file
// name
// BOOL - TRUE on success, FALSE on failure
//
//
// Examples:
// lpPathAndFileName szBuffer
//
// c:\foo\bar.exe returns c:\foo
// c:\bar.exe c:\
//
//---------------------------------------------------------------------------
BOOL
GetPathFromPathAndFilename( IN LPTSTR lpPathAndFileName, OUT TCHAR *szPath, IN DWORD cbSize )
{
INT iFileNameLength;
INT iPathLength;
INT iPathAndFileNameLength;
TCHAR Buffer[MAX_PATH];
TCHAR *lpFilePart;
lstrcpyn(Buffer, lpPathAndFileName, AS(Buffer));
if ( ! GetFullPathName(Buffer,
MAX_PATH,
lpPathAndFileName,
&lpFilePart) ) {
return( FALSE );
}
iFileNameLength = lstrlen( lpFilePart );
iPathAndFileNameLength = lstrlen( lpPathAndFileName );
lstrcpyn( szPath, lpPathAndFileName, cbSize );
szPath[iPathAndFileNameLength - iFileNameLength] = _T('\0');
//
// At this point szPath looks like either c:\foo\ or c:\
// So trim the last back slash unless at the root
//
iPathLength = lstrlen( szPath );
if( iPathLength > 3 )
{
szPath[iPathLength-1] = _T('\0');
}
return( TRUE );
}
//---------------------------------------------------------------------------
//
// Function: MyGetDiskFreeSpace
//
// Purpose: Gets the free space in bytes on the given drive and returns
// a LONGLONG (int64).
//
// The Win32 apis won't return an int64. Also, the Win32 apis
// require d:\. But this function will accept any fully
// qualified path.
//
// Arguments:
// LPTSTR - any fully qualified path
//
// Returns:
// LONGLONG - free space
//
//---------------------------------------------------------------------------
LONGLONG
MyGetDiskFreeSpace(LPTSTR Drive)
{
BOOL bRet;
DWORD nSectorsPerCluster,
nBytesPerSector,
nFreeClusters,
nTotalClusters;
TCHAR DriveBuffer[MAX_PATH];
LONGLONG FreeBytes;
HRESULT hrCat;
if( _istalpha( Drive[0] ) )
{
lstrcpyn(DriveBuffer, Drive, 4);
DriveBuffer[3] = _T('\0');
}
else if( Drive[0] == _T('\\') )
{
GetComputerNameFromUnc( Drive, DriveBuffer, AS(DriveBuffer) );
hrCat=StringCchCat( DriveBuffer, AS(DriveBuffer), _T("\\") );
hrCat=StringCchCat( DriveBuffer, AS(DriveBuffer), WizGlobals.DistShareName );
hrCat=StringCchCat( DriveBuffer, AS(DriveBuffer), _T("\\") );
}
else
{
AssertMsg(FALSE,
"MyGetDiskFreeSpace failed, programming error, bad Drive parameter");
}
bRet = GetDiskFreeSpace( DriveBuffer,
&nSectorsPerCluster,
&nBytesPerSector,
&nFreeClusters,
&nTotalClusters );
if( bRet == FALSE )
{
ReportErrorId( NULL,
MSGTYPE_ERR | MSGTYPE_WIN32,
IDS_ERR_UNABLE_TO_DETERMINE_FREE_SPACE,
DriveBuffer );
return( 0 );
}
FreeBytes = (LONGLONG) nFreeClusters *
(LONGLONG) nBytesPerSector *
(LONGLONG) nSectorsPerCluster;
return( FreeBytes );
}
//---------------------------------------------------------------------------
//
// Function: MySetupQuerySpaceRequiredOnDrive
//
// Purpose: Uses setupapi disk-space-list and returns the LONGLONG
// of how many bytes are needed.
//
// Arguments:
// LPTSTR - any fully qualified path
//
// Returns:
// LONGLONG - free space
//
//---------------------------------------------------------------------------
LONGLONG
MySetupQuerySpaceRequiredOnDrive(HDSKSPC hDiskSpace, LPTSTR Drive)
{
BOOL bRet;
LONGLONG llRequiredSpace;
TCHAR DriveBuffer[MAX_PATH];
if( _istalpha( Drive[0] ) )
{
lstrcpyn(DriveBuffer, Drive, 3);
DriveBuffer[2] = _T('\0');
}
else if( Drive[0] == _T('\\') )
{
GetComputerAndShareNameFromUnc( Drive, DriveBuffer, AS(DriveBuffer) );
}
else
{
AssertMsg(FALSE,
"SetupQuerySpaceRequiredOnDrive failed, programming error, bad Drive parameter");
}
bRet = SetupQuerySpaceRequiredOnDrive(
hDiskSpace,
DriveBuffer,
&llRequiredSpace,
NULL, 0);
AssertMsg(bRet,
"SetupQuerySpaceRequiredOnDrive failed, programming error");
return llRequiredSpace;
}
//---------------------------------------------------------------------------
//
// Function: IsPathOnLocalDiskDrive
//
// Purpose: Determines if the path is on a local disk drive or not.
//
// Arguments:
// LPTSTR lpPath - fully qualified path
//
// Returns: BOOL
//
//---------------------------------------------------------------------------
BOOL
IsPathOnLocalDiskDrive(LPCTSTR lpPath)
{
UINT nDriveType;
TCHAR szDrivePath[MAX_PATH + 1];
//
// Use GetDriveType to determine if the path is a local or a network path
//
lstrcpyn( szDrivePath, lpPath, AS(szDrivePath) );
if( szDrivePath[0] != _T('\\') )
{
//
// Truncate the path to the root dir
//
szDrivePath[3] = _T('\0');
}
nDriveType = GetDriveType( szDrivePath );
if( nDriveType == DRIVE_REMOTE )
{
return( FALSE );
}
else
{
return( TRUE );
}
}
//---------------------------------------------------------------------------
//
// Function: EnsureDirExists
//
// Purpose: Function that will iteratively create the given directory
// by creating each piece of the pathname if necessary.
//
// Arguments:
// LPTSTR lpDirName - dir name
//
// Returns: BOOL
//
// Notes:
// - This function requires a fully qualified pathname. Translate
// pathnames using MyGetFullPath() first.
//
// - The Win32 error code will be valid upon failure.
//
//---------------------------------------------------------------------------
BOOL EnsureDirExists(LPTSTR lpDirName)
{
BOOL bRestoreSlash;
DWORD dwAttribs;
TCHAR *p;
//
// Parse off the D:\ or \\srv\shr\. The lasterror will already
// be set by ParseDriveLetterOrUnc() if any errors occured.
//
if ( (p = ParseDriveLetterOrUnc(lpDirName)) == NULL )
return FALSE;
//
// Now parse off each piece of the pathname and make sure dir exists
//
while ( *p ) {
// find next \ or end // of pathname
while ( *p && *p != _T('\\') )
p++;
bRestoreSlash = FALSE;
if ( *p == _T('\\') ) {
*p = _T('\0');
bRestoreSlash = TRUE;
}
// see if a file with that name already exists
dwAttribs = GetFileAttributes(lpDirName);
if ( dwAttribs != (DWORD) -1 &&
!(dwAttribs & FILE_ATTRIBUTE_DIRECTORY) ) {
if ( bRestoreSlash )
*p = _T('\\');
SetLastError(ERROR_ALREADY_EXISTS);
return FALSE;
}
// create the dir and allow a failure if the dir already exists
if ( !CreateDirectory(lpDirName, NULL) &&
GetLastError() != ERROR_ALREADY_EXISTS ) {
if ( bRestoreSlash )
*p = _T('\\');
return FALSE;
}
if ( bRestoreSlash )
*p = _T('\\');
// advance to next piece of the pathname
p++;
}
return TRUE;
}
//---------------------------------------------------------------------------
//
// Function: DoesFolderExist
//
// Purpose: Checks if the given folder exists or not.
//
// Arguments:
// LPTSTR lpDirName - dir name
//
// Returns: BOOL
//
//---------------------------------------------------------------------------
BOOL DoesFolderExist(LPTSTR lpDirName)
{
DWORD dwAttribs = GetFileAttributes(lpDirName);
if ( dwAttribs == (DWORD) -1 )
return FALSE;
if ( !(dwAttribs & FILE_ATTRIBUTE_DIRECTORY) )
return FALSE;
return TRUE;
}
//---------------------------------------------------------------------------
//
// Function: DoesFileExist
//
// Purpose: Checks if the given file exists or not.
//
// Arguments:
// LPTSTR lpFileName - file name
//
// Returns: BOOL
//
//---------------------------------------------------------------------------
BOOL DoesFileExist(LPTSTR lpFileName)
{
DWORD dwAttribs = GetFileAttributes(lpFileName);
if ( dwAttribs == (DWORD) -1 )
return FALSE;
if ( dwAttribs & FILE_ATTRIBUTE_DIRECTORY )
return FALSE;
return TRUE;
}
//---------------------------------------------------------------------------
//
// Function: DoesPathExist
//
// Purpose: Checks if the given path exists or not. It does not pay
// attention to whether it is a file or directory.
//
// Arguments:
// LPTSTR lpPathName - path name
//
// Returns: BOOL
//
//---------------------------------------------------------------------------
BOOL DoesPathExist(LPTSTR lpPathName)
{
DWORD dwAttribs = GetFileAttributes(lpPathName);
if ( dwAttribs == (DWORD) -1 )
return FALSE;
return TRUE;
}
//---------------------------------------------------------------------------
//
// Function: ILFreePriv
//
// Purpose: Frees an ID list that some shell apis allocate with it's own
// special allocator.
//
// Arguments:
// LPITEMIDLIST pidl - pointer to shell specially alloced mem
//
// Returns: VOID
//
//---------------------------------------------------------------------------
VOID ILFreePriv(LPITEMIDLIST pidl)
{
LPMALLOC pMalloc;
if (pidl)
{
if ( NOERROR == SHGetMalloc(&pMalloc) )
{
pMalloc->lpVtbl->Free(pMalloc, pidl);
pMalloc->lpVtbl->Release(pMalloc);
}
}
}
//
// Constants used for GetOpenFileName() and GetSaveFileName() calls that
// allow user to browse for an answer file.
//
//#define TEXT_FILE_FILTER _T("Text Files (*.txt)\0*.txt\0Remote Boot Files (*.sif)\0*.sif\0Sysprep Inf Files (*.inf)\0*.inf\0All Files (*.*)\0*.*\0")
#define TEXT_EXTENSION _T("txt")
//----------------------------------------------------------------------------
//
// Function: GetAnswerFileName
//
// Purpose: Function for the 'Browse' button on the SaveScript page and
// the NewOrEdit page.
//
// Arguments:
// HWND hwnd - calling window
// LPTSTR buffer - output, pass in a MAX_PATH buffer
//
// Returns:
// BOOL - success
//
//----------------------------------------------------------------------------
BOOL GetAnswerFileName(HWND hwnd,
LPTSTR lpFileName,
BOOL bSavingFile)
{
OPENFILENAME ofn;
DWORD dwFlags;
TCHAR PathBuffer[MAX_PATH];
INT iRet;
HRESULT hrPrintf;
//
// If we haven't already loaded the resource strings, then load them now.
//
if( g_szSetupMgrFileExtensions[0] == _T('\0') )
{
TCHAR *StrTextFiles;
TCHAR *StrRemoteBootFiles;
TCHAR *StrSysprepFiles;
TCHAR *StrAllFiles;
//
// Load the resource strings
//
StrTextFiles = AllocateString(NULL, IDS_TEXT_FILES);
StrRemoteBootFiles = AllocateString(NULL, IDS_REMOTE_BOOT_FILES);
StrSysprepFiles = AllocateString(NULL, IDS_SYSPREP_FILES);
StrAllFiles = AllocateString(NULL, IDS_ALL_FILES);
//
// Build the text file filter string
//
//
// The question marks (?) are just placehoders for where the NULL char
// will be inserted.
//
hrPrintf=StringCchPrintf( g_szSetupMgrFileExtensions,AS(g_szSetupMgrFileExtensions),
_T("%s (*.txt)?*.txt?%s (*.sif)?*.sif?%s (*.inf)?*.inf?%s (*.*)?*.*?"),
StrTextFiles,
StrRemoteBootFiles,
StrSysprepFiles,
StrAllFiles );
FREE(StrTextFiles);
FREE(StrRemoteBootFiles);
FREE(StrSysprepFiles);
FREE(StrAllFiles);
ConvertQuestionsToNull( g_szSetupMgrFileExtensions );
}
if ( bSavingFile )
dwFlags = OFN_HIDEREADONLY |
OFN_PATHMUSTEXIST;
else
dwFlags = OFN_HIDEREADONLY |
OFN_FILEMUSTEXIST;
GetCurrentDirectory(MAX_PATH, PathBuffer);
ofn.lStructSize = sizeof(OPENFILENAME);
ofn.hwndOwner = hwnd;
ofn.hInstance = NULL;
ofn.lpstrFilter = g_szSetupMgrFileExtensions;
ofn.lpstrCustomFilter = NULL;
ofn.nMaxCustFilter = 0L;
ofn.nFilterIndex = 1;
ofn.lpstrFile = lpFileName;
ofn.nMaxFile = MAX_PATH;
ofn.lpstrFileTitle = NULL;
ofn.nMaxFileTitle = 0;
ofn.lpstrInitialDir = PathBuffer;
ofn.lpstrTitle = NULL;
ofn.Flags = dwFlags;
ofn.nFileOffset = 0;
ofn.nFileExtension = 0;
ofn.lpstrDefExt = TEXT_EXTENSION;
if ( bSavingFile )
iRet = GetSaveFileName(&ofn);
else
iRet = GetOpenFileName(&ofn);
if ( ! iRet )
return FALSE;
MyGetFullPath(lpFileName);
return TRUE;
}
//----------------------------------------------------------------------------
//
// Function: ShowBrowseFolder
//
// Purpose: Displays a browse folder for the user to select a file from.
// Takes the headache out of making an OPENFILENAME struct and filling
// it up.
//
// Arguments:
// HWND hwnd - handle to the dialog box
// TCHAR *szFileFilter - string to display descriptions and extensions
// on the files
// TCHAR *szFileExtension - string that is the default extension for the file
// DWORD dwFlags - bit flags used to initialize the browse dialog
// TCHAR *szStartingPath - path the browse should start at
// TCHAR *szFileNameAndPath - path and filename the user selected
//
// Returns: Non-Zero - if user specified a file
// Zero - if user did not specify a file
//
//----------------------------------------------------------------------------
INT
ShowBrowseFolder( IN HWND hwnd,
IN TCHAR *szFileFilter,
IN TCHAR *szFileExtension,
IN DWORD dwFlags,
IN TCHAR *szStartingPath,
IN OUT TCHAR *szFileNameAndPath ) {
OPENFILENAME ofn;
ofn.lStructSize = sizeof(OPENFILENAME);
ofn.hwndOwner = hwnd;
ofn.hInstance = NULL;
ofn.lpstrFilter = szFileFilter;
ofn.lpstrCustomFilter = NULL;
ofn.nMaxCustFilter = 0L;
ofn.nFilterIndex = 1;
ofn.lpstrFile = szFileNameAndPath;
ofn.nMaxFile = MAX_PATH;
ofn.lpstrFileTitle = NULL;
ofn.nMaxFileTitle = 0;
ofn.lpstrInitialDir = szStartingPath;
ofn.lpstrTitle = NULL;
ofn.Flags = dwFlags;
ofn.nFileOffset = 0;
ofn.nFileExtension = 0;
ofn.lpstrDefExt = szFileExtension;
return( GetOpenFileName( &ofn ) );
}
//----------------------------------------------------------------------------
//
// Function: GetPlatform
//
// Purpose:
//
// Arguments: OUT TCHAR *pBuffer - buffer to copy the platform string to,
// assumed to be able to hold MAX_PATH chars
//
// Returns: VOID
//
//----------------------------------------------------------------------------
VOID
GetPlatform( OUT TCHAR *pBuffer )
{
SYSTEM_INFO SystemInfo;
GetSystemInfo( &SystemInfo );
switch( SystemInfo.wProcessorArchitecture )
{
case PROCESSOR_ARCHITECTURE_INTEL:
lstrcpyn( pBuffer, _T("i386"), MAX_PATH );
break;
case PROCESSOR_ARCHITECTURE_AMD64:
lstrcpyn( pBuffer, _T("amd64"), MAX_PATH );
break;
default:
lstrcpyn( pBuffer, _T("i386"), MAX_PATH );
AssertMsg( FALSE,
"Unknown Processor. Can't set sysprep language files path." );
}
}