2015-05-12 92 views
3

我想P/Invoke SetFileTime,但我似乎无法得到它的工作。它总是返回一个错误代码5(拒绝访问),我不知道为什么。这里是我使用的代码:SetFileTime返回错误代码5

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); 

我的指针是有效的(2376),但我看到SetFileTime已经失败,返回(拒绝访问)的错误代码5。现在,我确保我以管理员身份运行,并且我的帐户拥有该路径的权限,但仍然没有雪茄。任何人有任何想法,为什么发生这种情况?

更新

Marshal.GetLastWin32Error()还调用SetFileTime后返回5。另外,我需要使这个调用工作,以便我可以在Windows的长路径上运行SetFileTime,该路径支持CreateFile,但当前的.NET文件库不支持Windows中的长路径。

+0

@Alexandru你有没有想过做一个谷歌搜索上你试图“调用/调用SetFileTime”的方法 – MethodMan

+0

@MethodMan是的,我不会问我没有。我完全阅读了它的API文档。 – Alexandru

+0

还有更多的资源/例子超出'API' – MethodMan

回答

3

SetFileTime文档:

的句柄文件或目录。该句柄必须使用具有FILE_WRITE_ATTRIBUTES访问权限的CreateFile函数创建。

您的代码无法做到这一点。 .net FileAccess枚举与Win32访问标志不兼容。您需要定义一个专门用于CreateFile的枚举。同样,您使用FileShareFileMode也是不正确的。

此的P/Invoke声明应该足够了:http://www.pinvoke.net/default.aspx/kernel32.createfile


正如阿列克谢说,不要叫GetLastError,因为你可能是捡了一个错误代码框架调用,而不是真正的错误。使用SetLastError = trueMarshal.GetLastWin32Error()

如果是CreateFile,您也无法检查返回值中的错误。

1

感谢所有帮助,我能够使用以下(FileAccess.ReadWrite转化为0x3而FILE_WRITE_ATTRIBUTES是为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()); 
     } 
    } 
} 
+0

我不知道你为什么继续使用'FileShare'和'FileMode'。它们与FileAccess一样错误。 –

+0

'FileShare'或'FileMode'没有错。它们按照预期使用'CreateFile'工作。他们只是不包含整套可能的选项(这对我所需要的是过度的)。 – Alexandru

+0

我不相信他们是正确的。你检查过数字值了吗? –