1 // Licensed to the .NET Foundation under one or more agreements.
2 // The .NET Foundation licenses this file to you under the MIT license.
3 // See the LICENSE file in the project root for more information.
4 //*****************************************************************************
9 // This module contains the message box utility code for the CLR. It is used
10 // by code in the CLR itself as well as other tools that build in the CLR tree.
11 // For message boxes inside the ExecutionEngine, EEMessageBox must be used
12 // instead of the these APIs.
14 //*****************************************************************************
15 #include "stdafx.h" // Standard header.
16 #include <utilcode.h> // Utility helpers.
18 #include "ndpversion.h"
19 #include "../dlls/mscorrc/resource.h"
23 BOOL ShouldDisplayMsgBoxOnCriticalFailure()
32 // To help find issues, we will always display dialogs for critical failures
33 // under debug builds. This includes asserts and other critical issues.
36 // Retrieve error mode
37 UINT last = SetErrorMode(0);
38 SetErrorMode(last); //set back to previous value
40 // SEM_FAILCRITICALERRORS indicates that the system does not display the critical-error-handler
41 // message box. Instead, the system sends the error to the calling process.
42 return !(last & SEM_FAILCRITICALERRORS);
49 // We'd like to use TaskDialogIndirect for asserts coming from managed code in particular
50 // to display the detailedText in a scrollable way. Also, we'd like to reuse the CLR's
51 // plumbing code for the rest of parts of the assert dialog. Note that the simple
52 // Win32 MessageBox does not support the detailedText value.
53 // If we later refactor MessageBoxImpl into its own DLL, move the lines referencing
54 // "Microsoft.Windows.Common-Controls" version 6 in stdafx.h as well.
56 HWND hWnd, // Handle to Owner Window
57 LPCWSTR message, // Message
58 LPCWSTR title, // Dialog box title
59 LPCWSTR detailedText, // Details like a stack trace, etc.
64 // May pump messages. Callers should be GC_TRIGGERS and MODE_PREEMPTIVE,
65 // but we can't include EE contracts here.
67 INJECT_FAULT(return IDCANCEL;);
69 // Assert if none of MB_ICON is set
70 PRECONDITION((uType & MB_ICONMASK) != 0);
74 return WszMessageBox(hWnd, message, title, uType);
78 HWND hWnd, // Handle to Owner Window
79 UINT uText, // Resource Identifier for Text message
80 UINT uTitle, // Resource Identifier for Title
81 UINT uType, // Style of MessageBox
82 BOOL displayForNonInteractive, // Display even if the process is running non interactive
83 BOOL showFileNameInTitle, // Flag to show FileName in Caption
84 va_list args) // Additional Arguments
89 INJECT_FAULT(return IDCANCEL;);
95 int result = IDCANCEL;
99 text.LoadResource(CCompRC::Error, uText);
100 title.LoadResource(CCompRC::Error, uTitle);
102 result = UtilMessageBoxNonLocalizedVA(hWnd, (LPWSTR)text.GetUnicode(),
103 (LPWSTR)title.GetUnicode(), uType, displayForNonInteractive, showFileNameInTitle, NULL, args);
109 EX_END_CATCH(SwallowAllExceptions);
114 int UtilMessageBoxNonLocalizedVA(
115 HWND hWnd, // Handle to Owner Window
116 LPCWSTR lpText, // Text message
117 LPCWSTR lpTitle, // Title
118 UINT uType, // Style of MessageBox
119 BOOL displayForNonInteractive, // Display even if the process is running non interactive
120 BOOL showFileNameInTitle, // Flag to show FileName in Caption
121 BOOL * pInputFromUser, // To distinguish between user pressing abort vs. assuming abort.
122 va_list args) // Additional Arguments
127 INJECT_FAULT(return IDCANCEL;);
129 // Assert if none of MB_ICON is set
130 PRECONDITION((uType & MB_ICONMASK) != 0);
134 return UtilMessageBoxNonLocalizedVA(hWnd, lpText, lpTitle, NULL, uType, displayForNonInteractive, showFileNameInTitle, pInputFromUser, args);
137 int UtilMessageBoxNonLocalizedVA(
138 HWND hWnd, // Handle to Owner Window
139 LPCWSTR lpText, // Text message
140 LPCWSTR lpTitle, // Title
141 LPCWSTR lpDetails,// Details like a stack trace, etc.
142 UINT uType, // Style of MessageBox
143 BOOL displayForNonInteractive, // Display even if the process is running non interactive
144 BOOL showFileNameInTitle, // Flag to show FileName in Caption
145 BOOL * pInputFromUser, // To distinguish between user pressing abort vs. assuming abort.
146 va_list args) // Additional Arguments
151 INJECT_FAULT(return IDCANCEL;);
153 // Assert if none of MB_ICON is set
154 PRECONDITION((uType & MB_ICONMASK) != 0);
158 int result = IDCANCEL;
159 if (pInputFromUser != NULL)
161 *pInputFromUser = FALSE;
166 StackSString formattedMessage;
167 StackSString formattedTitle;
168 SString details(lpDetails);
170 BOOL fDisplayMsgBox = TRUE;
172 // Format message string using optional parameters
173 formattedMessage.VPrintf(lpText, args);
175 // Try to get filename of Module and add it to title
176 if (showFileNameInTitle && WszGetModuleFileName(NULL, fileName))
178 LPCWSTR wszName = NULL;
183 SplitPathInterior(fileName, NULL, NULL, NULL, NULL, &wszName, &cchName, NULL, NULL);
184 formattedTitle.Printf(W("%s - %s"), wszName, lpTitle);
188 formattedTitle.Set(lpTitle);
191 #if !defined(FEATURE_UTILCODE_NO_DEPENDENCIES)
192 // If the current process isn't interactive (a service for example), then we report the message
193 // in the event log and via OutputDebugString.
195 // We may still however attempt to display the message box if the MB_SERVICE_NOTIFICATION
196 // message box style was specified.
197 if (!RunningInteractive())
200 StackSString message;
202 message.Printf(W(".NET Runtime version : %s - "), VER_FILEVERSION_STR_L);
204 message.Append(lpTitle);
205 if (!formattedMessage.IsEmpty())
206 message.Append(formattedMessage);
208 ClrReportEvent(W(".NET Runtime"),
209 EVENTLOG_ERROR_TYPE, // event type
211 1024, // event identifier
212 NULL, // no user security identifier
213 message.GetUnicode());
216 WszOutputDebugString(lpTitle);
217 if(!formattedMessage.IsEmpty())
218 WszOutputDebugString(formattedMessage);
220 // If we are running as a service and displayForNonInteractive is FALSE then IDABORT is
221 // the best value to return as it will most likely cause callers of this API to abort the process.
222 // This is the right thing to do since attaching a debugger doesn't make much sense when the process isn't
223 // running in interactive mode.
224 if(!displayForNonInteractive)
226 fDisplayMsgBox = FALSE;
231 // Include in the MB_DEFAULT_DESKTOP_ONLY style.
232 uType |= MB_DEFAULT_DESKTOP_ONLY;
235 #endif //!defined(FEATURE_UTILCODE_NO_DEPENDENCIES)
239 // We normally want to set the reading direction (right-to-left etc.) based on the resources
240 // in use. However, outside the CLR (SELF_NO_HOST) we can't assume we have resources and
241 // in CORECLR we can't even necessarily expect that our CLR callbacks have been initialized.
242 // This code path is used for ASSERT dialogs.
244 result = MessageBoxImpl(hWnd, formattedMessage, formattedTitle, details, uType);
246 if (pInputFromUser != NULL)
248 *pInputFromUser = TRUE;
256 EX_END_CATCH(SwallowAllExceptions);
262 HWND hWnd, // Handle to Owner Window
263 UINT uText, // Resource Identifier for Text message
264 UINT uTitle, // Resource Identifier for Title
265 UINT uType, // Style of MessageBox
266 BOOL displayForNonInteractive, // Display even if the process is running non interactive
267 BOOL showFileNameInTitle, // Flag to show FileName in Caption
268 ...) // Additional Arguments
277 va_start(marker, showFileNameInTitle);
279 int result = UtilMessageBoxVA(hWnd, uText, uTitle, uType, displayForNonInteractive, showFileNameInTitle, marker);
285 int UtilMessageBoxNonLocalized(
286 HWND hWnd, // Handle to Owner Window
287 LPCWSTR lpText, // Text message
288 LPCWSTR lpTitle, // Title message
289 UINT uType, // Style of MessageBox
290 BOOL displayForNonInteractive, // Display even if the process is running non interactive
291 BOOL showFileNameInTitle, // Flag to show FileName in Caption
292 ... ) // Additional Arguments
301 va_start(marker, showFileNameInTitle);
303 int result = UtilMessageBoxNonLocalizedVA(
304 hWnd, lpText, lpTitle, uType, displayForNonInteractive, showFileNameInTitle, NULL, marker);
310 int UtilMessageBoxCatastrophic(
311 UINT uText, // Text for MessageBox
312 UINT uTitle, // Title for MessageBox
313 UINT uType, // Style of MessageBox
314 BOOL showFileNameInTitle, // Flag to show FileName in Caption
324 va_start(marker, showFileNameInTitle);
326 int result = UtilMessageBoxCatastrophicVA(uText, uTitle, uType, showFileNameInTitle, marker);
332 int UtilMessageBoxCatastrophicNonLocalized(
333 LPCWSTR lpText, // Text for MessageBox
334 LPCWSTR lpTitle, // Title for MessageBox
335 UINT uType, // Style of MessageBox
336 BOOL showFileNameInTitle, // Flag to show FileName in Caption
346 va_start(marker, showFileNameInTitle);
348 int result = UtilMessageBoxCatastrophicNonLocalizedVA(lpText, lpTitle, uType, showFileNameInTitle, marker);
354 int UtilMessageBoxCatastrophicVA(
355 UINT uText, // Text for MessageBox
356 UINT uTitle, // Title for MessageBox
357 UINT uType, // Style of MessageBox
358 BOOL showFileNameInTitle, // Flag to show FileName in Caption
359 va_list args) // Additional Arguments
369 // We are already in a catastrophic situation so we can tolerate faults as well as SO & GC mode violations to keep going.
370 CONTRACT_VIOLATION(FaultNotFatal | GCViolation | ModeViolation | SOToleranceViolation);
372 if (!ShouldDisplayMsgBoxOnCriticalFailure())
375 // Add the MB_TASKMODAL style to indicate that the dialog should be displayed on top of the windows
376 // owned by the current thread and should prevent interaction with them until dismissed.
377 uType |= MB_TASKMODAL;
379 return UtilMessageBoxVA(hwnd, uText, uTitle, uType, TRUE, showFileNameInTitle, args);
382 int UtilMessageBoxCatastrophicNonLocalizedVA(
383 LPCWSTR lpText, // Text for MessageBox
384 LPCWSTR lpTitle, // Title for MessageBox
385 UINT uType, // Style of MessageBox
386 BOOL showFileNameInTitle, // Flag to show FileName in Caption
387 va_list args) // Additional Arguments
397 // We are already in a catastrophic situation so we can tolerate faults as well as SO & GC mode violations to keep going.
398 CONTRACT_VIOLATION(FaultNotFatal | GCViolation | ModeViolation | SOToleranceViolation);
400 if (!ShouldDisplayMsgBoxOnCriticalFailure())
403 // Add the MB_TASKMODAL style to indicate that the dialog should be displayed on top of the windows
404 // owned by the current thread and should prevent interaction with them until dismissed.
405 uType |= MB_TASKMODAL;
407 return UtilMessageBoxNonLocalizedVA(hwnd, lpText, lpTitle, uType, TRUE, showFileNameInTitle, NULL, args);