2008-09-13 6 views
9

¿Es posible usar E/S superpuestas con una tubería anónima? CreatePipe() no tiene ninguna forma de especificar FILE_FLAG_OVERLAPPED, por lo que supongo que ReadFile() se bloqueará, incluso si proporciono una estructura OVERLAPPED.E/S superpuestas en una tubería anónima

Respuesta

15

No. Como se explica here, las tuberías anónimas no son compatibles con E/S asíncronas. Necesita usar un tubo con nombre. Hay un código de ejemplo para hacer esto en MSDN here y here.

+0

Desde [SetNamedPipeHandleState] (https://msdn.microsoft.com/en-us/library/windows/desktop /aa365787(v=vs.85).aspx) docs parece que IO no bloqueante debe ser compatible con las tuberías anónimas con indicador PIPE_NOWAIT. –

+0

@anatolytechtonik lamentablemente eso no es lo mismo que la E/S solapada. –

13

Aquí es una implementación de una función de canalización anónima con la posibilidad de especificar 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); 
} 
+0

¡Gracias! Eso es justo lo que necesitaba. –

+2

La implementación 'MyCreatePipeEx' de Dave Hart es excelente (esencialmente eliminada del código fuente' CreatePipe' de Windows), pero debe cambiar 'PipeSerialNumber ++' por 'InterlockedIncrement (& PipeSerialNumber)' en dicha implementación para evitar condiciones de carrera en el código MT. – vladr

+2

Guau, ese método es increíblemente trivial y genio :). En resumen: crea un par de canalizaciones con nombre (leer canalización con CreateNamedPipe y write pipe con WriteFile) con todas las opciones Superpuestas y devuelve sus identificadores. – Fr0sT

Cuestiones relacionadas