Run Win32 processes in their own threads.
Process exit sequence adapted.

diff --git a/loader/task.c b/loader/task.c
index 8adcb13..c2724e7 100644
--- a/loader/task.c
+++ b/loader/task.c
@@ -57,7 +57,7 @@
 static HTASK16 hTaskToKill = 0;
 static UINT16 nTaskCount = 0;
 
-static void TASK_YieldToSystem(TDB*);
+static void TASK_YieldToSystem( void );
 
 extern BOOL THREAD_InitDone;
 
@@ -240,48 +240,8 @@
 
     if (pModule->flags & NE_FFLAGS_WIN32)
     {
-        /* FIXME: all this is an ugly hack */
-
-        OFSTRUCT *ofs = (OFSTRUCT *)((char*)(pModule) + (pModule)->fileinfo);
-        LPTHREAD_START_ROUTINE entry = (LPTHREAD_START_ROUTINE)
-                RVA_PTR(pModule->module32, OptionalHeader.AddressOfEntryPoint);
-        
-        /* Create 32-bit MODREF */
-        if ( !PE_CreateModule( pModule->module32, ofs, 0, FALSE ) )
-        {
-            ERR( task, "Could not initialize process\n" );
-            ExitProcess( 1 );
-        }
-
-        /* Initialize Thread-Local Storage */
-        PE_InitTls( pTask->thdb );
-
-	if (PE_HEADER(pModule->module32)->OptionalHeader.Subsystem==IMAGE_SUBSYSTEM_WINDOWS_CUI)
-		AllocConsole();
-
-        MODULE_InitializeDLLs( 0, DLL_PROCESS_ATTACH, (LPVOID)-1 );
-        TRACE(relay, "(entryproc=%p)\n", entry );
-
-#if 1
-        ExitProcess( entry(NULL) );
-#else
-{
-        DWORD size = PE_HEADER(pModule->module32)->OptionalHeader.SizeOfStackReserve;
-        DWORD id;
-        THDB *thdb;
-
-        CreateThread( NULL, size, entry, NULL, 0, &id );
-        thdb = THREAD_IdToTHDB( id );
-
-        while ( thdb->exit_code == 0x103 )
-        {
-            WaitEvent16( 0 );
-            QUEUE_Signal( pTask->hSelf );
-        }
-
-        ExitProcess( thdb->exit_code );
-}
-#endif
+        ERR( task, "Called for Win32 task!\n" );
+        ExitProcess( 1 );
     }
     else if (pModule->dos_image)
     {
@@ -356,7 +316,7 @@
 
     /* Fill the task structure */
 
-    pTask->nEvents       = 1;  /* So the task can be started */
+    pTask->nEvents       = 0;
     pTask->hSelf         = hTask;
     pTask->flags         = 0;
 
@@ -498,6 +458,9 @@
  */
 void TASK_StartTask( HTASK16 hTask )
 {
+    TDB *pTask = (TDB *)GlobalLock16( hTask );
+    if ( !pTask ) return;
+
     /* Add the task to the linked list */
 
     SYSLEVEL_EnterWin16Lock();
@@ -511,15 +474,26 @@
     if ( TASK_AddTaskEntryBreakpoint )
         TASK_AddTaskEntryBreakpoint( hTask );
 
-    /* Get the task up and running. If we ourselves are a 16-bit task,
-       we simply Yield(). If we are 32-bit however, we need to signal
-       the main process somehow (NOT YET IMPLEMENTED!) */
+    /* Get the task up and running. */
 
-    if ( THREAD_IsWin16( THREAD_Current() ) )
-        OldYield16();
+    if ( THREAD_IsWin16( pTask->thdb ) )
+    {
+        pTask->nEvents++;
+
+        /* If we ourselves are a 16-bit task, we simply Yield(). 
+           If we are 32-bit however, we need to signal the scheduler. */
+
+        if ( THREAD_IsWin16( THREAD_Current() ) )
+            OldYield16();
+        else
+            EVENT_WakeUp();
+    }
     else
-        /* wake-up the scheduler waiting in EVENT_WaitNetEvent */
-        EVENT_WakeUp();
+    {
+        /* To start a 32-bit task, we spawn its initial thread. */
+
+        SYSDEPS_SpawnThread( pTask->thdb );
+    }
 }
 
 
@@ -560,37 +534,25 @@
     GlobalFreeAll16( hPDB );
 }
 
-
 /***********************************************************************
- *           TASK_KillCurrentTask
- *
- * Kill the currently running task. As it's not possible to kill the
- * current task like this, it is simply marked for destruction, and will
- * be killed when either TASK_Reschedule or this function is called again 
- * in the context of another task.
+ *           TASK_KillTask
  */
-void TASK_KillCurrentTask( INT16 exitCode )
+void TASK_KillTask( HTASK16 hTask )
 {
-    TDB* pTask = (TDB*) GlobalLock16( GetCurrentTask() );
-    NE_MODULE* pModule = NE_GetPtr( pTask->hModule );
-    if (!pTask) USER_ExitWindows();  /* No current task yet */
+    TDB *pTask; 
 
-    if ( !THREAD_IsWin16( THREAD_Current() ) )
+    /* Enter the Win16Lock to protect global data structures */
+    SYSLEVEL_EnterWin16Lock();
+
+    if ( !hTask ) hTask = GetCurrentTask();
+    pTask = (TDB *)GlobalLock16( hTask );
+    if ( !pTask ) 
     {
-        FIXME(task, "called for Win32 thread (%04x)!\n", THREAD_Current()->teb_sel);
+        SYSLEVEL_LeaveWin16Lock();
         return;
     }
 
-    /* Enter the Win16Lock to protect global data structures
-       NOTE: We never explicitly leave it again. This shouldn't matter
-             though, as it will be released in TASK_Reschedule and this
-             task won't ever get scheduled again ... */
-
-    SYSLEVEL_EnterWin16Lock();
-
-    assert(hCurrentTask == GetCurrentTask());
-
-    TRACE(task, "Killing task %04x\n", hCurrentTask );
+    TRACE(task, "Killing task %04x\n", hTask );
 
     /* Delete active sockets */
 
@@ -598,9 +560,12 @@
 	WINSOCK_DeleteTaskWSI( pTask, pTask->pwsi );
 
 #ifdef MZ_SUPPORTED
+{
     /* Kill DOS VM task */
+    NE_MODULE *pModule = NE_GetPtr( pTask->hModule );
     if ( pModule->lpDosTask )
         MZ_KillModule( pModule->lpDosTask );
+}
 #endif
 
     /* Perform USER cleanup */
@@ -609,13 +574,6 @@
         pTask->userhandler( hCurrentTask, USIG_TERMINATION, 0,
                             pTask->hInstance, pTask->hQueue );
 
-    if (hTaskToKill && (hTaskToKill != hCurrentTask))
-    {
-        /* If another task is already marked for destruction, */
-        /* we can kill it now, as we are in another context.  */ 
-        TASK_DeleteTask( hTaskToKill );
-    }
-
     if (nTaskCount <= 1)
     {
         TRACE(task, "this is the last task, exiting\n" );
@@ -631,22 +589,71 @@
     Callout.PostAppMessage16( PROCESS_Initial()->task, WM_NULL, 0, 0 );
 
     /* Remove the task from the list to be sure we never switch back to it */
-    TASK_UnlinkTask( hCurrentTask );
+    TASK_UnlinkTask( hTask );
     if( nTaskCount )
     {
         TDB* p = (TDB *)GlobalLock16( hFirstTask );
         while( p )
         {
-            if( p->hYieldTo == hCurrentTask ) p->hYieldTo = 0;
+            if( p->hYieldTo == hTask ) p->hYieldTo = 0;
             p = (TDB *)GlobalLock16( p->hNext );
         }
     }
 
-    hTaskToKill = hCurrentTask;
-    hLockedTask = 0;
-
     pTask->nEvents = 0;
-    TASK_YieldToSystem(pTask);
+
+    if ( hLockedTask == hTask )
+        hLockedTask = 0;
+
+    if ( hTaskToKill && ( hTaskToKill != hCurrentTask ) )
+    {
+        /* If another task is already marked for destruction, */
+        /* we can kill it now, as we are in another context.  */ 
+        TASK_DeleteTask( hTaskToKill );
+        hTaskToKill = 0;
+    }
+
+    /*
+     * If hTask is not the task currently scheduled by the Win16
+     * scheduler, we simply delete it; otherwise we mark it for
+     * destruction.  Note that if the current task is a 32-bit
+     * one, hCurrentTask is *different* from GetCurrentTask()!
+     */
+    if ( hTask == hCurrentTask )
+    {
+        assert( hTaskToKill == 0 || hTaskToKill == hCurrentTask );
+        hTaskToKill = hCurrentTask;
+    }
+    else
+        TASK_DeleteTask( hTask );
+
+    SYSLEVEL_LeaveWin16Lock();
+}
+
+    
+/***********************************************************************
+ *           TASK_KillCurrentTask
+ *
+ * Kill the currently running task. As it's not possible to kill the
+ * current task like this, it is simply marked for destruction, and will
+ * be killed when either TASK_Reschedule or this function is called again 
+ * in the context of another task.
+ */
+void TASK_KillCurrentTask( INT16 exitCode )
+{
+    if ( !THREAD_IsWin16( THREAD_Current() ) )
+    {
+        FIXME(task, "called for Win32 thread (%04x)!\n", THREAD_Current()->teb_sel);
+        return;
+    }
+
+    assert(hCurrentTask == GetCurrentTask());
+
+    TRACE(task, "Killing current task %04x\n", hCurrentTask );
+
+    TASK_KillTask( 0 );
+
+    TASK_YieldToSystem();
 
     /* We should never return from this Yield() */
 
@@ -824,7 +831,7 @@
  * Scheduler interface, this way we ensure that all "unsafe" events are
  * processed outside the scheduler.
  */
-void TASK_YieldToSystem(TDB* pTask)
+static void TASK_YieldToSystem( void )
 {
     if ( !THREAD_IsWin16( THREAD_Current() ) )
     {
@@ -944,7 +951,7 @@
         pTask->nEvents--;
         return FALSE;
     }
-    TASK_YieldToSystem(pTask);
+    TASK_YieldToSystem();
 
     /* When we get back here, we have an event */
 
@@ -963,6 +970,12 @@
     if (!hTask) hTask = GetCurrentTask();
     if (!(pTask = (TDB *)GlobalLock16( hTask ))) return;
 
+    if ( !THREAD_IsWin16( pTask->thdb ) )
+    {
+        FIXME( task, "called for Win32 thread (%04x)!\n", pTask->thdb->teb_sel );
+        return;
+    }
+
     pTask->nEvents++;
     
     if ( !THREAD_IsWin16( THREAD_Current() ) )
@@ -1028,7 +1041,7 @@
     }
 
     if (pCurTask) pCurTask->nEvents++;  /* Make sure we get back here */
-    TASK_YieldToSystem(pCurTask);
+    TASK_YieldToSystem();
     if (pCurTask) pCurTask->nEvents--;
 }