Long paths

K

krazymike

Ok, I have an access module which builds an index of directories in
the subtree of a user-selected directory/drive. Then, it goes through
those and builds another index of all the files in those directories.
I'm using the FileSystemObject just for clean code. Here's the
problem I'm hitting. I'm hitting the 260 character MAX_PATH limit.

The fso is reporting the correct number of files, but for the files
that exceed the limit, it acts like they're not even there. No errors
are raised, nothing.

I've tried this in VB6, but again nothing. I was told the kernel has
some API's I can use, but honestly, I am not that well versed in API
usage.

Bottom line, I need to be able to capture the long path of every
file. I can use the shortpath for my metadata extraction, etc, but
for the people who use the output of this, I do need to capture the
"windows explorer" name.

Here's an example of a filepath that's too far out: (This is an actual
file that I generated for testing)

X:\shared\username
\New_Folderaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaadfasdfasdfasdifuasdiofuyeasdkofuheasdkjfjheaskldjfheaskdfheaskdjfheaskldjfheaskdjfhasd
\adsfdkjfheaskdjfheasldkjfheasdklfehasdfkljashdlfjksdfh.txt
 
P

Pegasus \(MVP\)

krazymike said:
Ok, I have an access module which builds an index of directories in
the subtree of a user-selected directory/drive. Then, it goes through
those and builds another index of all the files in those directories.
I'm using the FileSystemObject just for clean code. Here's the
problem I'm hitting. I'm hitting the 260 character MAX_PATH limit.

The fso is reporting the correct number of files, but for the files
that exceed the limit, it acts like they're not even there. No errors
are raised, nothing.

I've tried this in VB6, but again nothing. I was told the kernel has
some API's I can use, but honestly, I am not that well versed in API
usage.

Bottom line, I need to be able to capture the long path of every
file. I can use the shortpath for my metadata extraction, etc, but
for the people who use the output of this, I do need to capture the
"windows explorer" name.

Here's an example of a filepath that's too far out: (This is an actual
file that I generated for testing)

X:\shared\username
\New_Folderaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaadfasdfasdfasdifuasdiofuyeasdkofuheasdkjfjheaskldjfheaskdfheaskdjfheaskldjfheaskdjfhasd
\adsfdkjfheaskdjfheasldkjfheasdklfehasdfkljashdlfjksdfh.txt

There are a few applications that can process the full NTFS path
length of some 32,000 characters (I think), e.g. ntbackup.exe,
robocopy.exe or iexplore.exe. AFAIK, neither cscript.exe nor
wscript.exe is among them.
 
K

krazymike

Ok, can I call these apps and get something returned? This data is
going into an mdb, so just being able to access them isn't enough.
 
P

Pegasus \(MVP\)

You could execute robocopy.exe /L and monitor its screen output.
A good long-term strategy would be to educate your users to put
their data into their files, not into their file/folder names.


Ok, can I call these apps and get something returned? This data is
going into an mdb, so just being able to access them isn't enough.
 
H

Howard Kaikow

You need to use the Unicode version of API calls.

Start by looking at the CreateFileW, the Unicode version of CreateFile.
 
R

Ralph

krazymike said:
Ok, I have an access module which builds an index of directories in
the subtree of a user-selected directory/drive. Then, it goes through
those and builds another index of all the files in those directories.
I'm using the FileSystemObject just for clean code. Here's the
problem I'm hitting. I'm hitting the 260 character MAX_PATH limit.

The fso is reporting the correct number of files, but for the files
that exceed the limit, it acts like they're not even there. No errors
are raised, nothing.

I've tried this in VB6, but again nothing. I was told the kernel has
some API's I can use, but honestly, I am not that well versed in API
usage.

This limitation is limited to the ANSI (or 'A') versions of the API
functions. You can work with longer paths if you use the UNICODE or 'W'
versions: eg. use
... Alias "FindFirstFileW" instead of Alias "FindFirstFileA"
which is how you will find many VB/WinAPI calls declared. This is can be
confusing in some examples because for back-ward compatibility
"FindFirstFile" maps to "FindFirstFileA", and thus the 'A' or 'W' may be
missing in the Declare.
Take a look at this example:
http://www.dbforums.com/showthread.php?t=979095
(It uses the 'A' versions. Simply make the change yourself and then test it
against your data/paths.)

Note the explanation on using the "\\?\" hack if you want to pass a long
path.

hth
-ralph
 
K

krazymike

Unfortunately, I'm not dealing with users, as such. I work in a law
firm, and client's hard drives are often copied to network locations.
Add the network path to the file path of the files, and you get a lot
of 300+ character paths.

So, even if we educated the proper people, putting these files on the
network would negate their albeit proper practices. Second, we could
never educate every user we will deal with, as we cannot predict whom
our clients will be.
 
K

Klatuu

Try using Application.FileSearch instead of FSO.
The codinging is similar, but it is native to Access. FSO is an Office
object that is known to be flaky at times.
 
M

Mike Williams

Unfortunately, I'm not dealing with users, as such.
I work in a law firm, and client's hard drives are often
copied to network locations. Add the network path to
the file path of the files, and you get a lot of 300+
character paths.

Agreed. It is not always possible, and very rarely advisable, to attempt to
force your users into behaving in a specific way. The same kind of "long
name" problems often also occur with printer devicenames, which can
effectively be an almost unlimited length in all 32 bit versions of Windows
but which require you to jump through a few hoops in order to dig out their
long names when showing an API printer dialog.

Mike
 
A

Albert D. Kallal

Keep in mind that a standard ms-access feld is limited to 255 chars, and
perhaps you need to use a memo field to store the results????

In otther words, are you use its th fso that casuing the problem here, or is
it perhaps you exceeiding the limites of a stadnard text field?

here is the follwing code I use to walk a direcotry using the dir
command....I do't belive it suffers from the 255 char limit...

Sub dirTest()

Dim dlist As New Collection
Dim startDir As String
Dim i As Integer

startDir = "C:\access\"
Call FillDir(startDir, dlist)

MsgBox "there are " & dlist.Count & " in the dir"

' lets printout the stuff into debug window for a test

For i = 1 To dlist.Count
Debug.Print dlist(i)
Next i

End Sub

Sub FillDir(startDir As String, strFil As String, dlist As Collection)

' build up a list of files, and then
' add add to this list, any additinal
' folders

Dim strTemp As String
Dim colfolders As New Collection
Dim vFolderName As Variant

strTemp = Dir(startDir & strFil)

Do While strTemp <> ""
dlist.Add startDir & strTemp
strTemp = Dir
Loop

' now build a list of additional folders
strTemp = Dir(startDir & "*.*", vbDirectory)

Do While strTemp <> ""
If (GetAttr(startDir & strTemp) And vbDirectory) = vbDirectory Then
If (strTemp <> ".") And (strTemp <> "..") Then
colfolders.Add strTemp
End If
End If
strTemp = Dir
Loop

' now process each folder (recursion)
For Each vFolderName In colfolders
Call FillDir(startDir & vFolderName & "\", strFil, dlist)
Next vFolderName

End Sub

Sub FillDir(startDir As String, dlist As Collection)

' build up a list of files, and then
' add add to this list, any additional
' folders

Dim strTemp As String
Dim colFolders As New Collection
Dim vFolderName As Variant

strTemp = Dir(startDir)

Do While strTemp <> ""
dlist.Add startDir & strTemp
strTemp = Dir
Loop

' now build a list of additional folders
strTemp = Dir(startDir & "*.", vbDirectory)

Do While strTemp <> ""
If (strTemp <> ".") And (strTemp <> "..") Then
colFolders.Add strTemp
End If
strTemp = Dir
Loop

' now process each folder (recursion)
For Each vFolderName In colFolders
Call FillDir(startDir & vFolderName & "\", dlist)
Next vFolderName

End Sub
 
M

Mike Williams

[Addressed to the OP] Keep in mind that a standard
ms-access feld is limited to 255 chars, and perhaps you
need to use a memo field to store the results???? . . .
here is the follwing code I use to walk a direcotry using
the dir command....I do't belive it suffers from the 255
char limit...

Actually the maximum file name size limit appears to be heavily embedded
into the Windows OS. I'm using Windows Vista Ultimate and the OS (or at
least Windows Explorer) prevents me even from manually renaming a file such
that its total path length is greater than about 259 characters. And when I
make the name as long as the OS will permit (such as "c:\temp\a very long
file name . . . . ."and I later try to move that file into a directory that
has a longer path name (such as my desktop, for example) the system prevents
me from doing so, informing me that "The filename is too long for the
destination folder" and advising me to either shorten the filename and try
agin or alternatively choose a destination folder that has a shorter path.
And if I "cheat a little" by renaming "c:\temp" folder to "c:\t" (which
permits me to add a few extra characters to the filename) and if I then
cange it back to "c:\temp" after adding those few extra charcaters and then
use the code you posted to run through c:\temp I get a "File Not Found"
error when it attempts to access the file with the long name.

So, it looks as though this file name length limitation is more heavily
embedded into the OS than I at first thought it might be.

Mike
 
T

Tom Shelton

[Addressed to the OP] Keep in mind that a standard
ms-access feld is limited to 255 chars, and perhaps you
need to use a memo field to store the results???? . . .
here is the follwing code I use to walk a direcotry using
the dir command....I do't belive it suffers from the 255
char limit...

Actually the maximum file name size limit appears to be heavily embedded
into the Windows OS. I'm using Windows Vista Ultimate and the OS (or at
least Windows Explorer) prevents me even from manually renaming a file such
that its total path length is greater than about 259 characters. And when I
make the name as long as the OS will permit (such as "c:\temp\a very long
file name . . . . ."and I later try to move that file into a directory that
has a longer path name (such as my desktop, for example) the system prevents
me from doing so, informing me that "The filename is too long for the
destination folder" and advising me to either shorten the filename and try
agin or alternatively choose a destination folder that has a shorter path.
And if I "cheat a little" by renaming "c:\temp" folder to "c:\t" (which
permits me to add a few extra characters to the filename) and if I then
cange it back to "c:\temp" after adding those few extra charcaters and then
use the code you posted to run through c:\temp I get a "File Not Found"
error when it attempts to access the file with the long name.

So, it looks as though this file name length limitation is more heavily
embedded into the OS than I at first thought it might be.

Mike

Many of the Unicode api's allow you to access paths up to 32,000
characters (NTFS maximum path length) - but, you have to use the unicode
version of the api and prefix the path with \\?\ to tell it to use the long
path:

"\\?\C:\........\....\..."

Otherwise, they use MAX_PATH, which is defined as 260 - 259 chars + a null
terminator.
 
M

Mike Williams

Many of the Unicode api's allow you to access paths
up to 32,000 characters (NTFS maximum path length)
- but, you have to use the unicode version of the api and
prefix the path with \\?\ to tell it to use the long path:

Yes, I'm sure they do. And in fact I've already been informed that they do.
But I was merely commenting on how deeply the "limited character length path
and file name" is embedded into the Windows OS, to the point that even in
Vista Ultimate a user or even an administrator cannot manually create a long
file name using the standard "Windows Explorer" methods available to users.

Mike
 
K

Karl E. Peterson

krazymike said:
Unfortunately, I'm not dealing with users, as such. I work in a law
firm, and client's hard drives are often copied to network locations.
Add the network path to the file path of the files, and you get a lot
of 300+ character paths.

Seems like you could overcome this by simply sharing the folder from the server,
then attaching to it from the workstation?
 
R

Ron Weiner

Have you try'd to use the API GetShortPathName()

Here is the Declare:
Private Declare Function GetShortPathName Lib "kernel32.dll" _
Alias "GetShortPathNameA" (ByVal lpszLongPath As String, _
ByVal lpszShortPath As String, ByVal cchBuffer As Long) As Long

Here is a Function:
Public Function ShortName(strLongPath As String) As String
' Purpose Converts Long FileName to its Short FileName
Dim strShortPath As String
Dim Ret As Long
Const MAX_PATH = 260

If strLongPath = "" Then
Exit Function
End If
strShortPath = Space$(MAX_PATH)
Ret = GetShortPathName(strLongPath, strShortPath, MAX_PATH)
If Ret Then
ShortName = Left$(strShortPath, Ret)
End If
End Function


Rdub
 
H

Howard Kaikow

Mike Williams said:
[Addressed to the OP] Keep in mind that a standard
ms-access feld is limited to 255 chars, and perhaps you
need to use a memo field to store the results???? . . .
here is the follwing code I use to walk a direcotry using
the dir command....I do't belive it suffers from the 255
char limit...

Actually the maximum file name size limit appears to be heavily embedded
into the Windows OS. I'm using Windows Vista Ultimate and the OS (or at
least Windows Explorer) prevents me even from manually renaming a file such
that its total path length is greater than about 259 characters. And when I
make the name as long as the OS will permit (such as "c:\temp\a very long
file name . . . . ."and I later try to move that file into a directory that
has a longer path name (such as my desktop, for example) the system prevents
me from doing so, informing me that "The filename is too long for the
destination folder" and advising me to either shorten the filename and try
agin or alternatively choose a destination folder that has a shorter path.
And if I "cheat a little" by renaming "c:\temp" folder to "c:\t" (which
permits me to add a few extra characters to the filename) and if I then
cange it back to "c:\temp" after adding those few extra charcaters and then
use the code you posted to run through c:\temp I get a "File Not Found"
error when it attempts to access the file with the long name.

So, it looks as though this file name length limitation is more heavily
embedded into the OS than I at first thought it might be.

Yes, you have to use Unicode API calls.
 
K

krazymike

Ok, back to the original topic.

I used FindFirstFileA and FindNextFileA and was able to access a path
of 306 characters. Now, I need to cover the UNICODE characters which
may be in the file names. We get stuff from macs and linux machines
from time to time. As far as I understand, I should be able to change
the A to a W to use the unicode version. That doesn't work. I
prepended the "\\?\" to the path, and had no luck. I'm wondering if I
need some language packs installed to use unicode at all.

Any thoughts?

[Addressed to the OP] Keep in mind that a standard
ms-access feld is limited to 255 chars, and perhaps you
need to use a memo field to store the results????  . . .
here is the follwing code I use to walk a direcotry using
the dir command....I do't belive it suffers from the 255
char limit...
Actually the maximum file name size limit appears to be heavily embedded
into the Windows OS. I'm using Windows Vista Ultimate and the OS (or at
least Windows Explorer) prevents me even from manually renaming a file such
that its total path length is greater than about 259 characters. And when I
make the name as long as the OS will permit (such as "c:\temp\a very long
file name . . . . ."and I later try to move that file into a directory that
has a longer path name (such as my desktop, for example) the system prevents
me from doing so, informing me that "The filename is too long for the
destination folder" and advising me to either shorten the filename and try
agin or alternatively choose a destination folder that has a shorter path.
And if I "cheat a little" by renaming "c:\temp" folder to "c:\t" (which
permits me to add a few extra characters to the filename) and if I then
cange it back to "c:\temp" after adding those few extra charcaters and then
use the code you posted to run through c:\temp I get a "File Not Found"
error when it attempts to access the file with the long name.
So, it looks as though this file name length limitation is more heavily
embedded into the OS than I at first thought it might be.

Yes, you have to use Unicode API calls.
 
K

krazymike

This worked just fine, but I'm trying to process Unicode chars in
filenames now, and the "W" version doesn't seem to be working.

Also, to address an issue brought up, my fields are, in fact, Memo.
 
K

Karl E. Peterson

krazymike said:
Ok, back to the original topic.

I used FindFirstFileA and FindNextFileA and was able to access a path
of 306 characters. Now, I need to cover the UNICODE characters which
may be in the file names. We get stuff from macs and linux machines
from time to time. As far as I understand, I should be able to change
the A to a W to use the unicode version.
Right.

That doesn't work.

Huh? You're a *developer* and you post a *user* error report?
prepended the "\\?\" to the path, and had no luck. I'm wondering if I
need some language packs installed to use unicode at all.

Any thoughts?

Yeah. But I'll spare you most of them.

You need to understand Unimess, first. The way VB mangles the Unicode strings it
stores internally, when passing them externally, and vice-versa. To get Unicode
in/out of VB, you need to work directly with pointers. How are you declaring the
API(s) and their related structures? How are you filling the structures? How are
you reading what's returned?

"Doesn't work" doesn't even begin to provide the requisite clues.
 
K

krazymike

Thanks. That's a lot of help. You know it's people like you who make
it nearly impossible to get any help. Trying to make people look bad
and yourself good only serves to expose you as the jerk you clearly
are.

"Doesn't work" = hSearch gets value of -1 no matter what I do.

Prepending the \\?\ doesn't change anything. What I was told that my
code that works with the FindFirstFileA/FindNextFileA would work by
switching to the W implementation of these functions. I'm finding
that this is not the case.

I read somewhere that you need to pass the parameters to the W
implementations as UTF-16 strings, but I have yet to have any luck
with that either. The UTF-16 converter I found was returning null
strings. I tried using MultiByteToWideChar to generate a UTF-8, but I
don't think that's really doing much. The handler still receives the
-1 value.

I know this has to be possible, but perhaps not from VBA? If I can
get this working in vb6, that'd do fine, too. I'm just restricted
from using .Net in my department. Not my choice, just the way
"business" decisions are made sometimes.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Top