SetFileTime returns error code 5
I'm trying to P / Invoke SetFileTime but I can't seem to get it to work. It always returns error code 5 for me (access denied) and I'm not sure why. Here is the code I'm 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 can see that SetFileTime failed and returned error code 5 (access denied). I have now ensured that I am running as an administrator and that my account has permissions to this path, but still no cigar. Anyone have any ideas why this is happening?
Update
Marshal.GetLastWin32Error()
also returns 5 after the call SetFileTime
. Also, my need to make this call works so that I can SetFileTime
support long paths on Windows CreateFile
, but the current .NET file libraries do not support long paths on Windows.
source to share
From the documentation SetFileTime
:
A handle to a file or directory. The handle must be created using the CreateFile function with FILE_WRITE_ATTRIBUTES access.
Your code cannot do this. The .net enumeration is FileAccess
incompatible with Win32 access flags. You will need to specify an enum specifically for use with CreateFile
. Similarly, you use FileShare
and FileMode
incorrect.
This p / invoke declaration should suffice: http://www.pinvoke.net/default.aspx/kernel32.createfile
As Alexei said, don't name GetLastError
because you can choose an error code to call the structure rather than the true error. Use SetLastError = true
and Marshal.GetLastWin32Error()
.
You also cannot check for errors in the return value if CreateFile
.
source to share
Thanks to all the help I was able to achieve my goals using the following (FileAccess.ReadWrite translates to 0x3 and FILE_WRITE_ATTRIBUTES translates to 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());
}
}
}
source to share