Click here to Skip to main content
15,880,956 members
Please Sign up or sign in to vote.
0.00/5 (No votes)
See more:
I am working on a project where I am interacting between the components of VC++ (Server) and C# Client.

The C# component is been triggered by VC++ and further interactions happens between these components over Control Pipes.

The Control pipe is created at the VC++ as follows:
StartNamedPipeServer(const wchar_t* wszParametersXML)
{

m_hServerPipe = ::CreateNamedPipe(m_wszServerPipe, PIPE_ACCESS_DUPLEX | FILE_FLAG_OVERLAPPED, PIPE_TYPE_MESSAGE | PIPE_READMODE_MESSAGE | PIPE_WAIT, 1, MAX_PATH, MAX_PATH, 0, NULL);
if(m_hServerPipe!=INVALID_HANDLE_VALUE)
  {
     ::ConnectNamedPipe(m_hServerPipe, NULL);
  }
DWORD dwWrite=0;
::WriteFile(m_hServerPipe, szFilePath, strlen(szFilePath), &dwWrite, NULL);       // Writes some data to control pipe (usually a file path)
return 0;
}



The control pipe is created and connected fine. At the C# end the data is received without any problem and C# (Client) writes back to the same pipe with "wait" and "proceed" messages as below.

C#
while (true)
     {
         using (NamedPipeClientStream ClientPipeStream = new NamedPipeClientStream(".", NamedClientPipe, PipeDirection.InOut))
         {
             while (true)
             {
                 try
                 {
                     //The connect function will connect to the pipe if available
                     ClientPipeStream.Connect(1000);
                     break;
                 }
                 catch
                 {
                         // Pipe is not connected  - re attempt
                         continue;
                 }
             }
             //Read server reply
             StreamReader ClientStream = new StreamReader(ClientPipeStream);
             char[] param = new char[260];
             while (ClientStream.Peek() >= 0)
             {
                 ClientStream.Read(param, 0, param.Length);
             }

             using (StreamWriter ServerStreamWriter = new StreamWriter(ClientPipeStream))
             {
                 try
                 {
                     ServerStreamWriter.AutoFlush = true;
                     ServerStreamWriter.WriteLine("wait");

                    StartProcessing(modelFolderPath, mailslotName, ControlPipeName);  // ControlpipeName will be available and it is same as connected one // Task processing Implementation takes some 1 - 5 mins

                     ServerStreamWriter.WriteLine("proceed");
                     System.Threading.Thread.Sleep(1000);

                 }
                 catch (Exception ex)
                 {
                     ServerStreamWriter.WriteLine("proceed");
                     System.Threading.Thread.Sleep(1000);
                     retvalue = FAILURE; //program failed
                 }
             }
         }
     }


VC++ reads the messages for further processing as below.

C#
ReadNamedPipeServer()
{
char szClientUpdate[100];   
BOOL bSuccess=FALSE;
for (;;)
{
DWORD dwBytesAvail = 0;
if(!::PeekNamedPipe(m_hServerPipe, NULL, 0, NULL, &dwBytesAvail, NULL) || dwBytesAvail > 0)
{
   //SendText(L"Read some data from pipe");
    DWORD dwRead=0;
    bSuccess = ::ReadFile(m_hServerPipe, szClientUpdate, sizeof(szClientUpdate), &dwRead, NULL);    
    if (bSuccess) 
    {   
        if(strncmp(szClientUpdate, "wait", 4) == 0)
        {
            return 1;
        }
        if(strncmp(szClientUpdate, "proceed", 7) == 0)
        {
           return 0;
        }
    }
}

Need the experts suggestions and design changes if anything required here.

What I have tried:

The ReadNamedPipe server works fine and the messages "wait" and "proceed" are read fine. but sometimes, when "proceed" is written, the pipe is not been read at the VC++ ReadNamedPipeServer() method and the program goes to an infinite loop and hangs the application flow.(This happens in some specific machines like Win 10 64Bit and sometimes in Win7 64bit machines).
Posted
Updated 18-Jan-17 12:25pm
v3
Comments
Richard MacCutchan 18-Jan-17 7:01am    
You should not create an infinite loop without some way of breaking out when it does not read a valid message. Also, your if statement looks the wrong way round. If PeekNamedPipe returns zero then you try to read from the pipe.
Jagssnaik 18-Jan-17 7:16am    
Hi Richard,
Thanks for the inputs. I have corrected my if loop.

Regarding Infinite loop - I am trying to return depending on the messages sent by client, but sometimes client writes to the pipe and server cannot able to read because of Broken pipe or some other error.

I am new to IPC so could you please suggest in what way I can break the loop?
if(!bSuccess && (::GetLastError() == ERROR_BROKEN_PIPE))
{
return 0;
}
Trying this will be helpful ? Could you please suggest any better alternative?


Richard MacCutchan 18-Jan-17 7:23am    
not really. The problem is how to manage a system where data arrives in a random fashion. You need some way to poll the remote device, or receive a signal when some data arrives. In either case you need to check what has arrived and process it accordingly. If there is no data then you need to use some mechanism to wait until there is some. The information returned from the peek function should help you make those decisions. Study the documentation to see the best way of handling it.
Jagssnaik 18-Jan-17 7:30am    
Hi Richard, Thanks for you suggestions. I shall give it a try.
OverlappedIO is what you are suggesting for?

This content, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)



CodeProject, 20 Bay Street, 11th Floor Toronto, Ontario, Canada M5J 2N8 +1 (416) 849-8900