path.cpp

Upload User: wangcyou
Upload Date: 2007-01-01
Package Size: 142k
Code Size: 82k
Category: Windows Develop
Development Platform: Visual C++
  1. //---------------------------------------------------------------------------
  2. // Copyright (C) 1998, Interscope Ltd. All rights reserved.
  3. // Reproduction or distribution of this program, or any portion of it, 
  4. // is permitted only if this header is kept as it is.
  5. // For more information, contact:
  6. //
  7. // Interscope Ltd., 5 Culturii St., 5th Floor, 4800 Baia Mare, RO
  8. //    Phone/Fax: +40-62-215023
  9. //    E-mail: office@interscope.ro
  10. //
  11. //   $Author: Levente Farkas $
  12. //     $Date: 9/14/98 4:34a $
  13. //  $Modtime: 9/14/98 4:34a $
  14. // $Revision: 120 $
  15. //  $Archive: /Interscope/Callisto/Path.Cpp $
  16. // $Workfile: Path.Cpp $
  17. //-----------------------------------------------------------------------
  18. #ifdef __STDAFX__
  19. #include "StdAfx.H"
  20. #endif
  21. #include <Direct.H>
  22. #include <StdLib.H>
  23. #include <StdIO.H>
  24. #include <IO.H>
  25. #include <ShlObj.H>
  26. #ifndef __MFC__
  27. #include "Trace.H"
  28. #endif
  29. #include "AssertX.H"
  30. #include "StringHelper.Hpp"
  31. #include "OSVersion.Hpp"
  32. #include "Registry.Hpp"
  33. #include "Reminder.Hpp"
  34. #include "Path.Hpp"
  35. //--- Debugee --------------------------------------------------------------
  36. #ifdef _DEBUG
  37. #undef THIS_FILE
  38. static char THIS_FILE[] = __FILE__;
  39. #ifdef __MFC__
  40. #define new DEBUG_NEW
  41. #endif // __MFC__
  42. #endif // _DEBUG
  43. //-------------------------------------------------------------
  44. // Pre     :
  45. // Post    : 
  46. // Globals :
  47. // I/O     :
  48. // Task    : Create a string of length nDigits containing random digits
  49. //-------------------------------------------------------------
  50. static string RandomDigits(int nDigits)
  51. {
  52.     // Keep the number of digits in a rational limit
  53.     ASSERTX(nDigits >  0);
  54.     ASSERTX(nDigits < 20);
  55.     
  56. int    nDigits2 = nDigits;
  57. string Digits;
  58.     TCHAR  next_8_digits[9];
  59.     while(nDigits2 > 0)
  60.     {
  61.         SPRINTF(next_8_digits,_T("%08lx"),GetTickCount());
  62.         for(int i=0; i<8; i++)
  63.         {
  64.             Digits += next_8_digits[i];
  65.             if(--nDigits2 == 0)
  66.                 break;
  67.         }
  68.     }
  69.     int last_digit =rand();
  70.     if(last_digit < 0)
  71.         last_digit =(-last_digit);
  72.     last_digit %= 10;
  73.     Digits[nDigits - 1] ='0' + last_digit;
  74.     
  75. return Digits;
  76. }
  77. //-------------------------------------------------------------
  78. // Pre     :
  79. // Post    : 
  80. // Globals :
  81. // I/O     :
  82. // Task    : Helper function for the various CPath constructors. 
  83. //           Initializes the data members and establishes various
  84. //           class invariants
  85. //-------------------------------------------------------------
  86. inline void CPath::Init()
  87. {
  88. m_dwFindFileAttributes =0;
  89. m_hFindFile =NULL;
  90. }
  91. //-------------------------------------------------------------
  92. // Pre     :
  93. // Post    : 
  94. // Globals :
  95. // I/O     :
  96. // Task    : Helper function for the various CPath destructors.
  97. //           Cleans up varios internals
  98. //-------------------------------------------------------------
  99. inline void CPath::Exit()
  100. {
  101. if(m_hFindFile != NULL)
  102.     {
  103. FindClose(m_hFindFile);
  104.         m_hFindFile =NULL;
  105.     }
  106. }
  107. //-------------------------------------------------------------
  108. // Pre     :
  109. // Post    : 
  110. // Globals :
  111. // I/O     :
  112. // Task    : Constructs a path
  113. //-------------------------------------------------------------
  114. CPath::CPath()
  115. {
  116. Init();
  117.     Empty();
  118. }
  119. //-------------------------------------------------------------
  120. // Pre     :
  121. // Post    : 
  122. // Globals :
  123. // I/O     :
  124. // Task    : Constructs a path as copy of another
  125. //-------------------------------------------------------------
  126. CPath::CPath(const CPath& rPath)
  127. {
  128. Init();
  129. m_strPath =rPath.m_strPath;
  130. }
  131. //-------------------------------------------------------------
  132. // Pre     :
  133. // Post    : 
  134. // Globals :
  135. // I/O     :
  136. // Task    : Constructs a path and points it 2 lpszPath
  137. //-------------------------------------------------------------
  138. CPath::CPath(LPCTSTR lpszPath)
  139. {
  140. Init();
  141.     m_strPath =lpszPath ? lpszPath : _T("");
  142. }
  143. //-------------------------------------------------------------
  144. // Pre     :
  145. // Post    : 
  146. // Globals :
  147. // I/O     :
  148. // Task    : Constructs a path and points it 2 strPath
  149. //-------------------------------------------------------------
  150. CPath::CPath(const string& strPath)
  151. {
  152.     Init();
  153.     m_strPath =strPath;
  154. }
  155. //-------------------------------------------------------------
  156. // Pre     :
  157. // Post    : 
  158. // Globals :
  159. // I/O     :
  160. // Task    : Constructs a path and points it 2 specified 
  161. //           special directory
  162. //-------------------------------------------------------------
  163. CPath::CPath(SpecialDirectoryType eInitialDir)
  164. {
  165. Init();
  166.     switch(eInitialDir)
  167.     {
  168.         // Application's current directory  
  169.         case CURRENT_DIRECTORY:
  170.             CurrentDirectory();
  171.             break;
  172.         // Windows directory
  173.         case WINDOWS_DIRECTORY:
  174.             WindowsDirectory();
  175.             break;
  176.         // Windows' system directory    
  177.         case SYSTEM_DIRECTORY:
  178.             SystemDirectory();
  179.             break;
  180.         // The root directory of system drive
  181.         case SYSTEM_DRIVE_ROOT_DIRECTORY:
  182.             SystemDriveRootDirectory();
  183.             break;
  184.         // The directory where the executable of this app is
  185.         case MODULE_DIRECTORY:
  186.             #ifdef __MFC__
  187.             ModuleDirectory();
  188.             #else
  189.             ASSERTX(FALSE);
  190.             #endif
  191.             break;
  192.         // Windows temp directory
  193. case TEMP_DIRECTORY:
  194. TempDirectory();
  195. break;
  196.         // Program files directory
  197.         case PROGRAM_FILES_DIRECTORY:
  198.             ProgramFilesDirectory();
  199.             break;
  200.         // Common files directory
  201.         case COMMON_FILES_DIRECTORY:
  202.             CommonFilesDirectory();
  203.             break;
  204.         // Accessories directory
  205.         case ACCESSORIES_DIRECTORY:
  206.             AccessoriesDirectory();
  207.             break;
  208.         // Media directory
  209.         case MEDIA_DIRECTORY:
  210.             MediaDirectory();
  211.             break;
  212.         // INF directory
  213.         case DEVICE_DIRECTORY:
  214.             DeviceDirectory();
  215.             break;
  216.         // User specific directories
  217.         case USER_DESKTOP_DIRECTORY:
  218.             UserDesktopDirectory();
  219.             break;
  220.         case USER_FAVORITES_DIRECTORY:
  221.             UserFavoritesDirectory();
  222.             break;
  223.         case USER_FONTS_DIRECTORY:
  224.             UserFontsDirectory();
  225.             break;
  226.         case USER_NETHOOD_DIRECTORY:
  227.             UserNetworkNeighbourhoodDirectory();
  228.             break;
  229.         case USER_DOCUMENTS_DIRECTORY:
  230.             UserDocumentsDirectory();
  231.             break;
  232.         case USER_RECENT_DIRECTORY:
  233.             UserRecentDirectory();
  234.             break;
  235.         case USER_SENDTO_DIRECTORY:
  236.             UserSendToDirectory();
  237.             break;
  238.         case USER_RECYCLE_DIRECTORY:
  239.             UserRecycleBinDirectory();
  240.             break;
  241.         case USER_APPLICATION_DATA_DIRECTORY:
  242.             UserApplicationDataDirectory();
  243.             break;
  244.         case USER_TEMPLATES_DIRECTORY:
  245.             UserTemplatesDirectory();
  246.             break;
  247.         case USER_STARTMENU_DIRECTORY:
  248.             UserStartMenuDirectory();
  249.             break;
  250.         case USER_STARTMENU_STARTUP_DIRECTORY:
  251.             UserStartMenuStartupDirectory();
  252.             break;
  253.         case USER_STARTMENU_PROGRAMS_DIRECTORY:
  254.             UserStartMenuProgramsDirectory();
  255.             break;
  256.         // Directories common 2 all users
  257.         case COMMON_DESKTOP_DIRECTORY:
  258.             CommonDesktopDirectory();
  259.             break;
  260.         case COMMON_STARTMENU_DIRECTORY:
  261.             CommonStartMenuDirectory();
  262.             break;
  263.         case COMMON_STARTMENU_STARTUP_DIRECTORY:
  264.             CommonStartMenuStartupDirectory();
  265.             break;
  266.         case COMMON_STARTMENU_PROGRAMS_DIRECTORY:
  267.             CommonStartMenuProgramsDirectory();
  268.             break;
  269.         // Unknown special directory constant    
  270.         default:
  271.             // Accept only constants we know about
  272.             ASSERTX(FALSE);
  273.     }
  274. }
  275. //-------------------------------------------------------------
  276. // Pre     :
  277. // Post    : 
  278. // Globals :
  279. // I/O     :
  280. // Task    : Cleanup and destruct a path object
  281. //-------------------------------------------------------------
  282. CPath::~CPath()
  283. {
  284. Exit();
  285. }
  286. //-------------------------------------------------------------
  287. // Pre     :
  288. // Post    : Return TRUE if paths are equal
  289. // Globals :
  290. // I/O     :
  291. // Task    : Check if the two path are the same
  292. //-------------------------------------------------------------
  293. BOOL CPath::operator ==(const CPath& rPath) const
  294. {
  295.     // Get fully qualified versions of the paths
  296. string FullyQualified1;
  297.     string FullyQualified2;
  298. GetFullyQualified(FullyQualified1);
  299. rPath.GetFullyQualified(FullyQualified2);
  300.     // Compare them
  301. return STRICMP(FullyQualified1.c_str(),FullyQualified2.c_str()) == 0;
  302. }
  303. //-------------------------------------------------------------
  304. // Pre     :
  305. // Post    : Return TRUE if paths are different
  306. // Globals :
  307. // I/O     :
  308. // Task    : Check if the two path are different
  309. //-------------------------------------------------------------
  310. BOOL CPath::operator !=(const CPath& rPath) const
  311. {
  312.     return !(*this == rPath);
  313. }
  314. //-------------------------------------------------------------
  315. // Pre     :
  316. // Post    : 
  317. // Globals :
  318. // I/O     :
  319. // Task    : Assign a path 2 another
  320. //-------------------------------------------------------------
  321. CPath& CPath::operator =(const CPath& rPath)
  322. {                   
  323. if(this != &rPath)
  324. m_strPath =rPath.m_strPath;
  325.     
  326.     return *this;
  327. }
  328. //-------------------------------------------------------------
  329. // Pre     :
  330. // Post    : Return the path, so that assignements can be chained
  331. // Globals :
  332. // I/O     :
  333. // Task    : Assign a string 2 a path
  334. //-------------------------------------------------------------
  335. CPath& CPath::operator =(LPCTSTR lpszPath)
  336. {
  337.     m_strPath =lpszPath ? lpszPath : _T("");
  338.     return *this;
  339. }
  340. //-------------------------------------------------------------
  341. // Pre     :
  342. // Post    : Return the path, so that assignements can be chained
  343. // Globals :
  344. // I/O     :
  345. // Task    : Assign a string 2 a path
  346. //-------------------------------------------------------------
  347. CPath& CPath::operator =(const string& strPath)
  348. {
  349.     m_strPath =strPath;
  350.     return *this;
  351. }
  352. //-------------------------------------------------------------
  353. // Pre     :
  354. // Post    : Converts path 2 string
  355. // Globals :
  356. // I/O     :
  357. // Task    : Convert path 2 string
  358. //           Warning: because this pointer 2 string point in the data
  359. //           of this class, it is possible 2 cast the result of this 
  360. //           function in any non-constant pointer and alter the data.
  361. //           Very dangerous
  362. //-------------------------------------------------------------
  363. CPath::operator LPCTSTR() const
  364. {
  365.     return (LPCTSTR)m_strPath.c_str();
  366. }
  367. //-------------------------------------------------------------
  368. // Pre     :
  369. // Post    : Returns the drive component without a colon, e.g. "c"
  370. //           Returns the directory component with a leading backslash, 
  371. //              but no trailing backslash, e.g. "dirsubdir"
  372. //           Returns name compleletely without delimiters, e.g "letter"
  373. //           Returns extension completely without delimiters, e.g. "doc"
  374. // Globals :
  375. // I/O     :
  376. // Task    : Return the individual components of this path. 
  377. //           For any given argument, you can pass NULL if you are not 
  378. //           interested in that component.
  379. //           Do not rely on pNames being <= 8 characters, extensions 
  380. //           being <= 3 characters, or drives being 1 character
  381. //-------------------------------------------------------------
  382. void CPath::GetComponents(string* pDrive, 
  383.                           string* pDirectory, 
  384.                           string* pName, 
  385.                           string* pExtension) const
  386. {
  387.     TCHAR buff_drive[_MAX_DRIVE + 1];
  388.     TCHAR buff_dir  [_MAX_DIR   + 1];
  389.     TCHAR buff_name [_MAX_FNAME + 1];
  390.     TCHAR buff_ext  [_MAX_EXT   + 1];
  391.     ZeroMemory(buff_drive,sizeof(buff_drive));
  392.     ZeroMemory(buff_dir,  sizeof(buff_dir));
  393.     ZeroMemory(buff_name, sizeof(buff_name));
  394.     ZeroMemory(buff_ext,  sizeof(buff_ext));
  395. SPLITPATH(m_strPath.c_str(), 
  396.               pDrive     ? buff_drive : NULL,
  397.               pDirectory ? buff_dir   : NULL,
  398.               pName      ? buff_name  : NULL,
  399.               pExtension ? buff_ext   : NULL);
  400.                 
  401.     if(pDrive)
  402.         *pDrive =buff_drive;
  403.     if(pDirectory)
  404.         *pDirectory =buff_dir;
  405.     if(pName)
  406.         *pName =buff_name;
  407.     if(pExtension)
  408.         *pExtension =buff_ext;
  409. // DOS's _splitpath returns "d:", we return "d"
  410. if(pDrive)
  411. StripTrailingChar(*pDrive,DRIVE_DELIMITER);
  412. // DOS's _splitpath returns "dirsubdir", we return "dirsubdir"
  413. if(pDirectory)
  414. StripTrailingBackslash(*pDirectory);
  415. // DOS's _splitpath returns ".ext", we return "ext"
  416. if(pExtension)
  417. StripLeadingChar(*pExtension,EXTENSION_DELIMITER);
  418. }
  419. //-------------------------------------------------------------
  420. // Pre     :
  421. // Post    : 
  422. // Globals :
  423. // I/O     :
  424. // Task    : Get drive from path
  425. //-------------------------------------------------------------                       
  426. void CPath::GetDrive(string& rDrive) const
  427. {
  428. GetComponents(&rDrive);
  429. }
  430. //-------------------------------------------------------------
  431. // Pre     :
  432. // Post    : 
  433. // Globals :
  434. // I/O     :
  435. // Task    : Get drive and directory from path
  436. //-------------------------------------------------------------
  437. void CPath::GetDriveDirectory(string& rDriveDirectory) const
  438. {
  439.     string Drive;
  440.     string Directory;
  441. GetComponents(&Drive,&Directory);
  442. rDriveDirectory =Drive;
  443. if(!Drive.empty())
  444.     {
  445. rDriveDirectory += DRIVE_DELIMITER;
  446.         rDriveDirectory += Directory;
  447.     }
  448. }
  449. //-------------------------------------------------------------
  450. // Pre     :
  451. // Post    : 
  452. // Globals :
  453. // I/O     :
  454. // Task    : Get directory from path
  455. //-------------------------------------------------------------
  456. void CPath::GetDirectory(string& rDirectory) const
  457. {
  458.     GetComponents(NULL,&rDirectory);
  459. }    
  460. //-------------------------------------------------------------
  461. // Pre     :
  462. // Post    : 
  463. // Globals :
  464. // I/O     :
  465. // Task    : Get filename and extension from path
  466. //-------------------------------------------------------------
  467. void CPath::GetNameExtension(string& rNameExtension) const
  468. {
  469.     string Name;
  470.     string Extension;
  471. GetComponents(NULL,NULL,&Name,&Extension);
  472.     rNameExtension =Name;
  473.     if(!Extension.empty())
  474.     {
  475.      rNameExtension += EXTENSION_DELIMITER;
  476.         rNameExtension += Extension;
  477.     }
  478. }
  479. //-------------------------------------------------------------
  480. // Pre     :
  481. // Post    : 
  482. // Globals :
  483. // I/O     :
  484. // Task    : Get filename from path
  485. //-------------------------------------------------------------
  486. void CPath::GetName(string& rName) const
  487. {
  488.     GetComponents(NULL,NULL,&rName);
  489. }
  490. //-------------------------------------------------------------
  491. // Pre     :
  492. // Post    : 
  493. // Globals :
  494. // I/O     :
  495. // Task    : Get file extension from path
  496. //-------------------------------------------------------------
  497. void CPath::GetExtension(string& rExtension) const
  498. {
  499.     GetComponents(NULL,NULL,NULL,&rExtension);
  500. }   
  501. //-------------------------------------------------------------
  502. // Pre     :
  503. // Post    : 
  504. // Globals :
  505. // I/O     :
  506. // Task    : Get fully qualified path
  507. //-------------------------------------------------------------
  508. void CPath::GetFullyQualified(string& rFullyQualified) const
  509. {
  510.     TCHAR buff_fullname[MAX_PATH];
  511. FULLPATH(buff_fullname,m_strPath.c_str(),MAX_PATH-1);
  512.     rFullyQualified =buff_fullname;
  513. }
  514. //-------------------------------------------------------------
  515. // Pre     :
  516. // Post    : 
  517. // Globals :
  518. // I/O     :
  519. // Task    : Get fully qualified path in short (8.3 style) form
  520. //-------------------------------------------------------------
  521. void CPath::GetFullyQualifiedShort(string& rFullyQualifiedShort) const
  522. {
  523.     GetFullyQualified(rFullyQualifiedShort);
  524. #pragma message(Reminder(_T("Also implement a GetFullyQualifiedLong")))
  525.     TCHAR buff_fullname[MAX_PATH];
  526.     GetShortPathName(rFullyQualifiedShort.c_str(),buff_fullname,sizeof(buff_fullname)/sizeof(TCHAR));
  527.     rFullyQualifiedShort =buff_fullname;
  528. }
  529. //-------------------------------------------------------------
  530. // Pre     :
  531. // Post    : Return TRUE if path does not start from filesystem root
  532. // Globals :
  533. // I/O     :
  534. // Task    : Check if path is a relative one (e.g. doesn't start with C:...)
  535. //-------------------------------------------------------------    
  536. BOOL CPath::IsRelative() const
  537. {
  538.     return (m_strPath.find(DRIVE_DELIMITER) == string::npos);
  539. }
  540. //-------------------------------------------------------------
  541. // Pre     :
  542. // Post    : Return TRUE if there are wildcards in the path
  543. // Globals :
  544. // I/O     :
  545. // Task    : Check if path contains wildcards
  546. //-------------------------------------------------------------    
  547. BOOL CPath::IsWild() const
  548. {
  549.     return (m_strPath.find_first_of(WILD_SET) != string::npos);
  550. }
  551. //-------------------------------------------------------------
  552. // Pre     :
  553. // Post    : Return TRUE if path is lexically correct
  554. // Globals :
  555. // I/O     :
  556. // Task    : Determine whether lpszFileName is valid. A filename
  557. //           is valid if it contains only legal characters, doesn't
  558. //           have repeated contiguous subdirectory delimiters, has at 
  559. //           most one drive delimiter, and all components fit within 
  560. //           maximum sizes
  561. //           This routine does NOT determine if a file exists, or
  562. //           even if it could exist relative to the user's directory
  563. //           hierarchy. Its tests are for lexical correctness only
  564. //           See also: CPath::Exists
  565. //-------------------------------------------------------------
  566. BOOL CPath::IsValid () const
  567. {
  568.     // Check 4 illegal characters (no wildcards allowed)
  569.     // We accept either  or / as folder delimiter
  570.     if(IsWild() ||
  571.        (m_strPath.find_first_of(_T("|"<>")) != string::npos) || 
  572.        (m_strPath.find(_T("//")) != string::npos))
  573.         return FALSE;
  574.     int index =m_strPath.find(_T("\\"));
  575.     if((index != string::npos) && (index > 0))
  576.         return FALSE;
  577.     // Make sure : can appear only in the 2nd position as a drive delimiter
  578.     if(((index =m_strPath.find(':')) != string::npos) && (index != 1))
  579.         return FALSE;
  580.     // Make sure it fits in the maximum path size
  581.     if(m_strPath.length() > MAX_PATH)
  582.         return FALSE;
  583.     
  584.     // Path is valid
  585. return TRUE;
  586. }
  587. //-------------------------------------------------------------
  588. // Pre     :
  589. // Post    : 
  590. // Globals :
  591. // I/O     :
  592. // Task    : Set path components
  593. //-------------------------------------------------------------
  594. void CPath::SetComponents(LPCTSTR lpszDrive, 
  595.                           LPCTSTR lpszDirectory,
  596.   LPCTSTR lpszName, 
  597.                           LPCTSTR lpszExtension)
  598. {
  599.     TCHAR buff_fullname[MAX_PATH];
  600. MAKEPATH(buff_fullname,lpszDrive,lpszDirectory,lpszName,lpszExtension);
  601.     m_strPath.erase();
  602.     m_strPath =buff_fullname;
  603. }
  604. //-------------------------------------------------------------
  605. // Pre     :
  606. // Post    : 
  607. // Globals :
  608. // I/O     :
  609. // Task    : Set path's drive
  610. //-------------------------------------------------------------
  611. void CPath::SetDrive(TCHAR chDrive)
  612. {
  613. string Drive(1,chDrive);
  614. string Directory;
  615. string Name;
  616. string Extension;
  617. GetComponents(NULL,&Directory,&Name,&Extension);
  618. SetComponents(Drive.c_str(),Directory.c_str(),Name.c_str(),Extension.c_str());
  619. }
  620. //-------------------------------------------------------------
  621. // Pre     :
  622. // Post    : 
  623. // Globals :
  624. // I/O     :
  625. // Task    : Set path's directory
  626. //-------------------------------------------------------------
  627. void CPath::SetDirectory(LPCTSTR lpszDirectory, BOOL bEnsureAbsolute /*= FALSE*/)
  628. {
  629. string Drive;
  630. string Directory =lpszDirectory;
  631. string Name;
  632. string Extension;
  633. if(bEnsureAbsolute)
  634. EnsureLeadingBackslash(Directory);
  635. EnsureTrailingBackslash(Directory);
  636. GetComponents(&Drive,NULL,&Name,&Extension);
  637. SetComponents(Drive.c_str(),Directory.c_str(),Name.c_str(),Extension.c_str());
  638. }    
  639. //-------------------------------------------------------------
  640. // Pre     :
  641. // Post    : 
  642. // Globals :
  643. // I/O     :
  644. // Task    : Set path's drive and directory
  645. //-------------------------------------------------------------
  646. void CPath::SetDriveDirectory(LPCTSTR lpszDriveDirectory)
  647. {
  648. string DriveDirectory =lpszDriveDirectory;
  649. string Name;
  650. string Extension;
  651. EnsureTrailingBackslash(DriveDirectory);
  652. GetComponents(NULL,NULL,&Name,&Extension);
  653. SetComponents(NULL,DriveDirectory.c_str(),Name.c_str(),Extension.c_str());
  654. }    
  655. //-------------------------------------------------------------
  656. // Pre     :
  657. // Post    : 
  658. // Globals :
  659. // I/O     :
  660. // Task    : Set path's filename
  661. //-------------------------------------------------------------
  662. void CPath::SetName(LPCTSTR lpszName)
  663. {
  664. string Drive;
  665. string Directory;
  666. string Extension;
  667. GetComponents(&Drive,&Directory,NULL,&Extension);
  668. SetComponents(Drive.c_str(),Directory.c_str(),lpszName,Extension.c_str());
  669. }
  670. //-------------------------------------------------------------
  671. // Pre     :
  672. // Post    : 
  673. // Globals :
  674. // I/O     :
  675. // Task    : Set path's file extension
  676. //-------------------------------------------------------------
  677. void CPath::SetExtension(LPCTSTR lpszExtension)
  678. {
  679. string Drive;
  680. string Directory;
  681. string Name;
  682. GetComponents(&Drive,&Directory,&Name);
  683. SetComponents(Drive.c_str(),Directory.c_str(),Name.c_str(),lpszExtension);
  684. }
  685. //-------------------------------------------------------------
  686. // Pre     :
  687. // Post    : 
  688. // Globals :
  689. // I/O     :
  690. // Task    : Set path's filename and extension
  691. //-------------------------------------------------------------
  692. void CPath::SetNameExtension(LPCTSTR lpszNameExtension)
  693. {
  694. string Drive;
  695. string Directory;
  696. GetComponents(&Drive,&Directory);
  697. SetComponents(Drive.c_str(),Directory.c_str(),lpszNameExtension,NULL);
  698. }    
  699. //-------------------------------------------------------------
  700. // Pre     :
  701. // Post    : 
  702. // Globals :
  703. // I/O     :
  704. // Task    : Append a subdirectory 2 path's directory
  705. //-------------------------------------------------------------
  706. void CPath::AppendDirectory(LPCTSTR lpszSubDirectory)
  707. {                                               
  708. string Drive;
  709. string Directory;
  710. string SubDirectory =lpszSubDirectory;
  711. string Name;
  712. string Extension;
  713. if(SubDirectory.empty())
  714. return;
  715. // Strip out any preceeding backslash
  716. StripLeadingBackslash(SubDirectory);
  717. EnsureTrailingBackslash(SubDirectory);
  718. GetComponents(&Drive,&Directory,&Name,&Extension);
  719. EnsureTrailingBackslash(Directory);
  720.     Directory +=SubDirectory;
  721. SetComponents(Drive.c_str(),Directory.c_str(),Name.c_str(),Extension.c_str());
  722. }
  723. //-------------------------------------------------------------
  724. // Pre     : If pLastDirectory is given we will store the name of the
  725. //           deepest directory (the one we're just exiting) in it
  726. // Post    : 
  727. // Globals :
  728. // I/O     :
  729. // Task    : Remove deepest subdirectory from path
  730. //-------------------------------------------------------------
  731. void CPath::UpDirectory(string *pLastDirectory /*= NULL*/)
  732. {
  733. string Directory;
  734. GetDirectory(Directory);
  735. StripTrailingBackslash(Directory);
  736. if(Directory.empty())
  737. return;
  738.     string::size_type nDelimiter =Directory.rfind(DIRECTORY_DELIMITER);
  739. if(pLastDirectory != NULL)
  740. {
  741. *pLastDirectory =Directory.substr(nDelimiter);
  742. StripLeadingBackslash(*pLastDirectory);
  743. }
  744.     if(nDelimiter != string::npos)
  745. Directory =Directory.substr(0,nDelimiter);
  746. SetDirectory(Directory.c_str());
  747. }
  748. //-------------------------------------------------------------
  749. // Pre     :
  750. // Post    : 
  751. // Globals :
  752. // I/O     :
  753. // Task    : Set path 2 current directory
  754. //-------------------------------------------------------------
  755. void CPath::CurrentDirectory()
  756. {
  757. TCHAR buff_path[MAX_PATH];
  758.     GetCurrentDirectory(MAX_PATH,buff_path);
  759. Empty();
  760. SetDriveDirectory(buff_path);
  761. }
  762. //-------------------------------------------------------------
  763. // Pre     :
  764. // Post    : 
  765. // Globals :
  766. // I/O     :
  767. // Task    : Set path 2 Windows directory
  768. //-------------------------------------------------------------
  769. void CPath::WindowsDirectory()
  770. {
  771. TCHAR buff_path[MAX_PATH];
  772.     GetWindowsDirectory(buff_path,MAX_PATH);
  773.     
  774.     Empty();
  775.     SetDriveDirectory(buff_path);
  776. }
  777. //-------------------------------------------------------------
  778. // Pre     :
  779. // Post    : 
  780. // Globals :
  781. // I/O     :
  782. // Task    : Set path 2 Windows system directory
  783. //-------------------------------------------------------------
  784. void CPath::SystemDirectory()
  785. {
  786. TCHAR buff_path[MAX_PATH];
  787.     GetSystemDirectory(buff_path,MAX_PATH);
  788.     
  789.     Empty();
  790.     SetDriveDirectory(buff_path);
  791. }
  792. //-------------------------------------------------------------
  793. // Pre     :
  794. // Post    : 
  795. // Globals :
  796. // I/O     :
  797. // Task    : Set path 2 root of system drive (usually C:)
  798. //-------------------------------------------------------------
  799. void CPath::SystemDriveRootDirectory()
  800. {
  801.     SystemDirectory();
  802.     SetDirectory(_T(""));
  803. }
  804. //-------------------------------------------------------------
  805. // Pre     :
  806. // Post    : 
  807. // Globals :
  808. // I/O     :
  809. // Task    : Set path 2 the name of specified module
  810. //-------------------------------------------------------------
  811. void CPath::Module(HINSTANCE hInstance)
  812. {
  813.     TCHAR buff_path[MAX_PATH];
  814.     GetModuleFileName(hInstance,buff_path,MAX_PATH);
  815.     m_strPath =buff_path;
  816. }
  817. #ifdef __MFC__
  818. //-------------------------------------------------------------
  819. // Pre     :
  820. // Post    : 
  821. // Globals :
  822. // I/O     :
  823. // Task    : Set path 2 the name of current module
  824. //-------------------------------------------------------------
  825. void CPath::Module()
  826. {
  827.     Module(AfxGetInstanceHandle());
  828. }
  829. #endif
  830. //-------------------------------------------------------------
  831. // Pre     :
  832. // Post    : 
  833. // Globals :
  834. // I/O     :
  835. // Task    : Set path 2 the directory of current module
  836. //-------------------------------------------------------------
  837. void CPath::ModuleDirectory(HINSTANCE hInstance)
  838. {
  839. Module(hInstance);
  840. SetNameExtension(_T(""));
  841. }
  842. #ifdef __MFC__
  843. //-------------------------------------------------------------
  844. // Pre     :
  845. // Post    : 
  846. // Globals :
  847. // I/O     :
  848. // Task    : Set path 2 the directory of current module
  849. //-------------------------------------------------------------
  850. void CPath::ModuleDirectory()
  851. {
  852. Module();
  853. SetNameExtension(_T(""));
  854. }
  855. #endif
  856. //-------------------------------------------------------------
  857. // Pre     :
  858. // Post    : 
  859. // Globals :
  860. // I/O     :
  861. // Task    : Currently, if the current environment has an
  862. //           entry for the TEMP environment variable, the directory will
  863. //           be set to that. If not, the directory will be the Windows
  864. //           System directory. The caller of this method, however, should
  865. //           not rely on this convention
  866. //-------------------------------------------------------------
  867. void CPath::TempDirectory()
  868. {
  869.     TCHAR buff_path[MAX_PATH];
  870. GetTempPath(MAX_PATH,buff_path);
  871. m_strPath =buff_path;
  872. SetNameExtension(_T(""));
  873. }  
  874. //-------------------------------------------------------------
  875. // Pre     :
  876. // Post    : 
  877. // Globals :
  878. // I/O     :
  879. // Task    : Set path 2 program files folder
  880. //           Usually C:Program Files
  881. //-------------------------------------------------------------
  882. void CPath::ProgramFilesDirectory()
  883. {
  884.     string strPath;
  885.     if(GetRegistryPath(HKEY_LOCAL_MACHINE,_T("SOFTWARE\Microsoft\Windows\CurrentVersion"),_T("ProgramFilesDir"),strPath))
  886.     {
  887.         // Got a path, use it
  888.         Empty();
  889.         SetDriveDirectory(strPath.c_str());
  890.     }
  891.     else
  892.     {
  893.         // This is some old or unknown system
  894.         Empty();
  895.         SetDriveDirectory(_T("C:\Programs"));
  896.     }
  897. }
  898. //-------------------------------------------------------------
  899. // Pre     :
  900. // Post    : 
  901. // Globals :
  902. // I/O     :
  903. // Task    : Set path 2 common files folder
  904. //           Usually C:Program FilesCommon Files
  905. //-------------------------------------------------------------
  906. void CPath::CommonFilesDirectory()
  907. {
  908.     string strPath;
  909.     if(GetRegistryPath(HKEY_LOCAL_MACHINE,_T("SOFTWARE\Microsoft\Windows\CurrentVersion"),_T("CommonFilesDir"),strPath))
  910.     {
  911.         // Got a path, use it
  912.         Empty();
  913.         SetDriveDirectory(strPath.c_str());
  914.     }
  915.     else
  916.     {
  917.         // This is some old or unknown system
  918.         Empty();
  919.         SetDriveDirectory(_T("C:\Programs\Common"));
  920.     }
  921. }
  922. //-------------------------------------------------------------
  923. // Pre     :
  924. // Post    : 
  925. // Globals :
  926. // I/O     :
  927. // Task    : Set path 2 common files folder
  928. //           On Win95 is C:Program FilesAccessories
  929. //           On WinNT is C:Program FilesWindows NTAccessories
  930. //-------------------------------------------------------------
  931. void CPath::AccessoriesDirectory()
  932. {
  933.     // Accessories folder is in Program Files folder
  934.     ProgramFilesDirectory();
  935.     COSVersion osver;
  936.     WORD       ostype   =osver.GetOSType();
  937.     WORD       wintype  =osver.GetWindowsType();
  938.     BOOL       is_Win95 =(ostype==OS_WIN95) || (ostype==OS_WIN98);
  939.     BOOL       is_NT    =((ostype & OS_WINNT) != 0);
  940.     if((wintype != WIN_32S) && is_Win95)
  941.     {
  942.         // Windows 95
  943.         AppendDirectory(_T("Accessories"));
  944.         return;
  945.     }
  946.     if((wintype != WIN_32S) && is_NT && (((osver.GetMajorVersion()==3) && (osver.GetMinorVersion()>=51)) || (osver.GetMajorVersion()>3)))
  947.     {
  948.         // Windows NT with the new Chichago shell
  949.         AppendDirectory(_T("Windows NT\Accessories"));
  950.         return;
  951.     }
  952.     // This is some old or unknown system
  953.     AppendDirectory(_T("Accessry"));
  954. }
  955. //-------------------------------------------------------------
  956. // Pre     :
  957. // Post    : 
  958. // Globals :
  959. // I/O     :
  960. // Task    : Set path 2 media folder
  961. //           Usually C:WindowsMedia
  962. //-------------------------------------------------------------
  963. void CPath::MediaDirectory()
  964. {
  965.     string strPath;
  966.     if(GetRegistryPath(HKEY_LOCAL_MACHINE,_T("SOFTWARE\Microsoft\Windows\CurrentVersion"),_T("MediaPath"),strPath))
  967.     {
  968.         // Got a path, use it
  969.         Empty();
  970.         SetDriveDirectory(strPath.c_str());
  971.     }
  972.     else
  973.     {
  974.         // This is some old or unknown system
  975.         WindowsDirectory();
  976.         AppendDirectory(_T("Media"));
  977.     }
  978. }
  979. //-------------------------------------------------------------
  980. // Pre     :
  981. // Post    : 
  982. // Globals :
  983. // I/O     :
  984. // Task    : Set path 2 device definition folder
  985. //           Usually C:WindowsInf
  986. //-------------------------------------------------------------
  987. void CPath::DeviceDirectory()
  988. {
  989.     string strPath;
  990.     if(GetRegistryPath(HKEY_LOCAL_MACHINE,_T("SOFTWARE\Microsoft\Windows\CurrentVersion"),_T("DevicePath"),strPath))
  991.     {
  992.         // Got a path, use it
  993.         Empty();
  994.         SetDriveDirectory(strPath.c_str());
  995.     }
  996.     else
  997.     {
  998.         // This is some old or unknown system
  999.         WindowsDirectory();
  1000.         AppendDirectory(_T("Inf"));
  1001.     }
  1002. }
  1003. //-------------------------------------------------------------
  1004. // Pre     :
  1005. // Post    : If this function is called on a system which does not
  1006. //           support the new Chichago shell, it will return FALSE
  1007. // Globals :
  1008. // I/O     :
  1009. // Task    : Set path 2 one of the special folders in Chichago
  1010. //-------------------------------------------------------------
  1011. BOOL CPath::ShellDirectory(int nShellFolderID)
  1012. {
  1013.     COSVersion osver;
  1014.     WORD       ostype   =osver.GetOSType();
  1015.     WORD       wintype  =osver.GetWindowsType();
  1016.     BOOL       is_Win95 =(ostype==OS_WIN95) || (ostype==OS_WIN98);
  1017.     BOOL       is_NT    =((ostype & OS_WINNT) != 0);
  1018.     if((wintype != WIN_32S) && 
  1019.        (is_Win95 || (is_NT && (((osver.GetMajorVersion()==3) && (osver.GetMinorVersion()>=51)) || (osver.GetMajorVersion()>3)))))
  1020.     {
  1021.         // These systems support the new Chichago shell, get location from registry
  1022.         BOOL         result =FALSE;
  1023.         LPITEMIDLIST pidl   =NULL;
  1024.         TCHAR        special_path[MAX_PATH];
  1025.         // Get a PIDL 2 the special shell folder
  1026.         HRESULT hr =SHGetSpecialFolderLocation(NULL,nShellFolderID,&pidl);
  1027.         if(SUCCEEDED(hr))
  1028.         {
  1029.             // Convert the PIDL in2 a path
  1030.             result =SHGetPathFromIDList(pidl,special_path);
  1031.             // Free the PIDL
  1032.             // Get the address of our task allocator's IMalloc interface
  1033.             LPMALLOC pMalloc;
  1034.             hr =SHGetMalloc(&pMalloc);
  1035.             if(SUCCEEDED(hr))
  1036.             {
  1037.                 // Free the PIDL
  1038.                 pMalloc->Free(pidl);
  1039.             
  1040.                 // Free our task allocator
  1041.                 pMalloc->Release();
  1042.             }
  1043.         }
  1044.         if(result)
  1045.         {
  1046.             // We've got the special path, now set ourselves 2 point 2 this
  1047.             Empty();
  1048.             SetDriveDirectory(special_path);
  1049.         }
  1050.         return result;
  1051.     }
  1052.     // This is some old or unknown system, shell folders not supported
  1053.     return FALSE;
  1054. }
  1055. //---------------------------------------------------------------------------
  1056. // Pre     : 
  1057. // Post    : Return TRUE on success
  1058. // Globals : 
  1059. // I/O     : 
  1060. // Task    : Set path 2 one of the special folders in Chichago
  1061. //           This function manually digs in the registry instead of using
  1062. //           SHGetSpecialFolderLocation, since it seems that this does not work 4
  1063. //           special location constants beginning with 
  1064. //---------------------------------------------------------------------------
  1065. BOOL CPath::ShellDirectory2(int nShellFolderID)
  1066. {
  1067.     COSVersion osver;
  1068.     WORD       ostype   =osver.GetOSType();
  1069.     WORD       wintype  =osver.GetWindowsType();
  1070.     BOOL       is_Win95 =(ostype==OS_WIN95) || (ostype==OS_WIN98);
  1071.     BOOL       is_NT    =((ostype & OS_WINNT) != 0);
  1072.     if((wintype != WIN_32S) && 
  1073.        (is_Win95 || (is_NT && (((osver.GetMajorVersion()==3) && (osver.GetMinorVersion()>=51)) || (osver.GetMajorVersion()>3)))))
  1074.     {
  1075.         // These systems support the new Chichago shell, get location from registry
  1076.         HKEY      root;
  1077.         string   key;
  1078.         string   value;
  1079.         switch(nShellFolderID)
  1080.         {
  1081.             case CSIDL_DESKTOPDIRECTORY:
  1082.                 root  =HKEY_CURRENT_USER;
  1083.                 key   =_T("Software\Microsoft\Windows\CurrentVersion\Explorer\Shell Folders");
  1084.                 value =_T("Desktop");
  1085.                 break;
  1086.             case CSIDL_FAVORITES:
  1087.                 root  =HKEY_CURRENT_USER;
  1088.                 key   =_T("Software\Microsoft\Windows\CurrentVersion\Explorer\Shell Folders");
  1089.                 value =_T("Favorites");
  1090.                 break;
  1091.             case CSIDL_FONTS:
  1092.                 root  =HKEY_CURRENT_USER;
  1093.                 key   =_T("Software\Microsoft\Windows\CurrentVersion\Explorer\Shell Folders");
  1094.                 value =_T("Fonts");
  1095.                 break;
  1096.             case CSIDL_NETHOOD:
  1097.                 root  =HKEY_CURRENT_USER;
  1098.                 key   =_T("Software\Microsoft\Windows\CurrentVersion\Explorer\Shell Folders");
  1099.                 value =_T("NetHood");
  1100.                 break;
  1101.             case CSIDL_PERSONAL:
  1102.                 root  =HKEY_CURRENT_USER;
  1103.                 key   =_T("Software\Microsoft\Windows\CurrentVersion\Explorer\Shell Folders");
  1104.                 value =_T("Personal");
  1105.                 break;
  1106.             case CSIDL_RECENT:
  1107.                 root  =HKEY_CURRENT_USER;
  1108.                 key   =_T("Software\Microsoft\Windows\CurrentVersion\Explorer\Shell Folders");
  1109.                 value =_T("Recent");
  1110.                 break;
  1111.             case CSIDL_SENDTO:
  1112.                 root  =HKEY_CURRENT_USER;
  1113.                 key   =_T("Software\Microsoft\Windows\CurrentVersion\Explorer\Shell Folders");
  1114.                 value =_T("SendTo");
  1115.                 break;
  1116.             case CSIDL_TEMPLATES:
  1117.                 root  =HKEY_CURRENT_USER;
  1118.                 key   =_T("Software\Microsoft\Windows\CurrentVersion\Explorer\Shell Folders");
  1119.                 value =_T("Templates");
  1120.                 break;
  1121.             case CSIDL_APPDATA:
  1122.                 root  =HKEY_CURRENT_USER;
  1123.                 key   =_T("Software\Microsoft\Windows\CurrentVersion\Explorer\Shell Folders");
  1124.                 value =_T("AppData");
  1125.                 break;
  1126.             case CSIDL_STARTMENU:
  1127.                 root  =HKEY_CURRENT_USER;
  1128.                 key   =_T("Software\Microsoft\Windows\CurrentVersion\Explorer\Shell Folders");
  1129.                 value =_T("Start Menu");
  1130.                 break;
  1131.             case CSIDL_STARTUP:
  1132.                 root  =HKEY_CURRENT_USER;
  1133.                 key   =_T("Software\Microsoft\Windows\CurrentVersion\Explorer\Shell Folders");
  1134.                 value =_T("Startup");
  1135.                 break;
  1136.             case CSIDL_PROGRAMS:
  1137.                 root  =HKEY_CURRENT_USER;
  1138.                 key   =_T("Software\Microsoft\Windows\CurrentVersion\Explorer\Shell Folders");
  1139.                 value =_T("Programs");
  1140.                 break;
  1141.             case CSIDL_COMMON_DESKTOPDIRECTORY:
  1142.                 root  =HKEY_LOCAL_MACHINE;
  1143.                 key   =_T("SOFTWARE\Microsoft\Windows\CurrentVersion\Explorer\Shell Folders");
  1144.                 value =_T("Common Desktop");
  1145.                 break;
  1146.             case CSIDL_COMMON_STARTMENU:
  1147.                 root  =HKEY_LOCAL_MACHINE;
  1148.                 key   =_T("SOFTWARE\Microsoft\Windows\CurrentVersion\Explorer\Shell Folders");
  1149.                 value =_T("Common Start Menu");
  1150.                 break;
  1151.             case CSIDL_COMMON_STARTUP:
  1152.                 root  =HKEY_LOCAL_MACHINE;
  1153.                 key   =_T("SOFTWARE\Microsoft\Windows\CurrentVersion\Explorer\Shell Folders");
  1154.                 value =_T("Common Startup");
  1155.                 break;
  1156.             case CSIDL_COMMON_PROGRAMS:
  1157.                 root  =HKEY_LOCAL_MACHINE;
  1158.                 key   =_T("SOFTWARE\Microsoft\Windows\CurrentVersion\Explorer\Shell Folders");
  1159.                 value =_T("Common Programs");
  1160.                 break;
  1161.         }
  1162.         
  1163.         string strPath;
  1164.         if(GetRegistryPath(root,key.c_str(),value.c_str(),strPath))
  1165.         {
  1166.             // Got a path, use it
  1167.             Empty();
  1168.             SetDriveDirectory(strPath.c_str());
  1169.             return TRUE;
  1170.         }
  1171.     }
  1172.     // This is some old or unknown system
  1173.     return FALSE;
  1174. }
  1175. //---------------------------------------------------------------------------
  1176. // Pre     : 
  1177. // Post    : Return FALSE if specified value does not exist or some error
  1178. // Globals : 
  1179. // I/O     : 
  1180. // Task    : Dig in the registry 2 the specified location, and extract a path
  1181. //           Make sure the path is a valid 
  1182. //---------------------------------------------------------------------------
  1183. BOOL CPath::GetRegistryPath(HKEY hRootKey, LPCTSTR lpcszKeyName, LPCTSTR lpcszValueName, string &strPath)
  1184. {
  1185.     TCHAR     path_buffer    [MAX_PATH];
  1186.     TCHAR     expanded_buffer[MAX_PATH];
  1187.     DWORD     path_buffer_size =sizeof(path_buffer);
  1188.     CRegistry reg(hRootKey,lpcszKeyName,KEY_READ);
  1189.     
  1190.     if(reg.GetValue(lpcszValueName,(BYTE *)&path_buffer,path_buffer_size))
  1191.     {
  1192.         COSVersion osver;
  1193.         WORD       ostype =osver.GetOSType();
  1194.         BOOL       is_NT  =((ostype & OS_WINNT) != 0);
  1195.         if(is_NT)
  1196.         {
  1197.             // Running on NT and the ExpandEnvironmentStrings API requires
  1198.             // Unicode strings
  1199.             WCHAR path_buffer_unicode    [MAX_PATH];
  1200.             WCHAR expanded_buffer_unicode[MAX_PATH];
  1201.             MultiByteToWideChar(CP_ACP,0,path_buffer,-1,path_buffer_unicode,sizeof(path_buffer_unicode)/sizeof(WCHAR));
  1202.             ExpandEnvironmentStringsW(path_buffer_unicode,expanded_buffer_unicode,sizeof(expanded_buffer_unicode)/sizeof(WCHAR));
  1203.             WideCharToMultiByte(CP_ACP,0,expanded_buffer_unicode,-1,expanded_buffer,sizeof(path_buffer)/sizeof(TCHAR),NULL,NULL);
  1204.         }
  1205.         else
  1206.             ExpandEnvironmentStrings(path_buffer,expanded_buffer,path_buffer_size);
  1207.         strPath.erase();
  1208.         strPath =expanded_buffer;
  1209.         return TRUE;
  1210.     }
  1211.     // No such key and/or value
  1212.     return FALSE;
  1213. }
  1214. //-------------------------------------------------------------
  1215. // Pre     :
  1216. // Post    : If this function is called on a system which does not
  1217. //           support the new Chichago shell, it will clear the path
  1218. // Globals :
  1219. // I/O     :
  1220. // Task    : Set path 2 desktop folder of currently logged-in user
  1221. //-------------------------------------------------------------
  1222. void CPath::UserDesktopDirectory()
  1223. {
  1224.     if(!ShellDirectory(CSIDL_DESKTOPDIRECTORY))
  1225.         Empty();
  1226. }
  1227. //-------------------------------------------------------------
  1228. // Pre     :
  1229. // Post    : If this function is called on a system which does not
  1230. //           support the new Chichago shell, it will clear the path
  1231. // Globals :
  1232. // I/O     :
  1233. // Task    : Set path 2 favorites folder of currently logged-in user
  1234. //-------------------------------------------------------------
  1235. void CPath::UserFavoritesDirectory()
  1236. {
  1237.     if(!ShellDirectory(CSIDL_FAVORITES))
  1238.         Empty();
  1239. }
  1240. //-------------------------------------------------------------
  1241. // Pre     :
  1242. // Post    : If this function is called on a system which does not
  1243. //           support the new Chichago shell, it will clear the path
  1244. // Globals :
  1245. // I/O     :
  1246. // Task    : Set path 2 fonts folder of currently logged-in user
  1247. //-------------------------------------------------------------
  1248. void CPath::UserFontsDirectory()
  1249. {
  1250.     if(!ShellDirectory(CSIDL_FONTS))
  1251.         Empty();
  1252. }
  1253. //-------------------------------------------------------------
  1254. // Pre     :
  1255. // Post    : If this function is called on a system which does not
  1256. //           support the new Chichago shell, it will clear the path
  1257. // Globals :
  1258. // I/O     :
  1259. // Task    : Set path 2 network hood folder of currently logged-in user
  1260. //-------------------------------------------------------------
  1261. void CPath::UserNetworkNeighbourhoodDirectory()
  1262. {
  1263.     if(!ShellDirectory(CSIDL_NETHOOD))
  1264.         Empty();
  1265. }
  1266. //-------------------------------------------------------------
  1267. // Pre     :
  1268. // Post    : If this function is called on a system which does not
  1269. //           support the new Chichago shell, it will clear the path
  1270. // Globals :
  1271. // I/O     :
  1272. // Task    : Set path 2 personal folder of currently logged-in user
  1273. //           Usually C:My Documents
  1274. //-------------------------------------------------------------
  1275. void CPath::UserDocumentsDirectory()
  1276. {
  1277.     if(!ShellDirectory(CSIDL_PERSONAL))
  1278.         Empty();
  1279. }
  1280. //-------------------------------------------------------------
  1281. // Pre     :
  1282. // Post    : If this function is called on a system which does not
  1283. //           support the new Chichago shell, it will clear the path
  1284. // Globals :
  1285. // I/O     :
  1286. // Task    : Set path 2 recent folder of currently logged-in user
  1287. //-------------------------------------------------------------
  1288. void CPath::UserRecentDirectory()
  1289. {
  1290.     if(!ShellDirectory(CSIDL_RECENT))
  1291.         Empty();
  1292. }
  1293. //-------------------------------------------------------------
  1294. // Pre     :
  1295. // Post    : If this function is called on a system which does not
  1296. //           support the new Chichago shell, it will clear the path
  1297. // Globals :
  1298. // I/O     :
  1299. // Task    : Set path 2 SendTo folder of currently logged-in user
  1300. //-------------------------------------------------------------
  1301. void CPath::UserSendToDirectory()
  1302. {
  1303.     if(!ShellDirectory(CSIDL_SENDTO))
  1304.         Empty();
  1305. }
  1306. //-------------------------------------------------------------
  1307. // Pre     :
  1308. // Post    : If this function is called on a system which does not
  1309. //           support the new Chichago shell, it will clear the path
  1310. // Globals :
  1311. // I/O     :
  1312. // Task    : Set path 2 templates folder of currently logged-in user
  1313. //           Usually C:WindowsShellNew
  1314. //-------------------------------------------------------------
  1315. void CPath::UserTemplatesDirectory()
  1316. {
  1317.     if(!ShellDirectory(CSIDL_TEMPLATES))
  1318.         Empty();
  1319. }
  1320. //-------------------------------------------------------------
  1321. // Pre     :
  1322. // Post    : If this function is called on a system which does not
  1323. //           support the new Chichago shell, it will clear the path
  1324. // Globals :
  1325. // I/O     :
  1326. // Task    : Set path 2 the recycle bin directory
  1327. //           Usually C:Recycled
  1328. //-------------------------------------------------------------
  1329. void CPath::UserRecycleBinDirectory()
  1330. {
  1331.     if(!ShellDirectory(CSIDL_BITBUCKET))
  1332.         Empty();
  1333. }
  1334. //-------------------------------------------------------------
  1335. // Pre     :
  1336. // Post    : If this function is called on a system which does not
  1337. //           support the new Chichago shell, it will clear the path
  1338. // Globals :
  1339. // I/O     :
  1340. // Task    : Set path 2 the folder where application data is stored 
  1341. //           specific 2 currently logged-in user
  1342. //-------------------------------------------------------------
  1343. void CPath::UserApplicationDataDirectory()
  1344. {
  1345.     if(!ShellDirectory(CSIDL_APPDATA))
  1346.         Empty();
  1347. }
  1348. //-------------------------------------------------------------
  1349. // Pre     :
  1350. // Post    : If this function is called on a system which does not
  1351. //           support the new Chichago shell, it will clear the path
  1352. // Globals :
  1353. // I/O     :
  1354. // Task    : Set path 2 start menu folder of currently logged-in user
  1355. //-------------------------------------------------------------
  1356. void CPath::UserStartMenuDirectory()
  1357. {
  1358.     if(!ShellDirectory(CSIDL_STARTMENU))
  1359.         Empty();
  1360. }
  1361. //-------------------------------------------------------------
  1362. // Pre     :
  1363. // Post    : If this function is called on a system which does not
  1364. //           support the new Chichago shell, it will clear the path
  1365. // Globals :
  1366. // I/O     :
  1367. // Task    : Set path 2 startup folder of currently logged-in user
  1368. //-------------------------------------------------------------
  1369. void CPath::UserStartMenuStartupDirectory()
  1370. {
  1371.     if(!ShellDirectory(CSIDL_STARTUP))
  1372.         Empty();
  1373. }
  1374. //-------------------------------------------------------------
  1375. // Pre     :
  1376. // Post    : If this function is called on a system which does not
  1377. //           support the new Chichago shell, it will clear the path
  1378. // Globals :
  1379. // I/O     :
  1380. // Task    : Set path 2 programs menu folder of currently logged-in user
  1381. //-------------------------------------------------------------
  1382. void CPath::UserStartMenuProgramsDirectory()
  1383. {
  1384.     if(!ShellDirectory(CSIDL_PROGRAMS))
  1385.         Empty();
  1386. }
  1387. //-------------------------------------------------------------
  1388. // Pre     :
  1389. // Post    : If this function is called on a system which does not
  1390. //           support the new Chichago shell, it will clear the path
  1391. // Globals :
  1392. // I/O     :
  1393. // Task    : Set path 2 desktop folder common 2 all users
  1394. //-------------------------------------------------------------
  1395. void CPath::CommonDesktopDirectory()
  1396. {
  1397.     if(!ShellDirectory2(CSIDL_COMMON_DESKTOPDIRECTORY))
  1398.     {
  1399.         // Check if running on Windows 95, and workaround this if so
  1400.         COSVersion osver;
  1401.         WORD       ostype =osver.GetOSType();
  1402.         if((ostype == OS_WIN95) || (ostype == OS_WIN98))
  1403.         {
  1404.             // Manual workaround
  1405.             WindowsDirectory();
  1406.             AppendDirectory(_T("Desktop"));
  1407.         }
  1408.         else
  1409.             // Failure, clear path
  1410.             Empty();
  1411.     }
  1412. }
  1413. //-------------------------------------------------------------
  1414. // Pre     :
  1415. // Post    : If this function is called on a system which does not
  1416. //           support the new Chichago shell, it will clear the path
  1417. // Globals :
  1418. // I/O     :
  1419. // Task    : Set path 2 start menu folder common 2 all users
  1420. //-------------------------------------------------------------
  1421. void CPath::CommonStartMenuDirectory()
  1422. {
  1423.     if(!ShellDirectory2(CSIDL_COMMON_STARTMENU))
  1424.     {
  1425.         // Check if running on Windows 95, and workaround this if so
  1426.         COSVersion osver;
  1427.         WORD       ostype =osver.GetOSType();
  1428.         if((ostype == OS_WIN95) || (ostype == OS_WIN98))
  1429.         {
  1430.             // Manual workaround
  1431.             WindowsDirectory();
  1432.             AppendDirectory(_T("Start Menu"));
  1433.         }
  1434.         else
  1435.             // Failure, clear path
  1436.             Empty();
  1437.     }
  1438. }
  1439. //-------------------------------------------------------------
  1440. // Pre     :
  1441. // Post    : If this function is called on a system which does not
  1442. //           support the new Chichago shell, it will clear the path
  1443. // Globals :
  1444. // I/O     :
  1445. // Task    : Set path 2 startup folder common 2 all users
  1446. //-------------------------------------------------------------
  1447. void CPath::CommonStartMenuStartupDirectory()
  1448. {
  1449.     if(!ShellDirectory2(CSIDL_COMMON_STARTUP))
  1450.     {
  1451.         // Check if running on Windows 95, and workaround this if so
  1452.         COSVersion osver;
  1453.         WORD       ostype =osver.GetOSType();
  1454.         if((ostype == OS_WIN95) || (ostype == OS_WIN98))
  1455.         {
  1456.             // Manual workaround
  1457.             WindowsDirectory();
  1458.             AppendDirectory(_T("Start Menu\Programs\StartUp"));
  1459.         }
  1460.         else
  1461.             // Failure, clear path
  1462.             Empty();
  1463.     }
  1464. }
  1465. //-------------------------------------------------------------
  1466. // Pre     :
  1467. // Post    : If this function is called on a system which does not
  1468. //           support the new Chichago shell, it will clear the path
  1469. // Globals :
  1470. // I/O     :
  1471. // Task    : Set path 2 programs menu folder common 2 all users
  1472. //-------------------------------------------------------------
  1473. void CPath::CommonStartMenuProgramsDirectory()
  1474. {
  1475.     if(!ShellDirectory2(CSIDL_COMMON_PROGRAMS))
  1476.     {
  1477.         // Check if running on Windows 95, and workaround this if so
  1478.         COSVersion osver;
  1479.         WORD       ostype =osver.GetOSType();
  1480.         if((ostype == OS_WIN95) || (ostype == OS_WIN98))
  1481.         {
  1482.             // Manual workaround
  1483.             WindowsDirectory();
  1484.             AppendDirectory(_T("Start Menu\Programs"));
  1485.         }
  1486.         else
  1487.             // Failure, clear path
  1488.             Empty();
  1489.     }
  1490. }
  1491. #ifdef __MFC__
  1492. //-------------------------------------------------------------
  1493. // Pre     :
  1494. // Post    : 
  1495. // Globals :
  1496. // I/O     :
  1497. // Task    : Local profiles are private INI files but located in the same 
  1498. //           directory as the executable. These are used for less volatile
  1499. //           settings than those found in the applications main private INI
  1500. //           file, which would be in the Windows directory
  1501. //                
  1502. //           Sets the value of this path to <drive>:<directory><name>.ini
  1503. //           where name is from lpszName and drive and directory are from the
  1504. //           currently executing module's path.
  1505. //           See also: PrivateProfile, LocalProfile(UINT)
  1506. //-------------------------------------------------------------
  1507. void CPath::LocalProfile(LPCTSTR lpszName, LPCTSTR lpszExtension /*= NULL*/)
  1508. {
  1509. ModuleDirectory();
  1510.     
  1511.     if(lpszExtension == NULL)
  1512.         lpszExtension =INI_EXTENSION;
  1513. SetName(lpszName);
  1514. SetExtension(lpszExtension);
  1515. }
  1516. #endif
  1517. #ifdef __MFC__
  1518. //-------------------------------------------------------------
  1519. // Pre     :
  1520. // Post    : 
  1521. // Globals :
  1522. // I/O     :
  1523. // Task    : Like the above LocalProfile, but with the name supplied 
  1524. //           by a resource string identified by nResourceID
  1525. //           See also: LocalProfile(LPCTSTR)
  1526. //-------------------------------------------------------------
  1527. void CPath::LocalProfile(UINT nNameResourceID, UINT nExtensionResourceID /*= 0*/)
  1528. {
  1529.     CString Name;
  1530.     CString Extension;
  1531.     if(nExtensionResourceID)
  1532.         Extension.LoadString(nExtensionResourceID);
  1533.     else
  1534.         Extension =INI_EXTENSION;
  1535.                 
  1536.     if(Name.LoadString(nNameResourceID))
  1537.         LocalProfile(Name,Extension);
  1538. }
  1539. #endif
  1540. #ifdef __MFC__
  1541. //-------------------------------------------------------------
  1542. // Pre     :
  1543. // Post    : 
  1544. // Globals :
  1545. // I/O     :
  1546. // Task    : Set path 2 file with same name as the current module
  1547. //           and .INI extension in the Windows directory
  1548. //-------------------------------------------------------------
  1549. void CPath::PrivateProfile()
  1550. {
  1551.     CPath WindowsDirectory(WINDOWS_DIRECTORY);
  1552.     
  1553. Module();
  1554. SetDriveDirectory(WindowsDirectory);
  1555. SetExtension(INI_EXTENSION);
  1556. }
  1557. #endif
  1558. //-------------------------------------------------------------
  1559. // Pre     :
  1560. // Post    : 
  1561. // Globals :
  1562. // I/O     :
  1563. // Task    : Set path 2 file WIN.INI in the Windows directory
  1564. //-------------------------------------------------------------
  1565. void CPath::WindowsProfile()
  1566. {
  1567.     WindowsDirectory();
  1568. SetNameExtension(_T("Win.INI"));
  1569. }
  1570. //-------------------------------------------------------------
  1571. // Pre     :
  1572. // Post    : 
  1573. // Globals :
  1574. // I/O     :
  1575. // Task    : Set path 2 file WIN.INI in the Windows directory
  1576. //-------------------------------------------------------------
  1577. void CPath::SystemProfile()
  1578. {
  1579.     WindowsDirectory();
  1580. SetNameExtension(_T("System.INI"));
  1581. }
  1582. //-------------------------------------------------------------
  1583. // Pre     :
  1584. // Post    : 
  1585. // Globals :
  1586. // I/O     :
  1587. // Task    : Turn this path from "x:directorysubdirectoryname.ext"
  1588. //           to just "x:"
  1589. //-------------------------------------------------------------
  1590. void CPath::MakeRoot()
  1591. {   
  1592. SetDirectory(_T(""));
  1593. SetNameExtension(_T(""));
  1594. }
  1595. //-------------------------------------------------------------
  1596. // Pre     : Only the first 3 character from lpcszPrefix will be used
  1597. // Post    : Returns TRUE on success
  1598. // Globals :
  1599. // I/O     :
  1600. // Task    : Creates a temporary name
  1601. //-------------------------------------------------------------
  1602. BOOL CPath::CreateTempName(LPCTSTR lpcszPrefix)
  1603. {
  1604.     // Check that we've got a prefix
  1605.     if(!lpcszPrefix)
  1606.         return FALSE;
  1607. string Dir;
  1608.     TCHAR  temp_file[MAX_PATH];
  1609.     GetDriveDirectory(Dir);
  1610.     if(::GetTempFileName(Dir.c_str(),lpcszPrefix,0,temp_file) != 0)
  1611.     {
  1612.         // Got a temp file name
  1613.         *this =temp_file;
  1614.         SetExtension(_T("tmp"));
  1615.         // GetTempFileName actually created the file, remove it now,
  1616.         // we only needed a name
  1617.         Delete(TRUE);
  1618.         return TRUE;
  1619.     }
  1620. return FALSE;
  1621. }
  1622. //---------------------------------------------------------------------------
  1623. // Pre     : Only the first 3 character from lpcszPrefix will be used
  1624. // Post    : Returns TRUE on success
  1625. // Globals : 
  1626. // I/O     : 
  1627. // Task    : Creates a temporary folder name
  1628. //---------------------------------------------------------------------------
  1629. BOOL CPath::CreateTempDir(LPCTSTR lpcszPrefix, UINT nRetries)
  1630. {
  1631.     // Check that we've got a prefix
  1632.     if(!lpcszPrefix)
  1633.         return FALSE;
  1634.     UINT  retries =0;
  1635.     BOOL  bSuccess =FALSE;
  1636. TCHAR temp_prefix[ 5];
  1637.     TCHAR temp_name  [15];
  1638. ZeroMemory(temp_prefix, sizeof(temp_prefix));
  1639. STRNCPY(temp_prefix,lpcszPrefix,4);
  1640.     temp_prefix[3] ='';
  1641.     while(!bSuccess && (retries < nRetries))
  1642.     {
  1643.         STRCPY(temp_name, temp_prefix);
  1644.         string temp =RandomDigits(5);
  1645.         STRCAT(temp_name,temp.c_str());
  1646.         STRCAT(temp_name,_T(".tmp"));
  1647.         CPath test(*this);
  1648.         test.AppendDirectory(temp_name);
  1649.         if(!test.DirectoryExists() && test.CreateDirectory())
  1650.         {
  1651.             // CreateTempDir actually created the folder, remove it now,
  1652.             // we only needed a name
  1653.             test.RemoveDirectory();
  1654.             bSuccess =TRUE;
  1655.         }
  1656.         retries++;
  1657.     }
  1658.     if(bSuccess)
  1659.         AppendDirectory(temp_name);
  1660. return bSuccess;
  1661. }
  1662. //-------------------------------------------------------------
  1663. // Pre     :
  1664. // Post    : Returns TRUE on success
  1665. // Globals :
  1666. // I/O     :
  1667. // Task    : Sets path 2 a random name, and optionally ensures
  1668. //           uniqueness of that path
  1669. //-------------------------------------------------------------
  1670. BOOL CPath::CreateRandomName(BOOL bMustNotExist /*= TRUE*/, UINT nRetries /*= 1000*/)
  1671. {
  1672. string Name;
  1673. for(UINT nRetry=0; nRetry < nRetries; nRetry++)
  1674. {
  1675. Name =RandomDigits(8);
  1676. SetName(Name.c_str());
  1677.         if(!bMustNotExist)
  1678.             return TRUE;
  1679. if(!Exists())
  1680. return TRUE;
  1681. }
  1682. return FALSE;
  1683. }
  1684. //-------------------------------------------------------------
  1685. // Pre     :
  1686. // Post    : Returns TRUE on success
  1687. // Globals :
  1688. // I/O     :
  1689. // Task    : Create a new name, based on the existing name, for the same
  1690. //           drive and directory. If bMustNotExist, test the path up to 
  1691. //           nRetries till we get an unused path
  1692. //           See also: CreateRandomName
  1693. //-------------------------------------------------------------
  1694. BOOL CPath::CreateSimilarName(BOOL bMustNotExist /*= TRUE*/, UINT nRetries /*= 1000*/)
  1695. {
  1696. string NewName;
  1697.     string OriginalName;
  1698. GetName(OriginalName);
  1699. for(UINT nRetry=0; nRetry < nRetries; nRetry++)
  1700. {
  1701. NewName =OriginalName + RandomDigits(_MAX_FNAME - OriginalName.length());
  1702. SetName(NewName.c_str());
  1703. if(!Exists() || !bMustNotExist)
  1704. return TRUE;
  1705. }
  1706. return FALSE;
  1707. }
  1708. //-------------------------------------------------------------
  1709. // Pre     :
  1710. // Post    : Returns one of the EX_DRIVE_ constants
  1711. // Globals :
  1712. // I/O     :
  1713. // Task    : Return the type of the drive this path points to
  1714. //           See DrvType.H for more details
  1715. //-------------------------------------------------------------
  1716. UINT CPath::GetDriveType() const
  1717. {
  1718. CPath  RootPath = *this;
  1719.     string Root;
  1720. RootPath.MakeRoot();
  1721.     Root =(LPCTSTR)RootPath;
  1722. return GetDriveTypeEx(TOLOWER(Root[0]) - 'a');
  1723. }
  1724. //-------------------------------------------------------------
  1725. // Pre     :
  1726. // Post    : Return -1 on error
  1727. // Globals :
  1728. // I/O     :
  1729. // Task    : Find out the amount of free space on drive (in bytes)
  1730. //-------------------------------------------------------------
  1731. DWORD CPath::DriveFreeSpaceBytes() const
  1732. {
  1733.     CPath  RootPath = *this;
  1734.     string Root;
  1735. RootPath.MakeRoot();
  1736. DWORD nSectorsPerCluster;
  1737. DWORD nBytesPerSector;
  1738. DWORD nFreeClusters;
  1739. DWORD nClusters;
  1740. if(!GetDiskFreeSpace((LPCTSTR)RootPath,&nSectorsPerCluster,&nBytesPerSector,&nFreeClusters,&nClusters))
  1741. return 0;
  1742. else
  1743. return nFreeClusters * nSectorsPerCluster * nBytesPerSector;
  1744. }
  1745. //-------------------------------------------------------------
  1746. // Pre     :
  1747. // Post    : Return -1 on error
  1748. // Globals :
  1749. // I/O     :
  1750. // Task    : Find out the size of the drive (in bytes)
  1751. //-------------------------------------------------------------
  1752. DWORD CPath::DriveTotalSpaceBytes() const
  1753. {
  1754.     CPath  RootPath = *this;
  1755.     string Root;
  1756. RootPath.MakeRoot();
  1757. DWORD nSectorsPerCluster;
  1758. DWORD nBytesPerSector;
  1759. DWORD nFreeClusters;
  1760. DWORD nClusters;
  1761. if(!GetDiskFreeSpace((LPCTSTR)RootPath,&nSectorsPerCluster,&nBytesPerSector,&nFreeClusters,&nClusters))
  1762. return 0;
  1763. else
  1764. return nClusters * nSectorsPerCluster * nBytesPerSector;
  1765. }
  1766. //-------------------------------------------------------------
  1767. // Pre     :
  1768. // Post    : Return -1 on error
  1769. // Globals :
  1770. // I/O     :
  1771. // Task    : Find out the cluster size on this drive (in bytes)
  1772. //-------------------------------------------------------------
  1773. DWORD CPath::GetDriveClusterSize() const
  1774. {
  1775.     CPath  RootPath = *this;
  1776.     string Root;
  1777. RootPath.MakeRoot();
  1778. DWORD nSectorsPerCluster;
  1779. DWORD nBytesPerSector;
  1780. DWORD nFreeClusters;
  1781. DWORD nClusters;
  1782. if(!GetDiskFreeSpace((LPCTSTR)RootPath,&nSectorsPerCluster,&nBytesPerSector,&nFreeClusters,&nClusters))
  1783. return 0;
  1784. else
  1785. return nSectorsPerCluster * nBytesPerSector;
  1786. }
  1787. //-------------------------------------------------------------
  1788. // Pre     :
  1789. // Post    : Return TRUE on success
  1790. // Globals :
  1791. // I/O     :
  1792. // Task    : Find out info about drive
  1793. //-------------------------------------------------------------
  1794. BOOL CPath::GetDiskInfo(LPDWORD lpSectorsPerCluster,
  1795. LPDWORD lpBytesPerSector,
  1796. LPDWORD lpFreeClusters,
  1797. LPDWORD lpClusters) const
  1798. {
  1799.     // Create root path
  1800. CPath RootPath = *this;
  1801. RootPath.MakeRoot();
  1802. return GetDiskFreeSpace((LPCTSTR)RootPath,
  1803.                             lpSectorsPerCluster,
  1804.                             lpBytesPerSector,
  1805.                             lpFreeClusters,
  1806.                             lpClusters);
  1807. }
  1808. //---------------------------------------------------------------------------
  1809. // Pre     : 
  1810. // Post    : Return TRUE if a directory
  1811. // Globals : 
  1812. // I/O     : 
  1813. // Task    : Check if this path represents a directory
  1814. //---------------------------------------------------------------------------
  1815. BOOL CPath::IsDirectory() const
  1816. {
  1817.     // Check if this path has a filename
  1818.     string file_name;
  1819.     GetNameExtension(file_name);
  1820.     
  1821.     return file_name.empty();
  1822. }
  1823. //-------------------------------------------------------------
  1824. // Pre     :
  1825. // Post    : Return TRUE if directory exists
  1826. // Globals :
  1827. // I/O     :
  1828. // Task    : To determine if the directory exists, we need to
  1829. //           create a test path with a wildcard (*.*) extension
  1830. //           and see if FindFirstFile returns anything.  We don't
  1831. //           use CPath::FindFirst() because that routine parses out
  1832. //           '.' and '..', which fails for empty directories
  1833. //-------------------------------------------------------------
  1834. BOOL CPath::DirectoryExists() const
  1835. {
  1836.     // Create test path
  1837. CPath TestPath(m_strPath.c_str());
  1838. TestPath.SetNameExtension(WILD_NAME_EXTENSION);
  1839. WIN32_FIND_DATA FindData;
  1840. HANDLE          hFindFile =FindFirstFile((LPCTSTR)TestPath,&FindData); // Find anything
  1841. BOOL            bGotFile  =(hFindFile != INVALID_HANDLE_VALUE);
  1842. if(hFindFile != NULL) // Make sure we close the search
  1843.     FindClose(hFindFile);
  1844. return bGotFile;
  1845. }                                                     
  1846. //-------------------------------------------------------------
  1847. // Pre     :
  1848. // Post    : Return TRUE if there are no files(s)/folder(s) in
  1849. //           directory. All objects (with hidden, system, etc. attributes)
  1850. //           are looked up
  1851. // Globals :
  1852. // I/O     :
  1853. // Task    : Check if directory contains any file(s)
  1854. //-------------------------------------------------------------
  1855. BOOL CPath::IsDirectoryEmpty() const
  1856. {
  1857. CPath FileSpec = *this;
  1858. FileSpec.SetNameExtension(WILD_NAME_EXTENSION);
  1859. return !FileSpec.FindFirst(_A_NORMAL | _A_ARCH | _A_HIDDEN | _A_SYSTEM | _A_RDONLY) &&
  1860.            !FileSpec.FindFirst(_A_HIDDEN | _A_SUBDIR);
  1861. }
  1862. //-------------------------------------------------------------
  1863. // Pre     :
  1864. // Post    : Return TRUE if these is such a file
  1865. // Globals :
  1866. // I/O     :
  1867. // Task    : Check if file exists
  1868. //-------------------------------------------------------------
  1869. BOOL CPath::Exists() const
  1870. {
  1871. WIN32_FIND_DATA FindData;
  1872. HANDLE          hFindFile =FindFirstFile(m_strPath.c_str(),&FindData);
  1873. BOOL            bSuccess  =(hFindFile != INVALID_HANDLE_VALUE);
  1874. if(hFindFile != NULL) // Make sure we close the search
  1875.     FindClose(hFindFile);
  1876. return bSuccess;
  1877. }
  1878. //-------------------------------------------------------------
  1879. // Pre     :
  1880. // Post    : Return file size, -1 on error
  1881. // Globals :
  1882. // I/O     :
  1883. // Task    : Get file size (in bytes)
  1884. //-------------------------------------------------------------
  1885. DWORD CPath::GetSize() const
  1886. {
  1887.     WIN32_FIND_DATA FindData;
  1888. HANDLE          hFindFile =FindFirstFile(m_strPath.c_str(),&FindData);
  1889. BOOL            bSuccess  =(hFindFile != INVALID_HANDLE_VALUE);
  1890. if(hFindFile != NULL) // Make sure we close the search
  1891.     FindClose(hFindFile);
  1892.     return bSuccess ? FindData.nFileSizeLow : (DWORD)-1;
  1893. }
  1894. //-------------------------------------------------------------
  1895. // Pre     :
  1896. // Post    : Return file attributes
  1897. // Globals :
  1898. // I/O     :
  1899. // Task    : Get attributes of the file
  1900. //-------------------------------------------------------------
  1901. DWORD CPath::GetAttributes() const
  1902. {
  1903.     return GetFileAttributes(m_strPath.c_str());
  1904. }
  1905. //---------------------------------------------------------------------------
  1906. // Pre     : 
  1907. // Post    : Return TRUE on success
  1908. // Globals : 
  1909. // I/O     : 
  1910. // Task    : Set the attributes of the file
  1911. //---------------------------------------------------------------------------
  1912. BOOL CPath::SetAttributes(DWORD dwAttributes)
  1913. {
  1914.     return SetFileAttributes(m_strPath.c_str(),dwAttributes);
  1915. }
  1916. //-------------------------------------------------------------
  1917. // Pre     :
  1918. // Post    : Return TRUE on success
  1919. // Globals :
  1920. // I/O     :
  1921. // Task    : Get file creation, last acces and/or last modification 
  1922. //           time as local time
  1923. //-------------------------------------------------------------
  1924. BOOL CPath::GetTime(FILETIME *lpCreated, FILETIME *lpAccessed, FILETIME *lpModified) const
  1925. {
  1926.     WIN32_FIND_DATA findFileData;
  1927. HANDLE hFind =FindFirstFile(m_strPath.c_str(),&findFileData);
  1928. if(hFind == INVALID_HANDLE_VALUE)
  1929.         // Oops, no such file system object
  1930. return FALSE;
  1931.     FindClose(hFind);
  1932.     FILETIME ftLastWriteTimeLocal;
  1933.     FileTimeToLocalFileTime(&findFileData.ftLastWriteTime,&ftLastWriteTimeLocal);
  1934. if(lpCreated)
  1935.     {
  1936.         FILETIME ftCreationTimeLocal;
  1937.         FileTimeToLocalFileTime(&findFileData.ftCreationTime,&ftCreationTimeLocal);
  1938.         *lpCreated =ftCreationTimeLocal;
  1939.         if(!ftCreationTimeLocal.dwLowDateTime &&
  1940.            !ftCreationTimeLocal.dwHighDateTime)
  1941.            // Adjust time
  1942.            *lpCreated =ftLastWriteTimeLocal;
  1943.     }
  1944.     if(lpAccessed)
  1945.     {
  1946.         FILETIME ftLastAccessTimeLocal;
  1947.         FileTimeToLocalFileTime(&findFileData.ftLastAccessTime,&ftLastAccessTimeLocal);
  1948.         *lpAccessed =ftLastAccessTimeLocal;
  1949.         if(!ftLastAccessTimeLocal.dwLowDateTime &&
  1950.            !ftLastAccessTimeLocal.dwHighDateTime)
  1951.            // Adjust time
  1952.            *lpAccessed =ftLastWriteTimeLocal;
  1953.     }
  1954.     if(lpModified)
  1955.         *lpModified =ftLastWriteTimeLocal;
  1956.     return TRUE;
  1957. }
  1958. //---------------------------------------------------------------------------
  1959. // Pre     : 
  1960. // Post    : Return creation time
  1961. // Globals : 
  1962. // I/O     : 
  1963. // Task    : Get the time this file/folder was created
  1964. //---------------------------------------------------------------------------
  1965. FILETIME CPath::GetTimeCreated() const
  1966. {
  1967.     FILETIME file_time;
  1968.     ZeroMemory(&file_time,sizeof(file_time));
  1969.     GetTime(&file_time,NULL,NULL);
  1970.     return file_time;
  1971. }
  1972. //---------------------------------------------------------------------------
  1973. // Pre     : 
  1974. // Post    : Return last access time
  1975. // Globals : 
  1976. // I/O     : 
  1977. // Task    : Get the time this file/folder was last accessed
  1978. //---------------------------------------------------------------------------
  1979. FILETIME CPath::GetTimeLastAccessed() const
  1980. {
  1981.     FILETIME file_time;
  1982.     ZeroMemory(&file_time,sizeof(file_time));
  1983.     GetTime(NULL,&file_time,NULL);
  1984.     return file_time;
  1985. }
  1986. //---------------------------------------------------------------------------
  1987. // Pre     : 
  1988. // Post    : Return last modification time
  1989. // Globals : 
  1990. // I/O     : 
  1991. // Task    : Get the time this file/folder was last changed
  1992. //---------------------------------------------------------------------------
  1993. FILETIME CPath::GetTimeLastModified() const
  1994. {
  1995.     FILETIME file_time;
  1996.     ZeroMemory(&file_time,sizeof(file_time));
  1997.     GetTime(NULL,NULL,&file_time);
  1998.     return file_time;
  1999. }
  2000. //---------------------------------------------------------------------------
  2001. // Pre     : All time parameters are supposed 2 be local times
  2002. // Post    : Return TRUE on success
  2003. // Globals : 
  2004. // I/O     : 
  2005. // Task    : Set the creation, last acces and/or last modification time
  2006. //---------------------------------------------------------------------------
  2007. BOOL CPath::SetTime(const FILETIME *lpCreated, const FILETIME *lpAccessed, const FILETIME *lpModified)
  2008. {
  2009.     if(!lpCreated && !lpAccessed && !lpModified)
  2010.         // No time params specified
  2011.         return FALSE;
  2012.     WIN32_FIND_DATA findFileData;
  2013. HANDLE hFind =FindFirstFile(m_strPath.c_str(),&findFileData);
  2014. if(hFind == INVALID_HANDLE_VALUE)
  2015.         // Oops, no such file system object
  2016. return FALSE;
  2017.     FindClose(hFind);
  2018. if(lpCreated)
  2019.         LocalFileTimeToFileTime(lpCreated,&findFileData.ftCreationTime);
  2020.     if(lpAccessed)
  2021.         LocalFileTimeToFileTime(lpAccessed,&findFileData.ftLastAccessTime);
  2022.     if(lpModified)
  2023.         LocalFileTimeToFileTime(lpModified,&findFileData.ftLastWriteTime);
  2024.     HANDLE hFile =CreateFile(m_strPath.c_str(),GENERIC_WRITE,0,NULL,OPEN_EXISTING,FILE_ATTRIBUTE_NORMAL,NULL);
  2025.     if(hFile != INVALID_HANDLE_VALUE)
  2026.     {
  2027.         SetFileTime(hFile,lpCreated  ? &findFileData.ftCreationTime   : NULL,
  2028.                           lpAccessed ? &findFileData.ftLastAccessTime : NULL,
  2029.                           lpModified ? &findFileData.ftLastWriteTime  : NULL);
  2030.         CloseHandle(hFile);
  2031.         return TRUE;
  2032.     }
  2033.     return FALSE;
  2034. }
  2035. //---------------------------------------------------------------------------
  2036. // Pre     : lpCreated is supposed 2 be local time
  2037. // Post    : Return TRUE on success
  2038. // Globals : 
  2039. // I/O     : 
  2040. // Task    : Set the file's creation time
  2041. //---------------------------------------------------------------------------
  2042. BOOL CPath::SetTimeCreated(const FILETIME *lpCreated)
  2043. {
  2044.     return SetTime(lpCreated,NULL,NULL);
  2045. }
  2046. //---------------------------------------------------------------------------
  2047. // Pre     : lpModified is supposed 2 be local time
  2048. // Post    : Return TRUE on success
  2049. // Globals : 
  2050. // I/O     : 
  2051. // Task    : Set the file's creation time
  2052. //---------------------------------------------------------------------------
  2053. BOOL CPath::SetTimeLastModified(const FILETIME *lpModified)
  2054. {
  2055.     return SetTime(NULL,NULL,lpModified);
  2056. }
  2057. //---------------------------------------------------------------------------
  2058. // Pre     : lpAccessed is supposed 2 be local time
  2059. // Post    : Return TRUE on success
  2060. // Globals : 
  2061. // I/O     : 
  2062. // Task    : Set the file's creation time
  2063. //---------------------------------------------------------------------------
  2064. BOOL CPath::SetTimeLastAccessed(const FILETIME *lpAccessed)
  2065. {
  2066.     return SetTime(NULL,lpAccessed,NULL);
  2067. }
  2068. //-------------------------------------------------------------
  2069. // Pre     :
  2070. // Post    : Return TRUE on success
  2071. // Globals :
  2072. // I/O     :
  2073. // Task    : Delete file
  2074. //-------------------------------------------------------------
  2075. BOOL CPath::Delete(BOOL bEvenIfReadOnly)
  2076. {
  2077.     DWORD dwAttr =::GetFileAttributes(m_strPath.c_str());
  2078.     if(dwAttr == (DWORD)-1)
  2079.         // File does not exists
  2080.         return FALSE;
  2081.     if(((dwAttr & FILE_ATTRIBUTE_READONLY) == FILE_ATTRIBUTE_READONLY) && !bEvenIfReadOnly)
  2082.         // File is read-only, and we're not allowed 2 delete it
  2083.         return FALSE;
  2084.     SetFileAttributes(m_strPath.c_str(),FILE_ATTRIBUTE_NORMAL);
  2085.     return DeleteFile(m_strPath.c_str());
  2086. }
  2087. //-------------------------------------------------------------
  2088. // Pre     :
  2089. // Post    : Return TRUE on success
  2090. // Globals :
  2091. // I/O     :
  2092. // Task    : Rename file
  2093. //-------------------------------------------------------------
  2094. BOOL CPath::Rename(LPCTSTR lpszNewPath)
  2095. {
  2096.     return MoveTo(lpszNewPath,FALSE);
  2097. }
  2098. //-------------------------------------------------------------
  2099. // Pre     :
  2100. // Post    : Return TRUE on success, FALSE if there is such a target file
  2101. //           and we weren't granted permission 2 overwrite file or some error
  2102. // Globals :
  2103. // I/O     :
  2104. // Task    : Copy file
  2105. //           Since ::CopyFile will not overwrite read only files
  2106. //           we will make sure the target file is writable first
  2107. //-------------------------------------------------------------
  2108. BOOL CPath::CopyTo(LPCTSTR lpcszTargetFile, BOOL bOverwrite)
  2109. {
  2110.     // Check if the target file exists
  2111.     CPath TargetFile(lpcszTargetFile);
  2112.     if(TargetFile.Exists())
  2113.     {
  2114.         // Yeah there is already such a target file 
  2115.         // Decide if we should overwrite
  2116.         if(!bOverwrite)
  2117.             return FALSE;
  2118.         // Delete any previous target
  2119.         if(!TargetFile.Delete(TRUE))
  2120.             return FALSE;
  2121.     }
  2122.     // CopyFile will set the target's attributes 2 the same as 
  2123.     // the source after copying
  2124.     return CopyFile(m_strPath.c_str(),lpcszTargetFile,!bOverwrite);
  2125. }
  2126. //-------------------------------------------------------------
  2127. // Pre     :
  2128. // Post    : Return TRUE on success, FALSE if there is such a target file
  2129. //           and we weren't granted permission 2 overwrite file or some error
  2130. // Globals :
  2131. // I/O     :
  2132. // Task    : Move file
  2133. //-------------------------------------------------------------
  2134. BOOL CPath::MoveTo(LPCTSTR lpcszTargetFile, BOOL bOverwrite)
  2135. {
  2136.     // Check if the target file exists
  2137.     CPath TargetFile(lpcszTargetFile);
  2138.     if(TargetFile.Exists())
  2139.     {
  2140.         // Yeah there is already such a target file 
  2141.         // Decide if we should overwrite
  2142.         if(!bOverwrite)
  2143.             return FALSE;
  2144.         // Delete any previous target
  2145.         if(!TargetFile.Delete(TRUE))
  2146.             return FALSE;
  2147.     }
  2148.    return MoveFile(m_strPath.c_str(),lpcszTargetFile);
  2149. }
  2150. //-------------------------------------------------------------
  2151. // Pre     :
  2152. // Post    : Return TRUE if attributes do match
  2153. // Globals :
  2154. // I/O     :
  2155. // Task    : Compare finder attributes
  2156. //-------------------------------------------------------------
  2157. BOOL CPath::AttributesMatch(DWORD dwTargetAttributes, DWORD dwFileAttributes)
  2158. {
  2159. if(dwTargetAttributes == _A_NORMAL)
  2160. {
  2161. return ((_A_SUBDIR & dwFileAttributes) == 0);
  2162. }
  2163. else
  2164. {
  2165. return ( ((dwTargetAttributes & dwFileAttributes) != 0) &&
  2166.  ((_A_SUBDIR & dwTargetAttributes) == (_A_SUBDIR & dwFileAttributes)) );
  2167. }
  2168.     return FALSE;
  2169. }
  2170. //-------------------------------------------------------------
  2171. // Pre     :
  2172. // Post    : Return TRUE if any match found
  2173. // Globals :
  2174. // I/O     :
  2175. // Task    : Find the first file that meets this path and the specified attributes
  2176. //           You can specify the current attributes of the file or directory 
  2177. //           The attributes are represented by a combination (|) of the following 
  2178. //           constants:
  2179. //
  2180. //           _A_ARCH    Archive. Set whenever the file is 
  2181. //                      changed, and cleared by the BACKUP command
  2182. //           _A_HIDDEN  Hidden file. Not normally seen with 
  2183. //                      the DIR command, unless the /AH option 
  2184. //                      is used. Returns information about normal 
  2185. //                      files as well as files with this attribute
  2186. //           _A_NORMAL  Normal. File can be read or written to 
  2187. //                      without restriction
  2188. //           _A_RDONLY  Read-only. File cannot be opened for writing, 
  2189. //                      and a file with the same name cannot be created
  2190. //           _A_SUBDIR  Subdirectory
  2191. //           _A_SYSTEM  System file. Not normally seen with the DIR 
  2192. //                      command, unless the /AS option is used
  2193. //
  2194. //           These attributes do not follow a simple additive logic
  2195. //           Note that _A_NORMAL is 0x00, so it effectively cannot be
  2196. //           removed from the attribute set. You will therefore always
  2197. //           get normal files, and may also get Archive, Hidden, etc.
  2198. //           if you specify those attributes
  2199. //           See aso: FindFirstFile, FindNextFile
  2200. //-------------------------------------------------------------
  2201. BOOL CPath::FindFirst(DWORD dwAttributes /*= _A_NORMAL*/)
  2202. {
  2203. m_dwFindFileAttributes =dwAttributes;
  2204. BOOL bGotFile;
  2205. BOOL bWantSubdirectory =(BOOL)(_A_SUBDIR & dwAttributes);
  2206.     // Close handle to any previous enumeration
  2207.     Exit();
  2208. // i.) Finding first candidate file
  2209. WIN32_FIND_DATA FindData;
  2210. m_hFindFile =FindFirstFile(m_strPath.c_str(),&FindData);
  2211. bGotFile =(m_hFindFile != INVALID_HANDLE_VALUE);
  2212. while(bGotFile)
  2213. {
  2214. // ii.) Compare candidate to attributes, and filter out the "." and ".." folders
  2215. if(!AttributesMatch(m_dwFindFileAttributes,FindData.dwFileAttributes))
  2216. goto LABEL_GetAnother;
  2217. if(bWantSubdirectory && (FindData.cFileName[0] == '.'))
  2218. goto LABEL_GetAnother;
  2219. // iii.) Found match, prepare result
  2220.         if((_A_SUBDIR & m_dwFindFileAttributes) != 0)
  2221.             StripTrailingBackslash(m_strPath);
  2222. SetNameExtension(FindData.cFileName);
  2223.         if((_A_SUBDIR & dwAttributes) != 0)
  2224.             EnsureTrailingBackslash(m_strPath);
  2225. return TRUE;
  2226. // iv.) Not found match, get another
  2227.     LABEL_GetAnother:
  2228. bGotFile =FindNextFile(m_hFindFile,&FindData);
  2229. }
  2230. return FALSE;
  2231. }
  2232. //-------------------------------------------------------------
  2233. // Pre     :
  2234. // Post    : Return TRUE if a new match found
  2235. // Globals :
  2236. // I/O     :
  2237. // Task    : Find the next file that meets the conditions specified 
  2238. //           in the last FindFirst call
  2239. //-------------------------------------------------------------
  2240. BOOL CPath::FindNext()
  2241. {
  2242.     ASSERTX(m_hFindFile != NULL);
  2243. WIN32_FIND_DATA FindData;
  2244. while(FindNextFile(m_hFindFile,&FindData) != FALSE)
  2245.     { // while(FindNext(...))
  2246. if(AttributesMatch(m_dwFindFileAttributes,FindData.dwFileAttributes))
  2247. { // if(AttributesMatch(...)
  2248.         if((_A_SUBDIR & m_dwFindFileAttributes) == _A_SUBDIR)
  2249. {
  2250.                 // Found a directory
  2251. UpDirectory();
  2252. AppendDirectory(FindData.cFileName);
  2253. }
  2254. else
  2255.                 // Found a file
  2256. SetNameExtension(FindData.cFileName);
  2257.         if((_A_SUBDIR & m_dwFindFileAttributes) == _A_SUBDIR)
  2258.           EnsureTrailingBackslash(m_strPath);
  2259. return TRUE;
  2260. }
  2261. }
  2262. return FALSE;
  2263. }
  2264. //-------------------------------------------------------------
  2265. // Pre     :
  2266. // Post    : Return TRUE on success
  2267. // Globals :
  2268. // I/O     :
  2269. // Task    : Change current working directory of application 2 path
  2270. //-------------------------------------------------------------
  2271. BOOL CPath::ChangeDirectory()
  2272. {
  2273. string DriveDirectory;
  2274. GetDriveDirectory(DriveDirectory);
  2275.     return SetCurrentDirectory(DriveDirectory.c_str());
  2276. }
  2277. //-------------------------------------------------------------
  2278. // Pre     :
  2279. // Post    : Return TRUE if deleted OK
  2280. // Globals :
  2281. // I/O     :
  2282. // Task    : Delete everything in the directory
  2283. //-------------------------------------------------------------
  2284. BOOL CPath::RemoveDirectoryContent()
  2285. {
  2286.     // Deleting the directory's content
  2287.     // Iterate the content of the directory and delete it
  2288.     string filename;
  2289.     CPath  iterator(*this);
  2290.     BOOL   deleted_OK =TRUE;
  2291.     // Deleting all contained files
  2292.     iterator.SetNameExtension(WILD_NAME_EXTENSION);
  2293.     BOOL iterating =iterator.FindFirst(_A_NORMAL | _A_ARCH | _A_HIDDEN | _A_SYSTEM | _A_RDONLY);
  2294.     while(iterating)
  2295.     {
  2296.         // Found something
  2297.         deleted_OK =iterator.Delete(TRUE);
  2298.         if(!deleted_OK)
  2299.             break;
  2300.         iterator.SetNameExtension(WILD_NAME_EXTENSION);
  2301.         iterating =iterator.FindFirst(_A_NORMAL | _A_ARCH | _A_HIDDEN | _A_SYSTEM | _A_RDONLY);
  2302.     }
  2303.     if(!deleted_OK)
  2304.         return FALSE;
  2305.     // Deleting all contained directories
  2306.     iterator.SetNameExtension(WILD_NAME_EXTENSION);
  2307.     iterating =iterator.FindFirst(_A_HIDDEN | _A_SUBDIR);
  2308.     while(iterating)
  2309.     {
  2310.         // Found something
  2311.         deleted_OK =iterator.RemoveDirectory(TRUE);
  2312.         if(!deleted_OK)
  2313.             break;
  2314.         iterator.SetNameExtension(WILD_NAME_EXTENSION);
  2315.         iterator.UpDirectory();
  2316.         iterating =iterator.FindFirst(_A_HIDDEN | _A_SUBDIR);
  2317.     }
  2318.     return deleted_OK;
  2319. }
  2320. //-------------------------------------------------------------
  2321. // Pre     :
  2322. // Post    : Return TRUE if deleted OK
  2323. // Globals :
  2324. // I/O     :
  2325. // Task    : Remove the directory
  2326. //-------------------------------------------------------------
  2327. BOOL CPath::RemoveDirectory(BOOL bEvenIfNotEmpty)
  2328. {
  2329.     if(bEvenIfNotEmpty)
  2330.     {
  2331.         // Delete the directory's content
  2332.         if(!RemoveDirectoryContent())
  2333.             return FALSE;
  2334.     }
  2335.     // Make sure there is no enumeration in progress,
  2336.     // otherwise we we'll get an error (sharing violation) because
  2337.     // that search keeps an open handle for this directory
  2338.     Exit();
  2339.     
  2340.     // Deleting this directory (and only if it's empty)
  2341. string DriveDirectory;
  2342. GetDriveDirectory(DriveDirectory);
  2343.     return ::RemoveDirectory(DriveDirectory.c_str());
  2344. }
  2345. //-------------------------------------------------------------
  2346. // Pre     : If bCreateIntermediates is TRUE, create all eventually
  2347. //           missing parent directories too
  2348. // Post    : Return TRUE on success
  2349. // Globals :
  2350. // I/O     :
  2351. // Task    : Create new directory
  2352. //-------------------------------------------------------------
  2353. BOOL CPath::CreateDirectory(BOOL bCreateIntermediates /*= TRUE*/)
  2354. {
  2355. string PathText;
  2356. BOOL bSuccess;
  2357. GetDriveDirectory(PathText);
  2358.     StripTrailingBackslash(PathText);
  2359.     bSuccess =::CreateDirectory(PathText.c_str(),NULL);
  2360. if(!bSuccess)
  2361. bSuccess =ChangeDirectory();
  2362. if(!bSuccess && bCreateIntermediates)
  2363. {
  2364.         string::size_type nDelimiter =PathText.rfind(DIRECTORY_DELIMITER);
  2365.         if(nDelimiter == string::npos)
  2366. return FALSE;
  2367. PathText.resize(nDelimiter + 1);
  2368. CPath SubPath(PathText);
  2369. if(SubPath.CreateDirectory())
  2370. return CreateDirectory(FALSE);
  2371. else 
  2372. return FALSE;
  2373. }
  2374. return bSuccess;
  2375. }
  2376. //-------------------------------------------------------------
  2377. // Pre     : If bCreateIntermediates is TRUE, create all eventually
  2378. //           missing parent directories too
  2379. // Post    : 
  2380. // Globals :
  2381. // I/O     :
  2382. // Task    : Same as CreateDirectory, but throws an CPathException if
  2383. //           something goes wrong
  2384. //-------------------------------------------------------------
  2385. void CPath::CreateDirectoryEx(BOOL bCreateIntermediates /*= TRUE*/)
  2386. {                          
  2387. BOOL bSuccess =CreateDirectory(bCreateIntermediates);
  2388. if(!bSuccess)
  2389. throw new CPathException(GetLastError());
  2390. }