ucrtbase: Implement _register_onexit_function().
[wine.git] / dlls / msvcrt / exit.c
blob60aa85d4d8acfb22c2709fd73c14a37b79a8d190
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 typedef struct MSVCRT__onexit_table_t
39 MSVCRT__onexit_t *_first;
40 MSVCRT__onexit_t *_last;
41 MSVCRT__onexit_t *_end;
42 } MSVCRT__onexit_table_t;
44 static const char szMsgBoxTitle[] = "Wine C++ Runtime Library";
46 extern int MSVCRT_app_type;
47 extern MSVCRT_wchar_t *MSVCRT__wpgmptr;
49 static unsigned int MSVCRT_abort_behavior = MSVCRT__WRITE_ABORT_MSG | MSVCRT__CALL_REPORTFAULT;
50 static int MSVCRT_error_mode = MSVCRT__OUT_TO_DEFAULT;
52 void (*CDECL _aexit_rtn)(int) = MSVCRT__exit;
54 /* INTERNAL: call atexit functions */
55 static void __MSVCRT__call_atexit(void)
57 /* Note: should only be called with the exit lock held */
58 TRACE("%d atext functions to call\n", MSVCRT_atexit_registered);
59 /* Last registered gets executed first */
60 while (MSVCRT_atexit_registered > 0)
62 MSVCRT_atexit_registered--;
63 TRACE("next is %p\n",MSVCRT_atexit_table[MSVCRT_atexit_registered]);
64 if (MSVCRT_atexit_table[MSVCRT_atexit_registered])
65 (*MSVCRT_atexit_table[MSVCRT_atexit_registered])();
66 TRACE("returned\n");
70 /*********************************************************************
71 * __dllonexit (MSVCRT.@)
73 MSVCRT__onexit_t CDECL __dllonexit(MSVCRT__onexit_t func, MSVCRT__onexit_t **start, MSVCRT__onexit_t **end)
75 MSVCRT__onexit_t *tmp;
76 int len;
78 TRACE("(%p,%p,%p)\n", func, start, end);
80 if (!start || !*start || !end || !*end)
82 FIXME("bad table\n");
83 return NULL;
86 len = (*end - *start);
88 TRACE("table start %p-%p, %d entries\n", *start, *end, len);
90 if (++len <= 0)
91 return NULL;
93 tmp = MSVCRT_realloc(*start, len * sizeof(*tmp));
94 if (!tmp)
95 return NULL;
96 *start = tmp;
97 *end = tmp + len;
98 tmp[len - 1] = func;
99 TRACE("new table start %p-%p, %d entries\n", *start, *end, len);
100 return func;
103 /*********************************************************************
104 * _exit (MSVCRT.@)
106 void CDECL MSVCRT__exit(int exitcode)
108 TRACE("(%d)\n", exitcode);
109 ExitProcess(exitcode);
112 /* Print out an error message with an option to debug */
113 static void DoMessageBoxW(const MSVCRT_wchar_t *lead, const MSVCRT_wchar_t *message)
115 static const MSVCRT_wchar_t message_format[] = {'%','s','\n','\n','P','r','o','g','r','a','m',':',' ','%','s','\n',
116 '%','s','\n','\n','P','r','e','s','s',' ','O','K',' ','t','o',' ','e','x','i','t',' ','t','h','e',' ',
117 'p','r','o','g','r','a','m',',',' ','o','r',' ','C','a','n','c','e','l',' ','t','o',' ','s','t','a','r','t',' ',
118 't','h','e',' ','W','i','n','e',' ','d','e','b','b','u','g','e','r','.','\n',0};
120 MSGBOXPARAMSW msgbox;
121 MSVCRT_wchar_t text[2048];
122 INT ret;
124 MSVCRT__snwprintf(text,sizeof(text),message_format, lead, MSVCRT__wpgmptr, message);
126 msgbox.cbSize = sizeof(msgbox);
127 msgbox.hwndOwner = GetActiveWindow();
128 msgbox.hInstance = 0;
129 msgbox.lpszText = (LPCWSTR)text;
130 msgbox.lpszCaption = (LPCWSTR)szMsgBoxTitle;
131 msgbox.dwStyle = MB_OKCANCEL|MB_ICONERROR;
132 msgbox.lpszIcon = NULL;
133 msgbox.dwContextHelpId = 0;
134 msgbox.lpfnMsgBoxCallback = NULL;
135 msgbox.dwLanguageId = LANG_NEUTRAL;
137 ret = MessageBoxIndirectW(&msgbox);
138 if (ret == IDCANCEL)
139 DebugBreak();
142 static void DoMessageBox(const char *lead, const char *message)
144 MSVCRT_wchar_t leadW[1024], messageW[1024];
146 MSVCRT_mbstowcs(leadW, lead, 1024);
147 MSVCRT_mbstowcs(messageW, message, 1024);
149 DoMessageBoxW(leadW, messageW);
152 /*********************************************************************
153 * _amsg_exit (MSVCRT.@)
155 void CDECL _amsg_exit(int errnum)
157 TRACE("(%d)\n", errnum);
159 if ((MSVCRT_error_mode == MSVCRT__OUT_TO_MSGBOX) ||
160 ((MSVCRT_error_mode == MSVCRT__OUT_TO_DEFAULT) && (MSVCRT_app_type == 2)))
162 char text[32];
163 sprintf(text, "Error: R60%d",errnum);
164 DoMessageBox("Runtime error!", text);
166 else
167 _cprintf("\nruntime error R60%d\n",errnum);
168 _aexit_rtn(255);
171 /*********************************************************************
172 * abort (MSVCRT.@)
174 void CDECL MSVCRT_abort(void)
176 TRACE("()\n");
178 if (MSVCRT_abort_behavior & MSVCRT__WRITE_ABORT_MSG)
180 if ((MSVCRT_error_mode == MSVCRT__OUT_TO_MSGBOX) ||
181 ((MSVCRT_error_mode == MSVCRT__OUT_TO_DEFAULT) && (MSVCRT_app_type == 2)))
183 DoMessageBox("Runtime error!", "abnormal program termination");
185 else
186 _cputs("\nabnormal program termination\n");
188 MSVCRT_raise(MSVCRT_SIGABRT);
189 /* in case raise() returns */
190 MSVCRT__exit(3);
193 /*********************************************************************
194 * _set_abort_behavior (MSVCR80.@)
196 unsigned int CDECL MSVCRT__set_abort_behavior(unsigned int flags, unsigned int mask)
198 unsigned int old = MSVCRT_abort_behavior;
200 TRACE("%x, %x\n", flags, mask);
201 if (mask & MSVCRT__CALL_REPORTFAULT)
202 FIXME("_WRITE_CALL_REPORTFAULT unhandled\n");
204 MSVCRT_abort_behavior = (MSVCRT_abort_behavior & ~mask) | (flags & mask);
205 return old;
208 /*********************************************************************
209 * _wassert (MSVCRT.@)
211 void CDECL MSVCRT__wassert(const MSVCRT_wchar_t* str, const MSVCRT_wchar_t* file, unsigned int line)
213 static const MSVCRT_wchar_t assertion_failed[] = {'A','s','s','e','r','t','i','o','n',' ','f','a','i','l','e','d','!',0};
214 static const MSVCRT_wchar_t format_msgbox[] = {'F','i','l','e',':',' ','%','s','\n','L','i','n','e',':',' ','%','d',
215 '\n','\n','E','x','p','r','e','s','s','i','o','n',':',' ','\"','%','s','\"',0};
216 static const MSVCRT_wchar_t format_console[] = {'A','s','s','e','r','t','i','o','n',' ','f','a','i','l','e','d',':',' ',
217 '%','s',',',' ','f','i','l','e',' ','%','s',',',' ','l','i','n','e',' ','%','d','\n','\n',0};
219 TRACE("(%s,%s,%d)\n", debugstr_w(str), debugstr_w(file), line);
221 if ((MSVCRT_error_mode == MSVCRT__OUT_TO_MSGBOX) ||
222 ((MSVCRT_error_mode == MSVCRT__OUT_TO_DEFAULT) && (MSVCRT_app_type == 2)))
224 MSVCRT_wchar_t text[2048];
225 MSVCRT__snwprintf(text, sizeof(text), format_msgbox, file, line, str);
226 DoMessageBoxW(assertion_failed, text);
228 else
229 _cwprintf(format_console, str, file, line);
231 MSVCRT_raise(MSVCRT_SIGABRT);
232 MSVCRT__exit(3);
235 /*********************************************************************
236 * _assert (MSVCRT.@)
238 void CDECL MSVCRT__assert(const char* str, const char* file, unsigned int line)
240 MSVCRT_wchar_t strW[1024], fileW[1024];
242 MSVCRT_mbstowcs(strW, str, 1024);
243 MSVCRT_mbstowcs(fileW, file, 1024);
245 MSVCRT__wassert(strW, fileW, line);
248 /*********************************************************************
249 * _c_exit (MSVCRT.@)
251 void CDECL MSVCRT__c_exit(void)
253 TRACE("(void)\n");
254 /* All cleanup is done on DLL detach; Return to caller */
257 /*********************************************************************
258 * _cexit (MSVCRT.@)
260 void CDECL MSVCRT__cexit(void)
262 TRACE("(void)\n");
263 LOCK_EXIT;
264 __MSVCRT__call_atexit();
265 UNLOCK_EXIT;
268 /*********************************************************************
269 * _onexit (MSVCRT.@)
271 MSVCRT__onexit_t CDECL MSVCRT__onexit(MSVCRT__onexit_t func)
273 TRACE("(%p)\n",func);
275 if (!func)
276 return NULL;
278 LOCK_EXIT;
279 if (MSVCRT_atexit_registered > MSVCRT_atexit_table_size - 1)
281 MSVCRT__onexit_t *newtable;
282 TRACE("expanding table\n");
283 newtable = MSVCRT_calloc(MSVCRT_atexit_table_size + 32, sizeof(void *));
284 if (!newtable)
286 TRACE("failed!\n");
287 UNLOCK_EXIT;
288 return NULL;
290 memcpy (newtable, MSVCRT_atexit_table, MSVCRT_atexit_table_size*sizeof(void *));
291 MSVCRT_atexit_table_size += 32;
292 MSVCRT_free (MSVCRT_atexit_table);
293 MSVCRT_atexit_table = newtable;
295 MSVCRT_atexit_table[MSVCRT_atexit_registered] = func;
296 MSVCRT_atexit_registered++;
297 UNLOCK_EXIT;
298 return func;
301 /*********************************************************************
302 * exit (MSVCRT.@)
304 void CDECL MSVCRT_exit(int exitcode)
306 HMODULE hmscoree;
307 static const WCHAR mscoreeW[] = {'m','s','c','o','r','e','e',0};
308 void (WINAPI *pCorExitProcess)(int);
310 TRACE("(%d)\n",exitcode);
311 MSVCRT__cexit();
313 hmscoree = GetModuleHandleW(mscoreeW);
315 if (hmscoree)
317 pCorExitProcess = (void*)GetProcAddress(hmscoree, "CorExitProcess");
319 if (pCorExitProcess)
320 pCorExitProcess(exitcode);
323 ExitProcess(exitcode);
326 /*********************************************************************
327 * atexit (MSVCRT.@)
329 int CDECL MSVCRT_atexit(void (*func)(void))
331 TRACE("(%p)\n", func);
332 return MSVCRT__onexit((MSVCRT__onexit_t)func) == (MSVCRT__onexit_t)func ? 0 : -1;
335 /*********************************************************************
336 * _crt_atexit (UCRTBASE.@)
338 int CDECL MSVCRT__crt_atexit(void (*func)(void))
340 TRACE("(%p)\n", func);
341 return MSVCRT__onexit((MSVCRT__onexit_t)func) == (MSVCRT__onexit_t)func ? 0 : -1;
345 /*********************************************************************
346 * _initialize_onexit_table (UCRTBASE.@)
348 int CDECL MSVCRT__initialize_onexit_table(MSVCRT__onexit_table_t *table)
350 TRACE("(%p)\n", table);
352 if (!table)
353 return -1;
355 if (table->_first == table->_end)
356 table->_last = table->_end = table->_first = NULL;
357 return 0;
360 /*********************************************************************
361 * _register_onexit_function (UCRTBASE.@)
363 int CDECL MSVCRT__register_onexit_function(MSVCRT__onexit_table_t *table, MSVCRT__onexit_t func)
365 TRACE("(%p %p)\n", table, func);
367 if (!table)
368 return -1;
370 if (!table->_first)
372 table->_first = MSVCRT_calloc(32, sizeof(void *));
373 if (!table->_first)
375 WARN("failed to allocate initial table.\n");
376 return -1;
378 table->_last = table->_first;
379 table->_end = table->_first + 32;
382 /* grow if full */
383 if (table->_last == table->_end)
385 int len = table->_end - table->_first;
386 MSVCRT__onexit_t *tmp = MSVCRT_realloc(table->_first, 2 * len * sizeof(void *));
387 if (!tmp)
389 WARN("failed to grow table.\n");
390 return -1;
392 table->_first = tmp;
393 table->_end = table->_first + 2 * len;
394 table->_last = table->_first + len;
397 *table->_last = func;
398 table->_last++;
399 return 0;
402 /*********************************************************************
403 * _set_purecall_handler (MSVCR71.@)
405 MSVCRT_purecall_handler CDECL _set_purecall_handler(MSVCRT_purecall_handler function)
407 MSVCRT_purecall_handler ret = purecall_handler;
409 TRACE("(%p)\n", function);
410 purecall_handler = function;
411 return ret;
414 /*********************************************************************
415 * _purecall (MSVCRT.@)
417 void CDECL _purecall(void)
419 TRACE("(void)\n");
421 if(purecall_handler)
422 purecall_handler();
423 _amsg_exit( 25 );
426 /******************************************************************************
427 * _set_error_mode (MSVCRT.@)
429 * Set the error mode, which describes where the C run-time writes error messages.
431 * PARAMS
432 * mode - the new error mode
434 * RETURNS
435 * The old error mode.
438 int CDECL _set_error_mode(int mode)
441 const int old = MSVCRT_error_mode;
442 if ( MSVCRT__REPORT_ERRMODE != mode ) {
443 MSVCRT_error_mode = mode;
445 return old;