]> 4ch.mooo.com Git - 16.git/blob - src/lib/doslib/dos/winfcon.c
added a bunch of things~ and midi stuff~
[16.git] / src / lib / doslib / dos / winfcon.c
1 /* winfcon.c
2  *
3  * Fake console for Windows applications where a console is not available.
4  * (C) 2011-2012 Jonathan Campbell.
5  * Hackipedia DOS library.
6  *
7  * This code is licensed under the LGPL.
8  * <insert LGPL legal text here>
9  *
10  * This code allows the DOS/CPU test code to print to a console despite the
11  * fact that Windows 3.0/3.1 and Win32s do not provide a console. For this
12  * code to work, the program must include specific headers and #define a
13  * macro. The header will then redefine various standard C functions to
14  * redirect their use into this program. This code is not used for targets
15  * that provide a console.
16  */
17
18 #ifdef TARGET_WINDOWS
19 # include <windows.h>
20 # include <windows/apihelp.h>
21 #else
22 # error what
23 #endif
24
25 #include <setjmp.h>
26 #include <signal.h>
27 #include <stdlib.h>
28 #include <string.h>
29 #include <stdint.h>
30 #include <assert.h>
31 #include <stdlib.h>
32 #include <stdarg.h>
33 #include <unistd.h>
34 #include <stdio.h>
35 #include <conio.h>
36 #include <fcntl.h>
37 #include <dos.h>
38
39 #include <hw/cpu/cpu.h>
40 #include <hw/dos/dos.h>
41 #include <hw/dos/dosbox.h>
42 #include <hw/dos/doswin.h>
43 #include <hw/dos/winfcon.h>
44
45 #ifdef WIN_STDOUT_CONSOLE
46
47 /* _export is not valid for Win32. this silences a Watcom linker warning */
48 #if TARGET_MSDOS == 32
49 # define winproc_export
50 #else
51 # define winproc_export _export
52 #endif
53
54 #undef read
55 #undef write
56 #undef getch
57 #undef isatty
58
59 #define KBSIZE          256
60
61 static char             _win_WindowProcClass[128];
62
63 /* If we stick all these variables in the data segment and reference
64  * them directly, then we'll work from a single instance, but run into
65  * problems with who's data segment to use once we run in multiple
66  * instances. The problem, is that when an application creates a
67  * window of our class, the Window Proc is not guaranteed to be called
68  * with our DS segment/selector. In fact, it often seems to be the
69  * data segment of the first instance by which the window class was
70  * created. And under Windows 3.0, unless you used __loadds and
71  * MakeProcInstance, the DS segment could be any random segment
72  * that happened to be there when you were called.
73  *
74  * Our Window Proc below absolves itself of these problems by storing
75  * the pointer to the context in the Window data associated with the
76  * window (GetWindowLong/SetWindowLong), then using only that context
77  * pointer for maintaining itself.
78  *
79  * This DS segment limitation only affects the Window procedure and
80  * any functions called by the Window procedure. Other parts, like
81  * WinMain, do not have to worry about whether DS is correct and the
82  * data segment will always be the current instance running.
83  *
84  * Note that the above limitations are only an issue for the Win16
85  * world. The Win32 world is free from this hell and so we only
86  * have to maintain one context structure. */
87 typedef struct _win_console_ctx {
88         char            console[80*25];
89         char            _win_kb[KBSIZE];
90         int             conHeight,conWidth;
91         int             _win_kb_i,_win_kb_o;
92         int             monoSpaceFontHeight;
93 #if TARGET_MSDOS == 32 && defined(WIN386)
94         short int       monoSpaceFontWidth;
95 #else
96         int             monoSpaceFontWidth;
97 #endif
98         HFONT           monoSpaceFont;
99         int             pendingSigInt;
100         int             userReqClose;
101         int             allowClose;
102         int             conX,conY;
103         jmp_buf         exit_jmp;
104         HWND            hwndMain;
105         int             myCaret;
106 #if TARGET_MSDOS == 16 || (TARGET_MSDOS == 32 && defined(WIN386))
107         WORD            my_ds;
108 #endif  
109 };
110
111 HINSTANCE                       _win_hInstance;
112 static struct _win_console_ctx  _this_console;
113 static char                     temprintf[1024];
114
115 #if TARGET_MSDOS == 32 && defined(WIN386)
116 # define USER_GWW_CTX                   0
117 # define USER_GWW_MAX                   6
118 #elif TARGET_MSDOS == 16
119 # define USER_GWW_CTX                   0
120 # define USER_GWW_MAX                   4
121 #else
122 # define USER_GWW_MAX                   0
123 #endif
124 #define USER_GCW_MAX                    0
125
126 HWND _win_hwnd() {
127         return _this_console.hwndMain;
128 }
129
130 int _win_kb_insert(struct _win_console_ctx FAR *ctx,char c) {
131         if ((ctx->_win_kb_i+1)%KBSIZE == ctx->_win_kb_o) {
132                 MessageBeep(-1);
133                 return -1;
134         }
135
136         ctx->_win_kb[ctx->_win_kb_i] = c;
137         if (++ctx->_win_kb_i >= KBSIZE) ctx->_win_kb_i = 0;
138         return 0;
139 }
140
141 void _win_sigint() {
142         void (*sig)(int x) = signal(SIGINT,SIG_DFL);
143         if (sig != SIG_IGN && sig != SIG_DFL) sig(SIGINT);
144         signal(SIGINT,sig);
145         if (sig == SIG_DFL) longjmp(_this_console.exit_jmp,1);
146 }
147
148 void _win_sigint_post(struct _win_console_ctx FAR *ctx) {
149         /* because doing a longjmp() out of a Window proc is very foolish */
150         ctx->pendingSigInt = 1;
151 }
152
153 #if ((TARGET_MSDOS == 16 && TARGET_WINDOWS < 31) || (TARGET_MSDOS == 32 && defined(WIN386)))
154 FARPROC _win_WindowProc_MPI;
155 #endif
156 /* NTS: Win16 only: DS (data segment) is NOT necessarily the data segment of the instance
157  *      that spawned the window! Any attempt to access local variables will likely refer
158  *      to the copy in the first instance */
159 /* NTS: All code in this routine deliberately does not refer to the local data segment, unless it
160  *      has to (which it does through the segment value in the context). This reduces problems with
161  *      the screwy callback design in Windows 3.0/3.1. */
162 /* NTS: Do NOT use __loadds on this function prototype. It will seem to work, but because __loadds
163  *      reloads the (cached) instance data segment it will cause all instances to crash when you
164  *      spawn multiple instances and then close the first one you spawned. NOT using __loadds
165  *      removes that crash. */
166 WindowProcType_NoLoadDS winproc_export _win_WindowProc(HWND hwnd,UINT message,WPARAM wparam,LPARAM lparam) {
167 #if TARGET_MSDOS == 32 && defined(WIN386)
168         struct _win_console_ctx FAR *_ctx_console;
169         {
170                 unsigned short s = GetWindowWord(hwnd,USER_GWW_CTX);
171                 unsigned int o = GetWindowLong(hwnd,USER_GWW_CTX+2);
172                 _ctx_console = (void far *)MK_FP(s,o);
173         }
174         if (_ctx_console == NULL) return DefWindowProc(hwnd,message,wparam,lparam);
175 #elif TARGET_MSDOS == 16
176         struct _win_console_ctx FAR *_ctx_console;
177         _ctx_console = (void far *)GetWindowLong(hwnd,USER_GWW_CTX);
178         if (_ctx_console == NULL) return DefWindowProc(hwnd,message,wparam,lparam);
179 #else
180 # define _ctx_console (&_this_console)
181 #endif
182
183         if (message == WM_GETMINMAXINFO) {
184 #if TARGET_MSDOS == 32 && defined(WIN386) /* Watcom Win386 does NOT translate LPARAM for us */
185                 MINMAXINFO FAR *mm = (MINMAXINFO FAR*)win386_help_MapAliasToFlat(lparam);
186                 if (mm == NULL) return DefWindowProc(hwnd,message,wparam,lparam);
187 #else
188                 MINMAXINFO FAR *mm = (MINMAXINFO FAR*)(lparam);
189 #endif
190                 mm->ptMaxSize.x = (_ctx_console->monoSpaceFontWidth * _ctx_console->conWidth) +
191                         (2 * GetSystemMetrics(SM_CXFRAME));
192                 mm->ptMaxSize.y = (_ctx_console->monoSpaceFontHeight * _ctx_console->conHeight) +
193                         (2 * GetSystemMetrics(SM_CYFRAME)) + GetSystemMetrics(SM_CYCAPTION);
194                 mm->ptMinTrackSize.x = mm->ptMaxSize.x;
195                 mm->ptMinTrackSize.y = mm->ptMaxSize.y;
196                 mm->ptMaxTrackSize.x = mm->ptMaxSize.x;
197                 mm->ptMaxTrackSize.y = mm->ptMaxSize.y;
198                 return 0;
199         }
200         else if (message == WM_CLOSE) {
201                 if (_ctx_console->allowClose) DestroyWindow(hwnd);
202                 else _win_sigint_post(_ctx_console);
203                 _ctx_console->userReqClose = 1;
204         }
205         else if (message == WM_DESTROY) {
206                 _ctx_console->allowClose = 1;
207                 _ctx_console->userReqClose = 1;
208                 if (_ctx_console->myCaret) {
209                         HideCaret(hwnd);
210                         DestroyCaret();
211                         _ctx_console->myCaret = 0;
212                 }
213
214                 PostQuitMessage(0);
215                 _ctx_console->hwndMain = NULL;
216                 return 0; /* OK */
217         }
218         else if (message == WM_SETCURSOR) {
219                 if (LOWORD(lparam) == HTCLIENT) {
220                         SetCursor(LoadCursor(NULL,IDC_ARROW));
221                         return 1;
222                 }
223                 else {
224                         return DefWindowProc(hwnd,message,wparam,lparam);
225                 }
226         }
227         else if (message == WM_ACTIVATE) {
228                 if (wparam) {
229                         if (!_ctx_console->myCaret) {
230                                 CreateCaret(hwnd,NULL,_ctx_console->monoSpaceFontWidth,_ctx_console->monoSpaceFontHeight);
231                                 SetCaretPos(_ctx_console->conX * _ctx_console->monoSpaceFontWidth,
232                                         _ctx_console->conY * _ctx_console->monoSpaceFontHeight);
233                                 ShowCaret(hwnd);
234                                 _ctx_console->myCaret = 1;
235                         }
236                 }
237                 else {
238                         if (_ctx_console->myCaret) {
239                                 HideCaret(hwnd);
240                                 DestroyCaret();
241                                 _ctx_console->myCaret = 0;
242                         }
243                 }
244
245                 /* BUGFIX: Microsoft Windows 3.1 SDK says "return 0 if we processed the message".
246                  *         Yet if we actually do, we get funny behavior. Like if I minimize another
247                  *         application's window and then activate this app again, every keypress
248                  *         causes Windows to send WM_SYSKEYDOWN/WM_SYSKEYUP. Somehow passing it
249                  *         down to DefWindowProc() solves this. */
250                 return DefWindowProc(hwnd,message,wparam,lparam);
251         }
252         else if (message == WM_CHAR) {
253                 if (wparam > 0 && wparam <= 126) {
254                         if (wparam == 3) {
255                                 /* CTRL+C */
256                                 if (_ctx_console->allowClose) DestroyWindow(hwnd);
257                                 else _win_sigint_post(_ctx_console);
258                         }
259                         else {
260                                 _win_kb_insert(_ctx_console,(char)wparam);
261                         }
262                 }
263         }
264         else if (message == WM_ERASEBKGND) {
265                 RECT um;
266
267                 if (GetUpdateRect(hwnd,&um,FALSE)) {
268                         HBRUSH oldBrush,newBrush;
269                         HPEN oldPen,newPen;
270
271                         newPen = (HPEN)GetStockObject(NULL_PEN);
272                         newBrush = (HBRUSH)GetStockObject(WHITE_BRUSH);
273
274                         oldPen = SelectObject((HDC)wparam,newPen);
275                         oldBrush = SelectObject((HDC)wparam,newBrush);
276
277                         Rectangle((HDC)wparam,um.left,um.top,um.right+1,um.bottom+1);
278
279                         SelectObject((HDC)wparam,oldBrush);
280                         SelectObject((HDC)wparam,oldPen);
281                 }
282
283                 return 1; /* Important: Returning 1 signals to Windows that we processed the message. Windows 3.0 gets really screwed up if we don't! */
284         }
285         else if (message == WM_PAINT) {
286                 RECT um;
287
288                 if (GetUpdateRect(hwnd,&um,TRUE)) {
289                         PAINTSTRUCT ps;
290                         HFONT of;
291                         int y;
292
293                         BeginPaint(hwnd,&ps);
294                         SetBkMode(ps.hdc,OPAQUE);
295                         SetBkColor(ps.hdc,RGB(255,255,255));
296                         SetTextColor(ps.hdc,RGB(0,0,0));
297                         of = (HFONT)SelectObject(ps.hdc,_ctx_console->monoSpaceFont);
298                         for (y=0;y < _ctx_console->conHeight;y++) {
299                                 TextOut(ps.hdc,0,y * _ctx_console->monoSpaceFontHeight,
300                                         _ctx_console->console + (_ctx_console->conWidth * y),
301                                         _ctx_console->conWidth);
302                         }
303                         SelectObject(ps.hdc,of);
304                         EndPaint(hwnd,&ps);
305                 }
306
307                 return 0; /* Return 0 to signal we processed the message */
308         }
309         else {
310                 return DefWindowProc(hwnd,message,wparam,lparam);
311         }
312
313         return 0;
314 }
315
316 int _win_kbhit() {
317         _win_pump();
318         return _this_console._win_kb_i != _this_console._win_kb_o;
319 }
320
321 int _win_getch() {
322         do {
323                 if (_win_kbhit()) {
324                         int c = (int)((unsigned char)_this_console._win_kb[_this_console._win_kb_o]);
325                         if (++_this_console._win_kb_o >= KBSIZE) _this_console._win_kb_o = 0;
326                         return c;
327                 }
328
329                 _win_pump_wait();
330         } while (1);
331
332         return -1;
333 }
334
335 int _win_kb_read(char *p,int sz) {
336         int cnt=0;
337
338         while (sz-- > 0)
339                 *p++ = _win_getch();
340
341         return cnt;
342 }
343
344 int _win_kb_write(const char *p,int sz) {
345         int cnt=0;
346
347         while (sz-- > 0)
348                 _win_putc(*p++);
349
350         return cnt;
351 }
352
353 int _win_read(int fd,void *buf,int sz) {
354         if (fd == 0) return _win_kb_read((char*)buf,sz);
355         else if (fd == 1 || fd == 2) return -1;
356         else return read(fd,buf,sz);
357 }
358
359 int _win_write(int fd,const void *buf,int sz) {
360         if (fd == 0) return -1;
361         else if (fd == 1 || fd == 2) return _win_kb_write(buf,sz);
362         else return write(fd,buf,sz);
363 }
364
365 int _win_isatty(int fd) {
366         if (fd == 0 || fd == 1 || fd == 2) return 1; /* we're emulating one, so, yeah */
367         return isatty(fd);
368 }
369
370 void _win_pump_wait() {
371         MSG msg;
372
373         if (GetMessage(&msg,NULL,0,0)) {
374                 TranslateMessage(&msg);
375                 DispatchMessage(&msg);
376                 while (PeekMessage(&msg,NULL,0,0,PM_REMOVE)) {
377                         TranslateMessage(&msg);
378                         DispatchMessage(&msg);
379                 }
380         }
381
382         if (_this_console.pendingSigInt) {
383                 _this_console.pendingSigInt = 0;
384                 _win_sigint();
385         }
386 }
387
388 void _win_pump() {
389         MSG msg;
390
391 #if TARGET_MSDOS == 16 || (TARGET_MSDOS == 32 && defined(WIN386))
392         /* Hack: Windows has this nice "GetTickCount()" function that has serious problems
393          *       maintaining a count if we don't process the message pump! Doing this
394          *       prevents portions of this code from getting stuck in infinite loops
395          *       waiting for the damn timer to advance. Note that this is a serious
396          *       problem that only plagues Windows 3.1 and earlier. Windows 95 doesn't
397          *       have this problem.  */
398         PostMessage(_this_console.hwndMain,WM_USER,0,0);
399 #endif
400         if (PeekMessage(&msg,NULL,0,0,PM_REMOVE)) {
401                 do {
402                         TranslateMessage(&msg);
403                         DispatchMessage(&msg);
404                 } while (PeekMessage(&msg,NULL,0,0,PM_REMOVE));
405         }
406
407         if (_this_console.pendingSigInt) {
408                 _this_console.pendingSigInt = 0;
409                 _win_sigint();
410         }
411 }
412
413 void _win_update_cursor() {
414         if (_this_console.myCaret)
415                 SetCaretPos(_this_console.conX * _this_console.monoSpaceFontWidth,
416                         _this_console.conY * _this_console.monoSpaceFontHeight);
417 }
418
419 void _win_redraw_line_row() {
420         if (_this_console.conY >= 0 && _this_console.conY < _this_console.conHeight) {
421                 HDC hdc = GetDC(_this_console.hwndMain);
422                 HFONT of;
423
424                 SetBkMode(hdc,OPAQUE);
425                 SetBkColor(hdc,RGB(255,255,255));
426                 SetTextColor(hdc,RGB(0,0,0));
427                 of = (HFONT)SelectObject(hdc,_this_console.monoSpaceFont);
428                 if (_this_console.myCaret) HideCaret(_this_console.hwndMain);
429                 TextOut(hdc,0,_this_console.conY * _this_console.monoSpaceFontHeight,
430                         _this_console.console + (_this_console.conWidth * _this_console.conY),_this_console.conWidth);
431                 if (_this_console.myCaret) ShowCaret(_this_console.hwndMain);
432                 SelectObject(hdc,of);
433                 ReleaseDC(_this_console.hwndMain,hdc);
434         }
435 }
436
437 void _win_redraw_line_row_partial(int x1,int x2) {
438         if (x1 >= x2) return;
439
440         if (_this_console.conY >= 0 && _this_console.conY < _this_console.conHeight) {
441                 HDC hdc = GetDC(_this_console.hwndMain);
442                 HFONT of;
443
444                 SetBkMode(hdc,OPAQUE);
445                 SetBkColor(hdc,RGB(255,255,255));
446                 SetTextColor(hdc,RGB(0,0,0));
447                 of = (HFONT)SelectObject(hdc,_this_console.monoSpaceFont);
448                 if (_this_console.myCaret) HideCaret(_this_console.hwndMain);
449                 TextOut(hdc,x1 * _this_console.monoSpaceFontWidth,_this_console.conY * _this_console.monoSpaceFontHeight,
450                         _this_console.console + (_this_console.conWidth * _this_console.conY) + x1,x2 - x1);
451                 if (_this_console.myCaret) ShowCaret(_this_console.hwndMain);
452                 SelectObject(hdc,of);
453                 ReleaseDC(_this_console.hwndMain,hdc);
454         }
455 }
456
457 void _win_scrollup() {
458         HDC hdc = GetDC(_this_console.hwndMain);
459         if (_this_console.myCaret) HideCaret(_this_console.hwndMain);
460         BitBlt(hdc,0,0,_this_console.conWidth * _this_console.monoSpaceFontWidth,
461                 _this_console.conHeight * _this_console.monoSpaceFontHeight,hdc,
462                 0,_this_console.monoSpaceFontHeight,SRCCOPY);
463         if (_this_console.myCaret) ShowCaret(_this_console.hwndMain);
464         ReleaseDC(_this_console.hwndMain,hdc);
465
466         memmove(_this_console.console,_this_console.console+_this_console.conWidth,
467                 (_this_console.conHeight-1)*_this_console.conWidth);
468         memset(_this_console.console+((_this_console.conHeight-1)*_this_console.conWidth),
469                 ' ',_this_console.conWidth);
470 }
471
472 void _win_newline() {
473         _this_console.conX = 0;
474         if ((_this_console.conY+1) == _this_console.conHeight) {
475                 _win_redraw_line_row();
476                 _win_scrollup();
477                 _win_redraw_line_row();
478                 _win_update_cursor();
479                 _gdi_pause();
480         }
481         else {
482                 _win_redraw_line_row();
483                 _this_console.conY++;
484         }
485 }
486
487 /* write to the console. does NOT redraw the screen unless we get a newline or we need to scroll up */
488 void _win_putc(char c) {
489         if (c == 10) {
490                 _win_newline();
491         }
492         else if (c == 13) {
493                 _this_console.conX = 0;
494                 _win_redraw_line_row();
495                 _win_update_cursor();
496                 _gdi_pause();
497         }
498         else {
499                 if (_this_console.conX < _this_console.conWidth)
500                         _this_console.console[(_this_console.conY*_this_console.conWidth)+_this_console.conX] = c;
501                 if (++_this_console.conX == _this_console.conWidth)
502                         _win_newline();
503         }
504 }
505
506 size_t _win_printf(const char *fmt,...) {
507         int fX = _this_console.conX;
508         va_list va;
509         char *t;
510
511         va_start(va,fmt);
512         vsnprintf(temprintf,sizeof(temprintf)-1,fmt,va);
513         va_end(va);
514
515         t = temprintf;
516         if (*t != 0) {
517                 while (*t != 0) {
518                         if (*t == 13 || *t == 10) fX = 0;
519                         _win_putc(*t++);
520                 }
521                 if (fX <= _this_console.conX) _win_redraw_line_row_partial(fX,_this_console.conX);
522                 _win_update_cursor();
523         }
524
525         _win_pump();
526         return 0;
527 }
528
529 /* HACK: I don't know if real systems do this or QEMU is doing something wrong, but apparently if a program
530  *       rapidly prints a lot of text under Windows 3.1 (like the RDTSC test program) it can cause the GDI
531  *       to become 100% focused on TextOut() to the point not even the cursor updates when you move it, and
532  *       keyboard events to become severely stalled. Our solution to this problem is to see if we're running
533  *       under Windows 3.1 or earlier, and if so, purposely slow down our output with a software delay */
534 void _gdi_pause() {
535 #if defined(TARGET_WINDOWS)
536 # if TARGET_MSDOS == 32 && defined(WIN386)
537 # else
538         const DWORD ConDelay = 16UL; /* 16ms */
539 # endif
540 #endif
541
542 #if defined(TARGET_WINDOWS)
543         if (windows_mode != WINDOWS_NT) {
544 # if TARGET_MSDOS == 32 && defined(WIN386)
545                 /* nothing */
546 # else
547 #  if TARGET_MSDOS == 16
548                 if (ToolHelpInit()) {
549                         DWORD base,m;
550                         TIMERINFO ti;
551                         ti.dwSize = sizeof(ti);
552                         if (__TimerCount(&ti)) {
553                                 base = ti.dwmsSinceStart;
554
555                                 do {
556                                         Yield();
557                                         _win_pump();
558                                         if (!__TimerCount(&ti)) break;
559                                         m = ti.dwmsSinceStart;
560                                 } while ((m - base) < ConDelay);
561                         }
562                 }
563                 else {
564 #  else
565                 {
566 #  endif
567                         DWORD base,m;
568
569                         base = GetTickCount();
570                         do {
571                                 Yield();
572                                 _win_pump();
573                                 m = GetTickCount();
574                         } while ((m - base) < ConDelay);
575                 }
576 # endif
577         }
578 #endif
579 }
580
581 /* NOTES:
582  *   For Win16, programmers generally use WINAPI WinMain(...) but WINAPI is defined in such a way
583  *   that it always makes the function prolog return FAR. Unfortunately, when Watcom C's runtime
584  *   calls this function in a memory model that's compact or small, the call is made as if NEAR,
585  *   not FAR. To avoid a GPF or crash on return, we must simply declare it PASCAL instead. */
586 int PASCAL _win_main_con_entry(HINSTANCE hInstance,HINSTANCE hPrevInstance,LPSTR lpCmdLine,int nCmdShow,int (_cdecl *_main_f)(int argc,char**,char**)) {
587         WNDCLASS wnd;
588         MSG msg;
589
590         _win_hInstance = hInstance;
591         snprintf(_win_WindowProcClass,sizeof(_win_WindowProcClass),"_HW_DOS_WINFCON_%lX",(DWORD)hInstance);
592 #if ((TARGET_MSDOS == 16 && TARGET_WINDOWS < 31) || (TARGET_MSDOS == 32 && defined(WIN386)))
593         _win_WindowProc_MPI = MakeProcInstance((FARPROC)_win_WindowProc,hInstance);
594 #endif
595
596         /* clear the console */
597         memset(&_this_console,0,sizeof(_this_console));
598         memset(_this_console.console,' ',sizeof(_this_console.console));
599         _this_console._win_kb_i = _this_console._win_kb_o = 0;
600         _this_console.conHeight = 25;
601         _this_console.conWidth = 80;
602         _this_console.conX = 0;
603         _this_console.conY = 0;
604 #if TARGET_MSDOS == 16 || (TARGET_MSDOS == 32 && defined(WIN386))
605         {
606                 WORD s=0;
607
608                 __asm {
609                         mov     ax,ds
610                         mov     s,ax
611                 }
612                 _this_console.my_ds = s;
613         }
614 #endif
615
616         /* we need to know at this point what DOS/Windows combination we're running under */
617         probe_dos();
618         detect_windows();
619
620         /* we want each instance to have it's own WNDCLASS, even though Windows (Win16) considers them all instances
621          * coming from the same HMODULE. In Win32, there is no such thing as a "previous instance" anyway */
622         wnd.style = CS_HREDRAW|CS_VREDRAW;
623 #if ((TARGET_MSDOS == 16 && TARGET_WINDOWS < 31) || (TARGET_MSDOS == 32 && defined(WIN386)))
624         wnd.lpfnWndProc = (WNDPROC)_win_WindowProc_MPI;
625 #else
626         wnd.lpfnWndProc = _win_WindowProc;
627 #endif
628         wnd.cbClsExtra = USER_GCW_MAX;
629         wnd.cbWndExtra = USER_GWW_MAX;
630         wnd.hInstance = hInstance;
631         wnd.hIcon = NULL;
632         wnd.hCursor = NULL;
633         wnd.hbrBackground = NULL;
634         wnd.lpszMenuName = NULL;
635         wnd.lpszClassName = _win_WindowProcClass;
636
637         if (!RegisterClass(&wnd)) {
638                 MessageBox(NULL,"Unable to register Window class","Oops!",MB_OK);
639                 return 1;
640         }
641
642 /* Use the full path of our EXE image by default */
643         {
644                 char title[256];
645
646                 if (!GetModuleFileName(hInstance,title,sizeof(title)-1))
647                         strcpy(title,"<unknown>");
648
649                 _this_console.hwndMain = CreateWindow(_win_WindowProcClass,title,
650                         WS_OVERLAPPEDWINDOW,
651                         CW_USEDEFAULT,CW_USEDEFAULT,
652                         100,40,
653                         NULL,NULL,
654                         hInstance,NULL);
655         }
656
657         if (!_this_console.hwndMain) {
658                 MessageBox(NULL,"Unable to create window","Oops!",MB_OK);
659                 return 1;
660         }
661
662 #if TARGET_MSDOS == 32 && defined(WIN386)
663         /* our Win386 hack needs the address of our console context */
664         SetWindowWord(_this_console.hwndMain,USER_GWW_CTX,(WORD)FP_SEG(&_this_console));
665         SetWindowLong(_this_console.hwndMain,USER_GWW_CTX+2,(DWORD)FP_OFF(&_this_console));
666 #elif TARGET_MSDOS == 16
667         /* our Win16 hack needs the address of our console context */
668         SetWindowLong(_this_console.hwndMain,USER_GWW_CTX,(DWORD)(&_this_console));
669 #endif
670
671         /* Create the monospace font we use for terminal display */
672         {
673                 _this_console.monoSpaceFont = CreateFont(-12,0,0,0,FW_NORMAL,FALSE,FALSE,FALSE,DEFAULT_CHARSET,OUT_DEFAULT_PRECIS,CLIP_DEFAULT_PRECIS,DEFAULT_QUALITY,FIXED_PITCH | FF_DONTCARE,"Terminal");
674                 if (!_this_console.monoSpaceFont) {
675                         MessageBox(NULL,"Unable to create Font","Oops!",MB_OK);
676                         return 1;
677                 }
678
679                 {
680                         HWND hwnd = GetDesktopWindow();
681                         HDC hdc = GetDC(hwnd);
682                         _this_console.monoSpaceFontHeight = 12;
683                         if (!GetCharWidth(hdc,'A','A',&_this_console.monoSpaceFontWidth)) _this_console.monoSpaceFontWidth = 9;
684                         ReleaseDC(hwnd,hdc);
685                 }
686         }
687
688         ShowWindow(_this_console.hwndMain,nCmdShow);
689         UpdateWindow(_this_console.hwndMain);
690         SetWindowPos(_this_console.hwndMain,HWND_TOP,0,0,
691                 (_this_console.monoSpaceFontWidth * _this_console.conWidth) +
692                         (2 * GetSystemMetrics(SM_CXFRAME)),
693                 (_this_console.monoSpaceFontHeight * _this_console.conHeight) +
694                         (2 * GetSystemMetrics(SM_CYFRAME)) + GetSystemMetrics(SM_CYCAPTION),
695                 SWP_NOMOVE);
696
697         if (setjmp(_this_console.exit_jmp) == 0)
698                 _main_f(0,NULL,NULL); /* <- FIXME: We need to take the command line and generate argv[]. Also generate envp[] */
699
700         if (!_this_console.userReqClose) {
701                 _win_printf("\n<program terminated>");
702                 _this_console.allowClose = 1;
703                 while (GetMessage(&msg,NULL,0,0)) {
704                         TranslateMessage(&msg);
705                         DispatchMessage(&msg);
706                 }
707         }
708         else {
709                 if (IsWindow(_this_console.hwndMain)) {
710                         DestroyWindow(_this_console.hwndMain);
711                         while (GetMessage(&msg,NULL,0,0)) {
712                                 TranslateMessage(&msg);
713                                 DispatchMessage(&msg);
714                         }
715                 }
716         }
717
718         DeleteObject(_this_console.monoSpaceFont);
719         _this_console.monoSpaceFont = NULL;
720         return 0;
721 }
722 #endif
723