diff --git a/extern/w32/namedpipes/AppModule.InterProcessComm.dll b/extern/w32/namedpipes/AppModule.InterProcessComm.dll deleted file mode 100644 index 968c219f..00000000 Binary files a/extern/w32/namedpipes/AppModule.InterProcessComm.dll and /dev/null differ diff --git a/extern/w32/namedpipes/AppModule.InterProcessComm/AppModule.InterProcessComm.csproj b/extern/w32/namedpipes/AppModule.InterProcessComm/AppModule.InterProcessComm.csproj new file mode 100644 index 00000000..e3483eb3 --- /dev/null +++ b/extern/w32/namedpipes/AppModule.InterProcessComm/AppModule.InterProcessComm.csproj @@ -0,0 +1,120 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/extern/w32/namedpipes/AppModule.InterProcessComm/AppModule.InterProcessComm.csproj.user b/extern/w32/namedpipes/AppModule.InterProcessComm/AppModule.InterProcessComm.csproj.user new file mode 100644 index 00000000..53b5d76a --- /dev/null +++ b/extern/w32/namedpipes/AppModule.InterProcessComm/AppModule.InterProcessComm.csproj.user @@ -0,0 +1,48 @@ + + + + + + + + + + + + diff --git a/extern/w32/namedpipes/AppModule.InterProcessComm/AppModule.InterProcessComm.xml b/extern/w32/namedpipes/AppModule.InterProcessComm/AppModule.InterProcessComm.xml new file mode 100644 index 00000000..72cf09ae --- /dev/null +++ b/extern/w32/namedpipes/AppModule.InterProcessComm/AppModule.InterProcessComm.xml @@ -0,0 +1,263 @@ + + + + AppModule.InterProcessComm + + + + + Interface, which defines methods for a Channel Manager class. + + + A Channel Manager is responsible for creating and maintaining channels for inter-process communication. The opened channels are meant to be reusable for performance optimization. Each channel needs to procees requests by calling the HandleRequest method of the Channel Manager. + + + + + Initializes the Channel Manager. + + + + + Closes all opened channels and stops the Channel Manager. + + + + + Handles a request. + + + This method currently caters for text based requests. XML strings can be used in case complex request structures are needed. + + The incoming request. + The resulting response. + + + + Forces the Channel Manager to exit a sleeping mode and create a new channel. + + + Normally the Channel Manager will create a number of reusable channels, which will handle the incoming reqiests, and go into a sleeping mode. However if the request load is high, the Channel Manager needs to be asked to create additional channels. + + + + + Removes an existing channel. + + A parameter identifying the channel. + + + + Indicates whether the Channel Manager is in listening mode. + + + This property is left public so that other classes, like a server channel can start or stop listening based on the Channel Manager mode. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/extern/w32/namedpipes/AppModule.InterProcessComm/AssemblyInfo.cs b/extern/w32/namedpipes/AppModule.InterProcessComm/AssemblyInfo.cs new file mode 100644 index 00000000..e29b4fd9 --- /dev/null +++ b/extern/w32/namedpipes/AppModule.InterProcessComm/AssemblyInfo.cs @@ -0,0 +1,55 @@ +using System.Reflection; +using System.Runtime.CompilerServices; + +// +// General Information about an assembly is controlled through the following +// set of attributes. Change these attribute values to modify the information +// associated with an assembly. +// +[assembly: AssemblyTitle("AppModule.InterProcessComm")] +[assembly: AssemblyDescription("Inter Process Communication")] +[assembly: AssemblyConfiguration("")] +[assembly: AssemblyCompany("Ivan Latunov")] +[assembly: AssemblyProduct("Inter Process Communication")] +[assembly: AssemblyCopyright("Ivan Latunov")] +[assembly: AssemblyTrademark("")] +[assembly: AssemblyCulture("")] + +// +// Version information for an assembly consists of the following four values: +// +// Major Version +// Minor Version +// Build Number +// Revision +// +// You can specify all the values or you can default the Revision and Build Numbers +// by using the '*' as shown below: + +[assembly: AssemblyVersion("1.6.0.*")] + +// +// In order to sign your assembly you must specify a key to use. Refer to the +// Microsoft .NET Framework documentation for more information on assembly signing. +// +// Use the attributes below to control which key is used for signing. +// +// Notes: +// (*) If no key is specified, the assembly is not signed. +// (*) KeyName refers to a key that has been installed in the Crypto Service +// Provider (CSP) on your machine. KeyFile refers to a file which contains +// a key. +// (*) If the KeyFile and the KeyName values are both specified, the +// following processing occurs: +// (1) If the KeyName can be found in the CSP, that key is used. +// (2) If the KeyName does not exist and the KeyFile does exist, the key +// in the KeyFile is installed into the CSP and used. +// (*) In order to create a KeyFile, you can use the sn.exe (Strong Name) utility. +// When specifying the KeyFile, the location of the KeyFile should be +// relative to the project output directory which is +// %Project Directory%\obj\. For example, if your KeyFile is +// located in the project directory, you would specify the AssemblyKeyFile +// attribute as [assembly: AssemblyKeyFile("..\\..\\mykey.snk")] +// (*) Delay Signing is an advanced option - see the Microsoft .NET Framework +// documentation for more information on this. +// \ No newline at end of file diff --git a/extern/w32/namedpipes/AppModule.InterProcessComm/IChannelManager.cs b/extern/w32/namedpipes/AppModule.InterProcessComm/IChannelManager.cs new file mode 100644 index 00000000..9892ec68 --- /dev/null +++ b/extern/w32/namedpipes/AppModule.InterProcessComm/IChannelManager.cs @@ -0,0 +1,63 @@ +using System; + +namespace AppModule.InterProcessComm { + #region Comments + /// + /// Interface, which defines methods for a Channel Manager class. + /// + /// + /// A Channel Manager is responsible for creating and maintaining channels for inter-process communication. The opened channels are meant to be reusable for performance optimization. Each channel needs to procees requests by calling the HandleRequest method of the Channel Manager. + /// + #endregion + public interface IChannelManager { + #region Comments + /// + /// Initializes the Channel Manager. + /// + #endregion + void Initialize(); + void Start(); + #region Comments + /// + /// Closes all opened channels and stops the Channel Manager. + /// + #endregion + void Stop(); + #region Comments + /// + /// Handles a request. + /// + /// + /// This method currently caters for text based requests. XML strings can be used in case complex request structures are needed. + /// + /// The incoming request. + /// The resulting response. + #endregion + string HandleRequest(string request); + #region Comments + /// + /// Indicates whether the Channel Manager is in listening mode. + /// + /// + /// This property is left public so that other classes, like a server channel can start or stop listening based on the Channel Manager mode. + /// + #endregion + bool Listen {get; set;} + #region Comments + /// + /// Forces the Channel Manager to exit a sleeping mode and create a new channel. + /// + /// + /// Normally the Channel Manager will create a number of reusable channels, which will handle the incoming reqiests, and go into a sleeping mode. However if the request load is high, the Channel Manager needs to be asked to create additional channels. + /// + #endregion + void WakeUp(); + #region Comments + /// + /// Removes an existing channel. + /// + /// A parameter identifying the channel. + #endregion + void RemoveServerChannel(object param); + } +} diff --git a/extern/w32/namedpipes/AppModule.InterProcessComm/IClientChannel.cs b/extern/w32/namedpipes/AppModule.InterProcessComm/IClientChannel.cs new file mode 100644 index 00000000..68b4793f --- /dev/null +++ b/extern/w32/namedpipes/AppModule.InterProcessComm/IClientChannel.cs @@ -0,0 +1,43 @@ +using System; +using System.IO; + +namespace AppModule.InterProcessComm { + #region Comments + /// + /// + /// + #endregion + public interface IClientChannel : IDisposable { + #region Comments + /// + /// + /// + /// + /// + #endregion + string HandleRequest(string request); + #region Comments + /// + /// + /// + /// + /// + #endregion + string HandleRequest(Stream request); + #region Comments + /// + /// + /// + /// + /// + #endregion + object HandleRequest(object request); + #region Comments + /// + /// + /// + /// + #endregion + IClientChannel Create(); + } +} \ No newline at end of file diff --git a/extern/w32/namedpipes/AppModule.InterProcessComm/IInterProcessConnection.cs b/extern/w32/namedpipes/AppModule.InterProcessComm/IInterProcessConnection.cs new file mode 100644 index 00000000..d00b593e --- /dev/null +++ b/extern/w32/namedpipes/AppModule.InterProcessComm/IInterProcessConnection.cs @@ -0,0 +1,64 @@ +using System; + +namespace AppModule.InterProcessComm { + #region Comments + /// + /// + /// + #endregion + public interface IInterProcessConnection : IDisposable { + #region Comments + /// + /// + /// + #endregion + int NativeHandle{get;} + #region Comments + /// + /// + /// + #endregion + void Connect(); + #region Comments + /// + /// + /// + #endregion + void Close(); + #region Comments + /// + /// + /// + /// + #endregion + string Read(); + #region Comments + /// + /// + /// + /// + #endregion + byte[] ReadBytes(); + #region Comments + /// + /// + /// + /// + #endregion + void Write(string text); + #region Comments + /// + /// + /// + /// + #endregion + void WriteBytes(byte[] bytes); + #region Comments + /// + /// + /// + /// + #endregion + InterProcessConnectionState GetState(); + } +} \ No newline at end of file diff --git a/extern/w32/namedpipes/AppModule.InterProcessComm/InterProcessConnectionState.cs b/extern/w32/namedpipes/AppModule.InterProcessComm/InterProcessConnectionState.cs new file mode 100644 index 00000000..fd3bde89 --- /dev/null +++ b/extern/w32/namedpipes/AppModule.InterProcessComm/InterProcessConnectionState.cs @@ -0,0 +1,119 @@ +using System; + +namespace AppModule.InterProcessComm { + #region Comments + /// + /// + /// + #endregion + public enum InterProcessConnectionState { + #region Comments + /// + /// + /// + #endregion + NotSet = 0, + #region Comments + /// + /// + /// + #endregion + Error = 1, + #region Comments + /// + /// + /// + #endregion + Creating = 2, + #region Comments + /// + /// + /// + #endregion + Created = 3, + #region Comments + /// + /// + /// + #endregion + WaitingForClient = 4, + #region Comments + /// + /// + /// + #endregion + ConnectedToClient = 5, + #region Comments + /// + /// + /// + #endregion + ConnectingToServer = 6, + #region Comments + /// + /// + /// + #endregion + ConnectedToServer = 7, + #region Comments + /// + /// + /// + #endregion + Reading = 8, + #region Comments + /// + /// + /// + #endregion + ReadData = 9, + #region Comments + /// + /// + /// + #endregion + Writing = 10, + #region Comments + /// + /// + /// + #endregion + WroteData = 11, + #region Comments + /// + /// + /// + #endregion + Flushing = 12, + #region Comments + /// + /// + /// + #endregion + FlushedData = 13, + #region Comments + /// + /// + /// + #endregion + Disconnecting = 14, + #region Comments + /// + /// + /// + #endregion + Disconnected = 15, + #region Comments + /// + /// + /// + #endregion + Closing = 16, + #region Comments + /// + /// + /// + #endregion + Closed = 17, + } +} \ No newline at end of file diff --git a/extern/w32/namedpipes/AppModule.InterProcessComm/InterProcessIOException.cs b/extern/w32/namedpipes/AppModule.InterProcessComm/InterProcessIOException.cs new file mode 100644 index 00000000..dffab535 --- /dev/null +++ b/extern/w32/namedpipes/AppModule.InterProcessComm/InterProcessIOException.cs @@ -0,0 +1,41 @@ +using System; +using System.Runtime.Serialization; + +namespace AppModule.InterProcessComm { + #region Comments + /// + /// + /// + #endregion + public class InterProcessIOException : Exception { + #region Comments + /// + /// + /// + #endregion + public bool IsServerAvailable = true; + #region Comments + /// + /// + /// + #endregion + public uint ErrorCode = 0; + #region Comments + /// + /// + /// + /// + #endregion + public InterProcessIOException(String text) : base(text) { + } + #region Comments + /// + /// + /// + /// + /// + #endregion + protected InterProcessIOException(SerializationInfo info, StreamingContext context) : base(info, context) { + } + } +} diff --git a/extern/w32/namedpipes/AppModule.NamedPipes.dll b/extern/w32/namedpipes/AppModule.NamedPipes.dll deleted file mode 100644 index 7cc9478f..00000000 Binary files a/extern/w32/namedpipes/AppModule.NamedPipes.dll and /dev/null differ diff --git a/extern/w32/namedpipes/AppModule.NamedPipes/APipeConnection.cs b/extern/w32/namedpipes/AppModule.NamedPipes/APipeConnection.cs new file mode 100644 index 00000000..8c7d9761 --- /dev/null +++ b/extern/w32/namedpipes/AppModule.NamedPipes/APipeConnection.cs @@ -0,0 +1,175 @@ +using System; +using System.IO; +using AppModule.InterProcessComm; + +namespace AppModule.NamedPipes { + #region Comments + /// + /// An abstract class, which defines the methods for creating named pipes + /// connections, reading and writing data. + /// + /// + /// This class is inherited by + /// ClientPipeConnection + /// and ServerPipeConnection + /// classes, used for client and server applications respectively, which communicate + /// using NamesPipes. + /// + #endregion + public abstract class APipeConnection : IInterProcessConnection { + #region Comments + /// + /// A PipeHandle object containing + /// the native pipe handle. + /// + #endregion + protected PipeHandle Handle = new PipeHandle(); + #region Comments + /// + /// The name of the named pipe. + /// + /// + /// This name is used for creating a server pipe and connecting client ones to it. + /// + #endregion + protected string Name; + #region Comments + /// + /// Boolean field used by the IDisposable implementation. + /// + #endregion + protected bool disposed = false; + #region Comments + /// + /// The maximum bytes that will be read from the pipe connection. + /// + /// + /// This field could be used if the maximum length of the client message + /// is known and we want to implement some security, which prevents the + /// server from reading larger messages. + /// + #endregion + protected int maxReadBytes; + #region Comments + /// + /// Reads a message from the pipe connection and converts it to a string + /// using the UTF8 encoding. + /// + /// + /// See the NamedPipeWrapper.Read + /// method for an explanation of the message format. + /// + /// The UTF8 encoded string representation of the data. + #endregion + public string Read() { + CheckIfDisposed(); + return NamedPipeWrapper.Read(Handle, maxReadBytes); + } + #region Comments + /// + /// Reads a message from the pipe connection. + /// + /// + /// See the NamedPipeWrapper.ReadBytes + /// method for an explanation of the message format. + /// + /// The bytes read from the pipe connection. + #endregion + public byte[] ReadBytes() { + CheckIfDisposed(); + return NamedPipeWrapper.ReadBytes(Handle, maxReadBytes); + } + #region Comments + /// + /// Writes a string to the pipe connection/ + /// + /// The text to write. + #endregion + public void Write(string text) { + CheckIfDisposed(); + NamedPipeWrapper.Write(Handle, text); + } + #region Comments + /// + /// Writes an array of bytes to the pipe connection. + /// + /// The bytes array. + #endregion + public void WriteBytes(byte[] bytes) { + CheckIfDisposed(); + NamedPipeWrapper.WriteBytes(Handle, bytes); + } + #region Comments + /// + /// Closes the pipe connection. + /// + #endregion + public abstract void Close(); + #region Comments + /// + /// Connects a pipe connection. + /// + #endregion + public abstract void Connect(); + #region Comments + /// + /// Disposes a pipe connection by closing the underlying native handle. + /// + #endregion + public void Dispose() { + Dispose(true); + GC.SuppressFinalize(this); + } + #region Comments + /// + /// Disposes a pipe connection by closing the underlying native handle. + /// + /// A boolean indicating how the method is called. + #endregion + protected void Dispose(bool disposing) { + if(!this.disposed) { + NamedPipeWrapper.Close(this.Handle); + } + disposed = true; + } + #region Comments + /// + /// Checks if the pipe connection is disposed. + /// + /// + /// This check is done before performing any pipe operations. + /// + #endregion + public void CheckIfDisposed() { + if(this.disposed) { + throw new ObjectDisposedException("The Pipe Connection is disposed."); + } + } + #region Comments + /// + /// Gets the pipe connection state from the PipeHandle + /// object. + /// + /// The pipe connection state. + #endregion + public InterProcessConnectionState GetState() { + CheckIfDisposed(); + return this.Handle.State; + } + #region Comments + /// + /// Retrieved the operating system native handle for the pipe connection. + /// + #endregion + public int NativeHandle { + get { + CheckIfDisposed(); + return (int)this.Handle.Handle; + } + } + public int GetLocalUserID(ref int lowPart, ref int highPart, ref string sSIDString) + { + return ImpersonateWrapper.GetLocalUserID(this.Handle, ref lowPart, ref highPart, ref sSIDString); + } + } +} \ No newline at end of file diff --git a/extern/w32/namedpipes/AppModule.NamedPipes/AppModule.NamedPipes.csproj b/extern/w32/namedpipes/AppModule.NamedPipes/AppModule.NamedPipes.csproj new file mode 100644 index 00000000..ab9b7e4c --- /dev/null +++ b/extern/w32/namedpipes/AppModule.NamedPipes/AppModule.NamedPipes.csproj @@ -0,0 +1,145 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/extern/w32/namedpipes/AppModule.NamedPipes/AppModule.NamedPipes.csproj.user b/extern/w32/namedpipes/AppModule.NamedPipes/AppModule.NamedPipes.csproj.user new file mode 100644 index 00000000..56367003 --- /dev/null +++ b/extern/w32/namedpipes/AppModule.NamedPipes/AppModule.NamedPipes.csproj.user @@ -0,0 +1,48 @@ + + + + + + + + + + + + diff --git a/extern/w32/namedpipes/AppModule.NamedPipes/AppModule.NamedPipes.xml b/extern/w32/namedpipes/AppModule.NamedPipes/AppModule.NamedPipes.xml new file mode 100644 index 00000000..4c9dc960 --- /dev/null +++ b/extern/w32/namedpipes/AppModule.NamedPipes/AppModule.NamedPipes.xml @@ -0,0 +1,1160 @@ + + + + AppModule.NamedPipes + + + + + An abstract class, which defines the methods for creating named pipes + connections, reading and writing data. + + + This class is inherited by + ClientPipeConnection + and ServerPipeConnection + classes, used for client and server applications respectively, which communicate + using NamesPipes. + + + + + A PipeHandle object containing + the native pipe handle. + + + + + The name of the named pipe. + + + This name is used for creating a server pipe and connecting client ones to it. + + + + + Boolean field used by the IDisposable implementation. + + + + + The maximum bytes that will be read from the pipe connection. + + + This field could be used if the maximum length of the client message + is known and we want to implement some security, which prevents the + server from reading larger messages. + + + + + Reads a message from the pipe connection and converts it to a string + using the UTF8 encoding. + + + See the NamedPipeWrapper.Read + method for an explanation of the message format. + + The UTF8 encoded string representation of the data. + + + + Reads a message from the pipe connection. + + + See the NamedPipeWrapper.ReadBytes + method for an explanation of the message format. + + The bytes read from the pipe connection. + + + + Writes a string to the pipe connection/ + + The text to write. + + + + Writes an array of bytes to the pipe connection. + + The bytes array. + + + + Closes the pipe connection. + + + + + Connects a pipe connection. + + + + + Disposes a pipe connection by closing the underlying native handle. + + + + + Disposes a pipe connection by closing the underlying native handle. + + A boolean indicating how the method is called. + + + + Checks if the pipe connection is disposed. + + + This check is done before performing any pipe operations. + + + + + Gets the pipe connection state from the PipeHandle + object. + + The pipe connection state. + + + + Retrieved the operating system native handle for the pipe connection. + + + + + Used by client applications to communicate with server ones by using named pipes. + + + + + The network name of the server where the server pipe is created. + + + If "." is used as a server name then the pipe is connected to the local machine. + + + + + Closes a client named pipe connection. + + + A client pipe connection is closed by closing the underlying pipe handle. + + + + + Connects a client pipe to an existing server one. + + + + + Attempts to establish a connection to the a server named pipe. + + + If the attempt is successful the method creates the + PipeHandle object + and assigns it to the Handle + field.

+ This method is used when it is not known whether a server pipe already exists. +
+ True if a connection is established. +
+ + + Creates an instance of the ClientPipeConnection assuming that the server pipe + is created on the same machine. + + + The maximum bytes to read from the client is set to be Int32.MaxValue. + + The name of the server pipe. + + + + Creates an instance of the ClientPipeConnection specifying the network name + of the server. + + + The maximum bytes to read from the client is set to be Int32.MaxValue. + + The name of the server pipe. + The network name of the machine, where the server pipe is created. + + + + Object destructor. + + + + + This utility class exposes kernel32.dll methods for named pipes communication. + + + Use the following links for complete information about the exposed methods: + + + Named Pipe Functions + + + File Management Functions + + + Handle and Object Functions + + + System Error Codes + + + + + + + + + + + + Creates an instance of a named pipe and returns a handle for + subsequent pipe operations. + + Pointer to the null-terminated string that + uniquely identifies the pipe. + Pipe access mode, the overlapped mode, + the write-through mode, and the security access mode of the pipe handle. + Type, read, and wait modes of the pipe handle. + Maximum number of instances that can be + created for this pipe. + Number of bytes to reserve for the output buffer. + Number of bytes to reserve for the input buffer. + Default time-out value, in milliseconds. + Pointer to a + SecurityAttributes + object that specifies a security descriptor for the new named pipe. + If the function succeeds, the return value is a handle + to the server end of a named pipe instance. + + + + Enables a named pipe server process to wait for a client + process to connect to an instance of a named pipe. + + Handle to the server end of a named pipe instance. + Pointer to an + Overlapped object. + If the function succeeds, the return value is nonzero. + + + + 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. + + Pointer to a null-terminated string + specifying the pipe name. + Pointer to the buffer containing the data written + to the pipe. + Size of the write buffer, in bytes. + Pointer to the buffer that receives the data + read from the pipe. + Size of the read buffer, in bytes. + Pointer to a variable that receives the number + of bytes read from the pipe. + Number of milliseconds to wait for the + named pipe to be available. + If the function succeeds, the return value is nonzero. + + + + Creates or opens a file, directory, physical disk, volume, console buffer, + tape drive, communications resource, mailslot, or named pipe. + + Pointer to a null-terminated string that + specifies the name of the object to create or open. + Access to the object (reading, writing, or both). + Sharing mode of the object (reading, writing, both, or neither). + Pointer to a + SecurityAttributes + object that determines whether the returned handle can be inherited + by child processes. + Action to take on files that exist, + and which action to take when files do not exist. + File attributes and flags. + Handle to a template file, with the GENERIC_READ access right. + If the function succeeds, the return value is an open handle to the specified file. + + + + Reads data from a file, starting at the position indicated by the file pointer. + + Handle to the file to be read. + Pointer to the buffer that receives the data read from the file. + Number of bytes to be read from the file. + Pointer to the variable that receives the number of bytes read. + Pointer to an + Overlapped object. + The ReadFile function returns when one of the following + conditions is met: a write operation completes on the write end of + the pipe, the number of bytes requested has been read, or an error occurs. + + + + Writes data to a file at the position specified by the file pointer. + + Handle to the file. + Pointer to the buffer containing the data to be written to the file. + + Pointer to the variable that receives the number of bytes written. + Pointer to an + Overlapped object. + If the function succeeds, the return value is nonzero. + + + + Retrieves information about a specified named pipe. + + Handle to the named pipe for which information is wanted. + Pointer to a variable that indicates the current + state of the handle. + Pointer to a variable that receives the + number of current pipe instances. + Pointer to a variable that receives + the maximum number of bytes to be collected on the client's computer + before transmission to the server. + Pointer to a variable that receives + the maximum time, in milliseconds, that can pass before a remote named + pipe transfers information over the network. + Pointer to a buffer that receives the + null-terminated string containing the user name string associated + with the client application. + Size of the buffer specified by the + lpUserName parameter. + If the function succeeds, the return value is nonzero. + + + + Cancels all pending input and output (I/O) operations that were + issued by the calling thread for the specified file handle. + + Handle to a file. + If the function succeeds, the return value is nonzero. + + + + Waits until either a time-out interval elapses or an instance + of the specified named pipe is available for connection. + + Pointer to a null-terminated string that specifies + the name of the named pipe. + Number of milliseconds that the function will + wait for an instance of the named pipe to be available. + If an instance of the pipe is available before the + time-out interval elapses, the return value is nonzero. + + + + Retrieves the calling thread's last-error code value. + + The return value is the calling thread's last-error code value. + + + + Flushes the buffers of the specified file and causes all buffered data to be written to the file. + + Handle to an open file. + If the function succeeds, the return value is nonzero. + + + + Disconnects the server end of a named pipe instance from a client process. + + Handle to an instance of a named pipe. + If the function succeeds, the return value is nonzero. + + + + 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. + + Handle to the named pipe instance. + Pointer to a variable that supplies the new mode. + Pointer to a variable that specifies the maximum + number of bytes collected on the client computer before + transmission to the server. + Pointer to a variable that specifies the + maximum time, in milliseconds, that can pass before a remote + named pipe transfers information over the network. + If the function succeeds, the return value is nonzero. + + + + Closes an open object handle. + + Handle to an open object. + If the function succeeds, the return value is nonzero. + + + + Closes an open object handle. + + Handle to an open object. + If the function succeeds, the return value is nonzero. + + + + Sets the security descriptor attributes + + Reference to a SECURITY_DESCRIPTOR structure. + + + + + + + + Initializes a SECURITY_DESCRIPTOR structure. + + + + + + + + Private constructor. + + + + + A utility class that exposes named pipes operations. + + + This class uses the exposed exposed kernel32.dll methods by the + NamedPipeNative class + to provided controlled named pipe functionality. + + + + + This exception is thrown by named pipes communication methods. + + + + + Creates a NamedPipeIOException instance. + + The error message text. + + + + Creates a NamedPipeIOException instance. + + The error message text. + The native error code. + + + + Creates a NamedPipeIOException instance. + + The serialization information. + The streaming context. + + + + This utility class exposes kernel32.dll methods for named pipes communication. + + + Use the following links for complete information about the exposed methods: + + + Named Pipe Functions + + + File Management Functions + + + Handle and Object Functions + + + System Error Codes + + + + + + + Outbound pipe access. + + + + + Duplex pipe access. + + + + + Inbound pipe access. + + + + + Pipe blocking mode. + + + + + Pipe non-blocking mode. + + + + + Pipe read mode of type Byte. + + + + + Pipe read mode of type Message. + + + + + Byte pipe type. + + + + + Message pipe type. + + + + + Pipe client end. + + + + + Pipe server end. + + + + + Unlimited server pipe instances. + + + + + Waits indefinitely when connecting to a pipe. + + + + + Does not wait for the named pipe. + + + + + Uses the default time-out specified in a call to the CreateNamedPipe method. + + + + + + + + + + Generic write access to the pipe. + + + + + Generic execute access to the pipe. + + + + + Read, write, and execute access. + + + + + Create new file. Fails if the file exists. + + + + + Create new file. Overrides an existing file. + + + + + Open existing file. + + + + + Open existing file. If the file does not exist, creates it. + + + + + Opens the file and truncates it so that its size is zero bytes. + + + + + Invalid operating system handle. + + + + + The operation completed successfully. + + + + + The system cannot find the file specified. + + + + + All pipe instances are busy. + + + + + The pipe is being closed. + + + + + No process is on the other end of the pipe. + + + + + More data is available. + + + + + There is a process on other end of the pipe. + + + + + Waiting for a process to open the other end of the pipe. + + + + + Creates an instance of a named pipe and returns a handle for + subsequent pipe operations. + + Pointer to the null-terminated string that + uniquely identifies the pipe. + Pipe access mode, the overlapped mode, + the write-through mode, and the security access mode of the pipe handle. + Type, read, and wait modes of the pipe handle. + Maximum number of instances that can be + created for this pipe. + Number of bytes to reserve for the output buffer. + Number of bytes to reserve for the input buffer. + Default time-out value, in milliseconds. + Pointer to a + SECURITY_ATTRIBUTES + object that specifies a security descriptor for the new named pipe. + If the function succeeds, the return value is a handle + to the server end of a named pipe instance. + + + + Enables a named pipe server process to wait for a client + process to connect to an instance of a named pipe. + + Handle to the server end of a named pipe instance. + Pointer to an + Overlapped object. + If the function succeeds, the return value is nonzero. + + + + 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. + + Pointer to a null-terminated string + specifying the pipe name. + Pointer to the buffer containing the data written + to the pipe. + Size of the write buffer, in bytes. + Pointer to the buffer that receives the data + read from the pipe. + Size of the read buffer, in bytes. + Pointer to a variable that receives the number + of bytes read from the pipe. + Number of milliseconds to wait for the + named pipe to be available. + If the function succeeds, the return value is nonzero. + + + + Creates or opens a file, directory, physical disk, volume, console buffer, + tape drive, communications resource, mailslot, or named pipe. + + Pointer to a null-terminated string that + specifies the name of the object to create or open. + Access to the object (reading, writing, or both). + Sharing mode of the object (reading, writing, both, or neither). + Pointer to a + SecurityAttributes + object that determines whether the returned handle can be inherited + by child processes. + Action to take on files that exist, + and which action to take when files do not exist. + File attributes and flags. + Handle to a template file, with the GENERIC_READ access right. + If the function succeeds, the return value is an open handle to the specified file. + + + + Reads data from a file, starting at the position indicated by the file pointer. + + Handle to the file to be read. + Pointer to the buffer that receives the data read from the file. + Number of bytes to be read from the file. + Pointer to the variable that receives the number of bytes read. + Pointer to an + Overlapped object. + The ReadFile function returns when one of the following + conditions is met: a write operation completes on the write end of + the pipe, the number of bytes requested has been read, or an error occurs. + + + + Writes data to a file at the position specified by the file pointer. + + Handle to the file. + Pointer to the buffer containing the data to be written to the file. + + Pointer to the variable that receives the number of bytes written. + Pointer to an + Overlapped object. + If the function succeeds, the return value is nonzero. + + + + Retrieves information about a specified named pipe. + + Handle to the named pipe for which information is wanted. + Pointer to a variable that indicates the current + state of the handle. + Pointer to a variable that receives the + number of current pipe instances. + Pointer to a variable that receives + the maximum number of bytes to be collected on the client's computer + before transmission to the server. + Pointer to a variable that receives + the maximum time, in milliseconds, that can pass before a remote named + pipe transfers information over the network. + Pointer to a buffer that receives the + null-terminated string containing the user name string associated + with the client application. + Size of the buffer specified by the + lpUserName parameter. + If the function succeeds, the return value is nonzero. + + + + Cancels all pending input and output (I/O) operations that were + issued by the calling thread for the specified file handle. + + Handle to a file. + If the function succeeds, the return value is nonzero. + + + + Waits until either a time-out interval elapses or an instance + of the specified named pipe is available for connection. + + Pointer to a null-terminated string that specifies + the name of the named pipe. + Number of milliseconds that the function will + wait for an instance of the named pipe to be available. + If an instance of the pipe is available before the + time-out interval elapses, the return value is nonzero. + + + + Retrieves the calling thread's last-error code value. + + The return value is the calling thread's last-error code value. + + + + Flushes the buffers of the specified file and causes all buffered data to be written to the file. + + Handle to an open file. + If the function succeeds, the return value is nonzero. + + + + Disconnects the server end of a named pipe instance from a client process. + + Handle to an instance of a named pipe. + If the function succeeds, the return value is nonzero. + + + + 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. + + Handle to the named pipe instance. + Pointer to a variable that supplies the new mode. + Pointer to a variable that specifies the maximum + number of bytes collected on the client computer before + transmission to the server. + Pointer to a variable that specifies the + maximum time, in milliseconds, that can pass before a remote + named pipe transfers information over the network. + If the function succeeds, the return value is nonzero. + + + + Closes an open object handle. + + Handle to an open object. + If the function succeeds, the return value is nonzero. + + + + Sets the security descriptor attributes + + Reference to a SECURITY_DESCRIPTOR structure. + + + + + + + + Initializes a SECURITY_DESCRIPTOR structure. + + + + + + + + Private constructor. + + + + + Security Descriptor structure + + + + + Security Attributes structure. + + + + + This class is used as a dummy parameter only. + + + + + This class is used as a dummy parameter only. + + + + + A utility class that exposes named pipes operations. + + + This class uses the exposed exposed kernel32.dll methods by the + NamedPipeNative class + to provided controlled named pipe functionality. + + + + + The number of retries when creating a pipe or connecting to a pipe. + + + + + Wait time for the + NamedPipeNative.WaitNamedPipe + operation. + + + + + Reads a string from a named pipe using the UTF8 encoding. + + The pipe handle. + The maximum bytes to read. + A UTF8 string. + This function uses + AppModule.NamedPipes.ReadBytes + to read the bytes from the pipe and then converts them to string.

+ The first four bytes of the pipe data are expected to contain + the data length of the message. This method first reads those four + bytes and converts them to integer. It then continues to read from the pipe using + the extracted data length. +
+
+ + + Reads the bytes from a named pipe. + + The pipe handle. + The maximum bytes to read. + An array of bytes. + This method expects that the first four bytes in the pipe define + the length of the data to read. If the data length is greater than + maxBytes the method returns null.

+ The first four bytes of the pipe data are expected to contain + the data length of the message. This method first reads those four + bytes and converts them to integer. It then continues to read from the pipe using + the extracted data length. +
+
+ + + Writes a string to a named pipe. + + The pipe handle. + The text to write to the pipe. + This method converts the text into an array of bytes, using the + UTF8 encoding and the uses + AppModule.NamedPipes.WriteBytes + to write to the pipe.

+ When writing to a pipe the method first writes four bytes that define the data length. + It then writes the whole message.
+
+ + + Writes an array of bytes to a named pipe. + + The pipe handle. + The bytes to write. + If we try bytes array we attempt to write is empty then this method write a space character to the pipe. This is necessary because the other end of the pipe uses a blocking Read operation so we must write someting.

+ The bytes length is restricted by the maxBytes parameter, which is done primarily for security reasons.

+ When writing to a pipe the method first writes four bytes that define the data length. + It then writes the whole message.
+
+ + + Tries to connect to a named pipe on the same machine. + + The name of the pipe. + The resulting pipe handle. + Return true if the attempt succeeds. + This method is used mainly when stopping the pipe server. It unblocks the existing pipes, which wait for client connection. + + + + Tries to connect to a named pipe. + + The name of the pipe. + The name of the server. + The resulting pipe handle. + Return true if the attempt succeeds. + This method is used mainly when stopping the pipe server. It unblocks the existing pipes, which wait for client connection. + + + + Connects to a server named pipe on the same machine. + + The pipe name. + The pipe handle, which also contains the pipe state. + This method is used by clients to establish a pipe connection with a server pipe. + + + + Connects to a server named pipe. + + The pipe name. + The server name. + The pipe handle, which also contains the pipe state. + This method is used by clients to establish a pipe connection with a server pipe. + + + + Creates a server named pipe. + + The name of the pipe. + The size of the outbound buffer. + The size of the inbound buffer. + The pipe handle. + + + + Creates a server named pipe. + + The name of the pipe. + The size of the outbound buffer. + The size of the inbound buffer. + Specifies whether to make the pipe secure. + The pipe handle. + You can specify a security descriptor for a named pipe when you call the CreateNamedPipe function. The security descriptor controls access to both client and server ends of the named pipe. If NULL is specified, the named pipe gets a default security descriptor. 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. +

+ If the secure parameter is false the method creates a security descriptor that grants full access to Everyone. +
+
+ + + Creates a SECURITY_DESCRIPTOR with DACL = null, which allows full access to Everyone. + + The SECURITY_DESCRIPTOR structure. + + + + Starts waiting for client connections. + + + Blocks the current execution until a client pipe attempts to establish a connection. + + The pipe handle. + + + + Returns the number of instances of a named pipe. + + The pipe handle. + The number of instances. + + + + Closes a named pipe and releases the native handle. + + The pipe handle. + + + + Flushes all the data in a named pipe. + + The pipe handle. + + + + Disconnects a server named pipe from the client. + + + Server pipes can be reused by first disconnecting them from the client and then + calling the Connect + method to start listening. This improves the performance as it is not necessary + to create new pipe handles. + + The pipe handle. + + + + Private constructor. + + + + + Holds the operating system native handle and the current state of the pipe connection. + + + + + The operating system native handle. + + + + + The current state of the pipe connection. + + + + + Creates a PipeHandle instance using the passed native handle. + + The native handle. + + + + Creates a PipeHandle instance using the provided native handle and state. + + The native handle. + The state of the pipe connection. + + + + Creates a PipeHandle instance with an invalid native handle. + + + + + Used by server applications to communicate with client ones by using named pipes. + + + + + Disconnects a client named pipe. + + + When a client named pipe is disconnected, the server one is not closed. + The latter can later be reused by starting to listen again.

+ In a message oriented protocol the server will disconnect the client when the + response is sent and all the data is flushed. The same server named pipe + could then be reused by calling the + Connect method. +
+
+ + + Closes the operating system native handle of the named pipe. + + + + + Starts listening to client pipe connections. + + + This method will block the program execution until a client pipe attempts + to establish a connection.

+ When a client named pipe is disconnected, the server one is not closed. + The latter can later be reused by starting to listen again.

+
+
+ + + Creates a ServerPipeConnection instance and the underlying operating system handle. + + The name of the pipe. + The outbound buffer. + The inbound buffer. + The maximum bytes to read from clients. + + + + Creates a ServerPipeConnection instance and the underlying operating system handle. + + The name of the pipe. + The outbound buffer. + The inbound buffer. + Specifies whether the pipe is secure. + The maximum bytes to read from clients. + If the secure parameter is true the default security descriptor is used. 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. +

+ If the secure parameter is false the method creates a security descriptor that grants full access to Everyone. +
+
+ + + Object destructor. + + +
+
diff --git a/extern/w32/namedpipes/AppModule.NamedPipes/AssemblyInfo.cs b/extern/w32/namedpipes/AppModule.NamedPipes/AssemblyInfo.cs new file mode 100644 index 00000000..96413819 --- /dev/null +++ b/extern/w32/namedpipes/AppModule.NamedPipes/AssemblyInfo.cs @@ -0,0 +1,54 @@ +using System.Reflection; +using System.Runtime.CompilerServices; + +// +// General Information about an assembly is controlled through the following +// set of attributes. Change these attribute values to modify the information +// associated with an assembly. +[assembly: AssemblyTitle("AppModule.NamedPipes")] +[assembly: AssemblyDescription("Named Pipes Communication")] +[assembly: AssemblyConfiguration("")] +[assembly: AssemblyCompany("Ivan Latunov")] +[assembly: AssemblyProduct("Named Pipes")] +[assembly: AssemblyCopyright("Ivan Latunov")] +[assembly: AssemblyTrademark("")] +[assembly: AssemblyCulture("")] + +// +// Version information for an assembly consists of the following four values: +// +// Major Version +// Minor Version +// Build Number +// Revision +// +// You can specify all the values or you can default the Revision and Build Numbers +// by using the '*' as shown below: + +[assembly: AssemblyVersion("1.6.0.*")] + +// +// In order to sign your assembly you must specify a key to use. Refer to the +// Microsoft .NET Framework documentation for more information on assembly signing. +// +// Use the attributes below to control which key is used for signing. +// +// Notes: +// (*) If no key is specified, the assembly is not signed. +// (*) KeyName refers to a key that has been installed in the Crypto Service +// Provider (CSP) on your machine. KeyFile refers to a file which contains +// a key. +// (*) If the KeyFile and the KeyName values are both specified, the +// following processing occurs: +// (1) If the KeyName can be found in the CSP, that key is used. +// (2) If the KeyName does not exist and the KeyFile does exist, the key +// in the KeyFile is installed into the CSP and used. +// (*) In order to create a KeyFile, you can use the sn.exe (Strong Name) utility. +// When specifying the KeyFile, the location of the KeyFile should be +// relative to the project output directory which is +// %Project Directory%\obj\. For example, if your KeyFile is +// located in the project directory, you would specify the AssemblyKeyFile +// attribute as [assembly: AssemblyKeyFile("..\\..\\mykey.snk")] +// (*) Delay Signing is an advanced option - see the Microsoft .NET Framework +// documentation for more information on this. +// \ No newline at end of file diff --git a/extern/w32/namedpipes/AppModule.NamedPipes/ClientPipeConnection.cs b/extern/w32/namedpipes/AppModule.NamedPipes/ClientPipeConnection.cs new file mode 100644 index 00000000..707e9ef1 --- /dev/null +++ b/extern/w32/namedpipes/AppModule.NamedPipes/ClientPipeConnection.cs @@ -0,0 +1,102 @@ +using System; +using System.IO; + +using AppModule.InterProcessComm; + +namespace AppModule.NamedPipes { + #region Comments + /// + /// Used by client applications to communicate with server ones by using named pipes. + /// + #endregion + public sealed class ClientPipeConnection : APipeConnection { + #region Comments + /// + /// The network name of the server where the server pipe is created. + /// + /// + /// If "." is used as a server name then the pipe is connected to the local machine. + /// + #endregion + private string Server = "."; + #region Comments + /// + /// Closes a client named pipe connection. + /// + /// + /// A client pipe connection is closed by closing the underlying pipe handle. + /// + #endregion + public override void Close() { + CheckIfDisposed(); + NamedPipeWrapper.Close(this.Handle); + } + #region Comments + /// + /// Connects a client pipe to an existing server one. + /// + #endregion + public override void Connect() { + CheckIfDisposed(); + this.Handle = NamedPipeWrapper.ConnectToPipe(this.Name, this.Server); + } + #region Comments + /// + /// Attempts to establish a connection to the a server named pipe. + /// + /// + /// If the attempt is successful the method creates the + /// PipeHandle object + /// and assigns it to the Handle + /// field.

+ /// This method is used when it is not known whether a server pipe already exists. + ///
+ /// True if a connection is established. + #endregion + public bool TryConnect() { + CheckIfDisposed(); + bool ReturnVal = NamedPipeWrapper.TryConnectToPipe(this.Name, this.Server, out this.Handle); + + return ReturnVal; + } + #region Comments + /// + /// Creates an instance of the ClientPipeConnection assuming that the server pipe + /// is created on the same machine. + /// + /// + /// The maximum bytes to read from the client is set to be Int32.MaxValue. + /// + /// The name of the server pipe. + #endregion + public ClientPipeConnection(string name) { + this.Name = name; + this.Server = "."; + this.maxReadBytes = Int32.MaxValue; + } + #region Comments + /// + /// Creates an instance of the ClientPipeConnection specifying the network name + /// of the server. + /// + /// + /// The maximum bytes to read from the client is set to be Int32.MaxValue. + /// + /// The name of the server pipe. + /// The network name of the machine, where the server pipe is created. + #endregion + public ClientPipeConnection(string name, string server) { + this.Name = name; + this.Server = server; + this.maxReadBytes = Int32.MaxValue; + } + #region Comments + /// + /// Object destructor. + /// + #endregion + ~ClientPipeConnection() { + Dispose(false); + } + } +} \ No newline at end of file diff --git a/extern/w32/namedpipes/AppModule.NamedPipes/ImpersonateNative.cs b/extern/w32/namedpipes/AppModule.NamedPipes/ImpersonateNative.cs new file mode 100644 index 00000000..768174d6 --- /dev/null +++ b/extern/w32/namedpipes/AppModule.NamedPipes/ImpersonateNative.cs @@ -0,0 +1,450 @@ +using System; +using System.Text; +using System.Security; +using System.Runtime.InteropServices; + +namespace AppModule.NamedPipes { + #region Comments + /// + /// This utility class exposes kernel32.dll methods for named pipes communication. + /// + /// + /// Use the following links for complete information about the exposed methods: + /// + /// + /// Named Pipe Functions + /// + /// + /// File Management Functions + /// + /// + /// Handle and Object Functions + /// + /// + /// System Error Codes + /// + /// + /// + #endregion + [SuppressUnmanagedCodeSecurity] + public sealed class ImpersonateNative + { + #region Comments + /// + /// + /// + #endregion + public const int TOKEN_QUERY = 0X00000008; + + public enum TOKEN_INFORMATION_CLASS + { + TokenUser = 1, + TokenGroups, + TokenPrivileges, + TokenOwner, + TokenPrimaryGroup, + TokenDefaultDacl, + TokenSource, + TokenType, + TokenImpersonationLevel, + TokenStatistics, + TokenRestrictedSids, + TokenSessionId + } + + [StructLayout(LayoutKind.Sequential)] + public struct TOKEN_USER + { + public _SID_AND_ATTRIBUTES User; + } + + [StructLayout(LayoutKind.Sequential)] + public struct _SID_AND_ATTRIBUTES + { + public IntPtr Sid; + public int Attributes; + } + + [StructLayout(LayoutKind.Sequential)] + public struct _LUID + { + public int LowPart ; + public int HighPart; + } //LUID, *PLUID; + + + [StructLayout(LayoutKind.Sequential)] + public struct TOKEN_STATISTICS + { + public _LUID TokenId; + public _LUID AuthenticationId; + public int ExpirationTime; + public int TokenType; // enum ini in 1 TOKEN_TYPE + public int ImpersonationLevel; //SECURITY_IMPERSONATION_LEVEL ImpersonationLevel; + public int DynamicCharged; ////DWORD + public int DynamicAvailable; //DWORD + public int GroupCount; //DWORD + public int PrivilegeCount; //DWORD + public _LUID ModifiedId; + }// TOKEN_STATISTICS, *PTOKEN_STATISTICS; + + + #region Comments + /// + /// Creates an instance of a named pipe and returns a handle for + /// subsequent pipe operations. + /// + /// Pointer to the null-terminated string that + /// uniquely identifies the pipe. + /// Pipe access mode, the overlapped mode, + /// the write-through mode, and the security access mode of the pipe handle. + /// Type, read, and wait modes of the pipe handle. + /// Maximum number of instances that can be + /// created for this pipe. + /// Number of bytes to reserve for the output buffer. + /// Number of bytes to reserve for the input buffer. + /// Default time-out value, in milliseconds. + /// Pointer to a + /// SecurityAttributes + /// object that specifies a security descriptor for the new named pipe. + /// If the function succeeds, the return value is a handle + /// to the server end of a named pipe instance. + #endregion + [DllImport("kernel32.dll")] + public static extern IntPtr CreateNamedPipe( + String lpName, // pipe name + uint dwOpenMode, // pipe open mode + uint dwPipeMode, // pipe-specific modes + uint nMaxInstances, // maximum number of instances + uint nOutBufferSize, // output buffer size + uint nInBufferSize, // input buffer size + uint nDefaultTimeOut, // time-out interval + IntPtr pipeSecurityDescriptor // SD + ); + #region Comments + /// + /// Enables a named pipe server process to wait for a client + /// process to connect to an instance of a named pipe. + /// + /// Handle to the server end of a named pipe instance. + /// Pointer to an + /// Overlapped object. + /// If the function succeeds, the return value is nonzero. + #endregion + [DllImport("kernel32.dll")] + public static extern bool ConnectNamedPipe( + IntPtr hHandle, // handle to named pipe + Overlapped lpOverlapped // overlapped structure + ); + #region Comments + /// + /// 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. + /// + /// Pointer to a null-terminated string + /// specifying the pipe name. + /// Pointer to the buffer containing the data written + /// to the pipe. + /// Size of the write buffer, in bytes. + /// Pointer to the buffer that receives the data + /// read from the pipe. + /// Size of the read buffer, in bytes. + /// Pointer to a variable that receives the number + /// of bytes read from the pipe. + /// Number of milliseconds to wait for the + /// named pipe to be available. + /// If the function succeeds, the return value is nonzero. + #endregion + [DllImport("kernel32.dll")] + public static extern bool CallNamedPipe( + string lpNamedPipeName, + byte[] lpInBuffer, + uint nInBufferSize, + byte[] lpOutBuffer, + uint nOutBufferSize, + byte[] lpBytesRead, + int nTimeOut + ); + #region Comments + /// + /// Creates or opens a file, directory, physical disk, volume, console buffer, + /// tape drive, communications resource, mailslot, or named pipe. + /// + /// Pointer to a null-terminated string that + /// specifies the name of the object to create or open. + /// Access to the object (reading, writing, or both). + /// Sharing mode of the object (reading, writing, both, or neither). + /// Pointer to a + /// SecurityAttributes + /// object that determines whether the returned handle can be inherited + /// by child processes. + /// Action to take on files that exist, + /// and which action to take when files do not exist. + /// File attributes and flags. + /// Handle to a template file, with the GENERIC_READ access right. + /// If the function succeeds, the return value is an open handle to the specified file. + #endregion + [DllImport("kernel32.dll")] + public static extern IntPtr CreateFile( + String lpFileName, // file name + uint dwDesiredAccess, // access mode + uint dwShareMode, // share mode + SecurityAttributes attr, // SD + uint dwCreationDisposition, // how to create + uint dwFlagsAndAttributes, // file attributes + uint hTemplateFile); // handle to template file + #region Comments + /// + /// Reads data from a file, starting at the position indicated by the file pointer. + /// + /// Handle to the file to be read. + /// Pointer to the buffer that receives the data read from the file. + /// Number of bytes to be read from the file. + /// Pointer to the variable that receives the number of bytes read. + /// Pointer to an + /// Overlapped object. + /// The ReadFile function returns when one of the following + /// conditions is met: a write operation completes on the write end of + /// the pipe, the number of bytes requested has been read, or an error occurs. + #endregion + [DllImport("kernel32.dll")] + public static extern bool ReadFile( + IntPtr hHandle, // handle to file + byte[] lpBuffer, // data buffer + uint nNumberOfBytesToRead, // number of bytes to read + byte[] lpNumberOfBytesRead, // number of bytes read + uint lpOverlapped // overlapped buffer + ); + #region Comments + /// + /// Writes data to a file at the position specified by the file pointer. + /// + /// Handle to the file. + /// Pointer to the buffer containing the data to be written to the file. + /// + /// Pointer to the variable that receives the number of bytes written. + /// Pointer to an + /// Overlapped object. + /// If the function succeeds, the return value is nonzero. + #endregion + [DllImport("kernel32.dll")] + public static extern bool WriteFile( + IntPtr hHandle, // handle to file + byte[] lpBuffer, // data buffer + uint nNumberOfBytesToWrite, // number of bytes to write + byte[] lpNumberOfBytesWritten, // number of bytes written + uint lpOverlapped // overlapped buffer + ); + #region Comments + /// + /// Retrieves information about a specified named pipe. + /// + /// Handle to the named pipe for which information is wanted. + /// Pointer to a variable that indicates the current + /// state of the handle. + /// Pointer to a variable that receives the + /// number of current pipe instances. + /// Pointer to a variable that receives + /// the maximum number of bytes to be collected on the client's computer + /// before transmission to the server. + /// Pointer to a variable that receives + /// the maximum time, in milliseconds, that can pass before a remote named + /// pipe transfers information over the network. + /// Pointer to a buffer that receives the + /// null-terminated string containing the user name string associated + /// with the client application. + /// Size of the buffer specified by the + /// lpUserName parameter. + /// If the function succeeds, the return value is nonzero. + #endregion + [DllImport("kernel32.dll")] + public static extern bool GetNamedPipeHandleState( + IntPtr hHandle, + IntPtr lpState, + ref uint lpCurInstances, + IntPtr lpMaxCollectionCount, + IntPtr lpCollectDataTimeout, + IntPtr lpUserName, + IntPtr nMaxUserNameSize + ); + #region Comments + /// + /// Cancels all pending input and output (I/O) operations that were + /// issued by the calling thread for the specified file handle. + /// + /// Handle to a file. + /// If the function succeeds, the return value is nonzero. + #endregion + [DllImport("kernel32.dll")] + public static extern bool CancelIo( + IntPtr hHandle + ); + #region Comments + /// + /// Waits until either a time-out interval elapses or an instance + /// of the specified named pipe is available for connection. + /// + /// Pointer to a null-terminated string that specifies + /// the name of the named pipe. + /// Number of milliseconds that the function will + /// wait for an instance of the named pipe to be available. + /// If an instance of the pipe is available before the + /// time-out interval elapses, the return value is nonzero. + #endregion + [DllImport("kernel32.dll")] + public static extern bool WaitNamedPipe( + String name, + int timeout); + #region Comments + /// + /// Retrieves the calling thread's last-error code value. + /// + /// The return value is the calling thread's last-error code value. + #endregion + [DllImport("kernel32.dll")] + public static extern uint GetLastError(); + #region Comments + /// + /// Flushes the buffers of the specified file and causes all buffered data to be written to the file. + /// + /// Handle to an open file. + /// If the function succeeds, the return value is nonzero. + #endregion + [DllImport("kernel32.dll")] + public static extern bool FlushFileBuffers( + IntPtr hHandle); + #region Comments + /// + /// Disconnects the server end of a named pipe instance from a client process. + /// + /// Handle to an instance of a named pipe. + /// If the function succeeds, the return value is nonzero. + #endregion + [DllImport("kernel32.dll")] + public static extern bool DisconnectNamedPipe( + IntPtr hHandle); + #region Comments + /// + /// 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. + /// + /// Handle to the named pipe instance. + /// Pointer to a variable that supplies the new mode. + /// Pointer to a variable that specifies the maximum + /// number of bytes collected on the client computer before + /// transmission to the server. + /// Pointer to a variable that specifies the + /// maximum time, in milliseconds, that can pass before a remote + /// named pipe transfers information over the network. + /// If the function succeeds, the return value is nonzero. + #endregion + [DllImport("kernel32.dll")] + public static extern bool SetNamedPipeHandleState( + IntPtr hHandle, + ref uint mode, + IntPtr cc, + IntPtr cd); + #region Comments + /// + /// Closes an open object handle. + /// + /// Handle to an open object. + /// If the function succeeds, the return value is nonzero. + #endregion + [DllImport("kernel32.dll")] + public static extern bool CloseHandle( + IntPtr hHandle); + + [DllImport("kernel32.dll")] + public static extern IntPtr GetCurrentThread(); + + // native for named pipes + #region Comments + /// + /// Closes an open object handle. + /// + /// Handle to an open object. + /// If the function succeeds, the return value is nonzero. + #endregion + [DllImport("advapi32" )] + public static extern int ImpersonateNamedPipeClient( + IntPtr hHandle); + + [DllImport("advapi32" )] + public static extern bool RevertToSelf(); + + [DllImport("advapi32", SetLastError=true)] + public static extern bool OpenThreadToken( + IntPtr hThread, + uint desiredInfo, + bool openAsSelf, + out IntPtr TokenHandle); // handle to open access token + + [DllImport("advapi32")] + public static extern bool OpenProcessToken( + IntPtr ProcessHandle, // handle to process + int DesiredAccess, // desired access to process + ref IntPtr TokenHandle // handle to open access token + ); + + [DllImport("advapi32", CharSet=CharSet.Auto)] + public static extern bool GetTokenInformation( + IntPtr hToken, + TOKEN_INFORMATION_CLASS tokenInfoClass, + IntPtr TokenInformation, + int tokeInfoLength, + ref int reqLength); + + + [DllImport("advapi32", CharSet=CharSet.Auto)] + public static extern bool LookupAccountSid + ( + [In,MarshalAs(UnmanagedType.LPTStr)] string lpSystemName, // name of local or remote computer + IntPtr pSid, // security identifier + StringBuilder Account, // account name buffer + ref int cbName, // size of account name buffer + StringBuilder DomainName, // domain name + ref int cbDomainName, // size of domain name buffer + ref int peUse // SID type + // ref _SID_NAME_USE peUse // SID type + ); + + [DllImport("advapi32", CharSet=CharSet.Auto)] + public static extern bool ConvertSidToStringSid( + IntPtr pSID, + [In,Out,MarshalAs(UnmanagedType.LPTStr)] ref string pStringSid); + + #region Comments + /// + /// Sets the security descriptor attributes + /// + /// Reference to a SECURITY_DESCRIPTOR structure. + /// + /// + /// + /// + #endregion + [DllImport("Advapi32.dll", SetLastError=true)] + public static extern bool SetSecurityDescriptorDacl(ref SECURITY_DESCRIPTOR sd, bool bDaclPresent, IntPtr Dacl, bool bDaclDefaulted); + #region Comments + /// + /// Initializes a SECURITY_DESCRIPTOR structure. + /// + /// + /// + /// + #endregion + [DllImport("Advapi32.dll", SetLastError=true)] + public static extern bool InitializeSecurityDescriptor(out SECURITY_DESCRIPTOR sd, int dwRevision); + #region Comments + /// + /// Private constructor. + /// + #endregion + private ImpersonateNative() {} + } +} \ No newline at end of file diff --git a/extern/w32/namedpipes/AppModule.NamedPipes/ImpersonateWrapper.cs b/extern/w32/namedpipes/AppModule.NamedPipes/ImpersonateWrapper.cs new file mode 100644 index 00000000..b0fbecb3 --- /dev/null +++ b/extern/w32/namedpipes/AppModule.NamedPipes/ImpersonateWrapper.cs @@ -0,0 +1,214 @@ +using System; + +using AppModule.NamedPipes; +using System.Runtime.InteropServices; +using System.Text; + +using HANDLE = System.IntPtr; + +namespace AppModule.NamedPipes +{ + #region Comments + /// + /// A utility class that exposes named pipes operations. + /// + /// + /// This class uses the exposed exposed kernel32.dll methods by the + /// NamedPipeNative class + /// to provided controlled named pipe functionality. + /// + #endregion + public sealed class ImpersonateWrapper + { + + public const int TOKEN_QUERY = 0X00000008; + + const int ERROR_NO_MORE_ITEMS = 259; + + + + // Client USERID stuff + // 1. call ImpersonateNamedPipeClient(hPipe) + // 2. call OpenThreadToken(GetCurrentThread(), + // TOKEN_QUERY | TOKEN_QUERY_SOURCE, + // FALSE, + // phUserToken); + + public static int ImpersonateNamedPipeClient(IntPtr hPipeHandle) + { + int rcode = ImpersonateNative.ImpersonateNamedPipeClient(hPipeHandle); + return rcode; + } + + + static int PerformDump(HANDLE token) + { + StringBuilder sb = new StringBuilder(); + ImpersonateNative.TOKEN_USER tokUser; + const int bufLength = 256; + IntPtr tu = Marshal.AllocHGlobal( bufLength ); + int cb = bufLength; + if (ImpersonateNative.GetTokenInformation( token, ImpersonateNative.TOKEN_INFORMATION_CLASS.TokenUser, tu, cb, ref cb )) + Console.WriteLine("GetTokenInformation successful"); + else + { + Console.WriteLine("GetTokenInformation NOT successful"); + uint error = NamedPipeNative.GetLastError(); + Console.WriteLine("error" + error.ToString()); + } + + tokUser = (ImpersonateNative.TOKEN_USER) Marshal.PtrToStructure(tu, typeof(ImpersonateNative.TOKEN_USER) ); + //sb.Append(DumpAccountSid(tokUser.User.Sid)); + IntPtr pUserID = tokUser.User.Sid; + //Console.WriteLine("UserID: " + pUserID); + + DumpAccountSid(pUserID); + Marshal.FreeHGlobal( tu ); + + + tu = Marshal.AllocHGlobal(bufLength); + cb = bufLength; + + // get token states + ImpersonateNative.TOKEN_STATISTICS stats; + + if (ImpersonateNative.GetTokenInformation(token, ImpersonateNative.TOKEN_INFORMATION_CLASS.TokenStatistics, tu, cb, ref cb)) + { + stats = (ImpersonateNative.TOKEN_STATISTICS) Marshal.PtrToStructure(tu, typeof(ImpersonateNative.TOKEN_STATISTICS)); + Console.WriteLine("UserLow: "+stats.AuthenticationId.LowPart.ToString()); + Console.WriteLine("UserHigh: "+stats.AuthenticationId.HighPart.ToString()); + } + else + { + Console.WriteLine("failed"); + } + + return (int)pUserID; + } + + + static string DumpAccountSid(IntPtr SID) + { + int cchAccount = 0; + int cchDomain = 0; + int snu = 0 ; + StringBuilder sb = new StringBuilder(); + + // Caller allocated buffer + StringBuilder Account= null; + StringBuilder Domain = null; + bool ret = ImpersonateNative.LookupAccountSid(null, SID, Account, ref cchAccount, Domain, ref cchDomain, ref snu); + if ( ret == true ) + if ( Marshal.GetLastWin32Error() == ERROR_NO_MORE_ITEMS ) + return "Error"; + try + { + Account = new StringBuilder( cchAccount ); + Domain = new StringBuilder( cchDomain ); + ret = ImpersonateNative.LookupAccountSid(null, SID, Account, ref cchAccount, Domain, ref cchDomain, ref snu); + if (ret) + { + sb.Append(Domain); + sb.Append(@"\\"); + sb.Append(Account); + } + else + Console.WriteLine("logon account (no name) "); + } + catch (Exception ex) + { + Console.WriteLine(ex.Message); + } + finally + { + } + string SidString = null; + ImpersonateNative.ConvertSidToStringSid(SID, ref SidString); + sb.Append("\nSID: "); + sb.Append(SidString); + + + Console.WriteLine("Acct info: "+ sb.ToString()); + return sb.ToString(); + } + + public static int GetLocalUserID(PipeHandle handle, ref int lowPart, ref int highPart, ref string SidString) + { + int rcode = -1; + // get client userID + int code = ImpersonateNative.ImpersonateNamedPipeClient(handle.Handle); + if (code == 0) + { + uint lastError = NamedPipeNative.GetLastError(); + Console.WriteLine("ImpersonateNamedPipeClient Error: "+rcode.ToString()); + return -1; + } + + try + { + IntPtr hThread = ImpersonateNative.GetCurrentThread(); + uint iDesiredInfo = 24; //TOKEN_QUERY | TOKEN_QUERY_SOURCE; + IntPtr userToken = Marshal.AllocHGlobal(4); + + if (ImpersonateNative.OpenThreadToken(hThread, iDesiredInfo, true, out userToken)) + { + + StringBuilder sb = new StringBuilder(); + ImpersonateNative.TOKEN_USER tokUser; + const int bufLength = 256; + IntPtr tu = Marshal.AllocHGlobal( bufLength ); + int cb = bufLength; + if (ImpersonateNative.GetTokenInformation( userToken, ImpersonateNative.TOKEN_INFORMATION_CLASS.TokenUser, tu, cb, ref cb )) + { + tokUser = (ImpersonateNative.TOKEN_USER) Marshal.PtrToStructure(tu, typeof(ImpersonateNative.TOKEN_USER) ); + IntPtr pUserID = tokUser.User.Sid; + Marshal.FreeHGlobal( tu ); + + // get SID + //string SidString = null; + ImpersonateNative.ConvertSidToStringSid(pUserID, ref SidString); + + // get token states + tu = Marshal.AllocHGlobal(bufLength); + cb = bufLength; + ImpersonateNative.TOKEN_STATISTICS stats; + if (ImpersonateNative.GetTokenInformation(userToken, ImpersonateNative.TOKEN_INFORMATION_CLASS.TokenStatistics, tu, cb, ref cb)) + { + stats = (ImpersonateNative.TOKEN_STATISTICS) Marshal.PtrToStructure(tu, typeof(ImpersonateNative.TOKEN_STATISTICS)); + // copy low and high part + lowPart = stats.AuthenticationId.LowPart; + highPart = stats.AuthenticationId.HighPart; + rcode = -1; + } + } + else + { + Console.WriteLine("GetTokenInformation NOT successful"); + uint error = NamedPipeNative.GetLastError(); + Console.WriteLine("error" + error.ToString()); + } + + // close handle + ImpersonateNative.CloseHandle(hThread); + ImpersonateNative.RevertToSelf(); + } + else + { + int lastError = Marshal.GetLastWin32Error(); + uint errorcode = NamedPipeNative.GetLastError(); + Console.WriteLine("OpenThreadToken Error: "+ errorcode.ToString() + " code2: "+rcode.ToString()); + } + } + catch (Exception ex) + { + int error = Marshal.GetLastWin32Error(); + Console.WriteLine(ex.ToString()); + return rcode; + } + // end + + return rcode; + + } + } +} \ No newline at end of file diff --git a/extern/w32/namedpipes/AppModule.NamedPipes/NamedPipeIOException.cs b/extern/w32/namedpipes/AppModule.NamedPipes/NamedPipeIOException.cs new file mode 100644 index 00000000..7e705df9 --- /dev/null +++ b/extern/w32/namedpipes/AppModule.NamedPipes/NamedPipeIOException.cs @@ -0,0 +1,44 @@ +using System; +using System.Runtime.Serialization; + +using AppModule.InterProcessComm; + +namespace AppModule.NamedPipes { + #region Comments + /// + /// This exception is thrown by named pipes communication methods. + /// + #endregion + public class NamedPipeIOException : InterProcessIOException { + #region Comments + /// + /// Creates a NamedPipeIOException instance. + /// + /// The error message text. + #endregion + public NamedPipeIOException(String text) : base(text) { + } + #region Comments + /// + /// Creates a NamedPipeIOException instance. + /// + /// The error message text. + /// The native error code. + #endregion + public NamedPipeIOException(String text, uint errorCode) : base(text) { + this.ErrorCode = errorCode; + if (errorCode == NamedPipeNative.ERROR_CANNOT_CONNECT_TO_PIPE) { + this.IsServerAvailable = false; + } + } + #region Comments + /// + /// Creates a NamedPipeIOException instance. + /// + /// The serialization information. + /// The streaming context. + #endregion + protected NamedPipeIOException(SerializationInfo info, StreamingContext context) : base(info, context) { + } + } +} \ No newline at end of file diff --git a/extern/w32/namedpipes/AppModule.NamedPipes/NamedPipeNative.cs b/extern/w32/namedpipes/AppModule.NamedPipes/NamedPipeNative.cs new file mode 100644 index 00000000..369db387 --- /dev/null +++ b/extern/w32/namedpipes/AppModule.NamedPipes/NamedPipeNative.cs @@ -0,0 +1,568 @@ +using System; +using System.Security; +using System.Runtime.InteropServices; + +namespace AppModule.NamedPipes { + #region Comments + /// + /// This utility class exposes kernel32.dll methods for named pipes communication. + /// + /// + /// Use the following links for complete information about the exposed methods: + /// + /// + /// Named Pipe Functions + /// + /// + /// File Management Functions + /// + /// + /// Handle and Object Functions + /// + /// + /// System Error Codes + /// + /// + /// + #endregion + [SuppressUnmanagedCodeSecurity] + public sealed class NamedPipeNative { + #region Comments + /// + /// Outbound pipe access. + /// + #endregion + public const uint PIPE_ACCESS_OUTBOUND = 0x00000002; + #region Comments + /// + /// Duplex pipe access. + /// + #endregion + public const uint PIPE_ACCESS_DUPLEX = 0x00000003; + #region Comments + /// + /// Inbound pipe access. + /// + #endregion + public const uint PIPE_ACCESS_INBOUND = 0x00000001; + #region Comments + /// + /// Pipe blocking mode. + /// + #endregion + public const uint PIPE_WAIT = 0x00000000; + #region Comments + /// + /// Pipe non-blocking mode. + /// + #endregion + public const uint PIPE_NOWAIT = 0x00000001; + #region Comments + /// + /// Pipe read mode of type Byte. + /// + #endregion + public const uint PIPE_READMODE_BYTE = 0x00000000; + #region Comments + /// + /// Pipe read mode of type Message. + /// + #endregion + public const uint PIPE_READMODE_MESSAGE = 0x00000002; + #region Comments + /// + /// Byte pipe type. + /// + #endregion + public const uint PIPE_TYPE_BYTE = 0x00000000; + #region Comments + /// + /// Message pipe type. + /// + #endregion + public const uint PIPE_TYPE_MESSAGE = 0x00000004; + #region Comments + /// + /// Pipe client end. + /// + #endregion + public const uint PIPE_CLIENT_END = 0x00000000; + #region Comments + /// + /// Pipe server end. + /// + #endregion + public const uint PIPE_SERVER_END = 0x00000001; + #region Comments + /// + /// Unlimited server pipe instances. + /// + #endregion + public const uint PIPE_UNLIMITED_INSTANCES = 255; + #region Comments + /// + /// Waits indefinitely when connecting to a pipe. + /// + #endregion + public const uint NMPWAIT_WAIT_FOREVER = 0xffffffff; + #region Comments + /// + /// Does not wait for the named pipe. + /// + #endregion + public const uint NMPWAIT_NOWAIT = 0x00000001; + #region Comments + /// + /// Uses the default time-out specified in a call to the CreateNamedPipe method. + /// + #endregion + public const uint NMPWAIT_USE_DEFAULT_WAIT = 0x00000000; + #region Comments + /// + /// + /// + #endregion + public const uint GENERIC_READ = (0x80000000); + #region Comments + /// + /// Generic write access to the pipe. + /// + #endregion + public const uint GENERIC_WRITE = (0x40000000); + #region Comments + /// + /// Generic execute access to the pipe. + /// + #endregion + public const uint GENERIC_EXECUTE = (0x20000000); + #region Comments + /// + /// Read, write, and execute access. + /// + #endregion + public const uint GENERIC_ALL = (0x10000000); + #region Comments + /// + /// Create new file. Fails if the file exists. + /// + #endregion + public const uint CREATE_NEW = 1; + #region Comments + /// + /// Create new file. Overrides an existing file. + /// + #endregion + public const uint CREATE_ALWAYS = 2; + #region Comments + /// + /// Open existing file. + /// + #endregion + public const uint OPEN_EXISTING = 3; + #region Comments + /// + /// Open existing file. If the file does not exist, creates it. + /// + #endregion + public const uint OPEN_ALWAYS = 4; + #region Comments + /// + /// Opens the file and truncates it so that its size is zero bytes. + /// + #endregion + public const uint TRUNCATE_EXISTING = 5; + #region Comments + /// + /// Invalid operating system handle. + /// + #endregion + public const int INVALID_HANDLE_VALUE = -1; + #region Comments + /// + /// The operation completed successfully. + /// + #endregion + public const ulong ERROR_SUCCESS = 0; + #region Comments + /// + /// The system cannot find the file specified. + /// + #endregion + public const ulong ERROR_CANNOT_CONNECT_TO_PIPE = 2; + #region Comments + /// + /// All pipe instances are busy. + /// + #endregion + public const ulong ERROR_PIPE_BUSY = 231; + #region Comments + /// + /// The pipe is being closed. + /// + #endregion + public const ulong ERROR_NO_DATA = 232; + #region Comments + /// + /// No process is on the other end of the pipe. + /// + #endregion + public const ulong ERROR_PIPE_NOT_CONNECTED = 233; + #region Comments + /// + /// More data is available. + /// + #endregion + public const ulong ERROR_MORE_DATA = 234; + #region Comments + /// + /// There is a process on other end of the pipe. + /// + #endregion + public const ulong ERROR_PIPE_CONNECTED = 535; + #region Comments + /// + /// Waiting for a process to open the other end of the pipe. + /// + #endregion + public const ulong ERROR_PIPE_LISTENING = 536; + #region Comments + /// + /// Creates an instance of a named pipe and returns a handle for + /// subsequent pipe operations. + /// + /// Pointer to the null-terminated string that + /// uniquely identifies the pipe. + /// Pipe access mode, the overlapped mode, + /// the write-through mode, and the security access mode of the pipe handle. + /// Type, read, and wait modes of the pipe handle. + /// Maximum number of instances that can be + /// created for this pipe. + /// Number of bytes to reserve for the output buffer. + /// Number of bytes to reserve for the input buffer. + /// Default time-out value, in milliseconds. + /// Pointer to a + /// SECURITY_ATTRIBUTES + /// object that specifies a security descriptor for the new named pipe. + /// If the function succeeds, the return value is a handle + /// to the server end of a named pipe instance. + #endregion + [DllImport("kernel32.dll", SetLastError=true)] + public static extern IntPtr CreateNamedPipe( + String lpName, // pipe name + uint dwOpenMode, // pipe open mode + uint dwPipeMode, // pipe-specific modes + uint nMaxInstances, // maximum number of instances + uint nOutBufferSize, // output buffer size + uint nInBufferSize, // input buffer size + uint nDefaultTimeOut, // time-out interval + IntPtr pipeSecurityDescriptor // SD + ); + #region Comments + /// + /// Enables a named pipe server process to wait for a client + /// process to connect to an instance of a named pipe. + /// + /// Handle to the server end of a named pipe instance. + /// Pointer to an + /// Overlapped object. + /// If the function succeeds, the return value is nonzero. + #endregion + [DllImport("kernel32.dll", SetLastError=true)] + public static extern bool ConnectNamedPipe( + IntPtr hHandle, // handle to named pipe + Overlapped lpOverlapped // overlapped structure + ); + #region Comments + /// + /// 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. + /// + /// Pointer to a null-terminated string + /// specifying the pipe name. + /// Pointer to the buffer containing the data written + /// to the pipe. + /// Size of the write buffer, in bytes. + /// Pointer to the buffer that receives the data + /// read from the pipe. + /// Size of the read buffer, in bytes. + /// Pointer to a variable that receives the number + /// of bytes read from the pipe. + /// Number of milliseconds to wait for the + /// named pipe to be available. + /// If the function succeeds, the return value is nonzero. + #endregion + [DllImport("kernel32.dll", SetLastError=true)] + public static extern bool CallNamedPipe( + string lpNamedPipeName, + byte[] lpInBuffer, + uint nInBufferSize, + byte[] lpOutBuffer, + uint nOutBufferSize, + byte[] lpBytesRead, + int nTimeOut + ); + #region Comments + /// + /// Creates or opens a file, directory, physical disk, volume, console buffer, + /// tape drive, communications resource, mailslot, or named pipe. + /// + /// Pointer to a null-terminated string that + /// specifies the name of the object to create or open. + /// Access to the object (reading, writing, or both). + /// Sharing mode of the object (reading, writing, both, or neither). + /// Pointer to a + /// SecurityAttributes + /// object that determines whether the returned handle can be inherited + /// by child processes. + /// Action to take on files that exist, + /// and which action to take when files do not exist. + /// File attributes and flags. + /// Handle to a template file, with the GENERIC_READ access right. + /// If the function succeeds, the return value is an open handle to the specified file. + #endregion + [DllImport("kernel32.dll", SetLastError=true)] + public static extern IntPtr CreateFile( + String lpFileName, // file name + uint dwDesiredAccess, // access mode + uint dwShareMode, // share mode + SecurityAttributes attr, // SD + uint dwCreationDisposition, // how to create + uint dwFlagsAndAttributes, // file attributes + uint hTemplateFile); // handle to template file + #region Comments + /// + /// Reads data from a file, starting at the position indicated by the file pointer. + /// + /// Handle to the file to be read. + /// Pointer to the buffer that receives the data read from the file. + /// Number of bytes to be read from the file. + /// Pointer to the variable that receives the number of bytes read. + /// Pointer to an + /// Overlapped object. + /// The ReadFile function returns when one of the following + /// conditions is met: a write operation completes on the write end of + /// the pipe, the number of bytes requested has been read, or an error occurs. + #endregion + [DllImport("kernel32.dll", SetLastError=true)] + public static extern bool ReadFile( + IntPtr hHandle, // handle to file + byte[] lpBuffer, // data buffer + uint nNumberOfBytesToRead, // number of bytes to read + byte[] lpNumberOfBytesRead, // number of bytes read + uint lpOverlapped // overlapped buffer + ); + #region Comments + /// + /// Writes data to a file at the position specified by the file pointer. + /// + /// Handle to the file. + /// Pointer to the buffer containing the data to be written to the file. + /// + /// Pointer to the variable that receives the number of bytes written. + /// Pointer to an + /// Overlapped object. + /// If the function succeeds, the return value is nonzero. + #endregion + [DllImport("kernel32.dll", SetLastError=true)] + public static extern bool WriteFile( + IntPtr hHandle, // handle to file + byte[] lpBuffer, // data buffer + uint nNumberOfBytesToWrite, // number of bytes to write + byte[] lpNumberOfBytesWritten, // number of bytes written + uint lpOverlapped // overlapped buffer + ); + #region Comments + /// + /// Retrieves information about a specified named pipe. + /// + /// Handle to the named pipe for which information is wanted. + /// Pointer to a variable that indicates the current + /// state of the handle. + /// Pointer to a variable that receives the + /// number of current pipe instances. + /// Pointer to a variable that receives + /// the maximum number of bytes to be collected on the client's computer + /// before transmission to the server. + /// Pointer to a variable that receives + /// the maximum time, in milliseconds, that can pass before a remote named + /// pipe transfers information over the network. + /// Pointer to a buffer that receives the + /// null-terminated string containing the user name string associated + /// with the client application. + /// Size of the buffer specified by the + /// lpUserName parameter. + /// If the function succeeds, the return value is nonzero. + #endregion + [DllImport("kernel32.dll", SetLastError=true)] + public static extern bool GetNamedPipeHandleState( + IntPtr hHandle, + IntPtr lpState, + ref uint lpCurInstances, + IntPtr lpMaxCollectionCount, + IntPtr lpCollectDataTimeout, + IntPtr lpUserName, + IntPtr nMaxUserNameSize + ); + #region Comments + /// + /// Cancels all pending input and output (I/O) operations that were + /// issued by the calling thread for the specified file handle. + /// + /// Handle to a file. + /// If the function succeeds, the return value is nonzero. + #endregion + [DllImport("kernel32.dll", SetLastError=true)] + public static extern bool CancelIo( + IntPtr hHandle + ); + #region Comments + /// + /// Waits until either a time-out interval elapses or an instance + /// of the specified named pipe is available for connection. + /// + /// Pointer to a null-terminated string that specifies + /// the name of the named pipe. + /// Number of milliseconds that the function will + /// wait for an instance of the named pipe to be available. + /// If an instance of the pipe is available before the + /// time-out interval elapses, the return value is nonzero. + #endregion + [DllImport("kernel32.dll", SetLastError=true)] + public static extern bool WaitNamedPipe( + String name, + int timeout); + #region Comments + /// + /// Retrieves the calling thread's last-error code value. + /// + /// The return value is the calling thread's last-error code value. + #endregion + [DllImport("kernel32.dll", SetLastError=true)] + public static extern uint GetLastError(); + #region Comments + /// + /// Flushes the buffers of the specified file and causes all buffered data to be written to the file. + /// + /// Handle to an open file. + /// If the function succeeds, the return value is nonzero. + #endregion + [DllImport("kernel32.dll", SetLastError=true)] + public static extern bool FlushFileBuffers( + IntPtr hHandle); + #region Comments + /// + /// Disconnects the server end of a named pipe instance from a client process. + /// + /// Handle to an instance of a named pipe. + /// If the function succeeds, the return value is nonzero. + #endregion + [DllImport("kernel32.dll", SetLastError=true)] + public static extern bool DisconnectNamedPipe( + IntPtr hHandle); + #region Comments + /// + /// 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. + /// + /// Handle to the named pipe instance. + /// Pointer to a variable that supplies the new mode. + /// Pointer to a variable that specifies the maximum + /// number of bytes collected on the client computer before + /// transmission to the server. + /// Pointer to a variable that specifies the + /// maximum time, in milliseconds, that can pass before a remote + /// named pipe transfers information over the network. + /// If the function succeeds, the return value is nonzero. + #endregion + [DllImport("kernel32.dll", SetLastError=true)] + public static extern bool SetNamedPipeHandleState( + IntPtr hHandle, + ref uint mode, + IntPtr cc, + IntPtr cd); + #region Comments + /// + /// Closes an open object handle. + /// + /// Handle to an open object. + /// If the function succeeds, the return value is nonzero. + #endregion + [DllImport("kernel32.dll", SetLastError=true)] + public static extern bool CloseHandle( + IntPtr hHandle); + #region Comments + /// + /// Sets the security descriptor attributes + /// + /// Reference to a SECURITY_DESCRIPTOR structure. + /// + /// + /// + /// + #endregion + [DllImport("Advapi32.dll", SetLastError=true)] + public static extern bool SetSecurityDescriptorDacl(ref SECURITY_DESCRIPTOR sd, bool bDaclPresent, IntPtr Dacl, bool bDaclDefaulted); + #region Comments + /// + /// Initializes a SECURITY_DESCRIPTOR structure. + /// + /// + /// + /// + #endregion + [DllImport("Advapi32.dll", SetLastError=true)] + public static extern bool InitializeSecurityDescriptor(out SECURITY_DESCRIPTOR sd, int dwRevision); + #region Comments + /// + /// Private constructor. + /// + #endregion + private NamedPipeNative() {} + } + #region Comments + /// + /// Security Descriptor structure + /// + #endregion + [StructLayout(LayoutKind.Sequential)] + public struct SECURITY_DESCRIPTOR { + private byte Revision; + private byte Sbz1; + private ushort Control; + private IntPtr Owner; + private IntPtr Group; + private IntPtr Sacl; + private IntPtr Dacl; + } + #region Comments + /// + /// Security Attributes structure. + /// + #endregion + [StructLayout(LayoutKind.Sequential)] + public struct SECURITY_ATTRIBUTES { + public int nLength; + public IntPtr lpSecurityDescriptor; + public bool bInheritHandle; + } + #region Comments + /// + /// This class is used as a dummy parameter only. + /// + #endregion + [StructLayout(LayoutKind.Sequential)] + public class Overlapped { + } + #region Comments + /// + /// This class is used as a dummy parameter only. + /// + #endregion + [StructLayout(LayoutKind.Sequential)] + public class SecurityAttributes { + } +} \ No newline at end of file diff --git a/extern/w32/namedpipes/AppModule.NamedPipes/NamedPipeWrapper.cs b/extern/w32/namedpipes/AppModule.NamedPipes/NamedPipeWrapper.cs new file mode 100644 index 00000000..19e51f9b --- /dev/null +++ b/extern/w32/namedpipes/AppModule.NamedPipes/NamedPipeWrapper.cs @@ -0,0 +1,427 @@ +using System; +using System.Runtime.InteropServices; + +using AppModule.InterProcessComm; + +namespace AppModule.NamedPipes { + #region Comments + /// + /// A utility class that exposes named pipes operations. + /// + /// + /// This class uses the exposed exposed kernel32.dll methods by the + /// NamedPipeNative class + /// to provided controlled named pipe functionality. + /// + #endregion + public sealed class NamedPipeWrapper { + #region Comments + /// + /// The number of retries when creating a pipe or connecting to a pipe. + /// + #endregion + private const int ATTEMPTS = 2; + #region Comments + /// + /// Wait time for the + /// NamedPipeNative.WaitNamedPipe + /// operation. + /// + #endregion + private const int WAIT_TIME = 5000; + #region Comments + /// + /// Reads a string from a named pipe using the UTF8 encoding. + /// + /// The pipe handle. + /// The maximum bytes to read. + /// A UTF8 string. + /// This function uses + /// AppModule.NamedPipes.ReadBytes + /// to read the bytes from the pipe and then converts them to string.

+ /// The first four bytes of the pipe data are expected to contain + /// the data length of the message. This method first reads those four + /// bytes and converts them to integer. It then continues to read from the pipe using + /// the extracted data length. + ///
+ #endregion + public static string Read(PipeHandle handle, int maxBytes) { + string returnVal = ""; + byte[] bytes = ReadBytes(handle, maxBytes); + if (bytes != null) { + returnVal = System.Text.Encoding.UTF8.GetString(bytes); + } + return returnVal; + } + #region Comments + /// + /// Reads the bytes from a named pipe. + /// + /// The pipe handle. + /// The maximum bytes to read. + /// An array of bytes. + /// This method expects that the first four bytes in the pipe define + /// the length of the data to read. If the data length is greater than + /// maxBytes the method returns null.

+ /// The first four bytes of the pipe data are expected to contain + /// the data length of the message. This method first reads those four + /// bytes and converts them to integer. It then continues to read from the pipe using + /// the extracted data length. + ///
+ #endregion + public static byte[] ReadBytes(PipeHandle handle, int maxBytes) { + byte[] numReadWritten = new byte[4]; + byte[] intBytes = new byte[4]; + byte[] msgBytes = null; + int len; + + // Set the Handle state to Reading + handle.State = InterProcessConnectionState.Reading; + // Read the first four bytes and convert them to integer + if (NamedPipeNative.ReadFile(handle.Handle, intBytes, 4, numReadWritten, 0)) { + len = BitConverter.ToInt32(intBytes, 0); + msgBytes = new byte[len]; + // Read the rest of the data + if (!NamedPipeNative.ReadFile(handle.Handle, msgBytes, (uint)len, numReadWritten, 0)) { + handle.State = InterProcessConnectionState.Error; + throw new NamedPipeIOException("Error reading from pipe. Internal error: " + NamedPipeNative.GetLastError().ToString(), NamedPipeNative.GetLastError()); + } + } + else { + handle.State = InterProcessConnectionState.Error; + throw new NamedPipeIOException("Error reading from pipe. Internal error: " + NamedPipeNative.GetLastError().ToString(), NamedPipeNative.GetLastError()); + } + handle.State = InterProcessConnectionState.ReadData; + if (len > maxBytes) { + return null; + } + return msgBytes; + } + #region Comments + /// + /// Writes a string to a named pipe. + /// + /// The pipe handle. + /// The text to write to the pipe. + /// This method converts the text into an array of bytes, using the + /// UTF8 encoding and the uses + /// AppModule.NamedPipes.WriteBytes + /// to write to the pipe.

+ /// When writing to a pipe the method first writes four bytes that define the data length. + /// It then writes the whole message.
+ #endregion + public static void Write(PipeHandle handle, string text) { + WriteBytes(handle, System.Text.Encoding.UTF8.GetBytes(text)); + } + #region Comments + /// + /// Writes an array of bytes to a named pipe. + /// + /// The pipe handle. + /// The bytes to write. + /// If we try bytes array we attempt to write is empty then this method write a space character to the pipe. This is necessary because the other end of the pipe uses a blocking Read operation so we must write someting.

+ /// The bytes length is restricted by the maxBytes parameter, which is done primarily for security reasons.

+ /// When writing to a pipe the method first writes four bytes that define the data length. + /// It then writes the whole message.
+ #endregion + public static void WriteBytes(PipeHandle handle, byte[] bytes) { + byte[] numReadWritten = new byte[4]; + uint len; + + if (bytes == null) { + bytes = new byte[0]; + } + if (bytes.Length == 0) { + bytes = new byte[1]; + bytes = System.Text.Encoding.UTF8.GetBytes(" "); + } + // Get the message length + len = (uint)bytes.Length; + handle.State = InterProcessConnectionState.Writing; + // Write four bytes that define the message length + if (NamedPipeNative.WriteFile(handle.Handle, BitConverter.GetBytes(len), 4, numReadWritten, 0)) { + // Write the whole message + if (!NamedPipeNative.WriteFile(handle.Handle, bytes, len, numReadWritten, 0)) { + handle.State = InterProcessConnectionState.Error; + throw new NamedPipeIOException("Error writing to pipe. Internal error: " + NamedPipeNative.GetLastError().ToString(), NamedPipeNative.GetLastError()); + } + } + else { + handle.State = InterProcessConnectionState.Error; + throw new NamedPipeIOException("Error writing to pipe. Internal error: " + NamedPipeNative.GetLastError().ToString(), NamedPipeNative.GetLastError()); + } + handle.State = InterProcessConnectionState.Flushing; + Flush(handle); + handle.State = InterProcessConnectionState.FlushedData; + } + #region Comments + /// + /// Tries to connect to a named pipe on the same machine. + /// + /// The name of the pipe. + /// The resulting pipe handle. + /// Return true if the attempt succeeds. + /// This method is used mainly when stopping the pipe server. It unblocks the existing pipes, which wait for client connection. + #endregion + public static bool TryConnectToPipe(string pipeName, out PipeHandle handle) { + return TryConnectToPipe(pipeName, ".", out handle); + } + #region Comments + /// + /// Tries to connect to a named pipe. + /// + /// The name of the pipe. + /// The name of the server. + /// The resulting pipe handle. + /// Return true if the attempt succeeds. + /// This method is used mainly when stopping the pipe server. It unblocks the existing pipes, which wait for client connection. + #endregion + public static bool TryConnectToPipe(string pipeName, string serverName, out PipeHandle handle) { + handle = new PipeHandle(); + // Build the pipe name string + string name = @"\\" + serverName + @"\pipe\" + pipeName; + handle.State = InterProcessConnectionState.ConnectingToServer; + // Try to connect to a server pipe + handle.Handle = NamedPipeNative.CreateFile(name, NamedPipeNative.GENERIC_READ | NamedPipeNative.GENERIC_WRITE, 0, null, NamedPipeNative.OPEN_EXISTING, 0, 0); + if (handle.Handle.ToInt32() != NamedPipeNative.INVALID_HANDLE_VALUE) { + handle.State = InterProcessConnectionState.ConnectedToServer; + return true; + } else { + handle.State = InterProcessConnectionState.Error; + return false; + } + } + #region Comments + /// + /// Connects to a server named pipe on the same machine. + /// + /// The pipe name. + /// The pipe handle, which also contains the pipe state. + /// This method is used by clients to establish a pipe connection with a server pipe. + #endregion + public static PipeHandle ConnectToPipe(string pipeName) { + return ConnectToPipe(pipeName, "."); + } + #region Comments + /// + /// Connects to a server named pipe. + /// + /// The pipe name. + /// The server name. + /// The pipe handle, which also contains the pipe state. + /// This method is used by clients to establish a pipe connection with a server pipe. + #endregion + public static PipeHandle ConnectToPipe(string pipeName, string serverName) { + PipeHandle handle = new PipeHandle(); + // Build the name of the pipe. + string name = @"\\" + serverName + @"\pipe\" + pipeName; + + for (int i = 1; i<=ATTEMPTS; i++) { + handle.State = InterProcessConnectionState.ConnectingToServer; + // Try to connect to the server + handle.Handle = NamedPipeNative.CreateFile(name, NamedPipeNative.GENERIC_READ | NamedPipeNative.GENERIC_WRITE, 0, null, NamedPipeNative.OPEN_EXISTING, 0, 0); + if (handle.Handle.ToInt32() != NamedPipeNative.INVALID_HANDLE_VALUE) { + // The client managed to connect to the server pipe + handle.State = InterProcessConnectionState.ConnectedToServer; + // Set the read mode of the pipe channel + uint mode = NamedPipeNative.PIPE_READMODE_MESSAGE; + if (NamedPipeNative.SetNamedPipeHandleState(handle.Handle, ref mode, IntPtr.Zero, IntPtr.Zero)) { + break; + } + if (i >= ATTEMPTS) { + handle.State = InterProcessConnectionState.Error; + throw new NamedPipeIOException("Error setting read mode on pipe " + name + " . Internal error: " + NamedPipeNative.GetLastError().ToString(), NamedPipeNative.GetLastError()); + } + } + if (i >= ATTEMPTS) { + if (NamedPipeNative.GetLastError() != NamedPipeNative.ERROR_PIPE_BUSY) { + handle.State = InterProcessConnectionState.Error; + // After a certain number of unsuccessful attempt raise an exception + throw new NamedPipeIOException("Error connecting to pipe " + name + " . Internal error: " + NamedPipeNative.GetLastError().ToString(), NamedPipeNative.GetLastError()); + } else { + handle.State = InterProcessConnectionState.Error; + throw new NamedPipeIOException("Pipe " + name + " is too busy. Internal error: " + NamedPipeNative.GetLastError().ToString(), NamedPipeNative.GetLastError()); + } + } else { + // The pipe is busy so lets wait for some time and try again + if (NamedPipeNative.GetLastError() == NamedPipeNative.ERROR_PIPE_BUSY) + NamedPipeNative.WaitNamedPipe(name, WAIT_TIME); + } + } + + return handle; + } + #region Comments + /// + /// Creates a server named pipe. + /// + /// The name of the pipe. + /// The size of the outbound buffer. + /// The size of the inbound buffer. + /// The pipe handle. + #endregion + public static PipeHandle Create(string name, uint outBuffer, uint inBuffer) { + return Create(name, outBuffer, inBuffer, true); + } + #region Comments + /// + /// Creates a server named pipe. + /// + /// The name of the pipe. + /// The size of the outbound buffer. + /// The size of the inbound buffer. + /// Specifies whether to make the pipe secure. + /// The pipe handle. + /// You can specify a security descriptor for a named pipe when you call the CreateNamedPipe function. The security descriptor controls access to both client and server ends of the named pipe. If NULL is specified, the named pipe gets a default security descriptor. 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. + ///

+ /// If the secure parameter is false the method creates a security descriptor that grants full access to Everyone. + ///
+ #endregion + public static PipeHandle Create(string name, uint outBuffer, uint inBuffer, bool secure) { + if ((name.IndexOf("pipe") < 0) && (name.IndexOf("PIPE") < 0)) + name = @"\\.\pipe\" + name; + + PipeHandle handle = new PipeHandle(); + IntPtr secAttr = IntPtr.Zero; + SECURITY_ATTRIBUTES sa = new SECURITY_ATTRIBUTES(); + + if (!secure) { + SECURITY_DESCRIPTOR sd; + GetNullDaclSecurityDescriptor(out sd); + sa.lpSecurityDescriptor = Marshal.AllocHGlobal(Marshal.SizeOf(typeof(SECURITY_DESCRIPTOR))); + Marshal.StructureToPtr(sd, sa.lpSecurityDescriptor, false); + sa.bInheritHandle = false; + sa.nLength = Marshal.SizeOf(typeof(SECURITY_ATTRIBUTES)); + secAttr = Marshal.AllocHGlobal(Marshal.SizeOf(typeof(SECURITY_ATTRIBUTES))); + Marshal.StructureToPtr(sa, secAttr, false); + } + + try { + for (int i = 1; i<=ATTEMPTS; i++) { + handle.State = InterProcessConnectionState.Creating; + handle.Handle = NamedPipeNative.CreateNamedPipe( + name, + NamedPipeNative.PIPE_ACCESS_DUPLEX, + NamedPipeNative.PIPE_TYPE_MESSAGE | NamedPipeNative.PIPE_READMODE_MESSAGE | NamedPipeNative.PIPE_WAIT, + NamedPipeNative.PIPE_UNLIMITED_INSTANCES, + outBuffer, + inBuffer, + NamedPipeNative.NMPWAIT_WAIT_FOREVER, + secAttr); + if (handle.Handle.ToInt32() != NamedPipeNative.INVALID_HANDLE_VALUE) { + handle.State = InterProcessConnectionState.Created; + break; + } + if (i >= ATTEMPTS) { + handle.State = InterProcessConnectionState.Error; + throw new NamedPipeIOException("Error creating named pipe " + name + " . Internal error: " + NamedPipeNative.GetLastError().ToString(), NamedPipeNative.GetLastError()); + } + } + } + finally { + if (!secure) { + Marshal.FreeHGlobal(sa.lpSecurityDescriptor); + Marshal.FreeHGlobal(secAttr); + } + } + return handle; + } + #region Comments + /// + /// Creates a SECURITY_DESCRIPTOR with DACL = null, which allows full access to Everyone. + /// + /// The SECURITY_DESCRIPTOR structure. + #endregion + public static void GetNullDaclSecurityDescriptor(out SECURITY_DESCRIPTOR sd) { + if(NamedPipeNative.InitializeSecurityDescriptor(out sd, 1)) { + if(!NamedPipeNative.SetSecurityDescriptorDacl(ref sd, true, IntPtr.Zero, false)) { + throw new NamedPipeIOException("Error setting SECURITY_DESCRIPTOR attributes. Internal error: " + NamedPipeNative.GetLastError().ToString(), NamedPipeNative.GetLastError()); + } + } + else { + throw new NamedPipeIOException("Error setting SECURITY_DESCRIPTOR attributes. Internal error: " + NamedPipeNative.GetLastError().ToString(), NamedPipeNative.GetLastError()); + } + } + #region Comments + /// + /// Starts waiting for client connections. + /// + /// + /// Blocks the current execution until a client pipe attempts to establish a connection. + /// + /// The pipe handle. + #endregion + public static void Connect(PipeHandle handle) { + handle.State = InterProcessConnectionState.WaitingForClient; + bool connected = NamedPipeNative.ConnectNamedPipe(handle.Handle, null); + handle.State = InterProcessConnectionState.ConnectedToClient; + if (!connected && NamedPipeNative.GetLastError() != NamedPipeNative.ERROR_PIPE_CONNECTED) { + handle.State = InterProcessConnectionState.Error; + throw new NamedPipeIOException("Error connecting pipe. Internal error: " + NamedPipeNative.GetLastError().ToString(), NamedPipeNative.GetLastError()); + } + } + #region Comments + /// + /// Returns the number of instances of a named pipe. + /// + /// The pipe handle. + /// The number of instances. + #endregion + public static uint NumberPipeInstances(PipeHandle handle) { + uint curInstances = 0; + + if (NamedPipeNative.GetNamedPipeHandleState(handle.Handle, IntPtr.Zero, ref curInstances, IntPtr.Zero, IntPtr.Zero, IntPtr.Zero, IntPtr.Zero)) { + return curInstances; + } + else { + throw new NamedPipeIOException("Error getting the pipe state. Internal error: " + NamedPipeNative.GetLastError().ToString(), NamedPipeNative.GetLastError()); + } + } + #region Comments + /// + /// Closes a named pipe and releases the native handle. + /// + /// The pipe handle. + #endregion + public static void Close(PipeHandle handle) { + handle.State = InterProcessConnectionState.Closing; + NamedPipeNative.CloseHandle(handle.Handle); + handle.Handle = IntPtr.Zero; + handle.State = InterProcessConnectionState.Closed; + } + #region Comments + /// + /// Flushes all the data in a named pipe. + /// + /// The pipe handle. + #endregion + public static void Flush(PipeHandle handle) { + handle.State = InterProcessConnectionState.Flushing; + NamedPipeNative.FlushFileBuffers(handle.Handle); + handle.State = InterProcessConnectionState.FlushedData; + } + #region Comments + /// + /// Disconnects a server named pipe from the client. + /// + /// + /// Server pipes can be reused by first disconnecting them from the client and then + /// calling the Connect + /// method to start listening. This improves the performance as it is not necessary + /// to create new pipe handles. + /// + /// The pipe handle. + #endregion + public static void Disconnect(PipeHandle handle) { + handle.State = InterProcessConnectionState.Disconnecting; + NamedPipeNative.DisconnectNamedPipe(handle.Handle); + handle.State = InterProcessConnectionState.Disconnected; + } + #region Comments + /// + /// Private constructor. + /// + #endregion + private NamedPipeWrapper() {} + } +} \ No newline at end of file diff --git a/extern/w32/namedpipes/AppModule.NamedPipes/PipeHandle.cs b/extern/w32/namedpipes/AppModule.NamedPipes/PipeHandle.cs new file mode 100644 index 00000000..3bde3b96 --- /dev/null +++ b/extern/w32/namedpipes/AppModule.NamedPipes/PipeHandle.cs @@ -0,0 +1,55 @@ +using System; + +using AppModule.InterProcessComm; + +namespace AppModule.NamedPipes { + #region Comments + /// + /// Holds the operating system native handle and the current state of the pipe connection. + /// + #endregion + public sealed class PipeHandle { + #region Comments + /// + /// The operating system native handle. + /// + #endregion + public IntPtr Handle; + #region Comments + /// + /// The current state of the pipe connection. + /// + #endregion + public InterProcessConnectionState State; + #region Comments + /// + /// Creates a PipeHandle instance using the passed native handle. + /// + /// The native handle. + #endregion + public PipeHandle (int hnd) { + this.Handle = new IntPtr(hnd); + this.State = InterProcessConnectionState.NotSet; + } + #region Comments + /// + /// Creates a PipeHandle instance using the provided native handle and state. + /// + /// The native handle. + /// The state of the pipe connection. + #endregion + public PipeHandle (int hnd, InterProcessConnectionState state) { + this.Handle = new IntPtr(hnd); + this.State = state; + } + #region Comments + /// + /// Creates a PipeHandle instance with an invalid native handle. + /// + #endregion + public PipeHandle () { + this.Handle = new IntPtr(NamedPipeNative.INVALID_HANDLE_VALUE); + this.State = InterProcessConnectionState.NotSet; + } + } +} \ No newline at end of file diff --git a/extern/w32/namedpipes/AppModule.NamedPipes/ServerPipeConnection.cs b/extern/w32/namedpipes/AppModule.NamedPipes/ServerPipeConnection.cs new file mode 100644 index 00000000..5b5c739c --- /dev/null +++ b/extern/w32/namedpipes/AppModule.NamedPipes/ServerPipeConnection.cs @@ -0,0 +1,96 @@ +using System; +using System.IO; + +using AppModule.InterProcessComm; + +namespace AppModule.NamedPipes { + #region Comments + /// + /// Used by server applications to communicate with client ones by using named pipes. + /// + #endregion + public sealed class ServerPipeConnection : APipeConnection { + #region Comments + /// + /// Disconnects a client named pipe. + /// + /// + /// When a client named pipe is disconnected, the server one is not closed. + /// The latter can later be reused by starting to listen again.

+ /// In a message oriented protocol the server will disconnect the client when the + /// response is sent and all the data is flushed. The same server named pipe + /// could then be reused by calling the + /// Connect method. + ///
+ #endregion + public void Disconnect() { + CheckIfDisposed(); + NamedPipeWrapper.Disconnect(this.Handle); + } + #region Comments + /// + /// Closes the operating system native handle of the named pipe. + /// + #endregion + public override void Close() { + CheckIfDisposed(); + NamedPipeWrapper.Close(this.Handle); + } + #region Comments + /// + /// Starts listening to client pipe connections. + /// + /// + /// This method will block the program execution until a client pipe attempts + /// to establish a connection.

+ /// When a client named pipe is disconnected, the server one is not closed. + /// The latter can later be reused by starting to listen again.

+ ///
+ #endregion + public override void Connect() { + CheckIfDisposed(); + NamedPipeWrapper.Connect(this.Handle); + } + #region Comments + /// + /// Creates a ServerPipeConnection instance and the underlying operating system handle. + /// + /// The name of the pipe. + /// The outbound buffer. + /// The inbound buffer. + /// The maximum bytes to read from clients. + #endregion + public ServerPipeConnection(string name, uint outBuffer, uint inBuffer, int maxReadBytes) { + this.Name = name; + this.Handle = NamedPipeWrapper.Create(name, outBuffer, inBuffer, true); + this.maxReadBytes = maxReadBytes; + } + #region Comments + /// + /// Creates a ServerPipeConnection instance and the underlying operating system handle. + /// + /// The name of the pipe. + /// The outbound buffer. + /// The inbound buffer. + /// Specifies whether the pipe is secure. + /// The maximum bytes to read from clients. + /// If the secure parameter is true the default security descriptor is used. 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. + ///

+ /// If the secure parameter is false the method creates a security descriptor that grants full access to Everyone. + ///
+ #endregion + public ServerPipeConnection(string name, uint outBuffer, uint inBuffer, int maxReadBytes, bool secure) { + this.Name = name; + this.Handle = NamedPipeWrapper.Create(name, outBuffer, inBuffer, secure); + this.maxReadBytes = maxReadBytes; + } + #region Comments + /// + /// Object destructor. + /// + #endregion + ~ServerPipeConnection() { + Dispose(false); + } + } +} \ No newline at end of file