在Windows程序中查找打开的句柄

时间:2013-09-12 15:23:14

标签: c windows mingw

在Windows(MinGW)中,我的程序从调用进程继承了不需要的句柄。

这个过程不需要打开这些文件,但是因为它超出了父文件的生命周期,我会遇到文件被打开的常见问题。

在Linux上我解决了这个问题:

// Close all file descriptors
// It's hard to figure out how many are open, but the first 1000 should do
int fd;
for (fd = 0; fd < 1000; fd++)
  close (fd);

这在Windows中似乎不起作用。

如何确定哪些文件句柄已被继承?我怎么能关闭它们呢?

该项目使用MinGW和Windows的Unix兼容性API以C(无C ++)编写。

2 个答案:

答案 0 :(得分:1)

我现在已经对此进行了一些调查,我找到了解决实际问题的方法,但不是我想要的方法。

我原本以为我能够找到并清理任何不需要的打开文件,但事实证明这很难。我找到了一些不同的教程(herehere)如何执行此操作,但它们依赖于未记录的 API。我无法使这项技术发挥作用 - 可能是我做错了,或者可能在Windows Server 2012中更改了API - 但无论如何我不确定我是否想去那里; Sysinternals可以跟踪这些内容并保持Process Explorer正常工作,但我不希望我的项目有这样的维护负担。

我现在有两个选择:

  1. 在父(调用)进程中放入一些特殊的大小写代码,让它在适当的时候调用CreateProcess并禁用继承(它当前使用_spawnlp,因为它与Unix风格兼容管道和文件句柄,你不能非常可靠地使用CreateProcess

  2. 让进程立即使用CreateProcess调用自身,然后退出(或无限期等待)以杀死任何不需要的句柄。

  3. 第一种感觉更有效率。第二种是更灵活(它允许流程自己选择)。

    我想我会选择第一选项,因为对于我目前的需求,感觉就像是最差的。

答案 1 :(得分:-1)

首先是一些反向信息 - 为什么循环在Windows下不起作用:

在Linux中,句柄的数字为0 ... n。传递给“close()”的句柄和类似的函数直接传递给操作系统:

void close(int handle)
{
    syscall(SYS_CLOSE,handle);
}

但是在Windows中,操作系统使用自己的句柄,类似于指针地址,C库使用某种转换表:

void close(int handle)
{
    CloseHandle(table[handle]);
    table[handle]=NULL;
}

如果句柄保持打开状态,C库不知道(不是STDIN,STDOUT,STDERR),这些句柄将不在表中。

现在谈谈实际问题:

与Linux不同,Windows混合了不同类型的句柄(文件句柄,内存句柄,进程句柄......)。如果你能获得所有句柄的列表,你将不得不区别对待。

另一点是Windows库在内部使用一些句柄。如果您只是关闭父进程继承的所有句柄,您将冒着程序崩溃的风险,因为Windows库可能依赖于其中一些句柄。

因此,必须确保父应用程序确保没有句柄保持打开状态。默认情况下,Windows中不会继承句柄。但是,C库包装器(例如“fopen()”)将设置“继承句柄”标志,以便继承句柄。