Randor wrote: The CreateFileW[^] function can absolutely create files with paths greater than MAX_PATH.
I don't dispute that it can. I am saying there may be some problem (or trick that must be applied) on these OSes. I would love to discuss this further, but I'm afraid it'll be quite a long post. I hope you might be interested.
I hope you'll really try this and post back.
Okay, so I'm actually pinvoking the API method from a .NET framework. I will provide the entire code for you and you can easily run it in LINQPad (free utility at LINQPad - The .NET Programmer's Playground[^]
Running the Source Code
If you get that tool you can copy paste the entire listing directly into a new linqpad "query" and it'll run normally as any other .NET program. Of course, you can easily create a console app in VStudio 2015 or whatever. The code will still run.
MessageBoxW
If you run the code you will see that it will successfully call MessageBoxW and display some text in the message box. That was a test to insure that the text of the path was being marshalled properly.
You can see the pinvoke has the charset set to Auto and it does indeed convert and display the chars properly. That's important since we are going to pass the string for the text file.
If you set the Charset to Charset.Ansi, you'll see nonsense kanji characters or something since this is a W method.
Why MessageBoxW?
I'm simply setting up the idea that my pinvoke does seem to work properly, the string marshalling is correct and the error I get when attempting to create the file is more likely related to the file system or API than it is to a bad path string being passed.
Note: You'll need to change the path to a location that exists on your c:\ drive
So, if you run the code
*the MessageBox will pop up
*the code will attempt to create a file with a long name and fail
*the code will attempt to create a file with a shorter name and succeed -- proves the call to CreateFileW does indeed work.
The output (after the messagebox displays )looks like the following:
Output 3/8/2017 8:31:59 AM
Failed!
HRESULT: -2147024773 Error: 123
Seems to work..
The Error 123 is the error from the OS (GetLastError) which we've talked about.
The "Seems to work.." is the successful creation of the 2nd file (which is not a long file name) to prove that the call to CreateFileW() does indeed work as I've defined it and the pinvoke seems to be set up correctly.
What Do You Think?
Can you explain this? Can you provide a very small example of working code (written in C++ or something) which will actually create a long file name?
I put a lot into this so I hope it has caught your interest.
Great discussion.
[DllImport("kernel32.dll", SetLastError=true, CharSet=CharSet.Auto)]
public static extern SafeFileHandle CreateFileW(
String lpFileName,
EFileAccess dwDesiredAccess,
EFileShare dwShareMode,
IntPtr lpSecurityAttributes,
ECreationDisposition dwCreationDisposition,
EFileAttributes dwFlagsAndAttributes,
IntPtr hTemplateFile);
[DllImport("user32.dll", CharSet=CharSet.Auto)]
static extern int MessageBoxW(IntPtr hWnd, String text, String caption, int options);
void Main()
{
MessageBoxW(IntPtr.Zero, @"\\?\c:\users\<username>\temp\superlongfilenameand1234567890thisoneisgoingintherecordbooks1234567890andwillprobablytoastthisentire1234567890thingandiwonderwhatitisgoing1234567890todowhenilookatthefiletest1234567890ThisIsGoingToGoOnForALongLongLongLongLongTimeIthink123456789012345678901234567890123456789012345678901234567890_2017_03_10_2.txt", "Caption", 0);
Console.WriteLine(DateTime.Now);
SafeFileHandle sfh = CreateFileW(@"\\?\c:\users\<username>\temp\superlongfilenameand1234567890thisoneisgoingintherecordbooks1234567890andwillprobablytoastthisentire1234567890thingandiwonderwhatitisgoing1234567890todowhenilookatthefiletest1234567890ThisIsGoingToGoOnForALongLongLongLongLongTimeIthink123456789012345678901234567890123456789012345678901234567890_2017_03_10_2.txt",
EFileAccess.GenericWrite, EFileShare.Read,
IntPtr.Zero, ECreationDisposition.CreateAlways,
EFileAttributes.Archive, IntPtr.Zero);
if (sfh.IsInvalid ){
Console.WriteLine("Failed!");
int HRESULT = Marshal.GetHRForLastWin32Error();
int ERRORVAL = Marshal.GetLastWin32Error();
Console.WriteLine(String.Format("HRESULT: {0} Error: {1}",HRESULT, ERRORVAL));
}
else{
Console.WriteLine("Seems to work..");
}
sfh = CreateFileW(@"\\?\C:\Users\<username>\temp\notlongName_2017_03_11_2.txt",
EFileAccess.GenericWrite, EFileShare.Read,
IntPtr.Zero, ECreationDisposition.CreateAlways,
EFileAttributes.Archive, IntPtr.Zero);
if (sfh.IsInvalid ){
Console.WriteLine("Failed!");
int HRESULT = Marshal.GetHRForLastWin32Error();
int ERRORVAL = Marshal.GetLastWin32Error();
Console.WriteLine(String.Format("HRESULT: {0} Error: {1}",HRESULT, ERRORVAL));
}
else{
Console.WriteLine("Seems to work..");
}
}
public enum EFileAccess : uint
{
AccessSystemSecurity = 0x1000000,
MaximumAllowed = 0x2000000,
Delete = 0x10000,
ReadControl = 0x20000,
WriteDAC = 0x40000,
WriteOwner = 0x80000,
Synchronize = 0x100000,
StandardRightsRequired = 0xF0000,
StandardRightsRead = ReadControl,
StandardRightsWrite = ReadControl,
StandardRightsExecute = ReadControl,
StandardRightsAll = 0x1F0000,
SpecificRightsAll = 0xFFFF,
FILE_READ_DATA = 0x0001,
FILE_LIST_DIRECTORY = 0x0001,
FILE_WRITE_DATA = 0x0002,
FILE_ADD_FILE = 0x0002,
FILE_APPEND_DATA = 0x0004,
FILE_ADD_SUBDIRECTORY = 0x0004,
FILE_CREATE_PIPE_INSTANCE = 0x0004,
FILE_READ_EA = 0x0008,
FILE_WRITE_EA = 0x0010,
FILE_EXECUTE = 0x0020,
FILE_TRAVERSE = 0x0020,
FILE_DELETE_CHILD = 0x0040,
FILE_READ_ATTRIBUTES = 0x0080,
FILE_WRITE_ATTRIBUTES = 0x0100,
GenericRead = 0x80000000,
GenericWrite = 0x40000000,
GenericExecute = 0x20000000,
GenericAll = 0x10000000,
SPECIFIC_RIGHTS_ALL = 0x00FFFF,
FILE_ALL_ACCESS =
StandardRightsRequired |
Synchronize |
0x1FF,
FILE_GENERIC_READ =
StandardRightsRead |
FILE_READ_DATA |
FILE_READ_ATTRIBUTES |
FILE_READ_EA |
Synchronize,
FILE_GENERIC_WRITE =
StandardRightsWrite |
FILE_WRITE_DATA |
FILE_WRITE_ATTRIBUTES |
FILE_WRITE_EA |
FILE_APPEND_DATA |
Synchronize,
FILE_GENERIC_EXECUTE =
StandardRightsExecute |
FILE_READ_ATTRIBUTES |
FILE_EXECUTE |
Synchronize
}
[Flags]
public enum EFileAttributes : uint
{
Readonly = 0x00000001,
Hidden = 0x00000002,
System = 0x00000004,
Directory = 0x00000010,
Archive = 0x00000020,
Device = 0x00000040,
Normal = 0x00000080,
Temporary = 0x00000100,
SparseFile = 0x00000200,
ReparsePoint = 0x00000400,
Compressed = 0x00000800,
Offline = 0x00001000,
NotContentIndexed= 0x00002000,
Encrypted = 0x00004000,
Write_Through = 0x80000000,
Overlapped = 0x40000000,
NoBuffering = 0x20000000,
RandomAccess = 0x10000000,
SequentialScan = 0x08000000,
DeleteOnClose = 0x04000000,
BackupSemantics = 0x02000000,
PosixSemantics = 0x01000000,
OpenReparsePoint = 0x00200000,
OpenNoRecall = 0x00100000,
FirstPipeInstance= 0x00080000
}
[Flags]
public enum EFileShare : uint
{
None = 0x00000000,
Read = 0x00000001,
Write = 0x00000002,
Delete = 0x00000004
}
public enum ECreationDisposition : uint
{
New = 1,
CreateAlways = 2,
OpenExisting = 3,
OpenAlways = 4,
TruncateExisting = 5
}
|