using System;
using System.Runtime.InteropServices;
using System.Text;
using System.Threading;

namespace Vanara.PInvoke
{
	public static partial class Kernel32
	{
		/// <summary>Does not wait for the named pipe. If the named pipe is not available, the function returns an error.</summary>
		public const uint NMPWAIT_NOWAIT = 0x00000001;

		/// <summary>The time-out interval is the default value specified by the server process in the CreateNamedPipe function.</summary>
		public const uint NMPWAIT_USE_DEFAULT_WAIT = 0x00000000;

		/// <summary>The function does not return until an instance of the named pipe is available.</summary>
		public const uint NMPWAIT_WAIT_FOREVER = 0xffffffff;

		/// <summary>Values that can be used in the dwOpenMode parameter of <see cref="CreateNamedPipe"/>.</summary>
		[Flags]
		public enum PIPE_ACCESS : uint
		{
			/// <summary>
			/// The pipe is bi-directional; both server and client processes can read from and write to the pipe. This mode gives the server
			/// the equivalent of GENERIC_READ and GENERIC_WRITE access to the pipe. The client can specify GENERIC_READ or GENERIC_WRITE, or
			/// both, when it connects to the pipe using the CreateFile function.
			/// </summary>
			PIPE_ACCESS_DUPLEX = 0x00000003,

			/// <summary>
			/// The flow of data in the pipe goes from client to server only. This mode gives the server the equivalent of GENERIC_READ
			/// access to the pipe. The client must specify GENERIC_WRITE access when connecting to the pipe. If the client must read pipe
			/// settings by calling the GetNamedPipeInfo or GetNamedPipeHandleState functions, the client must specify GENERIC_WRITE and
			/// FILE_READ_ATTRIBUTES access when connecting to the pipe.
			/// </summary>
			PIPE_ACCESS_INBOUND = 0x00000001,

			/// <summary>
			/// The flow of data in the pipe goes from server to client only. This mode gives the server the equivalent of GENERIC_WRITE
			/// access to the pipe. The client must specify GENERIC_READ access when connecting to the pipe. If the client must change pipe
			/// settings by calling the SetNamedPipeHandleState function, the client must specify GENERIC_READ and FILE_WRITE_ATTRIBUTES
			/// access when connecting to the pipe.
			/// </summary>
			PIPE_ACCESS_OUTBOUND = 0x00000002,

			/// <summary>
			/// If you attempt to create multiple instances of a pipe with this flag, creation of the first instance succeeds, but creation
			/// of the next instance fails with ERROR_ACCESS_DENIED.
			/// </summary>
			FILE_FLAG_FIRST_PIPE_INSTANCE = 0x00080000,

			/// <summary>
			/// Write-through mode is enabled. This mode affects only write operations on byte-type pipes and, then, only when the client and
			/// server processes are on different computers. If this mode is enabled, functions writing to a named pipe do not return until
			/// the data written is transmitted across the network and is in the pipe's buffer on the remote computer. If this mode is not
			/// enabled, the system enhances the efficiency of network operations by buffering data until a minimum number of bytes
			/// accumulate or until a maximum time elapses.
			/// </summary>
			FILE_FLAG_WRITE_THROUGH = 0x80000000,

			/// <summary>
			/// Overlapped mode is enabled. If this mode is enabled, functions performing read, write, and connect operations that may take a
			/// significant time to be completed can return immediately. This mode enables the thread that started the operation to perform
			/// other operations while the time-consuming operation executes in the background. For example, in overlapped mode, a thread can
			/// handle simultaneous input and output (I/O) operations on multiple instances of a pipe or perform simultaneous read and write
			/// operations on the same pipe handle. If overlapped mode is not enabled, functions performing read, write, and connect
			/// operations on the pipe handle do not return until the operation is finished. The ReadFileEx and WriteFileEx functions can
			/// only be used with a pipe handle in overlapped mode. The ReadFile, WriteFile, ConnectNamedPipe, and TransactNamedPipe
			/// functions can execute either synchronously or as overlapped operations.
			/// </summary>
			FILE_FLAG_OVERLAPPED = 0x40000000,

			/// <summary>The caller will have write access to the named pipe's discretionary access control list (ACL).</summary>
			WRITE_DAC = 0x00040000,

			/// <summary>The caller will have write access to the named pipe's owner.</summary>
			WRITE_OWNER = 0x00080000,

			/// <summary>
			/// The caller will have write access to the named pipe's SACL. For more information, see Access-Control Lists (ACLs) and SACL
			/// Access Right.
			/// </summary>
			ACCESS_SYSTEM_SECURITY = 0x01000000
		}

		/// <summary>The pipe mode.</summary>
		[Flags]
		public enum PIPE_TYPE : uint
		{
			/// <summary>
			/// Blocking mode is enabled. When the pipe handle is specified in the ReadFile, WriteFile, or ConnectNamedPipe function, the
			/// operations are not completed until there is data to read, all data is written, or a client is connected. Use of this mode can
			/// mean waiting indefinitely in some situations for a client process to perform an action.
			/// </summary>
			PIPE_WAIT = 0x00000000,

			/// <summary>
			/// Nonblocking mode is enabled. In this mode, ReadFile, WriteFile, and ConnectNamedPipe always return immediately. Note that
			/// nonblocking mode is supported for compatibility with Microsoft LAN Manager version 2.0 and should not be used to achieve
			/// asynchronous I/O with named pipes. For more information on asynchronous pipe I/O, see Synchronous and Overlapped Input and Output.
			/// </summary>
			PIPE_NOWAIT = 0x00000001,

			/// <summary>Data is read from the pipe as a stream of bytes. This mode can be used with either PIPE_TYPE_MESSAGE or PIPE_TYPE_BYTE.</summary>
			PIPE_READMODE_BYTE = 0x00000000,

			/// <summary>
			/// Data is read from the pipe as a stream of messages. This mode can be only used if PIPE_TYPE_MESSAGE is also specified.
			/// </summary>
			PIPE_READMODE_MESSAGE = 0x00000002,

			/// <summary>
			/// Data is written to the pipe as a stream of bytes. This mode cannot be used with PIPE_READMODE_MESSAGE. The pipe does not
			/// distinguish bytes written during different write operations.
			/// </summary>
			PIPE_TYPE_BYTE = 0x00000000,

			/// <summary>
			/// Data is written to the pipe as a stream of messages. The pipe treats the bytes written during each write operation as a
			/// message unit. The GetLastError function returns ERROR_MORE_DATA when a message is not read completely. This mode can be used
			/// with either PIPE_READMODE_MESSAGE or PIPE_READMODE_BYTE.
			/// </summary>
			PIPE_TYPE_MESSAGE = 0x00000004,

			/// <summary>Connections from remote clients can be accepted and checked against the security descriptor for the pipe.</summary>
			PIPE_ACCEPT_REMOTE_CLIENTS = 0x00000000,

			/// <summary>Connections from remote clients are automatically rejected.</summary>
			PIPE_REJECT_REMOTE_CLIENTS = 0x00000008,

			/// <summary>The handle refers to the client end of a named pipe instance. This is the default.</summary>
			PIPE_CLIENT_END = 0x00000000,

			/// <summary>
			/// The handle refers to the server end of a named pipe instance. If this value is not specified, the handle refers to the client
			/// end of a named pipe instance.
			/// </summary>
			PIPE_SERVER_END = 0x00000001,
		}

		/// <summary>
		/// Connects to a message-type pipe (and waits if an instance of the pipe is not available), writes to and reads from the pipe, and
		/// then closes the pipe.
		/// </summary>
		/// <param name="lpNamedPipeName">The pipe name.</param>
		/// <param name="lpInBuffer">The data to be written to the pipe.</param>
		/// <param name="nInBufferSize">The size of the write buffer, in bytes.</param>
		/// <param name="lpOutBuffer">A pointer to the buffer that receives the data read from the pipe.</param>
		/// <param name="nOutBufferSize">The size of the read buffer, in bytes.</param>
		/// <param name="lpBytesRead">A pointer to a variable that receives the number of bytes read from the pipe.</param>
		/// <param name="nTimeOut">
		/// <para>
		/// The number of milliseconds to wait for the named pipe to be available. In addition to numeric values, the following special
		/// values can be specified.
		/// </para>
		/// <para>
		/// <list type="table">
		/// <listheader>
		/// <term>Value</term>
		/// <term>Meaning</term>
		/// </listheader>
		/// <item>
		/// <term>NMPWAIT_NOWAIT0x00000001</term>
		/// <term>Does not wait for the named pipe. If the named pipe is not available, the function returns an error.</term>
		/// </item>
		/// <item>
		/// <term>NMPWAIT_WAIT_FOREVER0xffffffff</term>
		/// <term>Waits indefinitely.</term>
		/// </item>
		/// <item>
		/// <term>NMPWAIT_USE_DEFAULT_WAIT0x00000000</term>
		/// <term>Uses the default time-out specified in a call to the CreateNamedPipe function.</term>
		/// </item>
		/// </list>
		/// </para>
		/// </param>
		/// <returns>
		/// <para>If the function succeeds, the return value is nonzero.</para>
		/// <para>If the function fails, the return value is zero. To get extended error information, call <c>GetLastError</c>.</para>
		/// <para>
		/// If the message written to the pipe by the server process is longer than nOutBufferSize, <c>CallNamedPipe</c> returns
		/// <c>FALSE</c>, and <c>GetLastError</c> returns ERROR_MORE_DATA. The remainder of the message is discarded, because
		/// <c>CallNamedPipe</c> closes the handle to the pipe before returning.
		/// </para>
		/// </returns>
		// BOOL WINAPI CallNamedPipe( _In_ LPCTSTR lpNamedPipeName, _In_ LPVOID lpInBuffer, _In_ DWORD nInBufferSize, _Out_ LPVOID
		// lpOutBuffer, _In_ DWORD nOutBufferSize, _Out_ LPDWORD lpBytesRead, _In_ DWORD nTimeOut); https://msdn.microsoft.com/en-us/library/windows/desktop/aa365144(v=vs.85).aspx
		[DllImport(Lib.Kernel32, SetLastError = true, CharSet = CharSet.Auto)]
		[PInvokeData("namedpipeapi.h", MSDNShortId = "aa365144")]
		[return: MarshalAs(UnmanagedType.Bool)]
		public static extern bool CallNamedPipe(string lpNamedPipeName, [In] IntPtr lpInBuffer, uint nInBufferSize, IntPtr lpOutBuffer, uint nOutBufferSize,
			[Out] out uint lpBytesRead, uint nTimeOut);

		/// <summary>
		/// Enables a named pipe server process to wait for a client process to connect to an instance of a named pipe. A client process
		/// connects by calling either the <c>CreateFile</c> or <c>CallNamedPipe</c> function.
		/// </summary>
		/// <param name="hNamedPipe">
		/// A handle to the server end of a named pipe instance. This handle is returned by the <c>CreateNamedPipe</c> function.
		/// </param>
		/// <param name="lpOverlapped">
		/// <para>A pointer to an <c>OVERLAPPED</c> structure.</para>
		/// <para>
		/// If hNamedPipe was opened with FILE_FLAG_OVERLAPPED, the lpOverlapped parameter must not be <c>NULL</c>. It must point to a valid
		/// <c>OVERLAPPED</c> structure. If hNamedPipe was opened with FILE_FLAG_OVERLAPPED and lpOverlapped is <c>NULL</c>, the function can
		/// incorrectly report that the connect operation is complete.
		/// </para>
		/// <para>
		/// If hNamedPipe was created with FILE_FLAG_OVERLAPPED and lpOverlapped is not <c>NULL</c>, the <c>OVERLAPPED</c> structure should
		/// contain a handle to a manual-reset event object (which the server can create by using the <c>CreateEvent</c> function).
		/// </para>
		/// <para>
		/// If hNamedPipe was not opened with FILE_FLAG_OVERLAPPED, the function does not return until a client is connected or an error
		/// occurs. Successful synchronous operations result in the function returning a nonzero value if a client connects after the
		/// function is called.
		/// </para>
		/// </param>
		/// <returns>
		/// <para>
		/// If the operation is synchronous, <c>ConnectNamedPipe</c> does not return until the operation has completed. If the function
		/// succeeds, the return value is nonzero. If the function fails, the return value is zero. To get extended error information, call <c>GetLastError</c>.
		/// </para>
		/// <para>
		/// If the operation is asynchronous, <c>ConnectNamedPipe</c> returns immediately. If the operation is still pending, the return
		/// value is zero and <c>GetLastError</c> returns ERROR_IO_PENDING. (You can use the <c>HasOverlappedIoCompleted</c> macro to
		/// determine when the operation has finished.) If the function fails, the return value is zero and <c>GetLastError</c> returns a
		/// value other than ERROR_IO_PENDING or ERROR_PIPE_CONNECTED.
		/// </para>
		/// <para>
		/// If a client connects before the function is called, the function returns zero and <c>GetLastError</c> returns
		/// ERROR_PIPE_CONNECTED. This can happen if a client connects in the interval between the call to <c>CreateNamedPipe</c> and the
		/// call to <c>ConnectNamedPipe</c>. In this situation, there is a good connection between client and server, even though the
		/// function returns zero.
		/// </para>
		/// </returns>
		// BOOL WINAPI ConnectNamedPipe( _In_ HANDLE hNamedPipe, _Inout_opt_ LPOVERLAPPED lpOverlapped); https://msdn.microsoft.com/en-us/library/windows/desktop/aa365146(v=vs.85).aspx
		[DllImport(Lib.Kernel32, SetLastError = true, ExactSpelling = true)]
		[PInvokeData("namedpipeapi.h", MSDNShortId = "aa365146")]
		[return: MarshalAs(UnmanagedType.Bool)]
		public static extern unsafe bool ConnectNamedPipe([In] HPIPE hNamedPipe, [Optional] NativeOverlapped* lpOverlapped);

		/// <summary>
		/// Creates an instance of a named pipe and returns a handle for subsequent pipe operations. A named pipe server process uses this
		/// function either to create the first instance of a specific named pipe and establish its basic attributes or to create a new
		/// instance of an existing named pipe.
		/// </summary>
		/// <param name="lpName">
		/// <para>The unique pipe name. This string must have the following form:</para>
		/// <para>\\.\pipe\pipename</para>
		/// <para>
		/// The pipename part of the name can include any character other than a backslash, including numbers and special characters. The
		/// entire pipe name string can be up to 256 characters long. Pipe names are not case sensitive.
		/// </para>
		/// </param>
		/// <param name="dwOpenMode">
		/// <para>The open mode. The function fails if dwOpenMode specifies anything other than 0 or the flags listed in the following tables.</para>
		/// <para>
		/// This parameter must specify one of the following pipe access modes. The same mode must be specified for each instance of the pipe.
		/// </para>
		/// <para>
		/// <list type="table">
		/// <listheader>
		/// <term>Mode</term>
		/// <term>Meaning</term>
		/// </listheader>
		/// <item>
		/// <term>PIPE_ACCESS_DUPLEX0x00000003</term>
		/// <term>
		/// The pipe is bi-directional; both server and client processes can read from and write to the pipe. This mode gives the server the
		/// equivalent of GENERIC_READ and GENERIC_WRITE access to the pipe. The client can specify GENERIC_READ or GENERIC_WRITE, or both,
		/// when it connects to the pipe using the CreateFile function.
		/// </term>
		/// </item>
		/// <item>
		/// <term>PIPE_ACCESS_INBOUND0x00000001</term>
		/// <term>
		/// The flow of data in the pipe goes from client to server only. This mode gives the server the equivalent of GENERIC_READ access to
		/// the pipe. The client must specify GENERIC_WRITE access when connecting to the pipe. If the client must read pipe settings by
		/// calling the GetNamedPipeInfo or GetNamedPipeHandleState functions, the client must specify GENERIC_WRITE and FILE_READ_ATTRIBUTES
		/// access when connecting to the pipe.
		/// </term>
		/// </item>
		/// <item>
		/// <term>PIPE_ACCESS_OUTBOUND0x00000002</term>
		/// <term>
		/// The flow of data in the pipe goes from server to client only. This mode gives the server the equivalent of GENERIC_WRITE access
		/// to the pipe. The client must specify GENERIC_READ access when connecting to the pipe. If the client must change pipe settings by
		/// calling the SetNamedPipeHandleState function, the client must specify GENERIC_READ and FILE_WRITE_ATTRIBUTES access when
		/// connecting to the pipe.
		/// </term>
		/// </item>
		/// </list>
		/// </para>
		/// <para>
		/// This parameter can also include one or more of the following flags, which enable the write-through and overlapped modes. These
		/// modes can be different for different instances of the same pipe.
		/// </para>
		/// <para>
		/// <list type="table">
		/// <listheader>
		/// <term>Mode</term>
		/// <term>Meaning</term>
		/// </listheader>
		/// <item>
		/// <term>FILE_FLAG_FIRST_PIPE_INSTANCE0x00080000</term>
		/// <term>
		/// If you attempt to create multiple instances of a pipe with this flag, creation of the first instance succeeds, but creation of
		/// the next instance fails with ERROR_ACCESS_DENIED.
		/// </term>
		/// </item>
		/// <item>
		/// <term>FILE_FLAG_WRITE_THROUGH0x80000000</term>
		/// <term>
		/// Write-through mode is enabled. This mode affects only write operations on byte-type pipes and, then, only when the client and
		/// server processes are on different computers. If this mode is enabled, functions writing to a named pipe do not return until the
		/// data written is transmitted across the network and is in the pipe's buffer on the remote computer. If this mode is not enabled,
		/// the system enhances the efficiency of network operations by buffering data until a minimum number of bytes accumulate or until a
		/// maximum time elapses.
		/// </term>
		/// </item>
		/// <item>
		/// <term>FILE_FLAG_OVERLAPPED0x40000000</term>
		/// <term>
		/// Overlapped mode is enabled. If this mode is enabled, functions performing read, write, and connect operations that may take a
		/// significant time to be completed can return immediately. This mode enables the thread that started the operation to perform other
		/// operations while the time-consuming operation executes in the background. For example, in overlapped mode, a thread can handle
		/// simultaneous input and output (I/O) operations on multiple instances of a pipe or perform simultaneous read and write operations
		/// on the same pipe handle. If overlapped mode is not enabled, functions performing read, write, and connect operations on the pipe
		/// handle do not return until the operation is finished. The ReadFileEx and WriteFileEx functions can only be used with a pipe
		/// handle in overlapped mode. The ReadFile, WriteFile, ConnectNamedPipe, and TransactNamedPipe functions can execute either
		/// synchronously or as overlapped operations.
		/// </term>
		/// </item>
		/// </list>
		/// </para>
		/// <para>
		/// This parameter can include any combination of the following security access modes. These modes can be different for different
		/// instances of the same pipe.
		/// </para>
		/// <para>
		/// <list type="table">
		/// <listheader>
		/// <term>Mode</term>
		/// <term>Meaning</term>
		/// </listheader>
		/// <item>
		/// <term>WRITE_DAC0x00040000L</term>
		/// <term>The caller will have write access to the named pipe's discretionary access control list (ACL).</term>
		/// </item>
		/// <item>
		/// <term>WRITE_OWNER0x00080000L</term>
		/// <term>The caller will have write access to the named pipe's owner.</term>
		/// </item>
		/// <item>
		/// <term>ACCESS_SYSTEM_SECURITY0x01000000L</term>
		/// <term>
		/// The caller will have write access to the named pipe's SACL. For more information, see Access-Control Lists (ACLs) and SACL Access Right.
		/// </term>
		/// </item>
		/// </list>
		/// </para>
		/// </param>
		/// <param name="dwPipeMode">
		/// <para>The pipe mode. The function fails if dwPipeMode specifies anything other than 0 or the flags listed in the following tables.</para>
		/// <para>One of the following type modes can be specified. The same type mode must be specified for each instance of the pipe.</para>
		/// <para>
		/// <list type="table">
		/// <listheader>
		/// <term>Mode</term>
		/// <term>Meaning</term>
		/// </listheader>
		/// <item>
		/// <term>PIPE_TYPE_BYTE0x00000000</term>
		/// <term>
		/// Data is written to the pipe as a stream of bytes. This mode cannot be used with PIPE_READMODE_MESSAGE. The pipe does not
		/// distinguish bytes written during different write operations.
		/// </term>
		/// </item>
		/// <item>
		/// <term>PIPE_TYPE_MESSAGE0x00000004</term>
		/// <term>
		/// Data is written to the pipe as a stream of messages. The pipe treats the bytes written during each write operation as a message
		/// unit. The GetLastError function returns ERROR_MORE_DATA when a message is not read completely. This mode can be used with either
		/// PIPE_READMODE_MESSAGE or PIPE_READMODE_BYTE.
		/// </term>
		/// </item>
		/// </list>
		/// </para>
		/// <para>One of the following read modes can be specified. Different instances of the same pipe can specify different read modes.</para>
		/// <para>
		/// <list type="table">
		/// <listheader>
		/// <term>Mode</term>
		/// <term>Meaning</term>
		/// </listheader>
		/// <item>
		/// <term>PIPE_READMODE_BYTE0x00000000</term>
		/// <term>Data is read from the pipe as a stream of bytes. This mode can be used with either PIPE_TYPE_MESSAGE or PIPE_TYPE_BYTE.</term>
		/// </item>
		/// <item>
		/// <term>PIPE_READMODE_MESSAGE0x00000002</term>
		/// <term>Data is read from the pipe as a stream of messages. This mode can be only used if PIPE_TYPE_MESSAGE is also specified.</term>
		/// </item>
		/// </list>
		/// </para>
		/// <para>One of the following wait modes can be specified. Different instances of the same pipe can specify different wait modes.</para>
		/// <para>
		/// <list type="table">
		/// <listheader>
		/// <term>Mode</term>
		/// <term>Meaning</term>
		/// </listheader>
		/// <item>
		/// <term>PIPE_WAIT0x00000000</term>
		/// <term>
		/// Blocking mode is enabled. When the pipe handle is specified in the ReadFile, WriteFile, or ConnectNamedPipe function, the
		/// operations are not completed until there is data to read, all data is written, or a client is connected. Use of this mode can
		/// mean waiting indefinitely in some situations for a client process to perform an action.
		/// </term>
		/// </item>
		/// <item>
		/// <term>PIPE_NOWAIT0x00000001</term>
		/// <term>
		/// Nonblocking mode is enabled. In this mode, ReadFile, WriteFile, and ConnectNamedPipe always return immediately.Note that
		/// nonblocking mode is supported for compatibility with Microsoft LAN Manager version 2.0 and should not be used to achieve
		/// asynchronous I/O with named pipes. For more information on asynchronous pipe I/O, see Synchronous and Overlapped Input and Output.
		/// </term>
		/// </item>
		/// </list>
		/// </para>
		/// <para>
		/// One of the following remote-client modes can be specified. Different instances of the same pipe can specify different
		/// remote-client modes.
		/// </para>
		/// <para>
		/// <list type="table">
		/// <listheader>
		/// <term>Mode</term>
		/// <term>Meaning</term>
		/// </listheader>
		/// <item>
		/// <term>PIPE_ACCEPT_REMOTE_CLIENTS0x00000000</term>
		/// <term>Connections from remote clients can be accepted and checked against the security descriptor for the pipe.</term>
		/// </item>
		/// <item>
		/// <term>PIPE_REJECT_REMOTE_CLIENTS0x00000008</term>
		/// <term>Connections from remote clients are automatically rejected.</term>
		/// </item>
		/// </list>
		/// </para>
		/// </param>
		/// <param name="nMaxInstances">
		/// <para>
		/// The maximum number of instances that can be created for this pipe. The first instance of the pipe can specify this value; the
		/// same number must be specified for other instances of the pipe. Acceptable values are in the range 1 through
		/// <c>PIPE_UNLIMITED_INSTANCES</c> (255).
		/// </para>
		/// <para>
		/// If this parameter is <c>PIPE_UNLIMITED_INSTANCES</c>, the number of pipe instances that can be created is limited only by the
		/// availability of system resources. If nMaxInstances is greater than <c>PIPE_UNLIMITED_INSTANCES</c>, the return value is
		/// <c>INVALID_HANDLE_VALUE</c> and <c>GetLastError</c> returns <c>ERROR_INVALID_PARAMETER</c>.
		/// </para>
		/// </param>
		/// <param name="nOutBufferSize">
		/// The number of bytes to reserve for the output buffer. For a discussion on sizing named pipe buffers, see the following Remarks section.
		/// </param>
		/// <param name="nInBufferSize">
		/// The number of bytes to reserve for the input buffer. For a discussion on sizing named pipe buffers, see the following Remarks section.
		/// </param>
		/// <param name="nDefaultTimeOut">
		/// <para>
		/// The default time-out value, in milliseconds, if the <c>WaitNamedPipe</c> function specifies <c>NMPWAIT_USE_DEFAULT_WAIT</c>. Each
		/// instance of a named pipe must specify the same value.
		/// </para>
		/// <para>A value of zero will result in a default time-out of 50 milliseconds.</para>
		/// </param>
		/// <param name="lpSecurityAttributes">
		/// A pointer to a <c>SECURITY_ATTRIBUTES</c> structure that specifies a security descriptor for the new named pipe and determines
		/// whether child processes can inherit the returned handle. If lpSecurityAttributes is <c>NULL</c>, the named pipe gets a default
		/// security descriptor and the handle cannot be inherited. The ACLs in the default security descriptor for a named pipe grant full
		/// control to the LocalSystem account, administrators, and the creator owner. They also grant read access to members of the Everyone
		/// group and the anonymous account.
		/// </param>
		/// <returns>
		/// <para>If the function succeeds, the return value is a handle to the server end of a named pipe instance.</para>
		/// <para>If the function fails, the return value is <c>INVALID_HANDLE_VALUE</c>. To get extended error information, call <c>GetLastError</c>.</para>
		/// </returns>
		// HANDLE WINAPI CreateNamedPipe( _In_ LPCTSTR lpName, _In_ DWORD dwOpenMode, _In_ DWORD dwPipeMode, _In_ DWORD nMaxInstances, _In_
		// DWORD nOutBufferSize, _In_ DWORD nInBufferSize, _In_ DWORD nDefaultTimeOut, _In_opt_ LPSECURITY_ATTRIBUTES lpSecurityAttributes); https://msdn.microsoft.com/en-us/library/windows/desktop/aa365150(v=vs.85).aspx
		[DllImport(Lib.Kernel32, SetLastError = true, CharSet = CharSet.Auto)]
		[PInvokeData("namedpipeapi.h", MSDNShortId = "aa365150")]
		public static extern SafeHPIPE CreateNamedPipe(string lpName, PIPE_ACCESS dwOpenMode, PIPE_TYPE dwPipeMode, uint nMaxInstances, uint nOutBufferSize, uint nInBufferSize,
			uint nDefaultTimeOut, [In, Optional] SECURITY_ATTRIBUTES lpSecurityAttributes);

		/// <summary>Creates an anonymous pipe, and returns handles to the read and write ends of the pipe.</summary>
		/// <param name="hReadPipe">A pointer to a variable that receives the read handle for the pipe.</param>
		/// <param name="hWritePipe">A pointer to a variable that receives the write handle for the pipe.</param>
		/// <param name="lpPipeAttributes">
		/// <para>
		/// A pointer to a <c>SECURITY_ATTRIBUTES</c> structure that determines whether the returned handle can be inherited by child
		/// processes. If lpPipeAttributes is <c>NULL</c>, the handle cannot be inherited.
		/// </para>
		/// <para>
		/// The <c>lpSecurityDescriptor</c> member of the structure specifies a security descriptor for the new pipe. If lpPipeAttributes is
		/// <c>NULL</c>, the pipe gets a default security descriptor. The ACLs in the default security descriptor for a pipe come from the
		/// primary or impersonation token of the creator.
		/// </para>
		/// </param>
		/// <param name="nSize">
		/// The size of the buffer for the pipe, in bytes. The size is only a suggestion; the system uses the value to calculate an
		/// appropriate buffering mechanism. If this parameter is zero, the system uses the default buffer size.
		/// </param>
		/// <returns>
		/// <para>If the function succeeds, the return value is nonzero.</para>
		/// <para>If the function fails, the return value is zero. To get extended error information, call <c>GetLastError</c>.</para>
		/// </returns>
		// BOOL WINAPI CreatePipe( _Out_ PHANDLE hReadPipe, _Out_ PHANDLE hWritePipe, _In_opt_ LPSECURITY_ATTRIBUTES lpPipeAttributes, _In_
		// DWORD nSize); https://msdn.microsoft.com/en-us/library/windows/desktop/aa365152(v=vs.85).aspx
		[DllImport(Lib.Kernel32, SetLastError = true, ExactSpelling = true)]
		[PInvokeData("namedpipeapi.h", MSDNShortId = "aa365152")]
		[return: MarshalAs(UnmanagedType.Bool)]
		public static extern bool CreatePipe(out SafeHPIPE hReadPipe, out SafeHPIPE hWritePipe, [In, Optional] SECURITY_ATTRIBUTES lpPipeAttributes, [In, Optional] uint nSize);

		/// <summary>Disconnects the server end of a named pipe instance from a client process.</summary>
		/// <param name="hNamedPipe">
		/// A handle to an instance of a named pipe. This handle must be created by the <c>CreateNamedPipe</c> function.
		/// </param>
		/// <returns>
		/// <para>If the function succeeds, the return value is nonzero.</para>
		/// <para>If the function fails, the return value is zero. To get extended error information, call <c>GetLastError</c>.</para>
		/// </returns>
		// BOOL WINAPI DisconnectNamedPipe( _In_ HANDLE hNamedPipe); https://msdn.microsoft.com/en-us/library/windows/desktop/aa365166(v=vs.85).aspx
		[DllImport(Lib.Kernel32, SetLastError = true, ExactSpelling = true)]
		[PInvokeData("namedpipeapi.h", MSDNShortId = "aa365166")]
		[return: MarshalAs(UnmanagedType.Bool)]
		public static extern bool DisconnectNamedPipe([In] HPIPE hNamedPipe);

		/// <summary>Retrieves the client computer name for the specified named pipe.</summary>
		/// <param name="Pipe">A handle to an instance of a named pipe. This handle must be created by the <c>CreateNamedPipe</c> function.</param>
		/// <param name="ClientComputerName">The computer name.</param>
		/// <param name="ClientComputerNameLength">The size of the ClientComputerName buffer, in bytes.</param>
		/// <returns>
		/// <para>If the function succeeds, the return value is nonzero.</para>
		/// <para>If the function fails, the return value is zero. To get extended error information, call the <c>GetLastError</c> function.</para>
		/// </returns>
		// BOOL WINAPI GetNamedPipeClientComputerName( _In_ HANDLE Pipe, _Out_ LPTSTR ClientComputerName, _In_ ULONG
		// ClientComputerNameLength); https://msdn.microsoft.com/en-us/library/windows/desktop/aa365437(v=vs.85).aspx
		[DllImport(Lib.Kernel32, SetLastError = true, CharSet = CharSet.Auto)]
		[PInvokeData("namedpipeapi.h", MSDNShortId = "aa365437")]
		[return: MarshalAs(UnmanagedType.Bool)]
		public static extern bool GetNamedPipeClientComputerName(HPIPE Pipe, StringBuilder ClientComputerName, uint ClientComputerNameLength);

		/// <summary>
		/// <para>Retrieves the client process identifier for the specified named pipe.</para>
		/// </summary>
		/// <param name="Pipe">
		/// <para>A handle to an instance of a named pipe. This handle must be created by the CreateNamedPipe function.</para>
		/// </param>
		/// <param name="ClientProcessId">
		/// <para>The process identifier.</para>
		/// </param>
		/// <returns>
		/// <para>If the function succeeds, the return value is nonzero.</para>
		/// <para>If the function fails, the return value is zero. To get extended error information, call the GetLastError function.</para>
		/// </returns>
		/// <remarks>
		/// <para>
		/// <c>Windows 10, version 1709:</c> Pipes are only supported within an app-container; ie, from one UWP process to another UWP
		/// process that's part of the same app. Also, named pipes must use the syntax "\.\pipe\LOCAL" for the pipe name.
		/// </para>
		/// </remarks>
		// https://docs.microsoft.com/en-us/windows/desktop/api/winbase/nf-winbase-getnamedpipeclientprocessid BOOL
		// GetNamedPipeClientProcessId( HANDLE Pipe, PULONG ClientProcessId );
		[DllImport(Lib.Kernel32, SetLastError = true, ExactSpelling = true)]
		[PInvokeData("winbase.h", MSDNShortId = "7001eb89-3d91-44e3-b245-b19e8ab5f9fe")]
		[return: MarshalAs(UnmanagedType.Bool)]
		public static extern bool GetNamedPipeClientProcessId(HPIPE Pipe, out uint ClientProcessId);

		/// <summary>
		/// <para>Retrieves the client session identifier for the specified named pipe.</para>
		/// </summary>
		/// <param name="Pipe">
		/// <para>A handle to an instance of a named pipe. This handle must be created by the CreateNamedPipe function.</para>
		/// </param>
		/// <param name="ClientSessionId">
		/// <para>The session identifier.</para>
		/// </param>
		/// <returns>
		/// <para>If the function succeeds, the return value is nonzero.</para>
		/// <para>If the function fails, the return value is zero. To get extended error information, call the GetLastError function.</para>
		/// </returns>
		/// <remarks>
		/// <para>
		/// <c>Windows 10, version 1709:</c> Pipes are only supported within an app-container; ie, from one UWP process to another UWP
		/// process that's part of the same app. Also, named pipes must use the syntax "\.\pipe\LOCAL" for the pipe name.
		/// </para>
		/// </remarks>
		// https://docs.microsoft.com/en-us/windows/desktop/api/winbase/nf-winbase-getnamedpipeclientsessionid BOOL
		// GetNamedPipeClientSessionId( HANDLE Pipe, PULONG ClientSessionId );
		[DllImport(Lib.Kernel32, SetLastError = true, ExactSpelling = true)]
		[PInvokeData("winbase.h", MSDNShortId = "b3ea0b7f-fead-4369-b87a-2f522a2a1984")]
		[return: MarshalAs(UnmanagedType.Bool)]
		public static extern bool GetNamedPipeClientSessionId(HPIPE Pipe, out uint ClientSessionId);

		/// <summary>
		/// Retrieves information about a specified named pipe. The information returned can vary during the lifetime of an instance of the
		/// named pipe.
		/// </summary>
		/// <param name="hNamedPipe">
		/// <para>
		/// A handle to the named pipe for which information is wanted. The handle must have GENERIC_READ access for a read-only or
		/// read/write pipe, or it must have GENERIC_WRITE and FILE_READ_ATTRIBUTES access for a write-only pipe.
		/// </para>
		/// <para>This parameter can also be a handle to an anonymous pipe, as returned by the <c>CreatePipe</c> function.</para>
		/// </param>
		/// <param name="lpState">
		/// <para>
		/// A pointer to a variable that indicates the current state of the handle. This parameter can be <c>NULL</c> if this information is
		/// not needed. Either or both of the following values can be specified.
		/// </para>
		/// <para>
		/// <list type="table">
		/// <listheader>
		/// <term>Value</term>
		/// <term>Meaning</term>
		/// </listheader>
		/// <item>
		/// <term>PIPE_NOWAIT0x00000001</term>
		/// <term>The pipe handle is in nonblocking mode. If this flag is not specified, the pipe handle is in blocking mode.</term>
		/// </item>
		/// <item>
		/// <term>PIPE_READMODE_MESSAGE0x00000002</term>
		/// <term>The pipe handle is in message-read mode. If this flag is not specified, the pipe handle is in byte-read mode.</term>
		/// </item>
		/// </list>
		/// </para>
		/// </param>
		/// <param name="lpCurInstances">
		/// A pointer to a variable that receives the number of current pipe instances. This parameter can be <c>NULL</c> if this information
		/// is not required.
		/// </param>
		/// <param name="lpMaxCollectionCount">
		/// A pointer to a variable that receives the maximum number of bytes to be collected on the client's computer before transmission to
		/// the server. This parameter must be <c>NULL</c> if the specified pipe handle is to the server end of a named pipe or if client and
		/// server processes are on the same computer. This parameter can be <c>NULL</c> if this information is not required.
		/// </param>
		/// <param name="lpCollectDataTimeout">
		/// A pointer to a variable that receives the maximum time, in milliseconds, that can pass before a remote named pipe transfers
		/// information over the network. This parameter must be <c>NULL</c> if the specified pipe handle is to the server end of a named
		/// pipe or if client and server processes are on the same computer. This parameter can be <c>NULL</c> if this information is not required.
		/// </param>
		/// <param name="lpUserName">
		/// <para>
		/// A pointer to a buffer that receives the user name string associated with the client application. The server can only retrieve
		/// this information if the client opened the pipe with SECURITY_IMPERSONATION access.
		/// </para>
		/// <para>
		/// This parameter must be <c>NULL</c> if the specified pipe handle is to the client end of a named pipe. This parameter can be
		/// <c>NULL</c> if this information is not required.
		/// </para>
		/// </param>
		/// <param name="nMaxUserNameSize">
		/// The size of the buffer specified by the lpUserName parameter, in <c>TCHARs</c>. This parameter is ignored if lpUserName is <c>NULL</c>.
		/// </param>
		/// <returns>
		/// <para>If the function succeeds, the return value is nonzero.</para>
		/// <para>If the function fails, the return value is zero. To get extended error information, call <c>GetLastError</c>.</para>
		/// </returns>
		// BOOL WINAPI GetNamedPipeHandleState( _In_ HANDLE hNamedPipe, _Out_opt_ LPDWORD lpState, _Out_opt_ LPDWORD lpCurInstances,
		// _Out_opt_ LPDWORD lpMaxCollectionCount, _Out_opt_ LPDWORD lpCollectDataTimeout, _Out_opt_ LPTSTR lpUserName, _In_ DWORD
		// nMaxUserNameSize); https://msdn.microsoft.com/en-us/library/windows/desktop/aa365443(v=vs.85).aspx
		[DllImport(Lib.Kernel32, SetLastError = true, CharSet = CharSet.Auto)]
		[PInvokeData("Winbase.h", MSDNShortId = "aa365443")]
		[return: MarshalAs(UnmanagedType.Bool)]
		public static extern bool GetNamedPipeHandleState([In] HPIPE hNamedPipe, out PIPE_TYPE lpState, out uint lpCurInstances, [Optional] IntPtr lpMaxCollectionCount,
			[Optional] IntPtr lpCollectDataTimeout, [Optional] StringBuilder lpUserName, [Optional] uint nMaxUserNameSize);

		/// <summary>
		/// Retrieves information about a specified named pipe. The information returned can vary during the lifetime of an instance of the
		/// named pipe.
		/// </summary>
		/// <param name="hNamedPipe">
		/// <para>
		/// A handle to the named pipe for which information is wanted. The handle must have GENERIC_READ access for a read-only or
		/// read/write pipe, or it must have GENERIC_WRITE and FILE_READ_ATTRIBUTES access for a write-only pipe.
		/// </para>
		/// <para>This parameter can also be a handle to an anonymous pipe, as returned by the <c>CreatePipe</c> function.</para>
		/// </param>
		/// <param name="lpState">
		/// <para>
		/// A pointer to a variable that indicates the current state of the handle. This parameter can be <c>NULL</c> if this information is
		/// not needed. Either or both of the following values can be specified.
		/// </para>
		/// <para>
		/// <list type="table">
		/// <listheader>
		/// <term>Value</term>
		/// <term>Meaning</term>
		/// </listheader>
		/// <item>
		/// <term>PIPE_NOWAIT0x00000001</term>
		/// <term>The pipe handle is in nonblocking mode. If this flag is not specified, the pipe handle is in blocking mode.</term>
		/// </item>
		/// <item>
		/// <term>PIPE_READMODE_MESSAGE0x00000002</term>
		/// <term>The pipe handle is in message-read mode. If this flag is not specified, the pipe handle is in byte-read mode.</term>
		/// </item>
		/// </list>
		/// </para>
		/// </param>
		/// <param name="lpCurInstances">
		/// A pointer to a variable that receives the number of current pipe instances. This parameter can be <c>NULL</c> if this information
		/// is not required.
		/// </param>
		/// <param name="lpMaxCollectionCount">
		/// A pointer to a variable that receives the maximum number of bytes to be collected on the client's computer before transmission to
		/// the server. This parameter must be <c>NULL</c> if the specified pipe handle is to the server end of a named pipe or if client and
		/// server processes are on the same computer. This parameter can be <c>NULL</c> if this information is not required.
		/// </param>
		/// <param name="lpCollectDataTimeout">
		/// A pointer to a variable that receives the maximum time, in milliseconds, that can pass before a remote named pipe transfers
		/// information over the network. This parameter must be <c>NULL</c> if the specified pipe handle is to the server end of a named
		/// pipe or if client and server processes are on the same computer. This parameter can be <c>NULL</c> if this information is not required.
		/// </param>
		/// <param name="lpUserName">
		/// <para>
		/// A pointer to a buffer that receives the user name string associated with the client application. The server can only retrieve
		/// this information if the client opened the pipe with SECURITY_IMPERSONATION access.
		/// </para>
		/// <para>
		/// This parameter must be <c>NULL</c> if the specified pipe handle is to the client end of a named pipe. This parameter can be
		/// <c>NULL</c> if this information is not required.
		/// </para>
		/// </param>
		/// <param name="nMaxUserNameSize">
		/// The size of the buffer specified by the lpUserName parameter, in <c>TCHARs</c>. This parameter is ignored if lpUserName is <c>NULL</c>.
		/// </param>
		/// <returns>
		/// <para>If the function succeeds, the return value is nonzero.</para>
		/// <para>If the function fails, the return value is zero. To get extended error information, call <c>GetLastError</c>.</para>
		/// </returns>
		// BOOL WINAPI GetNamedPipeHandleState( _In_ HANDLE hNamedPipe, _Out_opt_ LPDWORD lpState, _Out_opt_ LPDWORD lpCurInstances,
		// _Out_opt_ LPDWORD lpMaxCollectionCount, _Out_opt_ LPDWORD lpCollectDataTimeout, _Out_opt_ LPTSTR lpUserName, _In_ DWORD
		// nMaxUserNameSize); https://msdn.microsoft.com/en-us/library/windows/desktop/aa365443(v=vs.85).aspx
		[DllImport(Lib.Kernel32, SetLastError = true, CharSet = CharSet.Auto)]
		[PInvokeData("namedpipeapi.h", MSDNShortId = "aa365443")]
		[return: MarshalAs(UnmanagedType.Bool)]
		public static extern bool GetNamedPipeHandleState([In] HPIPE hNamedPipe, out PIPE_TYPE lpState, out uint lpCurInstances, out uint lpMaxCollectionCount, out uint lpCollectDataTimeout,
			[Optional] StringBuilder lpUserName, [Optional] uint nMaxUserNameSize);

		/// <summary>Retrieves information about the specified named pipe.</summary>
		/// <param name="hNamedPipe">
		/// <para>
		/// A handle to the named pipe instance. The handle must have GENERIC_READ access to the named pipe for a read-only or read/write
		/// pipe, or it must have GENERIC_WRITE and FILE_READ_ATTRIBUTES access for a write-only pipe.
		/// </para>
		/// <para>This parameter can also be a handle to an anonymous pipe, as returned by the <c>CreatePipe</c> function.</para>
		/// </param>
		/// <param name="lpFlags">
		/// <para>
		/// A pointer to a variable that receives the type of the named pipe. This parameter can be <c>NULL</c> if this information is not
		/// required. Otherwise, this parameter can be one or more of the following values.
		/// </para>
		/// <para>
		/// <list type="table">
		/// <listheader>
		/// <term>Value</term>
		/// <term>Meaning</term>
		/// </listheader>
		/// <item>
		/// <term>PIPE_CLIENT_END0x00000000</term>
		/// <term>The handle refers to the client end of a named pipe instance. This is the default.</term>
		/// </item>
		/// <item>
		/// <term>PIPE_SERVER_END0x00000001</term>
		/// <term>
		/// The handle refers to the server end of a named pipe instance. If this value is not specified, the handle refers to the client end
		/// of a named pipe instance.
		/// </term>
		/// </item>
		/// <item>
		/// <term>PIPE_TYPE_BYTE0x00000000</term>
		/// <term>The named pipe is a byte pipe. This is the default.</term>
		/// </item>
		/// <item>
		/// <term>PIPE_TYPE_MESSAGE0x00000004</term>
		/// <term>The named pipe is a message pipe. If this value is not specified, the pipe is a byte pipe.</term>
		/// </item>
		/// </list>
		/// </para>
		/// </param>
		/// <param name="lpOutBufferSize">
		/// A pointer to a variable that receives the size of the buffer for outgoing data, in bytes. If the buffer size is zero, the buffer
		/// is allocated as needed. This parameter can be <c>NULL</c> if this information is not required.
		/// </param>
		/// <param name="lpInBufferSize">
		/// A pointer to a variable that receives the size of the buffer for incoming data, in bytes. If the buffer size is zero, the buffer
		/// is allocated as needed. This parameter can be <c>NULL</c> if this information is not required.
		/// </param>
		/// <param name="lpMaxInstances">
		/// A pointer to a variable that receives the maximum number of pipe instances that can be created. If the variable is set to
		/// PIPE_UNLIMITED_INSTANCES (255), the number of pipe instances that can be created is limited only by the availability of system
		/// resources. This parameter can be <c>NULL</c> if this information is not required.
		/// </param>
		/// <returns>
		/// <para>If the function succeeds, the return value is nonzero.</para>
		/// <para>If the function fails, the return value is zero. To get extended error information, call <c>GetLastError</c>.</para>
		/// </returns>
		// BOOL WINAPI GetNamedPipeInfo( _In_ HANDLE hNamedPipe, _Out_opt_ LPDWORD lpFlags, _Out_opt_ LPDWORD lpOutBufferSize, _Out_opt_
		// LPDWORD lpInBufferSize, _Out_opt_ LPDWORD lpMaxInstances); https://msdn.microsoft.com/en-us/library/windows/desktop/aa365445(v=vs.85).aspx
		[DllImport(Lib.Kernel32, SetLastError = true, ExactSpelling = true)]
		[PInvokeData("namedpipeapi.h", MSDNShortId = "aa365445")]
		[return: MarshalAs(UnmanagedType.Bool)]
		public static extern bool GetNamedPipeInfo([In] HPIPE hNamedPipe, out PIPE_TYPE lpFlags, out uint lpOutBufferSize, out uint lpInBufferSize, out uint lpMaxInstances);

		/// <summary>
		/// <para>Retrieves the server process identifier for the specified named pipe.</para>
		/// </summary>
		/// <param name="Pipe">
		/// <para>A handle to an instance of a named pipe. This handle must be created by the CreateNamedPipe function.</para>
		/// </param>
		/// <param name="ServerProcessId">
		/// <para>The process identifier.</para>
		/// </param>
		/// <returns>
		/// <para>If the function succeeds, the return value is nonzero.</para>
		/// <para>If the function fails, the return value is zero. To get extended error information, call the GetLastError function.</para>
		/// </returns>
		/// <remarks>
		/// <para>
		/// <c>Windows 10, version 1709:</c> Pipes are only supported within an app-container; ie, from one UWP process to another UWP
		/// process that's part of the same app. Also, named pipes must use the syntax "\.\pipe\LOCAL" for the pipe name.
		/// </para>
		/// </remarks>
		// https://docs.microsoft.com/en-us/windows/desktop/api/winbase/nf-winbase-getnamedpipeserverprocessid BOOL
		// GetNamedPipeServerProcessId( HANDLE Pipe, PULONG ServerProcessId );
		[DllImport(Lib.Kernel32, SetLastError = true, ExactSpelling = true)]
		[PInvokeData("winbase.h", MSDNShortId = "1ee33a66-a71c-4c34-b907-aab7860294c4")]
		[return: MarshalAs(UnmanagedType.Bool)]
		public static extern bool GetNamedPipeServerProcessId(HPIPE Pipe, out uint ServerProcessId);

		/// <summary>
		/// <para>Retrieves the server session identifier for the specified named pipe.</para>
		/// </summary>
		/// <param name="Pipe">
		/// <para>A handle to an instance of a named pipe. This handle must be created by the CreateNamedPipe function.</para>
		/// </param>
		/// <param name="ServerSessionId">
		/// <para>The session identifier.</para>
		/// </param>
		/// <returns>
		/// <para>If the function succeeds, the return value is nonzero.</para>
		/// <para>If the function fails, the return value is zero. To get extended error information, call the GetLastError function.</para>
		/// </returns>
		/// <remarks>
		/// <para>
		/// <c>Windows 10, version 1709:</c> Pipes are only supported within an app-container; ie, from one UWP process to another UWP
		/// process that's part of the same app. Also, named pipes must use the syntax "\.\pipe\LOCAL" for the pipe name.
		/// </para>
		/// </remarks>
		// https://docs.microsoft.com/en-us/windows/desktop/api/winbase/nf-winbase-getnamedpipeserversessionid BOOL
		// GetNamedPipeServerSessionId( HANDLE Pipe, PULONG ServerSessionId );
		[DllImport(Lib.Kernel32, SetLastError = true, ExactSpelling = true)]
		[PInvokeData("winbase.h", MSDNShortId = "cd628d6d-aa13-4762-893b-42f6cf7a2ba6")]
		[return: MarshalAs(UnmanagedType.Bool)]
		public static extern bool GetNamedPipeServerSessionId(HPIPE Pipe, out uint ServerSessionId);

		/// <summary>
		/// Copies data from a named or anonymous pipe into a buffer without removing it from the pipe. It also returns information about
		/// data in the pipe.
		/// </summary>
		/// <param name="hNamedPipe">
		/// A handle to the pipe. This parameter can be a handle to a named pipe instance, as returned by the <c>CreateNamedPipe</c> or
		/// <c>CreateFile</c> function, or it can be a handle to the read end of an anonymous pipe, as returned by the <c>CreatePipe</c>
		/// function. The handle must have GENERIC_READ access to the pipe.
		/// </param>
		/// <param name="lpBuffer">
		/// A pointer to a buffer that receives data read from the pipe. This parameter can be <c>NULL</c> if no data is to be read.
		/// </param>
		/// <param name="nBufferSize">
		/// The size of the buffer specified by the lpBuffer parameter, in bytes. This parameter is ignored if lpBuffer is <c>NULL</c>.
		/// </param>
		/// <param name="lpBytesRead">
		/// A pointer to a variable that receives the number of bytes read from the pipe. This parameter can be <c>NULL</c> if no data is to
		/// be read.
		/// </param>
		/// <param name="lpTotalBytesAvail">
		/// A pointer to a variable that receives the total number of bytes available to be read from the pipe. This parameter can be
		/// <c>NULL</c> if no data is to be read.
		/// </param>
		/// <param name="lpBytesLeftThisMessage">
		/// A pointer to a variable that receives the number of bytes remaining in this message. This parameter will be zero for byte-type
		/// named pipes or for anonymous pipes. This parameter can be <c>NULL</c> if no data is to be read.
		/// </param>
		/// <returns>
		/// <para>If the function succeeds, the return value is nonzero.</para>
		/// <para>If the function fails, the return value is zero. To get extended error information, call <c>GetLastError</c>.</para>
		/// </returns>
		// BOOL WINAPI PeekNamedPipe( _In_ HANDLE hNamedPipe, _Out_opt_ LPVOID lpBuffer, _In_ DWORD nBufferSize, _Out_opt_ LPDWORD
		// lpBytesRead, _Out_opt_ LPDWORD lpTotalBytesAvail, _Out_opt_ LPDWORD lpBytesLeftThisMessage); https://msdn.microsoft.com/en-us/library/windows/desktop/aa365779(v=vs.85).aspx
		[DllImport(Lib.Kernel32, SetLastError = true, ExactSpelling = true)]
		[PInvokeData("namedpipeapi.h", MSDNShortId = "aa365779")]
		[return: MarshalAs(UnmanagedType.Bool)]
		public static extern bool PeekNamedPipe([In] HPIPE hNamedPipe, IntPtr lpBuffer, uint nBufferSize, out uint lpBytesRead, out uint lpTotalBytesAvail, out uint lpBytesLeftThisMessage);

		/// <summary>
		/// Copies data from a named or anonymous pipe into a buffer without removing it from the pipe. It also returns information about
		/// data in the pipe.
		/// </summary>
		/// <param name="hNamedPipe">
		/// A handle to the pipe. This parameter can be a handle to a named pipe instance, as returned by the <c>CreateNamedPipe</c> or
		/// <c>CreateFile</c> function, or it can be a handle to the read end of an anonymous pipe, as returned by the <c>CreatePipe</c>
		/// function. The handle must have GENERIC_READ access to the pipe.
		/// </param>
		/// <param name="lpBuffer">
		/// A pointer to a buffer that receives data read from the pipe. This parameter can be <c>NULL</c> if no data is to be read.
		/// </param>
		/// <param name="nBufferSize">
		/// The size of the buffer specified by the lpBuffer parameter, in bytes. This parameter is ignored if lpBuffer is <c>NULL</c>.
		/// </param>
		/// <param name="lpBytesRead">
		/// A pointer to a variable that receives the number of bytes read from the pipe. This parameter can be <c>NULL</c> if no data is to
		/// be read.
		/// </param>
		/// <param name="lpTotalBytesAvail">
		/// A pointer to a variable that receives the total number of bytes available to be read from the pipe. This parameter can be
		/// <c>NULL</c> if no data is to be read.
		/// </param>
		/// <param name="lpBytesLeftThisMessage">
		/// A pointer to a variable that receives the number of bytes remaining in this message. This parameter will be zero for byte-type
		/// named pipes or for anonymous pipes. This parameter can be <c>NULL</c> if no data is to be read.
		/// </param>
		/// <returns>
		/// <para>If the function succeeds, the return value is nonzero.</para>
		/// <para>If the function fails, the return value is zero. To get extended error information, call <c>GetLastError</c>.</para>
		/// </returns>
		// BOOL WINAPI PeekNamedPipe( _In_ HANDLE hNamedPipe, _Out_opt_ LPVOID lpBuffer, _In_ DWORD nBufferSize, _Out_opt_ LPDWORD
		// lpBytesRead, _Out_opt_ LPDWORD lpTotalBytesAvail, _Out_opt_ LPDWORD lpBytesLeftThisMessage); https://msdn.microsoft.com/en-us/library/windows/desktop/aa365779(v=vs.85).aspx
		[DllImport(Lib.Kernel32, SetLastError = true, ExactSpelling = true)]
		[PInvokeData("namedpipeapi.h", MSDNShortId = "aa365779")]
		[return: MarshalAs(UnmanagedType.Bool)]
		public static extern bool PeekNamedPipe([In] HPIPE hNamedPipe, byte[] lpBuffer, uint nBufferSize, out uint lpBytesRead, out uint lpTotalBytesAvail, out uint lpBytesLeftThisMessage);

		/// <summary>
		/// Sets the read mode and the blocking mode of the specified named pipe. If the specified handle is to the client end of a named
		/// pipe and if the named pipe server process is on a remote computer, the function can also be used to control local buffering.
		/// </summary>
		/// <param name="hNamedPipe">
		/// <para>
		/// A handle to the named pipe instance. This parameter can be a handle to the server end of the pipe, as returned by the
		/// <c>CreateNamedPipe</c> function, or to the client end of the pipe, as returned by the <c>CreateFile</c> function. The handle must
		/// have GENERIC_WRITE access to the named pipe for a write-only or read/write pipe, or it must have GENERIC_READ and
		/// FILE_WRITE_ATTRIBUTES access for a read-only pipe.
		/// </para>
		/// <para>This parameter can also be a handle to an anonymous pipe, as returned by the <c>CreatePipe</c> function.</para>
		/// </param>
		/// <param name="lpMode">
		/// <para>
		/// The new pipe mode. The mode is a combination of a read-mode flag and a wait-mode flag. This parameter can be <c>NULL</c> if the
		/// mode is not being set. Specify one of the following modes.
		/// </para>
		/// <para>
		/// <list type="table">
		/// <listheader>
		/// <term>Mode</term>
		/// <term>Meaning</term>
		/// </listheader>
		/// <item>
		/// <term>PIPE_READMODE_BYTE0x00000000</term>
		/// <term>Data is read from the pipe as a stream of bytes. This mode is the default if no read-mode flag is specified.</term>
		/// </item>
		/// <item>
		/// <term>PIPE_READMODE_MESSAGE0x00000002</term>
		/// <term>Data is read from the pipe as a stream of messages. The function fails if this flag is specified for a byte-type pipe.</term>
		/// </item>
		/// </list>
		/// </para>
		/// <para>One of the following wait modes can be specified.</para>
		/// <para>
		/// <list type="table">
		/// <listheader>
		/// <term>Mode</term>
		/// <term>Meaning</term>
		/// </listheader>
		/// <item>
		/// <term>PIPE_WAIT0x00000000</term>
		/// <term>
		/// Blocking mode is enabled. This mode is the default if no wait-mode flag is specified. When a blocking mode pipe handle is
		/// specified in the ReadFile, WriteFile, or ConnectNamedPipe function, operations are not finished until there is data to read, all
		/// data is written, or a client is connected. Use of this mode can mean waiting indefinitely in some situations for a client process
		/// to perform an action.
		/// </term>
		/// </item>
		/// <item>
		/// <term>PIPE_NOWAIT0x00000001</term>
		/// <term>
		/// Nonblocking mode is enabled. In this mode, ReadFile, WriteFile, and ConnectNamedPipe always return immediately. Note that
		/// nonblocking mode is supported for compatibility with Microsoft LAN Manager version 2.0 and should not be used to achieve
		/// asynchronous input and output (I/O) with named pipes.
		/// </term>
		/// </item>
		/// </list>
		/// </para>
		/// </param>
		/// <param name="lpMaxCollectionCount">
		/// The maximum number of bytes collected on the client computer before transmission to the server. This parameter must be
		/// <c>NULL</c> if the specified pipe handle is to the server end of a named pipe or if client and server processes are on the same
		/// machine. This parameter is ignored if the client process specifies the FILE_FLAG_WRITE_THROUGH flag in the <c>CreateFile</c>
		/// function when the handle was created. This parameter can be <c>NULL</c> if the collection count is not being set.
		/// </param>
		/// <param name="lpCollectDataTimeout">
		/// The maximum time, in milliseconds, that can pass before a remote named pipe transfers information over the network. This
		/// parameter must be <c>NULL</c> if the specified pipe handle is to the server end of a named pipe or if client and server processes
		/// are on the same computer. This parameter is ignored if the client process specified the FILE_FLAG_WRITE_THROUGH flag in the
		/// <c>CreateFile</c> function when the handle was created. This parameter can be <c>NULL</c> if the collection count is not being set.
		/// </param>
		/// <returns>
		/// <para>If the function succeeds, the return value is nonzero.</para>
		/// <para>If the function fails, the return value is zero. To get extended error information, call <c>GetLastError</c>.</para>
		/// </returns>
		// BOOL WINAPI SetNamedPipeHandleState( _In_ HANDLE hNamedPipe, _In_opt_ LPDWORD lpMode, _In_opt_ LPDWORD lpMaxCollectionCount,
		// _In_opt_ LPDWORD lpCollectDataTimeout); https://msdn.microsoft.com/en-us/library/windows/desktop/aa365787(v=vs.85).aspx
		[DllImport(Lib.Kernel32, SetLastError = true, ExactSpelling = true)]
		[PInvokeData("namedpipeapi.h", MSDNShortId = "aa365787")]
		[return: MarshalAs(UnmanagedType.Bool)]
		public static extern bool SetNamedPipeHandleState([In] HPIPE hNamedPipe, [In] in uint lpMode, [In] in uint lpMaxCollectionCount, [In] in uint lpCollectDataTimeout);

		/// <summary>
		/// Sets the read mode and the blocking mode of the specified named pipe. If the specified handle is to the client end of a named
		/// pipe and if the named pipe server process is on a remote computer, the function can also be used to control local buffering.
		/// </summary>
		/// <param name="hNamedPipe">
		/// <para>
		/// A handle to the named pipe instance. This parameter can be a handle to the server end of the pipe, as returned by the
		/// <c>CreateNamedPipe</c> function, or to the client end of the pipe, as returned by the <c>CreateFile</c> function. The handle must
		/// have GENERIC_WRITE access to the named pipe for a write-only or read/write pipe, or it must have GENERIC_READ and
		/// FILE_WRITE_ATTRIBUTES access for a read-only pipe.
		/// </para>
		/// <para>This parameter can also be a handle to an anonymous pipe, as returned by the <c>CreatePipe</c> function.</para>
		/// </param>
		/// <param name="lpMode">
		/// <para>
		/// The new pipe mode. The mode is a combination of a read-mode flag and a wait-mode flag. This parameter can be <c>NULL</c> if the
		/// mode is not being set. Specify one of the following modes.
		/// </para>
		/// <para>
		/// <list type="table">
		/// <listheader>
		/// <term>Mode</term>
		/// <term>Meaning</term>
		/// </listheader>
		/// <item>
		/// <term>PIPE_READMODE_BYTE0x00000000</term>
		/// <term>Data is read from the pipe as a stream of bytes. This mode is the default if no read-mode flag is specified.</term>
		/// </item>
		/// <item>
		/// <term>PIPE_READMODE_MESSAGE0x00000002</term>
		/// <term>Data is read from the pipe as a stream of messages. The function fails if this flag is specified for a byte-type pipe.</term>
		/// </item>
		/// </list>
		/// </para>
		/// <para>One of the following wait modes can be specified.</para>
		/// <para>
		/// <list type="table">
		/// <listheader>
		/// <term>Mode</term>
		/// <term>Meaning</term>
		/// </listheader>
		/// <item>
		/// <term>PIPE_WAIT0x00000000</term>
		/// <term>
		/// Blocking mode is enabled. This mode is the default if no wait-mode flag is specified. When a blocking mode pipe handle is
		/// specified in the ReadFile, WriteFile, or ConnectNamedPipe function, operations are not finished until there is data to read, all
		/// data is written, or a client is connected. Use of this mode can mean waiting indefinitely in some situations for a client process
		/// to perform an action.
		/// </term>
		/// </item>
		/// <item>
		/// <term>PIPE_NOWAIT0x00000001</term>
		/// <term>
		/// Nonblocking mode is enabled. In this mode, ReadFile, WriteFile, and ConnectNamedPipe always return immediately. Note that
		/// nonblocking mode is supported for compatibility with Microsoft LAN Manager version 2.0 and should not be used to achieve
		/// asynchronous input and output (I/O) with named pipes.
		/// </term>
		/// </item>
		/// </list>
		/// </para>
		/// </param>
		/// <param name="lpMaxCollectionCount">
		/// The maximum number of bytes collected on the client computer before transmission to the server. This parameter must be
		/// <c>NULL</c> if the specified pipe handle is to the server end of a named pipe or if client and server processes are on the same
		/// machine. This parameter is ignored if the client process specifies the FILE_FLAG_WRITE_THROUGH flag in the <c>CreateFile</c>
		/// function when the handle was created. This parameter can be <c>NULL</c> if the collection count is not being set.
		/// </param>
		/// <param name="lpCollectDataTimeout">
		/// The maximum time, in milliseconds, that can pass before a remote named pipe transfers information over the network. This
		/// parameter must be <c>NULL</c> if the specified pipe handle is to the server end of a named pipe or if client and server processes
		/// are on the same computer. This parameter is ignored if the client process specified the FILE_FLAG_WRITE_THROUGH flag in the
		/// <c>CreateFile</c> function when the handle was created. This parameter can be <c>NULL</c> if the collection count is not being set.
		/// </param>
		/// <returns>
		/// <para>If the function succeeds, the return value is nonzero.</para>
		/// <para>If the function fails, the return value is zero. To get extended error information, call <c>GetLastError</c>.</para>
		/// </returns>
		// BOOL WINAPI SetNamedPipeHandleState( _In_ HANDLE hNamedPipe, _In_opt_ LPDWORD lpMode, _In_opt_ LPDWORD lpMaxCollectionCount,
		// _In_opt_ LPDWORD lpCollectDataTimeout); https://msdn.microsoft.com/en-us/library/windows/desktop/aa365787(v=vs.85).aspx
		[DllImport(Lib.Kernel32, SetLastError = true, ExactSpelling = true)]
		[PInvokeData("namedpipeapi.h", MSDNShortId = "aa365787")]
		[return: MarshalAs(UnmanagedType.Bool)]
		public static extern bool SetNamedPipeHandleState([In] HPIPE hNamedPipe, [In, Optional] IntPtr lpMode, [In, Optional] IntPtr lpMaxCollectionCount, [In, Optional] IntPtr lpCollectDataTimeout);

		/// <summary>
		/// Combines the functions that write a message to and read a message from the specified named pipe into a single network operation.
		/// </summary>
		/// <param name="hNamedPipe">
		/// <para>A handle to the named pipe returned by the <c>CreateNamedPipe</c> or <c>CreateFile</c> function.</para>
		/// <para>This parameter can also be a handle to an anonymous pipe, as returned by the <c>CreatePipe</c> function.</para>
		/// </param>
		/// <param name="lpInBuffer">A pointer to the buffer containing the data to be written to the pipe.</param>
		/// <param name="nInBufferSize">The size of the input buffer, in bytes.</param>
		/// <param name="lpOutBuffer">A pointer to the buffer that receives the data read from the pipe.</param>
		/// <param name="nOutBufferSize">The size of the output buffer, in bytes.</param>
		/// <param name="lpBytesRead">
		/// <para>A pointer to the variable that receives the number of bytes read from the pipe.</para>
		/// <para>If lpOverlapped is <c>NULL</c>, lpBytesRead cannot be <c>NULL</c>.</para>
		/// <para>
		/// If lpOverlapped is not <c>NULL</c>, lpBytesRead can be <c>NULL</c>. If this is an overlapped read operation, you can get the
		/// number of bytes read by calling <c>GetOverlappedResult</c>. If hNamedPipe is associated with an I/O completion port, you can get
		/// the number of bytes read by calling <c>GetQueuedCompletionStatus</c>.
		/// </para>
		/// </param>
		/// <param name="lpOverlapped">
		/// <para>A pointer to an <c>OVERLAPPED</c> structure. This structure is required if hNamedPipe was opened with FILE_FLAG_OVERLAPPED.</para>
		/// <para>
		/// If hNamedPipe was opened with FILE_FLAG_OVERLAPPED, the lpOverlapped parameter must not be <c>NULL</c>. It must point to a valid
		/// <c>OVERLAPPED</c> structure. If hNamedPipe was created with FILE_FLAG_OVERLAPPED and lpOverlapped is <c>NULL</c>, the function
		/// can incorrectly report that the operation is complete.
		/// </para>
		/// <para>
		/// If hNamedPipe was opened with FILE_FLAG_OVERLAPPED and lpOverlapped is not <c>NULL</c>, <c>TransactNamedPipe</c> is executed as
		/// an overlapped operation. The <c>OVERLAPPED</c> structure should contain a manual-reset event object (which can be created by
		/// using the <c>CreateEvent</c> function). If the operation cannot be completed immediately, <c>TransactNamedPipe</c> returns
		/// <c>FALSE</c> and <c>GetLastError</c> returns ERROR_IO_PENDING. In this situation, the event object is set to the nonsignaled
		/// state before <c>TransactNamedPipe</c> returns, and it is set to the signaled state when the transaction has finished. Also, you
		/// can be notified when an overlapped operation completes by using the <c>GetQueuedCompletionStatus</c> or
		/// <c>GetQueuedCompletionStatusEx</c> functions. In this case, you do not need to assign the manual-reset event in the
		/// <c>OVERLAPPED</c> structure, and the completion happens against hNamedPipe in the same way as an asynchronous read or write
		/// operation. For more information about overlapped operations, see Pipes.
		/// </para>
		/// <para>
		/// If hNamedPipe was not opened with FILE_FLAG_OVERLAPPED, <c>TransactNamedPipe</c> does not return until the operation is complete.
		/// </para>
		/// </param>
		/// <returns>
		/// <para>If the function succeeds, the return value is nonzero.</para>
		/// <para>If the function fails, the return value is zero. To get extended error information, call <c>GetLastError</c>.</para>
		/// <para>
		/// If the message to be read is longer than the buffer specified by the nOutBufferSize parameter, <c>TransactNamedPipe</c> returns
		/// <c>FALSE</c> and the <c>GetLastError</c> function returns ERROR_MORE_DATA. The remainder of the message can be read by a
		/// subsequent call to <c>ReadFile</c>, <c>ReadFileEx</c>, or <c>PeekNamedPipe</c>.
		/// </para>
		/// </returns>
		// BOOL WINAPI TransactNamedPipe( _In_ HANDLE hNamedPipe, _In_ LPVOID lpInBuffer, _In_ DWORD nInBufferSize, _Out_ LPVOID lpOutBuffer,
		// _In_ DWORD nOutBufferSize, _Out_ LPDWORD lpBytesRead, _Inout_opt_ LPOVERLAPPED lpOverlapped); https://msdn.microsoft.com/en-us/library/windows/desktop/aa365790(v=vs.85).aspx
		[DllImport(Lib.Kernel32, SetLastError = true, ExactSpelling = true)]
		[PInvokeData("Winbase.h", MSDNShortId = "aa365790")]
		[return: MarshalAs(UnmanagedType.Bool)]
		public static extern unsafe bool TransactNamedPipe([In] HPIPE hNamedPipe, [In] IntPtr lpInBuffer, uint nInBufferSize, IntPtr lpOutBuffer, uint nOutBufferSize, [Out] out uint lpBytesRead,
			[Optional] NativeOverlapped* lpOverlapped);

		/// <summary>
		/// Waits until either a time-out interval elapses or an instance of the specified named pipe is available for connection (that is,
		/// the pipe's server process has a pending <c>ConnectNamedPipe</c> operation on the pipe).
		/// </summary>
		/// <param name="lpNamedPipeName">
		/// <para>
		/// The name of the named pipe. The string must include the name of the computer on which the server process is executing. A period
		/// may be used for the servername if the pipe is local. The following pipe name format is used:
		/// </para>
		/// <para>\\servername\pipe\pipename</para>
		/// </param>
		/// <param name="nTimeOut">
		/// <para>
		/// The number of milliseconds that the function will wait for an instance of the named pipe to be available. You can used one of the
		/// following values instead of specifying a number of milliseconds.
		/// </para>
		/// <para>
		/// <list type="table">
		/// <listheader>
		/// <term>Value</term>
		/// <term>Meaning</term>
		/// </listheader>
		/// <item>
		/// <term>NMPWAIT_USE_DEFAULT_WAIT0x00000000</term>
		/// <term>The time-out interval is the default value specified by the server process in the CreateNamedPipe function.</term>
		/// </item>
		/// <item>
		/// <term>NMPWAIT_WAIT_FOREVER0xffffffff</term>
		/// <term>The function does not return until an instance of the named pipe is available.</term>
		/// </item>
		/// </list>
		/// </para>
		/// </param>
		/// <returns>
		/// <para>If an instance of the pipe is available before the time-out interval elapses, the return value is nonzero.</para>
		/// <para>
		/// If an instance of the pipe is not available before the time-out interval elapses, the return value is zero. To get extended error
		/// information, call <c>GetLastError</c>.
		/// </para>
		/// </returns>
		// BOOL WINAPI WaitNamedPipe( _In_ LPCTSTR lpNamedPipeName, _In_ DWORD nTimeOut); https://msdn.microsoft.com/en-us/library/windows/desktop/aa365800(v=vs.85).aspx
		[DllImport(Lib.Kernel32, SetLastError = true, CharSet = CharSet.Auto)]
		[PInvokeData("namedpipeapi.h", MSDNShortId = "aa365800")]
		[return: MarshalAs(UnmanagedType.Bool)]
		public static extern bool WaitNamedPipe(string lpNamedPipeName, uint nTimeOut);

		/// <summary>Provides a handle to a pipe.</summary>
		[StructLayout(LayoutKind.Sequential)]
		public struct HPIPE : IKernelHandle
		{
			private IntPtr handle;

			/// <summary>Initializes a new instance of the <see cref="HPIPE"/> struct.</summary>
			/// <param name="preexistingHandle">An <see cref="IntPtr"/> object that represents the pre-existing handle to use.</param>
			public HPIPE(IntPtr preexistingHandle) => handle = preexistingHandle;

			/// <summary>Returns an invalid handle by instantiating a <see cref="HPIPE"/> object with <see cref="IntPtr.Zero"/>.</summary>
			public static HPIPE NULL => new HPIPE(IntPtr.Zero);

			/// <summary>Gets a value indicating whether this instance is a null handle.</summary>
			public bool IsNull => handle == IntPtr.Zero;

			/// <summary>Performs an explicit conversion from <see cref="HPIPE"/> to <see cref="IntPtr"/>.</summary>
			/// <param name="h">The handle.</param>
			/// <returns>The result of the conversion.</returns>
			public static explicit operator IntPtr(HPIPE h) => h.handle;

			/// <summary>Performs an implicit conversion from <see cref="IntPtr"/> to <see cref="HPIPE"/>.</summary>
			/// <param name="h">The pointer to a handle.</param>
			/// <returns>The result of the conversion.</returns>
			public static implicit operator HPIPE(IntPtr h) => new HPIPE(h);

			/// <summary>Performs an implicit conversion from <see cref="IntPtr"/> to <see cref="HPIPE"/>.</summary>
			/// <param name="h">The pointer to a handle.</param>
			/// <returns>The result of the conversion.</returns>
			public static implicit operator HFILE(HPIPE h) => h.handle;

			/// <summary>Implements the operator !=.</summary>
			/// <param name="h1">The first handle.</param>
			/// <param name="h2">The second handle.</param>
			/// <returns>The result of the operator.</returns>
			public static bool operator !=(HPIPE h1, HPIPE h2) => !(h1 == h2);

			/// <summary>Implements the operator ==.</summary>
			/// <param name="h1">The first handle.</param>
			/// <param name="h2">The second handle.</param>
			/// <returns>The result of the operator.</returns>
			public static bool operator ==(HPIPE h1, HPIPE h2) => h1.Equals(h2);

			/// <inheritdoc/>
			public override bool Equals(object obj) => obj is HPIPE h ? handle == h.handle : false;

			/// <inheritdoc/>
			public override int GetHashCode() => handle.GetHashCode();

			/// <inheritdoc/>
			public IntPtr DangerousGetHandle() => handle;
		}

		/// <summary>Provides a <see cref="SafeHandle"/> for <see cref="HPIPE"/> that is disposed using <see cref="CloseHandle"/>.</summary>
		public class SafeHPIPE : SafeHFILE
		{
			/// <summary>Initializes a new instance of the <see cref="SafeHPIPE"/> class and assigns an existing handle.</summary>
			/// <param name="preexistingHandle">An <see cref="IntPtr"/> object that represents the pre-existing handle to use.</param>
			/// <param name="ownsHandle"><see langword="true"/> to reliably release the handle during the finalization phase; otherwise, <see langword="false"/> (not recommended).</param>
			public SafeHPIPE(IntPtr preexistingHandle, bool ownsHandle = true) : base(preexistingHandle, ownsHandle) { }

			/// <summary>Initializes a new instance of the <see cref="SafeHPIPE"/> class.</summary>
			private SafeHPIPE() : base() { }

			/// <summary>Performs an implicit conversion from <see cref="SafeHPIPE"/> to <see cref="HPIPE"/>.</summary>
			/// <param name="h">The safe handle instance.</param>
			/// <returns>The result of the conversion.</returns>
			public static implicit operator HPIPE(SafeHPIPE h) => h.handle;

			/// <summary>Performs an implicit conversion from <see cref="SafeHPIPE"/> to <see cref="HPIPE"/>.</summary>
			/// <param name="h">The safe handle instance.</param>
			/// <returns>The result of the conversion.</returns>
			public static implicit operator HFILE(SafeHPIPE h) => h.handle;
		}
	}
}