orbs Posted April 28, 2014 Share Posted April 28, 2014 (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: 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 April 28, 2014 by orbs Signature - my forum contributions: Spoiler UDF: LFN - support for long file names (over 260 characters) InputImpose - impose valid characters in an input control TimeConvert - convert UTC to/from local time and/or reformat the string representation AMF - accept multiple files from Windows Explorer context menu DateDuration - literal description of the difference between given dates Apps: Touch - set the "modified" timestamp of a file to current time Show For Files - tray menu to show/hide files extensions, hidden & system files, and selection checkboxes SPDiff - Single-Pane Text Diff Link to comment Share on other sites More sharing options...
orbs Posted April 30, 2014 Author Share Posted April 30, 2014 (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 April 30, 2014 by orbs Signature - my forum contributions: Spoiler UDF: LFN - support for long file names (over 260 characters) InputImpose - impose valid characters in an input control TimeConvert - convert UTC to/from local time and/or reformat the string representation AMF - accept multiple files from Windows Explorer context menu DateDuration - literal description of the difference between given dates Apps: Touch - set the "modified" timestamp of a file to current time Show For Files - tray menu to show/hide files extensions, hidden & system files, and selection checkboxes SPDiff - Single-Pane Text Diff Link to comment Share on other sites More sharing options...
orbs Posted April 30, 2014 Author Share Posted April 30, 2014 (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 April 30, 2014 by orbs Signature - my forum contributions: Spoiler UDF: LFN - support for long file names (over 260 characters) InputImpose - impose valid characters in an input control TimeConvert - convert UTC to/from local time and/or reformat the string representation AMF - accept multiple files from Windows Explorer context menu DateDuration - literal description of the difference between given dates Apps: Touch - set the "modified" timestamp of a file to current time Show For Files - tray menu to show/hide files extensions, hidden & system files, and selection checkboxes SPDiff - Single-Pane Text Diff Link to comment Share on other sites More sharing options...
Solution Kilmatead Posted April 30, 2014 Solution Share Posted April 30, 2014 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. Link to comment Share on other sites More sharing options...
orbs Posted April 30, 2014 Author Share Posted April 30, 2014 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! so now it's time to move on - to copy/move files to/from too long paths! thank you so much! Signature - my forum contributions: Spoiler UDF: LFN - support for long file names (over 260 characters) InputImpose - impose valid characters in an input control TimeConvert - convert UTC to/from local time and/or reformat the string representation AMF - accept multiple files from Windows Explorer context menu DateDuration - literal description of the difference between given dates Apps: Touch - set the "modified" timestamp of a file to current time Show For Files - tray menu to show/hide files extensions, hidden & system files, and selection checkboxes SPDiff - Single-Pane Text Diff Link to comment Share on other sites More sharing options...
Recommended Posts
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 accountSign in
Already have an account? Sign in here.
Sign In Now