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
24 #include "wine/debug.h"
26 WINE_DEFAULT_DEBUG_CHANNEL(msvcrt);
29 #define LOCK_EXIT _mlock(_EXIT_LOCK1)
30 #define UNLOCK_EXIT _munlock(_EXIT_LOCK1)
32 static MSVCRT__onexit_t *MSVCRT_atexit_table = NULL;
33 static int MSVCRT_atexit_table_size = 0;
34 static int MSVCRT_atexit_registered = 0; /* Points to free slot */
35 static MSVCRT_purecall_handler purecall_handler = NULL;
37 static const char szMsgBoxTitle[] = "Wine C++ Runtime Library";
39 extern int MSVCRT_app_type;
40 extern char *MSVCRT__pgmptr;
42 static unsigned int MSVCRT_abort_behavior = MSVCRT__WRITE_ABORT_MSG | MSVCRT__CALL_REPORTFAULT;
43 static int MSVCRT_error_mode = MSVCRT__OUT_TO_DEFAULT;
45 void (*CDECL _aexit_rtn)(int) = MSVCRT__exit;
47 /* INTERNAL: call atexit functions */
48 static void __MSVCRT__call_atexit(void)
50 /* Note: should only be called with the exit lock held */
51 TRACE("%d atext functions to call\n", MSVCRT_atexit_registered);
52 /* Last registered gets executed first */
53 while (MSVCRT_atexit_registered > 0)
55 MSVCRT_atexit_registered--;
56 TRACE("next is %p\n",MSVCRT_atexit_table[MSVCRT_atexit_registered]);
57 if (MSVCRT_atexit_table[MSVCRT_atexit_registered])
58 (*MSVCRT_atexit_table[MSVCRT_atexit_registered])();
63 /*********************************************************************
64 * __dllonexit (MSVCRT.@)
66 MSVCRT__onexit_t CDECL __dllonexit(MSVCRT__onexit_t func, MSVCRT__onexit_t **start, MSVCRT__onexit_t **end)
68 MSVCRT__onexit_t *tmp;
71 TRACE("(%p,%p,%p)\n", func, start, end);
73 if (!start || !*start || !end || !*end)
79 len = (*end - *start);
81 TRACE("table start %p-%p, %d entries\n", *start, *end, len);
86 tmp = MSVCRT_realloc(*start, len * sizeof(tmp));
92 TRACE("new table start %p-%p, %d entries\n", *start, *end, len);
96 /*********************************************************************
99 void CDECL MSVCRT__exit(int exitcode)
101 TRACE("(%d)\n", exitcode);
102 ExitProcess(exitcode);
105 /* Print out an error message with an option to debug */
106 static void DoMessageBox(LPCSTR lead, LPCSTR message)
108 MSGBOXPARAMSA msgbox;
112 snprintf(text,sizeof(text),"%s\n\nProgram: %s\n%s\n\n"
113 "Press OK to exit the program, or Cancel to start the Wine debugger.\n ",
114 lead, MSVCRT__pgmptr, message);
116 msgbox.cbSize = sizeof(msgbox);
117 msgbox.hwndOwner = GetActiveWindow();
118 msgbox.hInstance = 0;
119 msgbox.lpszText = text;
120 msgbox.lpszCaption = szMsgBoxTitle;
121 msgbox.dwStyle = MB_OKCANCEL|MB_ICONERROR;
122 msgbox.lpszIcon = NULL;
123 msgbox.dwContextHelpId = 0;
124 msgbox.lpfnMsgBoxCallback = NULL;
125 msgbox.dwLanguageId = LANG_NEUTRAL;
127 ret = MessageBoxIndirectA(&msgbox);
132 /*********************************************************************
133 * _amsg_exit (MSVCRT.@)
135 void CDECL _amsg_exit(int errnum)
137 TRACE("(%d)\n", errnum);
139 if ((MSVCRT_error_mode == MSVCRT__OUT_TO_MSGBOX) ||
140 ((MSVCRT_error_mode == MSVCRT__OUT_TO_DEFAULT) && (MSVCRT_app_type == 2)))
143 sprintf(text, "Error: R60%d",errnum);
144 DoMessageBox("Runtime error!", text);
147 _cprintf("\nruntime error R60%d\n",errnum);
151 /*********************************************************************
154 void CDECL MSVCRT_abort(void)
158 if (MSVCRT_abort_behavior & MSVCRT__WRITE_ABORT_MSG)
160 if ((MSVCRT_error_mode == MSVCRT__OUT_TO_MSGBOX) ||
161 ((MSVCRT_error_mode == MSVCRT__OUT_TO_DEFAULT) && (MSVCRT_app_type == 2)))
163 DoMessageBox("Runtime error!", "abnormal program termination");
166 _cputs("\nabnormal program termination\n");
168 MSVCRT_raise(MSVCRT_SIGABRT);
169 /* in case raise() returns */
173 /*********************************************************************
174 * _set_abort_behavior (MSVCRT.@)
176 * Not exported by native msvcrt, added in msvcr80
178 unsigned int CDECL MSVCRT__set_abort_behavior(unsigned int flags, unsigned int mask)
180 unsigned int old = MSVCRT_abort_behavior;
182 TRACE("%x, %x\n", flags, mask);
183 if (mask & MSVCRT__CALL_REPORTFAULT)
184 FIXME("_WRITE_CALL_REPORTFAULT unhandled\n");
186 MSVCRT_abort_behavior = (MSVCRT_abort_behavior & ~mask) | (flags & mask);
190 /*********************************************************************
193 void CDECL MSVCRT__assert(const char* str, const char* file, unsigned int line)
195 TRACE("(%s,%s,%d)\n",str,file,line);
196 if ((MSVCRT_error_mode == MSVCRT__OUT_TO_MSGBOX) ||
197 ((MSVCRT_error_mode == MSVCRT__OUT_TO_DEFAULT) && (MSVCRT_app_type == 2)))
200 snprintf(text, sizeof(text), "File: %s\nLine: %d\n\nExpression: \"%s\"", file, line, str);
201 DoMessageBox("Assertion failed!", text);
204 _cprintf("Assertion failed: %s, file %s, line %d\n\n",str, file, line);
205 MSVCRT_raise(MSVCRT_SIGABRT);
206 /* in case raise() returns */
210 /*********************************************************************
213 void CDECL MSVCRT__c_exit(void)
216 /* All cleanup is done on DLL detach; Return to caller */
219 /*********************************************************************
222 void CDECL MSVCRT__cexit(void)
226 __MSVCRT__call_atexit();
230 /*********************************************************************
233 MSVCRT__onexit_t CDECL MSVCRT__onexit(MSVCRT__onexit_t func)
235 TRACE("(%p)\n",func);
241 if (MSVCRT_atexit_registered > MSVCRT_atexit_table_size - 1)
243 MSVCRT__onexit_t *newtable;
244 TRACE("expanding table\n");
245 newtable = MSVCRT_calloc(sizeof(void *),MSVCRT_atexit_table_size + 32);
252 memcpy (newtable, MSVCRT_atexit_table, MSVCRT_atexit_table_size);
253 MSVCRT_atexit_table_size += 32;
254 MSVCRT_free (MSVCRT_atexit_table);
255 MSVCRT_atexit_table = newtable;
257 MSVCRT_atexit_table[MSVCRT_atexit_registered] = func;
258 MSVCRT_atexit_registered++;
263 /*********************************************************************
266 void CDECL MSVCRT_exit(int exitcode)
269 static const WCHAR mscoreeW[] = {'m','s','c','o','r','e','e',0};
270 void WINAPI (*pCorExitProcess)(int);
272 TRACE("(%d)\n",exitcode);
275 hmscoree = GetModuleHandleW(mscoreeW);
279 pCorExitProcess = (void*)GetProcAddress(hmscoree, "CorExitProcess");
282 pCorExitProcess(exitcode);
285 ExitProcess(exitcode);
288 /*********************************************************************
291 int CDECL MSVCRT_atexit(void (*func)(void))
293 TRACE("(%p)\n", func);
294 return MSVCRT__onexit((MSVCRT__onexit_t)func) == (MSVCRT__onexit_t)func ? 0 : -1;
297 /* _set_purecall_handler - not exported in native msvcrt */
298 MSVCRT_purecall_handler CDECL _set_purecall_handler(MSVCRT_purecall_handler function)
300 MSVCRT_purecall_handler ret = purecall_handler;
302 TRACE("(%p)\n", function);
303 purecall_handler = function;
307 /*********************************************************************
308 * _purecall (MSVCRT.@)
310 void CDECL _purecall(void)
319 /******************************************************************************
320 * _set_error_mode (MSVCRT.@)
322 * Set the error mode, which describes where the C run-time writes error messages.
325 * mode - the new error mode
328 * The old error mode.
331 int CDECL _set_error_mode(int mode)
334 const int old = MSVCRT_error_mode;
335 if ( MSVCRT__REPORT_ERRMODE != mode ) {
336 MSVCRT_error_mode = mode;