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/*++
6
7
8
9Module Name:
10
11 msgbox.c
12
13Abstract:
14
15 Implementation of Message Box.
16
17
18
19--*/
20
21#include "pal/palinternal.h"
22#include "pal/critsect.h"
23#include "pal/dbgmsg.h"
24#include "pal/misc.h"
25
26#include <syslog.h>
27
28SET_DEFAULT_DEBUG_CHANNEL(MISC);
29
30CRITICAL_SECTION msgbox_critsec;
31
32
33/*++
34Function :
35 MsgBoxInitialize
36
37 Initialize the critical sections.
38
39Return value:
40 TRUE if initialize succeeded
41 FALSE otherwise
42
43--*/
44BOOL
45MsgBoxInitialize( void )
46{
47 TRACE( "Initialising the critical section.\n" );
48 InternalInitializeCriticalSection(&msgbox_critsec);
49
50 return TRUE;
51}
52
53/*++
54Function :
55 MsgBoxCleanup
56
57 Deletes the critical sections.
58
59--*/
60void MsgBoxCleanup( void )
61{
62 TRACE( "Deleting the critical section.\n" );
63 DeleteCriticalSection( &msgbox_critsec );
64}
65
66
67
68#ifdef __APPLE__
69#include "CoreFoundation/CFUserNotification.h"
70#include "CoreFoundation/CFString.h"
71#include "Security/AuthSession.h"
72#endif // __APPLE__
73
74
75/*++
76Function:
77 MessageBoxW
78
79This is a small subset of MessageBox that simply logs a message to the
80system logging facility and returns. A typical log entry will look
81like:
82
83May 23 15:48:10 rice example1: MessageBox: Caption: Error Text
84
85Note:
86 hWnd should always be NULL.
87
88See MSDN doc.
89--*/
90int
91PALAPI
92MessageBoxW(
93 IN LPVOID hWnd,
94 IN LPCWSTR lpText,
95 IN LPCWSTR lpCaption,
96 IN UINT uType)
97{
98 CHAR *text = NULL;
99 CHAR *caption = NULL;
100 INT len = 0;
101 INT rc = 0;
102
103 PERF_ENTRY(MessageBoxW);
104 ENTRY( "MessageBoxW (hWnd=%p, lpText=%p (%S), lpCaption=%p (%S), uType=%#x)\n",
105 hWnd, lpText?lpText:W16_NULLSTRING, lpText?lpText:W16_NULLSTRING,
106 lpCaption?lpCaption:W16_NULLSTRING,
107 lpCaption?lpCaption:W16_NULLSTRING, uType );
108
109 if (hWnd != NULL)
110 {
111 ASSERT("hWnd != NULL");
112 }
113
114 if(lpText)
115 {
116 len = WideCharToMultiByte(CP_ACP, 0, lpText, -1, NULL, 0, NULL, NULL);
117 if(len)
118 {
119 text = (LPSTR)PAL_malloc(len);
120 if(!text)
121 {
122 ERROR("malloc() failed!\n");
123 SetLastError( ERROR_NOT_ENOUGH_MEMORY );
124 goto error;
125 }
126 if( !WideCharToMultiByte( CP_ACP, 0, lpText, -1, text, len,
127 NULL, NULL))
128 {
129 ASSERT("WideCharToMultiByte failure\n");
130 SetLastError( ERROR_INTERNAL_ERROR );
131 goto error;
132 }
133 }
134 else
135 {
136 ASSERT("WideCharToMultiByte failure\n");
137 SetLastError( ERROR_INTERNAL_ERROR );
138 goto error;
139 }
140 }
141 else
142 {
143 WARN("No message text\n");
144
145 if (NULL == (text = PAL__strdup("(no message text)")))
146 {
147 ASSERT("strdup() failed\n");
148 SetLastError( ERROR_INTERNAL_ERROR );
149 goto error;
150 }
151 }
152 if (lpCaption)
153 {
154 len = WideCharToMultiByte( CP_ACP, 0, lpCaption, -1, NULL, 0,
155 NULL, NULL);
156 if(len)
157 {
158 caption = (CHAR*)PAL_malloc(len);
159 if(!caption)
160 {
161 ERROR("malloc() failed!\n");
162 SetLastError( ERROR_NOT_ENOUGH_MEMORY );
163 goto error;
164 }
165 if( !WideCharToMultiByte( CP_ACP, 0, lpCaption, -1, caption, len,
166 NULL, NULL))
167 {
168 ASSERT("WideCharToMultiByte failure\n");
169 SetLastError( ERROR_INTERNAL_ERROR );
170 goto error;
171 }
172 }
173 else
174 {
175 ASSERT("WideCharToMultiByte failure\n");
176 SetLastError( ERROR_INTERNAL_ERROR );
177 goto error;
178 }
179 }
180 else
181 {
182 if (NULL == (caption = PAL__strdup("Error")))
183 {
184 ERROR("strdup() failed\n");
185 SetLastError( ERROR_NOT_ENOUGH_MEMORY );
186 goto error;
187 }
188 }
189
190 rc = MessageBoxA(hWnd, text, caption, uType);
191
192error:
193 PAL_free(caption);
194 PAL_free(text);
195
196
197 LOGEXIT("MessageBoxW returns %d\n", rc);
198 PERF_EXIT(MessageBoxW);
199 return rc;
200}
201
202
203/*++
204Function:
205 MessageBoxA
206
207This is a small subset of MessageBox that simply logs a message to the
208system logging facility and returns. A typical log entry will look
209like:
210
211May 23 15:48:10 rice example1: MessageBox: Caption: Error Text
212
213Note:
214 hWnd should always be NULL.
215
216See MSDN doc.
217--*/
218int
219PALAPI
220MessageBoxA(
221 IN LPVOID hWnd,
222 IN LPCSTR lpText,
223 IN LPCSTR lpCaption,
224 IN UINT uType)
225{
226 INT rc = 0;
227
228 PERF_ENTRY(MessageBoxA);
229 ENTRY( "MessageBoxA (hWnd=%p, lpText=%p (%s), lpCaption=%p (%s), uType=%#x)\n",
230 hWnd, lpText?lpText:"NULL", lpText?lpText:"NULL",
231 lpCaption?lpCaption:"NULL",
232 lpCaption?lpCaption:"NULL", uType );
233
234 if (hWnd != NULL)
235 {
236 ASSERT("hWnd != NULL");
237 }
238
239 if (lpText == NULL)
240 {
241 WARN("No message text\n");
242
243 lpText = "(no message text)";
244 }
245
246 if (lpCaption == NULL)
247 {
248 lpCaption = "Error";
249 }
250
251 if (uType & MB_DEFMASK)
252 {
253 WARN("No support for alternate default buttons.\n");
254 }
255
256 /* set default status based on the type of button */
257 switch(uType & MB_TYPEMASK)
258 {
259 case MB_OK:
260 rc = IDOK;
261 break;
262
263 case MB_ABORTRETRYIGNORE:
264 rc = IDABORT;
265 break;
266
267 case MB_YESNO:
268 rc = IDNO;
269 break;
270
271 case MB_OKCANCEL :
272 rc = IDCANCEL;
273 break;
274
275 case MB_RETRYCANCEL :
276 rc = IDCANCEL;
277 break;
278
279 default:
280 ASSERT("Bad uType");
281 rc = IDOK;
282 break;
283 }
284
285 PALCEnterCriticalSection( &msgbox_critsec);
286
287#ifdef __APPLE__
288 OSStatus osstatus;
289
290 SecuritySessionId secSession;
291 SessionAttributeBits secSessionInfo;
292
293 osstatus = SessionGetInfo(callerSecuritySession, &secSession, &secSessionInfo);
294 if (noErr == osstatus && (secSessionInfo & sessionHasGraphicAccess) != 0)
295 {
296 CFStringRef cfsTitle = CFStringCreateWithCString(kCFAllocatorDefault, lpCaption, kCFStringEncodingUTF8);
297 CFStringRef cfsText = CFStringCreateWithCString(kCFAllocatorDefault, lpText, kCFStringEncodingUTF8);
298 CFStringRef cfsButton1 = NULL;
299 CFStringRef cfsButton2 = NULL;
300 CFStringRef cfsButton3 = NULL;
301 CFOptionFlags alertFlags = 0;
302 CFOptionFlags response;
303
304 switch (uType & MB_TYPEMASK)
305 {
306 case MB_OK:
307 // Nothing needed; since if all the buttons are null, a stock "OK" is used.
308 break;
309
310 case MB_ABORTRETRYIGNORE:
311 // Localization? Would be needed if this were used outside of debugging.
312 cfsButton1 = CFSTR("Abort");
313 cfsButton2 = CFSTR("Retry");
314 cfsButton3 = CFSTR("Ignore");
315 alertFlags = kCFUserNotificationCautionAlertLevel;
316 break;
317
318 case MB_YESNO:
319 cfsButton1 = CFSTR("Yes");
320 cfsButton2 = CFSTR("No");
321 break;
322
323 case MB_OKCANCEL:
324 cfsButton1 = CFSTR("OK");
325 cfsButton2 = CFSTR("Cancel");
326 break;
327
328 case MB_RETRYCANCEL:
329 cfsButton1 = CFSTR("Retry");
330 cfsButton2 = CFSTR("Cancel");
331 break;
332 }
333
334 CFUserNotificationDisplayAlert(0 /* no time out */, alertFlags, NULL /* iconURL */,
335 NULL /* soundURL */, NULL /* localizationURL */, cfsTitle, cfsText, cfsButton1,
336 cfsButton2, cfsButton3, &response);
337
338 switch (uType & MB_TYPEMASK)
339 {
340 case MB_OK:
341 break;
342
343 case MB_ABORTRETRYIGNORE:
344 switch (response)
345 {
346 case kCFUserNotificationDefaultResponse:
347 rc = IDABORT;
348 break;
349 case kCFUserNotificationAlternateResponse:
350 rc = IDRETRY;
351 break;
352 case kCFUserNotificationOtherResponse:
353 rc = IDIGNORE;
354 break;
355 }
356 break;
357
358 case MB_YESNO:
359 switch (response)
360 {
361 case kCFUserNotificationDefaultResponse:
362 rc = IDYES;
363 break;
364 case kCFUserNotificationAlternateResponse:
365 rc = IDNO;
366 break;
367 }
368 break;
369
370 case MB_OKCANCEL:
371 switch (response)
372 {
373 case kCFUserNotificationDefaultResponse:
374 rc = IDOK;
375 break;
376 case kCFUserNotificationAlternateResponse:
377 rc = IDCANCEL;
378 break;
379 }
380 break;
381
382 case MB_RETRYCANCEL:
383 switch (response)
384 {
385 case kCFUserNotificationDefaultResponse:
386 rc = IDRETRY;
387 break;
388 case kCFUserNotificationAlternateResponse:
389 rc = IDCANCEL;
390 break;
391 }
392 break;
393 }
394 }
395 else
396 {
397 // We're not in a login session, e.g., running via ssh, and so bringing
398 // up a message box would be bad form.
399 fprintf ( stderr, "MessageBox: %s: %s", lpCaption, lpText );
400 syslog(LOG_USER|LOG_ERR, "MessageBox: %s: %s", lpCaption, lpText);
401 }
402#else // __APPLE__
403 fprintf ( stderr, "MessageBox: %s: %s", lpCaption, lpText );
404 syslog(LOG_USER|LOG_ERR, "MessageBox: %s: %s", lpCaption, lpText);
405
406 // Some systems support displaying a GUI dialog. (This will suspend the current thread until they hit the
407 // 'OK' button and allow a debugger to be attached).
408 PAL_DisplayDialog(lpCaption, lpText);
409#endif // __APPLE__ else
410
411 PALCLeaveCriticalSection( &msgbox_critsec);
412
413 LOGEXIT("MessageBoxA returns %d\n", rc);
414 PERF_EXIT(MessageBoxA);
415 return rc;
416}
417