質問
匿名パイプでオーバーラップ I/O を使用することはできますか?CreatePipe() には FILE_FLAG_OVERLAPPED を指定する方法がないため、たとえ OVERLAPPED 構造体を指定したとしても ReadFile() はブロックされると思います。
解決
以下は、FILE_FLAG_OVERLAPPED を指定できる匿名パイプ関数の実装です。
/******************************************************************************\
* This is a part of the Microsoft Source Code Samples.
* Copyright 1995 - 1997 Microsoft Corporation.
* All rights reserved.
* This source code is only intended as a supplement to
* Microsoft Development Tools and/or WinHelp documentation.
* See these sources for detailed information regarding the
* Microsoft samples programs.
\******************************************************************************/
/*++
Copyright (c) 1997 Microsoft Corporation
Module Name:
pipeex.c
Abstract:
CreatePipe-like function that lets one or both handles be overlapped
Author:
Dave Hart Summer 1997
Revision History:
--*/
#include <windows.h>
#include <stdio.h>
ULONG PipeSerialNumber;
BOOL
APIENTRY
MyCreatePipeEx(
OUT LPHANDLE lpReadPipe,
OUT LPHANDLE lpWritePipe,
IN LPSECURITY_ATTRIBUTES lpPipeAttributes,
IN DWORD nSize,
DWORD dwReadMode,
DWORD dwWriteMode
)
/*++
Routine Description:
The CreatePipeEx API is used to create an anonymous pipe I/O device.
Unlike CreatePipe FILE_FLAG_OVERLAPPED may be specified for one or
both handles.
Two handles to the device are created. One handle is opened for
reading and the other is opened for writing. These handles may be
used in subsequent calls to ReadFile and WriteFile to transmit data
through the pipe.
Arguments:
lpReadPipe - Returns a handle to the read side of the pipe. Data
may be read from the pipe by specifying this handle value in a
subsequent call to ReadFile.
lpWritePipe - Returns a handle to the write side of the pipe. Data
may be written to the pipe by specifying this handle value in a
subsequent call to WriteFile.
lpPipeAttributes - An optional parameter that may be used to specify
the attributes of the new pipe. If the parameter is not
specified, then the pipe is created without a security
descriptor, and the resulting handles are not inherited on
process creation. Otherwise, the optional security attributes
are used on the pipe, and the inherit handles flag effects both
pipe handles.
nSize - Supplies the requested buffer size for the pipe. This is
only a suggestion and is used by the operating system to
calculate an appropriate buffering mechanism. A value of zero
indicates that the system is to choose the default buffering
scheme.
Return Value:
TRUE - The operation was successful.
FALSE/NULL - The operation failed. Extended error status is available
using GetLastError.
--*/
{
HANDLE ReadPipeHandle, WritePipeHandle;
DWORD dwError;
UCHAR PipeNameBuffer[ MAX_PATH ];
//
// Only one valid OpenMode flag - FILE_FLAG_OVERLAPPED
//
if ((dwReadMode | dwWriteMode) & (~FILE_FLAG_OVERLAPPED)) {
SetLastError(ERROR_INVALID_PARAMETER);
return FALSE;
}
//
// Set the default timeout to 120 seconds
//
if (nSize == 0) {
nSize = 4096;
}
sprintf( PipeNameBuffer,
"\\\\.\\Pipe\\RemoteExeAnon.%08x.%08x",
GetCurrentProcessId(),
PipeSerialNumber++
);
ReadPipeHandle = CreateNamedPipeA(
PipeNameBuffer,
PIPE_ACCESS_INBOUND | dwReadMode,
PIPE_TYPE_BYTE | PIPE_WAIT,
1, // Number of pipes
nSize, // Out buffer size
nSize, // In buffer size
120 * 1000, // Timeout in ms
lpPipeAttributes
);
if (! ReadPipeHandle) {
return FALSE;
}
WritePipeHandle = CreateFileA(
PipeNameBuffer,
GENERIC_WRITE,
0, // No sharing
lpPipeAttributes,
OPEN_EXISTING,
FILE_ATTRIBUTE_NORMAL | dwWriteMode,
NULL // Template file
);
if (INVALID_HANDLE_VALUE == WritePipeHandle) {
dwError = GetLastError();
CloseHandle( ReadPipeHandle );
SetLastError(dwError);
return FALSE;
}
*lpReadPipe = ReadPipeHandle;
*lpWritePipe = WritePipeHandle;
return( TRUE );
}
他のヒント
まず第一に理解する必要があります - とは何ですか 匿名パイプ そして、匿名と匿名の間には違いがあります 名前付きパイプ 全然。
本当に存在するだけ 単管タイプ (実装者 npfs.sys)。名前付きパイプと匿名パイプの間には、名前以外の違いはまったくありません。どちらも単なるパイプです。
いわゆる匿名パイプ - これは win7 より前の特殊/ランダムな名前付きパイプであり、本当の名前のないパイプは win7 から始まります。
msdnがそれを書くとき 「匿名パイプは一方通行パイプです」 - これは 嘘. 。他のパイプと同様に、一方向または二重にすることができます。msdnがそれを書くとき 「非同期 (オーバーラップ) 読み取りおよび書き込み操作は、匿名パイプではサポートされていません。」 - これは 嘘. 。もちろんパイプは非同期 IO をサポートします。パイプの名前はこれに影響しません。
win7 より前では、本当に名前のないパイプはまったく存在しませんでした。 CreatePipe
機能の使用 Win32Pipes.%08x.%08x
「匿名パイプ」の作成名の形式。
static LONG PipeSerialNumber;
WCHAR name[64];
swprintf(name, L"\\Device\\NamedPipe\\Win32Pipes.%08x.%08x",
GetCurrentProcessId(), InterlockedIncrement(&PipeSerialNumber));
win7から始める CreatePipe
パイプ ペアの作成には別の手法 (相対ファイル オープン) を使用します。これで、完全に匿名になります。
たとえば、一方のパイプが非同期で継承できないパイプ ペアを作成するコードです。別のパイプは同期性があり、継承可能です。両方のパイプは二重です (読み取りと書き込みの両方をサポート)
ULONG CreatePipeAnonymousPair7(PHANDLE phServerPipe, PHANDLE phClientPipe)
{
HANDLE hNamedPipe;
IO_STATUS_BLOCK iosb;
static UNICODE_STRING NamedPipe = RTL_CONSTANT_STRING(L"\\Device\\NamedPipe\\");
OBJECT_ATTRIBUTES oa = { sizeof(oa), 0, const_cast<PUNICODE_STRING>(&NamedPipe), OBJ_CASE_INSENSITIVE };
NTSTATUS status;
if (0 <= (status = NtOpenFile(&hNamedPipe, SYNCHRONIZE, &oa, &iosb, FILE_SHARE_VALID_FLAGS, 0)))
{
oa.RootDirectory = hNamedPipe;
static LARGE_INTEGER timeout = { 0, MINLONG };
static UNICODE_STRING empty = {};
oa.ObjectName = ∅
if (0 <= (status = ZwCreateNamedPipeFile(phServerPipe,
FILE_READ_ATTRIBUTES|FILE_READ_DATA|
FILE_WRITE_ATTRIBUTES|FILE_WRITE_DATA|
FILE_CREATE_PIPE_INSTANCE,
&oa, &iosb, FILE_SHARE_READ|FILE_SHARE_WRITE,
FILE_CREATE, 0, FILE_PIPE_BYTE_STREAM_TYPE, FILE_PIPE_BYTE_STREAM_MODE,
FILE_PIPE_QUEUE_OPERATION, 1, 0, 0, &timeout)))
{
oa.RootDirectory = *phServerPipe;
oa.Attributes = OBJ_CASE_INSENSITIVE|OBJ_INHERIT;
if (0 > (status = NtOpenFile(phClientPipe, SYNCHRONIZE|FILE_READ_ATTRIBUTES|FILE_READ_DATA|
FILE_WRITE_ATTRIBUTES|FILE_WRITE_DATA, &oa, &iosb,
FILE_SHARE_VALID_FLAGS, FILE_SYNCHRONOUS_IO_NONALERT)))
{
NtClose(oa.RootDirectory);
}
}
NtClose(hNamedPipe);
}
return RtlNtStatusToDosError(status);
}
ULONG CreatePipeAnonymousPair(PHANDLE phServerPipe, PHANDLE phClientPipe)
{
static char flag_supported = -1;
if (flag_supported < 0)
{
ULONG dwMajorVersion, dwMinorVersion;
RtlGetNtVersionNumbers(&dwMajorVersion, &dwMinorVersion, 0);
flag_supported = _WIN32_WINNT_WIN7 <= ((dwMajorVersion << 8)| dwMinorVersion);
}
if (flag_supported)
{
return CreatePipeAnonymousPair7(phServerPipe, phClientPipe);
}
static LONG PipeSerialNumber;
WCHAR name[64];
swprintf(name, L"\\\\?\\pipe\\Win32Pipes.%08x.%08x", GetCurrentProcessId(), InterlockedIncrement(&PipeSerialNumber));
HANDLE hClient, hServer = CreateNamedPipeW(name,
PIPE_ACCESS_DUPLEX|FILE_READ_DATA|FILE_WRITE_DATA|FILE_FLAG_OVERLAPPED,
PIPE_TYPE_BYTE|PIPE_READMODE_BYTE, 1, 0, 0, 0, 0);
if (hServer != INVALID_HANDLE_VALUE)
{
static SECURITY_ATTRIBUTES sa = { sizeof(sa), 0, TRUE };
hClient = CreateFileW(name, FILE_GENERIC_READ|FILE_GENERIC_WRITE,
FILE_SHARE_READ|FILE_SHARE_WRITE, &sa, OPEN_EXISTING, 0, 0);
if (hClient != INVALID_HANDLE_VALUE)
{
*phServerPipe = hServer, *phClientPipe = hClient;
return NOERROR;
}
CloseHandle(hServer);
}
return GetLastError();
}