Display abnormal exit text in a message box for GUI apps.
[wine] / dlls / msvcrt / exit.c
1 /*
2  * msvcrt.dll exit functions
3  *
4  * Copyright 2000 Jon Griffiths
5  *
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.
10  *
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.
15  *
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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
19  */
20 #include <stdio.h>
21 #include "msvcrt.h"
22
23 #include "msvcrt/conio.h"
24 #include "msvcrt/stdlib.h"
25 #include "mtdll.h"
26 #include "winuser.h"
27
28 #include "wine/debug.h"
29
30 WINE_DEFAULT_DEBUG_CHANNEL(msvcrt);
31
32 /* MT */
33 #define LOCK_EXIT   _mlock(_EXIT_LOCK1)
34 #define UNLOCK_EXIT _munlock(_EXIT_LOCK1)
35
36 static _onexit_t *MSVCRT_atexit_table = NULL;
37 static int MSVCRT_atexit_table_size = 0;
38 static int MSVCRT_atexit_registered = 0; /* Points to free slot */
39
40 static LPCSTR szMsgBoxTitle = "Wine C++ Runtime Library";
41
42 extern int MSVCRT_app_type;
43 extern char *MSVCRT__pgmptr;
44
45 /* INTERNAL: call atexit functions */
46 void __MSVCRT__call_atexit(void)
47 {
48   /* Note: should only be called with the exit lock held */
49   TRACE("%d atext functions to call\n", MSVCRT_atexit_registered);
50   /* Last registered gets executed first */
51   while (MSVCRT_atexit_registered > 0)
52   {
53     MSVCRT_atexit_registered--;
54     TRACE("next is %p\n",MSVCRT_atexit_table[MSVCRT_atexit_registered]);
55     if (MSVCRT_atexit_table[MSVCRT_atexit_registered])
56       (*MSVCRT_atexit_table[MSVCRT_atexit_registered])();
57     TRACE("returned\n");
58   }
59 }
60
61 /*********************************************************************
62  *              __dllonexit (MSVCRT.@)
63  */
64 _onexit_t __dllonexit(_onexit_t func, _onexit_t **start, _onexit_t **end)
65 {
66   _onexit_t *tmp;
67   int len;
68
69   TRACE("(%p,%p,%p)\n", func, start, end);
70
71   if (!start || !*start || !end || !*end)
72   {
73    FIXME("bad table\n");
74    return NULL;
75   }
76
77   len = (*end - *start);
78
79   TRACE("table start %p-%p, %d entries\n", *start, *end, len);
80
81   if (++len <= 0)
82     return NULL;
83
84   tmp = (_onexit_t *)MSVCRT_realloc(*start, len * sizeof(tmp));
85   if (!tmp)
86     return NULL;
87   *start = tmp;
88   *end = tmp + len;
89   tmp[len - 1] = func;
90   TRACE("new table start %p-%p, %d entries\n", *start, *end, len);
91   return func;
92 }
93
94 /*********************************************************************
95  *              _exit (MSVCRT.@)
96  */
97 void MSVCRT__exit(int exitcode)
98 {
99   TRACE("(%d)\n", exitcode);
100   ExitProcess(exitcode);
101 }
102
103 /* Print out an error message with an option to debug */
104 static void DoMessageBox(LPCSTR lead, LPCSTR message)
105 {
106   MSGBOXPARAMSA msgbox;
107   char text[2048];
108   INT ret;
109
110   snprintf(text,sizeof(text),"%s\n\nProgram: %s\n%s\n\n"
111                "Press OK to exit the program, or Cancel to start the Wine debugger.\n ",
112                lead, MSVCRT__pgmptr, message);
113
114   msgbox.cbSize = sizeof(msgbox);
115   msgbox.hwndOwner = GetActiveWindow();
116   msgbox.hInstance = 0;
117   msgbox.lpszText = text;
118   msgbox.lpszCaption = szMsgBoxTitle;
119   msgbox.dwStyle = MB_OKCANCEL|MB_ICONERROR;
120   msgbox.lpszIcon = NULL;
121   msgbox.dwContextHelpId = 0;
122   msgbox.lpfnMsgBoxCallback = NULL;
123   msgbox.dwLanguageId = LANG_NEUTRAL;
124
125   ret = MessageBoxIndirectA(&msgbox);
126   if (ret == IDCANCEL)
127     DebugBreak();
128 }
129
130 /*********************************************************************
131  *              _amsg_exit (MSVCRT.@)
132  */
133 void MSVCRT__amsg_exit(int errnum)
134 {
135   TRACE("(%d)\n", errnum);
136   /* FIXME: text for the error number. */
137   if (MSVCRT_app_type == 2)
138   {
139     char text[32];
140     sprintf(text, "Error: R60%d",errnum);
141     DoMessageBox("Runtime error!", text);
142   }
143   else
144     _cprintf("\nruntime error R60%d\n",errnum);
145   MSVCRT__exit(255);
146 }
147
148 /*********************************************************************
149  *              abort (MSVCRT.@)
150  */
151 void MSVCRT_abort(void)
152 {
153   TRACE("()\n");
154   if (MSVCRT_app_type == 2)
155   {
156     DoMessageBox("Runtime error!", "abnormal program termination");
157   }
158   else
159     _cputs("\nabnormal program termination\n");
160   MSVCRT__exit(3);
161 }
162
163 /*********************************************************************
164  *              _assert (MSVCRT.@)
165  */
166 void MSVCRT__assert(const char* str, const char* file, unsigned int line)
167 {
168   TRACE("(%s,%s,%d)\n",str,file,line);
169   if (MSVCRT_app_type == 2)
170   {
171     char text[2048];
172     snprintf(text, sizeof(text), "File: %s\nLine: %d\n\nEpression: \"%s\"", file, line, str);
173     DoMessageBox("Assertion failed!", text);
174   }
175   else
176     _cprintf("Assertion failed: %s, file %s, line %d\n\n",str, file, line);
177   MSVCRT__exit(3);
178 }
179
180 /*********************************************************************
181  *              _c_exit (MSVCRT.@)
182  */
183 void MSVCRT__c_exit(void)
184 {
185   TRACE("(void)\n");
186   /* All cleanup is done on DLL detach; Return to caller */
187 }
188
189 /*********************************************************************
190  *              _cexit (MSVCRT.@)
191  */
192 void MSVCRT__cexit(void)
193 {
194   TRACE("(void)\n");
195   /* All cleanup is done on DLL detach; Return to caller */
196 }
197
198 /*********************************************************************
199  *              _onexit (MSVCRT.@)
200  */
201 _onexit_t _onexit(_onexit_t func)
202 {
203   TRACE("(%p)\n",func);
204
205   if (!func)
206     return NULL;
207
208   LOCK_EXIT;
209   if (MSVCRT_atexit_registered > MSVCRT_atexit_table_size - 1)
210   {
211     _onexit_t *newtable;
212     TRACE("expanding table\n");
213     newtable = MSVCRT_calloc(sizeof(void *),MSVCRT_atexit_table_size + 32);
214     if (!newtable)
215     {
216       TRACE("failed!\n");
217       UNLOCK_EXIT;
218       return NULL;
219     }
220     memcpy (newtable, MSVCRT_atexit_table, MSVCRT_atexit_table_size);
221     MSVCRT_atexit_table_size += 32;
222     if (MSVCRT_atexit_table)
223       MSVCRT_free (MSVCRT_atexit_table);
224     MSVCRT_atexit_table = newtable;
225   }
226   MSVCRT_atexit_table[MSVCRT_atexit_registered] = func;
227   MSVCRT_atexit_registered++;
228   UNLOCK_EXIT;
229   return func;
230 }
231
232 /*********************************************************************
233  *              exit (MSVCRT.@)
234  */
235 void MSVCRT_exit(int exitcode)
236 {
237   TRACE("(%d)\n",exitcode);
238   LOCK_EXIT;
239   __MSVCRT__call_atexit();
240   UNLOCK_EXIT;
241   ExitProcess(exitcode);
242 }
243
244 /*********************************************************************
245  *              atexit (MSVCRT.@)
246  */
247 int MSVCRT_atexit(void (*func)(void))
248 {
249   TRACE("(%p)\n", func);
250   return _onexit((_onexit_t)func) == (_onexit_t)func ? 0 : -1;
251 }
252
253
254 /*********************************************************************
255  *              _purecall (MSVCRT.@)
256  */
257 void _purecall(void)
258 {
259   TRACE("(void)\n");
260   MSVCRT__amsg_exit( 25 );
261 }