/// <summary> /// Named pipe server through P/Invoke-ing the native APIs /// </summary> static void PInvokeNativePipeServer() { ///////////////////////////////////////////////////////////////////// // Create a named pipe. // // Prepare the pipe name String strPipeName = String.Format(@"\\{0}\pipe\{1}", ".", // Server name "HelloWorld" // Pipe name ); // Prepare the security attributes IntPtr pSa = IntPtr.Zero; // NULL SECURITY_ATTRIBUTES sa = new SECURITY_ATTRIBUTES(); SECURITY_DESCRIPTOR sd; SecurityNative.InitializeSecurityDescriptor(out sd, 1); // DACL is set as NULL to allow all access to the object. SecurityNative.SetSecurityDescriptorDacl(ref sd, true, IntPtr.Zero, false); sa.lpSecurityDescriptor = Marshal.AllocHGlobal(Marshal.SizeOf( typeof(SECURITY_DESCRIPTOR))); Marshal.StructureToPtr(sd, sa.lpSecurityDescriptor, false); sa.bInheritHandle = false; // Not inheritable sa.nLength = Marshal.SizeOf(typeof(SECURITY_ATTRIBUTES)); pSa = Marshal.AllocHGlobal(sa.nLength); Marshal.StructureToPtr(sa, pSa, false); // Create the named pipe. IntPtr hPipe = PipeNative.CreateNamedPipe( strPipeName, // The unique pipe name. PipeOpenMode.PIPE_ACCESS_DUPLEX, // The pipe is bi-directional PipeMode.PIPE_TYPE_MESSAGE | // Message type pipe PipeMode.PIPE_READMODE_MESSAGE | // Message-read mode PipeMode.PIPE_WAIT, // Blocking mode is on PipeNative.PIPE_UNLIMITED_INSTANCES, // Max server instances BUFFER_SIZE, // Output buffer size BUFFER_SIZE, // Input buffer size PipeNative.NMPWAIT_USE_DEFAULT_WAIT, // Time-out interval pSa // Pipe security attributes ); if (hPipe.ToInt32() == PipeNative.INVALID_HANDLE_VALUE) { Console.WriteLine("Unable to create named pipe {0} w/err 0x{1:X}", strPipeName, PipeNative.GetLastError()); return; } Console.WriteLine("The named pipe, {0}, is created.", strPipeName); ///////////////////////////////////////////////////////////////////// // Wait for the client to connect. // Console.WriteLine("Waiting for the client's connection..."); bool bConnected = PipeNative.ConnectNamedPipe(hPipe, IntPtr.Zero) ? true : PipeNative.GetLastError() == PipeNative.ERROR_PIPE_CONNECTED; if (!bConnected) { Console.WriteLine( "Error occurred while connecting to the client: 0x{0:X}", PipeNative.GetLastError()); PipeNative.CloseHandle(hPipe); // Close the pipe handle. return; } ///////////////////////////////////////////////////////////////////// // Read client requests from the pipe and write the response. // // A byte buffer of BUFFER_SIZE bytes. The buffer should be big // enough for ONE request from a client. string strMessage; byte[] bRequest = new byte[BUFFER_SIZE];// Client -> Server uint cbBytesRead, cbRequestBytes; byte[] bReply; // Server -> Client uint cbBytesWritten, cbReplyBytes; bool bResult; while (true) { // Receive one message from the pipe. cbRequestBytes = BUFFER_SIZE; bResult = PipeNative.ReadFile( // Read from the pipe. hPipe, // Handle of the pipe bRequest, // Buffer to receive data cbRequestBytes, // Size of buffer in bytes out cbBytesRead, // Number of bytes read IntPtr.Zero); // Not overlapped I/O if (!bResult /*Failed*/ || cbBytesRead == 0 /*Finished*/) { break; } // Unicode-encode the byte array and trim all the '\0' chars at // the end. strMessage = Encoding.Unicode.GetString(bRequest).TrimEnd('\0'); Console.WriteLine("Receives {0} bytes; Message: \"{1}\"", cbBytesRead, strMessage); // Prepare the response. // '\0' is appended in the end because the client may be a native // C++ program. strMessage = "Default response from server\0"; bReply = Encoding.Unicode.GetBytes(strMessage); cbReplyBytes = (uint)bReply.Length; // Write the response to the pipe. bResult = PipeNative.WriteFile( // Write to the pipe. hPipe, // Handle of the pipe bReply, // Buffer to write to cbReplyBytes, // Number of bytes to write out cbBytesWritten, // Number of bytes written IntPtr.Zero); // Not overlapped I/O if (!bResult /*Failed*/ || cbReplyBytes != cbBytesWritten /*Failed*/) { Console.WriteLine("WriteFile failed w/err 0x{0:X}", PipeNative.GetLastError()); break; } Console.WriteLine("Replies {0} bytes; Message: \"{1}\"", cbBytesWritten, strMessage.TrimEnd('\0')); } ///////////////////////////////////////////////////////////////////// // Flush the pipe to allow the client to read the pipe's contents // before disconnecting. Then disconnect the pipe, and close the // handle to this pipe instance. // PipeNative.FlushFileBuffers(hPipe); PipeNative.DisconnectNamedPipe(hPipe); PipeNative.CloseHandle(hPipe); }
static void PInvokeNativePipeClient() { ///////////////////////////////////////////////////////////////////// // Try to open a named pipe. // // Prepare the pipe name String strPipeName = String.Format(@"\\{0}\pipe\{1}", ".", // Server name "HelloWorld" // Pipe name ); IntPtr hPipe; while (true) { hPipe = PipeNative.CreateFile( strPipeName, // Pipe name FileDesiredAccess.GENERIC_READ | // Read and write access FileDesiredAccess.GENERIC_WRITE, FileShareMode.Zero, // No sharing IntPtr.Zero, // Default security attributes FileCreationDisposition.OPEN_EXISTING, // Opens existing pipe 0, // Default attributes 0); // No template file // Break if the pipe handle is valid. if (hPipe.ToInt32() != PipeNative.INVALID_HANDLE_VALUE) { break; } if (// Exit if an error other than ERROR_PIPE_BUSY occurs PipeNative.GetLastError() != PipeNative.ERROR_PIPE_BUSY || // All pipe instances are busy, so wait for five seconds !PipeNative.WaitNamedPipe(strPipeName, 5000)) { Console.WriteLine("Unable to open named pipe {0} w/err 0x{1:X}", strPipeName, PipeNative.GetLastError()); return; } } Console.WriteLine("The named pipe, {0}, is connected.", strPipeName); ///////////////////////////////////////////////////////////////////// // The pipe connected; change to message-read mode. // PipeMode mode = PipeMode.PIPE_READMODE_MESSAGE; bool bResult = PipeNative.SetNamedPipeHandleState( hPipe, ref mode, IntPtr.Zero, IntPtr.Zero); if (!bResult) { Console.WriteLine("SetNamedPipeHandleState failed w/err 0x{0:X}", PipeNative.GetLastError()); return; } ///////////////////////////////////////////////////////////////////// // Send a message to the pipe server and receive its response. // // A byte buffer of BUFFER_SIZE bytes. The buffer should be big // enough for ONE request to the server. string strMessage; byte[] bRequest; // Client -> Server uint cbBytesWritten, cbRequestBytes; byte[] bReply = new byte[BUFFER_SIZE]; // Server -> Client uint cbBytesRead, cbReplyBytes; // Send one message to the pipe. // '\0' is appended in the end because the client may be a native // C++ program. strMessage = "Default request from client\0"; bRequest = Encoding.Unicode.GetBytes(strMessage); cbRequestBytes = (uint)bRequest.Length; bResult = PipeNative.WriteFile( // Write to the pipe. hPipe, // Handle of the pipe bRequest, // Message to be written cbRequestBytes, // Number of bytes to write out cbBytesWritten, // Number of bytes written IntPtr.Zero); // Not overlapped if (!bResult /*Failed*/ || cbRequestBytes != cbBytesWritten /*Failed*/) { Console.WriteLine("WriteFile failed w/err 0x{0:X}", PipeNative.GetLastError()); return; } Console.WriteLine("Sends {0} bytes; Message: \"{1}\"", cbBytesWritten, strMessage.TrimEnd('\0')); // Receive the response from the server. cbReplyBytes = BUFFER_SIZE; do { bResult = PipeNative.ReadFile( // Read from the pipe. hPipe, // Handle of the pipe bReply, // Buffer to receive the reply cbReplyBytes, // Size of buffer out cbBytesRead, // Number of bytes read IntPtr.Zero); // Not overlapped if (!bResult && PipeNative.GetLastError() != PipeNative.ERROR_MORE_DATA) { Console.WriteLine("ReadFile failed w/err 0x{0:X}", PipeNative.GetLastError()); break; } strMessage = Encoding.Unicode.GetString(bReply).TrimEnd('\0'); Console.WriteLine("Receives {0} bytes; Message: \"{1}\"", cbBytesRead, strMessage); } while (!bResult); // Repeat loop if ERROR_MORE_DATA ///////////////////////////////////////////////////////////////////// // Close the pipe. // PipeNative.CloseHandle(hPipe); }