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"
21 #if !defined(FEATURE_CORESYSTEM)
23 #define NTDDI_VERSION NTDDI_WIN7
28 BOOL ShouldDisplayMsgBoxOnCriticalFailure()
37 // To help find issues, we will always display dialogs for critical failures
38 // under debug builds. This includes asserts and other critical issues.
41 // Retrieve error mode
42 UINT last = SetErrorMode(0);
43 SetErrorMode(last); //set back to previous value
45 // SEM_FAILCRITICALERRORS indicates that the system does not display the critical-error-handler
46 // message box. Instead, the system sends the error to the calling process.
47 return !(last & SEM_FAILCRITICALERRORS);
54 // We'd like to use TaskDialogIndirect for asserts coming from managed code in particular
55 // to display the detailedText in a scrollable way. Also, we'd like to reuse the CLR's
56 // plumbing code for the rest of parts of the assert dialog. Note that the simple
57 // Win32 MessageBox does not support the detailedText value.
58 // If we later refactor MessageBoxImpl into its own DLL, move the lines referencing
59 // "Microsoft.Windows.Common-Controls" version 6 in stdafx.h as well.
61 HWND hWnd, // Handle to Owner Window
62 LPCWSTR message, // Message
63 LPCWSTR title, // Dialog box title
64 LPCWSTR detailedText, // Details like a stack trace, etc.
69 // May pump messages. Callers should be GC_TRIGGERS and MODE_PREEMPTIVE,
70 // but we can't include EE contracts here.
72 INJECT_FAULT(return IDCANCEL;);
74 // Assert if none of MB_ICON is set
75 PRECONDITION((uType & MB_ICONMASK) != 0);
79 return WszMessageBox(hWnd, message, title, uType);
83 HWND hWnd, // Handle to Owner Window
84 UINT uText, // Resource Identifier for Text message
85 UINT uTitle, // Resource Identifier for Title
86 UINT uType, // Style of MessageBox
87 BOOL displayForNonInteractive, // Display even if the process is running non interactive
88 BOOL showFileNameInTitle, // Flag to show FileName in Caption
89 va_list args) // Additional Arguments
94 INJECT_FAULT(return IDCANCEL;);
100 int result = IDCANCEL;
104 text.LoadResource(CCompRC::Error, uText);
105 title.LoadResource(CCompRC::Error, uTitle);
107 result = UtilMessageBoxNonLocalizedVA(hWnd, (LPWSTR)text.GetUnicode(),
108 (LPWSTR)title.GetUnicode(), uType, displayForNonInteractive, showFileNameInTitle, NULL, args);
114 EX_END_CATCH(SwallowAllExceptions);
119 int UtilMessageBoxNonLocalizedVA(
120 HWND hWnd, // Handle to Owner Window
121 LPCWSTR lpText, // Text message
122 LPCWSTR lpTitle, // Title
123 UINT uType, // Style of MessageBox
124 BOOL displayForNonInteractive, // Display even if the process is running non interactive
125 BOOL showFileNameInTitle, // Flag to show FileName in Caption
126 BOOL * pInputFromUser, // To distinguish between user pressing abort vs. assuming abort.
127 va_list args) // Additional Arguments
132 INJECT_FAULT(return IDCANCEL;);
134 // Assert if none of MB_ICON is set
135 PRECONDITION((uType & MB_ICONMASK) != 0);
139 return UtilMessageBoxNonLocalizedVA(hWnd, lpText, lpTitle, NULL, uType, displayForNonInteractive, showFileNameInTitle, pInputFromUser, args);
142 int UtilMessageBoxNonLocalizedVA(
143 HWND hWnd, // Handle to Owner Window
144 LPCWSTR lpText, // Text message
145 LPCWSTR lpTitle, // Title
146 LPCWSTR lpDetails,// Details like a stack trace, etc.
147 UINT uType, // Style of MessageBox
148 BOOL displayForNonInteractive, // Display even if the process is running non interactive
149 BOOL showFileNameInTitle, // Flag to show FileName in Caption
150 BOOL * pInputFromUser, // To distinguish between user pressing abort vs. assuming abort.
151 va_list args) // Additional Arguments
156 INJECT_FAULT(return IDCANCEL;);
158 // Assert if none of MB_ICON is set
159 PRECONDITION((uType & MB_ICONMASK) != 0);
163 int result = IDCANCEL;
164 if (pInputFromUser != NULL)
166 *pInputFromUser = FALSE;
171 StackSString formattedMessage;
172 StackSString formattedTitle;
173 SString details(lpDetails);
175 BOOL fDisplayMsgBox = TRUE;
177 // Format message string using optional parameters
178 formattedMessage.VPrintf(lpText, args);
180 // Try to get filename of Module and add it to title
181 if (showFileNameInTitle && WszGetModuleFileName(NULL, fileName))
183 LPCWSTR wszName = NULL;
188 SplitPathInterior(fileName, NULL, NULL, NULL, NULL, &wszName, &cchName, NULL, NULL);
189 formattedTitle.Printf(W("%s - %s"), wszName, lpTitle);
193 formattedTitle.Set(lpTitle);
196 #if !defined(FEATURE_UTILCODE_NO_DEPENDENCIES)
197 // If the current process isn't interactive (a service for example), then we report the message
198 // in the event log and via OutputDebugString.
200 // We may still however attempt to display the message box if the MB_SERVICE_NOTIFICATION
201 // message box style was specified.
202 if (!RunningInteractive())
204 StackSString message;
206 message.Printf(W(".NET Runtime version : %s - "), VER_FILEVERSION_STR_L);
208 message.Append(lpTitle);
209 if (!formattedMessage.IsEmpty())
210 message.Append(formattedMessage);
212 ClrReportEvent(W(".NET Runtime"),
213 EVENTLOG_ERROR_TYPE, // event type
215 1024, // event identifier
216 NULL, // no user security identifier
217 message.GetUnicode());
220 WszOutputDebugString(lpTitle);
221 if(!formattedMessage.IsEmpty())
222 WszOutputDebugString(formattedMessage);
224 // If we are running as a service and displayForNonInteractive is FALSE then IDABORT is
225 // the best value to return as it will most likely cause callers of this API to abort the process.
226 // This is the right thing to do since attaching a debugger doesn't make much sense when the process isn't
227 // running in interactive mode.
228 if(!displayForNonInteractive)
230 fDisplayMsgBox = FALSE;
235 // Include in the MB_DEFAULT_DESKTOP_ONLY style.
236 uType |= MB_DEFAULT_DESKTOP_ONLY;
239 #endif //!defined(FEATURE_UTILCODE_NO_DEPENDENCIES)
243 // We normally want to set the reading direction (right-to-left etc.) based on the resources
244 // in use. However, outside the CLR (SELF_NO_HOST) we can't assume we have resources and
245 // in CORECLR we can't even necessarily expect that our CLR callbacks have been initialized.
246 // This code path is used for ASSERT dialogs.
248 result = MessageBoxImpl(hWnd, formattedMessage, formattedTitle, details, uType);
250 if (pInputFromUser != NULL)
252 *pInputFromUser = TRUE;
260 EX_END_CATCH(SwallowAllExceptions);
266 HWND hWnd, // Handle to Owner Window
267 UINT uText, // Resource Identifier for Text message
268 UINT uTitle, // Resource Identifier for Title
269 UINT uType, // Style of MessageBox
270 BOOL displayForNonInteractive, // Display even if the process is running non interactive
271 BOOL showFileNameInTitle, // Flag to show FileName in Caption
272 ...) // Additional Arguments
281 va_start(marker, showFileNameInTitle);
283 int result = UtilMessageBoxVA(hWnd, uText, uTitle, uType, displayForNonInteractive, showFileNameInTitle, marker);
289 int UtilMessageBoxNonLocalized(
290 HWND hWnd, // Handle to Owner Window
291 LPCWSTR lpText, // Text message
292 LPCWSTR lpTitle, // Title message
293 UINT uType, // Style of MessageBox
294 BOOL displayForNonInteractive, // Display even if the process is running non interactive
295 BOOL showFileNameInTitle, // Flag to show FileName in Caption
296 ... ) // Additional Arguments
305 va_start(marker, showFileNameInTitle);
307 int result = UtilMessageBoxNonLocalizedVA(
308 hWnd, lpText, lpTitle, uType, displayForNonInteractive, showFileNameInTitle, NULL, marker);
314 int UtilMessageBoxCatastrophic(
315 UINT uText, // Text for MessageBox
316 UINT uTitle, // Title for MessageBox
317 UINT uType, // Style of MessageBox
318 BOOL showFileNameInTitle, // Flag to show FileName in Caption
328 va_start(marker, showFileNameInTitle);
330 int result = UtilMessageBoxCatastrophicVA(uText, uTitle, uType, showFileNameInTitle, marker);
336 int UtilMessageBoxCatastrophicNonLocalized(
337 LPCWSTR lpText, // Text for MessageBox
338 LPCWSTR lpTitle, // Title for MessageBox
339 UINT uType, // Style of MessageBox
340 BOOL showFileNameInTitle, // Flag to show FileName in Caption
350 va_start(marker, showFileNameInTitle);
352 int result = UtilMessageBoxCatastrophicNonLocalizedVA(lpText, lpTitle, uType, showFileNameInTitle, marker);
358 int UtilMessageBoxCatastrophicVA(
359 UINT uText, // Text for MessageBox
360 UINT uTitle, // Title for MessageBox
361 UINT uType, // Style of MessageBox
362 BOOL showFileNameInTitle, // Flag to show FileName in Caption
363 va_list args) // Additional Arguments
373 // We are already in a catastrophic situation so we can tolerate faults as well as GC mode violations to keep going.
374 CONTRACT_VIOLATION(FaultNotFatal | GCViolation | ModeViolation);
376 if (!ShouldDisplayMsgBoxOnCriticalFailure())
379 // Add the MB_TASKMODAL style to indicate that the dialog should be displayed on top of the windows
380 // owned by the current thread and should prevent interaction with them until dismissed.
381 uType |= MB_TASKMODAL;
383 return UtilMessageBoxVA(hwnd, uText, uTitle, uType, TRUE, showFileNameInTitle, args);
386 int UtilMessageBoxCatastrophicNonLocalizedVA(
387 LPCWSTR lpText, // Text for MessageBox
388 LPCWSTR lpTitle, // Title for MessageBox
389 UINT uType, // Style of MessageBox
390 BOOL showFileNameInTitle, // Flag to show FileName in Caption
391 va_list args) // Additional Arguments
401 // We are already in a catastrophic situation so we can tolerate faults as well as GC mode violations to keep going.
402 CONTRACT_VIOLATION(FaultNotFatal | GCViolation | ModeViolation);
404 if (!ShouldDisplayMsgBoxOnCriticalFailure())
407 // Add the MB_TASKMODAL style to indicate that the dialog should be displayed on top of the windows
408 // owned by the current thread and should prevent interaction with them until dismissed.
409 uType |= MB_TASKMODAL;
411 return UtilMessageBoxNonLocalizedVA(hwnd, lpText, lpTitle, uType, TRUE, showFileNameInTitle, NULL, args);