diff options
author | dotnet-bot <dotnet-bot@microsoft.com> | 2015-01-30 14:14:42 -0800 |
---|---|---|
committer | dotnet-bot <dotnet-bot@microsoft.com> | 2015-01-30 14:14:42 -0800 |
commit | ef1e2ab328087c61a6878c1e84f4fc5d710aebce (patch) | |
tree | dee1bbb89e9d722e16b0d1485e3cdd1b6c8e2cfa /src/utilcode/posterror.cpp | |
download | coreclr-ef1e2ab328087c61a6878c1e84f4fc5d710aebce.tar.gz coreclr-ef1e2ab328087c61a6878c1e84f4fc5d710aebce.tar.bz2 coreclr-ef1e2ab328087c61a6878c1e84f4fc5d710aebce.zip |
Initial commit to populate CoreCLR repo
[tfs-changeset: 1407945]
Diffstat (limited to 'src/utilcode/posterror.cpp')
-rw-r--r-- | src/utilcode/posterror.cpp | 404 |
1 files changed, 404 insertions, 0 deletions
diff --git a/src/utilcode/posterror.cpp b/src/utilcode/posterror.cpp new file mode 100644 index 0000000000..0ae48aab71 --- /dev/null +++ b/src/utilcode/posterror.cpp @@ -0,0 +1,404 @@ +// +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. +// +//***************************************************************************** +// PostErrors.cpp +// +// This module contains the error handling/posting code for the engine. It +// is assumed that all methods may be called by a dispatch client, and therefore +// errors are always posted using IErrorInfo. +// + +//***************************************************************************** +#include "stdafx.h" // Standard header. + +#ifndef FEATURE_UTILCODE_NO_DEPENDENCIES + +#include <utilcode.h> // Utility helpers. +#include <corerror.h> +#include "../dlls/mscorrc/resource.h" +#include "ex.h" + +#include <posterror.h> + +#if !defined(lengthof) +#define lengthof(x) (sizeof(x)/sizeof(x[0])) +#endif + +// Local prototypes. +HRESULT FillErrorInfo(LPCWSTR szMsg, DWORD dwHelpContext); + +//***************************************************************************** +// Function that we'll expose to the outside world to fire off the shutdown method +//***************************************************************************** +#ifdef SHOULD_WE_CLEANUP +void ShutdownCompRC() +{ + CCompRC::ShutdownDefaultResourceDll(); +} +#endif /* SHOULD_WE_CLEANUP */ + +void GetResourceCultureCallbacks( + FPGETTHREADUICULTURENAMES* fpGetThreadUICultureNames, + FPGETTHREADUICULTUREID* fpGetThreadUICultureId) +{ + WRAPPER_NO_CONTRACT; + CCompRC::GetDefaultCallbacks( + fpGetThreadUICultureNames, + fpGetThreadUICultureId + ); +} +//***************************************************************************** +// Set callbacks to get culture info +//***************************************************************************** +void SetResourceCultureCallbacks( + FPGETTHREADUICULTURENAMES fpGetThreadUICultureNames, + FPGETTHREADUICULTUREID fpGetThreadUICultureId // TODO: Don't rely on the LCID, only the name +) +{ + WRAPPER_NO_CONTRACT; + CCompRC::SetDefaultCallbacks( + fpGetThreadUICultureNames, + fpGetThreadUICultureId + ); + +} + +//***************************************************************************** +// Public function to load a resource string +//***************************************************************************** +STDAPI UtilLoadStringRC( + UINT iResourceID, + __out_ecount(iMax) LPWSTR szBuffer, + int iMax, + int bQuiet +) +{ + WRAPPER_NO_CONTRACT; + return UtilLoadResourceString(bQuiet? CCompRC::Optional : CCompRC::Required,iResourceID, szBuffer, iMax); +} + +HRESULT UtilLoadResourceString(CCompRC::ResourceCategory eCategory, UINT iResourceID, __out_ecount (iMax) LPWSTR szBuffer, int iMax) +{ + CONTRACTL + { + DISABLED(NOTHROW); + GC_NOTRIGGER; + SO_TOLERANT; + } + CONTRACTL_END; + + HRESULT retVal = E_OUTOFMEMORY; + + BEGIN_SO_INTOLERANT_CODE_NO_THROW_CHECK_THREAD(return COR_E_STACKOVERFLOW); + SString::Startup(); + EX_TRY + { + CCompRC *pResourceDLL = CCompRC::GetDefaultResourceDll(); + + if (pResourceDLL != NULL) + { + retVal = pResourceDLL->LoadString(eCategory, iResourceID, szBuffer, iMax); + } + } + EX_CATCH + { + // Catch any errors and return E_OUTOFMEMORY; + retVal = E_OUTOFMEMORY; + } + EX_END_CATCH(SwallowAllExceptions); + + END_SO_INTOLERANT_CODE; + + return retVal; +} + +#ifdef FEATURE_USE_LCID +STDAPI UtilLoadStringRCEx( + LCID lcid, + UINT iResourceID, + __out_ecount(iMax) LPWSTR szBuffer, + int iMax, + int bQuiet, + int *pcwchUsed +) +{ + CONTRACTL + { + DISABLED(NOTHROW); + GC_NOTRIGGER; + SO_TOLERANT; + } + CONTRACTL_END; + + HRESULT retVal = E_OUTOFMEMORY; + + BEGIN_SO_INTOLERANT_CODE_NO_THROW_CHECK_THREAD(return COR_E_STACKOVERFLOW); + EX_TRY + { + SString::Startup(); + CCompRC *pResourceDLL = CCompRC::GetDefaultResourceDll(); + + if (pResourceDLL != NULL) + { + retVal = pResourceDLL->LoadString(bQuiet? CCompRC::Optional : CCompRC::Required,lcid, iResourceID, szBuffer, iMax, pcwchUsed); + } + } + EX_CATCH + { + // Catch any errors and return E_OUTOFMEMORY; + retVal = E_OUTOFMEMORY; + } + EX_END_CATCH(SwallowAllExceptions); + END_SO_INTOLERANT_CODE; + + return retVal; +} +#endif //FEATURE_USE_LCID + +//***************************************************************************** +// Format a Runtime Error message. +//***************************************************************************** +HRESULT __cdecl FormatRuntimeErrorVa( + __inout_ecount(cchMsg) WCHAR *rcMsg, // Buffer into which to format. + ULONG cchMsg, // Size of buffer, characters. + HRESULT hrRpt, // The HR to report. + va_list marker) // Optional args. +{ + CONTRACTL + { + NOTHROW; + GC_NOTRIGGER; + } + CONTRACTL_END; + + WCHAR rcBuf[512]; // Resource string. + HRESULT hr; + + // Ensure nul termination. + *rcMsg = W('\0'); + + // If this is one of our errors or if it is simply a resource ID, then grab the error from the rc file. + if ((HRESULT_FACILITY(hrRpt) == FACILITY_URT) || (HIWORD(hrRpt) == 0)) + { + hr = UtilLoadStringRC(LOWORD(hrRpt), rcBuf, NumItems(rcBuf), true); + if (hr == S_OK) + { + _vsnwprintf_s(rcMsg, cchMsg, _TRUNCATE, rcBuf, marker); + } + } + // Otherwise it isn't one of ours, so we need to see if the system can + // find the text for it. + else + { +#ifdef FEATURE_USE_LCID + if (WszFormatMessage(FORMAT_MESSAGE_FROM_SYSTEM, + 0, hrRpt, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), + rcMsg, cchMsg, 0/*<TODO>@todo: marker</TODO>*/)) +#else + if (WszFormatMessage(FORMAT_MESSAGE_FROM_SYSTEM, + 0, hrRpt, 0, + rcMsg, cchMsg, 0/*<TODO>@todo: marker</TODO>*/)) +#endif + { + hr = S_OK; + + // System messages contain a trailing \r\n, which we don't want normally. + size_t iLen = wcslen(rcMsg); + if (iLen > 3 && rcMsg[iLen - 2] == '\r' && rcMsg[iLen - 1] == '\n') + rcMsg[iLen - 2] = '\0'; + } + else + hr = HRESULT_FROM_GetLastError(); + } + + // If we failed to find the message anywhere, then issue a hard coded message. + if (FAILED(hr)) + { + _snwprintf_s(rcMsg, cchMsg, _TRUNCATE, W("Common Language Runtime Internal error: 0x%08x"), hrRpt); + DEBUG_STMT(DbgWriteEx(rcMsg)); + } + + return hrRpt; +} // FormatRuntimeErrorVa + +//***************************************************************************** +// Format a Runtime Error message, varargs. +//***************************************************************************** +HRESULT __cdecl FormatRuntimeError( + __out_ecount(cchMsg) WCHAR *rcMsg, // Buffer into which to format. + ULONG cchMsg, // Size of buffer, characters. + HRESULT hrRpt, // The HR to report. + ...) // Optional args. +{ + WRAPPER_NO_CONTRACT; + va_list marker; // User text. + va_start(marker, hrRpt); + hrRpt = FormatRuntimeErrorVa(rcMsg, cchMsg, hrRpt, marker); + va_end(marker); + return hrRpt; +} + +#ifdef FEATURE_COMINTEROP +//***************************************************************************** +// Create, fill out and set an error info object. Note that this does not fill +// out the IID for the error object; that is done elsewhere. +//***************************************************************************** +HRESULT FillErrorInfo( // Return status. + LPCWSTR szMsg, // Error message. + DWORD dwHelpContext) // Help context. +{ + CONTRACTL + { + NOTHROW; + GC_NOTRIGGER; + } + CONTRACTL_END; + + ICreateErrorInfo *pICreateErr; // Error info creation Iface pointer. + IErrorInfo *pIErrInfo = NULL; // The IErrorInfo interface. + HRESULT hr; // Return status. + + // Get the ICreateErrorInfo pointer. + hr = S_OK; + EX_TRY + { + hr = CreateErrorInfo(&pICreateErr); + } + EX_CATCH + { + hr = GET_EXCEPTION()->GetHR(); + } + EX_END_CATCH(SwallowAllExceptions); + + if (FAILED(hr)) + return (hr); + + // Set message text description. + if (FAILED(hr = pICreateErr->SetDescription((LPWSTR) szMsg))) + goto Exit1; + + // suppress PreFast warning about passing literal string to non-const API. + // This API (ICreateErrorInfo::SetHelpFile) is documented to take a const argument, but + // we can't put const in the signature because it would break existing implementors of + // the API. +#ifdef _PREFAST_ +#pragma prefast(push) +#pragma warning(disable:6298) +#endif + + // Set the help file and help context. + //<TODO>@todo: we don't have a help file yet.</TODO> + if (FAILED(hr = pICreateErr->SetHelpFile(const_cast<wchar_t*>(W("complib.hlp")))) || + FAILED(hr = pICreateErr->SetHelpContext(dwHelpContext))) + goto Exit1; + +#ifdef _PREFAST_ +#pragma prefast(pop) +#endif + + // Get the IErrorInfo pointer. + if (FAILED(hr = pICreateErr->QueryInterface(IID_IErrorInfo, (PVOID *) &pIErrInfo))) + goto Exit1; + + // Save the error and release our local pointers. + { + // If we get here, we have loaded oleaut32.dll. + CONTRACT_VIOLATION(ThrowsViolation); + SetErrorInfo(0L, pIErrInfo); + } + +Exit1: + pICreateErr->Release(); + if (pIErrInfo) { + pIErrInfo->Release(); + } + return hr; +} +#endif // FEATURE_COMINTEROP + +//***************************************************************************** +// This function will post an error for the client. If the LOWORD(hrRpt) can +// be found as a valid error message, then it is loaded and formatted with +// the arguments passed in. If it cannot be found, then the error is checked +// against FormatMessage to see if it is a system error. System errors are +// not formatted so no add'l parameters are required. If any errors in this +// process occur, hrRpt is returned for the client with no error posted. +//***************************************************************************** +extern "C" +HRESULT __cdecl PostErrorVA( // Returned error. + HRESULT hrRpt, // Reported error. + va_list marker) // Error arguments. +{ + CONTRACTL + { + NOTHROW; + GC_NOTRIGGER; + ENTRY_POINT; + } + CONTRACTL_END; + +#ifdef FEATURE_COMINTEROP + + const DWORD cchMsg = 4096; + WCHAR *rcMsg = (WCHAR*)alloca(cchMsg * sizeof(WCHAR)); // Error message. + HRESULT hr; + + BEGIN_ENTRYPOINT_NOTHROW; + + // Return warnings without text. + if (!FAILED(hrRpt)) + goto ErrExit; + + // If we are already out of memory or out of stack or the thread is in some bad state, + // we don't want throw gasoline on the fire by calling ErrorInfo stuff below (which can + // trigger a delayload of oleaut32.dll). We don't need to embellish transient errors + // so just return this without text. + if (Exception::IsTransient(hrRpt)) + { + goto ErrExit; + } + + // Format the error. + FormatRuntimeErrorVa(rcMsg, cchMsg, hrRpt, marker); + + // Turn the error into a posted error message. If this fails, we still + // return the original error message since a message caused by our error + // handling system isn't going to give you a clue about the original error. + hr = FillErrorInfo(rcMsg, LOWORD(hrRpt)); + _ASSERTE(hr == S_OK); + +ErrExit: + + END_ENTRYPOINT_NOTHROW; + +#endif // FEATURE_COMINTEROP + + return (hrRpt); +} // PostErrorVA + +#endif //!FEATURE_UTILCODE_NO_DEPENDENCIES + +//***************************************************************************** +// This function will post an error for the client. If the LOWORD(hrRpt) can +// be found as a valid error message, then it is loaded and formatted with +// the arguments passed in. If it cannot be found, then the error is checked +// against FormatMessage to see if it is a system error. System errors are +// not formatted so no add'l parameters are required. If any errors in this +// process occur, hrRpt is returned for the client with no error posted. +//***************************************************************************** +extern "C" +HRESULT __cdecl PostError( + HRESULT hrRpt, // Reported error. + ...) // Error arguments. +{ +#ifndef FEATURE_UTILCODE_NO_DEPENDENCIES + WRAPPER_NO_CONTRACT; + va_list marker; // User text. + va_start(marker, hrRpt); + hrRpt = PostErrorVA(hrRpt, marker); + va_end(marker); +#endif //!FEATURE_UTILCODE_NO_DEPENDENCIES + return hrRpt; +} |