Ejemplo n.º 1
0
    /// <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);
    }
Ejemplo n.º 2
0
    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);
    }