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())
205 StackSString message;
207 message.Printf(W(".NET Runtime version : %s - "), VER_FILEVERSION_STR_L);
209 message.Append(lpTitle);
210 if (!formattedMessage.IsEmpty())
211 message.Append(formattedMessage);
213 ClrReportEvent(W(".NET Runtime"),
214 EVENTLOG_ERROR_TYPE, // event type
216 1024, // event identifier
217 NULL, // no user security identifier
218 message.GetUnicode());
221 WszOutputDebugString(lpTitle);
222 if(!formattedMessage.IsEmpty())
223 WszOutputDebugString(formattedMessage);
225 // If we are running as a service and displayForNonInteractive is FALSE then IDABORT is
226 // the best value to return as it will most likely cause callers of this API to abort the process.
227 // This is the right thing to do since attaching a debugger doesn't make much sense when the process isn't
228 // running in interactive mode.
229 if(!displayForNonInteractive)
231 fDisplayMsgBox = FALSE;
236 // Include in the MB_DEFAULT_DESKTOP_ONLY style.
237 uType |= MB_DEFAULT_DESKTOP_ONLY;
240 #endif //!defined(FEATURE_UTILCODE_NO_DEPENDENCIES)
244 // We normally want to set the reading direction (right-to-left etc.) based on the resources
245 // in use. However, outside the CLR (SELF_NO_HOST) we can't assume we have resources and
246 // in CORECLR we can't even necessarily expect that our CLR callbacks have been initialized.
247 // This code path is used for ASSERT dialogs.
249 result = MessageBoxImpl(hWnd, formattedMessage, formattedTitle, details, uType);
251 if (pInputFromUser != NULL)
253 *pInputFromUser = TRUE;
261 EX_END_CATCH(SwallowAllExceptions);
267 HWND hWnd, // Handle to Owner Window
268 UINT uText, // Resource Identifier for Text message
269 UINT uTitle, // Resource Identifier for Title
270 UINT uType, // Style of MessageBox
271 BOOL displayForNonInteractive, // Display even if the process is running non interactive
272 BOOL showFileNameInTitle, // Flag to show FileName in Caption
273 ...) // Additional Arguments
282 va_start(marker, showFileNameInTitle);
284 int result = UtilMessageBoxVA(hWnd, uText, uTitle, uType, displayForNonInteractive, showFileNameInTitle, marker);
290 int UtilMessageBoxNonLocalized(
291 HWND hWnd, // Handle to Owner Window
292 LPCWSTR lpText, // Text message
293 LPCWSTR lpTitle, // Title message
294 UINT uType, // Style of MessageBox
295 BOOL displayForNonInteractive, // Display even if the process is running non interactive
296 BOOL showFileNameInTitle, // Flag to show FileName in Caption
297 ... ) // Additional Arguments
306 va_start(marker, showFileNameInTitle);
308 int result = UtilMessageBoxNonLocalizedVA(
309 hWnd, lpText, lpTitle, uType, displayForNonInteractive, showFileNameInTitle, NULL, marker);
315 int UtilMessageBoxCatastrophic(
316 UINT uText, // Text for MessageBox
317 UINT uTitle, // Title for MessageBox
318 UINT uType, // Style of MessageBox
319 BOOL showFileNameInTitle, // Flag to show FileName in Caption
329 va_start(marker, showFileNameInTitle);
331 int result = UtilMessageBoxCatastrophicVA(uText, uTitle, uType, showFileNameInTitle, marker);
337 int UtilMessageBoxCatastrophicNonLocalized(
338 LPCWSTR lpText, // Text for MessageBox
339 LPCWSTR lpTitle, // Title for MessageBox
340 UINT uType, // Style of MessageBox
341 BOOL showFileNameInTitle, // Flag to show FileName in Caption
351 va_start(marker, showFileNameInTitle);
353 int result = UtilMessageBoxCatastrophicNonLocalizedVA(lpText, lpTitle, uType, showFileNameInTitle, marker);
359 int UtilMessageBoxCatastrophicVA(
360 UINT uText, // Text for MessageBox
361 UINT uTitle, // Title for MessageBox
362 UINT uType, // Style of MessageBox
363 BOOL showFileNameInTitle, // Flag to show FileName in Caption
364 va_list args) // Additional Arguments
374 // We are already in a catastrophic situation so we can tolerate faults as well as SO & GC mode violations to keep going.
375 CONTRACT_VIOLATION(FaultNotFatal | GCViolation | ModeViolation | SOToleranceViolation);
377 if (!ShouldDisplayMsgBoxOnCriticalFailure())
380 // Add the MB_TASKMODAL style to indicate that the dialog should be displayed on top of the windows
381 // owned by the current thread and should prevent interaction with them until dismissed.
382 uType |= MB_TASKMODAL;
384 return UtilMessageBoxVA(hwnd, uText, uTitle, uType, TRUE, showFileNameInTitle, args);
387 int UtilMessageBoxCatastrophicNonLocalizedVA(
388 LPCWSTR lpText, // Text for MessageBox
389 LPCWSTR lpTitle, // Title for MessageBox
390 UINT uType, // Style of MessageBox
391 BOOL showFileNameInTitle, // Flag to show FileName in Caption
392 va_list args) // Additional Arguments
402 // We are already in a catastrophic situation so we can tolerate faults as well as SO & GC mode violations to keep going.
403 CONTRACT_VIOLATION(FaultNotFatal | GCViolation | ModeViolation | SOToleranceViolation);
405 if (!ShouldDisplayMsgBoxOnCriticalFailure())
408 // Add the MB_TASKMODAL style to indicate that the dialog should be displayed on top of the windows
409 // owned by the current thread and should prevent interaction with them until dismissed.
410 uType |= MB_TASKMODAL;
412 return UtilMessageBoxNonLocalizedVA(hwnd, lpText, lpTitle, uType, TRUE, showFileNameInTitle, NULL, args);