|  | /* | 
|  | * msvcrt.dll exit functions | 
|  | * | 
|  | * Copyright 2000 Jon Griffiths | 
|  | * | 
|  | * This library is free software; you can redistribute it and/or | 
|  | * modify it under the terms of the GNU Lesser General Public | 
|  | * License as published by the Free Software Foundation; either | 
|  | * version 2.1 of the License, or (at your option) any later version. | 
|  | * | 
|  | * This library is distributed in the hope that it will be useful, | 
|  | * but WITHOUT ANY WARRANTY; without even the implied warranty of | 
|  | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU | 
|  | * Lesser General Public License for more details. | 
|  | * | 
|  | * You should have received a copy of the GNU Lesser General Public | 
|  | * License along with this library; if not, write to the Free Software | 
|  | * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA | 
|  | */ | 
|  | #include <stdio.h> | 
|  | #include "msvcrt.h" | 
|  | #include "mtdll.h" | 
|  | #include "winuser.h" | 
|  | #include "wine/debug.h" | 
|  |  | 
|  | WINE_DEFAULT_DEBUG_CHANNEL(msvcrt); | 
|  |  | 
|  | /* MT */ | 
|  | #define LOCK_EXIT   _mlock(_EXIT_LOCK1) | 
|  | #define UNLOCK_EXIT _munlock(_EXIT_LOCK1) | 
|  |  | 
|  | static MSVCRT__onexit_t *MSVCRT_atexit_table = NULL; | 
|  | static int MSVCRT_atexit_table_size = 0; | 
|  | static int MSVCRT_atexit_registered = 0; /* Points to free slot */ | 
|  | static MSVCRT_purecall_handler purecall_handler = NULL; | 
|  |  | 
|  | static const char szMsgBoxTitle[] = "Wine C++ Runtime Library"; | 
|  |  | 
|  | extern int MSVCRT_app_type; | 
|  | extern char *MSVCRT__pgmptr; | 
|  |  | 
|  | void (*CDECL _aexit_rtn)(int) = MSVCRT__exit; | 
|  |  | 
|  | /* INTERNAL: call atexit functions */ | 
|  | static void __MSVCRT__call_atexit(void) | 
|  | { | 
|  | /* Note: should only be called with the exit lock held */ | 
|  | TRACE("%d atext functions to call\n", MSVCRT_atexit_registered); | 
|  | /* Last registered gets executed first */ | 
|  | while (MSVCRT_atexit_registered > 0) | 
|  | { | 
|  | MSVCRT_atexit_registered--; | 
|  | TRACE("next is %p\n",MSVCRT_atexit_table[MSVCRT_atexit_registered]); | 
|  | if (MSVCRT_atexit_table[MSVCRT_atexit_registered]) | 
|  | (*MSVCRT_atexit_table[MSVCRT_atexit_registered])(); | 
|  | TRACE("returned\n"); | 
|  | } | 
|  | } | 
|  |  | 
|  | /********************************************************************* | 
|  | *		__dllonexit (MSVCRT.@) | 
|  | */ | 
|  | MSVCRT__onexit_t CDECL __dllonexit(MSVCRT__onexit_t func, MSVCRT__onexit_t **start, MSVCRT__onexit_t **end) | 
|  | { | 
|  | MSVCRT__onexit_t *tmp; | 
|  | int len; | 
|  |  | 
|  | TRACE("(%p,%p,%p)\n", func, start, end); | 
|  |  | 
|  | if (!start || !*start || !end || !*end) | 
|  | { | 
|  | FIXME("bad table\n"); | 
|  | return NULL; | 
|  | } | 
|  |  | 
|  | len = (*end - *start); | 
|  |  | 
|  | TRACE("table start %p-%p, %d entries\n", *start, *end, len); | 
|  |  | 
|  | if (++len <= 0) | 
|  | return NULL; | 
|  |  | 
|  | tmp = MSVCRT_realloc(*start, len * sizeof(tmp)); | 
|  | if (!tmp) | 
|  | return NULL; | 
|  | *start = tmp; | 
|  | *end = tmp + len; | 
|  | tmp[len - 1] = func; | 
|  | TRACE("new table start %p-%p, %d entries\n", *start, *end, len); | 
|  | return func; | 
|  | } | 
|  |  | 
|  | /********************************************************************* | 
|  | *		_exit (MSVCRT.@) | 
|  | */ | 
|  | void CDECL MSVCRT__exit(int exitcode) | 
|  | { | 
|  | TRACE("(%d)\n", exitcode); | 
|  | ExitProcess(exitcode); | 
|  | } | 
|  |  | 
|  | /* Print out an error message with an option to debug */ | 
|  | static void DoMessageBox(LPCSTR lead, LPCSTR message) | 
|  | { | 
|  | MSGBOXPARAMSA msgbox; | 
|  | char text[2048]; | 
|  | INT ret; | 
|  |  | 
|  | snprintf(text,sizeof(text),"%s\n\nProgram: %s\n%s\n\n" | 
|  | "Press OK to exit the program, or Cancel to start the Wine debugger.\n ", | 
|  | lead, MSVCRT__pgmptr, message); | 
|  |  | 
|  | msgbox.cbSize = sizeof(msgbox); | 
|  | msgbox.hwndOwner = GetActiveWindow(); | 
|  | msgbox.hInstance = 0; | 
|  | msgbox.lpszText = text; | 
|  | msgbox.lpszCaption = szMsgBoxTitle; | 
|  | msgbox.dwStyle = MB_OKCANCEL|MB_ICONERROR; | 
|  | msgbox.lpszIcon = NULL; | 
|  | msgbox.dwContextHelpId = 0; | 
|  | msgbox.lpfnMsgBoxCallback = NULL; | 
|  | msgbox.dwLanguageId = LANG_NEUTRAL; | 
|  |  | 
|  | ret = MessageBoxIndirectA(&msgbox); | 
|  | if (ret == IDCANCEL) | 
|  | DebugBreak(); | 
|  | } | 
|  |  | 
|  | /********************************************************************* | 
|  | *		_amsg_exit (MSVCRT.@) | 
|  | */ | 
|  | void CDECL _amsg_exit(int errnum) | 
|  | { | 
|  | TRACE("(%d)\n", errnum); | 
|  | /* FIXME: text for the error number. */ | 
|  | if (MSVCRT_app_type == 2) | 
|  | { | 
|  | char text[32]; | 
|  | sprintf(text, "Error: R60%d",errnum); | 
|  | DoMessageBox("Runtime error!", text); | 
|  | } | 
|  | else | 
|  | _cprintf("\nruntime error R60%d\n",errnum); | 
|  | _aexit_rtn(255); | 
|  | } | 
|  |  | 
|  | /********************************************************************* | 
|  | *		abort (MSVCRT.@) | 
|  | */ | 
|  | void CDECL MSVCRT_abort(void) | 
|  | { | 
|  | TRACE("()\n"); | 
|  | if (MSVCRT_app_type == 2) | 
|  | { | 
|  | DoMessageBox("Runtime error!", "abnormal program termination"); | 
|  | } | 
|  | else | 
|  | _cputs("\nabnormal program termination\n"); | 
|  | MSVCRT_raise(MSVCRT_SIGABRT); | 
|  | /* in case raise() returns */ | 
|  | MSVCRT__exit(3); | 
|  | } | 
|  |  | 
|  | /********************************************************************* | 
|  | *		_assert (MSVCRT.@) | 
|  | */ | 
|  | void CDECL MSVCRT__assert(const char* str, const char* file, unsigned int line) | 
|  | { | 
|  | TRACE("(%s,%s,%d)\n",str,file,line); | 
|  | if (MSVCRT_app_type == 2) | 
|  | { | 
|  | char text[2048]; | 
|  | snprintf(text, sizeof(text), "File: %s\nLine: %d\n\nExpression: \"%s\"", file, line, str); | 
|  | DoMessageBox("Assertion failed!", text); | 
|  | } | 
|  | else | 
|  | _cprintf("Assertion failed: %s, file %s, line %d\n\n",str, file, line); | 
|  | MSVCRT_raise(MSVCRT_SIGABRT); | 
|  | /* in case raise() returns */ | 
|  | MSVCRT__exit(3); | 
|  | } | 
|  |  | 
|  | /********************************************************************* | 
|  | *		_c_exit (MSVCRT.@) | 
|  | */ | 
|  | void CDECL MSVCRT__c_exit(void) | 
|  | { | 
|  | TRACE("(void)\n"); | 
|  | /* All cleanup is done on DLL detach; Return to caller */ | 
|  | } | 
|  |  | 
|  | /********************************************************************* | 
|  | *		_cexit (MSVCRT.@) | 
|  | */ | 
|  | void CDECL MSVCRT__cexit(void) | 
|  | { | 
|  | TRACE("(void)\n"); | 
|  | LOCK_EXIT; | 
|  | __MSVCRT__call_atexit(); | 
|  | UNLOCK_EXIT; | 
|  | } | 
|  |  | 
|  | /********************************************************************* | 
|  | *		_onexit (MSVCRT.@) | 
|  | */ | 
|  | MSVCRT__onexit_t CDECL MSVCRT__onexit(MSVCRT__onexit_t func) | 
|  | { | 
|  | TRACE("(%p)\n",func); | 
|  |  | 
|  | if (!func) | 
|  | return NULL; | 
|  |  | 
|  | LOCK_EXIT; | 
|  | if (MSVCRT_atexit_registered > MSVCRT_atexit_table_size - 1) | 
|  | { | 
|  | MSVCRT__onexit_t *newtable; | 
|  | TRACE("expanding table\n"); | 
|  | newtable = MSVCRT_calloc(sizeof(void *),MSVCRT_atexit_table_size + 32); | 
|  | if (!newtable) | 
|  | { | 
|  | TRACE("failed!\n"); | 
|  | UNLOCK_EXIT; | 
|  | return NULL; | 
|  | } | 
|  | memcpy (newtable, MSVCRT_atexit_table, MSVCRT_atexit_table_size); | 
|  | MSVCRT_atexit_table_size += 32; | 
|  | MSVCRT_free (MSVCRT_atexit_table); | 
|  | MSVCRT_atexit_table = newtable; | 
|  | } | 
|  | MSVCRT_atexit_table[MSVCRT_atexit_registered] = func; | 
|  | MSVCRT_atexit_registered++; | 
|  | UNLOCK_EXIT; | 
|  | return func; | 
|  | } | 
|  |  | 
|  | /********************************************************************* | 
|  | *		exit (MSVCRT.@) | 
|  | */ | 
|  | void CDECL MSVCRT_exit(int exitcode) | 
|  | { | 
|  | TRACE("(%d)\n",exitcode); | 
|  | MSVCRT__cexit(); | 
|  | ExitProcess(exitcode); | 
|  | } | 
|  |  | 
|  | /********************************************************************* | 
|  | *		atexit (MSVCRT.@) | 
|  | */ | 
|  | int CDECL MSVCRT_atexit(void (*func)(void)) | 
|  | { | 
|  | TRACE("(%p)\n", func); | 
|  | return MSVCRT__onexit((MSVCRT__onexit_t)func) == (MSVCRT__onexit_t)func ? 0 : -1; | 
|  | } | 
|  |  | 
|  | /* _set_purecall_handler - not exported in native msvcrt */ | 
|  | MSVCRT_purecall_handler CDECL _set_purecall_handler(MSVCRT_purecall_handler function) | 
|  | { | 
|  | MSVCRT_purecall_handler ret = purecall_handler; | 
|  |  | 
|  | TRACE("(%p)\n", function); | 
|  | purecall_handler = function; | 
|  | return ret; | 
|  | } | 
|  |  | 
|  | /********************************************************************* | 
|  | *		_purecall (MSVCRT.@) | 
|  | */ | 
|  | void CDECL _purecall(void) | 
|  | { | 
|  | TRACE("(void)\n"); | 
|  |  | 
|  | if(purecall_handler) | 
|  | purecall_handler(); | 
|  | _amsg_exit( 25 ); | 
|  | } |