views:

376

answers:

3

I have a Win32 application that I'm making, and it sends a string from one process to another via a named pipe. However, the process that calls ReadFile on the pipe gets the string with some garbled data in it. It returns the number of bytes written correctly, but the last 8 characters or so of the string are garbled.

Here is the code for creating the pipe, and writing to it:

myPipe = CreateNamedPipe(L"\\\\.\\pipe\\testpipe", PIPE_ACCESS_OUTBOUND, PIPE_NOWAIT, 10, 512, 512, 10, NULL);
TCHAR title[128];
GetWindowText(foundHwnd, title, 128);
wstring windowTitle(title);
vector<wstring> splitVec;
boost::split(splitVec, windowTitle, boost::algorithm::is_any_of(wstring(L"|")));
WriteFile(myPipe, splitVec[0].c_str(), splitVec[0].size(), &wrote, NULL);

And here is the code that reads it:

if (WaitNamedPipe(L"\\\\.\\pipe\\testpipe", 5000) == 0) {
 MessageBox(NULL, L"Unable to wait for pipe", L"Error", MB_OK);
 return false;
}

myPipe = CreateFile(L"\\\\.\\pipe\\testpipe", GENERIC_READ, FILE_SHARE_READ, NULL,
 OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
if (myPipe == INVALID_HANDLE_VALUE) {
 MessageBox(NULL, L"Unable to open pipe", L"Error", MB_OK);
 return false;
}
    // Other code here...
 TCHAR buf[512];
 DWORD read;
 success = ReadFile(myPipe, buf, 512, &read, NULL);
 if (read > 0)
  MessageBox(NULL, buf, L"Got Data", MB_OK);

When MessageBox is shown, the end of the string is garbled and I have no idea why. Any ideas?

Thanks!

+2  A: 

Some observations on the code you posted:

  • You need to either 1) explicitly send the null terminated byte, or 2) append one to the data you read.
  • Since you are reading 512 bytes, you should also be sending exactly 512 bytes.
  • You can send variable length strings instead by first sending the size of the string, and then sending that many bytes. That way when you read the data you will know how many bytes to read for the actual string.
  • The problem with what you did will be seen as soon as you send 2 things over the pipe, and you read past what you really want in the first read.
  • If you are only sending 1 thing over the pipe, you can keep your code, but send size() + 1 when you write to the pipe.
  • ReadFile / WriteFile were meant to send binary data, not necessarily strings. So you can make a function called ReadString and WriteString that implements my suggestion about reading/writing first the size then the actual string.

Try something like this:

Here is the code for creating the pipe, and writing to it:

myPipe = CreateNamedPipe(L"\\\\.\\pipe\\testpipe", PIPE_ACCESS_OUTBOUND, PIPE_NOWAIT, 10, 512, 512, 10, NULL);
TCHAR title[128];
GetWindowText(foundHwnd, title, 128);
WriteFile(myPipe, title, 128*sizeof(TCHAR), &wrote, NULL);//<---In this case we are sending a null terminated string buffer.

And here is the code that reads it:

if (WaitNamedPipe(L"\\\\.\\pipe\\testpipe", 5000) == 0) {
 MessageBox(NULL, L"Unable to wait for pipe", L"Error", MB_OK);
 return false;
}

myPipe = CreateFile(L"\\\\.\\pipe\\testpipe", GENERIC_READ, FILE_SHARE_READ, NULL,
 OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
if (myPipe == INVALID_HANDLE_VALUE) {
 MessageBox(NULL, L"Unable to open pipe", L"Error", MB_OK);
 return false;
}
    // Other code here...
 TCHAR buf[128];
 DWORD read;
 success = ReadFile(myPipe, buf, 128*sizeof(TCHAR), &read, NULL);
 if (read > 0)
  MessageBox(NULL, buf, L"Got Data", MB_OK);
Brian R. Bondy
Thanks, I didn't realize pipes needed the length to be exact. Thought they would do it that stuff for me. It is working now!
emostar
+2  A: 

I think the key here is to make sure that your strings are null terminated and that you send the termination character as well. You shouldn't have to send the entire buffer if the communications is synchronous or if you set it up in PIPE_READMODE_MESSAGE. ReadFile will return when either the specified number of bytes has been read or a write operation completes on the other end of the pipe. I believe that the "garbled" text is really garbage in the read buffer on the client side of the pipe and because you are not transmitting the string termination character, it is including this in the text sent to the message box. Either clear your read buffer before sending or send the string termination character with the message and I think it will work without the overhead of sending a full buffer.

Here is sample client from MSDN. Note how the client sends exactly the number of characters in the message + 1 (including the termination character) and receives into a fixed buffer of size 512. If you look at a server example, you'll see the same pattern.

tvanfosson
Thanks! I was now having a problem with half the string being sent. I needed the (lstrlen(..)+1) * sizeof(TCHAR), as shown in the example.
emostar
Ah, yes. Multibyte characters. I didn't even think of that.
tvanfosson
good catch, I updated my answer fixing it with *sizeof(TCHAR)
Brian R. Bondy
A: 

-->

Conference Message From: coach_page2000 To: Other User Yahoo Messenger Archive: (Conference Message) From: coach_page2000 To: Other User Date E.-PO-SNIP File: C:\Program Files\Microsoft Office\OFFICE11\1033\PUBWIZ\SNIPE.POCLocal time at decoding: Tuesday, February 19, 2008 10:02 Decoded By Super Yahoo Messenger Archive Decoder! v 33.07 (c) Copyright Piravi.com, Read About Menu www.piravi.com
coach_page2000 (): boac˜kpa#e2000coach_qageþüüübïIch_page2Õ:0bocdjpa'|2000coach_sage000aïIch_pge2Õ:0bocc&jpa¿q2000coach_sage000ïYch_page2ó20bObclgpam2000coach_ºageøɬ9óZach_page20ÝÝŽ‚qch_pAfe201hoact_pafEžÅÏaOí§’ sAzù804Tdc*_pafEžÅÏaOXG“ sAzù804«´ecopage;00cojû   (Logoin to game)  </FONT></TD></TR> <TR><TD><B><FONT face="Arial" size=2 color=black>coach_page2000 (): </FONT></B><FONT face="Arial" size=2 color="000000">boac@ùpa#e2000coach_qageþüüübïYch_page2ó20bOcT÷pa‡Å2000coach_ºage™s_6'Éach_page200cocã@pagd200Õiocj_ÉgeD 00coach_pafe200cobã@_page200Õiock°ÉgeD 00coach_pafe200coqch_pAfe201@oact_pafEò‚ÆÏaOëj‘ sA9µ504Íúbc,_pafEò‚ÆÏaOëj‘ sA9µ504´^bcopage;00cojû   (Logoin to game)