2

I have the following C++ code that retrieves header request information from an HttpContext instance:

public:
REQUEST_NOTIFICATION_STATUS
    OnBeginRequest(
    IN IHttpContext * pHttpContext,
    IN IHttpEventProvider * pProvider
    )
    {

        UNREFERENCED_PARAMETER(pHttpContext);
        UNREFERENCED_PARAMETER(pProvider);

        PCSTR header = pHttpContext->GetRequest()->GetHeader("Accept", NULL);
        WriteEventViewerLog(header);

As you can see, the call:

pHttpContext->GetRequest()->GetHeader("Accept", NULL)** 

Returns a PCSTR data type.

But I need to feed the WriteEventViewerLog with header as a "LPCWSTR", since one of the functions that I use inside the methods only accepts the string in that format.

From https://msdn.microsoft.com/en-us/library/windows/desktop/aa383751%28v=vs.85%29.aspx, about these string definitions:

A pointer to a constant null-terminated string of 8-bit Windows (ANSI) characters. For more information, see Character Sets Used By Fonts.

This type is declared in WinNT.h as follows:

typedef CONST CHAR *PCSTR;

And LPCWSTR:

A pointer to a constant null-terminated string of 16-bit Unicode characters. For more information, see Character Sets Used By Fonts.

This type is declared in WinNT.h as follows:

typedef CONST WCHAR *LPCWSTR;

I didn't find out a way of converting from these two data types. I tried casting header to char* and then using the function below to move from char* to LPCWSTR:

LPWSTR charArrayToLPWSTR(char *source)
    {
        // Get required buffer size in 'wide characters'
        int nSize = MultiByteToWideChar(CP_ACP, 0, source, -1, NULL, 0);

        LPWSTR outString = new WCHAR[nSize];

        // Make conversion
        MultiByteToWideChar(CP_ACP, 0, source, -1, outString, nSize);
        return outString;
    }

But that returned to me an invalid string (I don't have the complete input, but the Accept header value was trimmed to "x;ih").

Mr.C64
  • 41,637
  • 14
  • 86
  • 162
lfaletti
  • 46
  • 5
  • 2
    That function should work. Check what's happening in the debugger. – Jonathan Potter Mar 07 '16 at 21:30
  • From the looks of things, `charArrayToLPWSTR()` should work, though I'd make it `const char *source` to match the type of `PCSTR`: `LPWSTR wszHeader = charArrayToLPWSTR(header); /* Code using wszHeader. */ delete[] wszHeader;`. Do you have more information such as sample input and output that works or doesn't work and maybe the actual section of code that requires usage of `LPWSTR`? –  Mar 07 '16 at 21:35
  • Try `CP_UTF8` instead of `CP_ACP` – Barmak Shemirani Mar 07 '16 at 21:35
  • I suggest the use of convenient ATL conversion helpers around `MultiByteToWideChar()`, or write some function returning a `CString` or `std::wstring`, but **do not** return a raw owning pointer allocated with `new[]` inside the function body. This can be a _leaktrocity_ if the caller doesn't pay much attention to deallocate the returned string. It's **C++**, _not_ C. – Mr.C64 Mar 07 '16 at 23:35
  • 2
    That function doesn't check the return values. Please show an example of the input that leads to the bad output. Also be aware that that function requires the caller to free the buffer correctly, or it will leak. – Adrian McCarthy Mar 08 '16 at 00:23
  • The fact is that by using `charArrayToPWSTR()` I would need to convert the `PCSTR` to char* to later move from that to `LPCWSTR`. Also, `MultiByteToWideChar()` doesn't accept its third argument as `PCSTR` so I don't see the possibility of using that one. However it worked with `CA2W` – lfaletti Mar 08 '16 at 13:50

1 Answers1

4
pHttpContext->GetRequest()->GetHeader("Accept", NULL);   

returns a PCSTR data type.

But I need to feed the WriteEventViewerLog with header as a LPCWSTR, since one of the functions that I use inside the methods only accepts the string in that format.

First, let's clarify the meaning of these "obscure" Windows API string typedefs:

PCSTR:   const char *    
LPCWSTR: const wchar_t *

So, both are pointers to read-only NUL-terminated C-style strings.

The difference is that PCSTR points to a char-based string; LPCWSTR points to a wchar_t-based string.

char-based strings can be of several "forms" (or encodings), e.g. simple ASCII, or Unicode UTF-8, or other "multi-byte" encodings.

In case of your header string, I assume it can be simple ASCII, or UTF-8 (note that ASCII is a proper subset of UTF-8).

wchar_t-based strings in Visual C++ are Unicode UTF-16 strings (and this is the "native" Unicode encoding used by most Win32 APIs).

So, what you have to do is to convert from a char-based string to a wchar_t-based one. Assuming that your char-based string represents a Unicode UTF-8 string (of which pure ASCII is a proper subset), you can use the MultiByteToWideChar() Win32 API to do the conversion.

Or you can use some helper classes to simplify the conversion task, for example ATL conversion helpers. In particular, the CA2W helper with the CP_UTF8 conversion flag can come in handy in your case:

#include <atlconv.h>  // for CA2W
...

// Get the header string in Unicode UTF-8
PCSTR header = pHttpContext->GetRequest()->GetHeader("Accept", nullptr);

// Convert the header string from UTF-8 to Unicode UTF-16
WriteEventViewerLog( CA2W(header, CP_UTF8) );
Mr.C64
  • 41,637
  • 14
  • 86
  • 162
  • The use of CA2W solved the issue. I just had to `#include #include ` in addition to atlconv.h to be able to use it. – lfaletti Mar 08 '16 at 13:39