Sign in to follow this  
Followers 0
orbs

fail of unicode filename convention for too long path

5 posts in this topic

#1 ·  Posted (edited)

hello,

trying to use the unicode filename convention (prefix ?) to create a folder - the folder is created but name is truncated to 255 characters.

code: trying to create a folder with full path name of 310 characters on local NTFS volume on Windows 7 64-bit (autoIt v3.3.10.2)

Global $sTooLongPathRoot='C:\folder\'
Global $sTooLongPath='123456789_123456789_123456789_123456789_123456789_123456789_123456789_123456789_123456789_123456789_'

; create too long path
ConsoleWrite('DirCreate : '&DirCreate('\\?\'&$sTooLongPathRoot&$sTooLongPath&$sTooLongPath&$sTooLongPath)&@CR)  ; result = 1 (OK)

result:

post-47848-0-22781400-1398714503_thumb.p

note: if i omit the unicode prefix, then only the root folder "C:folder" is created (and return value = 0).

what am i missing?

Edited by orbs

Share this post


Link to post
Share on other sites



#2 ·  Posted (edited)

so i came across the CreateDirectory function in kernel32, which has a unicode form CreateDirectoryW:

http://msdn.microsoft.com/en-us/library/windows/desktop/aa363855(v=vs.85).aspx

trying to implement it, the script delays, and terminates in the middle with:

>Exit code: -1073741819    Time: 11.119

Global $sTooLongPathRoot='C:\folder\'
Global $sTooLongPath='123456789_123456789_123456789_123456789_123456789_123456789_123456789_123456789_123456789_123456789_'

$hDLL=DllOpen('kernel32.dll')
MsgBox(0,'$hDLL',$hDLL) ; this happens, always showing 1

$aRet=DllCall($hDLL,'int','CreateDirectoryW','str','\\?\'&$sTooLongPathRoot&$sTooLongPath&$sTooLongPath&$sTooLongPath)
MsgBox(0,'@error',@error)   ; this does not happen!

DllClose($hDLL)

actually, given this is my first venture into DLL land, i'm not surprised; but i can't find my error.

some help please?

EDIT: same result using wstr instead of str

EDIT: MSDN says the parameter is type LPCTSTR (see the "T" in the middle?). but AutoIt help for DllCall does not include this type, it does have these though:

LPCSTR/LPSTR => str 
LPCWSTR/LPWSTR => wstr 
Edited by orbs

Share this post


Link to post
Share on other sites

#3 ·  Posted (edited)

apparently when calling this function you must add the 2nd parameter (the security attributes struct) which i though is optional.

#include <Array.au3>

Global $sTooLongPathRoot='C:\folder\'
Global $sTooLongPath='123456789_123456789_123456789_123456789_123456789_123456789_123456789_123456789_123456789_123456789_'

$hDLL=DllOpen('kernel32.dll')
MsgBox(0,'$hDLL',$hDLL) ; this happens, always showing 1

$aRet=DllCall($hDLL,'int','CreateDirectoryW','wstr','\\?\'&$sTooLongPathRoot&$sTooLongPath&$sTooLongPath&$sTooLongPath,'struct*',0)
MsgBox(0,'@error',@error)   ; now this happens, always showing 0

_ArrayDisplay($aRet)    ; $aRet[0]=0 means fail

DllClose($hDLL)

now the script does not crash, so i guess i'm calling the DLL correctly.

but the folder is not created (return value 0).

if i reduce the length of the path from 310 to 210, the folder is created. but MSDN specifically states that:

There is a default string size limit for paths of 248 characters. This limit is related to how theCreateDirectory function parses paths.

To extend this limit to 32,767 wide characters, call the Unicode version of the function and prepend "?" to the path. For more information, see Naming a File.

so what am i doing wrong?

Edited by orbs

Share this post


Link to post
Share on other sites

For simplicity you might just use the _WinAPI_CreateDirectory() UDF from #include <WinAPIFiles.au3>, to save the trouble of rewriting the DLL call for clarity.  (And yes, the $tSecurity parameter is optional.)

But a couple of things to note first: Generally speaking DLLCall's don't return "real" error codes (they only return whether or not the DLLcall function itself succeeded, not if the function within the DLL you wanted succeeded or not).  To obtain this, use _WinAPI_GetLastError() or _WinAPI_GetLastErrorMessage() after your DLLCall.  It's helpful for figuring out what really failed.

The MAX_PATH limit (actually the lpMaximumComponentLength parameter from GetVolumeInformation) still applies to any single component of a path, even when using the ? prefix.  In other words, ?C255255255... etc.  So 32767 only applies to the total length of the fully qualified path, it does not expand the component size.

Also. according to the MSDN docs _WinAPI_CreateDirectory() will fail if any single component of the leading path is missing, so you can't just give it something like "?C:255255255" without first verifying (and creating, if necessary) that "?C:255" exists, then "?C:255255", etc.

On a purely entertaining level, if you ever build the "?" prefix into a UDF yourself, note that it will always fail if applied to a sole root: ?C: will actually fail when referenced, though ?C:Test (or longer) will succeed. Just another API quirk, I guess. :D

Share this post


Link to post
Share on other sites

The MAX_PATH limit (actually the lpMaximumComponentLength parameter from GetVolumeInformation) still applies to any single component of a path, even when using the ? prefix.  In other words, ?C255255255... etc.  So 32767 only applies to the total length of the fully qualified path, it does not expand the component size.

 

thank you so much for the clarification! my test folder had indeed a single component longer than 255 chars.

now this (very crude) demo works:

#include <WinAPIFiles.au3>

Global $sTooLongPathRoot='C:\folder'
Global $sTooLongPath='123456789_123456789_123456789_123456789_123456789_123456789_123456789_123456789_123456789_123456789_'

_WinAPI_CreateDirectory('\\?\'&$sTooLongPathRoot)
_WinAPI_CreateDirectory('\\?\'&$sTooLongPathRoot&'\'&$sTooLongPath)
_WinAPI_CreateDirectory('\\?\'&$sTooLongPathRoot&'\'&$sTooLongPath&'\'&$sTooLongPath)
_WinAPI_CreateDirectory('\\?\'&$sTooLongPathRoot&'\'&$sTooLongPath&'\'&$sTooLongPath&'\'&$sTooLongPath)

yey!  :thumbsup:

so now it's time to move on - to copy/move files to/from too long paths!

thank you so much!

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!


Register a new account

Sign in

Already have an account? Sign in here.


Sign In Now
Sign in to follow this  
Followers 0