Abstract NamedPipes code for windows

This commit is contained in:
Jim Norman 2006-01-17 23:06:37 +00:00
parent 36b193d3eb
commit 12209176e7
24 changed files with 4354 additions and 0 deletions

View File

@ -0,0 +1,120 @@
<VisualStudioProject>
<CSHARP
ProjectType = "Local"
ProductVersion = "7.10.3077"
SchemaVersion = "2.0"
ProjectGuid = "{E98F1F7E-40B6-44C8-AC66-EC867B141FA1}"
>
<Build>
<Settings
ApplicationIcon = ""
AssemblyKeyContainerName = ""
AssemblyName = "AppModule.InterProcessComm"
AssemblyOriginatorKeyFile = ""
DefaultClientScript = "JScript"
DefaultHTMLPageLayout = "Grid"
DefaultTargetSchema = "IE50"
DelaySign = "false"
OutputType = "Library"
PreBuildEvent = ""
PostBuildEvent = ""
RootNamespace = "AppModule.InterProcessComm"
RunPostBuildEvent = "OnBuildSuccess"
StartupObject = ""
>
<Config
Name = "Debug"
AllowUnsafeBlocks = "false"
BaseAddress = "285212672"
CheckForOverflowUnderflow = "false"
ConfigurationOverrideFile = ""
DefineConstants = "DEBUG;TRACE"
DocumentationFile = "AppModule.InterProcessComm.xml"
DebugSymbols = "true"
FileAlignment = "4096"
IncrementalBuild = "false"
NoStdLib = "false"
NoWarn = ""
Optimize = "false"
OutputPath = "bin\Debug\"
RegisterForComInterop = "false"
RemoveIntegerChecks = "false"
TreatWarningsAsErrors = "false"
WarningLevel = "4"
/>
<Config
Name = "Release"
AllowUnsafeBlocks = "false"
BaseAddress = "285212672"
CheckForOverflowUnderflow = "false"
ConfigurationOverrideFile = ""
DefineConstants = "TRACE"
DocumentationFile = ""
DebugSymbols = "false"
FileAlignment = "4096"
IncrementalBuild = "false"
NoStdLib = "false"
NoWarn = ""
Optimize = "true"
OutputPath = "bin\Release\"
RegisterForComInterop = "false"
RemoveIntegerChecks = "false"
TreatWarningsAsErrors = "false"
WarningLevel = "4"
/>
</Settings>
<References>
<Reference
Name = "System"
AssemblyName = "System"
HintPath = "C:\WINDOWS\Microsoft.NET\Framework\v1.1.4322\System.dll"
/>
<Reference
Name = "System.Data"
AssemblyName = "System.Data"
HintPath = "C:\WINDOWS\Microsoft.NET\Framework\v1.1.4322\System.Data.dll"
/>
<Reference
Name = "System.XML"
AssemblyName = "System.Xml"
HintPath = "C:\WINDOWS\Microsoft.NET\Framework\v1.1.4322\System.XML.dll"
/>
</References>
</Build>
<Files>
<Include>
<File
RelPath = "AssemblyInfo.cs"
SubType = "Code"
BuildAction = "Compile"
/>
<File
RelPath = "IChannelManager.cs"
SubType = "Code"
BuildAction = "Compile"
/>
<File
RelPath = "IClientChannel.cs"
SubType = "Code"
BuildAction = "Compile"
/>
<File
RelPath = "IInterProcessConnection.cs"
SubType = "Code"
BuildAction = "Compile"
/>
<File
RelPath = "InterProcessConnectionState.cs"
SubType = "Code"
BuildAction = "Compile"
/>
<File
RelPath = "InterProcessIOException.cs"
SubType = "Code"
BuildAction = "Compile"
/>
</Include>
</Files>
</CSHARP>
</VisualStudioProject>

View File

@ -0,0 +1,48 @@
<VisualStudioProject>
<CSHARP LastOpenVersion = "7.10.3077" >
<Build>
<Settings ReferencePath = "" >
<Config
Name = "Debug"
EnableASPDebugging = "false"
EnableASPXDebugging = "false"
EnableUnmanagedDebugging = "false"
EnableSQLServerDebugging = "false"
RemoteDebugEnabled = "false"
RemoteDebugMachine = ""
StartAction = "Project"
StartArguments = ""
StartPage = ""
StartProgram = ""
StartURL = ""
StartWorkingDirectory = ""
StartWithIE = "true"
/>
<Config
Name = "Release"
EnableASPDebugging = "false"
EnableASPXDebugging = "false"
EnableUnmanagedDebugging = "false"
EnableSQLServerDebugging = "false"
RemoteDebugEnabled = "false"
RemoteDebugMachine = ""
StartAction = "Project"
StartArguments = ""
StartPage = ""
StartProgram = ""
StartURL = ""
StartWorkingDirectory = ""
StartWithIE = "true"
/>
</Settings>
</Build>
<OtherProjectSettings
CopyProjectDestinationFolder = ""
CopyProjectUncPath = ""
CopyProjectOption = "0"
ProjectView = "ProjectFiles"
ProjectTrust = "0"
/>
</CSHARP>
</VisualStudioProject>

View File

@ -0,0 +1,263 @@
<?xml version="1.0"?>
<doc>
<assembly>
<name>AppModule.InterProcessComm</name>
</assembly>
<members>
<member name="T:AppModule.InterProcessComm.IChannelManager">
<summary>
Interface, which defines methods for a Channel Manager class.
</summary>
<remarks>
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 <see cref="M:AppModule.InterProcessComm.IChannelManager.HandleRequest(System.String)">HandleRequest</see> method of the Channel Manager.
</remarks>
</member>
<member name="M:AppModule.InterProcessComm.IChannelManager.Initialize">
<summary>
Initializes the Channel Manager.
</summary>
</member>
<member name="M:AppModule.InterProcessComm.IChannelManager.Stop">
<summary>
Closes all opened channels and stops the Channel Manager.
</summary>
</member>
<member name="M:AppModule.InterProcessComm.IChannelManager.HandleRequest(System.String)">
<summary>
Handles a request.
</summary>
<remarks>
This method currently caters for text based requests. XML strings can be used in case complex request structures are needed.
</remarks>
<param name="request">The incoming request.</param>
<returns>The resulting response.</returns>
</member>
<member name="M:AppModule.InterProcessComm.IChannelManager.WakeUp">
<summary>
Forces the Channel Manager to exit a sleeping mode and create a new channel.
</summary>
<remarks>
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.
</remarks>
</member>
<member name="M:AppModule.InterProcessComm.IChannelManager.RemoveServerChannel(System.Object)">
<summary>
Removes an existing channel.
</summary>
<param name="param">A parameter identifying the channel.</param>
</member>
<member name="P:AppModule.InterProcessComm.IChannelManager.Listen">
<summary>
Indicates whether the Channel Manager is in listening mode.
</summary>
<remarks>
This property is left public so that other classes, like a server channel can start or stop listening based on the Channel Manager mode.
</remarks>
</member>
<member name="T:AppModule.InterProcessComm.IClientChannel">
<summary>
</summary>
</member>
<member name="M:AppModule.InterProcessComm.IClientChannel.HandleRequest(System.String)">
<summary>
</summary>
<param name="request"></param>
<returns></returns>
</member>
<member name="M:AppModule.InterProcessComm.IClientChannel.HandleRequest(System.IO.Stream)">
<summary>
</summary>
<param name="request"></param>
<returns></returns>
</member>
<member name="M:AppModule.InterProcessComm.IClientChannel.HandleRequest(System.Object)">
<summary>
</summary>
<param name="request"></param>
<returns></returns>
</member>
<member name="M:AppModule.InterProcessComm.IClientChannel.Create">
<summary>
</summary>
<returns></returns>
</member>
<member name="T:AppModule.InterProcessComm.IInterProcessConnection">
<summary>
</summary>
</member>
<member name="M:AppModule.InterProcessComm.IInterProcessConnection.Connect">
<summary>
</summary>
</member>
<member name="M:AppModule.InterProcessComm.IInterProcessConnection.Close">
<summary>
</summary>
</member>
<member name="M:AppModule.InterProcessComm.IInterProcessConnection.Read">
<summary>
</summary>
<returns></returns>
</member>
<member name="M:AppModule.InterProcessComm.IInterProcessConnection.ReadBytes">
<summary>
</summary>
<returns></returns>
</member>
<member name="M:AppModule.InterProcessComm.IInterProcessConnection.Write(System.String)">
<summary>
</summary>
<param name="text"></param>
</member>
<member name="M:AppModule.InterProcessComm.IInterProcessConnection.WriteBytes(System.Byte[])">
<summary>
</summary>
<param name="bytes"></param>
</member>
<member name="M:AppModule.InterProcessComm.IInterProcessConnection.GetState">
<summary>
</summary>
<returns></returns>
</member>
<member name="P:AppModule.InterProcessComm.IInterProcessConnection.NativeHandle">
<summary>
</summary>
</member>
<member name="T:AppModule.InterProcessComm.InterProcessConnectionState">
<summary>
</summary>
</member>
<member name="F:AppModule.InterProcessComm.InterProcessConnectionState.NotSet">
<summary>
</summary>
</member>
<member name="F:AppModule.InterProcessComm.InterProcessConnectionState.Error">
<summary>
</summary>
</member>
<member name="F:AppModule.InterProcessComm.InterProcessConnectionState.Creating">
<summary>
</summary>
</member>
<member name="F:AppModule.InterProcessComm.InterProcessConnectionState.Created">
<summary>
</summary>
</member>
<member name="F:AppModule.InterProcessComm.InterProcessConnectionState.WaitingForClient">
<summary>
</summary>
</member>
<member name="F:AppModule.InterProcessComm.InterProcessConnectionState.ConnectedToClient">
<summary>
</summary>
</member>
<member name="F:AppModule.InterProcessComm.InterProcessConnectionState.ConnectingToServer">
<summary>
</summary>
</member>
<member name="F:AppModule.InterProcessComm.InterProcessConnectionState.ConnectedToServer">
<summary>
</summary>
</member>
<member name="F:AppModule.InterProcessComm.InterProcessConnectionState.Reading">
<summary>
</summary>
</member>
<member name="F:AppModule.InterProcessComm.InterProcessConnectionState.ReadData">
<summary>
</summary>
</member>
<member name="F:AppModule.InterProcessComm.InterProcessConnectionState.Writing">
<summary>
</summary>
</member>
<member name="F:AppModule.InterProcessComm.InterProcessConnectionState.WroteData">
<summary>
</summary>
</member>
<member name="F:AppModule.InterProcessComm.InterProcessConnectionState.Flushing">
<summary>
</summary>
</member>
<member name="F:AppModule.InterProcessComm.InterProcessConnectionState.FlushedData">
<summary>
</summary>
</member>
<member name="F:AppModule.InterProcessComm.InterProcessConnectionState.Disconnecting">
<summary>
</summary>
</member>
<member name="F:AppModule.InterProcessComm.InterProcessConnectionState.Disconnected">
<summary>
</summary>
</member>
<member name="F:AppModule.InterProcessComm.InterProcessConnectionState.Closing">
<summary>
</summary>
</member>
<member name="F:AppModule.InterProcessComm.InterProcessConnectionState.Closed">
<summary>
</summary>
</member>
<member name="T:AppModule.InterProcessComm.InterProcessIOException">
<summary>
</summary>
</member>
<member name="F:AppModule.InterProcessComm.InterProcessIOException.IsServerAvailable">
<summary>
</summary>
</member>
<member name="F:AppModule.InterProcessComm.InterProcessIOException.ErrorCode">
<summary>
</summary>
</member>
<member name="M:AppModule.InterProcessComm.InterProcessIOException.#ctor(System.String)">
<summary>
</summary>
<param name="text"></param>
</member>
<member name="M:AppModule.InterProcessComm.InterProcessIOException.#ctor(System.Runtime.Serialization.SerializationInfo,System.Runtime.Serialization.StreamingContext)">
<summary>
</summary>
<param name="info"></param>
<param name="context"></param>
</member>
</members>
</doc>

View File

@ -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\<configuration>. 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.
//

View File

@ -0,0 +1,63 @@
using System;
namespace AppModule.InterProcessComm {
#region Comments
/// <summary>
/// Interface, which defines methods for a Channel Manager class.
/// </summary>
/// <remarks>
/// 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 <see cref="AppModule.InterProcessComm.IChannelManager.HandleRequest">HandleRequest</see> method of the Channel Manager.
/// </remarks>
#endregion
public interface IChannelManager {
#region Comments
/// <summary>
/// Initializes the Channel Manager.
/// </summary>
#endregion
void Initialize();
void Start();
#region Comments
/// <summary>
/// Closes all opened channels and stops the Channel Manager.
/// </summary>
#endregion
void Stop();
#region Comments
/// <summary>
/// Handles a request.
/// </summary>
/// <remarks>
/// This method currently caters for text based requests. XML strings can be used in case complex request structures are needed.
/// </remarks>
/// <param name="request">The incoming request.</param>
/// <returns>The resulting response.</returns>
#endregion
string HandleRequest(string request);
#region Comments
/// <summary>
/// Indicates whether the Channel Manager is in listening mode.
/// </summary>
/// <remarks>
/// This property is left public so that other classes, like a server channel can start or stop listening based on the Channel Manager mode.
/// </remarks>
#endregion
bool Listen {get; set;}
#region Comments
/// <summary>
/// Forces the Channel Manager to exit a sleeping mode and create a new channel.
/// </summary>
/// <remarks>
/// 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.
/// </remarks>
#endregion
void WakeUp();
#region Comments
/// <summary>
/// Removes an existing channel.
/// </summary>
/// <param name="param">A parameter identifying the channel.</param>
#endregion
void RemoveServerChannel(object param);
}
}

View File

@ -0,0 +1,43 @@
using System;
using System.IO;
namespace AppModule.InterProcessComm {
#region Comments
/// <summary>
///
/// </summary>
#endregion
public interface IClientChannel : IDisposable {
#region Comments
/// <summary>
///
/// </summary>
/// <param name="request"></param>
/// <returns></returns>
#endregion
string HandleRequest(string request);
#region Comments
/// <summary>
///
/// </summary>
/// <param name="request"></param>
/// <returns></returns>
#endregion
string HandleRequest(Stream request);
#region Comments
/// <summary>
///
/// </summary>
/// <param name="request"></param>
/// <returns></returns>
#endregion
object HandleRequest(object request);
#region Comments
/// <summary>
///
/// </summary>
/// <returns></returns>
#endregion
IClientChannel Create();
}
}

View File

@ -0,0 +1,64 @@
using System;
namespace AppModule.InterProcessComm {
#region Comments
/// <summary>
///
/// </summary>
#endregion
public interface IInterProcessConnection : IDisposable {
#region Comments
/// <summary>
///
/// </summary>
#endregion
int NativeHandle{get;}
#region Comments
/// <summary>
///
/// </summary>
#endregion
void Connect();
#region Comments
/// <summary>
///
/// </summary>
#endregion
void Close();
#region Comments
/// <summary>
///
/// </summary>
/// <returns></returns>
#endregion
string Read();
#region Comments
/// <summary>
///
/// </summary>
/// <returns></returns>
#endregion
byte[] ReadBytes();
#region Comments
/// <summary>
///
/// </summary>
/// <param name="text"></param>
#endregion
void Write(string text);
#region Comments
/// <summary>
///
/// </summary>
/// <param name="bytes"></param>
#endregion
void WriteBytes(byte[] bytes);
#region Comments
/// <summary>
///
/// </summary>
/// <returns></returns>
#endregion
InterProcessConnectionState GetState();
}
}

View File

@ -0,0 +1,119 @@
using System;
namespace AppModule.InterProcessComm {
#region Comments
/// <summary>
///
/// </summary>
#endregion
public enum InterProcessConnectionState {
#region Comments
/// <summary>
///
/// </summary>
#endregion
NotSet = 0,
#region Comments
/// <summary>
///
/// </summary>
#endregion
Error = 1,
#region Comments
/// <summary>
///
/// </summary>
#endregion
Creating = 2,
#region Comments
/// <summary>
///
/// </summary>
#endregion
Created = 3,
#region Comments
/// <summary>
///
/// </summary>
#endregion
WaitingForClient = 4,
#region Comments
/// <summary>
///
/// </summary>
#endregion
ConnectedToClient = 5,
#region Comments
/// <summary>
///
/// </summary>
#endregion
ConnectingToServer = 6,
#region Comments
/// <summary>
///
/// </summary>
#endregion
ConnectedToServer = 7,
#region Comments
/// <summary>
///
/// </summary>
#endregion
Reading = 8,
#region Comments
/// <summary>
///
/// </summary>
#endregion
ReadData = 9,
#region Comments
/// <summary>
///
/// </summary>
#endregion
Writing = 10,
#region Comments
/// <summary>
///
/// </summary>
#endregion
WroteData = 11,
#region Comments
/// <summary>
///
/// </summary>
#endregion
Flushing = 12,
#region Comments
/// <summary>
///
/// </summary>
#endregion
FlushedData = 13,
#region Comments
/// <summary>
///
/// </summary>
#endregion
Disconnecting = 14,
#region Comments
/// <summary>
///
/// </summary>
#endregion
Disconnected = 15,
#region Comments
/// <summary>
///
/// </summary>
#endregion
Closing = 16,
#region Comments
/// <summary>
///
/// </summary>
#endregion
Closed = 17,
}
}

View File

@ -0,0 +1,41 @@
using System;
using System.Runtime.Serialization;
namespace AppModule.InterProcessComm {
#region Comments
/// <summary>
///
/// </summary>
#endregion
public class InterProcessIOException : Exception {
#region Comments
/// <summary>
///
/// </summary>
#endregion
public bool IsServerAvailable = true;
#region Comments
/// <summary>
///
/// </summary>
#endregion
public uint ErrorCode = 0;
#region Comments
/// <summary>
///
/// </summary>
/// <param name="text"></param>
#endregion
public InterProcessIOException(String text) : base(text) {
}
#region Comments
/// <summary>
///
/// </summary>
/// <param name="info"></param>
/// <param name="context"></param>
#endregion
protected InterProcessIOException(SerializationInfo info, StreamingContext context) : base(info, context) {
}
}
}

Binary file not shown.

View File

@ -0,0 +1,175 @@
using System;
using System.IO;
using AppModule.InterProcessComm;
namespace AppModule.NamedPipes {
#region Comments
/// <summary>
/// An abstract class, which defines the methods for creating named pipes
/// connections, reading and writing data.
/// </summary>
/// <remarks>
/// This class is inherited by
/// <see cref="AppModule.NamedPipes.ClientPipeConnection">ClientPipeConnection</see>
/// and <see cref="AppModule.NamedPipes.ServerPipeConnection">ServerPipeConnection</see>
/// classes, used for client and server applications respectively, which communicate
/// using NamesPipes.
/// </remarks>
#endregion
public abstract class APipeConnection : IInterProcessConnection {
#region Comments
/// <summary>
/// A <see cref="AppModule.NamedPipes.PipeHandle">PipeHandle</see> object containing
/// the native pipe handle.
/// </summary>
#endregion
protected PipeHandle Handle = new PipeHandle();
#region Comments
/// <summary>
/// The name of the named pipe.
/// </summary>
/// <remarks>
/// This name is used for creating a server pipe and connecting client ones to it.
/// </remarks>
#endregion
protected string Name;
#region Comments
/// <summary>
/// Boolean field used by the IDisposable implementation.
/// </summary>
#endregion
protected bool disposed = false;
#region Comments
/// <summary>
/// The maximum bytes that will be read from the pipe connection.
/// </summary>
/// <remarks>
/// 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.
/// </remarks>
#endregion
protected int maxReadBytes;
#region Comments
/// <summary>
/// Reads a message from the pipe connection and converts it to a string
/// using the UTF8 encoding.
/// </summary>
/// <remarks>
/// See the <see cref="AppModule.NamedPipes.NamedPipeWrapper.Read">NamedPipeWrapper.Read</see>
/// method for an explanation of the message format.
/// </remarks>
/// <returns>The UTF8 encoded string representation of the data.</returns>
#endregion
public string Read() {
CheckIfDisposed();
return NamedPipeWrapper.Read(Handle, maxReadBytes);
}
#region Comments
/// <summary>
/// Reads a message from the pipe connection.
/// </summary>
/// <remarks>
/// See the <see cref="AppModule.NamedPipes.NamedPipeWrapper.ReadBytes">NamedPipeWrapper.ReadBytes</see>
/// method for an explanation of the message format.
/// </remarks>
/// <returns>The bytes read from the pipe connection.</returns>
#endregion
public byte[] ReadBytes() {
CheckIfDisposed();
return NamedPipeWrapper.ReadBytes(Handle, maxReadBytes);
}
#region Comments
/// <summary>
/// Writes a string to the pipe connection/
/// </summary>
/// <param name="text">The text to write.</param>
#endregion
public void Write(string text) {
CheckIfDisposed();
NamedPipeWrapper.Write(Handle, text);
}
#region Comments
/// <summary>
/// Writes an array of bytes to the pipe connection.
/// </summary>
/// <param name="bytes">The bytes array.</param>
#endregion
public void WriteBytes(byte[] bytes) {
CheckIfDisposed();
NamedPipeWrapper.WriteBytes(Handle, bytes);
}
#region Comments
/// <summary>
/// Closes the pipe connection.
/// </summary>
#endregion
public abstract void Close();
#region Comments
/// <summary>
/// Connects a pipe connection.
/// </summary>
#endregion
public abstract void Connect();
#region Comments
/// <summary>
/// Disposes a pipe connection by closing the underlying native handle.
/// </summary>
#endregion
public void Dispose() {
Dispose(true);
GC.SuppressFinalize(this);
}
#region Comments
/// <summary>
/// Disposes a pipe connection by closing the underlying native handle.
/// </summary>
/// <param name="disposing">A boolean indicating how the method is called.</param>
#endregion
protected void Dispose(bool disposing) {
if(!this.disposed) {
NamedPipeWrapper.Close(this.Handle);
}
disposed = true;
}
#region Comments
/// <summary>
/// Checks if the pipe connection is disposed.
/// </summary>
/// <remarks>
/// This check is done before performing any pipe operations.
/// </remarks>
#endregion
public void CheckIfDisposed() {
if(this.disposed) {
throw new ObjectDisposedException("The Pipe Connection is disposed.");
}
}
#region Comments
/// <summary>
/// Gets the pipe connection state from the <see cref="AppModule.NamedPipes.PipeHandle">PipeHandle</see>
/// object.
/// </summary>
/// <returns>The pipe connection state.</returns>
#endregion
public InterProcessConnectionState GetState() {
CheckIfDisposed();
return this.Handle.State;
}
#region Comments
/// <summary>
/// Retrieved the operating system native handle for the pipe connection.
/// </summary>
#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);
}
}
}

View File

@ -0,0 +1,145 @@
<VisualStudioProject>
<CSHARP
ProjectType = "Local"
ProductVersion = "7.10.3077"
SchemaVersion = "2.0"
ProjectGuid = "{077B53BB-404A-4B2F-BA17-AAE98C5E9C66}"
>
<Build>
<Settings
ApplicationIcon = ""
AssemblyKeyContainerName = ""
AssemblyName = "AppModule.NamedPipes"
AssemblyOriginatorKeyFile = ""
DefaultClientScript = "JScript"
DefaultHTMLPageLayout = "Grid"
DefaultTargetSchema = "IE50"
DelaySign = "false"
OutputType = "Library"
PreBuildEvent = ""
PostBuildEvent = ""
RootNamespace = "AppModule.NamedPipes"
RunPostBuildEvent = "OnBuildSuccess"
StartupObject = ""
>
<Config
Name = "Debug"
AllowUnsafeBlocks = "false"
BaseAddress = "285212672"
CheckForOverflowUnderflow = "false"
ConfigurationOverrideFile = ""
DefineConstants = "DEBUG;TRACE"
DocumentationFile = "AppModule.NamedPipes.xml"
DebugSymbols = "true"
FileAlignment = "4096"
IncrementalBuild = "false"
NoStdLib = "false"
NoWarn = ""
Optimize = "false"
OutputPath = "bin\Debug\"
RegisterForComInterop = "false"
RemoveIntegerChecks = "false"
TreatWarningsAsErrors = "false"
WarningLevel = "4"
/>
<Config
Name = "Release"
AllowUnsafeBlocks = "false"
BaseAddress = "285212672"
CheckForOverflowUnderflow = "false"
ConfigurationOverrideFile = ""
DefineConstants = "TRACE"
DocumentationFile = ""
DebugSymbols = "false"
FileAlignment = "4096"
IncrementalBuild = "false"
NoStdLib = "false"
NoWarn = ""
Optimize = "true"
OutputPath = "bin\Release\"
RegisterForComInterop = "false"
RemoveIntegerChecks = "false"
TreatWarningsAsErrors = "false"
WarningLevel = "4"
/>
</Settings>
<References>
<Reference
Name = "System"
AssemblyName = "System"
HintPath = "..\..\..\..\WINNT\Microsoft.NET\Framework\v1.1.4322\System.dll"
/>
<Reference
Name = "System.Data"
AssemblyName = "System.Data"
HintPath = "..\..\..\..\WINNT\Microsoft.NET\Framework\v1.1.4322\System.Data.dll"
/>
<Reference
Name = "System.XML"
AssemblyName = "System.Xml"
HintPath = "..\..\..\..\WINNT\Microsoft.NET\Framework\v1.1.4322\System.XML.dll"
/>
<Reference
Name = "AppModule.InterProcessComm"
Project = "{E98F1F7E-40B6-44C8-AC66-EC867B141FA1}"
Package = "{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}"
/>
</References>
</Build>
<Files>
<Include>
<File
RelPath = "APipeConnection.cs"
SubType = "Code"
BuildAction = "Compile"
/>
<File
RelPath = "AssemblyInfo.cs"
SubType = "Code"
BuildAction = "Compile"
/>
<File
RelPath = "ClientPipeConnection.cs"
SubType = "Code"
BuildAction = "Compile"
/>
<File
RelPath = "ImpersonateNative.cs"
SubType = "Code"
BuildAction = "Compile"
/>
<File
RelPath = "ImpersonateWrapper.cs"
SubType = "Code"
BuildAction = "Compile"
/>
<File
RelPath = "NamedPipeIOException.cs"
SubType = "Code"
BuildAction = "Compile"
/>
<File
RelPath = "NamedPipeNative.cs"
SubType = "Code"
BuildAction = "Compile"
/>
<File
RelPath = "NamedPipeWrapper.cs"
SubType = "Code"
BuildAction = "Compile"
/>
<File
RelPath = "PipeHandle.cs"
SubType = "Code"
BuildAction = "Compile"
/>
<File
RelPath = "ServerPipeConnection.cs"
SubType = "Code"
BuildAction = "Compile"
/>
</Include>
</Files>
</CSHARP>
</VisualStudioProject>

View File

@ -0,0 +1,48 @@
<VisualStudioProject>
<CSHARP LastOpenVersion = "7.10.3077" >
<Build>
<Settings ReferencePath = "D:\# Projects Test\Win32Security\v0.5_GotDotNet\Win32Security\bin\Debug\" >
<Config
Name = "Debug"
EnableASPDebugging = "false"
EnableASPXDebugging = "false"
EnableUnmanagedDebugging = "false"
EnableSQLServerDebugging = "false"
RemoteDebugEnabled = "false"
RemoteDebugMachine = ""
StartAction = "Project"
StartArguments = ""
StartPage = ""
StartProgram = ""
StartURL = ""
StartWorkingDirectory = ""
StartWithIE = "false"
/>
<Config
Name = "Release"
EnableASPDebugging = "false"
EnableASPXDebugging = "false"
EnableUnmanagedDebugging = "false"
EnableSQLServerDebugging = "false"
RemoteDebugEnabled = "false"
RemoteDebugMachine = ""
StartAction = "Project"
StartArguments = ""
StartPage = ""
StartProgram = ""
StartURL = ""
StartWorkingDirectory = ""
StartWithIE = "true"
/>
</Settings>
</Build>
<OtherProjectSettings
CopyProjectDestinationFolder = ""
CopyProjectUncPath = ""
CopyProjectOption = "0"
ProjectView = "ProjectFiles"
ProjectTrust = "0"
/>
</CSHARP>
</VisualStudioProject>

File diff suppressed because it is too large Load Diff

View File

@ -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\<configuration>. 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.
//

View File

@ -0,0 +1,102 @@
using System;
using System.IO;
using AppModule.InterProcessComm;
namespace AppModule.NamedPipes {
#region Comments
/// <summary>
/// Used by client applications to communicate with server ones by using named pipes.
/// </summary>
#endregion
public sealed class ClientPipeConnection : APipeConnection {
#region Comments
/// <summary>
/// The network name of the server where the server pipe is created.
/// </summary>
/// <remarks>
/// If "." is used as a server name then the pipe is connected to the local machine.
/// </remarks>
#endregion
private string Server = ".";
#region Comments
/// <summary>
/// Closes a client named pipe connection.
/// </summary>
/// <remarks>
/// A client pipe connection is closed by closing the underlying pipe handle.
/// </remarks>
#endregion
public override void Close() {
CheckIfDisposed();
NamedPipeWrapper.Close(this.Handle);
}
#region Comments
/// <summary>
/// Connects a client pipe to an existing server one.
/// </summary>
#endregion
public override void Connect() {
CheckIfDisposed();
this.Handle = NamedPipeWrapper.ConnectToPipe(this.Name, this.Server);
}
#region Comments
/// <summary>
/// Attempts to establish a connection to the a server named pipe.
/// </summary>
/// <remarks>
/// If the attempt is successful the method creates the
/// <see cref="AppModule.NamedPipes.PipeHandle">PipeHandle</see> object
/// and assigns it to the <see cref="AppModule.NamedPipes.APipeConnection.Handle">Handle</see>
/// field.<br/><br/>
/// This method is used when it is not known whether a server pipe already exists.
/// </remarks>
/// <returns>True if a connection is established.</returns>
#endregion
public bool TryConnect() {
CheckIfDisposed();
bool ReturnVal = NamedPipeWrapper.TryConnectToPipe(this.Name, this.Server, out this.Handle);
return ReturnVal;
}
#region Comments
/// <summary>
/// Creates an instance of the ClientPipeConnection assuming that the server pipe
/// is created on the same machine.
/// </summary>
/// <remarks>
/// The maximum bytes to read from the client is set to be Int32.MaxValue.
/// </remarks>
/// <param name="name">The name of the server pipe.</param>
#endregion
public ClientPipeConnection(string name) {
this.Name = name;
this.Server = ".";
this.maxReadBytes = Int32.MaxValue;
}
#region Comments
/// <summary>
/// Creates an instance of the ClientPipeConnection specifying the network name
/// of the server.
/// </summary>
/// <remarks>
/// The maximum bytes to read from the client is set to be Int32.MaxValue.
/// </remarks>
/// <param name="name">The name of the server pipe.</param>
/// <param name="server">The network name of the machine, where the server pipe is created.</param>
#endregion
public ClientPipeConnection(string name, string server) {
this.Name = name;
this.Server = server;
this.maxReadBytes = Int32.MaxValue;
}
#region Comments
/// <summary>
/// Object destructor.
/// </summary>
#endregion
~ClientPipeConnection() {
Dispose(false);
}
}
}

View File

@ -0,0 +1,450 @@
using System;
using System.Text;
using System.Security;
using System.Runtime.InteropServices;
namespace AppModule.NamedPipes {
#region Comments
/// <summary>
/// This utility class exposes kernel32.dll methods for named pipes communication.
/// </summary>
/// <remarks>
/// Use the following links for complete information about the exposed methods:
/// <list type="bullet">
/// <item>
/// <description><a href="http://msdn.microsoft.com/library/default.asp?url=/library/en-us/ipc/base/pipe_functions.asp" target="_blank">Named Pipe Functions</a></description>
/// </item>
/// <item>
/// <description><a href="http://msdn.microsoft.com/library/en-us/fileio/base/file_management_functions.asp" target="_blank">File Management Functions</a></description>
/// </item>
/// <item>
/// <description><a href="http://msdn.microsoft.com/library/default.asp?url=/library/en-us/sysinfo/base/handle_and_object_functions.asp" target="_blank">Handle and Object Functions</a></description>
/// </item>
/// <item>
/// <description><a href="http://msdn.microsoft.com/library/default.asp?url=/library/en-us/debug/base/system_error_codes.asp" target="_blank">System Error Codes</a></description>
/// </item>
/// </list>
/// </remarks>
#endregion
[SuppressUnmanagedCodeSecurity]
public sealed class ImpersonateNative
{
#region Comments
/// <summary>
///
/// </summary>
#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
/// <summary>
/// Creates an instance of a named pipe and returns a handle for
/// subsequent pipe operations.
/// </summary>
/// <param name="lpName">Pointer to the null-terminated string that
/// uniquely identifies the pipe.</param>
/// <param name="dwOpenMode">Pipe access mode, the overlapped mode,
/// the write-through mode, and the security access mode of the pipe handle.</param>
/// <param name="dwPipeMode">Type, read, and wait modes of the pipe handle.</param>
/// <param name="nMaxInstances">Maximum number of instances that can be
/// created for this pipe.</param>
/// <param name="nOutBufferSize">Number of bytes to reserve for the output buffer.</param>
/// <param name="nInBufferSize">Number of bytes to reserve for the input buffer.</param>
/// <param name="nDefaultTimeOut">Default time-out value, in milliseconds.</param>
/// <param name="pipeSecurityDescriptor">Pointer to a
/// <see cref="AppModule.NamedPipes.SecurityAttributes">SecurityAttributes</see>
/// object that specifies a security descriptor for the new named pipe.</param>
/// <returns>If the function succeeds, the return value is a handle
/// to the server end of a named pipe instance.</returns>
#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
/// <summary>
/// Enables a named pipe server process to wait for a client
/// process to connect to an instance of a named pipe.
/// </summary>
/// <param name="hHandle">Handle to the server end of a named pipe instance.</param>
/// <param name="lpOverlapped">Pointer to an
/// <see cref="AppModule.NamedPipes.Overlapped">Overlapped</see> object.</param>
/// <returns>If the function succeeds, the return value is nonzero.</returns>
#endregion
[DllImport("kernel32.dll")]
public static extern bool ConnectNamedPipe(
IntPtr hHandle, // handle to named pipe
Overlapped lpOverlapped // overlapped structure
);
#region Comments
/// <summary>
/// Connects to a message-type pipe (and waits if an instance of the
/// pipe is not available), writes to and reads from the pipe, and then closes the pipe.
/// </summary>
/// <param name="lpNamedPipeName">Pointer to a null-terminated string
/// specifying the pipe name.</param>
/// <param name="lpInBuffer">Pointer to the buffer containing the data written
/// to the pipe.</param>
/// <param name="nInBufferSize">Size of the write buffer, in bytes.</param>
/// <param name="lpOutBuffer">Pointer to the buffer that receives the data
/// read from the pipe.</param>
/// <param name="nOutBufferSize">Size of the read buffer, in bytes.</param>
/// <param name="lpBytesRead">Pointer to a variable that receives the number
/// of bytes read from the pipe.</param>
/// <param name="nTimeOut">Number of milliseconds to wait for the
/// named pipe to be available.</param>
/// <returns>If the function succeeds, the return value is nonzero.</returns>
#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
/// <summary>
/// Creates or opens a file, directory, physical disk, volume, console buffer,
/// tape drive, communications resource, mailslot, or named pipe.
/// </summary>
/// <param name="lpFileName">Pointer to a null-terminated string that
/// specifies the name of the object to create or open.</param>
/// <param name="dwDesiredAccess">Access to the object (reading, writing, or both).</param>
/// <param name="dwShareMode">Sharing mode of the object (reading, writing, both, or neither).</param>
/// <param name="attr">Pointer to a
/// <see cref="AppModule.NamedPipes.SecurityAttributes">SecurityAttributes</see>
/// object that determines whether the returned handle can be inherited
/// by child processes.</param>
/// <param name="dwCreationDisposition">Action to take on files that exist,
/// and which action to take when files do not exist.</param>
/// <param name="dwFlagsAndAttributes">File attributes and flags.</param>
/// <param name="hTemplateFile">Handle to a template file, with the GENERIC_READ access right.</param>
/// <returns>If the function succeeds, the return value is an open handle to the specified file.</returns>
#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
/// <summary>
/// Reads data from a file, starting at the position indicated by the file pointer.
/// </summary>
/// <param name="hHandle">Handle to the file to be read.</param>
/// <param name="lpBuffer">Pointer to the buffer that receives the data read from the file.</param>
/// <param name="nNumberOfBytesToRead">Number of bytes to be read from the file.</param>
/// <param name="lpNumberOfBytesRead">Pointer to the variable that receives the number of bytes read.</param>
/// <param name="lpOverlapped">Pointer to an
/// <see cref="AppModule.NamedPipes.Overlapped">Overlapped</see> object.</param>
/// <returns>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.</returns>
#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
/// <summary>
/// Writes data to a file at the position specified by the file pointer.
/// </summary>
/// <param name="hHandle">Handle to the file.</param>
/// <param name="lpBuffer">Pointer to the buffer containing the data to be written to the file.</param>
/// <param name="nNumberOfBytesToWrite"></param>
/// <param name="lpNumberOfBytesWritten">Pointer to the variable that receives the number of bytes written.</param>
/// <param name="lpOverlapped">Pointer to an
/// <see cref="AppModule.NamedPipes.Overlapped">Overlapped</see> object.</param>
/// <returns>If the function succeeds, the return value is nonzero.</returns>
#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
/// <summary>
/// Retrieves information about a specified named pipe.
/// </summary>
/// <param name="hHandle">Handle to the named pipe for which information is wanted.</param>
/// <param name="lpState">Pointer to a variable that indicates the current
/// state of the handle.</param>
/// <param name="lpCurInstances">Pointer to a variable that receives the
/// number of current pipe instances.</param>
/// <param name="lpMaxCollectionCount">Pointer to a variable that receives
/// the maximum number of bytes to be collected on the client's computer
/// before transmission to the server.</param>
/// <param name="lpCollectDataTimeout">Pointer to a variable that receives
/// the maximum time, in milliseconds, that can pass before a remote named
/// pipe transfers information over the network.</param>
/// <param name="lpUserName">Pointer to a buffer that receives the
/// null-terminated string containing the user name string associated
/// with the client application. </param>
/// <param name="nMaxUserNameSize">Size of the buffer specified by the
/// lpUserName parameter.</param>
/// <returns>If the function succeeds, the return value is nonzero.</returns>
#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
/// <summary>
/// Cancels all pending input and output (I/O) operations that were
/// issued by the calling thread for the specified file handle.
/// </summary>
/// <param name="hHandle">Handle to a file.</param>
/// <returns>If the function succeeds, the return value is nonzero.</returns>
#endregion
[DllImport("kernel32.dll")]
public static extern bool CancelIo(
IntPtr hHandle
);
#region Comments
/// <summary>
/// Waits until either a time-out interval elapses or an instance
/// of the specified named pipe is available for connection.
/// </summary>
/// <param name="name">Pointer to a null-terminated string that specifies
/// the name of the named pipe.</param>
/// <param name="timeout">Number of milliseconds that the function will
/// wait for an instance of the named pipe to be available.</param>
/// <returns>If an instance of the pipe is available before the
/// time-out interval elapses, the return value is nonzero.</returns>
#endregion
[DllImport("kernel32.dll")]
public static extern bool WaitNamedPipe(
String name,
int timeout);
#region Comments
/// <summary>
/// Retrieves the calling thread's last-error code value.
/// </summary>
/// <returns>The return value is the calling thread's last-error code value.</returns>
#endregion
[DllImport("kernel32.dll")]
public static extern uint GetLastError();
#region Comments
/// <summary>
/// Flushes the buffers of the specified file and causes all buffered data to be written to the file.
/// </summary>
/// <param name="hHandle">Handle to an open file.</param>
/// <returns>If the function succeeds, the return value is nonzero.</returns>
#endregion
[DllImport("kernel32.dll")]
public static extern bool FlushFileBuffers(
IntPtr hHandle);
#region Comments
/// <summary>
/// Disconnects the server end of a named pipe instance from a client process.
/// </summary>
/// <param name="hHandle">Handle to an instance of a named pipe.</param>
/// <returns>If the function succeeds, the return value is nonzero.</returns>
#endregion
[DllImport("kernel32.dll")]
public static extern bool DisconnectNamedPipe(
IntPtr hHandle);
#region Comments
/// <summary>
/// Sets the read mode and the blocking mode of the specified named pipe.
/// </summary>
/// <remarks>
/// 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.
/// </remarks>
/// <param name="hHandle">Handle to the named pipe instance.</param>
/// <param name="mode">Pointer to a variable that supplies the new mode.</param>
/// <param name="cc">Pointer to a variable that specifies the maximum
/// number of bytes collected on the client computer before
/// transmission to the server.</param>
/// <param name="cd">Pointer to a variable that specifies the
/// maximum time, in milliseconds, that can pass before a remote
/// named pipe transfers information over the network.</param>
/// <returns>If the function succeeds, the return value is nonzero.</returns>
#endregion
[DllImport("kernel32.dll")]
public static extern bool SetNamedPipeHandleState(
IntPtr hHandle,
ref uint mode,
IntPtr cc,
IntPtr cd);
#region Comments
/// <summary>
/// Closes an open object handle.
/// </summary>
/// <param name="hHandle">Handle to an open object.</param>
/// <returns>If the function succeeds, the return value is nonzero.</returns>
#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
/// <summary>
/// Closes an open object handle.
/// </summary>
/// <param name="hHandle">Handle to an open object.</param>
/// <returns>If the function succeeds, the return value is nonzero.</returns>
#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
/// <summary>
/// Sets the security descriptor attributes
/// </summary>
/// <param name="sd">Reference to a SECURITY_DESCRIPTOR structure.</param>
/// <param name="bDaclPresent"></param>
/// <param name="Dacl"></param>
/// <param name="bDaclDefaulted"></param>
/// <returns></returns>
#endregion
[DllImport("Advapi32.dll", SetLastError=true)]
public static extern bool SetSecurityDescriptorDacl(ref SECURITY_DESCRIPTOR sd, bool bDaclPresent, IntPtr Dacl, bool bDaclDefaulted);
#region Comments
/// <summary>
/// Initializes a SECURITY_DESCRIPTOR structure.
/// </summary>
/// <param name="sd"></param>
/// <param name="dwRevision"></param>
/// <returns></returns>
#endregion
[DllImport("Advapi32.dll", SetLastError=true)]
public static extern bool InitializeSecurityDescriptor(out SECURITY_DESCRIPTOR sd, int dwRevision);
#region Comments
/// <summary>
/// Private constructor.
/// </summary>
#endregion
private ImpersonateNative() {}
}
}

View File

@ -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
/// <summary>
/// A utility class that exposes named pipes operations.
/// </summary>
/// <remarks>
/// This class uses the exposed exposed kernel32.dll methods by the
/// <see cref="AppModule.NamedPipes.NamedPipeNative">NamedPipeNative</see> class
/// to provided controlled named pipe functionality.
/// </remarks>
#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;
}
}
}

View File

@ -0,0 +1,44 @@
using System;
using System.Runtime.Serialization;
using AppModule.InterProcessComm;
namespace AppModule.NamedPipes {
#region Comments
/// <summary>
/// This exception is thrown by named pipes communication methods.
/// </summary>
#endregion
public class NamedPipeIOException : InterProcessIOException {
#region Comments
/// <summary>
/// Creates a NamedPipeIOException instance.
/// </summary>
/// <param name="text">The error message text.</param>
#endregion
public NamedPipeIOException(String text) : base(text) {
}
#region Comments
/// <summary>
/// Creates a NamedPipeIOException instance.
/// </summary>
/// <param name="text">The error message text.</param>
/// <param name="errorCode">The native error code.</param>
#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
/// <summary>
/// Creates a NamedPipeIOException instance.
/// </summary>
/// <param name="info">The serialization information.</param>
/// <param name="context">The streaming context.</param>
#endregion
protected NamedPipeIOException(SerializationInfo info, StreamingContext context) : base(info, context) {
}
}
}

View File

@ -0,0 +1,568 @@
using System;
using System.Security;
using System.Runtime.InteropServices;
namespace AppModule.NamedPipes {
#region Comments
/// <summary>
/// This utility class exposes kernel32.dll methods for named pipes communication.
/// </summary>
/// <remarks>
/// Use the following links for complete information about the exposed methods:
/// <list type="bullet">
/// <item>
/// <description><a href="http://msdn.microsoft.com/library/default.asp?url=/library/en-us/ipc/base/pipe_functions.asp" target="_blank">Named Pipe Functions</a></description>
/// </item>
/// <item>
/// <description><a href="http://msdn.microsoft.com/library/en-us/fileio/base/file_management_functions.asp" target="_blank">File Management Functions</a></description>
/// </item>
/// <item>
/// <description><a href="http://msdn.microsoft.com/library/default.asp?url=/library/en-us/sysinfo/base/handle_and_object_functions.asp" target="_blank">Handle and Object Functions</a></description>
/// </item>
/// <item>
/// <description><a href="http://msdn.microsoft.com/library/default.asp?url=/library/en-us/debug/base/system_error_codes.asp" target="_blank">System Error Codes</a></description>
/// </item>
/// </list>
/// </remarks>
#endregion
[SuppressUnmanagedCodeSecurity]
public sealed class NamedPipeNative {
#region Comments
/// <summary>
/// Outbound pipe access.
/// </summary>
#endregion
public const uint PIPE_ACCESS_OUTBOUND = 0x00000002;
#region Comments
/// <summary>
/// Duplex pipe access.
/// </summary>
#endregion
public const uint PIPE_ACCESS_DUPLEX = 0x00000003;
#region Comments
/// <summary>
/// Inbound pipe access.
/// </summary>
#endregion
public const uint PIPE_ACCESS_INBOUND = 0x00000001;
#region Comments
/// <summary>
/// Pipe blocking mode.
/// </summary>
#endregion
public const uint PIPE_WAIT = 0x00000000;
#region Comments
/// <summary>
/// Pipe non-blocking mode.
/// </summary>
#endregion
public const uint PIPE_NOWAIT = 0x00000001;
#region Comments
/// <summary>
/// Pipe read mode of type Byte.
/// </summary>
#endregion
public const uint PIPE_READMODE_BYTE = 0x00000000;
#region Comments
/// <summary>
/// Pipe read mode of type Message.
/// </summary>
#endregion
public const uint PIPE_READMODE_MESSAGE = 0x00000002;
#region Comments
/// <summary>
/// Byte pipe type.
/// </summary>
#endregion
public const uint PIPE_TYPE_BYTE = 0x00000000;
#region Comments
/// <summary>
/// Message pipe type.
/// </summary>
#endregion
public const uint PIPE_TYPE_MESSAGE = 0x00000004;
#region Comments
/// <summary>
/// Pipe client end.
/// </summary>
#endregion
public const uint PIPE_CLIENT_END = 0x00000000;
#region Comments
/// <summary>
/// Pipe server end.
/// </summary>
#endregion
public const uint PIPE_SERVER_END = 0x00000001;
#region Comments
/// <summary>
/// Unlimited server pipe instances.
/// </summary>
#endregion
public const uint PIPE_UNLIMITED_INSTANCES = 255;
#region Comments
/// <summary>
/// Waits indefinitely when connecting to a pipe.
/// </summary>
#endregion
public const uint NMPWAIT_WAIT_FOREVER = 0xffffffff;
#region Comments
/// <summary>
/// Does not wait for the named pipe.
/// </summary>
#endregion
public const uint NMPWAIT_NOWAIT = 0x00000001;
#region Comments
/// <summary>
/// Uses the default time-out specified in a call to the CreateNamedPipe method.
/// </summary>
#endregion
public const uint NMPWAIT_USE_DEFAULT_WAIT = 0x00000000;
#region Comments
/// <summary>
///
/// </summary>
#endregion
public const uint GENERIC_READ = (0x80000000);
#region Comments
/// <summary>
/// Generic write access to the pipe.
/// </summary>
#endregion
public const uint GENERIC_WRITE = (0x40000000);
#region Comments
/// <summary>
/// Generic execute access to the pipe.
/// </summary>
#endregion
public const uint GENERIC_EXECUTE = (0x20000000);
#region Comments
/// <summary>
/// Read, write, and execute access.
/// </summary>
#endregion
public const uint GENERIC_ALL = (0x10000000);
#region Comments
/// <summary>
/// Create new file. Fails if the file exists.
/// </summary>
#endregion
public const uint CREATE_NEW = 1;
#region Comments
/// <summary>
/// Create new file. Overrides an existing file.
/// </summary>
#endregion
public const uint CREATE_ALWAYS = 2;
#region Comments
/// <summary>
/// Open existing file.
/// </summary>
#endregion
public const uint OPEN_EXISTING = 3;
#region Comments
/// <summary>
/// Open existing file. If the file does not exist, creates it.
/// </summary>
#endregion
public const uint OPEN_ALWAYS = 4;
#region Comments
/// <summary>
/// Opens the file and truncates it so that its size is zero bytes.
/// </summary>
#endregion
public const uint TRUNCATE_EXISTING = 5;
#region Comments
/// <summary>
/// Invalid operating system handle.
/// </summary>
#endregion
public const int INVALID_HANDLE_VALUE = -1;
#region Comments
/// <summary>
/// The operation completed successfully.
/// </summary>
#endregion
public const ulong ERROR_SUCCESS = 0;
#region Comments
/// <summary>
/// The system cannot find the file specified.
/// </summary>
#endregion
public const ulong ERROR_CANNOT_CONNECT_TO_PIPE = 2;
#region Comments
/// <summary>
/// All pipe instances are busy.
/// </summary>
#endregion
public const ulong ERROR_PIPE_BUSY = 231;
#region Comments
/// <summary>
/// The pipe is being closed.
/// </summary>
#endregion
public const ulong ERROR_NO_DATA = 232;
#region Comments
/// <summary>
/// No process is on the other end of the pipe.
/// </summary>
#endregion
public const ulong ERROR_PIPE_NOT_CONNECTED = 233;
#region Comments
/// <summary>
/// More data is available.
/// </summary>
#endregion
public const ulong ERROR_MORE_DATA = 234;
#region Comments
/// <summary>
/// There is a process on other end of the pipe.
/// </summary>
#endregion
public const ulong ERROR_PIPE_CONNECTED = 535;
#region Comments
/// <summary>
/// Waiting for a process to open the other end of the pipe.
/// </summary>
#endregion
public const ulong ERROR_PIPE_LISTENING = 536;
#region Comments
/// <summary>
/// Creates an instance of a named pipe and returns a handle for
/// subsequent pipe operations.
/// </summary>
/// <param name="lpName">Pointer to the null-terminated string that
/// uniquely identifies the pipe.</param>
/// <param name="dwOpenMode">Pipe access mode, the overlapped mode,
/// the write-through mode, and the security access mode of the pipe handle.</param>
/// <param name="dwPipeMode">Type, read, and wait modes of the pipe handle.</param>
/// <param name="nMaxInstances">Maximum number of instances that can be
/// created for this pipe.</param>
/// <param name="nOutBufferSize">Number of bytes to reserve for the output buffer.</param>
/// <param name="nInBufferSize">Number of bytes to reserve for the input buffer.</param>
/// <param name="nDefaultTimeOut">Default time-out value, in milliseconds.</param>
/// <param name="pipeSecurityDescriptor">Pointer to a
/// <see cref="AppModule.NamedPipes.SECURITY_ATTRIBUTES">SECURITY_ATTRIBUTES</see>
/// object that specifies a security descriptor for the new named pipe.</param>
/// <returns>If the function succeeds, the return value is a handle
/// to the server end of a named pipe instance.</returns>
#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
/// <summary>
/// Enables a named pipe server process to wait for a client
/// process to connect to an instance of a named pipe.
/// </summary>
/// <param name="hHandle">Handle to the server end of a named pipe instance.</param>
/// <param name="lpOverlapped">Pointer to an
/// <see cref="AppModule.NamedPipes.Overlapped">Overlapped</see> object.</param>
/// <returns>If the function succeeds, the return value is nonzero.</returns>
#endregion
[DllImport("kernel32.dll", SetLastError=true)]
public static extern bool ConnectNamedPipe(
IntPtr hHandle, // handle to named pipe
Overlapped lpOverlapped // overlapped structure
);
#region Comments
/// <summary>
/// Connects to a message-type pipe (and waits if an instance of the
/// pipe is not available), writes to and reads from the pipe, and then closes the pipe.
/// </summary>
/// <param name="lpNamedPipeName">Pointer to a null-terminated string
/// specifying the pipe name.</param>
/// <param name="lpInBuffer">Pointer to the buffer containing the data written
/// to the pipe.</param>
/// <param name="nInBufferSize">Size of the write buffer, in bytes.</param>
/// <param name="lpOutBuffer">Pointer to the buffer that receives the data
/// read from the pipe.</param>
/// <param name="nOutBufferSize">Size of the read buffer, in bytes.</param>
/// <param name="lpBytesRead">Pointer to a variable that receives the number
/// of bytes read from the pipe.</param>
/// <param name="nTimeOut">Number of milliseconds to wait for the
/// named pipe to be available.</param>
/// <returns>If the function succeeds, the return value is nonzero.</returns>
#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
/// <summary>
/// Creates or opens a file, directory, physical disk, volume, console buffer,
/// tape drive, communications resource, mailslot, or named pipe.
/// </summary>
/// <param name="lpFileName">Pointer to a null-terminated string that
/// specifies the name of the object to create or open.</param>
/// <param name="dwDesiredAccess">Access to the object (reading, writing, or both).</param>
/// <param name="dwShareMode">Sharing mode of the object (reading, writing, both, or neither).</param>
/// <param name="attr">Pointer to a
/// <see cref="AppModule.NamedPipes.SecurityAttributes">SecurityAttributes</see>
/// object that determines whether the returned handle can be inherited
/// by child processes.</param>
/// <param name="dwCreationDisposition">Action to take on files that exist,
/// and which action to take when files do not exist.</param>
/// <param name="dwFlagsAndAttributes">File attributes and flags.</param>
/// <param name="hTemplateFile">Handle to a template file, with the GENERIC_READ access right.</param>
/// <returns>If the function succeeds, the return value is an open handle to the specified file.</returns>
#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
/// <summary>
/// Reads data from a file, starting at the position indicated by the file pointer.
/// </summary>
/// <param name="hHandle">Handle to the file to be read.</param>
/// <param name="lpBuffer">Pointer to the buffer that receives the data read from the file.</param>
/// <param name="nNumberOfBytesToRead">Number of bytes to be read from the file.</param>
/// <param name="lpNumberOfBytesRead">Pointer to the variable that receives the number of bytes read.</param>
/// <param name="lpOverlapped">Pointer to an
/// <see cref="AppModule.NamedPipes.Overlapped">Overlapped</see> object.</param>
/// <returns>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.</returns>
#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
/// <summary>
/// Writes data to a file at the position specified by the file pointer.
/// </summary>
/// <param name="hHandle">Handle to the file.</param>
/// <param name="lpBuffer">Pointer to the buffer containing the data to be written to the file.</param>
/// <param name="nNumberOfBytesToWrite"></param>
/// <param name="lpNumberOfBytesWritten">Pointer to the variable that receives the number of bytes written.</param>
/// <param name="lpOverlapped">Pointer to an
/// <see cref="AppModule.NamedPipes.Overlapped">Overlapped</see> object.</param>
/// <returns>If the function succeeds, the return value is nonzero.</returns>
#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
/// <summary>
/// Retrieves information about a specified named pipe.
/// </summary>
/// <param name="hHandle">Handle to the named pipe for which information is wanted.</param>
/// <param name="lpState">Pointer to a variable that indicates the current
/// state of the handle.</param>
/// <param name="lpCurInstances">Pointer to a variable that receives the
/// number of current pipe instances.</param>
/// <param name="lpMaxCollectionCount">Pointer to a variable that receives
/// the maximum number of bytes to be collected on the client's computer
/// before transmission to the server.</param>
/// <param name="lpCollectDataTimeout">Pointer to a variable that receives
/// the maximum time, in milliseconds, that can pass before a remote named
/// pipe transfers information over the network.</param>
/// <param name="lpUserName">Pointer to a buffer that receives the
/// null-terminated string containing the user name string associated
/// with the client application. </param>
/// <param name="nMaxUserNameSize">Size of the buffer specified by the
/// lpUserName parameter.</param>
/// <returns>If the function succeeds, the return value is nonzero.</returns>
#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
/// <summary>
/// Cancels all pending input and output (I/O) operations that were
/// issued by the calling thread for the specified file handle.
/// </summary>
/// <param name="hHandle">Handle to a file.</param>
/// <returns>If the function succeeds, the return value is nonzero.</returns>
#endregion
[DllImport("kernel32.dll", SetLastError=true)]
public static extern bool CancelIo(
IntPtr hHandle
);
#region Comments
/// <summary>
/// Waits until either a time-out interval elapses or an instance
/// of the specified named pipe is available for connection.
/// </summary>
/// <param name="name">Pointer to a null-terminated string that specifies
/// the name of the named pipe.</param>
/// <param name="timeout">Number of milliseconds that the function will
/// wait for an instance of the named pipe to be available.</param>
/// <returns>If an instance of the pipe is available before the
/// time-out interval elapses, the return value is nonzero.</returns>
#endregion
[DllImport("kernel32.dll", SetLastError=true)]
public static extern bool WaitNamedPipe(
String name,
int timeout);
#region Comments
/// <summary>
/// Retrieves the calling thread's last-error code value.
/// </summary>
/// <returns>The return value is the calling thread's last-error code value.</returns>
#endregion
[DllImport("kernel32.dll", SetLastError=true)]
public static extern uint GetLastError();
#region Comments
/// <summary>
/// Flushes the buffers of the specified file and causes all buffered data to be written to the file.
/// </summary>
/// <param name="hHandle">Handle to an open file.</param>
/// <returns>If the function succeeds, the return value is nonzero.</returns>
#endregion
[DllImport("kernel32.dll", SetLastError=true)]
public static extern bool FlushFileBuffers(
IntPtr hHandle);
#region Comments
/// <summary>
/// Disconnects the server end of a named pipe instance from a client process.
/// </summary>
/// <param name="hHandle">Handle to an instance of a named pipe.</param>
/// <returns>If the function succeeds, the return value is nonzero.</returns>
#endregion
[DllImport("kernel32.dll", SetLastError=true)]
public static extern bool DisconnectNamedPipe(
IntPtr hHandle);
#region Comments
/// <summary>
/// Sets the read mode and the blocking mode of the specified named pipe.
/// </summary>
/// <remarks>
/// 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.
/// </remarks>
/// <param name="hHandle">Handle to the named pipe instance.</param>
/// <param name="mode">Pointer to a variable that supplies the new mode.</param>
/// <param name="cc">Pointer to a variable that specifies the maximum
/// number of bytes collected on the client computer before
/// transmission to the server.</param>
/// <param name="cd">Pointer to a variable that specifies the
/// maximum time, in milliseconds, that can pass before a remote
/// named pipe transfers information over the network.</param>
/// <returns>If the function succeeds, the return value is nonzero.</returns>
#endregion
[DllImport("kernel32.dll", SetLastError=true)]
public static extern bool SetNamedPipeHandleState(
IntPtr hHandle,
ref uint mode,
IntPtr cc,
IntPtr cd);
#region Comments
/// <summary>
/// Closes an open object handle.
/// </summary>
/// <param name="hHandle">Handle to an open object.</param>
/// <returns>If the function succeeds, the return value is nonzero.</returns>
#endregion
[DllImport("kernel32.dll", SetLastError=true)]
public static extern bool CloseHandle(
IntPtr hHandle);
#region Comments
/// <summary>
/// Sets the security descriptor attributes
/// </summary>
/// <param name="sd">Reference to a SECURITY_DESCRIPTOR structure.</param>
/// <param name="bDaclPresent"></param>
/// <param name="Dacl"></param>
/// <param name="bDaclDefaulted"></param>
/// <returns></returns>
#endregion
[DllImport("Advapi32.dll", SetLastError=true)]
public static extern bool SetSecurityDescriptorDacl(ref SECURITY_DESCRIPTOR sd, bool bDaclPresent, IntPtr Dacl, bool bDaclDefaulted);
#region Comments
/// <summary>
/// Initializes a SECURITY_DESCRIPTOR structure.
/// </summary>
/// <param name="sd"></param>
/// <param name="dwRevision"></param>
/// <returns></returns>
#endregion
[DllImport("Advapi32.dll", SetLastError=true)]
public static extern bool InitializeSecurityDescriptor(out SECURITY_DESCRIPTOR sd, int dwRevision);
#region Comments
/// <summary>
/// Private constructor.
/// </summary>
#endregion
private NamedPipeNative() {}
}
#region Comments
/// <summary>
/// Security Descriptor structure
/// </summary>
#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
/// <summary>
/// Security Attributes structure.
/// </summary>
#endregion
[StructLayout(LayoutKind.Sequential)]
public struct SECURITY_ATTRIBUTES {
public int nLength;
public IntPtr lpSecurityDescriptor;
public bool bInheritHandle;
}
#region Comments
/// <summary>
/// This class is used as a dummy parameter only.
/// </summary>
#endregion
[StructLayout(LayoutKind.Sequential)]
public class Overlapped {
}
#region Comments
/// <summary>
/// This class is used as a dummy parameter only.
/// </summary>
#endregion
[StructLayout(LayoutKind.Sequential)]
public class SecurityAttributes {
}
}

View File

@ -0,0 +1,427 @@
using System;
using System.Runtime.InteropServices;
using AppModule.InterProcessComm;
namespace AppModule.NamedPipes {
#region Comments
/// <summary>
/// A utility class that exposes named pipes operations.
/// </summary>
/// <remarks>
/// This class uses the exposed exposed kernel32.dll methods by the
/// <see cref="AppModule.NamedPipes.NamedPipeNative">NamedPipeNative</see> class
/// to provided controlled named pipe functionality.
/// </remarks>
#endregion
public sealed class NamedPipeWrapper {
#region Comments
/// <summary>
/// The number of retries when creating a pipe or connecting to a pipe.
/// </summary>
#endregion
private const int ATTEMPTS = 2;
#region Comments
/// <summary>
/// Wait time for the
/// <see cref="AppModule.NamedPipes.NamedPipeNative.WaitNamedPipe">NamedPipeNative.WaitNamedPipe</see>
/// operation.
/// </summary>
#endregion
private const int WAIT_TIME = 5000;
#region Comments
/// <summary>
/// Reads a string from a named pipe using the UTF8 encoding.
/// </summary>
/// <param name="handle">The pipe handle.</param>
/// <param name="maxBytes">The maximum bytes to read.</param>
/// <returns>A UTF8 string.</returns>
/// <remarks>This function uses
/// <see cref="AppModule.NamedPipes.NamedPipeWrapper.ReadBytes">AppModule.NamedPipes.ReadBytes</see>
/// to read the bytes from the pipe and then converts them to string.<br/><br/>
/// 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.
/// </remarks>
#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
/// <summary>
/// Reads the bytes from a named pipe.
/// </summary>
/// <param name="handle">The pipe handle.</param>
/// <param name="maxBytes">The maximum bytes to read.</param>
/// <returns>An array of bytes.</returns>
/// <remarks>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
/// <b>maxBytes</b> the method returns null.<br/><br/>
/// 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.
/// </remarks>
#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
/// <summary>
/// Writes a string to a named pipe.
/// </summary>
/// <param name="handle">The pipe handle.</param>
/// <param name="text">The text to write to the pipe.</param>
/// <remarks>This method converts the text into an array of bytes, using the
/// UTF8 encoding and the uses
/// <see cref="AppModule.NamedPipes.NamedPipeWrapper.WriteBytes">AppModule.NamedPipes.WriteBytes</see>
/// to write to the pipe.<br/><br/>
/// When writing to a pipe the method first writes four bytes that define the data length.
/// It then writes the whole message.</remarks>
#endregion
public static void Write(PipeHandle handle, string text) {
WriteBytes(handle, System.Text.Encoding.UTF8.GetBytes(text));
}
#region Comments
/// <summary>
/// Writes an array of bytes to a named pipe.
/// </summary>
/// <param name="handle">The pipe handle.</param>
/// <param name="bytes">The bytes to write.</param>
/// <remarks>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.<br/><br/>
/// The bytes length is restricted by the <b>maxBytes</b> parameter, which is done primarily for security reasons.<br/><br/>
/// When writing to a pipe the method first writes four bytes that define the data length.
/// It then writes the whole message.</remarks>
#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
/// <summary>
/// Tries to connect to a named pipe on the same machine.
/// </summary>
/// <param name="pipeName">The name of the pipe.</param>
/// <param name="handle">The resulting pipe handle.</param>
/// <returns>Return true if the attempt succeeds.</returns>
/// <remarks>This method is used mainly when stopping the pipe server. It unblocks the existing pipes, which wait for client connection.</remarks>
#endregion
public static bool TryConnectToPipe(string pipeName, out PipeHandle handle) {
return TryConnectToPipe(pipeName, ".", out handle);
}
#region Comments
/// <summary>
/// Tries to connect to a named pipe.
/// </summary>
/// <param name="pipeName">The name of the pipe.</param>
/// <param name="serverName">The name of the server.</param>
/// <param name="handle">The resulting pipe handle.</param>
/// <returns>Return true if the attempt succeeds.</returns>
/// <remarks>This method is used mainly when stopping the pipe server. It unblocks the existing pipes, which wait for client connection.</remarks>
#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
/// <summary>
/// Connects to a server named pipe on the same machine.
/// </summary>
/// <param name="pipeName">The pipe name.</param>
/// <returns>The pipe handle, which also contains the pipe state.</returns>
/// <remarks>This method is used by clients to establish a pipe connection with a server pipe.</remarks>
#endregion
public static PipeHandle ConnectToPipe(string pipeName) {
return ConnectToPipe(pipeName, ".");
}
#region Comments
/// <summary>
/// Connects to a server named pipe.
/// </summary>
/// <param name="pipeName">The pipe name.</param>
/// <param name="serverName">The server name.</param>
/// <returns>The pipe handle, which also contains the pipe state.</returns>
/// <remarks>This method is used by clients to establish a pipe connection with a server pipe.</remarks>
#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
/// <summary>
/// Creates a server named pipe.
/// </summary>
/// <param name="name">The name of the pipe.</param>
/// <param name="outBuffer">The size of the outbound buffer.</param>
/// <param name="inBuffer">The size of the inbound buffer.</param>
/// <returns>The pipe handle.</returns>
#endregion
public static PipeHandle Create(string name, uint outBuffer, uint inBuffer) {
return Create(name, outBuffer, inBuffer, true);
}
#region Comments
/// <summary>
/// Creates a server named pipe.
/// </summary>
/// <param name="name">The name of the pipe.</param>
/// <param name="outBuffer">The size of the outbound buffer.</param>
/// <param name="inBuffer">The size of the inbound buffer.</param>
/// <param name="secure">Specifies whether to make the pipe secure.</param>
/// <returns>The pipe handle.</returns>
/// <remarks>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.
/// <br/><br/>
/// If the <b>secure</b> parameter is false the method creates a security descriptor that grants full access to Everyone.
/// </remarks>
#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
/// <summary>
/// Creates a SECURITY_DESCRIPTOR with DACL = null, which allows full access to Everyone.
/// </summary>
/// <param name="sd">The SECURITY_DESCRIPTOR structure.</param>
#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
/// <summary>
/// Starts waiting for client connections.
/// </summary>
/// <remarks>
/// Blocks the current execution until a client pipe attempts to establish a connection.
/// </remarks>
/// <param name="handle">The pipe handle.</param>
#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
/// <summary>
/// Returns the number of instances of a named pipe.
/// </summary>
/// <param name="handle">The pipe handle.</param>
/// <returns>The number of instances.</returns>
#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
/// <summary>
/// Closes a named pipe and releases the native handle.
/// </summary>
/// <param name="handle">The pipe handle.</param>
#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
/// <summary>
/// Flushes all the data in a named pipe.
/// </summary>
/// <param name="handle">The pipe handle.</param>
#endregion
public static void Flush(PipeHandle handle) {
handle.State = InterProcessConnectionState.Flushing;
NamedPipeNative.FlushFileBuffers(handle.Handle);
handle.State = InterProcessConnectionState.FlushedData;
}
#region Comments
/// <summary>
/// Disconnects a server named pipe from the client.
/// </summary>
/// <remarks>
/// Server pipes can be reused by first disconnecting them from the client and then
/// calling the <see cref="AppModule.NamedPipes.NamedPipeWrapper.Connect">Connect</see>
/// method to start listening. This improves the performance as it is not necessary
/// to create new pipe handles.
/// </remarks>
/// <param name="handle">The pipe handle.</param>
#endregion
public static void Disconnect(PipeHandle handle) {
handle.State = InterProcessConnectionState.Disconnecting;
NamedPipeNative.DisconnectNamedPipe(handle.Handle);
handle.State = InterProcessConnectionState.Disconnected;
}
#region Comments
/// <summary>
/// Private constructor.
/// </summary>
#endregion
private NamedPipeWrapper() {}
}
}

View File

@ -0,0 +1,55 @@
using System;
using AppModule.InterProcessComm;
namespace AppModule.NamedPipes {
#region Comments
/// <summary>
/// Holds the operating system native handle and the current state of the pipe connection.
/// </summary>
#endregion
public sealed class PipeHandle {
#region Comments
/// <summary>
/// The operating system native handle.
/// </summary>
#endregion
public IntPtr Handle;
#region Comments
/// <summary>
/// The current state of the pipe connection.
/// </summary>
#endregion
public InterProcessConnectionState State;
#region Comments
/// <summary>
/// Creates a PipeHandle instance using the passed native handle.
/// </summary>
/// <param name="hnd">The native handle.</param>
#endregion
public PipeHandle (int hnd) {
this.Handle = new IntPtr(hnd);
this.State = InterProcessConnectionState.NotSet;
}
#region Comments
/// <summary>
/// Creates a PipeHandle instance using the provided native handle and state.
/// </summary>
/// <param name="hnd">The native handle.</param>
/// <param name="state">The state of the pipe connection.</param>
#endregion
public PipeHandle (int hnd, InterProcessConnectionState state) {
this.Handle = new IntPtr(hnd);
this.State = state;
}
#region Comments
/// <summary>
/// Creates a PipeHandle instance with an invalid native handle.
/// </summary>
#endregion
public PipeHandle () {
this.Handle = new IntPtr(NamedPipeNative.INVALID_HANDLE_VALUE);
this.State = InterProcessConnectionState.NotSet;
}
}
}

View File

@ -0,0 +1,96 @@
using System;
using System.IO;
using AppModule.InterProcessComm;
namespace AppModule.NamedPipes {
#region Comments
/// <summary>
/// Used by server applications to communicate with client ones by using named pipes.
/// </summary>
#endregion
public sealed class ServerPipeConnection : APipeConnection {
#region Comments
/// <summary>
/// Disconnects a client named pipe.
/// </summary>
/// <remarks>
/// When a client named pipe is disconnected, the server one is not closed.
/// The latter can later be reused by starting to listen again.<br/><br/>
/// 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
/// <see cref="AppModule.NamedPipes.ServerPipeConnection.Connect">Connect</see> method.
/// </remarks>
#endregion
public void Disconnect() {
CheckIfDisposed();
NamedPipeWrapper.Disconnect(this.Handle);
}
#region Comments
/// <summary>
/// Closes the operating system native handle of the named pipe.
/// </summary>
#endregion
public override void Close() {
CheckIfDisposed();
NamedPipeWrapper.Close(this.Handle);
}
#region Comments
/// <summary>
/// Starts listening to client pipe connections.
/// </summary>
/// <remarks>
/// This method will block the program execution until a client pipe attempts
/// to establish a connection.<br/><br/>
/// When a client named pipe is disconnected, the server one is not closed.
/// The latter can later be reused by starting to listen again.<br/><br/>
/// </remarks>
#endregion
public override void Connect() {
CheckIfDisposed();
NamedPipeWrapper.Connect(this.Handle);
}
#region Comments
/// <summary>
/// Creates a ServerPipeConnection instance and the underlying operating system handle.
/// </summary>
/// <param name="name">The name of the pipe.</param>
/// <param name="outBuffer">The outbound buffer.</param>
/// <param name="inBuffer">The inbound buffer.</param>
/// <param name="maxReadBytes">The maximum bytes to read from clients.</param>
#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
/// <summary>
/// Creates a ServerPipeConnection instance and the underlying operating system handle.
/// </summary>
/// <param name="name">The name of the pipe.</param>
/// <param name="outBuffer">The outbound buffer.</param>
/// <param name="inBuffer">The inbound buffer.</param>
/// <param name="secure">Specifies whether the pipe is secure.</param>
/// <param name="maxReadBytes">The maximum bytes to read from clients.</param>
/// <remarks>If the <b>secure</b> 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.
/// <br/><br/>
/// If the <b>secure</b> parameter is false the method creates a security descriptor that grants full access to Everyone.
/// </remarks>
#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
/// <summary>
/// Object destructor.
/// </summary>
#endregion
~ServerPipeConnection() {
Dispose(false);
}
}
}