我正在为其他开发人员编写临时文件管理器。我想删除文件,即使我们的控制台应用程序崩溃或被“X”按钮关闭。
到目前为止,我找到了std::set_terminate
,std::atexit
和SetConsoleCtrlHandler
方法,我可以使用这些方法删除所需的所有临时文件。问题是 - 我无法删除打开的文件。此外 - 我无法控制这些文件的流,导致开发人员使用多个库(例如GDAL),这些库使用自己的流机制,并且只能接受目标文件路径。
如何强行关闭并删除当前应用程序打开的所有文件?
答案 0 :(得分:5)
您需要关闭当前进程拥有的文件句柄。要做到这一点:
NtQuerySystemInformation
API与未记录的SystemHandleInformation
参数一起使用。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持有的所有句柄 流程终止时的流程。