0

I have a client and a server communicating using a named pipe.

I'm trying to pass the address stored by an LPCWSTR variable from the client to the server.

To do this, I first write the address onto a wchar_t buffer, then I send the server the size of that buffer (as a DWORD), so now the server knows how many bytes it has to read. I managed to send the buffer size successfully, I'm unable to send the complete string though.

Even though the server says it has read the required number of bytes, the buffer on the server side doesn't have the entire string.

Client:

wchar_t msgBuffer[1024];
LPCWSTR lpName = L"NameString";

_swprintf(msgBuffer, _T("%p\0"), lpName);       //Write data to the buffer

DWORD nBytesToWrite = wcslen(msgBuffer);        //Number of bytes to be written

bWriteFile = WriteFile(                         //Send the buffer size
    hCreateFile,
    &nBytesToWrite,
    (DWORD)sizeof(nBytesToWrite),
    &dwNoBytesWritten,
    NULL
);

bWriteFile = WriteFile(                         //Send the data
    hCreateFile,
    msgBuffer,
    (DWORD)wcslen(msgBuffer),
    &dwNoBytesWritten,
    NULL
);

Server:

DWORD dwBytesToRead = 0;

bReadFile = ReadFile(                           //Read the size of the next message
    hCreateNamedPipe,
    &dwBytesToRead,
    sizeof(DWORD),
    &dwNoBytesRead,
    NULL);

std::cout << "\nBytes to be read: " << dwBytesToRead;

wchar_t msg[] = L"";

bReadFile = ReadFile(                           //Read the data
    hCreateNamedPipe,
    &msg,
    dwBytesToRead,
    &dwNoBytesRead,
    NULL);

std::cout << "\nBytes Read: " << dwNoBytesRead;// << '\n' << msg;
wprintf(L"\nMessage: %s\nSize: %zu", msg, wcslen(msg));

This is what the output on the server side is:

Bytes to be read: 9

Bytes Read: 9

Message: 78E7

Size: 5

The address is 78E7325C on the client side, but my server only prints 78E7

Even though the server says to have read 9 bytes, the size of the resultant wchar_t is just 5, why is this?

EDIT: I've checked the buffer on the client side, it has the correct address stored. And is it okay to be sending the DWORD variable using the address-of (&) operator in WriteFile()?

The Solution

Changed (DWORD)wcslen(nBytesToWrite) to (DWORD)sizeof(nBytesToWrite)

wcslen gives the number of characters, whereas sizeof gives the number of bytes, and these aren't the same.

lmnml
  • 37
  • 5
  • Generally, your question lacks a [mcve]. However, how many bytes did you write? Is the reading or the writing the problem? As a new user here, please also take the [tour] and read [ask]. I'd also suggest you submit the minimal example to codereview.stackexchange.com, there are a few bad habits. – Ulrich Eckhardt Feb 27 '20 at 08:48
  • I wrote 9 bytes. The server knows it has to read 9 bytes (dwBytesToRead), and it claims to have read 9 bytes (dwNoBytesRead). However when I try to print the buffer, it shows only the first 4 characters. The size of the buffer is 5, meaning even though ReadFile() read 9 bytes, either all of it didn't end up in the buffer or I'm missing something else. – lmnml Feb 27 '20 at 09:00

1 Answers1

0

C-style strings are represented as pointers to a character array, with an implied length. The length is the number of characters in the array up to the first NUL character. When you interpret binary data as a C-style string (which your call to wprintf does), it stops writing characters once it finds the first character with a value of zero.

You are indeed able to read the entire message. The bug is that your code to verify this condition is based on a wrong assumption. You'll have to output dwNoBytesRead bytes in a loop, and cannot take advantage of the built-in string facilities of wprintf.


Besides that, you are reading into unallocated memory. wchar_t msg[] = L"" allocates an array of exactly one character, but you are reading into it, as if it were able to grow. That's not how things work in C. You'll need to familiarize yourself with the basics of the programming language you are using.


In addition, you are sending only half of your payload. WriteFile expects the number of bytes to write, but you are passing the return value of wcslen, i.e. the number of characters. On Windows, a wchar_t is 2 bytes wide.

IInspectable
  • 46,945
  • 8
  • 85
  • 181
  • Your last para was exactly what I overlooked. When I first learned about pipes, I was sending `char` types, where one char is one byte. However it isn't the same with `wchar_t`. Thanks for pointing out my mistake, understood the basics from this thread- https://stackoverflow.com/questions/7743356/length-of-a-c-stdstring-in-bytes – lmnml Feb 27 '20 at 10:18