/// <summary> /// WriteMessage - write an array of bytes and return the response from the /// server /// </summary> /// <param name="buffer">bytes to write</param> /// <param name="bytesToWrite">number of bytes to write</param> /// <returns>true if written successfully</returns> public MemoryStream WriteMessage(byte[] buffer, // the write buffer uint bytesToWrite) // number of bytes in the write buffer // message responses { // buffer to get the number of bytes read/written back byte[] _numReadWritten = new byte[4]; MemoryStream responseStream = null; bool success = false; // Write the byte buffer to the pipe success = NamedPipeInterop.WriteFile(_handle, buffer, bytesToWrite, _numReadWritten, 0); if (success) { byte[] responseBuffer = new byte[_responseBufferSize]; responseStream = new MemoryStream(_responseBufferSize); { do { // Read the response from the pipe. success = NamedPipeInterop.ReadFile( _handle, // pipe handle responseBuffer, // buffer to receive reply (uint)_responseBufferSize, // size of buffer _numReadWritten, // number of bytes read 0); // not overlapped // failed, not just more data to come if (!success && Marshal.GetLastWin32Error() != NamedPipeInterop.ERROR_MORE_DATA) { break; } // concat response to stream responseStream.Write(responseBuffer, 0, responseBuffer.Length); } while (!success); } } return(responseStream); }
/// <summary> /// CreatePipe - create the named pipe /// </summary> /// <returns>true is pipe created</returns> public bool CreatePipe() { // make a named pipe in message mode _handle = NamedPipeInterop.CreateNamedPipe(_pipeName, NamedPipeInterop.PIPE_ACCESS_DUPLEX, NamedPipeInterop.PIPE_TYPE_MESSAGE | NamedPipeInterop.PIPE_READMODE_MESSAGE | NamedPipeInterop.PIPE_WAIT, NamedPipeInterop.PIPE_UNLIMITED_INSTANCES, PIPE_SERVER_BUFFER_SIZE, PIPE_SERVER_BUFFER_SIZE, NamedPipeInterop.NMPWAIT_WAIT_FOREVER, IntPtr.Zero); // make sure we got a good one if (_handle.IsInvalid) { Debug.WriteLine("Could not create the pipe (" + _pipeName + ") - os returned " + Marshal.GetLastWin32Error()); return(false); } return(true); }
/// <summary> /// Connect - connect to an existing pipe /// </summary> /// <returns>true if connected</returns> public void Connect() { if (!_handle.IsInvalid) { throw new InvalidOperationException("Pipe is already connected!"); } string errMsg = ""; int errCode = 0; int retryAttempts = _retryConnect; // keep trying to connect while (retryAttempts > 0) { // mark off one attempt retryAttempts--; // connect to existing pipe _handle = NamedPipeInterop.CreateFile(_pipeName, NamedPipeInterop.GENERIC_READ | NamedPipeInterop.GENERIC_WRITE, 0, IntPtr.Zero, NamedPipeInterop.OPEN_EXISTING, 0, 0); // check to see if we connected if (!_handle.IsInvalid) { break; } // the pipe could not be opened as all instances are busy // any other error we bail for errCode = Marshal.GetLastWin32Error(); if (errCode != NamedPipeInterop.ERROR_PIPE_BUSY) { errMsg = string.Format("Could not open pipe {0} with error {1}", _pipeName, errCode); Trace.WriteLine(errMsg); throw new Win32Exception(errCode, errMsg); } // if it was busy, see if we can wait it out else if (!NamedPipeInterop.WaitNamedPipe(_pipeName, (uint)_retryTimeout)) { errCode = Marshal.GetLastWin32Error(); errMsg = string.Format("Wait for pipe {0} timed out after {1} milliseconds with error code {2}.", _pipeName, _retryTimeout, errCode); Trace.WriteLine(errMsg); throw new Win32Exception(errCode, errMsg); } } // indicate connection in debug Trace.WriteLine("Connected to pipe: " + _pipeName); // The pipe connected; change to message-read mode. bool success = false; int mode = (int)NamedPipeInterop.PIPE_READMODE_MESSAGE; // set to message mode success = NamedPipeInterop.SetNamedPipeHandleState( _handle, // pipe handle ref mode, // new pipe mode IntPtr.Zero, // don't set maximum bytes IntPtr.Zero); // don't set maximum time // currently implemented for just synchronous, message based pipes // so bail if we couldn't set the client up properly if (false == success) { errCode = Marshal.GetLastWin32Error(); errMsg = string.Format("Could not change pipe mode to message with error code {0}", errCode); Trace.WriteLine(errMsg); Dispose(); throw new Win32Exception(errCode, errMsg); } }
/// <summary> /// WaitForMessage - have the server wait for a message /// </summary> /// <returns>a non-null MessageStream if it got a message, null if timed out or error</returns> public MemoryStream WaitForMessage() { bool fullyRead = false; string errMsg = ""; int errCode = 0; // they want to talk to us, read their messages and write // replies MemoryStream receiveStream = new MemoryStream(); byte[] buffer = new byte[_receiveBufferSize]; byte[] _numReadWritten = new byte[4]; // need to read the whole message and put it in one message // byte buffer do { // Read the response from the pipe. if (!NamedPipeInterop.ReadFile( _handle, // pipe handle buffer, // buffer to receive reply (uint)_receiveBufferSize, // size of buffer _numReadWritten, // number of bytes read 0)) // not overlapped { // failed, not just more data to come errCode = Marshal.GetLastWin32Error(); if (errCode != NamedPipeInterop.ERROR_MORE_DATA) { break; } else { errMsg = string.Format("Could not read from pipe with error {0}", errCode); Trace.WriteLine(errMsg); throw new Win32Exception(errCode, errMsg); } } else { // we succeeded and no more data is coming fullyRead = true; } // concat the message bytes to the stream receiveStream.Write(buffer, 0, buffer.Length); } while (!fullyRead); if (receiveStream.Length > 0) { // now set up response with a polite response using the same // Unicode string protocol string reply = "Thanks for the message!"; byte[] msgBytes = Encoding.Unicode.GetBytes(reply); uint len = (uint)msgBytes.Length; // write the response message provided // by the delegate if (!NamedPipeInterop.WriteFile(_handle, msgBytes, len, _numReadWritten, 0)) { errCode = Marshal.GetLastWin32Error(); errMsg = string.Format("Could not write response with error {0}", errCode); Trace.WriteLine(errMsg); throw new Win32Exception(errCode, errMsg); } // return the message we received return(receiveStream); } else // didn't receive anything { return(null); } }
/// <summary> /// WaitForClientConnect - wait for a client to connect to this pipe /// </summary> /// <returns>true if connected, false if timed out</returns> public bool WaitForClientConnect() { // wait for someone to talk to us return(NamedPipeInterop.ConnectNamedPipe(_handle, IntPtr.Zero)); }