ViewVC Help
View File | Revision Log | Show Annotations | Revision Graph | Root Listing
root/cebix/BasiliskII/src/Windows/main_windows.cpp
Revision: 1.13
Committed: 2008-01-01T09:40:33Z (16 years, 10 months ago) by gbeauche
Branch: MAIN
Changes since 1.12: +1 -1 lines
Log Message:
Happy New Year!

File Contents

# User Rev Content
1 gbeauche 1.1 /*
2     * main_windows.cpp - Startup code for Windows
3     *
4 gbeauche 1.13 * Basilisk II (C) 1997-2008 Christian Bauer
5 gbeauche 1.1 *
6     * This program is free software; you can redistribute it and/or modify
7     * it under the terms of the GNU General Public License as published by
8     * the Free Software Foundation; either version 2 of the License, or
9     * (at your option) any later version.
10     *
11     * This program 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
14     * GNU General Public License for more details.
15     *
16     * You should have received a copy of the GNU General Public License
17     * along with this program; if not, write to the Free Software
18     * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
19     */
20    
21     #include "sysdeps.h"
22    
23     #include <stdio.h>
24     #include <stdlib.h>
25     #include <signal.h>
26     #include <errno.h>
27    
28     #include <SDL.h>
29     #include <SDL_mutex.h>
30     #include <SDL_thread.h>
31    
32     #include <string>
33     using std::string;
34    
35     #include "cpu_emulation.h"
36     #include "sys.h"
37     #include "rom_patches.h"
38     #include "xpram.h"
39     #include "timer.h"
40     #include "video.h"
41 gbeauche 1.3 #include "cdrom.h"
42 gbeauche 1.1 #include "emul_op.h"
43     #include "prefs.h"
44     #include "prefs_editor.h"
45     #include "macos_util.h"
46     #include "user_strings.h"
47     #include "version.h"
48     #include "main.h"
49     #include "vm_alloc.h"
50     #include "sigsegv.h"
51 gbeauche 1.6 #include "util_windows.h"
52 gbeauche 1.4 #include "kernel_windows.h"
53 gbeauche 1.1
54     #if USE_JIT
55 gbeauche 1.10 extern void flush_icache_range(uint8 *start, uint32 size); // from compemu_support.cpp
56 gbeauche 1.1 #endif
57    
58     #ifdef ENABLE_MON
59     # include "mon.h"
60     #endif
61    
62     #define DEBUG 0
63     #include "debug.h"
64    
65    
66     // Constants
67     const char ROM_FILE_NAME[] = "ROM";
68     const int SCRATCH_MEM_SIZE = 0x10000; // Size of scratch memory area
69    
70    
71     // CPU and FPU type, addressing mode
72     int CPUType;
73     bool CPUIs68060;
74     int FPUType;
75     bool TwentyFourBitAddressing;
76    
77    
78     // Global variables
79 gbeauche 1.9 HANDLE emul_thread = NULL; // Handle of MacOS emulation thread (main thread)
80    
81 gbeauche 1.1 static uint8 last_xpram[XPRAM_SIZE]; // Buffer for monitoring XPRAM changes
82     static bool xpram_thread_active = false; // Flag: XPRAM watchdog installed
83     static volatile bool xpram_thread_cancel = false; // Flag: Cancel XPRAM thread
84     static SDL_Thread *xpram_thread = NULL; // XPRAM watchdog
85    
86     static bool tick_thread_active = false; // Flag: 60Hz thread installed
87     static volatile bool tick_thread_cancel = false; // Flag: Cancel 60Hz thread
88     static SDL_Thread *tick_thread; // 60Hz thread
89    
90     static SDL_mutex *intflag_lock = NULL; // Mutex to protect InterruptFlags
91     #define LOCK_INTFLAGS SDL_LockMutex(intflag_lock)
92     #define UNLOCK_INTFLAGS SDL_UnlockMutex(intflag_lock)
93    
94 gbeauche 1.4 DWORD win_os; // Windows OS id
95     DWORD win_os_major; // Windows OS version major
96    
97 gbeauche 1.1 #if USE_SCRATCHMEM_SUBTERFUGE
98     uint8 *ScratchMem = NULL; // Scratch memory for Mac ROM writes
99     #endif
100    
101     #if REAL_ADDRESSING
102     static bool lm_area_mapped = false; // Flag: Low Memory area mmap()ped
103     #endif
104    
105    
106     // Prototypes
107     static int xpram_func(void *arg);
108     static int tick_func(void *arg);
109     static void one_tick(...);
110    
111    
112     /*
113     * Ersatz functions
114     */
115    
116     extern "C" {
117    
118     #ifndef HAVE_STRDUP
119     char *strdup(const char *s)
120     {
121     char *n = (char *)malloc(strlen(s) + 1);
122     strcpy(n, s);
123     return n;
124     }
125     #endif
126    
127     }
128    
129    
130     /*
131     * Map memory that can be accessed from the Mac side
132     */
133    
134     void *vm_acquire_mac(size_t size)
135     {
136 gbeauche 1.11 return vm_acquire(size, VM_MAP_DEFAULT | VM_MAP_32BIT);
137 gbeauche 1.1 }
138    
139    
140     /*
141     * SIGSEGV handler
142     */
143    
144 gbeauche 1.12 static sigsegv_return_t sigsegv_handler(sigsegv_info_t *sip)
145 gbeauche 1.1 {
146 gbeauche 1.12 const uintptr fault_address = (uintptr)sigsegv_get_fault_address(sip);
147 gbeauche 1.1 #if ENABLE_VOSF
148     // Handle screen fault
149 gbeauche 1.12 extern bool Screen_fault_handler(sigsegv_info_t *sip);
150     if (Screen_fault_handler(sip))
151 gbeauche 1.1 return SIGSEGV_RETURN_SUCCESS;
152     #endif
153    
154     #ifdef HAVE_SIGSEGV_SKIP_INSTRUCTION
155     // Ignore writes to ROM
156     if (((uintptr)fault_address - (uintptr)ROMBaseHost) < ROMSize)
157     return SIGSEGV_RETURN_SKIP_INSTRUCTION;
158    
159     // Ignore all other faults, if requested
160     if (PrefsFindBool("ignoresegv"))
161     return SIGSEGV_RETURN_SKIP_INSTRUCTION;
162     #endif
163    
164     return SIGSEGV_RETURN_FAILURE;
165     }
166    
167     /*
168     * Dump state when everything went wrong after a SEGV
169     */
170    
171 gbeauche 1.12 static void sigsegv_dump_state(sigsegv_info_t *sip)
172 gbeauche 1.1 {
173 gbeauche 1.12 const sigsegv_address_t fault_address = sigsegv_get_fault_address(sip);
174     const sigsegv_address_t fault_instruction = sigsegv_get_fault_instruction_address(sip);
175 gbeauche 1.1 fprintf(stderr, "Caught SIGSEGV at address %p", fault_address);
176 gbeauche 1.12 if (fault_instruction != SIGSEGV_INVALID_ADDRESS)
177 gbeauche 1.1 fprintf(stderr, " [IP=%p]", fault_instruction);
178     fprintf(stderr, "\n");
179     uaecptr nextpc;
180     extern void m68k_dumpstate(uaecptr *nextpc);
181     m68k_dumpstate(&nextpc);
182     #if USE_JIT && JIT_DEBUG
183     extern void compiler_dumpstate(void);
184     compiler_dumpstate();
185     #endif
186     VideoQuitFullScreen();
187     #ifdef ENABLE_MON
188     char *arg[4] = {"mon", "-m", "-r", NULL};
189     mon(3, arg);
190     QuitEmulator();
191     #endif
192     }
193    
194    
195     /*
196     * Main program
197     */
198    
199     static void usage(const char *prg_name)
200     {
201     printf(
202     "Usage: %s [OPTION...]\n"
203     "\nUnix options:\n"
204     " --config FILE\n read/write configuration from/to FILE\n"
205     " --display STRING\n X display to use\n"
206     " --break ADDRESS\n set ROM breakpoint\n"
207     " --rominfo\n dump ROM information\n", prg_name
208     );
209     LoadPrefs(); // read the prefs file so PrefsPrintUsage() will print the correct default values
210     PrefsPrintUsage();
211     exit(0);
212     }
213    
214     int main(int argc, char **argv)
215     {
216     char str[256];
217 gbeauche 1.3 bool cd_boot = false;
218 gbeauche 1.1
219     // Initialize variables
220     RAMBaseHost = NULL;
221     ROMBaseHost = NULL;
222     srand(time(NULL));
223     tzset();
224    
225     // Print some info
226     printf(GetString(STR_ABOUT_TEXT1), VERSION_MAJOR, VERSION_MINOR);
227     printf(" %s\n", GetString(STR_ABOUT_TEXT2));
228    
229     // Parse command line arguments
230     for (int i=1; i<argc; i++) {
231     if (strcmp(argv[i], "--help") == 0) {
232     usage(argv[0]);
233     } else if (strcmp(argv[i], "--break") == 0) {
234     argv[i++] = NULL;
235     if (i < argc) {
236     ROMBreakpoint = strtol(argv[i], NULL, 0);
237     argv[i] = NULL;
238     }
239     } else if (strcmp(argv[i], "--config") == 0) {
240     argv[i++] = NULL;
241     if (i < argc) {
242     extern string UserPrefsPath; // from prefs_unix.cpp
243     UserPrefsPath = argv[i];
244     argv[i] = NULL;
245     }
246     } else if (strcmp(argv[i], "--rominfo") == 0) {
247     argv[i] = NULL;
248     PrintROMInfo = true;
249 gbeauche 1.3 } else if (strcmp(argv[i], "--cdboot") == 0) {
250     argv[i] = NULL;
251     cd_boot = true;
252 gbeauche 1.1 }
253     }
254    
255     // Remove processed arguments
256     for (int i=1; i<argc; i++) {
257     int k;
258     for (k=i; k<argc; k++)
259     if (argv[k] != NULL)
260     break;
261     if (k > i) {
262     k -= i;
263     for (int j=i+k; j<argc; j++)
264     argv[j-k] = argv[j];
265     argc -= k;
266     }
267     }
268    
269     // Read preferences
270     PrefsInit(argc, argv);
271    
272 gbeauche 1.3 // Boot MacOS from CD-ROM?
273     if (cd_boot)
274     PrefsReplaceInt32("bootdriver", CDROMRefNum);
275    
276 gbeauche 1.1 // Any command line arguments left?
277     for (int i=1; i<argc; i++) {
278     if (argv[i][0] == '-') {
279     fprintf(stderr, "Unrecognized option '%s'\n", argv[i]);
280     usage(argv[0]);
281     }
282     }
283    
284 gbeauche 1.2 // Check we are using a Windows NT kernel >= 4.0
285     OSVERSIONINFO osvi;
286     ZeroMemory(&osvi, sizeof(OSVERSIONINFO));
287     osvi.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);
288 gbeauche 1.4 if (!GetVersionEx(&osvi)) {
289     ErrorAlert("Could not determine OS type");
290     QuitEmulator();
291     }
292     win_os = osvi.dwPlatformId;
293     win_os_major = osvi.dwMajorVersion;
294     if (win_os != VER_PLATFORM_WIN32_NT || win_os_major < 4) {
295 gbeauche 1.2 ErrorAlert(STR_NO_WIN32_NT_4);
296     QuitEmulator();
297     }
298    
299 gbeauche 1.6 // Check that drivers are installed
300     if (!check_drivers())
301     QuitEmulator();
302    
303 gbeauche 1.4 // Load win32 libraries
304     KernelInit();
305    
306 gbeauche 1.7 // FIXME: default to DIB driver
307     if (getenv("SDL_VIDEODRIVER") == NULL)
308     putenv("SDL_VIDEODRIVER=windib");
309    
310 gbeauche 1.1 // Initialize SDL system
311     int sdl_flags = 0;
312     #ifdef USE_SDL_VIDEO
313     sdl_flags |= SDL_INIT_VIDEO;
314     #endif
315     #ifdef USE_SDL_AUDIO
316     sdl_flags |= SDL_INIT_AUDIO;
317     #endif
318     assert(sdl_flags != 0);
319     if (SDL_Init(sdl_flags) == -1) {
320     char str[256];
321     sprintf(str, "Could not initialize SDL: %s.\n", SDL_GetError());
322     ErrorAlert(str);
323     QuitEmulator();
324     }
325     atexit(SDL_Quit);
326    
327     // Init system routines
328     SysInit();
329    
330     // Show preferences editor
331     if (!PrefsFindBool("nogui"))
332     if (!PrefsEditor())
333     QuitEmulator();
334    
335     // Install the handler for SIGSEGV
336     if (!sigsegv_install_handler(sigsegv_handler)) {
337     sprintf(str, GetString(STR_SIG_INSTALL_ERR), "SIGSEGV", strerror(errno));
338     ErrorAlert(str);
339     QuitEmulator();
340     }
341    
342     // Register dump state function when we got mad after a segfault
343     sigsegv_set_dump_state(sigsegv_dump_state);
344    
345     // Read RAM size
346     RAMSize = PrefsFindInt32("ramsize") & 0xfff00000; // Round down to 1MB boundary
347     if (RAMSize < 1024*1024) {
348     WarningAlert(GetString(STR_SMALL_RAM_WARN));
349     RAMSize = 1024*1024;
350     }
351    
352     // Initialize VM system
353     vm_init();
354    
355     // Create areas for Mac RAM and ROM
356     RAMBaseHost = (uint8 *)vm_acquire_mac(RAMSize);
357     ROMBaseHost = (uint8 *)vm_acquire_mac(0x100000);
358     if (RAMBaseHost == VM_MAP_FAILED || ROMBaseHost == VM_MAP_FAILED) {
359     ErrorAlert(STR_NO_MEM_ERR);
360     QuitEmulator();
361     }
362    
363     #if USE_SCRATCHMEM_SUBTERFUGE
364     // Allocate scratch memory
365     ScratchMem = (uint8 *)vm_acquire(SCRATCH_MEM_SIZE);
366     if (ScratchMem == VM_MAP_FAILED) {
367     ErrorAlert(STR_NO_MEM_ERR);
368     QuitEmulator();
369     }
370     ScratchMem += SCRATCH_MEM_SIZE/2; // ScratchMem points to middle of block
371     #endif
372    
373     #if DIRECT_ADDRESSING
374     // RAMBaseMac shall always be zero
375     MEMBaseDiff = (uintptr)RAMBaseHost;
376     RAMBaseMac = 0;
377     ROMBaseMac = Host2MacAddr(ROMBaseHost);
378     #endif
379     D(bug("Mac RAM starts at %p (%08x)\n", RAMBaseHost, RAMBaseMac));
380     D(bug("Mac ROM starts at %p (%08x)\n", ROMBaseHost, ROMBaseMac));
381    
382     // Get rom file path from preferences
383     const char *rom_path = PrefsFindString("rom");
384    
385     // Load Mac ROM
386     HANDLE rom_fh = CreateFile(rom_path ? rom_path : ROM_FILE_NAME,
387     GENERIC_READ,
388     0, NULL,
389     OPEN_EXISTING,
390     FILE_ATTRIBUTE_NORMAL,
391     NULL);
392     if (rom_fh == INVALID_HANDLE_VALUE) {
393     ErrorAlert(STR_NO_ROM_FILE_ERR);
394     QuitEmulator();
395     }
396     printf(GetString(STR_READING_ROM_FILE));
397     ROMSize = GetFileSize(rom_fh, NULL);
398     if (ROMSize != 64*1024 && ROMSize != 128*1024 && ROMSize != 256*1024 && ROMSize != 512*1024 && ROMSize != 1024*1024) {
399     ErrorAlert(STR_ROM_SIZE_ERR);
400     CloseHandle(rom_fh);
401     QuitEmulator();
402     }
403     DWORD bytes_read;
404     if (ReadFile(rom_fh, ROMBaseHost, ROMSize, &bytes_read, NULL) == 0 || bytes_read != ROMSize) {
405     ErrorAlert(STR_ROM_FILE_READ_ERR);
406     CloseHandle(rom_fh);
407     QuitEmulator();
408     }
409    
410     // Initialize native timers
411     timer_init();
412    
413     // Initialize everything
414     if (!InitAll())
415     QuitEmulator();
416     D(bug("Initialization complete\n"));
417    
418 gbeauche 1.9 // Get handle of main thread
419     emul_thread = GetCurrentThread();
420    
421 gbeauche 1.1 // SDL threads available, start 60Hz thread
422     tick_thread_active = ((tick_thread = SDL_CreateThread(tick_func, NULL)) != NULL);
423     if (!tick_thread_active) {
424     sprintf(str, GetString(STR_TICK_THREAD_ERR), strerror(errno));
425     ErrorAlert(str);
426     QuitEmulator();
427     }
428     D(bug("60Hz thread started\n"));
429    
430     // Start XPRAM watchdog thread
431     memcpy(last_xpram, XPRAM, XPRAM_SIZE);
432     xpram_thread_active = ((xpram_thread = SDL_CreateThread(xpram_func, NULL)) != NULL);
433     D(bug("XPRAM thread started\n"));
434    
435     // Start 68k and jump to ROM boot routine
436     D(bug("Starting emulation...\n"));
437     Start680x0();
438    
439     QuitEmulator();
440     return 0;
441     }
442    
443    
444     /*
445     * Quit emulator
446     */
447    
448     void QuitEmulator(void)
449     {
450     D(bug("QuitEmulator\n"));
451    
452     // Exit 680x0 emulation
453     Exit680x0();
454    
455     // Stop 60Hz thread
456     if (tick_thread_active) {
457     tick_thread_cancel = true;
458     SDL_WaitThread(tick_thread, NULL);
459     }
460    
461     // Stop XPRAM watchdog thread
462     if (xpram_thread_active) {
463     xpram_thread_cancel = true;
464     SDL_WaitThread(xpram_thread, NULL);
465     }
466    
467     // Deinitialize everything
468     ExitAll();
469    
470     // Free ROM/RAM areas
471     if (RAMBaseHost != VM_MAP_FAILED) {
472     vm_release(RAMBaseHost, RAMSize);
473     RAMBaseHost = NULL;
474     }
475     if (ROMBaseHost != VM_MAP_FAILED) {
476     vm_release(ROMBaseHost, 0x100000);
477     ROMBaseHost = NULL;
478     }
479    
480     #if USE_SCRATCHMEM_SUBTERFUGE
481     // Delete scratch memory area
482     if (ScratchMem != (uint8 *)VM_MAP_FAILED) {
483     vm_release((void *)(ScratchMem - SCRATCH_MEM_SIZE/2), SCRATCH_MEM_SIZE);
484     ScratchMem = NULL;
485     }
486     #endif
487    
488     // Exit VM wrappers
489     vm_exit();
490    
491     // Exit system routines
492     SysExit();
493    
494     // Exit preferences
495     PrefsExit();
496    
497 gbeauche 1.4 // Release win32 libraries
498     KernelExit();
499    
500 gbeauche 1.1 exit(0);
501     }
502    
503    
504     /*
505     * Code was patched, flush caches if neccessary (i.e. when using a real 680x0
506     * or a dynamically recompiling emulator)
507     */
508    
509     void FlushCodeCache(void *start, uint32 size)
510     {
511     #if USE_JIT
512     if (UseJIT)
513 gbeauche 1.10 flush_icache_range((uint8 *)start, size);
514 gbeauche 1.1 #endif
515     }
516    
517    
518     /*
519     * Mutexes
520     */
521    
522     struct B2_mutex {
523     B2_mutex() { m = SDL_CreateMutex(); }
524     ~B2_mutex() { if (m) SDL_DestroyMutex(m); }
525     SDL_mutex *m;
526     };
527    
528     B2_mutex *B2_create_mutex(void)
529     {
530     return new B2_mutex;
531     }
532    
533     void B2_lock_mutex(B2_mutex *mutex)
534     {
535     if (mutex)
536     SDL_LockMutex(mutex->m);
537     }
538    
539     void B2_unlock_mutex(B2_mutex *mutex)
540     {
541     if (mutex)
542     SDL_UnlockMutex(mutex->m);
543     }
544    
545     void B2_delete_mutex(B2_mutex *mutex)
546     {
547     delete mutex;
548     }
549    
550    
551     /*
552     * Interrupt flags (must be handled atomically!)
553     */
554    
555     uint32 InterruptFlags = 0;
556    
557     void SetInterruptFlag(uint32 flag)
558     {
559     LOCK_INTFLAGS;
560     InterruptFlags |= flag;
561     UNLOCK_INTFLAGS;
562     }
563    
564     void ClearInterruptFlag(uint32 flag)
565     {
566     LOCK_INTFLAGS;
567     InterruptFlags &= ~flag;
568     UNLOCK_INTFLAGS;
569     }
570    
571    
572     /*
573     * XPRAM watchdog thread (saves XPRAM every minute)
574     */
575    
576     static void xpram_watchdog(void)
577     {
578     if (memcmp(last_xpram, XPRAM, XPRAM_SIZE)) {
579     memcpy(last_xpram, XPRAM, XPRAM_SIZE);
580     SaveXPRAM();
581     }
582     }
583    
584     static int xpram_func(void *arg)
585     {
586     while (!xpram_thread_cancel) {
587     for (int i=0; i<60 && !xpram_thread_cancel; i++)
588     Delay_usec(999999); // Only wait 1 second so we quit promptly when xpram_thread_cancel becomes true
589     xpram_watchdog();
590     }
591     return 0;
592     }
593    
594    
595     /*
596     * 60Hz thread (really 60.15Hz)
597     */
598    
599     static void one_second(void)
600     {
601     // Pseudo Mac 1Hz interrupt, update local time
602     WriteMacInt32(0x20c, TimerDateTime());
603    
604     SetInterruptFlag(INTFLAG_1HZ);
605     TriggerInterrupt();
606     }
607    
608     static void one_tick(...)
609     {
610     static int tick_counter = 0;
611     if (++tick_counter > 60) {
612     tick_counter = 0;
613     one_second();
614     }
615    
616     // Trigger 60Hz interrupt
617     if (ROMVersion != ROM_VERSION_CLASSIC || HasMacStarted()) {
618     SetInterruptFlag(INTFLAG_60HZ);
619     TriggerInterrupt();
620     }
621     }
622    
623     static int tick_func(void *arg)
624     {
625     uint64 start = GetTicks_usec();
626     int64 ticks = 0;
627     uint64 next = GetTicks_usec();
628     while (!tick_thread_cancel) {
629     one_tick();
630     next += 16625;
631     int64 delay = next - GetTicks_usec();
632     if (delay > 0)
633     Delay_usec(delay);
634     else if (delay < -16625)
635     next = GetTicks_usec();
636     ticks++;
637     }
638     uint64 end = GetTicks_usec();
639     D(bug("%Ld ticks in %Ld usec = %f ticks/sec\n", ticks, end - start, ticks * 1000000.0 / (end - start)));
640     return 0;
641     }
642    
643    
644     /*
645 gbeauche 1.2 * Get the main window handle
646 gbeauche 1.1 */
647    
648 gbeauche 1.2 #ifdef USE_SDL_VIDEO
649     #include <SDL_syswm.h>
650 gbeauche 1.8 HWND GetMainWindowHandle(void)
651 gbeauche 1.1 {
652 gbeauche 1.2 SDL_SysWMinfo wmInfo;
653 gbeauche 1.8 SDL_VERSION(&wmInfo.version);
654 gbeauche 1.2 return SDL_GetWMInfo(&wmInfo) ? wmInfo.window : NULL;
655 gbeauche 1.1 }
656 gbeauche 1.2 #endif
657 gbeauche 1.1
658    
659 gbeauche 1.2 /*
660     * Display alert
661     */
662    
663     static void display_alert(int title_id, const char *text, int flags)
664 gbeauche 1.1 {
665 gbeauche 1.2 HWND hMainWnd = GetMainWindowHandle();
666     MessageBox(hMainWnd, text, GetString(title_id), MB_OK | flags);
667 gbeauche 1.1 }
668    
669    
670     /*
671     * Display error alert
672     */
673    
674     void ErrorAlert(const char *text)
675     {
676 gbeauche 1.2 if (PrefsFindBool("nogui"))
677 gbeauche 1.1 return;
678 gbeauche 1.2
679 gbeauche 1.1 VideoQuitFullScreen();
680 gbeauche 1.2 display_alert(STR_ERROR_ALERT_TITLE, text, MB_ICONSTOP);
681 gbeauche 1.1 }
682    
683    
684     /*
685     * Display warning alert
686     */
687    
688     void WarningAlert(const char *text)
689     {
690 gbeauche 1.2 if (PrefsFindBool("nogui"))
691 gbeauche 1.1 return;
692 gbeauche 1.2
693     display_alert(STR_WARNING_ALERT_TITLE, text, MB_ICONINFORMATION);
694 gbeauche 1.1 }
695    
696    
697     /*
698     * Display choice alert
699     */
700    
701     bool ChoiceAlert(const char *text, const char *pos, const char *neg)
702     {
703     printf(GetString(STR_SHELL_WARNING_PREFIX), text);
704     return false; //!!
705     }