I am trying to P/Invoke SetFileTime, but I can't seem to get it to work. It always returns an error code of 5 for me (access denied), and I am not sure why. Here is the code I am using:
void Main()
{
var pointer = CreateFile(@"C:\Users\User\Desktop\New folder\New Text Document.txt", FileAccess.ReadWrite, FileShare.None, IntPtr.Zero, FileMode.Open, FileAttributes.Normal, IntPtr.Zero);
Console.WriteLine(pointer);
var now = DateTime.Now.ToFileTime();
long lpCreationTime = now;
long lpLastAccessTime = now;
long lpLastWriteTime = now;
if (!SetFileTime(pointer, ref lpCreationTime, ref lpLastAccessTime, ref lpLastWriteTime))
Console.WriteLine(GetLastError());
CloseHandle(pointer);
}
[DllImport("kernel32.dll")]
static extern UInt32 GetLastError();
[DllImport("kernel32.dll", SetLastError = true)]
static extern Boolean SetFileTime(IntPtr hFile, ref long lpCreationTime, ref long lpLastAccessTime, ref long lpLastWriteTime);
[DllImport("kernel32.dll", SetLastError = true)]
static extern Boolean CloseHandle(IntPtr hObject);
[DllImport("kernel32.dll", CharSet = CharSet.Unicode, SetLastError = true)]
static extern IntPtr CreateFile(String fileName, [MarshalAs(UnmanagedType.U4)] FileAccess fileAccess, [MarshalAs(UnmanagedType.U4)] FileShare fileShare, IntPtr securityAttributes, [MarshalAs(UnmanagedType.U4)] FileMode creationDisposition, [MarshalAs(UnmanagedType.U4)] FileAttributes flags, IntPtr template);
My pointer is valid (2376) but I see that SetFileTime has failed and has returned an error code of 5 (access denied). Now, I have ensured I am running as administrator and that my account has permissions to that path, but still, no cigar. Anyone have any ideas why this is happening?
Update
Marshal.GetLastWin32Error() also returns 5 after the call to SetFileTime. Also, my need for making this call work is so that I can SetFileTime on long paths in Windows, which CreateFile supports, but the current file libraries of .NET do not support long paths in Windows.
From the documentation of SetFileTime:
A handle to the file or directory. The handle must have been created using the CreateFile function with the FILE_WRITE_ATTRIBUTES access right.
Your code doesn't manage to do that. The .net FileAccess enumeration is not compatible with Win32 access flags. You'll need to define an enum specifically for use with CreateFile. Likewise your use of FileShare and FileMode are not correct.
This p/invoke declaration should suffice: http://www.pinvoke.net/default.aspx/kernel32.createfile
As Alexei said, don't call GetLastError because you may be picking up an error code for a framework call rather than the true error. Use SetLastError = true and Marshal.GetLastWin32Error().
You also fail to check for errors in the return value if CreateFile.
Thanks to all the help, I was able to achieve my goals using the following (FileAccess.ReadWrite translates to 0x3 while FILE_WRITE_ATTRIBUTES is 0x100):
[DllImport("kernel32.dll", SetLastError = true)]
static extern Boolean SetFileTime(SafeFileHandle hFile, ref long lpCreationTime, ref long lpLastAccessTime, ref long lpLastWriteTime);
[DllImport("kernel32.dll", CharSet = CharSet.Unicode, SetLastError = true)]
static extern SafeFileHandle CreateFile(String fileName, uint fileAccess, [MarshalAs(UnmanagedType.U4)] FileShare fileShare, IntPtr securityAttributes, [MarshalAs(UnmanagedType.U4)] FileMode creationDisposition, [MarshalAs(UnmanagedType.U4)] FileAttributes flags, IntPtr template);
static void Main(string[] args)
{
var handle = CreateFile(@"C:\Users\User\Desktop\FileTimeTest.txt", (uint)(0x3 | 0x100), FileShare.None, IntPtr.Zero, FileMode.Create, FileAttributes.Normal, IntPtr.Zero);
if (!handle.IsInvalid)
{
using (var stream = new FileStream(handle, FileAccess.ReadWrite))
using (var writer = new StreamWriter(stream))
{
writer.WriteLine("Hello, world.");
var now = DateTime.MaxValue.ToFileTime();
if (!SetFileTime(handle, ref now, ref now, ref now))
Console.WriteLine(Marshal.GetLastWin32Error());
}
}
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With