现在,我在 Windows 中的大部分日常编程工作都是围绕各种 I/O 操作(管道、控制台、文件、套接字……)。我很清楚从不同类型的句柄读取和写入的不同方法(同步、异步等待事件完成、等待文件句柄、I/O 完成端口和可警报 I/O)。我们使用其中的许多。

对于我们的某些应用程序来说,只有一种方法来处理所有句柄将非常有用。我的意思是,程序可能不知道它收到了什么样的句柄,而我们想使用所有的 I/O 完成端口。

所以首先我会问:

假设我有一个句柄:

HANDLE h;

我的 I/O 进程已从某处接收到它。有没有简单可靠的方法来找出它是用什么标志创建的?有问题的主要标志是 FILE_FLAG_OVERLAPPED.

到目前为止我知道的唯一方法是尝试将此类句柄注册到 I/O 完成端口(使用 CreateIoCompletionPort())。如果成功,则已使用 FILE_FLAG_OVERLAPPED 创建句柄。但这样就只能使用 I/O 完成端口,因为在不关闭该端口的情况下无法从该端口注销句柄。 HANDLE h 本身。

提供一种简单的方法来确定是否存在 FILE_FLAG_OVERLAPPED, ,我的第二个问题就来了:

有什么方法可以将这样的标志添加到已经存在的句柄中吗?这将使最初为同步操作打开的句柄变为为异步操作打开。有没有办法创建相反的(删除 FILE_FLAG_OVERLAPPED 从异步创建同步句柄)?

在阅读了 MSDN 并谷歌搜索了很多之后,我还没有找到任何直接的方法。至少有一些技巧可以达到同样的效果吗?就像使用相同的方式重新创建句柄一样 CreateFile() 功能或类似的东西?甚至部分记录或根本没有记录的东西?

我需要这个的主要地方是确定进程应该从第三方应用程序发送给它的句柄中读取/写入的方式(或更改方式)。我们无法控制第三方产品如何创建其句柄。

亲爱的 Windows 专家:请帮助!

带着敬意

马丁

有帮助吗?

解决方案 2

3年过去了,Windows 8中已被释放。由于在Windows 8中实现控制台的引入回归我必须做些什么从而引发这个问题的问题。于是,我终于尝试使用ReOpenFile()函数调用。

在一个句子:我的目的是没用

在ReOpenFile()API是用于“服用现有的文件句柄和获得具有不同的一组访问权限的另一手柄”。至少是在href="http://msdn.microsoft.com/en-us/magazine/cc300448.aspx" rel="nofollow">原始文章的

我试图使用的ReOpenFile()有关控制台输入句柄:

  stdin_in = GetStdHandle(STD_INPUT_HANDLE);
  stdin_in_operlapped = ReOpenFile(stdin_in, GENERIC_READ | GENERIC_WRITE,
                                   FILE_SHARE_READ, FILE_FLAG_OVERLAPPED);
  if (stdin_in_operlapped ==  INVALID_HANDLE_VALUE)
    {
      my_debug("failed to ReOpen stdin handle with OVERLAPPED flag: %d", GetLastError());
      exit(1);
    }

和我所得到的是:错误1168:“找不到元素”。 “谢谢你微软”。我甚至不会尝试使用它的匿名管道,因为该文件规定:

“异步(重叠)读取和写入操作不被匿名管道支撑。这意味着你不能用匿名管道使用ReadFileEx和WriteFileEx功能。此外,当这些功能与匿名管道使用的ReadFile和WriteFile的lpOverlapped参数被忽略。”

感谢你,人民,一切为了您的建议。从手柄异步读取时,一个人必须准备好还的事实,操作可以同步完成。这我知道。我提出这个问题的主要原因是:

当一个同步读取已经对某些对象(至少匿名管道,并在Windows 8控制台输入)发出然后从在相同手柄将或者失败,或挂起另一线程调用CloseHandle的(),直到ReadFile的()完成;这意味着它会在许多情况下无限期挂起。这就是为什么我想与异步更换同步处理的原因。

现在很清楚,我认为这是根本不可能在Windows操作系统中,以取消直接的方式有些读操作。从同步手柄读取时,一个只是有从应用程序退出,即使ReadFile的()在某些线程从手柄还在读书,因为这是根本不可能可靠地醒来这样的读操作。在知道......在新的操作系统,可以取消该操作。但是,有没有办法知道天气线程处于ReadFile的()调用已经,或者还没有。如果ReadFile的()还没有叫那么有没有操作取消和后续读取将挂起。唯一的办法是关闭句柄,但操作挂起,或失败的一些对象,并在一些操作系统。这个唯一的妥善解决是异步I / O。但是,正如我在开头提到的,我们的应用程序是由第三方应用程序开始,我们不能强迫他们都始终创建与标准输入输出重叠标志设置命名管道。

我放弃了,并要实现肮脏丑陋的黑客......我们将不得不继续没有重复的结构从阅读已经重叠的标志创建把手,把手泄漏和线程....

其他提示

我发现我对 MSDN 的阅读能力很差:/我完全错过了功能 ReOpenFile() 它可能早在 2003 年 6 月就已在 Windows Server 2003 中引入(根据 本文)。至少为自己辩护一下:我希望 CreateFile() 交叉引用的描述 ReOpenFile() 描述。有一个参考 ReOpenFile() 页至 CreateFile() 页,但反之则不然。

这个功能似乎正是我所需要的:添加或删除 FILE_FLAG_OVELRAPPED 通过创建具有所需属性的新句柄到/从现有句柄!:-D 不过,我还没有测试过。遗憾的是,它仅适用于 Windows 2003 Server、Windows Vista 及更高版本。有关以前操作系统版本的问题已得到解答 这里. 。Windows 2003 Server 之前的操作系统中,公共 API 中不存在该函数。它由底层实现使用,但这些系统上的开发人员无法使用它(不支持)。

这实际上意味着至少在接下来的几年里我没有希望,除非我们放弃对旧版 Windows 平台的支持。这也意味着在 Windows Vista 之前的操作系统上,I/O 的情况非常糟糕。完全缺失的另一个令人痛苦的部分是取消那些旧系统上的同步和异步 I/O 的可能性。

此外,我仍然错过了答案的一部分:可以通过任何方式测试标志的存在吗?我还没有找到这样做的功能。这意味着,如果我们想保证文件对象中存在某些标志,则始终必须重新打开该文件。

如果我理解你以后,我想建议,如果有重叠标志被打开与否你不在乎。我相信,你可以在OVERLAPPED结构安全通过在两个同步和异步的情况。你的代码需要能够处理ReadFile()返回falseGetLastError()返回ERROR_IO_PENDING。您还需要适当的调用添加到GetOverlappedResult()WaitForSingleObject()等。

ReadFile() MSDN文章对这个下一些好的信息“注意事项与同步文件句柄的工作”,并“为异步文件句柄工作注意事项”“同步和文件位置”部分。

测试手柄标志可能应该做的方式为测试手柄与创建的权限相同。 试试吧。如果API失败,请尝试回退。如果失败,则返回一个错误。

我觉得真的讲的事是ReadFile的文档说的方式:“如果HFILE打开与FILE_FLAG_OVERLAPPED,...功能可能错误地报告说,读操作就完成了。”

我错误的解释是,(你需要问自己的问题是):如果有可能要检查的文件句柄的重叠状态,为什么会READFILE那么做检查,然后相应地验证重叠结构如果调用,以非重叠的方式与一个重叠手柄明确失败?

我不知道一种方法来确定一个手柄,并使用重新打开API的副作用的标志,但因为你的目标是

  

这将是非常有用的,只有一个方式来对待所有句柄

如果你希望同步行为(我的意思是使用同步API的非重叠的把手和喂养与上重叠的事件之后等待OVERLAPPED结构异步API)您可以随时使用异步API也如果手柄在非重叠的模式打开如已经由@Brett结果,表示 我可以证实,这个工程(至少对于命名管道)ES:点击

void connectSynchronous(HANDLE hPipeThatWeDontKnowItsFlag){
    ...
    BOOL bRet = ::ConnectNamedPipe(hPipeThatWeDontKnowItsFlag, pOverlapped);

    if(bRet == FALSE){
        DWORD dwLastErr = ::GetLastError();

        if(dwLastErr == ERROR_IO_PENDING){
            //The handle was opened for asynchronous IO so we have to wait for the operation
            ...waitFor on the overlapped hEvent;

        }else if(dwLastErr == ERROR_PIPE_CONNECTED){
            //The handle was opened for synchronous IO and the client was already connected before this call: that's OK!
            return;
        }else{
            throw Error(dwLastErr);
        }
    }/*else{
        //The handle was opened for synchronous IO and the client has connected: all OK
    }*/
}

到CreateIoCompletionPort劈一个替代方法是做一个零字节的ReadFile用NULL lpOverlapped的。如果它失败ERROR_INVALID_PARAMETER假定其用FILE_FLAG_OVERLAPPED打开。

许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top