namedpipewrapper.cs

来自「通过NamePipe与其他进程通信的代码」· CS 代码 · 共 477 行 · 第 1/2 页

CS
477
字号
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;

			byte[] numReadWritten = new byte[4];
			byte[] intBytes = new byte[4];
			byte[] msgBytes =  new byte[8108];
			int len;
			
			// Set the Handle state to Reading
			handle.State = InterProcessConnectionState.Reading;

			if (NamedPipeNative.ReadFile(handle.Handle, msgBytes, 8108, numReadWritten, 0))    //张河阳修改,试试
			{
				len=msgBytes.Length ;
			}
			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;
//			}
			RPIPEMessage msg=RPIPEMessage.GetMessage(msgBytes);
			return new string(msg.Data) ;
		}
		#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 =  new byte[50];
			int len;
			
			// Set the Handle state to Reading
			handle.State = InterProcessConnectionState.Reading;
			if (NamedPipeNative.ReadFile(handle.Handle, msgBytes, 50, numReadWritten, 0))    //张河阳修改,试试
			{
				len=msgBytes.Length ;
			}
			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));
			byte[] numReadWritten = new byte[4];
			uint len;
			RPIPEMessage msg=new RPIPEMessage(1,text);
			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());
			//				}
			//			}
			byte[] bytes=msg.GetBytes();
			
			 len = (uint)bytes.Length;
			if (NamedPipeNative.WriteFile(handle.Handle, bytes, len, numReadWritten, 0))   //张河阳,修改测试
			{

			}
			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>
		/// 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());
//				}
//			}
			if (bytes.Length >50)bytes=System.Text.Encoding.UTF8.GetBytes("To Long");//张河阳,修改测试
			len = (uint)bytes.Length;
			if (NamedPipeNative.WriteFile(handle.Handle, bytes, len, numReadWritten, 0))   //张河阳,修改测试
			{

			}
			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;

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?