Click here to Skip to main content
12,292,585 members (67,003 online)
Click here to Skip to main content
Add your own
alternative version


75 bookmarked

CPath - juggling file names made easy

, 9 Sep 2005 CPOL
Rate this:
Please Sign up or sign in to vote.
A wrapper class for path strings based on (and improving) the Shell Lightweight utility API.

Recent Changes (August 2005)


CPath is a string class customized to handle path and file names on Windows.

Working with file names is often a pain:

  • Correct concatenation using &:file = path & subfolder & name; .
  • Modification: BuildRoot, AddExtension etc.
  • Splitting into components (path, file name, title, extension, parent folder, root, and individual elements).
  • Cleanup, like trimming, un- and requoting.
  • Read from / Write to Registry with one command.
  • Expanding / Collapsing Environment strings.
  • Detecting type of the path (IsRoot, IsURL, etc.) and a variety of root types (drive, long path, server, share, protocol, pseudo-protocol).
  • Basic file system operations: FileExists etc.
  • Frequent Helpers like GetModuleFileName.

The project includes a test application where you can play around, explore and test the functionality.

Sample screenshot

Design and Dependencies:

The main design goal was comfortable use. It is based on CString and uses the Shell Lightweight Path Helper API, so it is not suitable for portable applications.

Things you must know

Construction and Assignment (from any CString) will do some path cleanup. By default, this is: removing quotes, trimming spaces (inside and outside the spaces), collapsing self- and up-references (".." and "."), replacing UNC long path specification ("\\?\C:\") by the actual root, and expanding environment strings. See EPathCleanup for other options.

Extraction: CPath provides an operator LPCTSTR (similar to CString). CPath::GetStr() retrieves the path, and allows to apply "repacking" options. By default, paths exceeding MAX_PATH receive their UNC prefix. See EPathPacking for more options. Use CPath::GetStr(0) to retrieve the unmodified contained path as CString (avoids copy).

Error Handling: CPath functions usually fall back to a "sensible default handling". For methods accessing the file system, call GetLastError() to retrieve error information.

Things you might want to know

» Concatenate using '&': CPath path = CPath("C:\\temp") & "foo.txt";.

» Split the path into components:

String root      = path.GetRoot();
CPath   folder    = path.GetPath();
CString fileName  = path.GetName();
CString fileTitle = path.GetTitle();
CString ext       = path.GetExtension();

» Chain Commands: path.Trim().RemoveQuotes().

» Get Application Directory: nsPath::GetModuleFileName().GetPath().


Complete documentation (generated by Doxygen) is available in the download (HTML / HTMLHelp).

Do you want to create similar documentation for your code? My Doxygen article tells you how.

Implementation Notes:

I didn't use CPathT, because the class is intended for a VC6 project (which won't be ported to VC7 very soon), and CPathT contains the same misfeatures as the Shell helper functions.

I did use CString, because it's well available outside of MFC projects (using WTL, or the "extract CString implementation" macro for DevStudio, or a CString clone class). Further, the guaranteed reference counting implementation allows for a convenient API without too much performance impact.

Like CString, CPath acts as an LPCTSTR if passed as an "unknown" argument to a function with a variable argument list. Remember, however, that this is not portable to other compilers.

Change Log

Please Note: Breaking changes were introduced with the March 2005 update, when merging two slightly distinct branches. Unfortunately, I opted for keeping my code base intact, not thinking of the article published. (I hope you don't mind too much and you still like the update.) All changes will cause a compiler error.

  • June 20, 2004: Initial release.
  • June 22, 2004
    • fixed: nsPath::CPath::MakeSystemFolder implements unmake correctly.
    • added: nsPath::CPath::MakeSystemFolder and nsPath::CPath::SearchOnPath set the Windows error code to zero if the function succeeds (thanks Hans Dietrich).
    • fixed: nsPath::CPath compiles correctly with warning level -W4.
  • Mar 3, 2005
    • Doxygen class member documentation now uses groups for better orientation.
    • fixed: eppAutoQuote bug in GetStr (thanks Stlan).
    • Added:
      • FromRegistry, ToRegistry
      • GetRootType
      • GetRoot has a new implementation.
      • MakeAbsolute, MakeRelative, MakeFullPath
      • EnvUnexpandRoot, EnvUnexpandDefaultRoots.
    • Breaking changes (sorry)
      • GetRoot -> ShellGetRoot (to distinct from the new, extended GetRoot implementation).
      • GetFileName --> GetName (consistency).
      • GetFileTitle --> GetTitle (consistency).
      • Made the creation functions independent functions in the nsPath namespace (they are well tugged away in the namespace so conflicts are avoided anyway).
  • Mar 17, 2005
    • Fixed bug in GetFileName (now: GetName): if the path ends in a backslash, GetFileName did return the entire path instead of an empty string (thanks woodland).
  • Aug 25, 2005
    • Fix: GetStr() did not Quote the string if it contains spaces (even if eppAutoQuote was given, which is the default).

      Note: this fix changes default behavior, and might break existing code in some circumstances (such as passing the path.GetStr() to a function that does not like quotes).

    • Added SplitRoot (separate first element from rest).
    • Added IsDot, IsDotDot (to check for ".", ".." path), and IsDotty (true if "." or ".."). The names are silly - suggestions?
    • Added IsValid, checking for Windows naming conventions.
    • fixed incompatibility with CStdString (causing an access violation when assigning an empty path).


This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


About the Author

Germany Germany
Peter is tired of being called "Mr. Chen", even so certain individuals insist on it. No, he's not chinese.

Peter has seen lots of boxes you youngsters wouldn't even accept as calculators. He is proud of having visited the insides of a 16 Bit Machine.

In his spare time he ponders new ways of turning groceries into biohazards, or tries to coax South American officials to add some stamps to his passport.

Beyond these trivialities Peter works for Klippel[^], a small german company that wants to make mankind happier by selling them novel loudspeaker measurement equipment.

Where are you from?[^]

Please, if you are using one of my articles for anything, just leave me a comment. Seeing that this stuff is actually useful to someone is what keeps me posting and updating them.
Should you happen to not like it, tell me, too

You may also be interested in...

Comments and Discussions

QuestionOut of memory Pin
swuk6-Oct-11 8:34
memberswuk6-Oct-11 8:34 
QuestionAny updates? Pin
roel_30-Jul-08 10:45
memberroel_30-Jul-08 10:45 
AnswerRe: Any updates? Pin
roel_31-Jul-08 4:09
memberroel_31-Jul-08 4:09 
GeneralRe: Any updates? Pin
peterchen13-Apr-09 14:29
memberpeterchen13-Apr-09 14:29 
GeneralRe: Any updates? Pin
Michael Stammberger9-May-09 2:10
memberMichael Stammberger9-May-09 2:10 
GeneralRe: Any updates? Pin
peterchen6-Jul-09 0:10
memberpeterchen6-Jul-09 0:10 
GeneralUnicode, sample project & ExpandEnvironmentStrings [modified] Pin
David McMinn26-Nov-07 5:10
memberDavid McMinn26-Nov-07 5:10 
I tried to recompile the demo application today and kept getting exceptions thrown during the ExpandEnvironmentStrings() call in CPath::ExpandEnvStrings().

It appears the reason is that ExpandEnvironmentStrings() will fill in the buffer up to the length specified and then fail because there is not enough space, but it does not always write the terminating null. So when the temporary CStringLock() is destructed, calling Release() the CString tries to do a strlen and gets the wrong length, causing the exception.

I fixed it by changing the the second CStringLock constructor to set the last character to a null:

CStringLock(CString & s, int minChars) : m_string(&s)
    m_buffer = m_string->GetBuffer(minChars);
    // fixes an incompatibility with CStdString, see "NullBuffer" in .cpp
    if (!s.GetLength() && !minChars)
        m_buffer = NullBuffer;
    m_buffer[minChars-1] = TEXT('\0');

I also had to change the definition of CPath::ExpandEnvStrings() so that the ExpandEnvironmentStrings() call used a length of "len+1" or "required+1" and the CStringLock() construction used "len+2" or "required+2" respectively.

Edit 2: Fix didn't fix it originally, nor the second time.

-- modified at 11:49 Monday 26th November, 2007
GeneralRe: Unicode, sample project & ExpandEnvironmentStrings Pin
peterchen26-Nov-07 7:56
memberpeterchen26-Nov-07 7:56 
GeneralRe: Unicode, sample project & ExpandEnvironmentStrings Pin
David McMinn26-Nov-07 23:06
memberDavid McMinn26-Nov-07 23:06 
QuestionStatic Function? Pin
Joel Matthias14-Sep-06 8:47
memberJoel Matthias14-Sep-06 8:47 
AnswerRe: Static Function? Pin
peterchen15-Sep-06 9:18
memberpeterchen15-Sep-06 9:18 
GeneralProblems with UNICODE. Pin
William GS20-Jul-06 14:12
memberWilliam GS20-Jul-06 14:12 
GeneralRe: Problems with UNICODE. Pin
peterchen15-Sep-06 9:20
memberpeterchen15-Sep-06 9:20 
GeneralA time saver! Pin
Jörgen Sigvardsson12-Jan-06 3:05
memberJörgen Sigvardsson12-Jan-06 3:05 
GeneralRe: A time saver! Pin
peterchen12-Jan-06 23:37
memberpeterchen12-Jan-06 23:37 
Generalcompare path.GetPath() == _T("") always false Pin
Michael Stammberger28-Nov-05 1:35
memberMichael Stammberger28-Nov-05 1:35 
GeneralRe: compare path.GetPath() == _T("") always false Pin
peterchen28-Nov-05 4:50
memberpeterchen28-Nov-05 4:50 
GeneralSilly Names... Nah! Pin
Johann Gerell12-Sep-05 13:51
memberJohann Gerell12-Sep-05 13:51 
Generalseems it doesn't support validation check Pin
HeartFriend18-Aug-05 1:07
memberHeartFriend18-Aug-05 1:07 
GeneralValidity Check - suggestions Pin
peterchen18-Aug-05 7:44
memberpeterchen18-Aug-05 7:44 
GeneralProblem converting demo app to console output Pin
defenestration4-Aug-05 2:05
memberdefenestration4-Aug-05 2:05 
GeneralCPath path(""); causes exception Pin
defenestration4-Aug-05 1:32
memberdefenestration4-Aug-05 1:32 
GeneralRe: CPath path(""); causes exception Pin
peterchen4-Aug-05 2:21
memberpeterchen4-Aug-05 2:21 
GeneralRe: CPath path(""); causes exception Pin
defenestration4-Aug-05 9:26
memberdefenestration4-Aug-05 9:26 
GeneralRe: CPath path(""); causes exception Pin
peterchen4-Aug-05 11:03
memberpeterchen4-Aug-05 11:03 
QuestionA bug? Pin
woodland16-Mar-05 15:39
memberwoodland16-Mar-05 15:39 
AnswerRe: A bug? Pin
peterchen16-Mar-05 19:43
memberpeterchen16-Mar-05 19:43 
AnswerArticle updated Pin
peterchen19-Mar-05 4:02
memberpeterchen19-Mar-05 4:02 
GeneralGreat Pin
Lado10-Mar-05 3:17
memberLado10-Mar-05 3:17 
GeneralRe: Great Pin
peterchen10-Mar-05 8:03
memberpeterchen10-Mar-05 8:03 
GeneralNeed help! Pin
rlaley27-Oct-04 2:37
memberrlaley27-Oct-04 2:37 
GeneralRe: Need help! Pin
peterchen27-Oct-04 10:05
memberpeterchen27-Oct-04 10:05 
GeneralRe: Need help! Pin
rlaley27-Oct-04 16:01
memberrlaley27-Oct-04 16:01 
GeneralRe: Need help! Pin
peterchen27-Oct-04 20:24
memberpeterchen27-Oct-04 20:24 
GeneralRe: Need help! Pin
rlaley27-Oct-04 22:17
memberrlaley27-Oct-04 22:17 
GeneralLooks Cool Pin
Vasudevan Deepak Kumar10-Oct-04 19:04
memberVasudevan Deepak Kumar10-Oct-04 19:04 
GeneralToo many ampersands Pin
Stlan6-Sep-04 21:26
memberStlan6-Sep-04 21:26 
GeneralRe: Too many ampersands Pin
peterchen6-Sep-04 23:16
memberpeterchen6-Sep-04 23:16 
GeneralRe: Too many ampersands Pin
Ralph Wetzel30-Jan-05 11:45
memberRalph Wetzel30-Jan-05 11:45 
GeneralRe: Too many ampersands Pin
peterchen30-Jan-05 12:30
memberpeterchen30-Jan-05 12:30 
GeneralVery nice! Pin
Hans Dietrich21-Jun-04 20:12
memberHans Dietrich21-Jun-04 20:12 
GeneralRe: Very nice! Pin
peterchen21-Jun-04 22:05
memberpeterchen21-Jun-04 22:05 
GeneralArticle updated Pin
peterchen22-Jun-04 10:11
memberpeterchen22-Jun-04 10:11 
GeneralCool, but why did you.... Pin
Peter Mares20-Jun-04 20:31
memberPeter Mares20-Jun-04 20:31 
GeneralRe: Cool, but why did you.... Pin
peterchen20-Jun-04 20:43
memberpeterchen20-Jun-04 20:43 
GeneralRe: Cool, but why did you.... Pin
KaЯl21-Jun-04 23:55
memberKaЯl21-Jun-04 23:55 
GeneralBad links to files Pin
Darren Schroeder20-Jun-04 2:34
memberDarren Schroeder20-Jun-04 2:34 
Generalfixed Pin
peterchen20-Jun-04 2:50
memberpeterchen20-Jun-04 2:50 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.

| Advertise | Privacy | Terms of Use | Mobile
Web02 | 2.8.160518.1 | Last Updated 9 Sep 2005
Article Copyright 2004 by peterchen
Everything else Copyright © CodeProject, 1999-2016
Layout: fixed | fluid