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
27 #include "wine/debug.h"
29 WINE_DEFAULT_DEBUG_CHANNEL(msvcrt
);
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
)
64 if (table
->_first
== table
->_end
)
65 table
->_last
= table
->_end
= table
->_first
= NULL
;
69 static int register_onexit_function(_onexit_table_t
*table
, _onexit_t func
)
74 EnterCriticalSection(&MSVCRT_onexit_cs
);
77 table
->_first
= calloc(32, sizeof(void *));
80 WARN("failed to allocate initial table.\n");
81 LeaveCriticalSection(&MSVCRT_onexit_cs
);
84 table
->_last
= table
->_first
;
85 table
->_end
= table
->_first
+ 32;
89 if (table
->_last
== table
->_end
)
91 int len
= table
->_end
- table
->_first
;
92 _PVFV
*tmp
= realloc(table
->_first
, 2 * len
* sizeof(void *));
95 WARN("failed to grow table.\n");
96 LeaveCriticalSection(&MSVCRT_onexit_cs
);
100 table
->_end
= table
->_first
+ 2 * len
;
101 table
->_last
= table
->_first
+ len
;
104 *table
->_last
= (_PVFV
)func
;
106 LeaveCriticalSection(&MSVCRT_onexit_cs
);
110 static int execute_onexit_table(_onexit_table_t
*table
)
112 _onexit_table_t copy
;
118 EnterCriticalSection(&MSVCRT_onexit_cs
);
119 if (!table
->_first
|| table
->_first
>= table
->_last
)
121 LeaveCriticalSection(&MSVCRT_onexit_cs
);
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
--)
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
)
156 TRACE("(%p,%p,%p)\n", func
, start
, end
);
158 if (!start
|| !*start
|| !end
|| !*end
)
160 FIXME("bad table\n");
164 len
= (*end
- *start
);
166 TRACE("table start %p-%p, %d entries\n", *start
, *end
, len
);
171 tmp
= realloc(*start
, len
* sizeof(*tmp
));
177 TRACE("new table start %p-%p, %d entries\n", *start
, *end
, len
);
181 /*********************************************************************
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
;
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
);
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)))
238 sprintf(text
, "Error: R60%d",errnum
);
239 DoMessageBox("Runtime error!", text
);
242 _cprintf("\nruntime error R60%d\n",errnum
);
246 /*********************************************************************
249 void CDECL
abort(void)
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");
261 _cputs("\nabnormal program termination\n");
264 /* in case raise() returns */
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
);
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)))
296 _snwprintf(text
, sizeof(text
), L
"File: %ls\nLine: %d\n\nExpression: \"%ls\"", file
, line
, str
);
297 DoMessageBoxW(L
"Assertion failed!", text
);
300 fwprintf(MSVCRT_stderr
, L
"Assertion failed: %ls, file %ls, line %d\n\n", str
, file
, line
);
306 /*********************************************************************
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 /*********************************************************************
322 void CDECL
_c_exit(void)
325 /* All cleanup is done on DLL detach; Return to caller */
328 /*********************************************************************
331 void CDECL
_cexit(void)
339 /*********************************************************************
342 _onexit_t CDECL
_onexit(_onexit_t func
)
344 TRACE("(%p)\n",func
);
350 register_onexit_function(&MSVCRT_atexit_table
, func
);
356 /*********************************************************************
359 void CDECL
exit(int exitcode
)
362 void (WINAPI
*pCorExitProcess
)(int);
364 TRACE("(%d)\n",exitcode
);
367 hmscoree
= GetModuleHandleW(L
"mscoree");
371 pCorExitProcess
= (void*)GetProcAddress(hmscoree
, "CorExitProcess");
374 pCorExitProcess(exitcode
);
377 ExitProcess(exitcode
);
380 /*********************************************************************
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
);
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
);
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
;
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
;
476 /*********************************************************************
477 * _get_purecall_handler (MSVCR80.@)
479 _purecall_handler CDECL
_get_purecall_handler(void)
482 return purecall_handler
;
486 /*********************************************************************
487 * _purecall (MSVCRT.@)
489 void CDECL
_purecall(void)
498 /******************************************************************************
499 * _set_error_mode (MSVCRT.@)
501 * Set the error mode, which describes where the C run-time writes error messages.
504 * mode - the new error mode
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
;