diff --git a/dlls/gdi/printdrv.c b/dlls/gdi/printdrv.c
index 8bd2dcd60562d08f88981656f912bac730066fd3..4ecb1e92a4367e88c2f3a67987fd68d5ae37e93e 100644
--- a/dlls/gdi/printdrv.c
+++ b/dlls/gdi/printdrv.c
@@ -617,15 +617,26 @@ INT16 WINAPI WriteSpool16(HPJOB16 hJob, LPSTR lpData, INT16 cch)
     return nRet;
 }
 
+typedef INT WINAPI (*MSGBOX_PROC)( HWND, LPCSTR, LPCSTR, UINT );
+
 /**********************************************************************
  *           WriteDialog   (GDI.242)
  *
  */
 INT16 WINAPI WriteDialog16(HPJOB16 hJob, LPSTR lpMsg, INT16 cchMsg)
 {
+    HMODULE mod;
+    MSGBOX_PROC pMessageBoxA;
+    INT16 ret = 0;
+
     TRACE("%04x %04x '%s'\n", hJob,  cchMsg, lpMsg);
 
-    return Callout.MessageBoxA(0, lpMsg, "Printing Error", MB_OKCANCEL);
+    if ((mod = GetModuleHandleA("user32.dll")))
+    {
+        if ((pMessageBoxA = (MSGBOX_PROC)GetProcAddress( mod, "MessageBoxA" )))
+            ret = pMessageBoxA(0, lpMsg, "Printing Error", MB_OKCANCEL);
+    }
+    return ret;
 }
 
 
diff --git a/dlls/kernel/comm.c b/dlls/kernel/comm.c
index defa7e041a4925ec5341f49f18225b669afa0d4a..c6da61cd8bd0101c198e62cd92f3a74668a6c6e1 100644
--- a/dlls/kernel/comm.c
+++ b/dlls/kernel/comm.c
@@ -340,7 +340,7 @@ static void CALLBACK comm_notification( ULONG_PTR private )
   /* send notifications, if any */
   if (ptr->wnd && mask) {
     TRACE("notifying %04x: cid=%d, mask=%02x\n", ptr->wnd, cid, mask);
-    Callout.PostMessageA(ptr->wnd, WM_COMMNOTIFY, cid, mask);
+    if (Callout.PostMessageA) Callout.PostMessageA(ptr->wnd, WM_COMMNOTIFY, cid, mask);
   }
 }
 
diff --git a/if1632/thunk.c b/if1632/thunk.c
index 3aa43ec2adc832e0fe9633c879099b9bec9926f0..3a1dbcd885de7de0118a3db7dd3f51ad1c4ad38e 100644
--- a/if1632/thunk.c
+++ b/if1632/thunk.c
@@ -43,7 +43,6 @@ CALLOUT_TABLE Callout = {
     /* GetMessageA */ NULL,
     /* SendMessageA */ NULL,
     /* PostMessageA */ NULL,
-    /* PostAppMessage16 */ NULL,
     /* TranslateMessage */ NULL,
     /* DispatchMessageA */ NULL,
     /* RedrawWindow */ NULL,
@@ -168,7 +167,7 @@ void THUNK_InitCallout(void)
     HMODULE hModule;
     NE_MODULE *pModule;
 
-    hModule = LoadLibraryA( "user32.dll" );
+    hModule = GetModuleHandleA( "user32.dll" );
     if ( hModule )
     {
 #define GETADDR( name )  \
@@ -188,21 +187,21 @@ void THUNK_InitCallout(void)
         GETADDR( MessageBoxW );
 #undef GETADDR
     }
+    else WARN("no 32-bit USER\n");
 
-    pModule = NE_GetPtr( LoadLibrary16( "USER.EXE" ) );
+    pModule = NE_GetPtr( GetModuleHandle16( "USER.EXE" ) );
     if ( pModule )
     {
 #define GETADDR( var, name, thk )  \
         *(FARPROC *)&Callout.var = THUNK_GetCalloutThunk( pModule, name, \
                                                (RELAY)THUNK_CallTo16_##thk )
 
-        GETADDR( PostAppMessage16, "PostAppMessage", word_wwwl );
         GETADDR( FinalUserInit16, "FinalUserInit", word_ );
         GETADDR( InitThreadInput16, "InitThreadInput", word_ww );
         GETADDR( UserYield16, "UserYield", word_ );
         GETADDR( DestroyIcon32, "DestroyIcon32", word_ww );
         GETADDR( UserSignalProc, "SignalProc32", word_lllw );
-
 #undef GETADDR
     }
+    else WARN("no 16-bit USER\n");
 }
diff --git a/include/callback.h b/include/callback.h
index 9ba70165da35615de8174b34b747cc9e85b5c0fc..7813e4015416ef0ed862aa1c9450aead6f9ec67c 100644
--- a/include/callback.h
+++ b/include/callback.h
@@ -31,7 +31,6 @@ typedef struct
     BOOL WINAPI     (*GetMessageA)( MSG*, HWND, UINT, UINT );
     LRESULT WINAPI  (*SendMessageA)( HWND, UINT, WPARAM, LPARAM );
     BOOL WINAPI     (*PostMessageA)( HWND, UINT, WPARAM, LPARAM );
-    BOOL16 WINAPI   (*PostAppMessage16)( HTASK16, UINT16, WPARAM16, LPARAM );
     BOOL WINAPI     (*TranslateMessage)( const MSG *msg );
     LONG WINAPI     (*DispatchMessageA)( const MSG* msg );
     BOOL WINAPI     (*RedrawWindow)( HWND, const RECT *, HRGN, UINT );
diff --git a/include/task.h b/include/task.h
index cb666eb3fb55c2739acae395a927cffa2305928f..75cdc593c9031243cce781541b9f5859700fb4dc 100644
--- a/include/task.h
+++ b/include/task.h
@@ -147,7 +147,7 @@ extern THHOOK *pThhook;
 
 extern BOOL TASK_Create( struct _NE_MODULE *pModule, UINT16 cmdShow,
                          struct _TEB *teb, LPCSTR cmdline, BYTE len );
-extern void TASK_KillTask( HTASK16 hTask );
+extern void TASK_ExitTask(void);
 extern HTASK16 TASK_GetNextTask( HTASK16 hTask );
 extern void TASK_Reschedule(void);
 extern void TASK_InstallTHHook( THHOOK *pNewThook );
diff --git a/loader/dos/dosvm.c b/loader/dos/dosvm.c
index ba52f4a4bd1c52b2cccd2b8a1fe15b23e1868fc9..0097f145d745093801fe2f08effe8f47c86af1c7 100644
--- a/loader/dos/dosvm.c
+++ b/loader/dos/dosvm.c
@@ -420,12 +420,15 @@ void DOSVM_Wait( int read_pipe, HANDLE hObject )
   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 @@ void DOSVM_Wait( int read_pipe, HANDLE hObject )
 	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 e1978cf0697aaba2154ed66623b84ca43fa02c6b..ae2d2980e96e7a20e22133d5a160a182c842d4b8 100644
--- a/loader/module.c
+++ b/loader/module.c
@@ -827,7 +827,8 @@ HINSTANCE WINAPI WinExec( LPCSTR lpCmdLine, UINT nCmdShow )
                         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 @@ HINSTANCE WINAPI LoadModule( LPCSTR name, LPVOID paramBlock )
                         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 4db25a2700f6fe021e582b18f589fa1c37893e02..e6bafa09edee25b28fb4d3c441908bbb244bc580 100644
--- a/loader/task.c
+++ b/loader/task.c
@@ -379,78 +379,62 @@ static void TASK_DeleteTask( HTASK16 hTask )
 /***********************************************************************
  *           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 );
-
-    /* When deleting the current task ... */
-    if ( hTask == hCurrentTask )
-    {
-        DWORD lockCount;
+    TASK_DeleteTask( pTask->hSelf );
 
-        /* ... schedule another one ... */
-        TASK_Reschedule();
-
-        /* ... and completely release the Win16Lock, just in case. */
-        ReleaseThunkLock( &lockCount );
-
-        return;
-    }
+    /* ... schedule another one ... */
+    TASK_Reschedule();
 
-    SYSLEVEL_LeaveWin16Lock();
+    /* ... and completely release the Win16Lock, just in case. */
+    ReleaseThunkLock( &lockCount );
 }
 
 /***********************************************************************
@@ -838,7 +822,7 @@ void WINAPI Yield16(void)
     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 @@ HANDLE WINAPI GetFastQueue16( void )
     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)
diff --git a/miscemu/main.c b/miscemu/main.c
index b8bd8cdb601b8cb5d6d8cccbe50d16e4a307bae4..da547d941483e066093a0c6ad9b8d70c04551141 100644
--- a/miscemu/main.c
+++ b/miscemu/main.c
@@ -23,6 +23,13 @@ void wine_initial_task(void)
     HINSTANCE16 instance;
     STARTUPINFOA info;
 
+    if (!LoadLibraryA( "user32.dll" ))
+    {
+        MESSAGE( "Cannot load user32.dll\n" );
+        ExitProcess( GetLastError() );
+    }
+    THUNK_InitCallout();
+
     GetStartupInfoA( &info );
     if (!(info.dwFlags & STARTF_USESHOWWINDOW)) info.wShowWindow = SW_SHOWNORMAL;
 
diff --git a/objects/palette.c b/objects/palette.c
index 46558190e1fef9d9bd5d4fb8c0b5ee40a27d96c2..3a634aa6a27dbf21f555828c36d555caf49b863c 100644
--- a/objects/palette.c
+++ b/objects/palette.c
@@ -787,14 +787,16 @@ INT16 WINAPI UpdateColors16( HDC16 hDC )
     if (!(dc = DC_GetDCPtr( hDC ))) return 0;
     size = dc->devCaps->sizePalette;
     GDI_ReleaseObj( hDC );
-    hWnd = Callout.WindowFromDC( hDC );
-
-    /* Docs say that we have to remap current drawable pixel by pixel
-     * but it would take forever given the speed of XGet/PutPixel.
-     */
-    if (hWnd && size) 
-        Callout.RedrawWindow( hWnd, NULL, 0, RDW_INVALIDATE );
+    if (Callout.WindowFromDC)
+    {
+        hWnd = Callout.WindowFromDC( hDC );
 
+        /* Docs say that we have to remap current drawable pixel by pixel
+         * but it would take forever given the speed of XGet/PutPixel.
+         */
+        if (hWnd && size)
+            Callout.RedrawWindow( hWnd, NULL, 0, RDW_INVALIDATE );
+    }
     return 0x666;
 }
 
diff --git a/scheduler/process.c b/scheduler/process.c
index 44a56cd1a414b3cc3aa69e511a446ceab11d7cfa..f6bc48a875bcd0f749959e0915464b66f36c9581 100644
--- a/scheduler/process.c
+++ b/scheduler/process.c
@@ -236,39 +236,6 @@ static BOOL process_init( char *argv[] )
 }
 
 
-/***********************************************************************
- *           load_system_dlls
- *
- * Load system DLLs into the initial process (and initialize them)
- */
-static int load_system_dlls(void)
-{
-    /* Load KERNEL */
-    if (!LoadLibraryA( "KERNEL32" )) return 0;
-
-    /* Get pointers to USER routines called by KERNEL */
-    THUNK_InitCallout();
-
-    /* Call FinalUserInit routine */
-    Callout.FinalUserInit16();
-
-    /* Note: The USIG_PROCESS_CREATE signal is supposed to be sent in the
-     *       context of the parent process.  Actually, the USER signal proc
-     *       doesn't really care about that, but it *does* require that the
-     *       startup parameters are correctly set up, so that GetProcessDword
-     *       works.  Furthermore, before calling the USER signal proc the 
-     *       16-bit stack must be set up, which it is only after TASK_Create
-     *       in the case of a 16-bit process. Thus, we send the signal here.
-     */
-    PROCESS_CallUserSignalProc( USIG_PROCESS_CREATE, 0 );
-    PROCESS_CallUserSignalProc( USIG_THREAD_INIT, 0 );
-    PROCESS_CallUserSignalProc( USIG_PROCESS_INIT, 0 );
-    PROCESS_CallUserSignalProc( USIG_PROCESS_LOADED, 0 );
-
-    return 1;
-}
-
-
 /***********************************************************************
  *           build_command_line
  *
@@ -361,14 +328,29 @@ static void start_process(void)
         goto error;
     wm->refCount++;
 
-    /* Load the system dlls */
-    if (!load_system_dlls()) goto error;
-
     EnterCriticalSection( &current_process.crit_section );
     PE_InitTls();
     MODULE_DllProcessAttach( current_process.exe_modref, (LPVOID)1 );
     LeaveCriticalSection( &current_process.crit_section );
 
+    /* Get pointers to USER routines called by KERNEL */
+    THUNK_InitCallout();
+
+    /* Call FinalUserInit routine */
+    if (Callout.FinalUserInit16) Callout.FinalUserInit16();
+
+    /* Note: The USIG_PROCESS_CREATE signal is supposed to be sent in the
+     *       context of the parent process.  Actually, the USER signal proc
+     *       doesn't really care about that, but it *does* require that the
+     *       startup parameters are correctly set up, so that GetProcessDword
+     *       works.  Furthermore, before calling the USER signal proc the 
+     *       16-bit stack must be set up, which it is only after TASK_Create
+     *       in the case of a 16-bit process. Thus, we send the signal here.
+     */
+    PROCESS_CallUserSignalProc( USIG_PROCESS_CREATE, 0 );
+    PROCESS_CallUserSignalProc( USIG_THREAD_INIT, 0 );
+    PROCESS_CallUserSignalProc( USIG_PROCESS_INIT, 0 );
+    PROCESS_CallUserSignalProc( USIG_PROCESS_LOADED, 0 );
     /* Call UserSignalProc ( USIG_PROCESS_RUNNING ... ) only for non-GUI win32 apps */
     if (console_app) PROCESS_CallUserSignalProc( USIG_PROCESS_RUNNING, 0 );
 
diff --git a/scheduler/thread.c b/scheduler/thread.c
index 9647432654afadce2a547f494a37e98a55adb563..4b0f128a71991f264375d344044bb2f93ccf4a86 100644
--- a/scheduler/thread.c
+++ b/scheduler/thread.c
@@ -374,7 +374,7 @@ void WINAPI ExitThread( DWORD code ) /* [in] Exit code for this thread */
     else
     {
         MODULE_DllThreadDetach( NULL );
-        if (!(NtCurrentTeb()->tibflags & TEBF_WIN32)) TASK_KillTask( 0 );
+        if (!(NtCurrentTeb()->tibflags & TEBF_WIN32)) TASK_ExitTask();
         SYSDEPS_ExitThread( code );
     }
 }
diff --git a/win32/except.c b/win32/except.c
index ecfe9331f60806ceb830ac1a6adb2d524febe84f..4ed10333e6126f9ec5dd57df0fa016511279ccc4 100644
--- a/win32/except.c
+++ b/win32/except.c
@@ -282,7 +282,10 @@ void WINAPI FatalAppExit16( UINT16 action, LPCSTR str )
 void WINAPI FatalAppExitA( UINT action, LPCSTR str )
 {
     WARN("AppExit\n");
-    Callout.MessageBoxA( 0, str, NULL, MB_SYSTEMMODAL | MB_OK );
+    if (Callout.MessageBoxA)
+        Callout.MessageBoxA( 0, str, NULL, MB_SYSTEMMODAL | MB_OK );
+    else
+        ERR( "%s\n", debugstr_a(str) );
     ExitProcess(0);
 }
 
@@ -293,6 +296,9 @@ void WINAPI FatalAppExitA( UINT action, LPCSTR str )
 void WINAPI FatalAppExitW( UINT action, LPCWSTR str )
 {
     WARN("AppExit\n");
-    Callout.MessageBoxW( 0, str, NULL, MB_SYSTEMMODAL | MB_OK );
+    if (Callout.MessageBoxW)
+        Callout.MessageBoxW( 0, str, NULL, MB_SYSTEMMODAL | MB_OK );
+    else
+        ERR( "%s\n", debugstr_w(str) );
     ExitProcess(0);
 }