2 // Copyright (c) Microsoft. All rights reserved.
3 // Licensed under the MIT license. See LICENSE file in the project root for full license information.
5 //*****************************************************************************
8 // This module contains the error handling/posting code for the engine. It
9 // is assumed that all methods may be called by a dispatch client, and therefore
10 // errors are always posted using IErrorInfo.
13 //*****************************************************************************
14 #include "stdafx.h" // Standard header.
16 #ifndef FEATURE_UTILCODE_NO_DEPENDENCIES
18 #include <utilcode.h> // Utility helpers.
20 #include "../dlls/mscorrc/resource.h"
23 #include <posterror.h>
25 #if !defined(lengthof)
26 #define lengthof(x) (sizeof(x)/sizeof(x[0]))
30 HRESULT FillErrorInfo(LPCWSTR szMsg, DWORD dwHelpContext);
32 //*****************************************************************************
33 // Function that we'll expose to the outside world to fire off the shutdown method
34 //*****************************************************************************
35 #ifdef SHOULD_WE_CLEANUP
38 CCompRC::ShutdownDefaultResourceDll();
40 #endif /* SHOULD_WE_CLEANUP */
42 void GetResourceCultureCallbacks(
43 FPGETTHREADUICULTURENAMES* fpGetThreadUICultureNames,
44 FPGETTHREADUICULTUREID* fpGetThreadUICultureId)
47 CCompRC::GetDefaultCallbacks(
48 fpGetThreadUICultureNames,
49 fpGetThreadUICultureId
52 //*****************************************************************************
53 // Set callbacks to get culture info
54 //*****************************************************************************
55 void SetResourceCultureCallbacks(
56 FPGETTHREADUICULTURENAMES fpGetThreadUICultureNames,
57 FPGETTHREADUICULTUREID fpGetThreadUICultureId // TODO: Don't rely on the LCID, only the name
61 CCompRC::SetDefaultCallbacks(
62 fpGetThreadUICultureNames,
63 fpGetThreadUICultureId
68 //*****************************************************************************
69 // Public function to load a resource string
70 //*****************************************************************************
71 STDAPI UtilLoadStringRC(
73 __out_ecount(iMax) LPWSTR szBuffer,
79 return UtilLoadResourceString(bQuiet? CCompRC::Optional : CCompRC::Required,iResourceID, szBuffer, iMax);
82 HRESULT UtilLoadResourceString(CCompRC::ResourceCategory eCategory, UINT iResourceID, __out_ecount (iMax) LPWSTR szBuffer, int iMax)
92 HRESULT retVal = E_OUTOFMEMORY;
94 BEGIN_SO_INTOLERANT_CODE_NO_THROW_CHECK_THREAD(return COR_E_STACKOVERFLOW);
98 CCompRC *pResourceDLL = CCompRC::GetDefaultResourceDll();
100 if (pResourceDLL != NULL)
102 retVal = pResourceDLL->LoadString(eCategory, iResourceID, szBuffer, iMax);
107 // Catch any errors and return E_OUTOFMEMORY;
108 retVal = E_OUTOFMEMORY;
110 EX_END_CATCH(SwallowAllExceptions);
112 END_SO_INTOLERANT_CODE;
117 #ifdef FEATURE_USE_LCID
118 STDAPI UtilLoadStringRCEx(
121 __out_ecount(iMax) LPWSTR szBuffer,
135 HRESULT retVal = E_OUTOFMEMORY;
137 BEGIN_SO_INTOLERANT_CODE_NO_THROW_CHECK_THREAD(return COR_E_STACKOVERFLOW);
141 CCompRC *pResourceDLL = CCompRC::GetDefaultResourceDll();
143 if (pResourceDLL != NULL)
145 retVal = pResourceDLL->LoadString(bQuiet? CCompRC::Optional : CCompRC::Required,lcid, iResourceID, szBuffer, iMax, pcwchUsed);
150 // Catch any errors and return E_OUTOFMEMORY;
151 retVal = E_OUTOFMEMORY;
153 EX_END_CATCH(SwallowAllExceptions);
154 END_SO_INTOLERANT_CODE;
158 #endif //FEATURE_USE_LCID
160 //*****************************************************************************
161 // Format a Runtime Error message.
162 //*****************************************************************************
163 HRESULT __cdecl FormatRuntimeErrorVa(
164 __inout_ecount(cchMsg) WCHAR *rcMsg, // Buffer into which to format.
165 ULONG cchMsg, // Size of buffer, characters.
166 HRESULT hrRpt, // The HR to report.
167 va_list marker) // Optional args.
176 WCHAR rcBuf[512]; // Resource string.
179 // Ensure nul termination.
182 // If this is one of our errors or if it is simply a resource ID, then grab the error from the rc file.
183 if ((HRESULT_FACILITY(hrRpt) == FACILITY_URT) || (HIWORD(hrRpt) == 0))
185 hr = UtilLoadStringRC(LOWORD(hrRpt), rcBuf, NumItems(rcBuf), true);
188 _vsnwprintf_s(rcMsg, cchMsg, _TRUNCATE, rcBuf, marker);
191 // Otherwise it isn't one of ours, so we need to see if the system can
192 // find the text for it.
195 #ifdef FEATURE_USE_LCID
196 if (WszFormatMessage(FORMAT_MESSAGE_FROM_SYSTEM,
197 0, hrRpt, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
198 rcMsg, cchMsg, 0/*<TODO>@todo: marker</TODO>*/))
200 if (WszFormatMessage(FORMAT_MESSAGE_FROM_SYSTEM,
202 rcMsg, cchMsg, 0/*<TODO>@todo: marker</TODO>*/))
207 // System messages contain a trailing \r\n, which we don't want normally.
208 size_t iLen = wcslen(rcMsg);
209 if (iLen > 3 && rcMsg[iLen - 2] == '\r' && rcMsg[iLen - 1] == '\n')
210 rcMsg[iLen - 2] = '\0';
213 hr = HRESULT_FROM_GetLastError();
216 // If we failed to find the message anywhere, then issue a hard coded message.
219 _snwprintf_s(rcMsg, cchMsg, _TRUNCATE, W("Common Language Runtime Internal error: 0x%08x"), hrRpt);
220 DEBUG_STMT(DbgWriteEx(rcMsg));
224 } // FormatRuntimeErrorVa
226 //*****************************************************************************
227 // Format a Runtime Error message, varargs.
228 //*****************************************************************************
229 HRESULT __cdecl FormatRuntimeError(
230 __out_ecount(cchMsg) WCHAR *rcMsg, // Buffer into which to format.
231 ULONG cchMsg, // Size of buffer, characters.
232 HRESULT hrRpt, // The HR to report.
233 ...) // Optional args.
236 va_list marker; // User text.
237 va_start(marker, hrRpt);
238 hrRpt = FormatRuntimeErrorVa(rcMsg, cchMsg, hrRpt, marker);
243 #ifdef FEATURE_COMINTEROP
244 //*****************************************************************************
245 // Create, fill out and set an error info object. Note that this does not fill
246 // out the IID for the error object; that is done elsewhere.
247 //*****************************************************************************
248 HRESULT FillErrorInfo( // Return status.
249 LPCWSTR szMsg, // Error message.
250 DWORD dwHelpContext) // Help context.
259 ICreateErrorInfo *pICreateErr = NULL; // Error info creation Iface pointer.
260 IErrorInfo *pIErrInfo = NULL; // The IErrorInfo interface.
261 HRESULT hr; // Return status.
263 // Get the ICreateErrorInfo pointer.
267 hr = CreateErrorInfo(&pICreateErr);
271 hr = GET_EXCEPTION()->GetHR();
273 EX_END_CATCH(SwallowAllExceptions);
278 // Set message text description.
279 if (FAILED(hr = pICreateErr->SetDescription((LPWSTR) szMsg)))
282 // suppress PreFast warning about passing literal string to non-const API.
283 // This API (ICreateErrorInfo::SetHelpFile) is documented to take a const argument, but
284 // we can't put const in the signature because it would break existing implementors of
287 #pragma prefast(push)
288 #pragma warning(disable:6298)
291 // Set the help file and help context.
292 //<TODO>@todo: we don't have a help file yet.</TODO>
293 if (FAILED(hr = pICreateErr->SetHelpFile(const_cast<wchar_t*>(W("complib.hlp")))) ||
294 FAILED(hr = pICreateErr->SetHelpContext(dwHelpContext)))
301 // Get the IErrorInfo pointer.
302 if (FAILED(hr = pICreateErr->QueryInterface(IID_IErrorInfo, (PVOID *) &pIErrInfo)))
305 // Save the error and release our local pointers.
307 // If we get here, we have loaded oleaut32.dll.
308 CONTRACT_VIOLATION(ThrowsViolation);
309 SetErrorInfo(0L, pIErrInfo);
313 pICreateErr->Release();
315 pIErrInfo->Release();
319 #endif // FEATURE_COMINTEROP
321 //*****************************************************************************
322 // This function will post an error for the client. If the LOWORD(hrRpt) can
323 // be found as a valid error message, then it is loaded and formatted with
324 // the arguments passed in. If it cannot be found, then the error is checked
325 // against FormatMessage to see if it is a system error. System errors are
326 // not formatted so no add'l parameters are required. If any errors in this
327 // process occur, hrRpt is returned for the client with no error posted.
328 //*****************************************************************************
330 HRESULT __cdecl PostErrorVA( // Returned error.
331 HRESULT hrRpt, // Reported error.
332 va_list marker) // Error arguments.
342 #ifdef FEATURE_COMINTEROP
344 const DWORD cchMsg = 4096;
345 WCHAR *rcMsg = (WCHAR*)alloca(cchMsg * sizeof(WCHAR)); // Error message.
348 BEGIN_ENTRYPOINT_NOTHROW;
350 // Return warnings without text.
354 // If we are already out of memory or out of stack or the thread is in some bad state,
355 // we don't want throw gasoline on the fire by calling ErrorInfo stuff below (which can
356 // trigger a delayload of oleaut32.dll). We don't need to embellish transient errors
357 // so just return this without text.
358 if (Exception::IsTransient(hrRpt))
364 FormatRuntimeErrorVa(rcMsg, cchMsg, hrRpt, marker);
366 // Turn the error into a posted error message. If this fails, we still
367 // return the original error message since a message caused by our error
368 // handling system isn't going to give you a clue about the original error.
369 hr = FillErrorInfo(rcMsg, LOWORD(hrRpt));
370 _ASSERTE(hr == S_OK);
374 END_ENTRYPOINT_NOTHROW;
376 #endif // FEATURE_COMINTEROP
381 #endif //!FEATURE_UTILCODE_NO_DEPENDENCIES
383 //*****************************************************************************
384 // This function will post an error for the client. If the LOWORD(hrRpt) can
385 // be found as a valid error message, then it is loaded and formatted with
386 // the arguments passed in. If it cannot be found, then the error is checked
387 // against FormatMessage to see if it is a system error. System errors are
388 // not formatted so no add'l parameters are required. If any errors in this
389 // process occur, hrRpt is returned for the client with no error posted.
390 //*****************************************************************************
392 HRESULT __cdecl PostError(
393 HRESULT hrRpt, // Reported error.
394 ...) // Error arguments.
396 #ifndef FEATURE_UTILCODE_NO_DEPENDENCIES
398 va_list marker; // User text.
399 va_start(marker, hrRpt);
400 hrRpt = PostErrorVA(hrRpt, marker);
402 #endif //!FEATURE_UTILCODE_NO_DEPENDENCIES