C# SetFileTime返回错误代码5
我正在尝试p/调用SetFileTime,但似乎无法使其工作。它总是为我返回一个错误代码5(拒绝访问),我不知道为什么。以下是我正在使用的代码:C# SetFileTime返回错误代码5,c#,file,io,pinvoke,kernel32,C#,File,Io,Pinvoke,Kernel32,我正在尝试p/调用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, FileAttri
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中的长路径。来自SetFileTime
的文档:
文件或目录的句柄。句柄必须是使用具有文件写入属性访问权限的CreateFile函数创建的
您的代码无法做到这一点。.net文件访问
枚举与Win32访问标志不兼容。您需要定义一个专门用于CreateFile
的枚举。同样,您使用的FileShare
和FileMode
也不正确
此p/invoke声明应足以:
正如Alexei所说,不要调用
GetLastError
,因为您可能在为框架调用提取错误代码,而不是真正的错误。使用SetLastError=true
和Marshal.GetLastWin32Error()
如果
CreateFile
,也无法检查返回值中的错误 多亏了所有的帮助,我能够通过以下方式实现我的目标(FileAccess.ReadWrite转换为0x3,而FILE_WRITE_属性为0x100):
@Alexandru你有没有想过在谷歌上搜索你试图调用SetFileTime的方法。我已经完全阅读了它的API文档。除了
API
之外,还有更多的资源/示例。有没有理由忽略.net framework方法来实现这一点?@DavidHeffernan有没有.net framework方法来实现这一点?我可以使用Reflector查看源代码。我不知道您为什么继续使用FileShare
和FileMode
。它们与FileAccess
FileShare
或FileMode
一样错误。它们与CreateFile
一起工作。它们只是没有包含所有可能的选项(对于我所需要的来说,这些选项太过分了),我不相信它们是正确的。你检查过数值了吗?@DavidHeffernan我没有,但我知道,通过我自己的实验(我在CreateFile方面做了很多工作),它们可以达到预期的目的。如果您不相信我,您可以看到使用它们的不仅仅是我,因为在调用CreateFile()时还有各种其他方法签名使用它们。我不认为有那么多人会像这样P/Invoke,如果它对他们不起作用的话。但是,最重要的是,请记住这些是位标志,其中最重要的是标志包含它们所需的位。不,我在回答中提到的pinvoke.net签名使用适当的位标志定义枚举。恰好FileShare
匹配。大概这是故意的,我怀疑这些价值观是否会改变FileMode
有一个额外的值FileMode.Append
,该值CreateFile
无法理解<代码>文件模式是真正的枚举,而不是位标志。在我看来,你应该停止滥用这些类型,并按照pinvoke.net显示的方式来做。那么,为什么他们在这里建议在顶部部分使用.net文件访问?@IronHide抱歉,我不理解你的问题我是在链接下引用这段代码的[DllImport(“kernel32.dll”,CharSet=CharSet.Auto,SetLastError=true)]公共静态外部IntPtr CreateFile([Marshallas(UnmanagedType.LPTStr)]字符串文件名,[Marshallas(UnmanagedType.U4)]FileAccess访问,
这里是.netFileAccess@IronHide好吧,我觉得这是错的。FileAccess
的序号与GENERIC\u READ
和GENERIC\u WRITE
不匹配。更深奥的标志根本不存在。
[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());
}
}
}