msvcrt: Partially implement _set_abort_behavior.
[wine.git] / dlls / msvcrt / exit.c
blobac7e9b345d03a27dd0f7287307c669ac6ac7b53d
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 <stdio.h>
21 #include "msvcrt.h"
22 #include "mtdll.h"
23 #include "winuser.h"
24 #include "wine/debug.h"
26 WINE_DEFAULT_DEBUG_CHANNEL(msvcrt);
28 /* MT */
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;
44 void (*CDECL _aexit_rtn)(int) = MSVCRT__exit;
46 /* INTERNAL: call atexit functions */
47 static void __MSVCRT__call_atexit(void)
49 /* Note: should only be called with the exit lock held */
50 TRACE("%d atext functions to call\n", MSVCRT_atexit_registered);
51 /* Last registered gets executed first */
52 while (MSVCRT_atexit_registered > 0)
54 MSVCRT_atexit_registered--;
55 TRACE("next is %p\n",MSVCRT_atexit_table[MSVCRT_atexit_registered]);
56 if (MSVCRT_atexit_table[MSVCRT_atexit_registered])
57 (*MSVCRT_atexit_table[MSVCRT_atexit_registered])();
58 TRACE("returned\n");
62 /*********************************************************************
63 * __dllonexit (MSVCRT.@)
65 MSVCRT__onexit_t CDECL __dllonexit(MSVCRT__onexit_t func, MSVCRT__onexit_t **start, MSVCRT__onexit_t **end)
67 MSVCRT__onexit_t *tmp;
68 int len;
70 TRACE("(%p,%p,%p)\n", func, start, end);
72 if (!start || !*start || !end || !*end)
74 FIXME("bad table\n");
75 return NULL;
78 len = (*end - *start);
80 TRACE("table start %p-%p, %d entries\n", *start, *end, len);
82 if (++len <= 0)
83 return NULL;
85 tmp = MSVCRT_realloc(*start, len * sizeof(tmp));
86 if (!tmp)
87 return NULL;
88 *start = tmp;
89 *end = tmp + len;
90 tmp[len - 1] = func;
91 TRACE("new table start %p-%p, %d entries\n", *start, *end, len);
92 return func;
95 /*********************************************************************
96 * _exit (MSVCRT.@)
98 void CDECL MSVCRT__exit(int exitcode)
100 TRACE("(%d)\n", exitcode);
101 ExitProcess(exitcode);
104 /* Print out an error message with an option to debug */
105 static void DoMessageBox(LPCSTR lead, LPCSTR message)
107 MSGBOXPARAMSA msgbox;
108 char text[2048];
109 INT ret;
111 snprintf(text,sizeof(text),"%s\n\nProgram: %s\n%s\n\n"
112 "Press OK to exit the program, or Cancel to start the Wine debugger.\n ",
113 lead, MSVCRT__pgmptr, message);
115 msgbox.cbSize = sizeof(msgbox);
116 msgbox.hwndOwner = GetActiveWindow();
117 msgbox.hInstance = 0;
118 msgbox.lpszText = text;
119 msgbox.lpszCaption = szMsgBoxTitle;
120 msgbox.dwStyle = MB_OKCANCEL|MB_ICONERROR;
121 msgbox.lpszIcon = NULL;
122 msgbox.dwContextHelpId = 0;
123 msgbox.lpfnMsgBoxCallback = NULL;
124 msgbox.dwLanguageId = LANG_NEUTRAL;
126 ret = MessageBoxIndirectA(&msgbox);
127 if (ret == IDCANCEL)
128 DebugBreak();
131 /*********************************************************************
132 * _amsg_exit (MSVCRT.@)
134 void CDECL _amsg_exit(int errnum)
136 TRACE("(%d)\n", errnum);
137 /* FIXME: text for the error number. */
138 if (MSVCRT_app_type == 2)
140 char text[32];
141 sprintf(text, "Error: R60%d",errnum);
142 DoMessageBox("Runtime error!", text);
144 else
145 _cprintf("\nruntime error R60%d\n",errnum);
146 _aexit_rtn(255);
149 /*********************************************************************
150 * abort (MSVCRT.@)
152 void CDECL MSVCRT_abort(void)
154 TRACE("()\n");
156 if (MSVCRT_abort_behavior & MSVCRT__WRITE_ABORT_MSG)
158 if (MSVCRT_app_type == 2)
160 DoMessageBox("Runtime error!", "abnormal program termination");
162 else
163 _cputs("\nabnormal program termination\n");
165 MSVCRT_raise(MSVCRT_SIGABRT);
166 /* in case raise() returns */
167 MSVCRT__exit(3);
170 /*********************************************************************
171 * _set_abort_behavior (MSVCRT.@)
173 * Not exported by native msvcrt, added in msvcr80
175 unsigned int CDECL MSVCRT__set_abort_behavior(unsigned int flags, unsigned int mask)
177 unsigned int old = MSVCRT_abort_behavior;
179 TRACE("%x, %x\n", flags, mask);
180 if (mask & MSVCRT__CALL_REPORTFAULT)
181 FIXME("_WRITE_CALL_REPORTFAULT unhandled\n");
183 MSVCRT_abort_behavior = (MSVCRT_abort_behavior & ~mask) | (flags & mask);
184 return old;
187 /*********************************************************************
188 * _assert (MSVCRT.@)
190 void CDECL MSVCRT__assert(const char* str, const char* file, unsigned int line)
192 TRACE("(%s,%s,%d)\n",str,file,line);
193 if (MSVCRT_app_type == 2)
195 char text[2048];
196 snprintf(text, sizeof(text), "File: %s\nLine: %d\n\nExpression: \"%s\"", file, line, str);
197 DoMessageBox("Assertion failed!", text);
199 else
200 _cprintf("Assertion failed: %s, file %s, line %d\n\n",str, file, line);
201 MSVCRT_raise(MSVCRT_SIGABRT);
202 /* in case raise() returns */
203 MSVCRT__exit(3);
206 /*********************************************************************
207 * _c_exit (MSVCRT.@)
209 void CDECL MSVCRT__c_exit(void)
211 TRACE("(void)\n");
212 /* All cleanup is done on DLL detach; Return to caller */
215 /*********************************************************************
216 * _cexit (MSVCRT.@)
218 void CDECL MSVCRT__cexit(void)
220 TRACE("(void)\n");
221 LOCK_EXIT;
222 __MSVCRT__call_atexit();
223 UNLOCK_EXIT;
226 /*********************************************************************
227 * _onexit (MSVCRT.@)
229 MSVCRT__onexit_t CDECL MSVCRT__onexit(MSVCRT__onexit_t func)
231 TRACE("(%p)\n",func);
233 if (!func)
234 return NULL;
236 LOCK_EXIT;
237 if (MSVCRT_atexit_registered > MSVCRT_atexit_table_size - 1)
239 MSVCRT__onexit_t *newtable;
240 TRACE("expanding table\n");
241 newtable = MSVCRT_calloc(sizeof(void *),MSVCRT_atexit_table_size + 32);
242 if (!newtable)
244 TRACE("failed!\n");
245 UNLOCK_EXIT;
246 return NULL;
248 memcpy (newtable, MSVCRT_atexit_table, MSVCRT_atexit_table_size);
249 MSVCRT_atexit_table_size += 32;
250 MSVCRT_free (MSVCRT_atexit_table);
251 MSVCRT_atexit_table = newtable;
253 MSVCRT_atexit_table[MSVCRT_atexit_registered] = func;
254 MSVCRT_atexit_registered++;
255 UNLOCK_EXIT;
256 return func;
259 /*********************************************************************
260 * exit (MSVCRT.@)
262 void CDECL MSVCRT_exit(int exitcode)
264 TRACE("(%d)\n",exitcode);
265 MSVCRT__cexit();
266 ExitProcess(exitcode);
269 /*********************************************************************
270 * atexit (MSVCRT.@)
272 int CDECL MSVCRT_atexit(void (*func)(void))
274 TRACE("(%p)\n", func);
275 return MSVCRT__onexit((MSVCRT__onexit_t)func) == (MSVCRT__onexit_t)func ? 0 : -1;
278 /* _set_purecall_handler - not exported in native msvcrt */
279 MSVCRT_purecall_handler CDECL _set_purecall_handler(MSVCRT_purecall_handler function)
281 MSVCRT_purecall_handler ret = purecall_handler;
283 TRACE("(%p)\n", function);
284 purecall_handler = function;
285 return ret;
288 /*********************************************************************
289 * _purecall (MSVCRT.@)
291 void CDECL _purecall(void)
293 TRACE("(void)\n");
295 if(purecall_handler)
296 purecall_handler();
297 _amsg_exit( 25 );