 |
|
 |
I wanted to see how it deals with XXL paths, so I thought the easiest way to do it would be to simply paste a quite long (longer than 255 characters) line of text into the editbox in your example program. The list box was gray for some time, and then I got the message box: "Out of memory." It can also happen with paths shorter than 255 characters. Try this: I\wanted\to\see\how\it\deals\with\XXL\paths,\so\I\thought\the\easiest\way\to\do\it\would\be\to\simply\paste\a\quite\long\(about\400\characters)\line\of\text\into\the\editbox\in\your\example\program or this: I wanted to see how it deals with XXL paths, so I thought the easiest way to do it would be to simply paste a quite long (about 400 characters) line of text into the editbox in your example programI wanted to see how but if you prepend c:\ then it's OK. This (longer than 255) is not OK: c:\I wanted to see how it deals with XXL paths, so I thought the easiest way to do it would be to simply paste a quite long (about 400 characters) line of text into the editbox in your example programI wanted to see how it deals with XXL paths, so I thought the easiest way\I wanted to see how it deals with XXL paths, so I thought the easiest way to do
|
|
|
|
 |
|
 |
Thanks Peter for this useful class. Will you have time to upload your unicode-aware version? I've hacked my own now but it would be nice to use a tested version. Also I have a feature request: an 'EnsureDirectoryExists' function that will check if a directory exists and create it if necessary - recursively if need be (I mean, also create parent directories that may not exist).
cheers,
roel
|
|
|
|
 |
|
 |
Here's a suggestion for how this function could be implemented:
BOOL CPath::EnsureDirectoryExists()
{
if (ExistLocation()) {
return true;
}
CArray<cstring> directories;
CString location = GetDir();
int curPos = 0;
directories.Add(location.Tokenize(_T("\\"), curPos));
while (curPos != -1) {
CString dir = location.Tokenize(_T("\\"), curPos);
directories.Add(dir);
}
CString tmppath = GetDrive();
tmppath += "\\";
for (INT_PTR i = 0 ; i < directories.GetCount() ; i++) {
CString directory = directories[i];
CPath path(tmppath + directory + "\\");
if (!path.ExistLocation()) {
path.CreateDirectory();
}
tmppath = path.GetLocation();
}
return ExistLocation();
}
BOOL CPath::CreateDirectory()
{
CString location = GetLocation();
return ::_tmkdir(location) != -1;
}
</cstring>
|
|
|
|
 |
|
 |
Hi roel,
sorry for the late feedback.
I've just spent some late hours merging the changes between a private branch and this one. I hope I can update this article next weekend (no promise, though... The merge isn't complete, and I also have a list of roughly a dozen points that should be fixed, too.)
The private branch contains a global function to the same effect, with CPath having some new utility functions - like GetParent - that make that easier to implement.
|
|
|
|
 |
|
 |
How about SHCreateDirectoryEx() or MakeSureDirectoryPathExists()?
Both will create not existing folders...
Best regards
Michael
|
|
|
|
 |
|
 |
update is still pending
I'll get ot it in the near future, fingers crossed...
|
|
|
|
 |
|
 |
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);
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
|
|
|
|
 |
|
 |
Unfortunately, I'm currently travelling (again), I hope I get to it when I'm back.
I have two branches of the CPath code, which I long planned to merge, updating this articl is probably due. At least one of the branches works well with Unicode, and there was a fi to ExpandEnvironmentString (though I don't remember what it was).
I hope you can work around the issue in the meantime. I'll be back on Dec 6th, and have a few days off before I'm back in the office.
Thanks for the feedback, and it's always good to know someone's using that stuff! I'll send you a messag when the article is updated.
|
|
|
|
 |
|
 |
Yes, I can work around the problems for now. I look forward to an updated article. Your CPath class has been a fantastic time saver for me, thanks for producing it.
|
|
|
|
 |
|
 |
This class would be perfect (almost) if it had static versions of many of the functions, so that just getting the file extension of a file, for example, would not require creation of a CPath object.
|
|
|
|
 |
|
 |
In this case I typically use
s = ...
CString ext = CPath(s).GetExtension();
which is only one letter over CPath::GetExtension(s)
I considered static/global functions, but decided against because:
- I wanted to support member call chaining (e.g. CPath(s).GetPath().RemoveBackslash())
- I wanted to avoid offering two versions of each function (one by member, one global/static)
Further, due to how CString works, if s in above example is already a CString, it is copied only by reference when the CPath is created, so there's no extra performance hit for the extra class.
OTOH i you give me good reasons for a dual API (beyond "it's more featury" ), I can add it - I'd clean up the nsPath namespace, and put everything there. It's just a lot of ugly manual call forwarding.
We are a big screwed up dysfunctional psychotic happy family - some more screwed up, others more happy, but everybody's psychotic joint venture definition of CP
Linkify! || Fold With Us! || sighist
|
|
|
|
 |
|
 |
Hi Peter. Thanks for this great class.
I am using it in a UNICODE compliant project and I have problems:
1)
const LPCTSTR InvalidChars_Windows =
_T( "\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0A\x0B\x0C\x0D\x0E\x0F"
"\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1A\x1B\x1C\x1D\x1E\x1F"
"\\/:*?\"<>|");
Error:
Path.cpp(1901) : error C2308: concatenating mismatched wide strings
2) CString GetEnvVar(LPCTSTR envVar)
There is a char: "", it must be: _T("")
William GS
|
|
|
|
 |
|
 |
I'm not sure if I missed your post (sorry if so), or already replied to it. I'm currently on the road (back in October), and will look into it when I'm back.
We are a big screwed up dysfunctional psychotic happy family - some more screwed up, others more happy, but everybody's psychotic joint venture definition of CP
Linkify! || Fold With Us! || sighist
|
|
|
|
 |
|
|
 |
|
 |
Es war mir ein vergnügen
We say "get a life" to each other, disappointed or jokingly. What we forget, though, is that this is possibly the most destructive advice you can give to a geek.
boost your code || Fold With Us! || sighist
|
|
|
|
 |
|
 |
Hi!
I'm not sure, if this behaviour is a bug, but it's a bad trap in any case:
A comparison of the result of GetPath() with an empty string gives always false!
if (path.GetPath() == _T(""))
assert (false);
Only if I type cast it to CString, the result is correct:
if ((CString)path.GetPath() == _T(""))
assert (false);
Maybe there is a possibility to fix this in CPath!?
Anyway, a great and helpful class! Thanks peterchen for that!
Michael
|
|
|
|
 |
|
 |
ouch!
I guess this is a problem with the CPath extractors (returning an LPCTSTR).
I'm hesitant to change them, so either GetPath() should return a CString instead of a CPath, or I have to add comparison operators (which I wanted to avoid, but better than tripping over this way...)
We say "get a life" to each other, disappointed or jokingly. What we forget, though, is that this is possibly the most destructive advice you can give to a geek.
boost your code || Fold With Us! || sighist
|
|
|
|
 |
|
 |
peterchen: Added IsDot, IsDotDot (to check for ".", ".." path), and IsDotty (true if "." or ".."). The names are silly - suggestions?
Not silly. Cute. Really.
--
The Blog: Bits and Pieces
|
|
|
|
 |
|
 |
could it check whether a string is a valid string for a file?
|
|
|
|
 |
|
 |
there is "Exists", which checks if the file / directory exists, but I guess this is not what you are looking for.
A simple validity check would be (I think):
bool CPath::IsValidPath(bool allowXXLPath = false)
{
if (!allowXXLPath && m_path.getLength() > 255)
return false;
int idx = m_path.FindOneOf("\\/:*?\"<>|");
if (idx >= 0)
return false;
return true;
}
This checks for the characters flagged "invalid" on an NTFS drive I'm not sure about the following things:
- Invalid characters is probably file system dependent
- Which file systems allow Unicode?
- no check is made for valid protocols, different restrictions for server / share names, etc.
Recommendations / Links?
Pandoras Gift #44: Hope. The one that keeps you on suffering. aber.. "Wie gesagt, der Scheiss is' Therapie" boost your code || Fold With Us! || sighist | doxygen
|
|
|
|
 |
|
 |
I have written a small console app to test the CPath class with the CStdString class (http://codeproject.com/string/stdstring.asp) and it works OK apart from a couple of problems. Let me explain...
I have a functions to output to the console which are based on your CXShellPathDlg::AddToList() demo app functions. For example,
void PrintPathOutput(LPCTSTR name,LPCTSTR value);
All the tests compile OK apart from the following (I've listed the lines followed by the compiler error):
PrintPathOutput("Create Path(epcRemoveArgs)", CPath(s1, epc_Default | epcRemoveArgs));
error C2665: 'CPath::CPath' : none of the 6 overloads can convert parameter 1 from type 'class nsPath::CPath'
PrintPathOutput("Canonicalize", CPath(s1,0).Canonicalize());
error C2665: 'CPath::CPath' : none of the 6 overloads can convert parameter 1 from type 'class nsPath::CPath'
error C2228: left of '.Canonicalize' must have class/struct/union type
PrintPathOutput("QuoteSpaces(string)", nsPath::QuoteSpaces(s1));
error C2664: 'QuoteSpaces' : cannot convert parameter 1 from 'class nsPath::CPath' to 'const class CStdStr &'
Reason: cannot convert from 'class nsPath::CPath' to 'const class CStdStr'
No constructor could take the source type, or constructor overload resolution was ambiguous
PrintPathOutput("CreateSplitArgs", SplitArgs(s1, &sargs));
error C2664: 'SplitArgs' : cannot convert parameter 1 from 'class nsPath::CPath' to 'const class CStdStr &'
Reason: cannot convert from 'class nsPath::CPath' to 'const class CStdStr'
No constructor could take the source type, or constructor overload resolution was ambiguous
PrintPathOutput("PathSplitIconLocation", SplitIconLocation(s1, &icon));
error C2664: 'SplitIconLocation' : cannot convert parameter 1 from 'class nsPath::CPath' to 'const class CStdStr &'
Reason: cannot convert from 'class nsPath::CPath' to 'const class CStdStr'
No constructor could take the source type, or constructor overload resolution was ambiguous
Since the parameter list for PrintPathOutput() is the same as the parameter list for CXShellPathDlg::AddToList(), I don't understand why the errors are appearing.
I would appreciate your help in finding out what's wrong.
|
|
|
|
 |
|
 |
Thanks for your very useful class. I am new to C++ and am in the process of building up a library of useful classes. Your class has just been included
Now for the bug...
I know you can just use "CPath path" to get an empty path, but doing "CPath path("")" should not cause an exception.
|
|
|
|
 |
|
 |
Hi,
I can't reproduce the problem (I tried the version from CP, and the one I use at w*rk) - also BoundsChecker says it's all fine.
Could you give me a (preferrably small) snippet that reproduces the problem?
(the only additional code that runs is the cleanup routines - *after* assigning to a CString, where there should be no difference.
Pandoras Gift #44: Hope. The one that keeps you on suffering. aber.. "Wie gesagt, der Scheiss is' Therapie" boost your code || Fold With Us! || sighist | doxygen
|
|
|
|
 |
|
 |
I am using a replacement for CString (http://www.codeproject.com/string/stdstring.asp) and so that may be the cause of the problem, although I cannot see what the problem is. I have traced it and the exception occurs in "CPath & CPath::ExpandEnvStrings()" at the following point:
if (required > len+1)
ExpandEnvironmentStrings(
m_path,
CStringLock(target, required), required+1);
I don't suppose you would be able to help me track the problem down ?
I can e-mail you a zipped up copy of the test project.
|
|
|
|
 |
|
 |
defenestration wrote:
I can e-mail you a zipped up copy of the test project.
Send it to [edited], together with the command line thingie if possible. I'll see what I can do. No promises.
There might be a problem with CStringLock (but everytime I have doubts I can convince myself that it is correct), or maybe there's a nasty side effect with the CStdString implementation.
I've been using it heavily with MFC and WTL CString without problems (but they use very similar code). With your other problem, I guess CStdString and CString handle some overloads correctly, I'll see if I can clean it up
Which compiler are you using?
Pandoras Gift #44: Hope. The one that keeps you on suffering. aber.. "Wie gesagt, der Scheiss is' Therapie" boost your code || Fold With Us! || sighist | doxygen
|
|
|
|
 |