Release 6.15.
[wine.git] / dlls / msvcrt / exit.c
blob323d205b1bde0961afba8db4c97765d091a56625
1 /*
2 * msvcrt.dll exit functions
4 * Copyright 2000 Jon Griffiths
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
20 #include <conio.h>
21 #include <process.h>
22 #include <signal.h>
23 #include <stdio.h>
24 #include "msvcrt.h"
25 #include "mtdll.h"
26 #include "winuser.h"
27 #include "wine/debug.h"
29 WINE_DEFAULT_DEBUG_CHANNEL(msvcrt);
31 /* MT */
32 #define LOCK_EXIT _lock(_EXIT_LOCK1)
33 #define UNLOCK_EXIT _unlock(_EXIT_LOCK1)
35 static _purecall_handler purecall_handler = NULL;
37 static _onexit_table_t MSVCRT_atexit_table;
39 typedef void (__stdcall *_tls_callback_type)(void*,ULONG,void*);
40 static _tls_callback_type tls_atexit_callback;
42 static CRITICAL_SECTION MSVCRT_onexit_cs;
43 static CRITICAL_SECTION_DEBUG MSVCRT_onexit_cs_debug =
45 0, 0, &MSVCRT_onexit_cs,
46 { &MSVCRT_onexit_cs_debug.ProcessLocksList, &MSVCRT_onexit_cs_debug.ProcessLocksList },
47 0, 0, { (DWORD_PTR)(__FILE__ ": MSVCRT_onexit_cs") }
49 static CRITICAL_SECTION MSVCRT_onexit_cs = { &MSVCRT_onexit_cs_debug, -1, 0, 0, 0, 0 };
51 extern int MSVCRT_app_type;
52 extern wchar_t *MSVCRT__wpgmptr;
54 static unsigned int MSVCRT_abort_behavior = _WRITE_ABORT_MSG | _CALL_REPORTFAULT;
55 static int MSVCRT_error_mode = _OUT_TO_DEFAULT;
57 void (*CDECL _aexit_rtn)(int) = _exit;
59 static int initialize_onexit_table(_onexit_table_t *table)
61 if (!table)
62 return -1;
64 if (table->_first == table->_end)
65 table->_last = table->_end = table->_first = NULL;
66 return 0;
69 static int register_onexit_function(_onexit_table_t *table, _onexit_t func)
71 if (!table)
72 return -1;
74 EnterCriticalSection(&MSVCRT_onexit_cs);
75 if (!table->_first)
77 table->_first = calloc(32, sizeof(void *));
78 if (!table->_first)
80 WARN("failed to allocate initial table.\n");
81 LeaveCriticalSection(&MSVCRT_onexit_cs);
82 return -1;
84 table->_last = table->_first;
85 table->_end = table->_first + 32;
88 /* grow if full */
89 if (table->_last == table->_end)
91 int len = table->_end - table->_first;
92 _PVFV *tmp = realloc(table->_first, 2 * len * sizeof(void *));
93 if (!tmp)
95 WARN("failed to grow table.\n");
96 LeaveCriticalSection(&MSVCRT_onexit_cs);
97 return -1;
99 table->_first = tmp;
100 table->_end = table->_first + 2 * len;
101 table->_last = table->_first + len;
104 *table->_last = (_PVFV)func;
105 table->_last++;
106 LeaveCriticalSection(&MSVCRT_onexit_cs);
107 return 0;
110 static int execute_onexit_table(_onexit_table_t *table)
112 _onexit_table_t copy;
113 _PVFV *func;
115 if (!table)
116 return -1;
118 EnterCriticalSection(&MSVCRT_onexit_cs);
119 if (!table->_first || table->_first >= table->_last)
121 LeaveCriticalSection(&MSVCRT_onexit_cs);
122 return 0;
124 copy._first = table->_first;
125 copy._last = table->_last;
126 copy._end = table->_end;
127 memset(table, 0, sizeof(*table));
128 initialize_onexit_table(table);
129 LeaveCriticalSection(&MSVCRT_onexit_cs);
131 for (func = copy._last - 1; func >= copy._first; func--)
133 if (*func)
134 (*func)();
137 free(copy._first);
138 return 0;
141 static void call_atexit(void)
143 /* Note: should only be called with the exit lock held */
144 if (tls_atexit_callback) tls_atexit_callback(NULL, DLL_PROCESS_DETACH, NULL);
145 execute_onexit_table(&MSVCRT_atexit_table);
148 /*********************************************************************
149 * __dllonexit (MSVCRT.@)
151 _onexit_t CDECL __dllonexit(_onexit_t func, _onexit_t **start, _onexit_t **end)
153 _onexit_t *tmp;
154 int len;
156 TRACE("(%p,%p,%p)\n", func, start, end);
158 if (!start || !*start || !end || !*end)
160 FIXME("bad table\n");
161 return NULL;
164 len = (*end - *start);
166 TRACE("table start %p-%p, %d entries\n", *start, *end, len);
168 if (++len <= 0)
169 return NULL;
171 tmp = realloc(*start, len * sizeof(*tmp));
172 if (!tmp)
173 return NULL;
174 *start = tmp;
175 *end = tmp + len;
176 tmp[len - 1] = func;
177 TRACE("new table start %p-%p, %d entries\n", *start, *end, len);
178 return func;
181 /*********************************************************************
182 * _exit (MSVCRT.@)
184 void CDECL _exit(int exitcode)
186 TRACE("(%d)\n", exitcode);
187 ExitProcess(exitcode);
190 /* Print out an error message with an option to debug */
191 static void DoMessageBoxW(const wchar_t *lead, const wchar_t *message)
193 MSGBOXPARAMSW msgbox;
194 wchar_t text[2048];
195 INT ret;
197 _snwprintf(text, ARRAY_SIZE(text), L"%ls\n\nProgram: %ls\n%ls\n\n"
198 L"Press OK to exit the program, or Cancel to start the Wine debugger.\n",
199 lead, MSVCRT__wpgmptr, message);
201 msgbox.cbSize = sizeof(msgbox);
202 msgbox.hwndOwner = GetActiveWindow();
203 msgbox.hInstance = 0;
204 msgbox.lpszText = text;
205 msgbox.lpszCaption = L"Wine C++ Runtime Library";
206 msgbox.dwStyle = MB_OKCANCEL|MB_ICONERROR;
207 msgbox.lpszIcon = NULL;
208 msgbox.dwContextHelpId = 0;
209 msgbox.lpfnMsgBoxCallback = NULL;
210 msgbox.dwLanguageId = LANG_NEUTRAL;
212 ret = MessageBoxIndirectW(&msgbox);
213 if (ret == IDCANCEL)
214 DebugBreak();
217 static void DoMessageBox(const char *lead, const char *message)
219 wchar_t leadW[1024], messageW[1024];
221 mbstowcs(leadW, lead, 1024);
222 mbstowcs(messageW, message, 1024);
224 DoMessageBoxW(leadW, messageW);
227 /*********************************************************************
228 * _amsg_exit (MSVCRT.@)
230 void CDECL _amsg_exit(int errnum)
232 TRACE("(%d)\n", errnum);
234 if ((MSVCRT_error_mode == _OUT_TO_MSGBOX) ||
235 ((MSVCRT_error_mode == _OUT_TO_DEFAULT) && (MSVCRT_app_type == 2)))
237 char text[32];
238 sprintf(text, "Error: R60%d",errnum);
239 DoMessageBox("Runtime error!", text);
241 else
242 _cprintf("\nruntime error R60%d\n",errnum);
243 _aexit_rtn(255);
246 /*********************************************************************
247 * abort (MSVCRT.@)
249 void CDECL abort(void)
251 TRACE("()\n");
253 if (MSVCRT_abort_behavior & _WRITE_ABORT_MSG)
255 if ((MSVCRT_error_mode == _OUT_TO_MSGBOX) ||
256 ((MSVCRT_error_mode == _OUT_TO_DEFAULT) && (MSVCRT_app_type == 2)))
258 DoMessageBox("Runtime error!", "abnormal program termination");
260 else
261 _cputs("\nabnormal program termination\n");
263 raise(SIGABRT);
264 /* in case raise() returns */
265 _exit(3);
268 #if _MSVCR_VER>=80
269 /*********************************************************************
270 * _set_abort_behavior (MSVCR80.@)
272 unsigned int CDECL _set_abort_behavior(unsigned int flags, unsigned int mask)
274 unsigned int old = MSVCRT_abort_behavior;
276 TRACE("%x, %x\n", flags, mask);
277 if (mask & _CALL_REPORTFAULT)
278 FIXME("_WRITE_CALL_REPORTFAULT unhandled\n");
280 MSVCRT_abort_behavior = (MSVCRT_abort_behavior & ~mask) | (flags & mask);
281 return old;
283 #endif
285 /*********************************************************************
286 * _wassert (MSVCRT.@)
288 void CDECL _wassert(const wchar_t* str, const wchar_t* file, unsigned int line)
290 TRACE("(%s,%s,%d)\n", debugstr_w(str), debugstr_w(file), line);
292 if ((MSVCRT_error_mode == _OUT_TO_MSGBOX) ||
293 ((MSVCRT_error_mode == _OUT_TO_DEFAULT) && (MSVCRT_app_type == 2)))
295 wchar_t text[2048];
296 _snwprintf(text, sizeof(text), L"File: %ls\nLine: %d\n\nExpression: \"%ls\"", file, line, str);
297 DoMessageBoxW(L"Assertion failed!", text);
299 else
300 fwprintf(MSVCRT_stderr, L"Assertion failed: %ls, file %ls, line %d\n\n", str, file, line);
302 raise(SIGABRT);
303 _exit(3);
306 /*********************************************************************
307 * _assert (MSVCRT.@)
309 void CDECL _assert(const char* str, const char* file, unsigned int line)
311 wchar_t strW[1024], fileW[1024];
313 mbstowcs(strW, str, 1024);
314 mbstowcs(fileW, file, 1024);
316 _wassert(strW, fileW, line);
319 /*********************************************************************
320 * _c_exit (MSVCRT.@)
322 void CDECL _c_exit(void)
324 TRACE("(void)\n");
325 /* All cleanup is done on DLL detach; Return to caller */
328 /*********************************************************************
329 * _cexit (MSVCRT.@)
331 void CDECL _cexit(void)
333 TRACE("(void)\n");
334 LOCK_EXIT;
335 call_atexit();
336 UNLOCK_EXIT;
339 /*********************************************************************
340 * _onexit (MSVCRT.@)
342 _onexit_t CDECL _onexit(_onexit_t func)
344 TRACE("(%p)\n",func);
346 if (!func)
347 return NULL;
349 LOCK_EXIT;
350 register_onexit_function(&MSVCRT_atexit_table, func);
351 UNLOCK_EXIT;
353 return func;
356 /*********************************************************************
357 * exit (MSVCRT.@)
359 void CDECL exit(int exitcode)
361 HMODULE hmscoree;
362 void (WINAPI *pCorExitProcess)(int);
364 TRACE("(%d)\n",exitcode);
365 _cexit();
367 hmscoree = GetModuleHandleW(L"mscoree");
369 if (hmscoree)
371 pCorExitProcess = (void*)GetProcAddress(hmscoree, "CorExitProcess");
373 if (pCorExitProcess)
374 pCorExitProcess(exitcode);
377 ExitProcess(exitcode);
380 /*********************************************************************
381 * atexit (MSVCRT.@)
383 int CDECL MSVCRT_atexit(void (__cdecl *func)(void))
385 TRACE("(%p)\n", func);
386 return _onexit((_onexit_t)func) == (_onexit_t)func ? 0 : -1;
389 #if _MSVCR_VER >= 140
390 static _onexit_table_t MSVCRT_quick_exit_table;
392 /*********************************************************************
393 * _crt_at_quick_exit (UCRTBASE.@)
395 int CDECL _crt_at_quick_exit(void (__cdecl *func)(void))
397 TRACE("(%p)\n", func);
398 return register_onexit_function(&MSVCRT_quick_exit_table, (_onexit_t)func);
401 /*********************************************************************
402 * quick_exit (UCRTBASE.@)
404 void CDECL quick_exit(int exitcode)
406 TRACE("(%d)\n", exitcode);
408 execute_onexit_table(&MSVCRT_quick_exit_table);
409 _exit(exitcode);
412 /*********************************************************************
413 * _crt_atexit (UCRTBASE.@)
415 int CDECL _crt_atexit(void (__cdecl *func)(void))
417 TRACE("(%p)\n", func);
418 return _onexit((_onexit_t)func) == (_onexit_t)func ? 0 : -1;
421 /*********************************************************************
422 * _initialize_onexit_table (UCRTBASE.@)
424 int CDECL _initialize_onexit_table(_onexit_table_t *table)
426 TRACE("(%p)\n", table);
428 return initialize_onexit_table(table);
431 /*********************************************************************
432 * _register_onexit_function (UCRTBASE.@)
434 int CDECL _register_onexit_function(_onexit_table_t *table, _onexit_t func)
436 TRACE("(%p %p)\n", table, func);
438 return register_onexit_function(table, func);
441 /*********************************************************************
442 * _execute_onexit_table (UCRTBASE.@)
444 int CDECL _execute_onexit_table(_onexit_table_t *table)
446 TRACE("(%p)\n", table);
448 return execute_onexit_table(table);
450 #endif
452 /*********************************************************************
453 * _register_thread_local_exe_atexit_callback (UCRTBASE.@)
455 void CDECL _register_thread_local_exe_atexit_callback(_tls_callback_type callback)
457 TRACE("(%p)\n", callback);
458 tls_atexit_callback = callback;
461 #if _MSVCR_VER>=71
462 /*********************************************************************
463 * _set_purecall_handler (MSVCR71.@)
465 _purecall_handler CDECL _set_purecall_handler(_purecall_handler function)
467 _purecall_handler ret = purecall_handler;
469 TRACE("(%p)\n", function);
470 purecall_handler = function;
471 return ret;
473 #endif
475 #if _MSVCR_VER>=80
476 /*********************************************************************
477 * _get_purecall_handler (MSVCR80.@)
479 _purecall_handler CDECL _get_purecall_handler(void)
481 TRACE("\n");
482 return purecall_handler;
484 #endif
486 /*********************************************************************
487 * _purecall (MSVCRT.@)
489 void CDECL _purecall(void)
491 TRACE("(void)\n");
493 if(purecall_handler)
494 purecall_handler();
495 _amsg_exit( 25 );
498 /******************************************************************************
499 * _set_error_mode (MSVCRT.@)
501 * Set the error mode, which describes where the C run-time writes error messages.
503 * PARAMS
504 * mode - the new error mode
506 * RETURNS
507 * The old error mode.
510 int CDECL _set_error_mode(int mode)
513 const int old = MSVCRT_error_mode;
514 if ( _REPORT_ERRMODE != mode ) {
515 MSVCRT_error_mode = mode;
517 return old;