Check all Callouts function pointers for NULL before using them.
Don't load USER dll if not needed by the application.

diff --git a/loader/dos/dosvm.c b/loader/dos/dosvm.c
index ba52f4a..0097f14 100644
--- a/loader/dos/dosvm.c
+++ b/loader/dos/dosvm.c
@@ -420,12 +420,15 @@
   objc=hObject?2:1;
   do {
     /* check for messages (waste time before the response check below) */
-    while (Callout.PeekMessageA(&msg,0,0,0,PM_REMOVE|PM_NOYIELD)) {
-      /* got a message */
-      DOSVM_ProcessMessage(&msg);
-      /* we don't need a TranslateMessage here */
-      Callout.DispatchMessageA(&msg);
-      got_msg = TRUE;
+    if (Callout.PeekMessageA)
+    {
+        while (Callout.PeekMessageA(&msg,0,0,0,PM_REMOVE|PM_NOYIELD)) {
+            /* got a message */
+            DOSVM_ProcessMessage(&msg);
+            /* we don't need a TranslateMessage here */
+            Callout.DispatchMessageA(&msg);
+            got_msg = TRUE;
+        }
     }
     if (!got_msg) {
       /* check for console input */
@@ -448,7 +451,11 @@
 	break;
     }
     /* nothing yet, block while waiting for something to do */
-    waitret=Callout.MsgWaitForMultipleObjects(objc,objs,FALSE,INFINITE,QS_ALLINPUT);
+    if (Callout.MsgWaitForMultipleObjects)
+        waitret = Callout.MsgWaitForMultipleObjects(objc,objs,FALSE,INFINITE,QS_ALLINPUT);
+    else
+        waitret = WaitForMultipleObjects(objc,objs,FALSE,INFINITE);
+
     if (waitret==(DWORD)-1) {
       ERR_(module)("dosvm wait error=%ld\n",GetLastError());
     }
diff --git a/loader/module.c b/loader/module.c
index e1978cf..ae2d298 100644
--- a/loader/module.c
+++ b/loader/module.c
@@ -827,7 +827,8 @@
                         0, NULL, NULL, &startup, &info ))
     {
         /* Give 30 seconds to the app to come up */
-        if (Callout.WaitForInputIdle ( info.hProcess, 30000 ) == 0xFFFFFFFF)
+        if (Callout.WaitForInputIdle &&
+            Callout.WaitForInputIdle( info.hProcess, 30000 ) == 0xFFFFFFFF)
             WARN("WaitForInputIdle failed: Error %ld\n", GetLastError() );
         hInstance = 33;
         /* Close off the handles */
@@ -884,7 +885,8 @@
                         params->lpEnvAddress, NULL, &startup, &info ))
     {
         /* Give 30 seconds to the app to come up */
-        if ( Callout.WaitForInputIdle ( info.hProcess, 30000 ) ==  0xFFFFFFFF ) 
+        if (Callout.WaitForInputIdle &&
+            Callout.WaitForInputIdle( info.hProcess, 30000 ) ==  0xFFFFFFFF )
             WARN("WaitForInputIdle failed: Error %ld\n", GetLastError() );
         hInstance = 33;
         /* Close off the handles */
diff --git a/loader/task.c b/loader/task.c
index 4db25a2..e6bafa0 100644
--- a/loader/task.c
+++ b/loader/task.c
@@ -379,78 +379,62 @@
 /***********************************************************************
  *           TASK_KillTask
  */
-void TASK_KillTask( HTASK16 hTask )
+void TASK_ExitTask(void)
 {
     TDB *pTask; 
+    DWORD lockCount;
 
     /* Enter the Win16Lock to protect global data structures */
     SYSLEVEL_EnterWin16Lock();
 
-    if ( !hTask ) hTask = GetCurrentTask();
-    pTask = (TDB *)GlobalLock16( hTask );
+    pTask = (TDB *)GlobalLock16( GetCurrentTask() );
     if ( !pTask ) 
     {
         SYSLEVEL_LeaveWin16Lock();
         return;
     }
 
-    TRACE("Killing task %04x\n", hTask );
+    TRACE("Killing task %04x\n", pTask->hSelf );
 
     /* Perform USER cleanup */
 
-    TASK_CallTaskSignalProc( USIG16_TERMINATION, hTask );
+    TASK_CallTaskSignalProc( USIG16_TERMINATION, pTask->hSelf );
     PROCESS_CallUserSignalProc( USIG_PROCESS_EXIT, 0 );
     PROCESS_CallUserSignalProc( USIG_THREAD_EXIT, 0 );
     PROCESS_CallUserSignalProc( USIG_PROCESS_DESTROY, 0 );
 
-    if (nTaskCount <= 1)
+    /* Remove the task from the list to be sure we never switch back to it */
+    TASK_UnlinkTask( pTask->hSelf );
+
+    if (!nTaskCount || (nTaskCount == 1 && hFirstTask == initial_task))
     {
         TRACE("this is the last task, exiting\n" );
+        ERR("done\n");
         ExitKernel16();
     }
 
-    /* FIXME: Hack! Send a message to the initial task so that
-     * the GetMessage wakes up and the initial task can check whether
-     * it is the only remaining one and terminate itself ...
-     * The initial task should probably install hooks or something
-     * to get informed about task termination :-/
-     */
-    Callout.PostAppMessage16( initial_task, WM_NULL, 0, 0 );
-
-    /* Remove the task from the list to be sure we never switch back to it */
-    TASK_UnlinkTask( hTask );
     if( nTaskCount )
     {
         TDB* p = (TDB *)GlobalLock16( hFirstTask );
         while( p )
         {
-            if( p->hYieldTo == hTask ) p->hYieldTo = 0;
+            if( p->hYieldTo == pTask->hSelf ) p->hYieldTo = 0;
             p = (TDB *)GlobalLock16( p->hNext );
         }
     }
 
     pTask->nEvents = 0;
 
-    if ( hLockedTask == hTask )
+    if ( hLockedTask == pTask->hSelf )
         hLockedTask = 0;
 
-    TASK_DeleteTask( hTask );
+    TASK_DeleteTask( pTask->hSelf );
 
-    /* When deleting the current task ... */
-    if ( hTask == hCurrentTask )
-    {
-        DWORD lockCount;
+    /* ... schedule another one ... */
+    TASK_Reschedule();
 
-        /* ... schedule another one ... */
-        TASK_Reschedule();
-
-        /* ... and completely release the Win16Lock, just in case. */
-        ReleaseThunkLock( &lockCount );
-
-        return;
-    }
-
-    SYSLEVEL_LeaveWin16Lock();
+    /* ... and completely release the Win16Lock, just in case. */
+    ReleaseThunkLock( &lockCount );
 }
 
 /***********************************************************************
@@ -838,7 +822,7 @@
     TDB *pCurTask = (TDB *)GlobalLock16( GetCurrentTask() );
 
     if (pCurTask) pCurTask->hYieldTo = 0;
-    if (pCurTask && pCurTask->hQueue) Callout.UserYield16();
+    if (pCurTask && pCurTask->hQueue && Callout.UserYield16) Callout.UserYield16();
     else OldYield16();
 }
 
@@ -1148,7 +1132,7 @@
     TEB *teb = NtCurrentTeb();
     if (!teb) return 0;
 
-    if (!teb->queue)
+    if (!teb->queue && Callout.InitThreadInput16)
         Callout.InitThreadInput16( 0, THREAD_IsWin16(teb)? 4 : 5 );
 
     if (!teb->queue)