/// <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);
    }
Example #2
0
    static void Main(string[] args)
    {
        /////////////////////////////////////////////////////////////////////
        // Create the mailslot.
        //

        // Prepare the slot name
        String strMailslotName = String.Format(@"\\{0}\mailslot\{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);

        // ACL 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 mailslot.
        IntPtr hMailslot = MailslotNative.CreateMailslot(
            strMailslotName,            // The name of the mailslot
            0,                          // No maximum message size
            MailslotNative.MAILSLOT_WAIT_FOREVER,
            pSa);                       // Security attributes

        if (hMailslot.ToInt32() == MailslotNative.INVALID_HANDLE_VALUE)
        {
            Console.WriteLine("CreateMailslot failed w/err 0x{0:X}",
                              Marshal.GetLastWin32Error());
            return;
        }

        Console.WriteLine("Mailslot {0} created successfully.", strMailslotName);


        /////////////////////////////////////////////////////////////////////
        // Check messages in the mailslot.
        //

        try
        {
            // In a loop, check for new messages every 5 seconds.
            while (true)
            {
                Console.WriteLine("Checking new messages...");
                ReadMailslot(hMailslot);

                System.Threading.Thread.Sleep(5000);
            }
        }
        finally
        {
            /////////////////////////////////////////////////////////////////
            // Close the handle of the mailslot instance.
            //

            MailslotNative.CloseHandle(hMailslot);
        }
    }