void JavascriptError::SetErrorMessage(JavascriptError *pError, HRESULT hr, ScriptContext* scriptContext, va_list argList)
    {
        Assert(FAILED(hr));
        char16 * allocatedString = nullptr;

        if (FACILITY_CONTROL == HRESULT_FACILITY(hr) || FACILITY_JSCRIPT == HRESULT_FACILITY(hr))
        {
            if (argList != nullptr)
            {
                HRESULT hrAdjusted = GetAdjustedResourceStringHr(hr, /* isFormatString */ true);

                BSTR message = BstrGetResourceString(hrAdjusted);
                if (message != nullptr)
                {
                    size_t len = _vscwprintf(message, argList);
                    Assert(len > 0);
                    len = AllocSizeMath::Add(len, 1);
                    allocatedString = RecyclerNewArrayLeaf(scriptContext->GetRecycler(), char16, len);

#pragma prefast(push)
#pragma prefast(disable:26014, "allocatedString allocated size more than msglen")
#pragma prefast(disable:26000, "allocatedString allocated size more than msglen")
                    len = vswprintf_s(allocatedString, len, message, argList);
                    Assert(len > 0);
#pragma prefast(pop)

                    SysFreeString(message);
                }
            }
            if (allocatedString == nullptr)
            {
                HRESULT hrAdjusted = GetAdjustedResourceStringHr(hr, /* isFormatString */ false);

                BSTR message = BstrGetResourceString(hrAdjusted);
                if (message == nullptr)
                {
                    message = BstrGetResourceString(IDS_UNKNOWN_RUNTIME_ERROR);
                }
                if (message != nullptr)
                {
                    uint32 len = SysStringLen(message) +1;
                    allocatedString = RecyclerNewArrayLeaf(scriptContext->GetRecycler(), char16, len);
                    wcscpy_s(allocatedString, len, message);
                    SysFreeString(message);
                }
            }
        }
        JavascriptError::SetErrorMessageProperties(pError, hr, allocatedString, scriptContext);
    }
    void JavascriptError::SetErrorMessage(JavascriptError *pError, HRESULT hr, ScriptContext* scriptContext, va_list argList)
    {
        Assert(FAILED(hr));
        wchar_t * allocatedString = nullptr;

        if (FACILITY_CONTROL == HRESULT_FACILITY(hr) || FACILITY_JSCRIPT == HRESULT_FACILITY(hr))
        {
            if (argList != nullptr)
            {
                HRESULT hrAdjusted = GetAdjustedResourceStringHr(hr, /* isFormatString */ true);

                BSTR message = BstrGetResourceString(hrAdjusted);
                if (message != nullptr)
                {
                    size_t len = _vscwprintf(message, argList);
                    Assert(len > 0);
                    len = AllocSizeMath::Add(len, 1);
                    allocatedString = RecyclerNewArrayLeaf(scriptContext->GetRecycler(), wchar_t, len);

#pragma prefast(push)
#pragma prefast(disable:26014, "allocatedString allocated size more than msglen")
#pragma prefast(disable:26000, "allocatedString allocated size more than msglen")
                    len = vswprintf_s(allocatedString, len, message, argList);
                    Assert(len > 0);
#pragma prefast(pop)

                    SysFreeString(message);
                }
            }
    void JavascriptError::SetErrorMessage(JavascriptError *pError, HRESULT hr, PCWSTR varName, ScriptContext* scriptContext)
    {
        Assert(FAILED(hr));
        char16 * allocatedString = nullptr;

        if (FACILITY_CONTROL == HRESULT_FACILITY(hr) || FACILITY_JSCRIPT == HRESULT_FACILITY(hr))
        {
            if (varName != nullptr)
            {
                HRESULT hrAdjusted = GetAdjustedResourceStringHr(hr, /* isFormatString */ true);

                BSTR message = BstrGetResourceString(hrAdjusted);
                if (message != nullptr)
                {
                    uint32 msglen = SysStringLen(message);
                    size_t varlen = wcslen(varName);
                    size_t len = AllocSizeMath::Add(msglen, varlen);
                    allocatedString = RecyclerNewArrayLeaf(scriptContext->GetRecycler(), char16, len);
                    size_t outputIndex = 0;
                    for (size_t i = 0; i < msglen; i++)
                    {
                        Assert(outputIndex < len);
                        if (message[i] == _u('%') && i + 1 < msglen && message[i+1] == _u('s'))
                        {
                            Assert(len - outputIndex >= varlen);
                            wcscpy_s(allocatedString + outputIndex, len - outputIndex, varName);
                            outputIndex += varlen;
                            wcscpy_s(allocatedString + outputIndex, len - outputIndex, message + i + 2);
                            outputIndex += (msglen - i);
                            break;
                        }
#pragma prefast(push)
#pragma prefast(disable:26014, "allocatedString allocated size more than msglen")
#pragma prefast(disable:26000, "allocatedString allocated size more than msglen")
                        allocatedString[outputIndex++] = message[i];
#pragma prefast(pop)
                    }
                    SysFreeString(message);
                    if (outputIndex != len)
                    {
                        allocatedString = nullptr;
                    }
                }
            }
            if (allocatedString == nullptr)
            {
                HRESULT hrAdjusted = GetAdjustedResourceStringHr(hr, /* isFormatString */ false);

                BSTR message = BstrGetResourceString(hrAdjusted);
                if (message == nullptr)
                {
                    message = BstrGetResourceString(IDS_UNKNOWN_RUNTIME_ERROR);
                }
                if (message != nullptr)
                {
                    uint32 len = SysStringLen(message) +1;
                    allocatedString = RecyclerNewArrayLeaf(scriptContext->GetRecycler(), char16, len);
                    wcscpy_s(allocatedString, len, message);
                    SysFreeString(message);
                }
            }
        }
        JavascriptError::SetErrorMessageProperties(pError, hr, allocatedString, scriptContext);
    }
    void JavascriptErrorDebug::SetErrorMessage(JavascriptError *pError, HRESULT hr, PCWSTR varDescription, ScriptContext* scriptContext)
    {
        Assert(FAILED(hr));

        char16* allocatedString = nullptr;
        BSTR restrictedDescription = nullptr;
        BSTR message = nullptr;
        size_t length = 1; // +1 for null character

#ifdef ENABLE_PROJECTION
        // Get the restricted error string - but only if the WinRT is enabled and we are targeting WinBlue+.
        if (JavascriptErrorDebug::Is(pError)
            && scriptContext->GetConfig()->IsWinRTEnabled()
            && scriptContext->GetConfig()->GetProjectionConfig() != nullptr
            && scriptContext->GetConfig()->GetProjectionConfig()->IsTargetWindowsBlueOrLater())
        {
            restrictedDescription = JavascriptErrorDebug::FromVar(pError)->GetRestrictedErrorString();
            length += SysStringLen(restrictedDescription);
        }
#endif

        if (varDescription != nullptr)
        {
            length += wcslen(varDescription);
        }
        else
        {
            if (FACILITY_CONTROL == HRESULT_FACILITY(hr))
            {
                message = BstrGetResourceString(hr);
            }
            if (message == nullptr)
            {
                // Default argument array of empty strings, for CLR parity
                DWORD_PTR pArgs[] = { (DWORD_PTR)_u(""), (DWORD_PTR)_u(""), (DWORD_PTR)_u(""), (DWORD_PTR)_u(""), (DWORD_PTR)_u(""),
                    (DWORD_PTR)_u(""), (DWORD_PTR)_u(""), (DWORD_PTR)_u(""), (DWORD_PTR)_u(""), (DWORD_PTR)_u("") };

                if (FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM |
                    FORMAT_MESSAGE_ARGUMENT_ARRAY,
                    NULL,
                    hr,
                    0,
                    msgBuff,
                    _countof(msgBuff),
                    (va_list*)pArgs))
                {
                    message = SysAllocString(msgBuff);
                }
            }
            if (message == nullptr)
            {
                message = BstrGetResourceString(IDS_UNKNOWN_RUNTIME_ERROR);
            }
            if (message != nullptr)
            {
                length += SysStringLen(message);
            }
        }

        // If length == 1, we didn't find any description strings - leave allocatedString null.
        if (length > 1)
        {
             // If we have a restricted description, the error message format is ("%s\r\n%s", message, restrictedMessage).
             if (restrictedDescription != nullptr)
             {
                 // length should be longer by 2 characters to handle the \r\n
                 allocatedString = RecyclerNewArrayLeaf(scriptContext->GetRecycler(), char16, length + 2);
                 StringCchPrintfW(allocatedString, length + 2, _u("%s\r\n%s"), varDescription ? varDescription : message, restrictedDescription);
             }
             else
             {
                 allocatedString = RecyclerNewArrayLeaf(scriptContext->GetRecycler(), char16, length);
                 wcscpy_s(allocatedString, length, varDescription ? varDescription : message);
             }
        }

        if (restrictedDescription != nullptr)
        {
            SysFreeString(restrictedDescription);
            restrictedDescription = nullptr;
        }

        if (message != nullptr)
        {
            SysFreeString(message);
            message = nullptr;
        }

        JavascriptError::SetErrorMessageProperties(pError, hr, allocatedString, scriptContext);
    }