Keep track of per-column information inside the listview.
[wine] / dlls / winedos / dosvm.c
1 /*
2  * DOS Virtual Machine
3  *
4  * Copyright 1998 Ove Kåven
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  * Note: This code hasn't been completely cleaned up yet.
21  */
22
23 #include "config.h"
24
25 #include <stdio.h>
26 #include <stdlib.h>
27 #include <string.h>
28 #include <errno.h>
29 #include <fcntl.h>
30 #include <signal.h>
31 #ifdef HAVE_UNISTD_H
32 # include <unistd.h>
33 #endif
34 #ifdef HAVE_SYS_TIME_H
35 # include <sys/time.h>
36 #endif
37 #include <sys/types.h>
38
39 #include "wine/winbase16.h"
40 #include "wine/exception.h"
41 #include "windef.h"
42 #include "winbase.h"
43 #include "wingdi.h"
44 #include "winuser.h"
45 #include "winnt.h"
46 #include "wincon.h"
47
48 #include "msdos.h"
49 #include "file.h"
50 #include "miscemu.h"
51 #include "dosexe.h"
52 #include "dosvm.h"
53 #include "stackframe.h"
54 #include "wine/debug.h"
55 #include "msvcrt/excpt.h"
56
57 WINE_DEFAULT_DEBUG_CHANNEL(int);
58 WINE_DECLARE_DEBUG_CHANNEL(module);
59 WINE_DECLARE_DEBUG_CHANNEL(relay);
60
61 WORD DOSVM_psp = 0;
62 WORD DOSVM_retval = 0;
63 const struct DPMI_segments *DOSVM_dpmi_segments = NULL;
64
65 #ifdef MZ_SUPPORTED
66
67 #ifdef HAVE_SYS_VM86_H
68 # include <sys/vm86.h>
69 #endif
70 #ifdef HAVE_SYS_MMAN_H
71 # include <sys/mman.h>
72 #endif
73
74 #define IF_CLR(ctx)     ((ctx)->EFlags &= ~VIF_MASK)
75 #define IF_SET(ctx)     ((ctx)->EFlags |= VIF_MASK)
76 #define IF_ENABLED(ctx) ((ctx)->EFlags & VIF_MASK)
77 #define SET_PEND(ctx)   ((ctx)->EFlags |= VIP_MASK)
78 #define CLR_PEND(ctx)   ((ctx)->EFlags &= ~VIP_MASK)
79 #define IS_PEND(ctx)    ((ctx)->EFlags & VIP_MASK)
80
81 #undef TRY_PICRETURN
82
83 typedef struct _DOSEVENT {
84   int irq,priority;
85   DOSRELAY relay;
86   void *data;
87   struct _DOSEVENT *next;
88 } DOSEVENT, *LPDOSEVENT;
89
90 static CRITICAL_SECTION qcrit = CRITICAL_SECTION_INIT("DOSVM");
91 static struct _DOSEVENT *pending_event, *current_event;
92 static int sig_sent;
93 static HANDLE event_notifier;
94 static CONTEXT86 *current_context;
95
96 static int DOSVM_SimulateInt( int vect, CONTEXT86 *context, BOOL inwine )
97 {
98   FARPROC16 handler=DOSVM_GetRMHandler(vect);
99
100   /* check for our real-mode hooks */
101   if (vect==0x31) {
102     if (context->SegCs==DOSVM_dpmi_segments->wrap_seg) {
103       /* exit from real-mode wrapper */
104       return -1;
105     }
106     /* we could probably move some other dodgy stuff here too from dpmi.c */
107   }
108   /* check if the call is from our fake BIOS interrupt stubs */
109   if ((context->SegCs==0xf000) && !inwine) {
110     if (vect != (context->Eip/4)) {
111       TRACE("something fishy going on here (interrupt stub is %02lx)\n", context->Eip/4);
112     }
113     TRACE("builtin interrupt %02x has been branched to\n", vect);
114     DOSVM_RealModeInterrupt(vect, context);
115   }
116   /* check if the call goes to an unhooked interrupt */
117   else if (SELECTOROF(handler)==0xf000) {
118     /* if so, call it directly */
119     TRACE("builtin interrupt %02x has been invoked (through vector %02x)\n", OFFSETOF(handler)/4, vect);
120     DOSVM_RealModeInterrupt(OFFSETOF(handler)/4, context);
121   }
122   /* the interrupt is hooked, simulate interrupt in DOS space */
123   else {
124     WORD*stack= PTR_REAL_TO_LIN( context->SegSs, context->Esp );
125     WORD flag=LOWORD(context->EFlags);
126
127     TRACE_(int)("invoking hooked interrupt %02x at %04x:%04x\n", vect,
128                 SELECTOROF(handler), OFFSETOF(handler));
129     if (IF_ENABLED(context)) flag|=IF_MASK;
130     else flag&=~IF_MASK;
131
132     *(--stack)=flag;
133     *(--stack)=context->SegCs;
134     *(--stack)=LOWORD(context->Eip);
135     context->Esp-=6;
136     context->SegCs=SELECTOROF(handler);
137     context->Eip=OFFSETOF(handler);
138     IF_CLR(context);
139   }
140   return 0;
141 }
142
143 #define SHOULD_PEND(x) \
144   (x && ((!current_event) || (x->priority < current_event->priority)))
145
146 static void DOSVM_SendQueuedEvent(CONTEXT86 *context)
147 {
148   LPDOSEVENT event = pending_event;
149
150   if (SHOULD_PEND(event)) {
151     /* remove from "pending" list */
152     pending_event = event->next;
153     /* process event */
154     if (event->irq>=0) {
155       /* it's an IRQ, move it to "current" list */
156       event->next = current_event;
157       current_event = event;
158       TRACE("dispatching IRQ %d\n",event->irq);
159       /* note that if DOSVM_SimulateInt calls an internal interrupt directly,
160        * current_event might be cleared (and event freed) in this very call! */
161       DOSVM_SimulateInt((event->irq<8)?(event->irq+8):(event->irq-8+0x70),context,TRUE);
162     } else {
163       /* callback event */
164       TRACE("dispatching callback event\n");
165       (*event->relay)(context,event->data);
166       free(event);
167     }
168   }
169   if (!SHOULD_PEND(pending_event)) {
170     TRACE("clearing Pending flag\n");
171     CLR_PEND(context);
172   }
173 }
174
175 static void DOSVM_SendQueuedEvents(CONTEXT86 *context)
176 {
177   /* we will send all queued events as long as interrupts are enabled,
178    * but IRQ events will disable interrupts again */
179   while (IS_PEND(context) && IF_ENABLED(context))
180     DOSVM_SendQueuedEvent(context);
181 }
182
183 /***********************************************************************
184  *              QueueEvent (WINEDOS.@)
185  */
186 void WINAPI DOSVM_QueueEvent( INT irq, INT priority, DOSRELAY relay, LPVOID data)
187 {
188   LPDOSEVENT event, cur, prev;
189
190   if (current_context) {
191     EnterCriticalSection(&qcrit);
192     event = malloc(sizeof(DOSEVENT));
193     if (!event) {
194       ERR("out of memory allocating event entry\n");
195       return;
196     }
197     event->irq = irq; event->priority = priority;
198     event->relay = relay; event->data = data;
199
200     /* insert event into linked list, in order *after*
201      * all earlier events of higher or equal priority */
202     cur = pending_event; prev = NULL;
203     while (cur && cur->priority<=priority) {
204       prev = cur;
205       cur = cur->next;
206     }
207     event->next = cur;
208     if (prev) prev->next = event;
209     else pending_event = event;
210
211     /* alert the vm86 about the new event */
212     if (!sig_sent) {
213       TRACE("new event queued, signalling (time=%ld)\n", GetTickCount());
214       kill(dosvm_pid,SIGUSR2);
215       sig_sent++;
216     } else {
217       TRACE("new event queued (time=%ld)\n", GetTickCount());
218     }
219
220     /* Wake up DOSVM_Wait so that it can serve pending events. */
221     SetEvent(event_notifier);
222
223     LeaveCriticalSection(&qcrit);
224   } else {
225     /* DOS subsystem not running */
226     /* (this probably means that we're running a win16 app
227      *  which uses DPMI to thunk down to DOS services) */
228     if (irq<0) {
229       /* callback event, perform it with dummy context */
230       CONTEXT86 context;
231       memset(&context,0,sizeof(context));
232       (*relay)(&context,data);
233     } else {
234       ERR("IRQ without DOS task: should not happen\n");
235     }
236   }
237 }
238
239 static void DOSVM_ProcessConsole(void)
240 {
241   INPUT_RECORD msg;
242   DWORD res;
243   BYTE scan;
244
245   if (ReadConsoleInputA(GetStdHandle(STD_INPUT_HANDLE),&msg,1,&res)) {
246     switch (msg.EventType) {
247     case KEY_EVENT:
248       scan = msg.Event.KeyEvent.wVirtualScanCode;
249       if (!msg.Event.KeyEvent.bKeyDown) scan |= 0x80;
250
251       /* check whether extended bit is set,
252        * and if so, queue the extension prefix */
253       if (msg.Event.KeyEvent.dwControlKeyState & ENHANCED_KEY) {
254         DOSVM_Int09SendScan(0xE0,0);
255       }
256       DOSVM_Int09SendScan(scan,msg.Event.KeyEvent.uChar.AsciiChar);
257       break;
258     case MOUSE_EVENT:
259       DOSVM_Int33Console(&msg.Event.MouseEvent);
260       break;
261     case WINDOW_BUFFER_SIZE_EVENT:
262       FIXME("unhandled WINDOW_BUFFER_SIZE_EVENT.\n");
263       break;
264     case MENU_EVENT:
265       FIXME("unhandled MENU_EVENT.\n");
266       break;
267     case FOCUS_EVENT:
268       FIXME("unhandled FOCUS_EVENT.\n");
269       break;
270     default:
271       FIXME("unknown console event: %d\n", msg.EventType);
272     }
273   }
274 }
275
276 static void DOSVM_ProcessMessage(MSG *msg)
277 {
278   BYTE scan = 0;
279
280   TRACE("got message %04x, wparam=%08x, lparam=%08lx\n",msg->message,msg->wParam,msg->lParam);
281   if ((msg->message>=WM_MOUSEFIRST)&&
282       (msg->message<=WM_MOUSELAST)) {
283     DOSVM_Int33Message(msg->message,msg->wParam,msg->lParam);
284   } else {
285     switch (msg->message) {
286     case WM_KEYUP:
287       scan = 0x80;
288     case WM_KEYDOWN:
289       scan |= (msg->lParam >> 16) & 0x7f;
290
291       /* check whether extended bit is set,
292        * and if so, queue the extension prefix */
293       if (msg->lParam & 0x1000000) {
294         /* FIXME: some keys (function keys) have
295          * extended bit set even when they shouldn't,
296          * should check for them */
297         DOSVM_Int09SendScan(0xE0,0);
298       }
299       DOSVM_Int09SendScan(scan,0);
300       break;
301     }
302   }
303 }
304
305 /***********************************************************************
306  *              Wait (WINEDOS.@)
307  */
308 void WINAPI DOSVM_Wait( INT read_pipe, HANDLE hObject )
309 {
310   MSG msg;
311   DWORD waitret;
312   HANDLE objs[3];
313   int objc;
314   BOOL got_msg = FALSE;
315
316   objs[0]=GetStdHandle(STD_INPUT_HANDLE);
317   objs[1]=event_notifier;
318   objs[2]=hObject;
319   objc=hObject?3:2;
320   do {
321     /* check for messages (waste time before the response check below) */
322     if (PeekMessageA)
323     {
324         while (PeekMessageA(&msg,0,0,0,PM_REMOVE|PM_NOYIELD)) {
325             /* got a message */
326             DOSVM_ProcessMessage(&msg);
327             /* we don't need a TranslateMessage here */
328             DispatchMessageA(&msg);
329             got_msg = TRUE;
330         }
331     }
332 chk_console_input:
333     if (!got_msg) {
334       /* check for console input */
335       INPUT_RECORD msg;
336       DWORD num;
337       if (PeekConsoleInputA(objs[0],&msg,1,&num) && num) {
338         DOSVM_ProcessConsole();
339         got_msg = TRUE;
340       }
341     }
342     if (read_pipe == -1) {
343       /* dispatch pending events */
344       if (SHOULD_PEND(pending_event)) {
345         CONTEXT86 context = *current_context;
346         IF_SET(&context);
347         SET_PEND(&context);
348         DOSVM_SendQueuedEvents(&context);
349         got_msg = TRUE;
350       }
351       if (got_msg) break;
352     } else {
353       fd_set readfds;
354       struct timeval timeout={0,0};
355       /* quick check for response from dosmod
356        * (faster than doing the full blocking wait, if data already available) */
357       FD_ZERO(&readfds); FD_SET(read_pipe,&readfds);
358       if (select(read_pipe+1,&readfds,NULL,NULL,&timeout)>0)
359         break;
360     }
361     /* nothing yet, block while waiting for something to do */
362     if (MsgWaitForMultipleObjects)
363         waitret = MsgWaitForMultipleObjects(objc,objs,FALSE,INFINITE,QS_ALLINPUT);
364     else
365         waitret = WaitForMultipleObjects(objc,objs,FALSE,INFINITE);
366
367     if (waitret==(DWORD)-1) {
368       ERR_(module)("dosvm wait error=%ld\n",GetLastError());
369     }
370     if ((read_pipe != -1) && hObject) {
371       if (waitret==(WAIT_OBJECT_0+2)) break;
372     }
373     if (waitret==WAIT_OBJECT_0)
374       goto chk_console_input;
375   } while (TRUE);
376 }
377
378 DWORD WINAPI DOSVM_Loop( HANDLE hThread )
379 {
380   HANDLE objs[2];
381   MSG msg;
382   DWORD waitret;
383
384   objs[0] = GetStdHandle(STD_INPUT_HANDLE);
385   objs[1] = hThread;
386
387   for(;;) {
388       TRACE_(int)("waiting for action\n");
389       waitret = MsgWaitForMultipleObjects(2, objs, FALSE, INFINITE, QS_ALLINPUT);
390       if (waitret == WAIT_OBJECT_0) {
391           DOSVM_ProcessConsole();
392       }
393       else if (waitret == WAIT_OBJECT_0 + 1) {
394          DWORD rv;
395          if(!GetExitCodeThread(hThread, &rv)) {
396              ERR("Failed to get thread exit code!\n");
397              rv = 0;
398          }
399          return rv;
400       }
401       else if (waitret == WAIT_OBJECT_0 + 2) {
402           while (PeekMessageA(&msg,0,0,0,PM_REMOVE)) {
403               if (msg.hwnd) {
404                   /* it's a window message */
405                   DOSVM_ProcessMessage(&msg);
406                   DispatchMessageA(&msg);
407               } else {
408                   /* it's a thread message */
409                   switch (msg.message) {
410                   case WM_QUIT:
411                       /* stop this madness!! */
412                       return 0;
413                   case WM_USER:
414                       /* run passed procedure in this thread */
415                       /* (sort of like APC, but we signal the completion) */
416                       {
417                           DOS_SPC *spc = (DOS_SPC *)msg.lParam;
418                           TRACE_(int)("calling %p with arg %08lx\n", spc->proc, spc->arg);
419                           (spc->proc)(spc->arg);
420                           TRACE_(int)("done, signalling event %x\n", msg.wParam);
421                           SetEvent( (HANDLE)msg.wParam );
422                       }
423                       break;
424                   }
425               }
426           }
427       }
428       else
429       {
430           ERR_(int)("MsgWaitForMultipleObjects returned unexpected value.\n");
431           return 0;
432       }
433   }
434 }
435
436 static WINE_EXCEPTION_FILTER(exception_handler)
437 {
438   EXCEPTION_RECORD *rec = GetExceptionInformation()->ExceptionRecord;
439   CONTEXT *context = GetExceptionInformation()->ContextRecord;
440   int ret, arg = rec->ExceptionInformation[0];
441
442   switch(rec->ExceptionCode) {
443   case EXCEPTION_VM86_INTx:
444     if (TRACE_ON(relay)) {
445       DPRINTF("Call DOS int 0x%02x ret=%04lx:%04lx\n",
446               arg, context->SegCs, context->Eip );
447       DPRINTF(" eax=%08lx ebx=%08lx ecx=%08lx edx=%08lx esi=%08lx edi=%08lx\n",
448               context->Eax, context->Ebx, context->Ecx, context->Edx,
449               context->Esi, context->Edi );
450       DPRINTF(" ebp=%08lx esp=%08lx ds=%04lx es=%04lx fs=%04lx gs=%04lx flags=%08lx\n",
451               context->Ebp, context->Esp, context->SegDs, context->SegEs,
452               context->SegFs, context->SegGs, context->EFlags );
453       }
454     ret = DOSVM_SimulateInt(arg, context, FALSE);
455     if (TRACE_ON(relay)) {
456       DPRINTF("Ret  DOS int 0x%02x ret=%04lx:%04lx\n",
457               arg, context->SegCs, context->Eip );
458       DPRINTF(" eax=%08lx ebx=%08lx ecx=%08lx edx=%08lx esi=%08lx edi=%08lx\n",
459               context->Eax, context->Ebx, context->Ecx, context->Edx,
460               context->Esi, context->Edi );
461       DPRINTF(" ebp=%08lx esp=%08lx ds=%04lx es=%04lx fs=%04lx gs=%04lx flags=%08lx\n",
462               context->Ebp, context->Esp, context->SegDs, context->SegEs,
463               context->SegFs, context->SegGs, context->EFlags );
464     }
465     return ret ? EXCEPTION_EXECUTE_HANDLER : EXCEPTION_CONTINUE_EXECUTION;
466
467   case EXCEPTION_VM86_STI:
468   /* case EXCEPTION_VM86_PICRETURN: */
469     IF_SET(context);
470     EnterCriticalSection(&qcrit);
471     sig_sent++;
472     while (NtCurrentTeb()->alarms) {
473       DOSVM_QueueEvent(0,DOS_PRIORITY_REALTIME,NULL,NULL);
474       /* hmm, instead of relying on this signal counter, we should
475        * probably check how many ticks have *really* passed, probably using
476        * QueryPerformanceCounter() or something like that */
477       InterlockedDecrement(&(NtCurrentTeb()->alarms));
478     }
479     TRACE_(int)("context=%p, current=%p\n", context, current_context);
480     TRACE_(int)("cs:ip=%04lx:%04lx, ss:sp=%04lx:%04lx\n", context->SegCs, context->Eip, context->SegSs, context->Esp);
481     if (!ISV86(context)) {
482       ERR_(int)("@#&*%%, winedos signal handling is *still* messed up\n");
483     }
484     TRACE_(int)("DOS task enabled interrupts %s events pending, sending events (time=%ld)\n", IS_PEND(context)?"with":"without", GetTickCount());
485     DOSVM_SendQueuedEvents(context);
486     sig_sent=0;
487     LeaveCriticalSection(&qcrit);
488     return EXCEPTION_CONTINUE_EXECUTION;
489   }
490   return EXCEPTION_CONTINUE_SEARCH;
491 }
492
493 int WINAPI DOSVM_Enter( CONTEXT86 *context )
494 {
495   CONTEXT86 *old_context = current_context;
496
497   current_context = context;
498   __TRY
499   {
500     __wine_enter_vm86( context );
501     TRACE_(module)( "vm86 returned: %s\n", strerror(errno) );
502   }
503   __EXCEPT(exception_handler)
504   {
505     TRACE_(module)( "leaving vm86 mode\n" );
506   }
507   __ENDTRY
508   current_context = old_context;
509   return 0;
510 }
511
512 /***********************************************************************
513  *              OutPIC (WINEDOS.@)
514  */
515 void WINAPI DOSVM_PIC_ioport_out( WORD port, BYTE val)
516 {
517     LPDOSEVENT event;
518
519     if ((port==0x20) && (val==0x20)) {
520       EnterCriticalSection(&qcrit);
521       if (current_event) {
522         /* EOI (End Of Interrupt) */
523         TRACE("received EOI for current IRQ, clearing\n");
524         event = current_event;
525         current_event = event->next;
526         if (event->relay)
527         (*event->relay)(NULL,event->data);
528         free(event);
529
530         if (pending_event) {
531           /* another event is pending, which we should probably
532            * be able to process now */
533           TRACE("another event pending, setting flag\n");
534           current_context->EFlags |= VIP_MASK;
535         }
536       } else {
537         WARN("EOI without active IRQ\n");
538       }
539       LeaveCriticalSection(&qcrit);
540     } else {
541       FIXME("unrecognized PIC command %02x\n",val);
542     }
543 }
544
545 /***********************************************************************
546  *              SetTimer (WINEDOS.@)
547  */
548 void WINAPI DOSVM_SetTimer( UINT ticks )
549 {
550   struct itimerval tim;
551
552   if (dosvm_pid) {
553     /* the PC clocks ticks at 1193180 Hz */
554     tim.it_interval.tv_sec=0;
555     tim.it_interval.tv_usec=MulDiv(ticks,1000000,1193180);
556     /* sanity check */
557     if (!tim.it_interval.tv_usec) tim.it_interval.tv_usec=1;
558     /* first tick value */
559     tim.it_value = tim.it_interval;
560     TRACE_(int)("setting timer tick delay to %ld us\n", tim.it_interval.tv_usec);
561     setitimer(ITIMER_REAL, &tim, NULL);
562   }
563 }
564
565 /***********************************************************************
566  *              GetTimer (WINEDOS.@)
567  */
568 UINT WINAPI DOSVM_GetTimer( void )
569 {
570   struct itimerval tim;
571
572   if (dosvm_pid) {
573     getitimer(ITIMER_REAL, &tim);
574     return MulDiv(tim.it_value.tv_usec,1193180,1000000);
575   }
576   return 0;
577 }
578
579 #else /* !MZ_SUPPORTED */
580
581 /***********************************************************************
582  *              Enter (WINEDOS.@)
583  */
584 INT WINAPI DOSVM_Enter( CONTEXT86 *context )
585 {
586  ERR_(module)("DOS realmode not supported on this architecture!\n");
587  return -1;
588 }
589
590 /***********************************************************************
591  *              Wait (WINEDOS.@)
592  */
593 void WINAPI DOSVM_Wait( INT read_pipe, HANDLE hObject) {}
594
595 /***********************************************************************
596  *              OutPIC (WINEDOS.@)
597  */
598 void WINAPI DOSVM_PIC_ioport_out( WORD port, BYTE val) {}
599
600 /***********************************************************************
601  *              SetTimer (WINEDOS.@)
602  */
603 void WINAPI DOSVM_SetTimer( UINT ticks ) {}
604
605 /***********************************************************************
606  *              GetTimer (WINEDOS.@)
607  */
608 UINT WINAPI DOSVM_GetTimer( void ) { return 0; }
609
610 /***********************************************************************
611  *              QueueEvent (WINEDOS.@)
612  */
613 void WINAPI DOSVM_QueueEvent( INT irq, INT priority, DOSRELAY relay, LPVOID data)
614 {
615   if (irq<0) {
616     /* callback event, perform it with dummy context */
617     CONTEXT86 context;
618     memset(&context,0,sizeof(context));
619     (*relay)(&context,data);
620   } else {
621     ERR("IRQ without DOS task: should not happen\n");
622   }
623 }
624
625 #endif
626
627 /**********************************************************************
628  *          DOSVM_GetRMHandler
629  *
630  * Return the real mode interrupt vector for a given interrupt.
631  */
632 FARPROC16 DOSVM_GetRMHandler( BYTE intnum )
633 {
634     return ((FARPROC16*)0)[intnum];
635 }
636
637
638 /**********************************************************************
639  *          DOSVM_SetRMHandler
640  *
641  * Set the real mode interrupt handler for a given interrupt.
642  */
643 void DOSVM_SetRMHandler( BYTE intnum, FARPROC16 handler )
644 {
645     TRACE("Set real mode interrupt vector %02x <- %04x:%04x\n",
646                  intnum, HIWORD(handler), LOWORD(handler) );
647     ((FARPROC16*)0)[intnum] = handler;
648 }
649
650
651 static const INTPROC real_mode_handlers[] =
652 {
653     /* 00 */ 0, 0, 0, 0, 0, 0, 0, 0,
654     /* 08 */ 0, DOSVM_Int09Handler, 0, 0, 0, 0, 0, 0,
655     /* 10 */ DOSVM_Int10Handler, INT_Int11Handler, INT_Int12Handler, INT_Int13Handler,
656              0, INT_Int15Handler, DOSVM_Int16Handler, DOSVM_Int17Handler,
657     /* 18 */ 0, 0, INT_Int1aHandler, 0, 0, 0, 0, 0,
658     /* 20 */ DOSVM_Int20Handler, DOSVM_Int21Handler, 0, 0, 0, INT_Int25Handler, 0, 0,
659     /* 28 */ 0, DOSVM_Int29Handler, INT_Int2aHandler, 0, 0, 0, 0, INT_Int2fHandler,
660     /* 30 */ 0, DOSVM_Int31Handler, 0, DOSVM_Int33Handler, INT_Int34Handler, INT_Int35Handler, INT_Int36Handler, INT_Int37Handler,
661     /* 38 */ INT_Int38Handler, INT_Int39Handler, INT_Int3aHandler, INT_Int3bHandler, INT_Int3cHandler, INT_Int3dHandler, INT_Int3eHandler, 0,
662     /* 40 */ 0, 0, 0, 0, 0, 0, 0, 0,
663     /* 48 */ 0, 0, 0, 0, 0, 0, 0, 0,
664     /* 50 */ 0, 0, 0, 0, 0, 0, 0, 0,
665     /* 58 */ 0, 0, 0, 0, 0, 0, 0, 0,
666     /* 60 */ 0, 0, 0, 0, 0, 0, 0, DOSVM_Int67Handler
667 };
668
669
670 /**********************************************************************
671  *          DOSVM_RealModeInterrupt
672  *
673  * Handle real mode interrupts
674  */
675 void DOSVM_RealModeInterrupt( BYTE intnum, CONTEXT86 *context )
676 {
677     if (intnum < sizeof(real_mode_handlers)/sizeof(INTPROC) && real_mode_handlers[intnum])
678         (*real_mode_handlers[intnum])(context);
679     else
680     {
681         FIXME("Unknown Interrupt in DOS mode: 0x%x\n", intnum);
682         FIXME("    eax=%08lx ebx=%08lx ecx=%08lx edx=%08lx\n",
683               context->Eax, context->Ebx, context->Ecx, context->Edx);
684         FIXME("    esi=%08lx edi=%08lx ds=%04lx es=%04lx\n",
685               context->Esi, context->Edi, context->SegDs, context->SegEs );
686     }
687 }
688
689
690 /**********************************************************************
691  *          DOSVM_Init
692  */
693 BOOL WINAPI DOSVM_Init( HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved )
694 {
695     TRACE_(module)("(%p,%ld,%p)\n", hinstDLL, fdwReason, lpvReserved);
696
697     if (fdwReason == DLL_PROCESS_ATTACH)
698     {
699         /* initialize the memory */
700         TRACE("Initializing DOS memory structures\n");
701         DOSMEM_Init( TRUE );
702         DOSDEV_InstallDOSDevices();
703         DOSVM_dpmi_segments = DOSMEM_GetDPMISegments();
704
705 #ifdef MZ_SUPPORTED
706         event_notifier = CreateEventA(NULL, FALSE, FALSE, NULL);
707         if(!event_notifier)
708           ERR("Failed to create event object!\n");
709 #endif
710
711     }
712     return TRUE;
713 }