C++/Win32:如何等待挂起的删除完成

2024-01-12

Solved:

  • 可行的解决方案:履行机构的答复 https://stackoverflow.com/questions/3764072/c-win32-how-to-wait-for-a-pending-delete-to-complete/3764298#3764298
  • 对实际发生情况的解释:汉斯的回答 https://stackoverflow.com/questions/3764072/c-win32-how-to-wait-for-a-pending-delete-to-complete/3764322#3764322
  • 为什么OpenFile没有通过“DELETE PENDING”的解释:本杰明的回答 https://stackoverflow.com/questions/3764072/c-win32-how-to-wait-for-a-pending-delete-to-complete/3776438#3776438

问题:

我们的软件在很大程度上是专有脚本语言的解释器引擎。该脚本语言能够创建文件、处理文件,然后删除文件。这些都是单独的操作,并且在这些操作之间没有文件句柄保持打开状态。

(即在文件创建期间,创建一个句柄,用于写入,然后关闭。在文件处理部分期间,一个单独的文件句柄打开文件,从中读取文件,并在 EOF 处关闭。并且finally,删除使用::DeleteFile,它只使用文件名,根本不使用文件句柄)。

最近我们开始意识到,特定的宏(脚本)有时无法在随后的某个随机时间创建文件(即,它在“创建、处理、删除”的前一百次迭代期间成功,但是当它出现时)回到创建它一百零一次,Windows 回复“访问被拒绝”)。

更深入地研究这个问题,我编写了一个非常简单的程序,它循环如下所示:

while (true) {
    HANDLE hFile = CreateFileA(pszFilename, FILE_ALL_ACCESS, FILE_SHARE_READ,
                               NULL, CREATE_NEW, FILE_ATTRIBUTE_NORMAL, NULL);
    if (hFile == INVALID_HANDLE_VALUE)
        return OpenFailed;

    const DWORD dwWrite = strlen(pszFilename);
    DWORD dwWritten;

    if (!WriteFile(hFile, pszFilename, dwWrite, &dwWritten, NULL) || dwWritten != dwWrite)
        return WriteFailed;

    if (!CloseHandle(hFile))
        return CloseFailed;

    if (!DeleteFileA(pszFilename))
        return DeleteFailed;
}

正如您所看到的,这是直接针对 Win32 API 的,并且非常简单。我创建一个文件,写入它,关闭句柄,删除它,冲洗,重复......

但在某个地方,我会在 CreateFile() 调用期间收到 Access Denied (5) 错误。查看 sysinternal 的 ProcessMonitor,我可以看到根本问题是当我尝试再次创建文件时,该文件上有一个待删除的文件。

问题:

  • 有没有办法等待删除完成?
  • 有没有办法检测文件是否正在等待删除?

我们尝试了第一个选项,即在 HFILE 上简单地使用 WaitForSingleObject()。但 HFILE 始终在 WaitForSingleObject 执行之前关闭,因此 WaitForSingleObject 始终返回 WAIT_FAILED。显然,尝试等待关闭句柄是行不通的。

我可以等待该文件所在文件夹的更改通知。但是,对于偶尔出现问题的问题来说,这似乎是一种极其耗费资源的混乱(也就是说:在我的 Windows 7 x64 E6600 PC 上进行的测试中,通常会出现问题)在迭代 12000+ 时失败——在其他机器上,它可能会在迭代 7、15 或 56 时发生,或者永远不会发生)。

我无法辨别任何明确允许这种以太的 CreateFile() 参数。无论 CreateFile 有什么参数,打开文件确实是不行的any当文件待删除时访问。

由于我可以在 Windows XP 机器和 x64 Windows 7 机器上看到此行为,因此我非常确定这是 Microsoft “按照预期”的核心 NTFS 行为。因此,我需要一个解决方案,允许操作系统在我尝试继续之前完成删除,最好不要不必要地占用 CPU 周期,并且不会产生监视该文件所在文件夹的巨大开销(如果可能)。

1 https://stackoverflow.com/questions/3764072/c-win32-how-to-wait-for-a-pending-delete-to-complete/3764298#3764298是的,此循环在写入失败或关闭泄漏失败时返回,但由于这是一个简单的控制台测试应用程序,因此应用程序本身会退出,并且 Windows 保证在进程完成时操作系统会关闭所有句柄。所以这里不存在泄漏。

bool DeleteFileNowA(const char * pszFilename)
{
    // Determine the path in which to store the temp filename
    char szPath[MAX_PATH];
    strcpy(szPath, pszFilename);
    PathRemoveFileSpecA(szPath);

    // Generate a guaranteed to be unique temporary filename to house the pending delete
    char szTempName[MAX_PATH];
    if (!GetTempFileNameA(szPath, ".xX", 0, szTempName))
        return false;

    // Move the real file to the dummy filename
    if (!MoveFileExA(pszFilename, szTempName, MOVEFILE_REPLACE_EXISTING))
        return false;

    // Queue the deletion (the OS will delete it when all handles (ours or other processes) close)
    if (!DeleteFileA(szTempName))
        return false;

    return true;
}

Windows 中还有其他进程需要该文件的一部分。搜索索引器是一个明显的候选者。或者病毒扫描程序。他们将打开文件以进行完全共享,包括 FILE_SHARE_DELETE,以便其他进程不会受到他们打开文件的严重影响。

这通常效果很好,除非您以很高的速度创建/写入/删除。删除将成功,但文件无法从文件系统中消失,直到该文件的最后一个句柄关闭为止。例如,搜索索引器所持有的句柄。任何尝试打开该待删除文件的程序都将被错误 5 捕获。

否则,这是多任务操作系统上的一个常见问题,您无法知道哪些其他进程可能想要弄乱您的文件。您的使用模式似乎不寻常,请先检查一下。解决方法是捕获错误、睡眠并重试。或者使用 SHFileOperation() 将文件移动到回收站。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

C++/Win32:如何等待挂起的删除完成 的相关文章

  • nUnit Assert.That委托并发问题

    我的代码中遇到了一些暂时的死锁 无法解决它 简单的代码 我无法创建一个简单的调用链来重现代码InvokeChangeEvent Test public async void Test sut InvokeChangeEvent foo fi
  • Active Directory:获取用户所属的组

    我想找到用户所属的组列表 我尝试了几种解决方案http www codeproject com KB system everythingInAD aspx http www codeproject com KB system everyth
  • C++11 类型推导与 const char *

    In GotW 94 http herbsutter com 2013 08 12 gotw 94 solution aaa style almost always auto Herb Sutter 对 经典 C 声明进行了区分 const
  • flock():在没有竞争条件的情况下删除锁定的文件?

    我使用flock 来实现进程间命名互斥 即某个进程可以决定锁定 some name 这是通过锁定临时目录中名为 some name 的文件来实现的 lockfile tmp some name lock fd open lockfile O
  • Windows 上任何单个进程可以寻址的最大内存量

    Windows 版本的内存限制 http msdn microsoft com en us library windows desktop aa366778 28v vs 85 29 aspx回答 Windows 上任何单个进程可以寻址的最
  • 如何使用C#检测IIS版本?

    如何使用C 检测IIS版本 更新 我的意思是来自 winapp 实际上该场景是开发一个自定义安装程序 想要检查已安装 IIS 的版本以调用适当的 api 在这里找到了答案 链接文本 http forums iis net p 1162404
  • Oracle ODP.Net 与实体框架 6 - 从表视图中选择时出现 ORA-00955

    我创建了两个应用程序 第一个使用 ODP Net 另一个没有实体 效果很好 static void Main string args OracleConnection con new OracleConnection using conne
  • 同步和异步 API

    我正在开发一个库 它提供一些耗时的服务 我需要每个 API 有两个版本 一个用于同步函数调用 另一个用于异步 图书馆用户应决定使用哪个版本 服务结果可能对于系统继续运行 同步调用 至关重要 可能需要在不同的工作线程中完成相同的操作 因为结果
  • 如何查看某个函数以 3 秒的间隔被调用了多少次?

    我想检查我的函数在 3 秒内可以运行多少次 我写了这段代码 include
  • 使用箭头键滚动可滚动控件

    我正在使用一个ScrollableControl在我的 C 项目中 我想知道如何将箭头键映射到垂直 水平滚动 编辑 我的图片框获得焦点 并且我设法映射滚动键 这里的问题是 当我按下箭头键时 它会滚动一次 然后失去焦点 将其交给滚动查看器旁边
  • 为什么不能使用 C# 对象初始值设定项语法调用方法? [关闭]

    就目前情况而言 这个问题不太适合我们的问答形式 我们希望答案得到事实 参考资料或专业知识的支持 但这个问题可能会引发辩论 争论 民意调查或扩展讨论 如果您觉得这个问题可以改进并可能重新开放 访问帮助中心 help reopen questi
  • 重复取消引用多个指针,效率较低?

    而不是写 string name first gt next gt next gt next gt name int age first gt next gt next gt next gt age 将其写为 node billy bloc
  • C++ 标准是否保证未使用的私有字段会影响 sizeof?

    考虑以下结构 class Foo int a 在 g 中测试 我明白了sizeof Foo 4但这是由标准保证的吗 是否允许编译器注意到a是一个未使用的私有字段并将其从类的内存表示中删除 导致更小的 sizeof 我不希望任何编译器真正进行
  • 如何在 .NET Core 中设置全局环境变量(用户范围或系统范围)

    在完整的 NET中我们可以通过EnvironmentVariableTarget枚举到Environment SetEnvironmentVariable call public enum EnvironmentVariableTarget
  • 以编程方式将 Word 文件另存为图片

    我想将Word文档的第一页另存为图片 使用 C 有什么方法可以做到这一点 您可以将 Word 文档打印到 XPS 文档 在 WPF Net 3 5 应用程序中打开它 并使用 WPF 框架的文档和图像功能将第一个内部固定页面对象转换为位图 如
  • 在 C# 中同步闪烁标签

    我创建了一个BlinkingLabel类 源自Forms Label 其中有一个Forms Timer这允许我启用和禁用闪烁效果 我创建了 4 个标签BlinkingLabel类型 我的问题是 如果所有 4 个标签在不同时间闪烁 则闪烁效果
  • 显示具有相同节点值的多个 XML 数据条目

    我有一个 XML 文档 其中包含课程信息 如下所示
  • AZURE:workerrole 中的异步 Run()

    我有一个异步任务 async Task UploadFiles 我想在 azure 工作者角色的 Run 方法中调用 UploadFiles 上的 等待 但 await 仅适用于声明为异步的方法 那么我可以使 Run 方法异步 如下所示 p
  • Qt 对象的生命周期

    Qt 对象的生命周期是多少 Such as QTcpSocket socket new QTcpSocket 套接字什么时候会被销毁 我应该使用 delete socket 有什么区别吗 QTcpSocket socket 我找不到有关此的
  • SQL 注入在 winform 中有效吗?

    我正在用 C 制作一个 Windows 软件 我读过关于sql injection但我没有发现它适用于我的应用程序 SQL 注入在 winform 中有效吗 如果是的话如何预防 EDIT 我正在使用文本框来读取用户名和密码 通过使用 tex

随机推荐