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 #if _MSVCR_VER > 0 || defined(_DEBUG)
55 static unsigned int MSVCRT_abort_behavior
= _WRITE_ABORT_MSG
| _CALL_REPORTFAULT
;
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
)
67 if (table
->_first
== table
->_end
)
68 table
->_last
= table
->_end
= table
->_first
= NULL
;
72 static int register_onexit_function(_onexit_table_t
*table
, _onexit_t func
)
77 EnterCriticalSection(&MSVCRT_onexit_cs
);
80 table
->_first
= calloc(32, sizeof(void *));
83 WARN("failed to allocate initial table.\n");
84 LeaveCriticalSection(&MSVCRT_onexit_cs
);
87 table
->_last
= table
->_first
;
88 table
->_end
= table
->_first
+ 32;
92 if (table
->_last
== table
->_end
)
94 int len
= table
->_end
- table
->_first
;
95 _PVFV
*tmp
= realloc(table
->_first
, 2 * len
* sizeof(void *));
98 WARN("failed to grow table.\n");
99 LeaveCriticalSection(&MSVCRT_onexit_cs
);
103 table
->_end
= table
->_first
+ 2 * len
;
104 table
->_last
= table
->_first
+ len
;
107 *table
->_last
= (_PVFV
)func
;
109 LeaveCriticalSection(&MSVCRT_onexit_cs
);
113 static int execute_onexit_table(_onexit_table_t
*table
)
115 _onexit_table_t copy
;
121 EnterCriticalSection(&MSVCRT_onexit_cs
);
122 if (!table
->_first
|| table
->_first
>= table
->_last
)
124 LeaveCriticalSection(&MSVCRT_onexit_cs
);
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
--)
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
)
159 TRACE("(%p,%p,%p)\n", func
, start
, end
);
161 if (!start
|| !*start
|| !end
|| !*end
)
163 FIXME("bad table\n");
167 len
= (*end
- *start
);
169 TRACE("table start %p-%p, %d entries\n", *start
, *end
, len
);
174 tmp
= realloc(*start
, len
* sizeof(*tmp
));
180 TRACE("new table start %p-%p, %d entries\n", *start
, *end
, len
);
184 /*********************************************************************
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
;
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
);
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)))
241 sprintf(text
, "Error: R60%d",errnum
);
242 DoMessageBox("Runtime error!", text
);
245 _cprintf("\nruntime error R60%d\n",errnum
);
249 /*********************************************************************
252 void CDECL
abort(void)
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");
265 _cputs("\nabnormal program termination\n");
269 /* in case raise() returns */
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
);
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)))
301 _snwprintf(text
, sizeof(text
), L
"File: %ls\nLine: %d\n\nExpression: \"%ls\"", file
, line
, str
);
302 DoMessageBoxW(L
"Assertion failed!", text
);
305 fwprintf(stderr
, L
"Assertion failed: %ls, file %ls, line %d\n\n", str
, file
, line
);
311 /*********************************************************************
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 /*********************************************************************
327 void CDECL
_c_exit(void)
330 /* All cleanup is done on DLL detach; Return to caller */
333 /*********************************************************************
336 void CDECL
_cexit(void)
344 /*********************************************************************
347 _onexit_t CDECL
_onexit(_onexit_t func
)
349 TRACE("(%p)\n",func
);
355 register_onexit_function(&MSVCRT_atexit_table
, func
);
361 /*********************************************************************
364 void CDECL
exit(int exitcode
)
367 void (WINAPI
*pCorExitProcess
)(int);
369 TRACE("(%d)\n",exitcode
);
372 hmscoree
= GetModuleHandleW(L
"mscoree");
376 pCorExitProcess
= (void*)GetProcAddress(hmscoree
, "CorExitProcess");
379 pCorExitProcess(exitcode
);
382 ExitProcess(exitcode
);
385 /*********************************************************************
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
);
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
);
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
;
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
;
481 /*********************************************************************
482 * _get_purecall_handler (MSVCR80.@)
484 _purecall_handler CDECL
_get_purecall_handler(void)
487 return purecall_handler
;
491 /*********************************************************************
492 * _purecall (MSVCRT.@)
494 void CDECL
_purecall(void)
503 /******************************************************************************
504 * _set_error_mode (MSVCRT.@)
506 * Set the error mode, which describes where the C run-time writes error messages.
509 * mode - the new error mode
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
;