0

I'm trying to modify this function https://stackoverflow.com/a/35658917/19324589

from CStringA (i have no idea what data type is it) to std::wstring

char buf[1024] to wstring buf

'original' function:

        char buf[1024];

        DWORD dwRead = 0;
        DWORD dwAvail = 0;

        if (!::PeekNamedPipe(hPipeRead, NULL, 0, NULL, &dwAvail, NULL))
            break;

        if (!dwAvail) // No data available, return
            break;

        if (!::ReadFile(hPipeRead, buf, min(sizeof(buf) - 1, dwAvail), &dwRead, NULL) || !dwRead)
            // Error, the child process might ended
            break;

        buf[dwRead] = 0;
        strResult += buf;

my attempt:

when i modify buf from char to wstring, it stores only garbage after the ReadFile line.

        std::wstring strResult;
        // ...

        std::wstring buf(1024, '\0');
        DWORD dwRead = 0;
        DWORD dwAvail = 0;

        if (!::PeekNamedPipe(hPipeRead, NULL, 0, NULL, &dwAvail, NULL))
            break;

        if (!dwAvail) // No data available, return
            break;

        if (!::ReadFile(hPipeRead, buf.data(), min((buf.size() * sizeof(wchar_t)), dwAvail), &dwRead, NULL) || !dwRead)
            // Error, the child process might ended
            break;

        strResult += buf;

I end up doing:

bool bProcessEnded = false;
std::string result;

for (; !bProcessEnded;)
{
    // Give some timeslice (50 ms), so we won't waste 100% CPU.
    bProcessEnded = WaitForSingleObject(pi.hProcess, 50) == WAIT_OBJECT_0;

    // Even if process exited - we continue reading, if
    // there is some data available over pipe.
    for (;;)
    {
        char buf[1024];
        DWORD dwRead = 0;
        DWORD dwAvail = 0;

        if (!::PeekNamedPipe(hPipeRead, NULL, 0, NULL, &dwAvail, NULL))
            break;

        if (!dwAvail) // No data available, return
            break;

        if (!::ReadFile(hPipeRead, buf, min((sizeof(buf) - 1), dwAvail), &dwRead, NULL) || !dwRead)
            // Error, the child process might ended
            break;

        buf[dwRead] = 0;
        result += buf;
    }
} //for

CloseHandle(hPipeWrite);
CloseHandle(hPipeRead);
CloseHandle(pi.hProcess);
CloseHandle(pi.hThread);
return to_wstring(result);

In my use case buf is returning a data like already connected to 127.0.0.1:5555

I would like to understand what i'm doing wrong?

273K
  • 29,503
  • 10
  • 41
  • 64
Cesar
  • 41
  • 2
  • 5
  • 16
  • You are better off storing the raw bytes of the spawned process's output into a `std::string` first (which is exactly what the original code does, just using `CStringA` instead, which is a wrapper for a dynamic `char[]` array, same as `std::string` is). If you need a `std::wstring` afterwards, then you can convert the `std::string` as a whole to `std::wstring` using `std::wstring_convert` or equivalent. Don't try to convert *arbitrary chunks of bytes* while you are still reading the bytes, as you are likely to encounter decoding errors that way. Wait until you have the full bytes first. – Remy Lebeau Aug 29 '22 at 23:09
  • @RemyLebeau i see, why do i get garbage when using wchar? nothing is being converted there as by default its using wstring – Cesar Aug 29 '22 at 23:24
  • Because you are not using `std::wstring` correctly. For one thing, the output is not likely to be encoded in UTF-16 to begin with. And second, you are ignoring `dwRead` when appending `buf` to `strResult`. `dwRead` tells you how many *bytes* (not *characters*!) were written into `buf`, which is likely to be less than what you allocated space for, so you need to ignore the unfilled space. Look at using `basic_string::append()` instead of the `basic_string::operator+=` (that would also eliminate the need to null-terminate `buf` before appending it). – Remy Lebeau Aug 29 '22 at 23:34
  • Side note: When in doubt, [look for documentation](https://learn.microsoft.com/en-us/cpp/atl-mfc-shared/using-cstring?view=msvc-170). Your mileage may vary, Google play games with the search results , but for me that link shows up as the first suggestion for a search for *CStringA*. – user4581301 Aug 30 '22 at 00:29
  • The last character of `CStringA` and `CStringW` tells you the type: `char` and `wchar_t`. Note that `ReadFile` is just reading bytes. It has no concept of type. If you read 8-bit data into a `CStringW` or a `std::wstring`, you will get garbage with no errors. – Tim Roberts Aug 30 '22 at 02:03
  • A lot will depend on the encoding used by your char string. If it's ASCII as in your example or Latin-1 you're in luck, because you can just copy the string character by character. Other encodings can be hellishly complex unless you have a library to handle it for you. – Mark Ransom Aug 30 '22 at 02:33

0 Answers0