Although low level windows API has been capable of long paths for quite a while (at least since winXP), the windows shell (including windows explorer and the system open/save dialogs) are still very much limited to MAX_PATH characters. You cannot create folders whose overall path name exceeds 260 letters, unless they are on a volume that has short 8.3 filenames enabled.
The over-hyped windows 10 LongPathsEnabled registry tweak offered next to nothing in this respect. All you get with it (or the equivalent longPathAware manifest) is the ability to have long paths without the \\?\ prefix — but only for the low level file API. All the shell programming API is still MAX_PATH constrained; you can forget about IShellFolder, IShellItem and all the rest of it. |
In a sense programming for long paths is easy: enlarge all buffers of MAX_PATH size to a new constant MAX_PATH_EX (=32767), and prepend all path names with \\?\ or \\?\UNC\ (or even \??\ :), but that's only the tip of the iceberg. Reviewing a 7.5MB code base for hidden path length assumptions is an unenviable way to spend one's Christmas holidays, but I did just that and I want to share with you the details, that should help your program become long path aware.
1. Create a deep path for testing
This is easier said than done. If you try creating long directories on system partition C:\ where short 8.3 names are enabled, there will be a back door using GetShortPathName — your supposed big name will only be 8 characters long (e.g. VERYLA~1). You must create a fresh partition and make sure you turn off 8.3 paths using fsutil 8dot3name. You cannot have an individual folder name larger than _MAX_FNAME (=256) letters, so you should create a few folders within folders with large-ish names. When you approach the 260 letter path limit you cannot go any deeper using windows explorer. Instead you should create a folder junction and use it as a shortcut to go deeper.
2. Search your code for MAX_PATH use
Prepare to be shocked: searching my source code gave 425 occurrence(s) have been found. OMG, this is going to be a long and deep code review. All text buffers should be enlarged to MAX_PATH_EX (=32767) or you can drop them altogether for CString objects. Create simple helpers to check for the existence of the long path prefix \\?\ and for adding it whenever names get close to the limit. It doesn't stop with your code either, you should check the framework you are using too. I had to change the WTL source code in a few places where it uses MAX_PATH (CRecentDocumentList and CFileDialog classes). Good luck if you are using MFC :)
3. Start programs: Failed
Whereas most low level API is long path aware, SetCurrentDirectory isn't. Anything above MAX_PATH and it will fail. This hints a deeper (no pun intended) problem in windows kernel, because you cannot start any program situated in a deep folder — unless there is a 8.3 bypass. Even CreateProcess fails.
4. Open documents (?)
You cannot use the system open/save dialogs to reach in a deep directory structure. ShellExecute doesn't deal with \\?\ prefix either. What's the point storing a document somewhere when you cannot even open it? The way out of this ravine is to use AssocQueryString to manually locate the program that will open a file type, then launch it with CreateProcess. The latter can pass command line arguments that are situated deep. Still many programs like Notepad or all MS Office suite will just fail. Irfanview works but it is a small consolation <g>
5. Deep file operations: out of order
Windows explorer just won't bother, so how do you copy/rename/delete deep files? None of the most used shell functions work: SHFileOperation, SHGetFileInfo etc. These will fail at the merest hint of \\?\ prefix, even when the path is actually below the MAX_PATH limit! You must resort to low level API like CopyFileEx and DeleteFile to do your low level file operations. Exceptionally DragQueryFile will understand CF_HDROP formats that embed long path names, but don't expect windows explorer to accept the drop.
WM_DROPFILES message is eaten for deep items, another blow to drag-drop interoperability
6. Windows Shell: total disaster
I am a big fan of the shell architecture with its extensibility and custom handlers, but the whole edifice just founders in deep water. Very sad. Forget about the trusty IShellFolder interface. IShellItem can be created with long paths using simple pidls (SHSimpleIDListFromPath), but are good for nothing but a lame error return: 0x8007006f the file name is too long. Network "simple pidls" are full of bugs. Until such time as the MS shell programmer team do a major code review we must do without:
7. File change notifications
Things are slightly better in the autorefresh department. SHChangeNotify will circulate deep path changes via simple pidls for attentive listeners. SHChangeNotifyRegister is out of its depth but the trusty
FindFirstChangeNotification works with long paths.
Finally here are some sundry considerations for your oversized directories:
If you think about it, all this considerable effort is a monumental waste of time, because very few people go mad with verbose folder names. But it is an interesting adventure and you can go boast to your programming buddies that you broke the path depth world record <g>
ps. Happy new year!
Post a comment on this topic »