在Windows上强制关闭文件的路径

时间:2014-08-21 12:41:30

标签: c++ winapi temporary-files

我正在为其他开发人员编写临时文件管理器。我想删除文件,即使我们的控制台应用程序崩溃或被“X”按钮关闭。

到目前为止,我找到了std::set_terminatestd::atexitSetConsoleCtrlHandler方法,我可以使用这些方法删除所需的所有临时文件。问题是 - 我无法删除打开的文件。此外 - 我无法控制这些文件的流,导致开发人员使用多个库(例如GDAL),这些库使用自己的流机制,并且只能接受目标文件路径。

如何强行关闭并删除当前应用程序打开的所有文件?

2 个答案:

答案 0 :(得分:5)

您需要关闭当前进程拥有的文件句柄。要做到这一点:

  • NtQuerySystemInformation API与未记录的SystemHandleInformation参数一起使用。
  • 这将为您提供系统中打开的所有句柄的数组
  • 遍历数组并仅选择与进程PID匹配的数组,并且是文件句柄
  • 然后,您可以使用GetFinalPathNameByHandle进一步缩小范围,以获取已打开文件的路径,例如您可以选择特定文件名或名称中包含tmp的所有文件。
  • 对于您要删除的任何文件,请拨打CloseHandle()以强制关闭句柄,当然还要在路径上DeleteFile()

一些代码(没有任何错误检查):

SYSTEM_HANDLE_INFORMATION* pInfo=NULL;
DWORD dwSize=0;
NTSTATUS status=0;

do
{
  // keep reallocing until buffer is big enough
  status = NtQuerySystemInformation(SystemHandleInformation, pInfo, dwSize, &dwSize);
  if (status==STATUS_INFO_LENGTH_MISMATCH)
     pInfo = (SYSTEM_HANDLE_INFORMATION*)realloc(pInfo, dwSize);
} while(status!=0);

// iterate over every handle
for (DWORD i=0; i<pInfo->dwCount; i++)
{
  if (pInfo->handles[i].ProcessID==GetCurrentProcessId() && pInfo->handles[i].HandleType==28)
  {
     TCHAR szPath[MAX_PATH];
     GetFinalPathNameByHandle((HANDLE)pInfo->handles[i].HandleNumber, szPath, MAX_PATH, 0);
     if (_tcsstr(szFilePath, L"filename_I_want_to_delete"))
     {
       CloseHandle((HANDLE)pInfo->handles[i].HandleNumber);
       DeleteFile(szPath);
     }
  }
}

这假设您需要删除的所有文件都由执行删除的进程拥有。如果任何文件属于另一个进程,则需要使用带有DuplicateHandle()选项的DUPLICATE_CLOSE_SOURCE进行额外步骤。假设您具有合适的权限,则会为您提供句柄,然后您可以像以前一样关闭并删除该文件。

有一些很好的示例代码here

答案 1 :(得分:3)

毕竟我决定使用IInspectable的解决方案,他在评论中发帖。只需将其作为答案发布,我就可以将其标记为

  

编写一个执行所有清理的启动器应用程序。该   启动程序在进程上调用CreateProcess和WaitForSingleObject   处理。无论过程如何,都会发出进程句柄的信号   终止(干净关机,崩溃等)。你不必担心   关于强制关闭文件 - 操作系统关闭a持有的所有句柄   流程终止时的流程。