2 * PROJECT: ReactOS Automatic Testing Utility
3 * LICENSE: GPL-2.0+ (https://spdx.org/licenses/GPL-2.0+)
4 * PURPOSE: Class that manages an unidirectional anonymous byte stream pipe
5 * COPYRIGHT: Copyright 2015 Thomas Faber (thomas.faber@reactos.org)
6 * Copyright 2019 Colin Finck (colin@reactos.org)
11 LONG
CPipe::m_lPipeCount
= 0;
15 * Constructs a CPipe object and initializes read and write handles.
19 SECURITY_ATTRIBUTES SecurityAttributes
;
21 SecurityAttributes
.nLength
= sizeof(SecurityAttributes
);
22 SecurityAttributes
.bInheritHandle
= TRUE
;
23 SecurityAttributes
.lpSecurityDescriptor
= NULL
;
25 // Construct a unique pipe name.
26 WCHAR wszPipeName
[MAX_PATH
];
27 InterlockedIncrement(&m_lPipeCount
);
28 swprintf(wszPipeName
, L
"\\\\.\\pipe\\TestmanPipe%ld", m_lPipeCount
);
30 // Create a named pipe with the default settings, but overlapped (asynchronous) operations.
31 // Latter feature is why we can't simply use CreatePipe.
32 const DWORD dwDefaultBufferSize
= 4096;
33 const DWORD dwDefaultTimeoutMilliseconds
= 120000;
35 m_hReadPipe
= CreateNamedPipeW(wszPipeName
,
36 PIPE_ACCESS_INBOUND
| FILE_FLAG_OVERLAPPED
,
37 PIPE_TYPE_BYTE
| PIPE_READMODE_BYTE
| PIPE_WAIT
,
41 dwDefaultTimeoutMilliseconds
,
43 if (m_hReadPipe
== INVALID_HANDLE_VALUE
)
45 FATAL("CreateNamedPipe failed\n");
48 // Use CreateFileW to get the write handle to the pipe.
49 // Writing is done synchronously, so no FILE_FLAG_OVERLAPPED here!
50 m_hWritePipe
= CreateFileW(wszPipeName
,
55 FILE_ATTRIBUTE_NORMAL
,
57 if (m_hWritePipe
== INVALID_HANDLE_VALUE
)
59 FATAL("CreateFileW failed\n");
62 // Prepare the OVERLAPPED structure for reading.
63 ZeroMemory(&m_ReadOverlapped
, sizeof(m_ReadOverlapped
));
64 m_ReadOverlapped
.hEvent
= CreateEventW(NULL
, TRUE
, TRUE
, NULL
);
65 if (!m_ReadOverlapped
.hEvent
)
67 FATAL("CreateEvent failed\n");
72 * Destructs a CPipe object and closes all open handles.
77 CloseHandle(m_hReadPipe
);
79 CloseHandle(m_hWritePipe
);
83 * Closes a CPipe's read pipe, leaving the write pipe unchanged.
86 CPipe::CloseReadPipe()
89 FATAL("Trying to close already closed read pipe\n");
90 CloseHandle(m_hReadPipe
);
95 * Closes a CPipe's write pipe, leaving the read pipe unchanged.
98 CPipe::CloseWritePipe()
101 FATAL("Trying to close already closed write pipe\n");
102 CloseHandle(m_hWritePipe
);
107 * Reads data from a pipe without advancing the read offset and/or retrieves information about available data.
109 * This function must not be called after CloseReadPipe.
112 * An optional buffer to read pipe data into.
115 * The size of the buffer specified in Buffer, or 0 if no read should be performed.
118 * On return, the number of bytes actually read from the pipe into Buffer.
120 * @param TotalBytesAvailable
121 * On return, the total number of bytes available to read from the pipe.
124 * True on success, false on failure; call GetLastError for error information.
129 CPipe::Peek(PVOID Buffer
, DWORD BufferSize
, PDWORD BytesRead
, PDWORD TotalBytesAvailable
)
132 FATAL("Trying to peek from a closed read pipe\n");
134 return PeekNamedPipe(m_hReadPipe
, Buffer
, BufferSize
, BytesRead
, TotalBytesAvailable
, NULL
);
138 * Reads data from the read pipe, advancing the read offset accordingly.
140 * This function must not be called after CloseReadPipe.
143 * Buffer to read pipe data into.
145 * @param NumberOfBytesToRead
146 * The number of bytes to read into Buffer.
148 * @param NumberOfBytesRead
149 * On return, the number of bytes actually read from the pipe into Buffer.
152 * Returns a Win32 error code. Expected error codes include:
153 * - ERROR_SUCCESS: The read has completed successfully.
154 * - WAIT_TIMEOUT: The given timeout has elapsed before any data was read.
155 * - ERROR_BROKEN_PIPE: The other end of the pipe has been closed.
160 CPipe::Read(PVOID Buffer
, DWORD NumberOfBytesToRead
, PDWORD NumberOfBytesRead
, DWORD TimeoutMilliseconds
)
164 FATAL("Trying to read from a closed read pipe\n");
167 if (ReadFile(m_hReadPipe
, Buffer
, NumberOfBytesToRead
, NumberOfBytesRead
, &m_ReadOverlapped
))
169 // The asynchronous read request could be satisfied immediately.
170 return ERROR_SUCCESS
;
173 DWORD dwLastError
= GetLastError();
174 if (dwLastError
== ERROR_IO_PENDING
)
176 // The asynchronous read request could not be satisfied immediately, so wait for it with the given timeout.
177 DWORD dwWaitResult
= WaitForSingleObject(m_ReadOverlapped
.hEvent
, TimeoutMilliseconds
);
178 if (dwWaitResult
== WAIT_OBJECT_0
)
180 // Fill NumberOfBytesRead.
181 if (GetOverlappedResult(m_hReadPipe
, &m_ReadOverlapped
, NumberOfBytesRead
, FALSE
))
183 // We successfully read NumberOfBytesRead bytes.
184 return ERROR_SUCCESS
;
187 dwLastError
= GetLastError();
188 if (dwLastError
== ERROR_BROKEN_PIPE
)
190 // The other end of the pipe has been closed.
191 return ERROR_BROKEN_PIPE
;
195 // An unexpected error.
196 FATAL("GetOverlappedResult failed\n");
201 // This may be WAIT_TIMEOUT or an unexpected error.
207 // This may be ERROR_BROKEN_PIPE or an unexpected error.
213 * Writes data to the write pipe.
215 * This function must not be called after CloseWritePipe.
218 * Buffer containing the data to write.
220 * @param NumberOfBytesToWrite
221 * The number of bytes to write to the pipe from Buffer.
223 * @param NumberOfBytesWritten
224 * On return, the number of bytes actually written to the pipe.
227 * True on success, false on failure; call GetLastError for error information.
232 CPipe::Write(LPCVOID Buffer
, DWORD NumberOfBytesToWrite
, PDWORD NumberOfBytesWritten
)
235 FATAL("Trying to write to a closed write pipe\n");
237 return WriteFile(m_hWritePipe
, Buffer
, NumberOfBytesToWrite
, NumberOfBytesWritten
, NULL
);