Two way C++ to C# communication using named pipes

15,925

Solution 1

Disposing of a StreamWriter or StreamReader will close the underlying stream.

Your using statements therefore will be causing the stream to close.

    public void ThreadStartClient(object obj)
    {
            // Ensure that we only start the client after the server has created the pipe
            ManualResetEvent SyncClientServer = (ManualResetEvent)obj;

            // Only continue after the server was created -- otherwise we just fail badly
            // SyncClientServer.WaitOne();

            using (NamedPipeClientStream pipeStream = new NamedPipeClientStream(".", "SAPipe"))
            {
                // The connect function will indefinately wait for the pipe to become available
                // If that is not acceptable specify a maximum waiting time (in ms)
                pipeStream.Connect();


                //Write from client to server
                StreamWriter sw = new StreamWriter(pipeStream))
                sw.WriteLine("What's your status?");

                //Read server reply
                StreamReader sr = new StreamReader(pipeStream)
                string temp = "";
                temp = sr.ReadLine();   //Pipe is already closed here ... why?

                MessageBox.Show(temp);
            }
    }

It should also be noted that because you wrap your stream in a using statement, the commented out pipeStream.Close() function isn't needed.

Solution 2

Ok, got it working for my application .... thanks Blam !

Here's the C++ server (run this inside a thread):

UINT CNamedPipe::StartNamedPipeServer()
{
    if(!m_bServerActive)
        return 0;

    LPTSTR lpszPipename = "\\\\.\\pipe\\MyPipe"; 
        HANDLE hPipe; 
        BOOL flg;
        DWORD dwWrite,dwRead;
        char szServerUpdate[200];
        char szClientUpdate[200];

        hPipe = CreateNamedPipe (    lpszPipename, 
                                    PIPE_ACCESS_DUPLEX,
                                    PIPE_TYPE_MESSAGE | 
                                    PIPE_READMODE_MESSAGE | 
                                    PIPE_WAIT,                  //HAS TO BE THIS
                                    PIPE_UNLIMITED_INSTANCES,    // max. instances 
                                    BUFSIZE,                    // output buffer size 
                                    BUFSIZE,                    // input buffer size 
                                    PIPE_TIMEOUT,                // client time-out 
                                    NULL);                        // no security attribute 

        if (hPipe == INVALID_HANDLE_VALUE) 
            return 0;

        ConnectNamedPipe(hPipe, NULL);


        strcpy( szServerUpdate,"busy");

        //Write status to Client
        flg = WriteFile(hPipe, szServerUpdate, strlen(szServerUpdate), &dwWrite, NULL);

        EndServer();
        StartServer();

        return 0;
}

And here's the C# client:

public void ThreadStartClient(object obj)
        {
            // Ensure that we only start the client after the server has created the pipe
            ManualResetEvent SyncClientServer = (ManualResetEvent)obj;

            using (NamedPipeClientStream pipeStream = new NamedPipeClientStream(".", "MyPipe", PipeDirection.InOut))
            {

                // The connect function will indefinately wait for the pipe to become available
                // If that is not acceptable specify a maximum waiting time (in ms)
                pipeStream.Connect();

                if (!pipeStream.IsConnected)    //It thinks it's connected but can't read anything ....
                {
                    MessageBox.Show("Failed to connect ....");
                    return;
                }

                //Read server reply
                StreamReader sr = new StreamReader(pipeStream);

                char[] c = new char[200];

                while (sr.Peek() >= 0)
                {
                    sr.Read(c, 0, c.Length);
                }

                string s = new string(c);
                MessageBox.Show(s);
            }
        }

I'm not actually sending anything from the client to the server because I don't need to ... the key thing in this was the PIPE_WAIT parameter in the CreateNamedPipe() function. This makes the server wait for a client connection.

Share:
15,925

Related videos on Youtube

Bob Moore
Author by

Bob Moore

Updated on September 15, 2022

Comments

  • Bob Moore
    Bob Moore over 1 year

    I am trying to have a 2-way communication between a VC++ 6 app and a C# app. I am using named pipes. In my C++ code I can read the message from the C# client but then the server "dies" and I have to restart it again.

    What I want to do is have the C# app connect to the C++ app, request a status, and the C++ app goes off and checks the status, and then returns either "busy" or "idle".

    I can't write anything back to the C# client as it says the connection has been closed. Some things I have commented out are things I have tried already.

    C++ code (started as a thread)

    UINT CNamedPipe::StartNamedPipeServer()
    {
    LPTSTR lpszPipename = "\\\\.\\pipe\\SAPipe"; 
        HANDLE hPipe; 
        BOOL flg;
        DWORD dwWrite,dwRead;
        char szServerUpdate[200];
        char szClientUpdate[200];
    
        hPipe = CreateNamedPipe (    lpszPipename, 
                                    PIPE_ACCESS_DUPLEX,
                                    PIPE_TYPE_MESSAGE | 
                                    PIPE_READMODE_MESSAGE | 
                                    PIPE_NOWAIT,                    //changed from nowait
                                    PIPE_UNLIMITED_INSTANCES,    // max. instances 
                                    BUFSIZE,                    // output buffer size 
                                    BUFSIZE,                    // input buffer size 
                                    PIPE_TIMEOUT,                // client time-out 
                                    NULL);                        // no security attribute 
    
        if (hPipe == INVALID_HANDLE_VALUE) 
            return 0;
    
        ConnectNamedPipe(hPipe, NULL);
    
        while(m_bServerActive)  //This seems to work well ....
        {
    
            //Read from client
            flg = ReadFile(hPipe,szClientUpdate,strlen(szClientUpdate),&dwRead, NULL);
    
            if(flg) //Read something from the client!!!!
            {
                CString csMsg,csTmp;
    
                for(int i=0;i<dwRead;i++){
                    csTmp.Format("%c",szClientUpdate[i]);
                    csMsg += csTmp;
                }
    
    
                AfxMessageBox("Client message: " + csMsg);
    
                strcpy( szServerUpdate,"busy");
    
                //Write status to Client
                flg = WriteFile(hPipe, szServerUpdate, strlen(szServerUpdate), &dwWrite, NULL);
    
                EndServer();
                StartServer();
            }
    
        }
    
        return 0;
    

    }

    C# Code:

    public void ThreadStartClient(object obj)
        {
            // Ensure that we only start the client after the server has created the pipe
            ManualResetEvent SyncClientServer = (ManualResetEvent)obj;
    
            // Only continue after the server was created -- otherwise we just fail badly
            // SyncClientServer.WaitOne();
    
            using (NamedPipeClientStream pipeStream = new NamedPipeClientStream(".", "SAPipe"))
            {
                // The connect function will indefinately wait for the pipe to become available
                // If that is not acceptable specify a maximum waiting time (in ms)
                pipeStream.Connect();
    
                //Write from client to server
               using (StreamWriter sw = new StreamWriter(pipeStream))
                {
                    sw.WriteLine("What's your status?");
               }
    
                //Read server reply
                /*using (StreamReader sr = new StreamReader(pipeStream))
                {
                    string temp = "";
                    temp = sr.ReadLine();   //Pipe is already closed here ... why?
    
                    MessageBox.Show(temp);
    
                }*/
    
                //pipeStream.Close();
    
            }
        }
    }
    
  • Bob Moore
    Bob Moore almost 12 years
    Thanks, that's a great help. I'll change my code and see what happens. As you might have guessed, I'm new to C#.
  • Blam
    Blam almost 12 years
    No problem, remember to press the check under the votes, that way you'll get a better approval rating!