namedpipewrapper.cs
来自「通过NamePipe与其他进程通信的代码」· CS 代码 · 共 477 行 · 第 1/2 页
CS
477 行
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) {
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() {}
}
}
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?