Winapi 是否可以将为同步I/O打开的句柄在其生存期内更改为为为异步I/O打开的句柄?

Winapi 是否可以将为同步I/O打开的句柄在其生存期内更改为为为异步I/O打开的句柄?,winapi,asynchronous,synchronous,createfile,overlapped-io,Winapi,Asynchronous,Synchronous,Createfile,Overlapped Io,现在,我在Windows中的大部分日常编程工作都是围绕各种I/O操作(管道、控制台、文件、套接字等)进行的。我非常了解从不同类型的句柄(同步、异步等待事件完成、等待文件句柄、I/O完成端口和警报I/O)读写的不同方法。我们使用其中的许多 对于我们的一些应用程序,只有一种方法来处理所有句柄是非常有用的。我的意思是,程序可能不知道它收到了什么样的句柄,我们想使用,比如说,所有的I/O完成端口 首先我想问: 假设我有一个手柄: HANDLE h; 我的进程从某处接收到的I/O。有没有什么简单可靠的方

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

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

首先我想问:

假设我有一个手柄:

HANDLE h;
我的进程从某处接收到的I/O。有没有什么简单可靠的方法来找出它是用什么标志创建的?所讨论的主要标志是
文件\u标志\u重叠

到目前为止,我知道的唯一方法是尝试将此类句柄注册到I/O完成端口(使用
CreateIoCompletionPort()
)。如果该操作成功,则已创建句柄,且文件\u标志\u重叠。但是,必须只使用I/O完成端口,因为如果不关闭
句柄
h
本身,就无法从中注销句柄

如果有一种简单的方法来确定是否存在重叠的
文件\u FLAG\u
,那么我的第二个问题就来了:

有没有办法将这样的标志添加到已经存在的句柄中?这将使原本为同步操作打开的句柄为异步操作打开。是否有一种方法可以创建反向(删除
文件\u标志\u重叠
以从异步创建同步句柄)

我没有找到任何直接的方法后,通过阅读MSDN和谷歌搜索了很多。至少会有一些技巧可以做到这一点吗?类似于使用
CreateFile()
函数或类似的方法重新创建句柄吗?甚至部分记录或根本没有记录

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

亲爱的Windows大师:请帮帮我

关于


Martin

测试句柄标志的方法可能与测试创建句柄时使用的权限的方法相同。 试试看。如果API失败,请尝试回退。如果失败,则返回一个错误

我认为真正能说明问题的是ReadFile的文档所说的“如果在打开hFile时文件重叠,…函数可能会错误地报告读取操作已完成。”


我对错误的解释是,(您需要问自己的问题是):如果可以检查文件句柄的重叠状态,为什么ReadFile不进行该检查,然后相应地验证重叠结构,如果使用重叠句柄以非重叠方式调用,则显式失败?

我看我对MSDN的理解不好:/I完全错过了可能早在2003年6月在Windows Server 2003中引入的函数(根据)。至少为自己辩护一点:我希望
CreateFile()
描述能够交叉引用
rebootfile()
描述。在
rebootfile()
页面上有一个到
CreateFile()
页面的引用,但不是相反

此函数似乎正好支持我所需的功能:通过创建具有所需属性的新句柄,向现有句柄添加或删除
文件\u FLAG\u ovelapped
:-我还没有测试过。不幸的是,它仅在Windows 2003 Server、Windows Vista及更高版本上可用。关于先前操作系统版本的问题已经得到了回答。Windows 2003 Server之前的操作系统中的公用API中不存在此函数。它由底层实现使用,但这些系统上的开发人员无法使用(不受支持)

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


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

如果我理解您的意图,我想建议您不要介意是否使用重叠标志打开文件。我相信在同步和异步情况下,您都可以安全地传递一个重叠的
结构。您的代码需要能够处理
ReadFile()
返回的
false
GetLastError()
返回的
ERROR\u IO\u PENDING
。您还需要添加对
GetOverlappedResult()
WaitForSingleObject()
等的适当调用


ReadFile()
上的MSDN文章在“使用同步文件句柄的注意事项”和“同步和文件位置”中的“使用异步文件句柄的注意事项”中提供了一些关于这方面的好信息部分。

我不知道如何确定句柄的标志以及使用重新打开api的副作用,但是因为您的目标是

只有一种方法可以处理所有句柄,这将非常有用

如果您希望同步行为(我的意思是使用同步api进行非结束
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
    }*/
}
  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);
    }