www.pudn.com > cab文件压缩、解压程序源代码.zip > path.cpp, change:1998-09-28,size:83945b


//--------------------------------------------------------------------------- 
// Copyright (C) 1998, Interscope Ltd. All rights reserved. 
// Reproduction or distribution of this program, or any portion of it,  
// is permitted only if this header is kept as it is. 
// For more information, contact: 
// 
// Interscope Ltd., 5 Culturii St., 5th Floor, 4800 Baia Mare, RO 
//    Phone/Fax: +40-62-215023 
//    E-mail: office@interscope.ro 
// 
//   $Author: Levente Farkas $ 
//     $Date: 9/14/98 4:34a $ 
//  $Modtime: 9/14/98 4:34a $ 
// $Revision: 120 $ 
//  $Archive: /Interscope/Callisto/Path.Cpp $ 
// $Workfile: Path.Cpp $ 
//----------------------------------------------------------------------- 
 
#ifdef __STDAFX__ 
#include "StdAfx.H" 
#endif 
 
#include  
#include  
#include  
#include  
#include  
 
#ifndef __MFC__ 
#include "Trace.H" 
#endif 
 
#include "AssertX.H" 
#include "StringHelper.Hpp" 
#include "OSVersion.Hpp" 
#include "Registry.Hpp" 
#include "Reminder.Hpp" 
#include "Path.Hpp" 
 
 
//--- Debugee -------------------------------------------------------------- 
 
#ifdef _DEBUG 
#undef THIS_FILE 
static char THIS_FILE[] = __FILE__; 
#ifdef __MFC__ 
#define new DEBUG_NEW 
#endif // __MFC__ 
#endif // _DEBUG 
 
 
//------------------------------------------------------------- 
// Pre     : 
// Post    :  
// Globals : 
// I/O     : 
// Task    : Create a string of length nDigits containing random digits 
//------------------------------------------------------------- 
static string RandomDigits(int nDigits) 
{ 
    // Keep the number of digits in a rational limit 
    ASSERTX(nDigits >  0); 
    ASSERTX(nDigits < 20); 
     
	int    nDigits2 = nDigits; 
	string Digits; 
    TCHAR  next_8_digits[9]; 
    while(nDigits2 > 0) 
    { 
        SPRINTF(next_8_digits,_T("%08lx"),GetTickCount()); 
 
        for(int i=0; i<8; i++) 
        { 
            Digits += next_8_digits[i]; 
            if(--nDigits2 == 0) 
                break; 
        } 
    } 
 
    int last_digit =rand(); 
    if(last_digit < 0) 
        last_digit =(-last_digit); 
    last_digit %= 10; 
    Digits[nDigits - 1] ='0' + last_digit; 
     
	return Digits; 
} 
 
//------------------------------------------------------------- 
// Pre     : 
// Post    :  
// Globals : 
// I/O     : 
// Task    : Helper function for the various CPath constructors.  
//           Initializes the data members and establishes various 
//           class invariants 
//------------------------------------------------------------- 
inline void CPath::Init() 
{ 
	m_dwFindFileAttributes =0; 
	m_hFindFile =NULL; 
} 
 
//------------------------------------------------------------- 
// Pre     : 
// Post    :  
// Globals : 
// I/O     : 
// Task    : Helper function for the various CPath destructors. 
//           Cleans up varios internals 
//------------------------------------------------------------- 
inline void CPath::Exit() 
{ 
	if(m_hFindFile != NULL) 
    { 
		FindClose(m_hFindFile); 
        m_hFindFile =NULL; 
    } 
} 
 
//------------------------------------------------------------- 
// Pre     : 
// Post    :  
// Globals : 
// I/O     : 
// Task    : Constructs a path 
//------------------------------------------------------------- 
CPath::CPath() 
{ 
	Init(); 
    Empty(); 
} 
 
//------------------------------------------------------------- 
// Pre     : 
// Post    :  
// Globals : 
// I/O     : 
// Task    : Constructs a path as copy of another 
//------------------------------------------------------------- 
CPath::CPath(const CPath& rPath) 
{ 
	Init(); 
	m_strPath =rPath.m_strPath; 
} 
 
//------------------------------------------------------------- 
// Pre     : 
// Post    :  
// Globals : 
// I/O     : 
// Task    : Constructs a path and points it 2 lpszPath 
//------------------------------------------------------------- 
CPath::CPath(LPCTSTR lpszPath) 
{ 
	Init(); 
    m_strPath =lpszPath ? lpszPath : _T(""); 
} 
 
//------------------------------------------------------------- 
// Pre     : 
// Post    :  
// Globals : 
// I/O     : 
// Task    : Constructs a path and points it 2 strPath 
//------------------------------------------------------------- 
CPath::CPath(const string& strPath) 
{ 
    Init(); 
    m_strPath =strPath; 
} 
 
//------------------------------------------------------------- 
// Pre     : 
// Post    :  
// Globals : 
// I/O     : 
// Task    : Constructs a path and points it 2 specified  
//           special directory 
//------------------------------------------------------------- 
CPath::CPath(SpecialDirectoryType eInitialDir) 
{ 
	Init(); 
    switch(eInitialDir) 
    {	 
        // Application's current directory	  
        case CURRENT_DIRECTORY: 
            CurrentDirectory(); 
            break; 
        // Windows directory 
        case WINDOWS_DIRECTORY: 
            WindowsDirectory(); 
            break; 
        // Windows' system directory     
        case SYSTEM_DIRECTORY: 
            SystemDirectory(); 
            break; 
        // The root directory of system drive 
        case SYSTEM_DRIVE_ROOT_DIRECTORY: 
            SystemDriveRootDirectory(); 
            break; 
        // The directory where the executable of this app is 
        case MODULE_DIRECTORY: 
            #ifdef __MFC__ 
            ModuleDirectory(); 
            #else 
            ASSERTX(FALSE); 
            #endif 
            break; 
        // Windows temp directory 
		case TEMP_DIRECTORY: 
			TempDirectory(); 
			break; 
 
        // Program files directory 
        case PROGRAM_FILES_DIRECTORY: 
            ProgramFilesDirectory(); 
            break; 
        // Common files directory 
        case COMMON_FILES_DIRECTORY: 
            CommonFilesDirectory(); 
            break; 
        // Accessories directory 
        case ACCESSORIES_DIRECTORY: 
            AccessoriesDirectory(); 
            break; 
        // Media directory 
        case MEDIA_DIRECTORY: 
            MediaDirectory(); 
            break; 
        // INF directory 
        case DEVICE_DIRECTORY: 
            DeviceDirectory(); 
            break; 
 
        // User specific directories 
        case USER_DESKTOP_DIRECTORY: 
            UserDesktopDirectory(); 
            break; 
        case USER_FAVORITES_DIRECTORY: 
            UserFavoritesDirectory(); 
            break; 
        case USER_FONTS_DIRECTORY: 
            UserFontsDirectory(); 
            break; 
        case USER_NETHOOD_DIRECTORY: 
            UserNetworkNeighbourhoodDirectory(); 
            break; 
        case USER_DOCUMENTS_DIRECTORY: 
            UserDocumentsDirectory(); 
            break; 
        case USER_RECENT_DIRECTORY: 
            UserRecentDirectory(); 
            break; 
        case USER_SENDTO_DIRECTORY: 
            UserSendToDirectory(); 
            break; 
        case USER_RECYCLE_DIRECTORY: 
            UserRecycleBinDirectory(); 
            break; 
        case USER_APPLICATION_DATA_DIRECTORY: 
            UserApplicationDataDirectory(); 
            break; 
        case USER_TEMPLATES_DIRECTORY: 
            UserTemplatesDirectory(); 
            break; 
        case USER_STARTMENU_DIRECTORY: 
            UserStartMenuDirectory(); 
            break; 
        case USER_STARTMENU_STARTUP_DIRECTORY: 
            UserStartMenuStartupDirectory(); 
            break; 
        case USER_STARTMENU_PROGRAMS_DIRECTORY: 
            UserStartMenuProgramsDirectory(); 
            break; 
 
        // Directories common 2 all users 
        case COMMON_DESKTOP_DIRECTORY: 
            CommonDesktopDirectory(); 
            break; 
        case COMMON_STARTMENU_DIRECTORY: 
            CommonStartMenuDirectory(); 
            break; 
        case COMMON_STARTMENU_STARTUP_DIRECTORY: 
            CommonStartMenuStartupDirectory(); 
            break; 
        case COMMON_STARTMENU_PROGRAMS_DIRECTORY: 
            CommonStartMenuProgramsDirectory(); 
            break; 
 
        // Unknown special directory constant     
        default: 
            // Accept only constants we know about 
            ASSERTX(FALSE); 
    } 
} 
 
//------------------------------------------------------------- 
// Pre     : 
// Post    :  
// Globals : 
// I/O     : 
// Task    : Cleanup and destruct a path object 
//------------------------------------------------------------- 
CPath::~CPath() 
{ 
	Exit(); 
} 
 
//------------------------------------------------------------- 
// Pre     : 
// Post    : Return TRUE if paths are equal 
// Globals : 
// I/O     : 
// Task    : Check if the two path are the same 
//------------------------------------------------------------- 
BOOL CPath::operator ==(const CPath& rPath) const 
{ 
    // Get fully qualified versions of the paths 
	string FullyQualified1; 
    string FullyQualified2; 
	 
	GetFullyQualified(FullyQualified1); 
	rPath.GetFullyQualified(FullyQualified2); 
	 
    // Compare them 
	return STRICMP(FullyQualified1.c_str(),FullyQualified2.c_str()) == 0; 
} 
 
//------------------------------------------------------------- 
// Pre     : 
// Post    : Return TRUE if paths are different 
// Globals : 
// I/O     : 
// Task    : Check if the two path are different 
//------------------------------------------------------------- 
BOOL CPath::operator !=(const CPath& rPath) const 
{ 
    return !(*this == rPath); 
} 
 
//------------------------------------------------------------- 
// Pre     : 
// Post    :  
// Globals : 
// I/O     : 
// Task    : Assign a path 2 another 
//------------------------------------------------------------- 
CPath& CPath::operator =(const CPath& rPath) 
{                    
	if(this != &rPath) 
		m_strPath =rPath.m_strPath; 
		     
    return *this; 
} 
 
//------------------------------------------------------------- 
// Pre     : 
// Post    : Return the path, so that assignements can be chained 
// Globals : 
// I/O     : 
// Task    : Assign a string 2 a path 
//------------------------------------------------------------- 
CPath& CPath::operator =(LPCTSTR lpszPath) 
{ 
    m_strPath =lpszPath ? lpszPath : _T(""); 
    return *this; 
} 
 
//------------------------------------------------------------- 
// Pre     : 
// Post    : Return the path, so that assignements can be chained 
// Globals : 
// I/O     : 
// Task    : Assign a string 2 a path 
//------------------------------------------------------------- 
CPath& CPath::operator =(const string& strPath) 
{ 
    m_strPath =strPath; 
    return *this; 
} 
 
//------------------------------------------------------------- 
// Pre     : 
// Post    : Converts path 2 string 
// Globals : 
// I/O     : 
// Task    : Convert path 2 string 
//           Warning: because this pointer 2 string point in the data 
//           of this class, it is possible 2 cast the result of this  
//           function in any non-constant pointer and alter the data. 
//           Very dangerous 
//------------------------------------------------------------- 
CPath::operator LPCTSTR() const 
{ 
    return (LPCTSTR)m_strPath.c_str(); 
} 
 
//------------------------------------------------------------- 
// Pre     : 
// Post    : Returns the drive component without a colon, e.g. "c" 
//           Returns the directory component with a leading backslash,  
//              but no trailing backslash, e.g. "\dir\subdir" 
//           Returns name compleletely without delimiters, e.g "letter" 
//           Returns extension completely without delimiters, e.g. "doc" 
// Globals : 
// I/O     : 
// Task    : Return the individual components of this path.  
//           For any given argument, you can pass NULL if you are not  
//           interested in that component. 
//           Do not rely on pNames being <= 8 characters, extensions  
//           being <= 3 characters, or drives being 1 character 
//------------------------------------------------------------- 
void CPath::GetComponents(string* pDrive,  
                       	  string* pDirectory,  
                       	  string* pName,  
                          string* pExtension) const 
{ 
    TCHAR buff_drive[_MAX_DRIVE + 1]; 
    TCHAR buff_dir  [_MAX_DIR   + 1]; 
    TCHAR buff_name [_MAX_FNAME + 1]; 
    TCHAR buff_ext  [_MAX_EXT   + 1]; 
 
    ZeroMemory(buff_drive,sizeof(buff_drive)); 
    ZeroMemory(buff_dir,  sizeof(buff_dir)); 
    ZeroMemory(buff_name, sizeof(buff_name)); 
    ZeroMemory(buff_ext,  sizeof(buff_ext)); 
 
	SPLITPATH(m_strPath.c_str(),  
              pDrive     ? buff_drive : NULL, 
              pDirectory ? buff_dir   : NULL, 
              pName      ? buff_name  : NULL, 
              pExtension ? buff_ext   : NULL); 
                 
    if(pDrive) 
        *pDrive =buff_drive; 
    if(pDirectory) 
        *pDirectory =buff_dir; 
    if(pName) 
        *pName =buff_name; 
    if(pExtension) 
        *pExtension =buff_ext; 
 
	// DOS's _splitpath returns "d:", we return "d" 
	if(pDrive) 
		StripTrailingChar(*pDrive,DRIVE_DELIMITER); 
	// DOS's _splitpath returns "\dir\subdir\", we return "\dir\subdir" 
	if(pDirectory) 
		StripTrailingBackslash(*pDirectory); 
	// DOS's _splitpath returns ".ext", we return "ext"	 
	if(pExtension) 
		StripLeadingChar(*pExtension,EXTENSION_DELIMITER); 
} 
 
//------------------------------------------------------------- 
// Pre     : 
// Post    :  
// Globals : 
// I/O     : 
// Task    : Get drive from path 
//-------------------------------------------------------------                        
void CPath::GetDrive(string& rDrive) const 
{ 
	GetComponents(&rDrive); 
} 
 
//------------------------------------------------------------- 
// Pre     : 
// Post    :  
// Globals : 
// I/O     : 
// Task    : Get drive and directory from path 
//------------------------------------------------------------- 
void CPath::GetDriveDirectory(string& rDriveDirectory) const 
{ 
    string Drive; 
    string Directory; 
 
	GetComponents(&Drive,&Directory); 
	rDriveDirectory =Drive; 
	if(!Drive.empty()) 
    { 
		rDriveDirectory += DRIVE_DELIMITER; 
        rDriveDirectory += Directory; 
    } 
} 
 
//------------------------------------------------------------- 
// Pre     : 
// Post    :  
// Globals : 
// I/O     : 
// Task    : Get directory from path 
//------------------------------------------------------------- 
void CPath::GetDirectory(string& rDirectory) const 
{ 
    GetComponents(NULL,&rDirectory); 
}     
 
//------------------------------------------------------------- 
// Pre     : 
// Post    :  
// Globals : 
// I/O     : 
// Task    : Get filename and extension from path 
//------------------------------------------------------------- 
void CPath::GetNameExtension(string& rNameExtension) const 
{ 
    string Name; 
    string Extension; 
 
	GetComponents(NULL,NULL,&Name,&Extension); 
    rNameExtension =Name; 
    if(!Extension.empty()) 
    { 
    	rNameExtension += EXTENSION_DELIMITER; 
        rNameExtension += Extension; 
    } 
} 
 
//------------------------------------------------------------- 
// Pre     : 
// Post    :  
// Globals : 
// I/O     : 
// Task    : Get filename from path 
//------------------------------------------------------------- 
void CPath::GetName(string& rName) const 
{ 
    GetComponents(NULL,NULL,&rName); 
} 
 
//------------------------------------------------------------- 
// Pre     : 
// Post    :  
// Globals : 
// I/O     : 
// Task    : Get file extension from path 
//------------------------------------------------------------- 
void CPath::GetExtension(string& rExtension) const 
{ 
    GetComponents(NULL,NULL,NULL,&rExtension); 
}    
 
//------------------------------------------------------------- 
// Pre     : 
// Post    :  
// Globals : 
// I/O     : 
// Task    : Get fully qualified path 
//------------------------------------------------------------- 
void CPath::GetFullyQualified(string& rFullyQualified) const 
{ 
    TCHAR buff_fullname[MAX_PATH]; 
 
	FULLPATH(buff_fullname,m_strPath.c_str(),MAX_PATH-1); 
    rFullyQualified =buff_fullname; 
} 
 
//------------------------------------------------------------- 
// Pre     : 
// Post    :  
// Globals : 
// I/O     : 
// Task    : Get fully qualified path in short (8.3 style) form 
//------------------------------------------------------------- 
void CPath::GetFullyQualifiedShort(string& rFullyQualifiedShort) const 
{ 
    GetFullyQualified(rFullyQualifiedShort); 
 
#pragma message(Reminder(_T("Also implement a GetFullyQualifiedLong"))) 
 
    TCHAR buff_fullname[MAX_PATH]; 
    GetShortPathName(rFullyQualifiedShort.c_str(),buff_fullname,sizeof(buff_fullname)/sizeof(TCHAR)); 
    rFullyQualifiedShort =buff_fullname; 
} 
 
//------------------------------------------------------------- 
// Pre     : 
// Post    : Return TRUE if path does not start from filesystem root 
// Globals : 
// I/O     : 
// Task    : Check if path is a relative one (e.g. doesn't start with C:\...) 
//-------------------------------------------------------------     
BOOL CPath::IsRelative() const 
{ 
    return (m_strPath.find(DRIVE_DELIMITER) == string::npos); 
} 
 
//------------------------------------------------------------- 
// Pre     : 
// Post    : Return TRUE if there are wildcards in the path 
// Globals : 
// I/O     : 
// Task    : Check if path contains wildcards 
//-------------------------------------------------------------     
BOOL CPath::IsWild() const 
{ 
    return (m_strPath.find_first_of(WILD_SET) != string::npos); 
} 
 
//------------------------------------------------------------- 
// Pre     : 
// Post    : Return TRUE if path is lexically correct 
// Globals : 
// I/O     : 
// Task    : Determine whether lpszFileName is valid. A filename 
//           is valid if it contains only legal characters, doesn't 
//           have repeated contiguous subdirectory delimiters, has at  
//           most one drive delimiter, and all components fit within  
//           maximum sizes 
//           This routine does NOT determine if a file exists, or 
//           even if it could exist relative to the user's directory 
//           hierarchy. Its tests are for lexical correctness only 
//           See also: CPath::Exists 
//------------------------------------------------------------- 
BOOL CPath::IsValid () const 
{ 
    // Check 4 illegal characters (no wildcards allowed) 
    // We accept either \ or / as folder delimiter 
    if(IsWild() || 
       (m_strPath.find_first_of(_T("|\"<>")) != string::npos) ||  
       (m_strPath.find(_T("//")) != string::npos)) 
        return FALSE; 
 
    int index =m_strPath.find(_T("\\\\")); 
    if((index != string::npos) && (index > 0)) 
        return FALSE; 
 
    // Make sure : can appear only in the 2nd position as a drive delimiter 
    if(((index =m_strPath.find(':')) != string::npos) && (index != 1)) 
        return FALSE; 
 
    // Make sure it fits in the maximum path size 
    if(m_strPath.length() > MAX_PATH) 
        return FALSE; 
     
    // Path is valid 
	return TRUE; 
} 
 
//------------------------------------------------------------- 
// Pre     : 
// Post    :  
// Globals : 
// I/O     : 
// Task    : Set path components 
//------------------------------------------------------------- 
void CPath::SetComponents(LPCTSTR lpszDrive,  
                          LPCTSTR lpszDirectory, 
						  LPCTSTR lpszName,  
                          LPCTSTR lpszExtension) 
{ 
    TCHAR buff_fullname[MAX_PATH]; 
 
	MAKEPATH(buff_fullname,lpszDrive,lpszDirectory,lpszName,lpszExtension); 
 
    m_strPath.erase(); 
    m_strPath =buff_fullname; 
} 
 
//------------------------------------------------------------- 
// Pre     : 
// Post    :  
// Globals : 
// I/O     : 
// Task    : Set path's drive 
//------------------------------------------------------------- 
void CPath::SetDrive(TCHAR chDrive) 
{ 
	string	Drive(1,chDrive); 
	string	Directory; 
	string	Name; 
	string	Extension; 
	 
	GetComponents(NULL,&Directory,&Name,&Extension); 
	SetComponents(Drive.c_str(),Directory.c_str(),Name.c_str(),Extension.c_str()); 
} 
 
//------------------------------------------------------------- 
// Pre     : 
// Post    :  
// Globals : 
// I/O     : 
// Task    : Set path's directory 
//------------------------------------------------------------- 
void CPath::SetDirectory(LPCTSTR lpszDirectory, BOOL bEnsureAbsolute /*= FALSE*/) 
{ 
	string	Drive;	 
	string	Directory =lpszDirectory; 
	string	Name; 
	string	Extension; 
	 
	if(bEnsureAbsolute) 
		EnsureLeadingBackslash(Directory); 
	EnsureTrailingBackslash(Directory); 
 
	GetComponents(&Drive,NULL,&Name,&Extension); 
	SetComponents(Drive.c_str(),Directory.c_str(),Name.c_str(),Extension.c_str()); 
}     
 
//------------------------------------------------------------- 
// Pre     : 
// Post    :  
// Globals : 
// I/O     : 
// Task    : Set path's drive and directory 
//------------------------------------------------------------- 
void CPath::SetDriveDirectory(LPCTSTR lpszDriveDirectory) 
{ 
	string	DriveDirectory =lpszDriveDirectory; 
	string	Name; 
	string	Extension; 
	 
	EnsureTrailingBackslash(DriveDirectory); 
	 
	GetComponents(NULL,NULL,&Name,&Extension); 
	SetComponents(NULL,DriveDirectory.c_str(),Name.c_str(),Extension.c_str()); 
}     
 
//------------------------------------------------------------- 
// Pre     : 
// Post    :  
// Globals : 
// I/O     : 
// Task    : Set path's filename 
//------------------------------------------------------------- 
void CPath::SetName(LPCTSTR lpszName) 
{ 
	string	Drive; 
	string	Directory; 
	string	Extension; 
	 
	GetComponents(&Drive,&Directory,NULL,&Extension); 
	SetComponents(Drive.c_str(),Directory.c_str(),lpszName,Extension.c_str()); 
} 
 
//------------------------------------------------------------- 
// Pre     : 
// Post    :  
// Globals : 
// I/O     : 
// Task    : Set path's file extension 
//------------------------------------------------------------- 
void CPath::SetExtension(LPCTSTR lpszExtension) 
{ 
	string	Drive; 
	string	Directory; 
	string	Name; 
	 
	GetComponents(&Drive,&Directory,&Name); 
	SetComponents(Drive.c_str(),Directory.c_str(),Name.c_str(),lpszExtension); 
} 
 
//------------------------------------------------------------- 
// Pre     : 
// Post    :  
// Globals : 
// I/O     : 
// Task    : Set path's filename and extension 
//------------------------------------------------------------- 
void CPath::SetNameExtension(LPCTSTR lpszNameExtension) 
{ 
	string	Drive; 
	string	Directory; 
 
	GetComponents(&Drive,&Directory); 
	SetComponents(Drive.c_str(),Directory.c_str(),lpszNameExtension,NULL); 
}     
 
//------------------------------------------------------------- 
// Pre     : 
// Post    :  
// Globals : 
// I/O     : 
// Task    : Append a subdirectory 2 path's directory 
//------------------------------------------------------------- 
void CPath::AppendDirectory(LPCTSTR lpszSubDirectory) 
{                                                
	string	Drive; 
	string	Directory; 
	string	SubDirectory =lpszSubDirectory; 
	string	Name; 
	string	Extension; 
	 
	if(SubDirectory.empty()) 
		return; 
 
	// Strip out any preceeding backslash 
	StripLeadingBackslash(SubDirectory); 
	EnsureTrailingBackslash(SubDirectory); 
 
	GetComponents(&Drive,&Directory,&Name,&Extension); 
	EnsureTrailingBackslash(Directory); 
    Directory +=SubDirectory; 
 
	SetComponents(Drive.c_str(),Directory.c_str(),Name.c_str(),Extension.c_str()); 
} 
 
//------------------------------------------------------------- 
// Pre     : If pLastDirectory is given we will store the name of the 
//           deepest directory (the one we're just exiting) in it 
// Post    :  
// Globals : 
// I/O     : 
// Task    : Remove deepest subdirectory from path 
//------------------------------------------------------------- 
void CPath::UpDirectory(string *pLastDirectory /*= NULL*/) 
{ 
	string Directory; 
 
	GetDirectory(Directory);	 
	StripTrailingBackslash(Directory); 
	if(Directory.empty()) 
		return; 
	 
    string::size_type nDelimiter =Directory.rfind(DIRECTORY_DELIMITER); 
	 
	if(pLastDirectory != NULL) 
	{ 
		*pLastDirectory =Directory.substr(nDelimiter); 
		StripLeadingBackslash(*pLastDirectory); 
	} 
		 
    if(nDelimiter != string::npos) 
		Directory =Directory.substr(0,nDelimiter); 
		 
	SetDirectory(Directory.c_str()); 
} 
 
//------------------------------------------------------------- 
// Pre     : 
// Post    :  
// Globals : 
// I/O     : 
// Task    : Set path 2 current directory 
//------------------------------------------------------------- 
void CPath::CurrentDirectory() 
{ 
	TCHAR buff_path[MAX_PATH]; 
	 
    GetCurrentDirectory(MAX_PATH,buff_path); 
	 
	Empty(); 
	SetDriveDirectory(buff_path); 
} 
 
//------------------------------------------------------------- 
// Pre     : 
// Post    :  
// Globals : 
// I/O     : 
// Task    : Set path 2 Windows directory 
//------------------------------------------------------------- 
void CPath::WindowsDirectory() 
{ 
	TCHAR buff_path[MAX_PATH]; 
	 
    GetWindowsDirectory(buff_path,MAX_PATH); 
     
    Empty(); 
    SetDriveDirectory(buff_path); 
} 
 
//------------------------------------------------------------- 
// Pre     : 
// Post    :  
// Globals : 
// I/O     : 
// Task    : Set path 2 Windows system directory 
//------------------------------------------------------------- 
void CPath::SystemDirectory() 
{ 
	TCHAR buff_path[MAX_PATH]; 
	 
    GetSystemDirectory(buff_path,MAX_PATH); 
     
    Empty(); 
    SetDriveDirectory(buff_path); 
} 
 
//------------------------------------------------------------- 
// Pre     : 
// Post    :  
// Globals : 
// I/O     : 
// Task    : Set path 2 root of system drive (usually C:\) 
//------------------------------------------------------------- 
void CPath::SystemDriveRootDirectory() 
{ 
    SystemDirectory(); 
    SetDirectory(_T("")); 
} 
 
//------------------------------------------------------------- 
// Pre     : 
// Post    :  
// Globals : 
// I/O     : 
// Task    : Set path 2 the name of specified module 
//------------------------------------------------------------- 
void CPath::Module(HINSTANCE hInstance) 
{ 
    TCHAR buff_path[MAX_PATH]; 
 
    GetModuleFileName(hInstance,buff_path,MAX_PATH); 
    m_strPath =buff_path; 
} 
 
#ifdef __MFC__ 
//------------------------------------------------------------- 
// Pre     : 
// Post    :  
// Globals : 
// I/O     : 
// Task    : Set path 2 the name of current module 
//------------------------------------------------------------- 
void CPath::Module() 
{ 
    Module(AfxGetInstanceHandle()); 
} 
#endif 
 
//------------------------------------------------------------- 
// Pre     : 
// Post    :  
// Globals : 
// I/O     : 
// Task    : Set path 2 the directory of current module 
//------------------------------------------------------------- 
void CPath::ModuleDirectory(HINSTANCE hInstance) 
{ 
	Module(hInstance); 
	SetNameExtension(_T("")); 
} 
 
#ifdef __MFC__ 
//------------------------------------------------------------- 
// Pre     : 
// Post    :  
// Globals : 
// I/O     : 
// Task    : Set path 2 the directory of current module 
//------------------------------------------------------------- 
void CPath::ModuleDirectory() 
{ 
	Module(); 
	SetNameExtension(_T("")); 
} 
#endif 
 
//------------------------------------------------------------- 
// Pre     : 
// Post    :  
// Globals : 
// I/O     : 
// Task    : Currently, if the current environment has an 
//           entry for the TEMP environment variable, the directory will 
//           be set to that. If not, the directory will be the Windows 
//           System directory. The caller of this method, however, should 
//           not rely on this convention 
//------------------------------------------------------------- 
void CPath::TempDirectory() 
{ 
    TCHAR buff_path[MAX_PATH]; 
 
	GetTempPath(MAX_PATH,buff_path); 
 
	m_strPath =buff_path; 
	SetNameExtension(_T(""));	 
}						  
 
//------------------------------------------------------------- 
// Pre     : 
// Post    :  
// Globals : 
// I/O     : 
// Task    : Set path 2 program files folder 
//           Usually C:\Program Files 
//------------------------------------------------------------- 
void CPath::ProgramFilesDirectory() 
{ 
    string strPath; 
    if(GetRegistryPath(HKEY_LOCAL_MACHINE,_T("SOFTWARE\\Microsoft\\Windows\\CurrentVersion"),_T("ProgramFilesDir"),strPath)) 
    { 
        // Got a path, use it 
        Empty(); 
        SetDriveDirectory(strPath.c_str()); 
    } 
    else 
    { 
        // This is some old or unknown system 
        Empty(); 
        SetDriveDirectory(_T("C:\\Programs")); 
    } 
} 
 
//------------------------------------------------------------- 
// Pre     : 
// Post    :  
// Globals : 
// I/O     : 
// Task    : Set path 2 common files folder 
//           Usually C:\Program Files\Common Files 
//------------------------------------------------------------- 
void CPath::CommonFilesDirectory() 
{ 
    string strPath; 
    if(GetRegistryPath(HKEY_LOCAL_MACHINE,_T("SOFTWARE\\Microsoft\\Windows\\CurrentVersion"),_T("CommonFilesDir"),strPath)) 
    { 
        // Got a path, use it 
        Empty(); 
        SetDriveDirectory(strPath.c_str()); 
    } 
    else 
    { 
        // This is some old or unknown system 
        Empty(); 
        SetDriveDirectory(_T("C:\\Programs\\Common")); 
    } 
} 
 
//------------------------------------------------------------- 
// Pre     : 
// Post    :  
// Globals : 
// I/O     : 
// Task    : Set path 2 common files folder 
//           On Win95 is C:\Program Files\Accessories 
//           On WinNT is C:\Program Files\Windows NT\Accessories 
//------------------------------------------------------------- 
void CPath::AccessoriesDirectory() 
{ 
    // Accessories folder is in Program Files folder 
    ProgramFilesDirectory(); 
 
    COSVersion osver; 
    WORD       ostype   =osver.GetOSType(); 
    WORD       wintype  =osver.GetWindowsType(); 
    BOOL       is_Win95 =(ostype==OS_WIN95) || (ostype==OS_WIN98); 
    BOOL       is_NT    =((ostype & OS_WINNT) != 0); 
 
    if((wintype != WIN_32S) && is_Win95) 
    { 
        // Windows 95 
        AppendDirectory(_T("Accessories")); 
        return; 
    } 
 
    if((wintype != WIN_32S) && is_NT && (((osver.GetMajorVersion()==3) && (osver.GetMinorVersion()>=51)) || (osver.GetMajorVersion()>3))) 
    { 
        // Windows NT with the new Chichago shell 
        AppendDirectory(_T("Windows NT\\Accessories")); 
        return; 
    } 
 
    // This is some old or unknown system 
    AppendDirectory(_T("Accessry")); 
} 
 
//------------------------------------------------------------- 
// Pre     : 
// Post    :  
// Globals : 
// I/O     : 
// Task    : Set path 2 media folder 
//           Usually C:\Windows\Media 
//------------------------------------------------------------- 
void CPath::MediaDirectory() 
{ 
    string strPath; 
    if(GetRegistryPath(HKEY_LOCAL_MACHINE,_T("SOFTWARE\\Microsoft\\Windows\\CurrentVersion"),_T("MediaPath"),strPath)) 
    { 
        // Got a path, use it 
        Empty(); 
        SetDriveDirectory(strPath.c_str()); 
    } 
    else 
    { 
        // This is some old or unknown system 
        WindowsDirectory(); 
        AppendDirectory(_T("Media")); 
    } 
} 
 
//------------------------------------------------------------- 
// Pre     : 
// Post    :  
// Globals : 
// I/O     : 
// Task    : Set path 2 device definition folder 
//           Usually C:\Windows\Inf 
//------------------------------------------------------------- 
void CPath::DeviceDirectory() 
{ 
    string strPath; 
    if(GetRegistryPath(HKEY_LOCAL_MACHINE,_T("SOFTWARE\\Microsoft\\Windows\\CurrentVersion"),_T("DevicePath"),strPath)) 
    { 
        // Got a path, use it 
        Empty(); 
        SetDriveDirectory(strPath.c_str()); 
    } 
    else 
    { 
        // This is some old or unknown system 
        WindowsDirectory(); 
        AppendDirectory(_T("Inf")); 
    } 
} 
 
//------------------------------------------------------------- 
// Pre     : 
// Post    : If this function is called on a system which does not 
//           support the new Chichago shell, it will return FALSE 
// Globals : 
// I/O     : 
// Task    : Set path 2 one of the special folders in Chichago 
//------------------------------------------------------------- 
BOOL CPath::ShellDirectory(int nShellFolderID) 
{ 
    COSVersion osver; 
    WORD       ostype   =osver.GetOSType(); 
    WORD       wintype  =osver.GetWindowsType(); 
    BOOL       is_Win95 =(ostype==OS_WIN95) || (ostype==OS_WIN98); 
    BOOL       is_NT    =((ostype & OS_WINNT) != 0); 
 
    if((wintype != WIN_32S) &&  
       (is_Win95 || (is_NT && (((osver.GetMajorVersion()==3) && (osver.GetMinorVersion()>=51)) || (osver.GetMajorVersion()>3))))) 
    { 
        // These systems support the new Chichago shell, get location from registry 
        BOOL         result =FALSE; 
        LPITEMIDLIST pidl   =NULL; 
        TCHAR        special_path[MAX_PATH]; 
 
        // Get a PIDL 2 the special shell folder 
        HRESULT hr =SHGetSpecialFolderLocation(NULL,nShellFolderID,&pidl); 
        if(SUCCEEDED(hr)) 
        { 
            // Convert the PIDL in2 a path 
            result =SHGetPathFromIDList(pidl,special_path); 
 
            // Free the PIDL 
            // Get the address of our task allocator's IMalloc interface 
            LPMALLOC pMalloc; 
            hr =SHGetMalloc(&pMalloc); 
 
            if(SUCCEEDED(hr)) 
            { 
                // Free the PIDL 
                pMalloc->Free(pidl); 
             
                // Free our task allocator 
                pMalloc->Release(); 
            } 
        } 
 
        if(result) 
        { 
            // We've got the special path, now set ourselves 2 point 2 this 
            Empty(); 
            SetDriveDirectory(special_path); 
        } 
 
        return result; 
    } 
 
    // This is some old or unknown system, shell folders not supported 
    return FALSE; 
} 
 
//--------------------------------------------------------------------------- 
// Pre     :  
// Post    : Return TRUE on success 
// Globals :  
// I/O     :  
// Task    : Set path 2 one of the special folders in Chichago 
//           This function manually digs in the registry instead of using 
//           SHGetSpecialFolderLocation, since it seems that this does not work 4 
//           special location constants beginning with  
//--------------------------------------------------------------------------- 
BOOL CPath::ShellDirectory2(int nShellFolderID) 
{ 
    COSVersion osver; 
    WORD       ostype   =osver.GetOSType(); 
    WORD       wintype  =osver.GetWindowsType(); 
    BOOL       is_Win95 =(ostype==OS_WIN95) || (ostype==OS_WIN98); 
    BOOL       is_NT    =((ostype & OS_WINNT) != 0); 
 
    if((wintype != WIN_32S) &&  
       (is_Win95 || (is_NT && (((osver.GetMajorVersion()==3) && (osver.GetMinorVersion()>=51)) || (osver.GetMajorVersion()>3))))) 
    { 
        // These systems support the new Chichago shell, get location from registry 
        HKEY      root; 
        string   key; 
        string   value; 
 
        switch(nShellFolderID) 
        { 
            case CSIDL_DESKTOPDIRECTORY: 
                root  =HKEY_CURRENT_USER; 
                key   =_T("Software\\Microsoft\\Windows\\CurrentVersion\\Explorer\\Shell Folders"); 
                value =_T("Desktop"); 
                break; 
 
            case CSIDL_FAVORITES: 
                root  =HKEY_CURRENT_USER; 
                key   =_T("Software\\Microsoft\\Windows\\CurrentVersion\\Explorer\\Shell Folders"); 
                value =_T("Favorites"); 
                break; 
 
            case CSIDL_FONTS: 
                root  =HKEY_CURRENT_USER; 
                key   =_T("Software\\Microsoft\\Windows\\CurrentVersion\\Explorer\\Shell Folders"); 
                value =_T("Fonts"); 
                break; 
 
            case CSIDL_NETHOOD: 
                root  =HKEY_CURRENT_USER; 
                key   =_T("Software\\Microsoft\\Windows\\CurrentVersion\\Explorer\\Shell Folders"); 
                value =_T("NetHood"); 
                break; 
 
            case CSIDL_PERSONAL: 
                root  =HKEY_CURRENT_USER; 
                key   =_T("Software\\Microsoft\\Windows\\CurrentVersion\\Explorer\\Shell Folders"); 
                value =_T("Personal"); 
                break; 
 
            case CSIDL_RECENT: 
                root  =HKEY_CURRENT_USER; 
                key   =_T("Software\\Microsoft\\Windows\\CurrentVersion\\Explorer\\Shell Folders"); 
                value =_T("Recent"); 
                break; 
 
            case CSIDL_SENDTO: 
                root  =HKEY_CURRENT_USER; 
                key   =_T("Software\\Microsoft\\Windows\\CurrentVersion\\Explorer\\Shell Folders"); 
                value =_T("SendTo"); 
                break; 
 
            case CSIDL_TEMPLATES: 
                root  =HKEY_CURRENT_USER; 
                key   =_T("Software\\Microsoft\\Windows\\CurrentVersion\\Explorer\\Shell Folders"); 
                value =_T("Templates"); 
                break; 
 
            case CSIDL_APPDATA: 
                root  =HKEY_CURRENT_USER; 
                key   =_T("Software\\Microsoft\\Windows\\CurrentVersion\\Explorer\\Shell Folders"); 
                value =_T("AppData"); 
                break; 
 
            case CSIDL_STARTMENU: 
                root  =HKEY_CURRENT_USER; 
                key   =_T("Software\\Microsoft\\Windows\\CurrentVersion\\Explorer\\Shell Folders"); 
                value =_T("Start Menu"); 
                break; 
 
            case CSIDL_STARTUP: 
                root  =HKEY_CURRENT_USER; 
                key   =_T("Software\\Microsoft\\Windows\\CurrentVersion\\Explorer\\Shell Folders"); 
                value =_T("Startup"); 
                break; 
 
            case CSIDL_PROGRAMS: 
                root  =HKEY_CURRENT_USER; 
                key   =_T("Software\\Microsoft\\Windows\\CurrentVersion\\Explorer\\Shell Folders"); 
                value =_T("Programs"); 
                break; 
 
            case CSIDL_COMMON_DESKTOPDIRECTORY: 
                root  =HKEY_LOCAL_MACHINE; 
                key   =_T("SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Explorer\\Shell Folders"); 
                value =_T("Common Desktop"); 
                break; 
 
            case CSIDL_COMMON_STARTMENU: 
                root  =HKEY_LOCAL_MACHINE; 
                key   =_T("SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Explorer\\Shell Folders"); 
                value =_T("Common Start Menu"); 
                break; 
 
            case CSIDL_COMMON_STARTUP: 
                root  =HKEY_LOCAL_MACHINE; 
                key   =_T("SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Explorer\\Shell Folders"); 
                value =_T("Common Startup"); 
                break; 
 
            case CSIDL_COMMON_PROGRAMS: 
                root  =HKEY_LOCAL_MACHINE; 
                key   =_T("SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Explorer\\Shell Folders"); 
                value =_T("Common Programs"); 
                break; 
        } 
         
        string strPath; 
        if(GetRegistryPath(root,key.c_str(),value.c_str(),strPath)) 
        { 
            // Got a path, use it 
            Empty(); 
            SetDriveDirectory(strPath.c_str()); 
 
            return TRUE; 
        } 
    } 
 
    // This is some old or unknown system 
    return FALSE; 
} 
 
//--------------------------------------------------------------------------- 
// Pre     :  
// Post    : Return FALSE if specified value does not exist or some error 
// Globals :  
// I/O     :  
// Task    : Dig in the registry 2 the specified location, and extract a path 
//           Make sure the path is a valid  
//--------------------------------------------------------------------------- 
BOOL CPath::GetRegistryPath(HKEY hRootKey, LPCTSTR lpcszKeyName, LPCTSTR lpcszValueName, string &strPath) 
{ 
    TCHAR     path_buffer    [MAX_PATH]; 
    TCHAR     expanded_buffer[MAX_PATH]; 
    DWORD     path_buffer_size =sizeof(path_buffer); 
    CRegistry reg(hRootKey,lpcszKeyName,KEY_READ); 
     
    if(reg.GetValue(lpcszValueName,(BYTE *)&path_buffer,path_buffer_size)) 
    { 
        COSVersion osver; 
        WORD       ostype =osver.GetOSType(); 
        BOOL       is_NT  =((ostype & OS_WINNT) != 0); 
 
        if(is_NT) 
        { 
            // Running on NT and the ExpandEnvironmentStrings API requires 
            // Unicode strings 
            WCHAR path_buffer_unicode    [MAX_PATH]; 
            WCHAR expanded_buffer_unicode[MAX_PATH]; 
 
            MultiByteToWideChar(CP_ACP,0,path_buffer,-1,path_buffer_unicode,sizeof(path_buffer_unicode)/sizeof(WCHAR)); 
            ExpandEnvironmentStringsW(path_buffer_unicode,expanded_buffer_unicode,sizeof(expanded_buffer_unicode)/sizeof(WCHAR)); 
            WideCharToMultiByte(CP_ACP,0,expanded_buffer_unicode,-1,expanded_buffer,sizeof(path_buffer)/sizeof(TCHAR),NULL,NULL); 
        } 
        else 
            ExpandEnvironmentStrings(path_buffer,expanded_buffer,path_buffer_size); 
 
        strPath.erase(); 
        strPath =expanded_buffer; 
 
        return TRUE; 
    } 
 
    // No such key and/or value 
    return FALSE; 
} 
 
//------------------------------------------------------------- 
// Pre     : 
// Post    : If this function is called on a system which does not 
//           support the new Chichago shell, it will clear the path 
// Globals : 
// I/O     : 
// Task    : Set path 2 desktop folder of currently logged-in user 
//------------------------------------------------------------- 
void CPath::UserDesktopDirectory() 
{ 
    if(!ShellDirectory(CSIDL_DESKTOPDIRECTORY)) 
        Empty(); 
} 
 
//------------------------------------------------------------- 
// Pre     : 
// Post    : If this function is called on a system which does not 
//           support the new Chichago shell, it will clear the path 
// Globals : 
// I/O     : 
// Task    : Set path 2 favorites folder of currently logged-in user 
//------------------------------------------------------------- 
void CPath::UserFavoritesDirectory() 
{ 
    if(!ShellDirectory(CSIDL_FAVORITES)) 
        Empty(); 
} 
 
//------------------------------------------------------------- 
// Pre     : 
// Post    : If this function is called on a system which does not 
//           support the new Chichago shell, it will clear the path 
// Globals : 
// I/O     : 
// Task    : Set path 2 fonts folder of currently logged-in user 
//------------------------------------------------------------- 
void CPath::UserFontsDirectory() 
{ 
    if(!ShellDirectory(CSIDL_FONTS)) 
        Empty(); 
} 
 
//------------------------------------------------------------- 
// Pre     : 
// Post    : If this function is called on a system which does not 
//           support the new Chichago shell, it will clear the path 
// Globals : 
// I/O     : 
// Task    : Set path 2 network hood folder of currently logged-in user 
//------------------------------------------------------------- 
void CPath::UserNetworkNeighbourhoodDirectory() 
{ 
    if(!ShellDirectory(CSIDL_NETHOOD)) 
        Empty(); 
} 
 
//------------------------------------------------------------- 
// Pre     : 
// Post    : If this function is called on a system which does not 
//           support the new Chichago shell, it will clear the path 
// Globals : 
// I/O     : 
// Task    : Set path 2 personal folder of currently logged-in user 
//           Usually C:\My Documents 
//------------------------------------------------------------- 
void CPath::UserDocumentsDirectory() 
{ 
    if(!ShellDirectory(CSIDL_PERSONAL)) 
        Empty(); 
} 
 
//------------------------------------------------------------- 
// Pre     : 
// Post    : If this function is called on a system which does not 
//           support the new Chichago shell, it will clear the path 
// Globals : 
// I/O     : 
// Task    : Set path 2 recent folder of currently logged-in user 
//------------------------------------------------------------- 
void CPath::UserRecentDirectory() 
{ 
    if(!ShellDirectory(CSIDL_RECENT)) 
        Empty(); 
} 
 
//------------------------------------------------------------- 
// Pre     : 
// Post    : If this function is called on a system which does not 
//           support the new Chichago shell, it will clear the path 
// Globals : 
// I/O     : 
// Task    : Set path 2 SendTo folder of currently logged-in user 
//------------------------------------------------------------- 
void CPath::UserSendToDirectory() 
{ 
    if(!ShellDirectory(CSIDL_SENDTO)) 
        Empty(); 
} 
 
//------------------------------------------------------------- 
// Pre     : 
// Post    : If this function is called on a system which does not 
//           support the new Chichago shell, it will clear the path 
// Globals : 
// I/O     : 
// Task    : Set path 2 templates folder of currently logged-in user 
//           Usually C:\Windows\ShellNew 
//------------------------------------------------------------- 
void CPath::UserTemplatesDirectory() 
{ 
    if(!ShellDirectory(CSIDL_TEMPLATES)) 
        Empty(); 
} 
 
//------------------------------------------------------------- 
// Pre     : 
// Post    : If this function is called on a system which does not 
//           support the new Chichago shell, it will clear the path 
// Globals : 
// I/O     : 
// Task    : Set path 2 the recycle bin directory 
//           Usually C:\Recycled 
//------------------------------------------------------------- 
void CPath::UserRecycleBinDirectory() 
{ 
    if(!ShellDirectory(CSIDL_BITBUCKET)) 
        Empty(); 
} 
 
//------------------------------------------------------------- 
// Pre     : 
// Post    : If this function is called on a system which does not 
//           support the new Chichago shell, it will clear the path 
// Globals : 
// I/O     : 
// Task    : Set path 2 the folder where application data is stored  
//           specific 2 currently logged-in user 
//------------------------------------------------------------- 
void CPath::UserApplicationDataDirectory() 
{ 
    if(!ShellDirectory(CSIDL_APPDATA)) 
        Empty(); 
} 
 
//------------------------------------------------------------- 
// Pre     : 
// Post    : If this function is called on a system which does not 
//           support the new Chichago shell, it will clear the path 
// Globals : 
// I/O     : 
// Task    : Set path 2 start menu folder of currently logged-in user 
//------------------------------------------------------------- 
void CPath::UserStartMenuDirectory() 
{ 
    if(!ShellDirectory(CSIDL_STARTMENU)) 
        Empty(); 
} 
 
//------------------------------------------------------------- 
// Pre     : 
// Post    : If this function is called on a system which does not 
//           support the new Chichago shell, it will clear the path 
// Globals : 
// I/O     : 
// Task    : Set path 2 startup folder of currently logged-in user 
//------------------------------------------------------------- 
void CPath::UserStartMenuStartupDirectory() 
{ 
    if(!ShellDirectory(CSIDL_STARTUP)) 
        Empty(); 
} 
 
//------------------------------------------------------------- 
// Pre     : 
// Post    : If this function is called on a system which does not 
//           support the new Chichago shell, it will clear the path 
// Globals : 
// I/O     : 
// Task    : Set path 2 programs menu folder of currently logged-in user 
//------------------------------------------------------------- 
void CPath::UserStartMenuProgramsDirectory() 
{ 
    if(!ShellDirectory(CSIDL_PROGRAMS)) 
        Empty(); 
} 
 
//------------------------------------------------------------- 
// Pre     : 
// Post    : If this function is called on a system which does not 
//           support the new Chichago shell, it will clear the path 
// Globals : 
// I/O     : 
// Task    : Set path 2 desktop folder common 2 all users 
//------------------------------------------------------------- 
void CPath::CommonDesktopDirectory() 
{ 
    if(!ShellDirectory2(CSIDL_COMMON_DESKTOPDIRECTORY)) 
    { 
        // Check if running on Windows 95, and workaround this if so 
        COSVersion osver; 
        WORD       ostype =osver.GetOSType(); 
        if((ostype == OS_WIN95) || (ostype == OS_WIN98)) 
        { 
            // Manual workaround 
            WindowsDirectory(); 
            AppendDirectory(_T("Desktop")); 
        } 
        else 
            // Failure, clear path 
            Empty(); 
    } 
} 
 
//------------------------------------------------------------- 
// Pre     : 
// Post    : If this function is called on a system which does not 
//           support the new Chichago shell, it will clear the path 
// Globals : 
// I/O     : 
// Task    : Set path 2 start menu folder common 2 all users 
//------------------------------------------------------------- 
void CPath::CommonStartMenuDirectory() 
{ 
    if(!ShellDirectory2(CSIDL_COMMON_STARTMENU)) 
    { 
        // Check if running on Windows 95, and workaround this if so 
        COSVersion osver; 
        WORD       ostype =osver.GetOSType(); 
        if((ostype == OS_WIN95) || (ostype == OS_WIN98)) 
        { 
            // Manual workaround 
            WindowsDirectory(); 
            AppendDirectory(_T("Start Menu")); 
        } 
        else 
            // Failure, clear path 
            Empty(); 
    } 
} 
 
//------------------------------------------------------------- 
// Pre     : 
// Post    : If this function is called on a system which does not 
//           support the new Chichago shell, it will clear the path 
// Globals : 
// I/O     : 
// Task    : Set path 2 startup folder common 2 all users 
//------------------------------------------------------------- 
void CPath::CommonStartMenuStartupDirectory() 
{ 
    if(!ShellDirectory2(CSIDL_COMMON_STARTUP)) 
    { 
        // Check if running on Windows 95, and workaround this if so 
        COSVersion osver; 
        WORD       ostype =osver.GetOSType(); 
        if((ostype == OS_WIN95) || (ostype == OS_WIN98)) 
        { 
            // Manual workaround 
            WindowsDirectory(); 
            AppendDirectory(_T("Start Menu\\Programs\\StartUp")); 
        } 
        else 
            // Failure, clear path 
            Empty(); 
    } 
} 
 
//------------------------------------------------------------- 
// Pre     : 
// Post    : If this function is called on a system which does not 
//           support the new Chichago shell, it will clear the path 
// Globals : 
// I/O     : 
// Task    : Set path 2 programs menu folder common 2 all users 
//------------------------------------------------------------- 
void CPath::CommonStartMenuProgramsDirectory() 
{ 
    if(!ShellDirectory2(CSIDL_COMMON_PROGRAMS)) 
    { 
        // Check if running on Windows 95, and workaround this if so 
        COSVersion osver; 
        WORD       ostype =osver.GetOSType(); 
        if((ostype == OS_WIN95) || (ostype == OS_WIN98)) 
        { 
            // Manual workaround 
            WindowsDirectory(); 
            AppendDirectory(_T("Start Menu\\Programs")); 
        } 
        else 
            // Failure, clear path 
            Empty(); 
    } 
} 
 
#ifdef __MFC__ 
//------------------------------------------------------------- 
// Pre     : 
// Post    :  
// Globals : 
// I/O     : 
// Task    : Local profiles are private INI files but located in the same  
//           directory as the executable. These are used for less volatile 
//           settings than those found in the applications main private INI 
//           file, which would be in the Windows directory 
//                 
//           Sets the value of this path to :\\.ini 
//           where name is from lpszName and drive and directory are from the 
//           currently executing module's path. 
//           See also: PrivateProfile, LocalProfile(UINT) 
//------------------------------------------------------------- 
void CPath::LocalProfile(LPCTSTR lpszName, LPCTSTR lpszExtension /*= NULL*/) 
{ 
	ModuleDirectory(); 
     
    if(lpszExtension == NULL) 
        lpszExtension =INI_EXTENSION; 
 
	SetName(lpszName); 
	SetExtension(lpszExtension); 
} 
#endif 
 
#ifdef __MFC__ 
//------------------------------------------------------------- 
// Pre     : 
// Post    :  
// Globals : 
// I/O     : 
// Task    : Like the above LocalProfile, but with the name supplied  
//           by a resource string identified by nResourceID 
//           See also: LocalProfile(LPCTSTR) 
//------------------------------------------------------------- 
void CPath::LocalProfile(UINT nNameResourceID, UINT nExtensionResourceID /*= 0*/) 
{ 
    CString Name; 
    CString Extension; 
 
    if(nExtensionResourceID) 
        Extension.LoadString(nExtensionResourceID); 
    else 
        Extension =INI_EXTENSION; 
                 
    if(Name.LoadString(nNameResourceID)) 
        LocalProfile(Name,Extension); 
} 
#endif 
 
#ifdef __MFC__ 
//------------------------------------------------------------- 
// Pre     : 
// Post    :  
// Globals : 
// I/O     : 
// Task    : Set path 2 file with same name as the current module 
//           and .INI extension in the Windows directory 
//------------------------------------------------------------- 
void CPath::PrivateProfile() 
{ 
    CPath WindowsDirectory(WINDOWS_DIRECTORY); 
     
	Module(); 
	SetDriveDirectory(WindowsDirectory); 
	SetExtension(INI_EXTENSION); 
} 
#endif 
 
//------------------------------------------------------------- 
// Pre     : 
// Post    :  
// Globals : 
// I/O     : 
// Task    : Set path 2 file WIN.INI in the Windows directory 
//------------------------------------------------------------- 
void CPath::WindowsProfile() 
{ 
    WindowsDirectory(); 
	SetNameExtension(_T("Win.INI")); 
} 
 
//------------------------------------------------------------- 
// Pre     : 
// Post    :  
// Globals : 
// I/O     : 
// Task    : Set path 2 file WIN.INI in the Windows directory 
//------------------------------------------------------------- 
void CPath::SystemProfile() 
{ 
    WindowsDirectory(); 
	SetNameExtension(_T("System.INI")); 
} 
 
//------------------------------------------------------------- 
// Pre     : 
// Post    :  
// Globals : 
// I/O     : 
// Task    : Turn this path from "x:\directory\subdirectory\name.ext" 
//           to just "x:\" 
//------------------------------------------------------------- 
void CPath::MakeRoot() 
{    
	SetDirectory(_T("")); 
	SetNameExtension(_T("")); 
} 
 
//------------------------------------------------------------- 
// Pre     : Only the first 3 character from lpcszPrefix will be used 
// Post    : Returns TRUE on success 
// Globals : 
// I/O     : 
// Task    : Creates a temporary name 
//------------------------------------------------------------- 
BOOL CPath::CreateTempName(LPCTSTR lpcszPrefix) 
{ 
    // Check that we've got a prefix 
    if(!lpcszPrefix) 
        return FALSE; 
 
	string Dir; 
    TCHAR  temp_file[MAX_PATH]; 
 
    GetDriveDirectory(Dir); 
 
    if(::GetTempFileName(Dir.c_str(),lpcszPrefix,0,temp_file) != 0) 
    { 
        // Got a temp file name 
        *this =temp_file; 
        SetExtension(_T("tmp")); 
 
        // GetTempFileName actually created the file, remove it now, 
        // we only needed a name 
        Delete(TRUE); 
 
        return TRUE; 
    } 
 
	return FALSE; 
} 
 
//--------------------------------------------------------------------------- 
// Pre     : Only the first 3 character from lpcszPrefix will be used 
// Post    : Returns TRUE on success 
// Globals :  
// I/O     :  
// Task    : Creates a temporary folder name 
//--------------------------------------------------------------------------- 
BOOL CPath::CreateTempDir(LPCTSTR lpcszPrefix, UINT nRetries) 
{ 
    // Check that we've got a prefix 
    if(!lpcszPrefix) 
        return FALSE; 
 
    UINT  retries =0; 
    BOOL  bSuccess =FALSE; 
	TCHAR temp_prefix[ 5]; 
    TCHAR temp_name  [15]; 
 
	ZeroMemory(temp_prefix, sizeof(temp_prefix)); 
	STRNCPY(temp_prefix,lpcszPrefix,4); 
    temp_prefix[3] ='\0'; 
 
    while(!bSuccess && (retries < nRetries)) 
    { 
        STRCPY(temp_name, temp_prefix); 
        string temp =RandomDigits(5); 
        STRCAT(temp_name,temp.c_str()); 
        STRCAT(temp_name,_T(".tmp")); 
 
        CPath test(*this); 
 
        test.AppendDirectory(temp_name); 
        if(!test.DirectoryExists() && test.CreateDirectory()) 
        { 
            // CreateTempDir actually created the folder, remove it now, 
            // we only needed a name 
            test.RemoveDirectory(); 
            bSuccess =TRUE; 
        } 
 
        retries++; 
    } 
 
    if(bSuccess) 
        AppendDirectory(temp_name); 
 
	return bSuccess; 
} 
 
//------------------------------------------------------------- 
// Pre     : 
// Post    : Returns TRUE on success 
// Globals : 
// I/O     : 
// Task    : Sets path 2 a random name, and optionally ensures 
//           uniqueness of that path 
//------------------------------------------------------------- 
BOOL CPath::CreateRandomName(BOOL bMustNotExist /*= TRUE*/, UINT nRetries /*= 1000*/) 
{ 
	string Name; 
 
	for(UINT nRetry=0; nRetry < nRetries; nRetry++) 
	{ 
		Name =RandomDigits(8); 
		SetName(Name.c_str()); 
        if(!bMustNotExist) 
            return TRUE; 
		if(!Exists()) 
			return TRUE; 
	} 
 
	return FALSE; 
} 
 
//------------------------------------------------------------- 
// Pre     : 
// Post    : Returns TRUE on success 
// Globals : 
// I/O     : 
// Task    : Create a new name, based on the existing name, for the same 
//           drive and directory. If bMustNotExist, test the path up to  
//           nRetries till we get an unused path 
//           See also: CreateRandomName 
//------------------------------------------------------------- 
BOOL CPath::CreateSimilarName(BOOL bMustNotExist /*= TRUE*/, UINT nRetries /*= 1000*/) 
{ 
	string NewName; 
    string OriginalName; 
 
	GetName(OriginalName); 
		 
	for(UINT nRetry=0; nRetry < nRetries; nRetry++) 
	{ 
		NewName =OriginalName + RandomDigits(_MAX_FNAME - OriginalName.length()); 
		SetName(NewName.c_str()); 
		if(!Exists() || !bMustNotExist) 
			return TRUE; 
	} 
 
	return FALSE; 
} 
 
//------------------------------------------------------------- 
// Pre     : 
// Post    : Returns one of the EX_DRIVE_ constants 
// Globals : 
// I/O     : 
// Task    : Return the type of the drive this path points to 
//           See DrvType.H for more details 
//------------------------------------------------------------- 
UINT CPath::GetDriveType() const 
{ 
	CPath  RootPath = *this; 
    string Root; 
 
	RootPath.MakeRoot(); 
    Root =(LPCTSTR)RootPath; 
 
	return GetDriveTypeEx(TOLOWER(Root[0]) - 'a'); 
} 
 
//------------------------------------------------------------- 
// Pre     : 
// Post    : Return -1 on error 
// Globals : 
// I/O     : 
// Task    : Find out the amount of free space on drive (in bytes) 
//------------------------------------------------------------- 
DWORD CPath::DriveFreeSpaceBytes() const 
{ 
    CPath  RootPath = *this; 
    string Root; 
 
	RootPath.MakeRoot(); 
 
	DWORD nSectorsPerCluster; 
	DWORD nBytesPerSector; 
	DWORD nFreeClusters; 
	DWORD nClusters; 
 
	if(!GetDiskFreeSpace((LPCTSTR)RootPath,&nSectorsPerCluster,&nBytesPerSector,&nFreeClusters,&nClusters)) 
		return 0; 
	else		 
		return nFreeClusters * nSectorsPerCluster * nBytesPerSector; 
} 
 
//------------------------------------------------------------- 
// Pre     : 
// Post    : Return -1 on error 
// Globals : 
// I/O     : 
// Task    : Find out the size of the drive (in bytes) 
//------------------------------------------------------------- 
DWORD CPath::DriveTotalSpaceBytes() const 
{ 
    CPath  RootPath = *this; 
    string Root; 
 
	RootPath.MakeRoot(); 
 
	DWORD nSectorsPerCluster; 
	DWORD nBytesPerSector; 
	DWORD nFreeClusters; 
	DWORD nClusters; 
 
	if(!GetDiskFreeSpace((LPCTSTR)RootPath,&nSectorsPerCluster,&nBytesPerSector,&nFreeClusters,&nClusters)) 
		return 0; 
	else		 
		return nClusters * nSectorsPerCluster * nBytesPerSector; 
} 
 
//------------------------------------------------------------- 
// Pre     : 
// Post    : Return -1 on error 
// Globals : 
// I/O     : 
// Task    : Find out the cluster size on this drive (in bytes) 
//------------------------------------------------------------- 
DWORD CPath::GetDriveClusterSize() const 
{ 
    CPath  RootPath = *this; 
    string Root; 
 
	RootPath.MakeRoot(); 
 
	DWORD nSectorsPerCluster; 
	DWORD nBytesPerSector; 
	DWORD nFreeClusters; 
	DWORD nClusters; 
 
	if(!GetDiskFreeSpace((LPCTSTR)RootPath,&nSectorsPerCluster,&nBytesPerSector,&nFreeClusters,&nClusters)) 
		return 0; 
	else		 
		return nSectorsPerCluster * nBytesPerSector; 
} 
 
//------------------------------------------------------------- 
// Pre     : 
// Post    : Return TRUE on success 
// Globals : 
// I/O     : 
// Task    : Find out info about drive 
//------------------------------------------------------------- 
BOOL CPath::GetDiskInfo(LPDWORD lpSectorsPerCluster, 
						LPDWORD lpBytesPerSector, 
						LPDWORD lpFreeClusters, 
						LPDWORD lpClusters) const 
{ 
    // Create root path 
	CPath RootPath = *this; 
	RootPath.MakeRoot(); 
 
	return GetDiskFreeSpace((LPCTSTR)RootPath, 
                            lpSectorsPerCluster, 
                            lpBytesPerSector, 
                            lpFreeClusters, 
                            lpClusters); 
} 
 
//--------------------------------------------------------------------------- 
// Pre     :  
// Post    : Return TRUE if a directory 
// Globals :  
// I/O     :  
// Task    : Check if this path represents a directory 
//--------------------------------------------------------------------------- 
BOOL CPath::IsDirectory() const 
{ 
    // Check if this path has a filename 
    string file_name; 
    GetNameExtension(file_name); 
     
    return file_name.empty(); 
} 
 
//------------------------------------------------------------- 
// Pre     : 
// Post    : Return TRUE if directory exists 
// Globals : 
// I/O     : 
// Task    : To determine if the directory exists, we need to 
//           create a test path with a wildcard (*.*) extension 
//           and see if FindFirstFile returns anything.  We don't 
//           use CPath::FindFirst() because that routine parses out 
//           '.' and '..', which fails for empty directories 
//------------------------------------------------------------- 
BOOL CPath::DirectoryExists() const 
{ 
    // Create test path	 
	CPath TestPath(m_strPath.c_str()); 
	TestPath.SetNameExtension(WILD_NAME_EXTENSION); 
 
	WIN32_FIND_DATA	FindData; 
	HANDLE          hFindFile =FindFirstFile((LPCTSTR)TestPath,&FindData); // Find anything 
	BOOL            bGotFile  =(hFindFile != INVALID_HANDLE_VALUE); 
 
	if(hFindFile != NULL)	// Make sure we close the search 
	    FindClose(hFindFile); 
 
	return bGotFile; 
}                                                      
 
//------------------------------------------------------------- 
// Pre     : 
// Post    : Return TRUE if there are no files(s)/folder(s) in 
//           directory. All objects (with hidden, system, etc. attributes) 
//           are looked up 
// Globals : 
// I/O     : 
// Task    : Check if directory contains any file(s) 
//-------------------------------------------------------------	 
BOOL CPath::IsDirectoryEmpty() const 
{ 
	CPath FileSpec = *this; 
	 
	FileSpec.SetNameExtension(WILD_NAME_EXTENSION); 
	return !FileSpec.FindFirst(_A_NORMAL | _A_ARCH | _A_HIDDEN | _A_SYSTEM | _A_RDONLY) && 
           !FileSpec.FindFirst(_A_HIDDEN | _A_SUBDIR); 
} 
 
//------------------------------------------------------------- 
// Pre     : 
// Post    : Return TRUE if these is such a file 
// Globals : 
// I/O     : 
// Task    : Check if file exists 
//------------------------------------------------------------- 
BOOL CPath::Exists() const 
{ 
	WIN32_FIND_DATA FindData; 
	HANDLE          hFindFile =FindFirstFile(m_strPath.c_str(),&FindData); 
	BOOL            bSuccess  =(hFindFile != INVALID_HANDLE_VALUE); 
 
	if(hFindFile != NULL)	// Make sure we close the search 
	    FindClose(hFindFile); 
 
	return bSuccess; 
} 
 
//------------------------------------------------------------- 
// Pre     : 
// Post    : Return file size, -1 on error 
// Globals : 
// I/O     : 
// Task    : Get file size (in bytes) 
//------------------------------------------------------------- 
DWORD CPath::GetSize() const 
{ 
    WIN32_FIND_DATA FindData; 
	HANDLE          hFindFile =FindFirstFile(m_strPath.c_str(),&FindData); 
	BOOL            bSuccess  =(hFindFile != INVALID_HANDLE_VALUE); 
 
	if(hFindFile != NULL)	// Make sure we close the search 
	    FindClose(hFindFile); 
 
    return bSuccess ? FindData.nFileSizeLow : (DWORD)-1; 
} 
 
//------------------------------------------------------------- 
// Pre     : 
// Post    : Return file attributes 
// Globals : 
// I/O     : 
// Task    : Get attributes of the file 
//------------------------------------------------------------- 
DWORD CPath::GetAttributes() const 
{ 
    return GetFileAttributes(m_strPath.c_str()); 
} 
 
//--------------------------------------------------------------------------- 
// Pre     :  
// Post    : Return TRUE on success 
// Globals :  
// I/O     :  
// Task    : Set the attributes of the file 
//--------------------------------------------------------------------------- 
BOOL CPath::SetAttributes(DWORD dwAttributes) 
{ 
    return SetFileAttributes(m_strPath.c_str(),dwAttributes); 
} 
 
//------------------------------------------------------------- 
// Pre     : 
// Post    : Return TRUE on success 
// Globals : 
// I/O     : 
// Task    : Get file creation, last acces and/or last modification  
//           time as local time 
//------------------------------------------------------------- 
BOOL CPath::GetTime(FILETIME *lpCreated, FILETIME *lpAccessed, FILETIME *lpModified) const 
{ 
    WIN32_FIND_DATA findFileData; 
	HANDLE hFind =FindFirstFile(m_strPath.c_str(),&findFileData); 
	if(hFind == INVALID_HANDLE_VALUE) 
        // Oops, no such file system object 
		return FALSE; 
    FindClose(hFind); 
 
    FILETIME ftLastWriteTimeLocal; 
    FileTimeToLocalFileTime(&findFileData.ftLastWriteTime,&ftLastWriteTimeLocal); 
 
	if(lpCreated) 
    { 
        FILETIME ftCreationTimeLocal; 
        FileTimeToLocalFileTime(&findFileData.ftCreationTime,&ftCreationTimeLocal); 
 
        *lpCreated =ftCreationTimeLocal; 
        if(!ftCreationTimeLocal.dwLowDateTime && 
           !ftCreationTimeLocal.dwHighDateTime) 
           // Adjust time 
           *lpCreated =ftLastWriteTimeLocal; 
    } 
 
    if(lpAccessed) 
    { 
        FILETIME ftLastAccessTimeLocal; 
        FileTimeToLocalFileTime(&findFileData.ftLastAccessTime,&ftLastAccessTimeLocal); 
 
        *lpAccessed =ftLastAccessTimeLocal; 
        if(!ftLastAccessTimeLocal.dwLowDateTime && 
           !ftLastAccessTimeLocal.dwHighDateTime) 
           // Adjust time 
           *lpAccessed =ftLastWriteTimeLocal; 
    } 
 
    if(lpModified) 
        *lpModified =ftLastWriteTimeLocal; 
 
    return TRUE; 
} 
 
//--------------------------------------------------------------------------- 
// Pre     :  
// Post    : Return creation time 
// Globals :  
// I/O     :  
// Task    : Get the time this file/folder was created 
//--------------------------------------------------------------------------- 
FILETIME CPath::GetTimeCreated() const 
{ 
    FILETIME file_time; 
    ZeroMemory(&file_time,sizeof(file_time)); 
 
    GetTime(&file_time,NULL,NULL); 
 
    return file_time; 
} 
 
//--------------------------------------------------------------------------- 
// Pre     :  
// Post    : Return last access time 
// Globals :  
// I/O     :  
// Task    : Get the time this file/folder was last accessed 
//--------------------------------------------------------------------------- 
FILETIME CPath::GetTimeLastAccessed() const 
{ 
    FILETIME file_time; 
    ZeroMemory(&file_time,sizeof(file_time)); 
 
    GetTime(NULL,&file_time,NULL); 
 
    return file_time; 
} 
 
//--------------------------------------------------------------------------- 
// Pre     :  
// Post    : Return last modification time 
// Globals :  
// I/O     :  
// Task    : Get the time this file/folder was last changed 
//--------------------------------------------------------------------------- 
FILETIME CPath::GetTimeLastModified() const 
{ 
    FILETIME file_time; 
    ZeroMemory(&file_time,sizeof(file_time)); 
 
    GetTime(NULL,NULL,&file_time); 
 
    return file_time; 
} 
 
//--------------------------------------------------------------------------- 
// Pre     : All time parameters are supposed 2 be local times 
// Post    : Return TRUE on success 
// Globals :  
// I/O     :  
// Task    : Set the creation, last acces and/or last modification time 
//--------------------------------------------------------------------------- 
BOOL CPath::SetTime(const FILETIME *lpCreated, const FILETIME *lpAccessed, const FILETIME *lpModified) 
{ 
    if(!lpCreated && !lpAccessed && !lpModified) 
        // No time params specified 
        return FALSE; 
 
    WIN32_FIND_DATA findFileData; 
	HANDLE hFind =FindFirstFile(m_strPath.c_str(),&findFileData); 
	if(hFind == INVALID_HANDLE_VALUE) 
        // Oops, no such file system object 
		return FALSE; 
    FindClose(hFind); 
 
	if(lpCreated) 
        LocalFileTimeToFileTime(lpCreated,&findFileData.ftCreationTime); 
    if(lpAccessed) 
        LocalFileTimeToFileTime(lpAccessed,&findFileData.ftLastAccessTime); 
    if(lpModified) 
        LocalFileTimeToFileTime(lpModified,&findFileData.ftLastWriteTime); 
 
    HANDLE hFile =CreateFile(m_strPath.c_str(),GENERIC_WRITE,0,NULL,OPEN_EXISTING,FILE_ATTRIBUTE_NORMAL,NULL); 
    if(hFile != INVALID_HANDLE_VALUE) 
    { 
        SetFileTime(hFile,lpCreated  ? &findFileData.ftCreationTime   : NULL, 
                          lpAccessed ? &findFileData.ftLastAccessTime : NULL, 
                          lpModified ? &findFileData.ftLastWriteTime  : NULL); 
        CloseHandle(hFile); 
        return TRUE; 
    } 
 
    return FALSE; 
} 
 
//--------------------------------------------------------------------------- 
// Pre     : lpCreated is supposed 2 be local time 
// Post    : Return TRUE on success 
// Globals :  
// I/O     :  
// Task    : Set the file's creation time 
//--------------------------------------------------------------------------- 
BOOL CPath::SetTimeCreated(const FILETIME *lpCreated) 
{ 
    return SetTime(lpCreated,NULL,NULL); 
} 
 
//--------------------------------------------------------------------------- 
// Pre     : lpModified is supposed 2 be local time 
// Post    : Return TRUE on success 
// Globals :  
// I/O     :  
// Task    : Set the file's creation time 
//--------------------------------------------------------------------------- 
BOOL CPath::SetTimeLastModified(const FILETIME *lpModified) 
{ 
    return SetTime(NULL,NULL,lpModified); 
} 
 
//--------------------------------------------------------------------------- 
// Pre     : lpAccessed is supposed 2 be local time 
// Post    : Return TRUE on success 
// Globals :  
// I/O     :  
// Task    : Set the file's creation time 
//--------------------------------------------------------------------------- 
BOOL CPath::SetTimeLastAccessed(const FILETIME *lpAccessed) 
{ 
    return SetTime(NULL,lpAccessed,NULL); 
} 
 
//------------------------------------------------------------- 
// Pre     : 
// Post    : Return TRUE on success 
// Globals : 
// I/O     : 
// Task    : Delete file 
//------------------------------------------------------------- 
BOOL CPath::Delete(BOOL bEvenIfReadOnly) 
{ 
    DWORD dwAttr =::GetFileAttributes(m_strPath.c_str()); 
    if(dwAttr == (DWORD)-1) 
        // File does not exists 
        return FALSE; 
 
    if(((dwAttr & FILE_ATTRIBUTE_READONLY) == FILE_ATTRIBUTE_READONLY) && !bEvenIfReadOnly) 
        // File is read-only, and we're not allowed 2 delete it 
        return FALSE; 
 
    SetFileAttributes(m_strPath.c_str(),FILE_ATTRIBUTE_NORMAL); 
    return DeleteFile(m_strPath.c_str()); 
}	 
 
//------------------------------------------------------------- 
// Pre     : 
// Post    : Return TRUE on success 
// Globals : 
// I/O     : 
// Task    : Rename file 
//------------------------------------------------------------- 
BOOL CPath::Rename(LPCTSTR lpszNewPath) 
{ 
    return MoveTo(lpszNewPath,FALSE); 
}	 
 
//------------------------------------------------------------- 
// Pre     : 
// Post    : Return TRUE on success, FALSE if there is such a target file 
//           and we weren't granted permission 2 overwrite file or some error 
// Globals : 
// I/O     : 
// Task    : Copy file 
//           Since ::CopyFile will not overwrite read only files 
//           we will make sure the target file is writable first 
//------------------------------------------------------------- 
BOOL CPath::CopyTo(LPCTSTR lpcszTargetFile, BOOL bOverwrite) 
{ 
    // Check if the target file exists 
    CPath TargetFile(lpcszTargetFile); 
    if(TargetFile.Exists()) 
    { 
        // Yeah there is already such a target file  
        // Decide if we should overwrite 
        if(!bOverwrite) 
            return FALSE; 
 
        // Delete any previous target 
        if(!TargetFile.Delete(TRUE)) 
            return FALSE; 
    } 
 
    // CopyFile will set the target's attributes 2 the same as  
    // the source after copying 
    return CopyFile(m_strPath.c_str(),lpcszTargetFile,!bOverwrite); 
} 
 
//------------------------------------------------------------- 
// Pre     : 
// Post    : Return TRUE on success, FALSE if there is such a target file 
//           and we weren't granted permission 2 overwrite file or some error 
// Globals : 
// I/O     : 
// Task    : Move file 
//------------------------------------------------------------- 
BOOL CPath::MoveTo(LPCTSTR lpcszTargetFile, BOOL bOverwrite) 
{ 
    // Check if the target file exists 
    CPath TargetFile(lpcszTargetFile); 
    if(TargetFile.Exists()) 
    { 
        // Yeah there is already such a target file  
        // Decide if we should overwrite 
        if(!bOverwrite) 
            return FALSE; 
 
        // Delete any previous target 
        if(!TargetFile.Delete(TRUE)) 
            return FALSE; 
    } 
 
   return MoveFile(m_strPath.c_str(),lpcszTargetFile); 
} 
 
//------------------------------------------------------------- 
// Pre     : 
// Post    : Return TRUE if attributes do match 
// Globals : 
// I/O     : 
// Task    : Compare finder attributes 
//------------------------------------------------------------- 
BOOL CPath::AttributesMatch(DWORD dwTargetAttributes, DWORD dwFileAttributes) 
{ 
	if(dwTargetAttributes == _A_NORMAL) 
	{ 
		return ((_A_SUBDIR & dwFileAttributes) == 0); 
	} 
	else 
	{ 
		return ( ((dwTargetAttributes & dwFileAttributes) != 0) && 
				 ((_A_SUBDIR & dwTargetAttributes) == (_A_SUBDIR & dwFileAttributes)) ); 
	} 
 
    return FALSE; 
} 
 
//------------------------------------------------------------- 
// Pre     : 
// Post    : Return TRUE if any match found 
// Globals : 
// I/O     : 
// Task    : Find the first file that meets this path and the specified attributes 
//           You can specify the current attributes of the file or directory  
//           The attributes are represented by a combination (|) of the following  
//           constants: 
// 
//           _A_ARCH    Archive. Set whenever the file is  
//                      changed, and cleared by the BACKUP command 
//           _A_HIDDEN  Hidden file. Not normally seen with  
//                      the DIR command, unless the /AH option  
//                      is used. Returns information about normal  
//                      files as well as files with this attribute 
//           _A_NORMAL  Normal. File can be read or written to  
//                      without restriction 
//           _A_RDONLY  Read-only. File cannot be opened for writing,  
//                      and a file with the same name cannot be created 
//           _A_SUBDIR  Subdirectory 
//           _A_SYSTEM  System file. Not normally seen with the DIR  
//                      command, unless the /AS option is used 
// 
//           These attributes do not follow a simple additive logic 
//           Note that _A_NORMAL is 0x00, so it effectively cannot be 
//           removed from the attribute set. You will therefore always 
//           get normal files, and may also get Archive, Hidden, etc. 
//           if you specify those attributes 
//           See aso: FindFirstFile, FindNextFile 
//------------------------------------------------------------- 
BOOL CPath::FindFirst(DWORD dwAttributes /*= _A_NORMAL*/) 
{ 
	m_dwFindFileAttributes =dwAttributes; 
	BOOL bGotFile; 
	BOOL bWantSubdirectory =(BOOL)(_A_SUBDIR & dwAttributes); 
 
    // Close handle to any previous enumeration 
    Exit(); 
 
	// i.) Finding first candidate file 
	WIN32_FIND_DATA	FindData; 
	m_hFindFile =FindFirstFile(m_strPath.c_str(),&FindData); 
	bGotFile =(m_hFindFile != INVALID_HANDLE_VALUE); 
 
	while(bGotFile) 
	{ 
		// ii.) Compare candidate to attributes, and filter out the "." and ".." folders 
		if(!AttributesMatch(m_dwFindFileAttributes,FindData.dwFileAttributes)) 
			goto LABEL_GetAnother; 
		if(bWantSubdirectory && (FindData.cFileName[0] == '.')) 
			goto LABEL_GetAnother; 
 
		// iii.) Found match, prepare result 
        if((_A_SUBDIR & m_dwFindFileAttributes) != 0) 
            StripTrailingBackslash(m_strPath); 
 
		SetNameExtension(FindData.cFileName); 
 
        if((_A_SUBDIR & dwAttributes) != 0) 
            EnsureTrailingBackslash(m_strPath); 
		return TRUE; 
	 
		// iv.) Not found match, get another 
	    LABEL_GetAnother: 
		bGotFile =FindNextFile(m_hFindFile,&FindData); 
	} 
	 
	return FALSE; 
} 
 
//------------------------------------------------------------- 
// Pre     : 
// Post    : Return TRUE if a new match found 
// Globals : 
// I/O     : 
// Task    : Find the next file that meets the conditions specified  
//           in the last FindFirst call 
//------------------------------------------------------------- 
BOOL CPath::FindNext() 
{ 
    ASSERTX(m_hFindFile != NULL); 
 
	WIN32_FIND_DATA	FindData;	 
	while(FindNextFile(m_hFindFile,&FindData) != FALSE) 
    { // while(FindNext(...)) 
 
		if(AttributesMatch(m_dwFindFileAttributes,FindData.dwFileAttributes)) 
		{ // if(AttributesMatch(...) 
	        if((_A_SUBDIR & m_dwFindFileAttributes) == _A_SUBDIR) 
			{ 
                // Found a directory 
				UpDirectory(); 
 
				AppendDirectory(FindData.cFileName); 
			} 
			else 
                // Found a file 
				SetNameExtension(FindData.cFileName); 
 
	        if((_A_SUBDIR & m_dwFindFileAttributes) == _A_SUBDIR) 
    	    	EnsureTrailingBackslash(m_strPath); 
			return TRUE; 
		} 
	} 
 
	return FALSE; 
} 
 
//------------------------------------------------------------- 
// Pre     : 
// Post    : Return TRUE on success 
// Globals : 
// I/O     : 
// Task    : Change current working directory of application 2 path 
//------------------------------------------------------------- 
BOOL CPath::ChangeDirectory() 
{ 
	string DriveDirectory; 
	GetDriveDirectory(DriveDirectory); 
 
    return SetCurrentDirectory(DriveDirectory.c_str()); 
} 
 
//------------------------------------------------------------- 
// Pre     : 
// Post    : Return TRUE if deleted OK 
// Globals : 
// I/O     : 
// Task    : Delete everything in the directory 
//------------------------------------------------------------- 
BOOL CPath::RemoveDirectoryContent() 
{ 
    // Deleting the directory's content 
    // Iterate the content of the directory and delete it 
    string filename; 
    CPath  iterator(*this); 
    BOOL   deleted_OK =TRUE; 
 
    // Deleting all contained files 
    iterator.SetNameExtension(WILD_NAME_EXTENSION); 
    BOOL iterating =iterator.FindFirst(_A_NORMAL | _A_ARCH | _A_HIDDEN | _A_SYSTEM | _A_RDONLY); 
    while(iterating) 
    { 
        // Found something 
        deleted_OK =iterator.Delete(TRUE); 
 
        if(!deleted_OK) 
            break; 
 
        iterator.SetNameExtension(WILD_NAME_EXTENSION); 
        iterating =iterator.FindFirst(_A_NORMAL | _A_ARCH | _A_HIDDEN | _A_SYSTEM | _A_RDONLY); 
    } 
 
    if(!deleted_OK) 
        return FALSE; 
 
    // Deleting all contained directories 
    iterator.SetNameExtension(WILD_NAME_EXTENSION); 
    iterating =iterator.FindFirst(_A_HIDDEN | _A_SUBDIR); 
    while(iterating) 
    { 
        // Found something 
        deleted_OK =iterator.RemoveDirectory(TRUE); 
 
        if(!deleted_OK) 
            break; 
 
        iterator.SetNameExtension(WILD_NAME_EXTENSION); 
        iterator.UpDirectory(); 
        iterating =iterator.FindFirst(_A_HIDDEN | _A_SUBDIR); 
    } 
 
    return deleted_OK; 
} 
 
//------------------------------------------------------------- 
// Pre     : 
// Post    : Return TRUE if deleted OK 
// Globals : 
// I/O     : 
// Task    : Remove the directory 
//------------------------------------------------------------- 
BOOL CPath::RemoveDirectory(BOOL bEvenIfNotEmpty) 
{ 
    if(bEvenIfNotEmpty) 
    { 
        // Delete the directory's content 
        if(!RemoveDirectoryContent()) 
            return FALSE; 
    } 
 
    // Make sure there is no enumeration in progress, 
    // otherwise we we'll get an error (sharing violation) because 
    // that search keeps an open handle for this directory 
    Exit(); 
     
    // Deleting this directory (and only if it's empty) 
	string DriveDirectory; 
	GetDriveDirectory(DriveDirectory); 
 
    return ::RemoveDirectory(DriveDirectory.c_str()); 
} 
 
//------------------------------------------------------------- 
// Pre     : If bCreateIntermediates is TRUE, create all eventually 
//           missing parent directories too 
// Post    : Return TRUE on success 
// Globals : 
// I/O     : 
// Task    : Create new directory 
//------------------------------------------------------------- 
BOOL CPath::CreateDirectory(BOOL bCreateIntermediates /*= TRUE*/) 
{ 
	string	PathText; 
	BOOL	bSuccess; 
		 
	GetDriveDirectory(PathText); 
    StripTrailingBackslash(PathText); 
    bSuccess =::CreateDirectory(PathText.c_str(),NULL); 
	if(!bSuccess) 
		bSuccess =ChangeDirectory(); 
		 
	if(!bSuccess && bCreateIntermediates) 
	{ 
        string::size_type nDelimiter =PathText.rfind(DIRECTORY_DELIMITER); 
        if(nDelimiter == string::npos) 
			return FALSE; 
 
		PathText.resize(nDelimiter + 1); 
		CPath SubPath(PathText); 
		 
		if(SubPath.CreateDirectory()) 
			return CreateDirectory(FALSE); 
		else  
			return FALSE; 
	} 
 
	return bSuccess; 
}			 
 
//------------------------------------------------------------- 
// Pre     : If bCreateIntermediates is TRUE, create all eventually 
//           missing parent directories too 
// Post    :  
// Globals : 
// I/O     : 
// Task    : Same as CreateDirectory, but throws an CPathException if 
//           something goes wrong 
//------------------------------------------------------------- 
void CPath::CreateDirectoryEx(BOOL bCreateIntermediates /*= TRUE*/) 
{                           
	BOOL bSuccess =CreateDirectory(bCreateIntermediates); 
	 
	if(!bSuccess) 
		throw new CPathException(GetLastError()); 
}