include/mscvpdb.h: Use flexible array members for the rest of structures.
[wine.git] / dlls / msvcrt / exit.c
blobc8db6c405da51f11d5dd91cd66f2b679026973e3
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 #if _MSVCR_VER > 0 || defined(_DEBUG)
55 static unsigned int MSVCRT_abort_behavior = _WRITE_ABORT_MSG | _CALL_REPORTFAULT;
56 #endif
58 static int MSVCRT_error_mode = _OUT_TO_DEFAULT;
60 void (*CDECL _aexit_rtn)(int) = _exit;
62 static int initialize_onexit_table(_onexit_table_t *table)
64 if (!table)
65 return -1;
67 if (table->_first == table->_end)
68 table->_last = table->_end = table->_first = NULL;
69 return 0;
72 static int register_onexit_function(_onexit_table_t *table, _onexit_t func)
74 if (!table)
75 return -1;
77 EnterCriticalSection(&MSVCRT_onexit_cs);
78 if (!table->_first)
80 table->_first = calloc(32, sizeof(void *));
81 if (!table->_first)
83 WARN("failed to allocate initial table.\n");
84 LeaveCriticalSection(&MSVCRT_onexit_cs);
85 return -1;
87 table->_last = table->_first;
88 table->_end = table->_first + 32;
91 /* grow if full */
92 if (table->_last == table->_end)
94 int len = table->_end - table->_first;
95 _PVFV *tmp = realloc(table->_first, 2 * len * sizeof(void *));
96 if (!tmp)
98 WARN("failed to grow table.\n");
99 LeaveCriticalSection(&MSVCRT_onexit_cs);
100 return -1;
102 table->_first = tmp;
103 table->_end = table->_first + 2 * len;
104 table->_last = table->_first + len;
107 *table->_last = (_PVFV)func;
108 table->_last++;
109 LeaveCriticalSection(&MSVCRT_onexit_cs);
110 return 0;
113 static int execute_onexit_table(_onexit_table_t *table)
115 _onexit_table_t copy;
116 _PVFV *func;
118 if (!table)
119 return -1;
121 EnterCriticalSection(&MSVCRT_onexit_cs);
122 if (!table->_first || table->_first >= table->_last)
124 LeaveCriticalSection(&MSVCRT_onexit_cs);
125 return 0;
127 copy._first = table->_first;
128 copy._last = table->_last;
129 copy._end = table->_end;
130 memset(table, 0, sizeof(*table));
131 initialize_onexit_table(table);
132 LeaveCriticalSection(&MSVCRT_onexit_cs);
134 for (func = copy._last - 1; func >= copy._first; func--)
136 if (*func)
137 (*func)();
140 free(copy._first);
141 return 0;
144 static void call_atexit(void)
146 /* Note: should only be called with the exit lock held */
147 if (tls_atexit_callback) tls_atexit_callback(NULL, DLL_PROCESS_DETACH, NULL);
148 execute_onexit_table(&MSVCRT_atexit_table);
151 /*********************************************************************
152 * __dllonexit (MSVCRT.@)
154 _onexit_t CDECL __dllonexit(_onexit_t func, _onexit_t **start, _onexit_t **end)
156 _onexit_t *tmp;
157 int len;
159 TRACE("(%p,%p,%p)\n", func, start, end);
161 if (!start || !*start || !end || !*end)
163 FIXME("bad table\n");
164 return NULL;
167 len = (*end - *start);
169 TRACE("table start %p-%p, %d entries\n", *start, *end, len);
171 if (++len <= 0)
172 return NULL;
174 tmp = realloc(*start, len * sizeof(*tmp));
175 if (!tmp)
176 return NULL;
177 *start = tmp;
178 *end = tmp + len;
179 tmp[len - 1] = func;
180 TRACE("new table start %p-%p, %d entries\n", *start, *end, len);
181 return func;
184 /*********************************************************************
185 * _exit (MSVCRT.@)
187 void CDECL _exit(int exitcode)
189 TRACE("(%d)\n", exitcode);
190 ExitProcess(exitcode);
193 /* Print out an error message with an option to debug */
194 static void DoMessageBoxW(const wchar_t *lead, const wchar_t *message)
196 MSGBOXPARAMSW msgbox;
197 wchar_t text[2048];
198 INT ret;
200 _snwprintf(text, ARRAY_SIZE(text), L"%ls\n\nProgram: %ls\n%ls\n\n"
201 L"Press OK to exit the program, or Cancel to start the Wine debugger.\n",
202 lead, MSVCRT__wpgmptr, message);
204 msgbox.cbSize = sizeof(msgbox);
205 msgbox.hwndOwner = GetActiveWindow();
206 msgbox.hInstance = 0;
207 msgbox.lpszText = text;
208 msgbox.lpszCaption = L"Wine C++ Runtime Library";
209 msgbox.dwStyle = MB_OKCANCEL|MB_ICONERROR;
210 msgbox.lpszIcon = NULL;
211 msgbox.dwContextHelpId = 0;
212 msgbox.lpfnMsgBoxCallback = NULL;
213 msgbox.dwLanguageId = LANG_NEUTRAL;
215 ret = MessageBoxIndirectW(&msgbox);
216 if (ret == IDCANCEL)
217 DebugBreak();
220 static void DoMessageBox(const char *lead, const char *message)
222 wchar_t leadW[1024], messageW[1024];
224 mbstowcs(leadW, lead, 1024);
225 mbstowcs(messageW, message, 1024);
227 DoMessageBoxW(leadW, messageW);
230 /*********************************************************************
231 * _amsg_exit (MSVCRT.@)
233 void CDECL _amsg_exit(int errnum)
235 TRACE("(%d)\n", errnum);
237 if ((MSVCRT_error_mode == _OUT_TO_MSGBOX) ||
238 ((MSVCRT_error_mode == _OUT_TO_DEFAULT) && (MSVCRT_app_type == 2)))
240 char text[32];
241 sprintf(text, "Error: R60%d",errnum);
242 DoMessageBox("Runtime error!", text);
244 else
245 _cprintf("\nruntime error R60%d\n",errnum);
246 _aexit_rtn(255);
249 /*********************************************************************
250 * abort (MSVCRT.@)
252 void CDECL abort(void)
254 TRACE("()\n");
256 #if (_MSVCR_VER > 0 && _MSVCR_VER < 100) || _MSVCR_VER == 120 || defined(_DEBUG)
257 if (MSVCRT_abort_behavior & _WRITE_ABORT_MSG)
259 if ((MSVCRT_error_mode == _OUT_TO_MSGBOX) ||
260 ((MSVCRT_error_mode == _OUT_TO_DEFAULT) && (MSVCRT_app_type == 2)))
262 DoMessageBox("Runtime error!", "abnormal program termination");
264 else
265 _cputs("\nabnormal program termination\n");
267 #endif
268 raise(SIGABRT);
269 /* in case raise() returns */
270 _exit(3);
273 #if _MSVCR_VER>=80
274 /*********************************************************************
275 * _set_abort_behavior (MSVCR80.@)
277 unsigned int CDECL _set_abort_behavior(unsigned int flags, unsigned int mask)
279 unsigned int old = MSVCRT_abort_behavior;
281 TRACE("%x, %x\n", flags, mask);
282 if (mask & _CALL_REPORTFAULT)
283 FIXME("_WRITE_CALL_REPORTFAULT unhandled\n");
285 MSVCRT_abort_behavior = (MSVCRT_abort_behavior & ~mask) | (flags & mask);
286 return old;
288 #endif
290 /*********************************************************************
291 * _wassert (MSVCRT.@)
293 void DECLSPEC_NORETURN CDECL _wassert(const wchar_t* str, const wchar_t* file, unsigned int line)
295 ERR("(%s,%s,%d)\n", debugstr_w(str), debugstr_w(file), line);
297 if ((MSVCRT_error_mode == _OUT_TO_MSGBOX) ||
298 ((MSVCRT_error_mode == _OUT_TO_DEFAULT) && (MSVCRT_app_type == 2)))
300 wchar_t text[2048];
301 _snwprintf(text, sizeof(text), L"File: %ls\nLine: %d\n\nExpression: \"%ls\"", file, line, str);
302 DoMessageBoxW(L"Assertion failed!", text);
304 else
305 fwprintf(stderr, L"Assertion failed: %ls, file %ls, line %d\n\n", str, file, line);
307 raise(SIGABRT);
308 _exit(3);
311 /*********************************************************************
312 * _assert (MSVCRT.@)
314 void DECLSPEC_NORETURN CDECL _assert(const char* str, const char* file, unsigned int line)
316 wchar_t strW[1024], fileW[1024];
318 mbstowcs(strW, str, 1024);
319 mbstowcs(fileW, file, 1024);
321 _wassert(strW, fileW, line);
324 /*********************************************************************
325 * _c_exit (MSVCRT.@)
327 void CDECL _c_exit(void)
329 TRACE("(void)\n");
330 /* All cleanup is done on DLL detach; Return to caller */
333 /*********************************************************************
334 * _cexit (MSVCRT.@)
336 void CDECL _cexit(void)
338 TRACE("(void)\n");
339 LOCK_EXIT;
340 call_atexit();
341 UNLOCK_EXIT;
344 /*********************************************************************
345 * _onexit (MSVCRT.@)
347 _onexit_t CDECL _onexit(_onexit_t func)
349 TRACE("(%p)\n",func);
351 if (!func)
352 return NULL;
354 LOCK_EXIT;
355 register_onexit_function(&MSVCRT_atexit_table, func);
356 UNLOCK_EXIT;
358 return func;
361 /*********************************************************************
362 * exit (MSVCRT.@)
364 void CDECL exit(int exitcode)
366 HMODULE hmscoree;
367 void (WINAPI *pCorExitProcess)(int);
369 TRACE("(%d)\n",exitcode);
370 _cexit();
372 hmscoree = GetModuleHandleW(L"mscoree");
374 if (hmscoree)
376 pCorExitProcess = (void*)GetProcAddress(hmscoree, "CorExitProcess");
378 if (pCorExitProcess)
379 pCorExitProcess(exitcode);
382 ExitProcess(exitcode);
385 /*********************************************************************
386 * atexit (MSVCRT.@)
388 int CDECL MSVCRT_atexit(void (__cdecl *func)(void))
390 TRACE("(%p)\n", func);
391 return _onexit((_onexit_t)func) == (_onexit_t)func ? 0 : -1;
394 #if _MSVCR_VER >= 140
395 static _onexit_table_t MSVCRT_quick_exit_table;
397 /*********************************************************************
398 * _crt_at_quick_exit (UCRTBASE.@)
400 int CDECL _crt_at_quick_exit(void (__cdecl *func)(void))
402 TRACE("(%p)\n", func);
403 return register_onexit_function(&MSVCRT_quick_exit_table, (_onexit_t)func);
406 /*********************************************************************
407 * quick_exit (UCRTBASE.@)
409 void CDECL quick_exit(int exitcode)
411 TRACE("(%d)\n", exitcode);
413 execute_onexit_table(&MSVCRT_quick_exit_table);
414 _exit(exitcode);
417 /*********************************************************************
418 * _crt_atexit (UCRTBASE.@)
420 int CDECL _crt_atexit(void (__cdecl *func)(void))
422 TRACE("(%p)\n", func);
423 return _onexit((_onexit_t)func) == (_onexit_t)func ? 0 : -1;
426 /*********************************************************************
427 * _initialize_onexit_table (UCRTBASE.@)
429 int CDECL _initialize_onexit_table(_onexit_table_t *table)
431 TRACE("(%p)\n", table);
433 return initialize_onexit_table(table);
436 /*********************************************************************
437 * _register_onexit_function (UCRTBASE.@)
439 int CDECL _register_onexit_function(_onexit_table_t *table, _onexit_t func)
441 TRACE("(%p %p)\n", table, func);
443 return register_onexit_function(table, func);
446 /*********************************************************************
447 * _execute_onexit_table (UCRTBASE.@)
449 int CDECL _execute_onexit_table(_onexit_table_t *table)
451 TRACE("(%p)\n", table);
453 return execute_onexit_table(table);
455 #endif
457 /*********************************************************************
458 * _register_thread_local_exe_atexit_callback (UCRTBASE.@)
460 void CDECL _register_thread_local_exe_atexit_callback(_tls_callback_type callback)
462 TRACE("(%p)\n", callback);
463 tls_atexit_callback = callback;
466 #if _MSVCR_VER>=71
467 /*********************************************************************
468 * _set_purecall_handler (MSVCR71.@)
470 _purecall_handler CDECL _set_purecall_handler(_purecall_handler function)
472 _purecall_handler ret = purecall_handler;
474 TRACE("(%p)\n", function);
475 purecall_handler = function;
476 return ret;
478 #endif
480 #if _MSVCR_VER>=80
481 /*********************************************************************
482 * _get_purecall_handler (MSVCR80.@)
484 _purecall_handler CDECL _get_purecall_handler(void)
486 TRACE("\n");
487 return purecall_handler;
489 #endif
491 /*********************************************************************
492 * _purecall (MSVCRT.@)
494 void CDECL _purecall(void)
496 TRACE("(void)\n");
498 if(purecall_handler)
499 purecall_handler();
500 _amsg_exit( 25 );
503 /******************************************************************************
504 * _set_error_mode (MSVCRT.@)
506 * Set the error mode, which describes where the C run-time writes error messages.
508 * PARAMS
509 * mode - the new error mode
511 * RETURNS
512 * The old error mode.
515 int CDECL _set_error_mode(int mode)
518 const int old = MSVCRT_error_mode;
519 if ( _REPORT_ERRMODE != mode ) {
520 MSVCRT_error_mode = mode;
522 return old;