2015-05-12 117 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

我不相信他們是正確的。你檢查過數字值了嗎? –