Two way C++ to C# communication using named pipes
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.
Related videos on Youtube
Bob Moore
Updated on September 15, 2022Comments
-
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 almost 12 yearsThanks, 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 almost 12 yearsNo problem, remember to press the check under the votes, that way you'll get a better approval rating!