Remove always defined FEATURE_CORECLR
[platform/upstream/coreclr.git] / src / utilcode / utilmessagebox.cpp
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 //*****************************************************************************
5 // UtilMessageBox.cpp
6 //
7
8 //
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.
13 //
14 //*****************************************************************************
15 #include "stdafx.h"                     // Standard header.
16 #include <utilcode.h>                   // Utility helpers.
17 #include <corerror.h>
18 #include "ndpversion.h"
19 #include "../dlls/mscorrc/resource.h"
20 #include "ex.h"
21
22
23 BOOL ShouldDisplayMsgBoxOnCriticalFailure()
24 {
25     CONTRACTL
26     {
27         NOTHROW;
28     }
29     CONTRACTL_END;
30
31 #ifdef _DEBUG
32     // To help find issues, we will always display dialogs for critical failures
33     // under debug builds. This includes asserts and other critical issues.
34    return TRUE;
35 #else      
36     // Retrieve error mode
37     UINT last = SetErrorMode(0);
38     SetErrorMode(last);         //set back to previous value
39                     
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);
43 #endif // _DEBUG
44 }
45
46
47
48
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.  
55 int MessageBoxImpl(
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.
60                   UINT uType)
61 {
62     CONTRACTL
63     {
64         // May pump messages.  Callers should be GC_TRIGGERS and MODE_PREEMPTIVE,
65         // but we can't include EE contracts here.
66         THROWS;
67         INJECT_FAULT(return IDCANCEL;);
68
69         // Assert if none of MB_ICON is set
70         PRECONDITION((uType & MB_ICONMASK) != 0);
71     }
72     CONTRACTL_END;
73
74     return WszMessageBox(hWnd, message, title, uType);
75 }
76
77 int UtilMessageBoxVA(
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
85 {
86     CONTRACTL
87     {
88         NOTHROW;
89         INJECT_FAULT(return IDCANCEL;);
90     }
91     CONTRACTL_END;
92
93     SString text;
94     SString title; 
95     int result = IDCANCEL;
96     
97     EX_TRY
98     {
99         text.LoadResource(CCompRC::Error, uText);
100         title.LoadResource(CCompRC::Error, uTitle);
101
102         result = UtilMessageBoxNonLocalizedVA(hWnd, (LPWSTR)text.GetUnicode(), 
103             (LPWSTR)title.GetUnicode(), uType, displayForNonInteractive, showFileNameInTitle, NULL, args);
104     }
105     EX_CATCH
106     {
107         result = IDCANCEL;
108     }
109     EX_END_CATCH(SwallowAllExceptions);
110
111     return result;            
112 }
113
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
123 {
124     CONTRACTL
125     {
126         NOTHROW;
127         INJECT_FAULT(return IDCANCEL;);
128
129         // Assert if none of MB_ICON is set
130         PRECONDITION((uType & MB_ICONMASK) != 0);
131     }
132     CONTRACTL_END;
133
134     return UtilMessageBoxNonLocalizedVA(hWnd, lpText, lpTitle, NULL, uType, displayForNonInteractive, showFileNameInTitle, pInputFromUser, args);
135 }
136
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
147 {
148     CONTRACTL
149     {
150         NOTHROW;
151         INJECT_FAULT(return IDCANCEL;);
152
153         // Assert if none of MB_ICON is set
154         PRECONDITION((uType & MB_ICONMASK) != 0);
155     }
156     CONTRACTL_END;
157
158     int result = IDCANCEL;
159         if (pInputFromUser != NULL)
160         {
161         *pInputFromUser = FALSE;
162         }
163
164     EX_TRY
165     {   
166         StackSString formattedMessage;
167         StackSString formattedTitle;
168         SString details(lpDetails);
169         PathString fileName;
170         BOOL fDisplayMsgBox = TRUE;
171         
172         // Format message string using optional parameters
173         formattedMessage.VPrintf(lpText, args);
174        
175         // Try to get filename of Module and add it to title
176         if (showFileNameInTitle && WszGetModuleFileName(NULL, fileName))
177         {           
178             LPCWSTR wszName = NULL;
179             size_t cchName = 0;
180
181                   
182             
183             SplitPathInterior(fileName, NULL, NULL, NULL, NULL, &wszName, &cchName, NULL, NULL);
184             formattedTitle.Printf(W("%s - %s"), wszName, lpTitle);
185         }
186         else
187         {
188             formattedTitle.Set(lpTitle);
189         }
190
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. 
194         // 
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())
198         {
199             HANDLE h;
200             StackSString message;
201
202             message.Printf(W(".NET Runtime version : %s - "), VER_FILEVERSION_STR_L);
203             if (lpTitle)
204                 message.Append(lpTitle);
205             if (!formattedMessage.IsEmpty())
206                 message.Append(formattedMessage);
207
208             ClrReportEvent(W(".NET Runtime"),
209                 EVENTLOG_ERROR_TYPE,    // event type 
210                 0,                      // category zero
211                 1024,                   // event identifier
212                 NULL,                   // no user security identifier
213                 message.GetUnicode());
214             
215             if(lpTitle != NULL)
216                 WszOutputDebugString(lpTitle);
217             if(!formattedMessage.IsEmpty())
218                 WszOutputDebugString(formattedMessage);
219
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)   
225             {
226                 fDisplayMsgBox = FALSE;
227                 result = IDABORT;
228             }
229             else
230             {
231                 // Include in the MB_DEFAULT_DESKTOP_ONLY style.
232                 uType |= MB_DEFAULT_DESKTOP_ONLY;                            
233             }
234         }
235 #endif //!defined(FEATURE_UTILCODE_NO_DEPENDENCIES)
236
237         if (fDisplayMsgBox)
238         {
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.
243             
244             result = MessageBoxImpl(hWnd, formattedMessage, formattedTitle, details, uType);
245             
246             if (pInputFromUser != NULL)
247             {
248                 *pInputFromUser = TRUE;
249             }
250         }
251     }        
252     EX_CATCH
253     {
254         result = IDCANCEL;
255     }
256     EX_END_CATCH(SwallowAllExceptions);
257
258     return result;
259 }
260
261 int UtilMessageBox(
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
269 {
270     CONTRACTL
271     {
272         NOTHROW;
273     }
274     CONTRACTL_END;
275
276     va_list marker;
277     va_start(marker, showFileNameInTitle);
278
279     int result = UtilMessageBoxVA(hWnd, uText, uTitle, uType, displayForNonInteractive, showFileNameInTitle, marker);
280     va_end( marker );
281
282     return result;    
283 }
284
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
293 {
294     CONTRACTL
295     {
296         NOTHROW;
297     }
298     CONTRACTL_END;
299
300     va_list marker;
301     va_start(marker, showFileNameInTitle);
302
303     int result = UtilMessageBoxNonLocalizedVA(
304         hWnd, lpText, lpTitle, uType, displayForNonInteractive, showFileNameInTitle, NULL, marker);
305     va_end( marker );
306
307     return result;
308 }
309
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
315                   ...)
316 {
317     CONTRACTL
318     {
319         NOTHROW;
320     }
321     CONTRACTL_END;
322
323     va_list marker;
324     va_start(marker, showFileNameInTitle);
325
326     int result = UtilMessageBoxCatastrophicVA(uText, uTitle, uType, showFileNameInTitle, marker);
327     va_end( marker );
328
329     return result;
330 }
331
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
337                   ...)
338 {
339     CONTRACTL
340     {
341         NOTHROW;
342     }
343     CONTRACTL_END;
344
345     va_list marker;
346     va_start(marker, showFileNameInTitle);
347
348     int result = UtilMessageBoxCatastrophicNonLocalizedVA(lpText, lpTitle, uType, showFileNameInTitle, marker);
349     va_end( marker );
350
351     return result;
352 }
353
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
360 {
361     CONTRACTL
362     {
363         NOTHROW;
364     }
365     CONTRACTL_END;
366
367     HWND hwnd = NULL;
368
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);
371
372     if (!ShouldDisplayMsgBoxOnCriticalFailure())
373         return IDABORT;
374
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;
378
379     return UtilMessageBoxVA(hwnd, uText, uTitle, uType, TRUE, showFileNameInTitle, args);
380 }
381
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
388 {
389     CONTRACTL
390     {
391         NOTHROW;
392     }
393     CONTRACTL_END;
394
395     HWND hwnd = NULL;
396
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);
399
400     if (!ShouldDisplayMsgBoxOnCriticalFailure())
401         return IDABORT;
402
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;
406
407     return UtilMessageBoxNonLocalizedVA(hwnd, lpText, lpTitle, uType, TRUE, showFileNameInTitle, NULL, args);
408 }
409