Remove some calls to HEAP_strdupAtoW from advapi32.
[wine] / loader / task.c
index 3cb6b4b..4316614 100644 (file)
@@ -2,47 +2,63 @@
  * Task functions
  *
  * Copyright 1995 Alexandre Julliard
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
  */
 
+#include "config.h"
+#include "wine/port.h"
+
 #include <stdlib.h>
 #include <string.h>
 #include <assert.h>
-#include <unistd.h>
+#ifdef HAVE_UNISTD_H
+# include <unistd.h>
+#endif
+
+#include "winbase.h"
+#include "wingdi.h"
+#include "winnt.h"
+#include "winuser.h"
 
 #include "wine/winbase16.h"
-#include "callback.h"
 #include "drive.h"
 #include "file.h"
 #include "global.h"
 #include "instance.h"
-#include "message.h"
-#include "miscemu.h"
 #include "module.h"
-#include "neexe.h"
-#include "process.h"
-#include "queue.h"
+#include "winternl.h"
 #include "selectors.h"
+#include "wine/server.h"
+#include "syslevel.h"
 #include "stackframe.h"
 #include "task.h"
 #include "thread.h"
 #include "toolhelp.h"
-#include "winnt.h"
-#include "winsock.h"
-#include "syslevel.h"
-#include "debugtools.h"
-#include "dosexe.h"
-#include "services.h"
-#include "server.h"
 
-DEFAULT_DEBUG_CHANNEL(task)
-DECLARE_DEBUG_CHANNEL(relay)
-DECLARE_DEBUG_CHANNEL(toolhelp)
+#include "wine/debug.h"
+
+WINE_DEFAULT_DEBUG_CHANNEL(task);
+WINE_DECLARE_DEBUG_CHANNEL(relay);
+WINE_DECLARE_DEBUG_CHANNEL(toolhelp);
 
   /* Min. number of thunks allocated when creating a new segment */
 #define MIN_THUNKS  32
 
 
-static THHOOK DefaultThhook = { 0 };
+static THHOOK DefaultThhook;
 THHOOK *pThhook = &DefaultThhook;
 
 #define hCurrentTask (pThhook->CurTDB)
@@ -51,7 +67,7 @@ THHOOK *pThhook = &DefaultThhook;
 
 static UINT16 nTaskCount = 0;
 
-static HTASK initial_task;
+static HTASK16 initial_task;
 
 /***********************************************************************
  *          TASK_InstallTHHook
@@ -70,12 +86,31 @@ void TASK_InstallTHHook( THHOOK *pNewThhook )
  */
 HTASK16 TASK_GetNextTask( HTASK16 hTask )
 {
-    TDB* pTask = (TDB*)GlobalLock16(hTask);
+    TDB* pTask = TASK_GetPtr( hTask );
 
     if (pTask->hNext) return pTask->hNext;
-    return (hFirstTask != hTask) ? hFirstTask : 0; 
+    return (hFirstTask != hTask) ? hFirstTask : 0;
+}
+
+
+/***********************************************************************
+ *          TASK_GetPtr
+ */
+TDB *TASK_GetPtr( HTASK16 hTask )
+{
+    return GlobalLock16( hTask );
+}
+
+
+/***********************************************************************
+ *          TASK_GetCurrent
+ */
+TDB *TASK_GetCurrent(void)
+{
+    return TASK_GetPtr( GetCurrentTask() );
 }
 
+
 /***********************************************************************
  *           TASK_LinkTask
  */
@@ -84,11 +119,11 @@ static void TASK_LinkTask( HTASK16 hTask )
     HTASK16 *prevTask;
     TDB *pTask;
 
-    if (!(pTask = (TDB *)GlobalLock16( hTask ))) return;
+    if (!(pTask = TASK_GetPtr( hTask ))) return;
     prevTask = &hFirstTask;
     while (*prevTask)
     {
-        TDB *prevTaskPtr = (TDB *)GlobalLock16( *prevTask );
+        TDB *prevTaskPtr = TASK_GetPtr( *prevTask );
         if (prevTaskPtr->priority >= pTask->priority) break;
         prevTask = &prevTaskPtr->hNext;
     }
@@ -109,12 +144,12 @@ static void TASK_UnlinkTask( HTASK16 hTask )
     prevTask = &hFirstTask;
     while (*prevTask && (*prevTask != hTask))
     {
-        pTask = (TDB *)GlobalLock16( *prevTask );
+        pTask = TASK_GetPtr( *prevTask );
         prevTask = &pTask->hNext;
     }
     if (*prevTask)
     {
-        pTask = (TDB *)GlobalLock16( *prevTask );
+        pTask = TASK_GetPtr( *prevTask );
         *prevTask = pTask->hNext;
         pTask->hNext = 0;
         nTaskCount--;
@@ -153,13 +188,13 @@ static void TASK_CreateThunks( HGLOBAL16 handle, WORD offset, WORD count )
  *
  * Allocate a thunk for MakeProcInstance().
  */
-static SEGPTR TASK_AllocThunk( HTASK16 hTask )
+static SEGPTR TASK_AllocThunk(void)
 {
     TDB *pTask;
     THUNKS *pThunk;
     WORD sel, base;
-    
-    if (!(pTask = (TDB *)GlobalLock16( hTask ))) return 0;
+
+    if (!(pTask = TASK_GetCurrent())) return 0;
     sel = pTask->hCSAlias;
     pThunk = &pTask->thunks;
     base = (int)pThunk - (int)pTask;
@@ -169,7 +204,7 @@ static SEGPTR TASK_AllocThunk( HTASK16 hTask )
         if (!sel)  /* Allocate a new segment */
         {
             sel = GLOBAL_Alloc( GMEM_FIXED, sizeof(THUNKS) + (MIN_THUNKS-1)*8,
-                                pTask->hPDB, TRUE, FALSE, FALSE );
+                                pTask->hPDB, WINE_LDT_FLAGS_CODE );
             if (!sel) return (SEGPTR)0;
             TASK_CreateThunks( sel, 0, MIN_THUNKS );
             pThunk->next = sel;
@@ -179,7 +214,7 @@ static SEGPTR TASK_AllocThunk( HTASK16 hTask )
     }
     base += pThunk->free;
     pThunk->free = *(WORD *)((BYTE *)pThunk + pThunk->free);
-    return PTR_SEG_OFF_TO_SEGPTR( sel, base );
+    return MAKESEGPTR( sel, base );
 }
 
 
@@ -188,13 +223,13 @@ static SEGPTR TASK_AllocThunk( HTASK16 hTask )
  *
  * Free a MakeProcInstance() thunk.
  */
-static BOOL TASK_FreeThunk( HTASK16 hTask, SEGPTR thunk )
+static BOOL TASK_FreeThunk( SEGPTR thunk )
 {
     TDB *pTask;
     THUNKS *pThunk;
     WORD sel, base;
-    
-    if (!(pTask = (TDB *)GlobalLock16( hTask ))) return 0;
+
+    if (!(pTask = TASK_GetCurrent())) return 0;
     sel = pTask->hCSAlias;
     pThunk = &pTask->thunks;
     base = (int)pThunk - (int)pTask;
@@ -219,25 +254,25 @@ static BOOL TASK_FreeThunk( HTASK16 hTask, SEGPTR thunk )
  *       by entering the Win16Lock while linking the task into the
  *       global task list.
  */
-BOOL TASK_Create( NE_MODULE *pModule, UINT16 cmdShow, TEB *teb, LPCSTR cmdline, BYTE len )
+static TDB *TASK_Create( NE_MODULE *pModule, UINT16 cmdShow, TEB *teb, LPCSTR cmdline, BYTE len )
 {
     HTASK16 hTask;
     TDB *pTask;
     char name[10];
-    PDB *pdb32 = PROCESS_Current();
+    FARPROC16 proc;
 
       /* Allocate the task structure */
 
-    hTask = GLOBAL_Alloc( GMEM_FIXED | GMEM_ZEROINIT, sizeof(TDB),
-                          pModule->self, FALSE, FALSE, FALSE );
-    if (!hTask) return FALSE;
-    pTask = (TDB *)GlobalLock16( hTask );
+    hTask = GlobalAlloc16( GMEM_FIXED | GMEM_ZEROINIT, sizeof(TDB) );
+    if (!hTask) return NULL;
+    pTask = TASK_GetPtr( hTask );
+    FarSetOwner16( hTask, pModule->self );
 
     /* Fill the task structure */
 
     pTask->hSelf = hTask;
 
-    if (teb->tibflags & TEBF_WIN32)
+    if (teb && teb->tibflags & TEBF_WIN32)
     {
         pTask->flags        |= TDBF_WIN32;
         pTask->hInstance     = pModule->self;
@@ -245,7 +280,6 @@ BOOL TASK_Create( NE_MODULE *pModule, UINT16 cmdShow, TEB *teb, LPCSTR cmdline,
         /* NOTE: for 16-bit tasks, the instance handles are updated later on
            in NE_InitProcess */
     }
-    if (MZ_Current() && MZ_Current()->load_seg) pTask->flags |= TDBF_WINOLDAP;
 
     pTask->version       = pModule->expected_version;
     pTask->hModule       = pModule->self;
@@ -255,8 +289,9 @@ BOOL TASK_Create( NE_MODULE *pModule, UINT16 cmdShow, TEB *teb, LPCSTR cmdline,
     pTask->teb           = teb;
     pTask->curdrive      = DRIVE_GetCurrentDrive() | 0x80;
     strcpy( pTask->curdir, "\\" );
-    lstrcpynA( pTask->curdir + 1, DRIVE_GetDosCwd( DRIVE_GetCurrentDrive() ),
-                 sizeof(pTask->curdir) - 1 );
+    WideCharToMultiByte(CP_ACP, 0, DRIVE_GetDosCwd(DRIVE_GetCurrentDrive()), -1,
+                        pTask->curdir + 1, sizeof(pTask->curdir) - 1, NULL, NULL);
+    pTask->curdir[sizeof(pTask->curdir) - 1] = 0; /* ensure 0 termination */
 
       /* Create the thunks block */
 
@@ -270,33 +305,33 @@ BOOL TASK_Create( NE_MODULE *pModule, UINT16 cmdShow, TEB *teb, LPCSTR cmdline,
       /* Allocate a selector for the PDB */
 
     pTask->hPDB = GLOBAL_CreateBlock( GMEM_FIXED, &pTask->pdb, sizeof(PDB16),
-                                    pModule->self, FALSE, FALSE, FALSE, NULL );
+                                      pModule->self, WINE_LDT_FLAGS_DATA );
 
       /* Fill the PDB */
 
     pTask->pdb.int20 = 0x20cd;
     pTask->pdb.dispatcher[0] = 0x9a;  /* ljmp */
-    PUT_DWORD(&pTask->pdb.dispatcher[1], (DWORD)NE_GetEntryPoint(
-           GetModuleHandle16("KERNEL"), 102 ));  /* KERNEL.102 is DOS3Call() */
-    pTask->pdb.savedint22 = INT_GetPMHandler( 0x22 );
-    pTask->pdb.savedint23 = INT_GetPMHandler( 0x23 );
-    pTask->pdb.savedint24 = INT_GetPMHandler( 0x24 );
+    proc = GetProcAddress16( GetModuleHandle16("KERNEL"), "DOS3Call" );
+    memcpy( &pTask->pdb.dispatcher[1], &proc, sizeof(proc) );
+    pTask->pdb.savedint22 = 0;
+    pTask->pdb.savedint23 = 0;
+    pTask->pdb.savedint24 = 0;
     pTask->pdb.fileHandlesPtr =
-        PTR_SEG_OFF_TO_SEGPTR( GlobalHandleToSel16(pTask->hPDB),
-                               (int)&((PDB16 *)0)->fileHandles );
+        MAKESEGPTR( GlobalHandleToSel16(pTask->hPDB), (int)&((PDB16 *)0)->fileHandles );
     pTask->pdb.hFileHandles = 0;
     memset( pTask->pdb.fileHandles, 0xff, sizeof(pTask->pdb.fileHandles) );
-    pTask->pdb.environment    = pdb32->env_db->env_sel;
+    /* FIXME: should we make a copy of the environment? */
+    pTask->pdb.environment    = SELECTOROF(GetDOSEnvironment16());
     pTask->pdb.nbFiles        = 20;
 
     /* Fill the command line */
 
     if (!cmdline)
     {
-        cmdline = pdb32->env_db->cmd_line;
+        cmdline = GetCommandLineA();
         /* remove the first word (program name) */
         if (*cmdline == '"')
-            if (!(cmdline = strchr( cmdline+1, '"' ))) cmdline = pdb32->env_db->cmd_line;
+            if (!(cmdline = strchr( cmdline+1, '"' ))) cmdline = GetCommandLineA();
         while (*cmdline && (*cmdline != ' ') && (*cmdline != '\t')) cmdline++;
         while ((*cmdline == ' ') || (*cmdline == '\t')) cmdline++;
         len = strlen(cmdline);
@@ -315,40 +350,26 @@ BOOL TASK_Create( NE_MODULE *pModule, UINT16 cmdShow, TEB *teb, LPCSTR cmdline,
       /* Allocate a code segment alias for the TDB */
 
     pTask->hCSAlias = GLOBAL_CreateBlock( GMEM_FIXED, (void *)pTask,
-                                          sizeof(TDB), pTask->hPDB, TRUE,
-                                          FALSE, FALSE, NULL );
-
-      /* Set the owner of the environment block */
-
-    FarSetOwner16( pTask->pdb.environment, pTask->hPDB );
+                                          sizeof(TDB), pTask->hPDB, WINE_LDT_FLAGS_CODE );
 
       /* Default DTA overwrites command line */
 
-    pTask->dta = PTR_SEG_OFF_TO_SEGPTR( pTask->hPDB, 
-                                (int)&pTask->pdb.cmdLine - (int)&pTask->pdb );
+    pTask->dta = MAKESEGPTR( pTask->hPDB, (int)&pTask->pdb.cmdLine - (int)&pTask->pdb );
 
     /* Create scheduler event for 16-bit tasks */
 
     if ( !(pTask->flags & TDBF_WIN32) )
-    {
-        pTask->hEvent = CreateEventA( NULL, TRUE, FALSE, NULL );
-        pTask->hEvent = ConvertToGlobalHandle( pTask->hEvent );
-    }
-
-    /* Enter task handle into thread and process */
-    teb->htask16 = hTask;
-    if (!initial_task) initial_task = hTask;
+        NtCreateEvent( &pTask->hEvent, EVENT_ALL_ACCESS, NULL, TRUE, FALSE );
 
-    /* Add the task to the linked list */
+    /* Enter task handle into thread */
 
-    SYSLEVEL_EnterWin16Lock();
-    TASK_LinkTask( hTask );
-    SYSLEVEL_LeaveWin16Lock();
+    if (teb) teb->htask16 = hTask;
+    if (!initial_task) initial_task = hTask;
 
-    return TRUE;
+    return pTask;
 }
 
+
 /***********************************************************************
  *           TASK_DeleteTask
  */
@@ -357,7 +378,7 @@ static void TASK_DeleteTask( HTASK16 hTask )
     TDB *pTask;
     HGLOBAL16 hPDB;
 
-    if (!(pTask = (TDB *)GlobalLock16( hTask ))) return;
+    if (!(pTask = TASK_GetPtr( hTask ))) return;
     hPDB = pTask->hPDB;
 
     pTask->magic = 0xdead; /* invalidate signature */
@@ -381,251 +402,129 @@ static void TASK_DeleteTask( HTASK16 hTask )
     GlobalFreeAll16( hPDB );
 }
 
+
 /***********************************************************************
- *           TASK_KillTask
+ *           TASK_CreateMainTask
+ *
+ * Create a task for the main (32-bit) process.
  */
-void TASK_KillTask( HTASK16 hTask )
+void TASK_CreateMainTask(void)
 {
-    TDB *pTask; 
-
-    /* Enter the Win16Lock to protect global data structures */
-    SYSLEVEL_EnterWin16Lock();
-
-    if ( !hTask ) hTask = GetCurrentTask();
-    pTask = (TDB *)GlobalLock16( hTask );
-    if ( !pTask ) 
+    TDB *pTask;
+    STARTUPINFOA startup_info;
+    UINT cmdShow = 1; /* SW_SHOWNORMAL but we don't want to include winuser.h here */
+
+    GetStartupInfoA( &startup_info );
+    if (startup_info.dwFlags & STARTF_USESHOWWINDOW) cmdShow = startup_info.wShowWindow;
+    pTask = TASK_Create( (NE_MODULE *)GlobalLock16( MapHModuleLS(GetModuleHandleA(0)) ),
+                         cmdShow, NtCurrentTeb(), NULL, 0 );
+    if (!pTask)
     {
-        SYSLEVEL_LeaveWin16Lock();
-        return;
+        ERR("could not create task for main process\n");
+        ExitProcess(1);
     }
 
-    TRACE("Killing task %04x\n", hTask );
-
-    /* Perform USER cleanup */
-
-    TASK_CallTaskSignalProc( USIG16_TERMINATION, hTask );
-    PROCESS_CallUserSignalProc( USIG_PROCESS_EXIT, 0 );
-    PROCESS_CallUserSignalProc( USIG_THREAD_EXIT, 0 );
-    PROCESS_CallUserSignalProc( USIG_PROCESS_DESTROY, 0 );
+    /* Add the task to the linked list */
+    /* (no need to get the win16 lock, we are the only thread at this point) */
+    TASK_LinkTask( pTask->hSelf );
+}
 
-    if (nTaskCount <= 1)
-    {
-        TRACE("this is the last task, exiting\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 );
+/* startup routine for a new 16-bit thread */
+static DWORD CALLBACK task_start( TDB *pTask )
+{
+    DWORD ret;
 
-    /* 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;
-            p = (TDB *)GlobalLock16( p->hNext );
-        }
-    }
+    NtCurrentTeb()->tibflags &= ~TEBF_WIN32;
+    NtCurrentTeb()->htask16 = pTask->hSelf;
 
-    pTask->nEvents = 0;
+    _EnterWin16Lock();
+    TASK_LinkTask( pTask->hSelf );
+    pTask->teb = NtCurrentTeb();
+    ret = NE_StartTask();
+    _LeaveWin16Lock();
+    return ret;
+}
 
-    if ( hLockedTask == hTask )
-        hLockedTask = 0;
 
-    TASK_DeleteTask( hTask );
+/***********************************************************************
+ *           TASK_SpawnTask
+ *
+ * Spawn a new 16-bit task.
+ */
+HTASK16 TASK_SpawnTask( NE_MODULE *pModule, WORD cmdShow,
+                        LPCSTR cmdline, BYTE len, HANDLE *hThread )
+{
+    TDB *pTask;
 
-    /* When deleting the current task ... */
-    if ( hTask == hCurrentTask )
+    if (!(pTask = TASK_Create( pModule, cmdShow, NULL, cmdline, len ))) return 0;
+    if (!(*hThread = CreateThread( NULL, 0, (LPTHREAD_START_ROUTINE)task_start, pTask, 0, NULL )))
     {
-        DWORD lockCount;
-
-        /* ... schedule another one ... */
-        TASK_Reschedule();
-
-        /* ... and completely release the Win16Lock, just in case. */
-        ReleaseThunkLock( &lockCount );
-
-        return;
+        TASK_DeleteTask( pTask->hSelf );
+        return 0;
     }
-
-    SYSLEVEL_LeaveWin16Lock();
+    return pTask->hSelf;
 }
 
+
 /***********************************************************************
- *           TASK_Reschedule
- *
- * This is where all the magic of task-switching happens!
- *
- * 16-bit Windows performs non-preemptive (cooperative) multitasking.
- * This means that each 16-bit task runs until it voluntarily yields 
- * control, at which point the scheduler gets active and selects the
- * next task to run.
- *
- * In Wine, all processes, even 16-bit ones, are scheduled preemptively
- * by the standard scheduler of the underlying OS.  As many 16-bit apps
- * *rely* on the behaviour of the Windows scheduler, however, we have
- * to simulate that behaviour.
- *
- * This is achieved as follows: every 16-bit task is at time (except
- * during task creation and deletion) in one of two states: either it
- * is the one currently running, then the global variable hCurrentTask
- * contains its task handle, or it is not currently running, then it
- * is blocked on a special scheduler event, a global handle to which
- * is stored in the task struct.
- *
- * When the current task yields control, this routine gets called. Its
- * purpose is to determine the next task to be active, signal the 
- * scheduler event of that task, and then put the current task to sleep
- * waiting for *its* scheduler event to get signalled again.
- *
- * This routine can get called in a few other special situations as well:
- *
- * - On creation of a 16-bit task, the Unix process executing the task
- *   calls TASK_Reschedule once it has completed its initialization.
- *   At this point, the task needs to be blocked until its scheduler
- *   event is signalled the first time (this will be done by the parent
- *   process to get the task up and running).
- *
- * - When the task currently running terminates itself, this routine gets
- *   called and has to schedule another task, *without* blocking the 
- *   terminating task.
- *
- * - When a 32-bit thread posts an event for a 16-bit task, it might be
- *   the case that *no* 16-bit task is currently running.  In this case
- *   the task that has now an event pending is to be scheduled.
- *
+ *           TASK_ExitTask
  */
-void TASK_Reschedule(void)
+void TASK_ExitTask(void)
 {
-    TDB *pOldTask = NULL, *pNewTask = NULL;
-    HTASK16 hOldTask = 0, hNewTask = 0;
-    enum { MODE_YIELD, MODE_SLEEP, MODE_WAKEUP } mode;
+    TDB *pTask;
     DWORD lockCount;
 
-    SYSLEVEL_EnterWin16Lock();
-
-    /* Check what we need to do */
-    hOldTask = GetCurrentTask();
-    pOldTask = (TDB *)GlobalLock16( hOldTask );
-    TRACE( "entered with hCurrentTask %04x by hTask %04x (pid %ld)\n", 
-           hCurrentTask, hOldTask, (long) getpid() );
+    /* Enter the Win16Lock to protect global data structures */
+    _EnterWin16Lock();
 
-    if ( pOldTask && THREAD_IsWin16( NtCurrentTeb() ) )
+    pTask = TASK_GetCurrent();
+    if ( !pTask )
     {
-        /* We are called by an active (non-deleted) 16-bit task */
+        _LeaveWin16Lock();
+        return;
+    }
 
-        /* If we don't even have a current task, or else the current
-           task has yielded, we'll need to schedule a new task and
-           (possibly) put the calling task to sleep.  Otherwise, we
-           only block the caller. */
+    TRACE("Killing task %04x\n", pTask->hSelf );
 
-        if ( !hCurrentTask || hCurrentTask == hOldTask )
-            mode = MODE_YIELD;
-        else
-            mode = MODE_SLEEP;
-    }
-    else
-    {
-        /* We are called by a deleted 16-bit task or a 32-bit thread */
+    /* Perform USER cleanup */
 
-        /* The only situation where we need to do something is if we
-           now do not have a current task.  Then, we'll need to wake up
-           some task that has events pending. */
+    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 ( !hCurrentTask || hCurrentTask == hOldTask )
-            mode = MODE_WAKEUP;
-        else
-        {
-            /* nothing to do */
-            SYSLEVEL_LeaveWin16Lock();
-            return;
-        }
-    }
+    /* Remove the task from the list to be sure we never switch back to it */
+    TASK_UnlinkTask( pTask->hSelf );
 
-    /* Find a task to yield to: check for DirectedYield() */
-    if ( mode == MODE_YIELD && pOldTask && pOldTask->hYieldTo )
+    if (!nTaskCount || (nTaskCount == 1 && hFirstTask == initial_task))
     {
-        hNewTask = pOldTask->hYieldTo;
-        pNewTask = (TDB *)GlobalLock16( hNewTask );
-        if( !pNewTask || !pNewTask->nEvents) hNewTask = 0;
-        pOldTask->hYieldTo = 0;
+        TRACE("this is the last task, exiting\n" );
+        ExitKernel16();
     }
 
-    /* Find a task to yield to: check for pending events */
-    if ( (mode == MODE_YIELD || mode == MODE_WAKEUP) && !hNewTask )
+    if( nTaskCount )
     {
-        hNewTask = hFirstTask;
-        while (hNewTask)
+        TDB* p = TASK_GetPtr( hFirstTask );
+        while( p )
         {
-            pNewTask = (TDB *)GlobalLock16( hNewTask );
-
-            TRACE( "\ttask = %04x, events = %i\n", hNewTask, pNewTask->nEvents );
-
-            if (pNewTask->nEvents) break;
-            hNewTask = pNewTask->hNext;
+            if( p->hYieldTo == pTask->hSelf ) p->hYieldTo = 0;
+            p = TASK_GetPtr( p->hNext );
         }
-        if (hLockedTask && (hNewTask != hLockedTask)) hNewTask = 0;
-    }
-
-    /* If we are still the task with highest priority, just return ... */
-    if ( mode == MODE_YIELD && hNewTask && hNewTask == hCurrentTask )
-    {
-        TRACE("returning to the current task (%04x)\n", hCurrentTask );
-        SYSLEVEL_LeaveWin16Lock();
-
-        /* Allow Win32 threads to thunk down even while a Win16 task is
-           in a tight PeekMessage() or Yield() loop ... */
-        ReleaseThunkLock( &lockCount );
-        RestoreThunkLock( lockCount );
-        return;
-    }
-
-    /* If no task to yield to found, suspend 16-bit scheduler ... */
-    if ( mode == MODE_YIELD && !hNewTask )
-    {
-        TRACE("No currently active task\n");
-        hCurrentTask = 0;
     }
 
-    /* If we found a task to wake up, do it ... */
-    if ( (mode == MODE_YIELD || mode == MODE_WAKEUP) && hNewTask )
-    {
-        TRACE("Switching to task %04x (%.8s)\n",
-                      hNewTask, pNewTask->module_name );
-
-        pNewTask->priority++;
-        TASK_UnlinkTask( hNewTask );
-        TASK_LinkTask( hNewTask );
-        pNewTask->priority--;
-
-        hCurrentTask = hNewTask;
-        SetEvent( pNewTask->hEvent );
-
-        /* This is set just in case some app reads it ... */
-        pNewTask->ss_sp = pNewTask->teb->cur_stack;
-    }
+    pTask->nEvents = 0;
 
-    /* If we need to put the current task to sleep, do it ... */
-    if ( (mode == MODE_YIELD || mode == MODE_SLEEP) && hOldTask != hCurrentTask )
-    {
-        ResetEvent( pOldTask->hEvent );
+    if ( hLockedTask == pTask->hSelf )
+        hLockedTask = 0;
 
-        ReleaseThunkLock( &lockCount );
-        SYSLEVEL_CheckNotLevel( 1 );
-        WaitForSingleObject( pOldTask->hEvent, INFINITE );
-        RestoreThunkLock( lockCount );
-    }
+    TASK_DeleteTask( pTask->hSelf );
 
-    SYSLEVEL_LeaveWin16Lock();
+    /* ... and completely release the Win16Lock, just in case. */
+    ReleaseThunkLock( &lockCount );
 }
 
+
 /***********************************************************************
  *           InitTask  (KERNEL.91)
  *
@@ -637,23 +536,23 @@ void WINAPI InitTask16( CONTEXT86 *context )
     INSTANCEDATA *pinstance;
     SEGPTR ptr;
 
-    EAX_reg(context) = 0;
-    if (!(pTask = (TDB *)GlobalLock16( GetCurrentTask() ))) return;
+    context->Eax = 0;
+    if (!(pTask = TASK_GetCurrent())) return;
 
-    /* Note: we need to trust that BX/CX contain the stack/heap sizes, 
+    /* Note: we need to trust that BX/CX contain the stack/heap sizes,
        as some apps, notably Visual Basic apps, *modify* the heap/stack
        size of the instance data segment before calling InitTask() */
 
     /* Initialize the INSTANCEDATA structure */
-    pinstance = (INSTANCEDATA *)PTR_SEG_OFF_TO_LIN(CURRENT_DS, 0);
+    pinstance = MapSL( MAKESEGPTR(CURRENT_DS, 0) );
     pinstance->stackmin    = OFFSETOF( pTask->teb->cur_stack ) + sizeof( STACK16FRAME );
     pinstance->stackbottom = pinstance->stackmin; /* yup, that's right. Confused me too. */
-    pinstance->stacktop    = ( pinstance->stackmin > BX_reg(context)? 
-                               pinstance->stackmin - BX_reg(context) : 0 ) + 150; 
+    pinstance->stacktop    = ( pinstance->stackmin > LOWORD(context->Ebx) ?
+                               pinstance->stackmin - LOWORD(context->Ebx) : 0 ) + 150;
 
     /* Initialize the local heap */
-    if ( CX_reg(context) )
-        LocalInit16( GlobalHandleToSel16(pTask->hInstance), 0, CX_reg(context) );
+    if (LOWORD(context->Ecx))
+        LocalInit16( GlobalHandleToSel16(pTask->hInstance), 0, LOWORD(context->Ecx) );
 
     /* Initialize implicitly loaded DLLs */
     NE_InitializeDLLs( pTask->hModule );
@@ -670,23 +569,23 @@ void WINAPI InitTask16( CONTEXT86 *context )
      * 0 (=%bp) is pushed on the stack
      */
     ptr = stack16_push( sizeof(WORD) );
-    *(WORD *)PTR_SEG_TO_LIN(ptr) = 0;
-    ESP_reg(context) -= 2;
+    *(WORD *)MapSL(ptr) = 0;
+    context->Esp -= 2;
 
-    EAX_reg(context) = 1;
-        
-    if (!pTask->pdb.cmdLine[0]) EBX_reg(context) = 0x80;
+    context->Eax = 1;
+
+    if (!pTask->pdb.cmdLine[0]) context->Ebx = 0x80;
     else
     {
         LPBYTE p = &pTask->pdb.cmdLine[1];
         while ((*p == ' ') || (*p == '\t')) p++;
-        EBX_reg(context) = 0x80 + (p - pTask->pdb.cmdLine);
+        context->Ebx = 0x80 + (p - pTask->pdb.cmdLine);
     }
-    ECX_reg(context) = pinstance->stacktop;
-    EDX_reg(context) = pTask->nCmdShow;
-    ESI_reg(context) = (DWORD)pTask->hPrevInstance;
-    EDI_reg(context) = (DWORD)pTask->hInstance;
-    ES_reg (context) = (WORD)pTask->hPDB;
+    context->Ecx   = pinstance->stacktop;
+    context->Edx   = pTask->nCmdShow;
+    context->Esi   = (DWORD)pTask->hPrevInstance;
+    context->Edi   = (DWORD)pTask->hInstance;
+    context->SegEs = (WORD)pTask->hPDB;
 }
 
 
@@ -698,9 +597,9 @@ BOOL16 WINAPI WaitEvent16( HTASK16 hTask )
     TDB *pTask;
 
     if (!hTask) hTask = GetCurrentTask();
-    pTask = (TDB *)GlobalLock16( hTask );
+    pTask = TASK_GetPtr( hTask );
 
-    if ( !THREAD_IsWin16( NtCurrentTeb() ) )
+    if (pTask->flags & TDBF_WIN32)
     {
         FIXME("called for Win32 thread (%04x)!\n", NtCurrentTeb()->teb_sel);
         return TRUE;
@@ -711,11 +610,20 @@ BOOL16 WINAPI WaitEvent16( HTASK16 hTask )
         pTask->nEvents--;
         return FALSE;
     }
-    TASK_Reschedule();
 
-    /* When we get back here, we have an event */
+    if (pTask->teb == NtCurrentTeb())
+    {
+        DWORD lockCount;
+
+        NtResetEvent( pTask->hEvent, NULL );
+        ReleaseThunkLock( &lockCount );
+        SYSLEVEL_CheckNotLevel( 1 );
+        WaitForSingleObject( pTask->hEvent, INFINITE );
+        RestoreThunkLock( lockCount );
+        if (pTask->nEvents > 0) pTask->nEvents--;
+    }
+    else FIXME("for other task %04x cur=%04x\n",pTask->hSelf,GetCurrentTask());
 
-    if (pTask->nEvents > 0) pTask->nEvents--;
     return TRUE;
 }
 
@@ -728,9 +636,9 @@ void WINAPI PostEvent16( HTASK16 hTask )
     TDB *pTask;
 
     if (!hTask) hTask = GetCurrentTask();
-    if (!(pTask = (TDB *)GlobalLock16( hTask ))) return;
+    if (!(pTask = TASK_GetPtr( hTask ))) return;
 
-    if ( !THREAD_IsWin16( pTask->teb ) )
+    if (pTask->flags & TDBF_WIN32)
     {
         FIXME("called for Win32 thread (%04x)!\n", pTask->teb->teb_sel );
         return;
@@ -738,9 +646,7 @@ void WINAPI PostEvent16( HTASK16 hTask )
 
     pTask->nEvents++;
 
-    /* If we are a 32-bit task, we might need to wake up the 16-bit scheduler */
-    if ( !THREAD_IsWin16( NtCurrentTeb() ) )
-        TASK_Reschedule();
+    if (pTask->nEvents == 1) NtSetEvent( pTask->hEvent, NULL );
 }
 
 
@@ -753,14 +659,14 @@ void WINAPI SetPriority16( HTASK16 hTask, INT16 delta )
     INT16 newpriority;
 
     if (!hTask) hTask = GetCurrentTask();
-    if (!(pTask = (TDB *)GlobalLock16( hTask ))) return;
+    if (!(pTask = TASK_GetPtr( hTask ))) return;
     newpriority = pTask->priority + delta;
     if (newpriority < -32) newpriority = -32;
     else if (newpriority > 15) newpriority = 15;
 
     pTask->priority = newpriority + 1;
-    TASK_UnlinkTask( hTask );
-    TASK_LinkTask( hTask );
+    TASK_UnlinkTask( pTask->hSelf );
+    TASK_LinkTask( pTask->hSelf );
     pTask->priority--;
 }
 
@@ -790,21 +696,14 @@ HTASK16 WINAPI IsTaskLocked16(void)
  */
 void WINAPI OldYield16(void)
 {
-    TDB *pCurTask = (TDB *)GlobalLock16( GetCurrentTask() );
-
-    if ( !THREAD_IsWin16( NtCurrentTeb() ) )
-    {
-        FIXME("called for Win32 thread (%04x)!\n", NtCurrentTeb()->teb_sel);
-        return;
-    }
+   DWORD count;
 
-    if (pCurTask) pCurTask->nEvents++;  /* Make sure we get back here */
-    TASK_Reschedule();
-    if (pCurTask) pCurTask->nEvents--;
+   ReleaseThunkLock(&count);
+   RestoreThunkLock(count);
 }
 
 /***********************************************************************
- *           WIN32_OldYield16  (KERNEL.447)
+ *           WIN32_OldYield  (KERNEL.447)
  */
 void WINAPI WIN32_OldYield16(void)
 {
@@ -819,32 +718,46 @@ void WINAPI WIN32_OldYield16(void)
  */
 void WINAPI DirectedYield16( HTASK16 hTask )
 {
-    TDB *pCurTask = (TDB *)GlobalLock16( GetCurrentTask() );
+    TDB *pCurTask = TASK_GetCurrent();
 
-    if ( !THREAD_IsWin16( NtCurrentTeb() ) )
+    if (!pCurTask) OldYield16();
+    else
     {
-        FIXME("called for Win32 thread (%04x)!\n", NtCurrentTeb()->teb_sel);
-        return;
-    }
-
-    TRACE("%04x: DirectedYield(%04x)\n", pCurTask->hSelf, hTask );
-
-    pCurTask->hYieldTo = hTask;
-    OldYield16();
+        if (pCurTask->flags & TDBF_WIN32)
+        {
+            FIXME("called for Win32 thread (%04x)!\n", NtCurrentTeb()->teb_sel);
+            return;
+        }
 
-    TRACE("%04x: back from DirectedYield(%04x)\n", pCurTask->hSelf, hTask );
+        TRACE("%04x: DirectedYield(%04x)\n", pCurTask->hSelf, hTask );
+        pCurTask->hYieldTo = hTask;
+        OldYield16();
+        TRACE("%04x: back from DirectedYield(%04x)\n", pCurTask->hSelf, hTask );
+    }
 }
 
 /***********************************************************************
- *           Yield16  (KERNEL.29)
+ *           Yield  (KERNEL.29)
  */
 void WINAPI Yield16(void)
 {
-    TDB *pCurTask = (TDB *)GlobalLock16( GetCurrentTask() );
+    TDB *pCurTask = TASK_GetCurrent();
 
     if (pCurTask) pCurTask->hYieldTo = 0;
-    if (pCurTask && pCurTask->hQueue) Callout.UserYield16();
-    else OldYield16();
+    if (pCurTask && pCurTask->hQueue)
+    {
+        HMODULE mod = GetModuleHandleA( "user32.dll" );
+        if (mod)
+        {
+            FARPROC proc = GetProcAddress( mod, "UserYield16" );
+            if (proc)
+            {
+                proc();
+                return;
+            }
+        }
+    }
+    OldYield16();
 }
 
 /***********************************************************************
@@ -859,7 +772,7 @@ HTASK16 WINAPI KERNEL_490( HTASK16 someTask )
 }
 
 /***********************************************************************
- *           MakeProcInstance16  (KERNEL.51)
+ *           MakeProcInstance  (KERNEL.51)
  */
 FARPROC16 WINAPI MakeProcInstance16( FARPROC16 func, HANDLE16 hInstance )
 {
@@ -873,7 +786,7 @@ FARPROC16 WINAPI MakeProcInstance16( FARPROC16 func, HANDLE16 hInstance )
 
     if (!HIWORD(func)) {
       /* Win95 actually protects via SEH, but this is better for debugging */
-      ERR("Ouch ! Called with invalid func 0x%08lx !\n", (DWORD)func);
+      WARN("Ouch ! Called with invalid func 0x%08lx !\n", (DWORD)func);
       return (FARPROC16)0;
     }
 
@@ -882,18 +795,18 @@ FARPROC16 WINAPI MakeProcInstance16( FARPROC16 func, HANDLE16 hInstance )
        if ( (!(hInstance & 4)) ||
             ((hInstance != 0xffff) && IS_SELECTOR_FREE(hInstance|7)) )
        {
-           ERR("Invalid hInstance (%04x) passed to MakeProcInstance !\n",
+           WARN("Invalid hInstance (%04x) passed to MakeProcInstance !\n",
                hInstance);
            return 0;
        }
     }
 
-    if ( (CURRENT_DS != hInstanceSelector)
+    if ( (GlobalHandleToSel16(CURRENT_DS) != hInstanceSelector)
       && (hInstance != 0)
       && (hInstance != 0xffff) )
     {
        /* calling MPI with a foreign DSEG is invalid ! */
-        ERR("Problem with hInstance? Got %04x, using %04x instead\n",
+        WARN("Problem with hInstance? Got %04x, using %04x instead\n",
                    hInstance,CURRENT_DS);
     }
 
@@ -908,17 +821,17 @@ FARPROC16 WINAPI MakeProcInstance16( FARPROC16 func, HANDLE16 hInstance )
     if (NE_GetPtr(FarGetOwner16(hInstance))->flags & NE_FFLAGS_LIBMODULE)
        return func;
 
-    thunkaddr = TASK_AllocThunk( GetCurrentTask() );
+    thunkaddr = TASK_AllocThunk();
     if (!thunkaddr) return (FARPROC16)0;
-    thunk = PTR_SEG_TO_LIN( thunkaddr );
-    lfunc = PTR_SEG_TO_LIN( func );
+    thunk = MapSL( thunkaddr );
+    lfunc = MapSL( (SEGPTR)func );
 
     TRACE("(%08lx,%04x): got thunk %08lx\n",
           (DWORD)func, hInstance, (DWORD)thunkaddr );
     if (((lfunc[0]==0x8c) && (lfunc[1]==0xd8)) || /* movw %ds, %ax */
        ((lfunc[0]==0x1e) && (lfunc[1]==0x58))    /* pushw %ds, popw %ax */
     ) {
-       FIXME("This was the (in)famous \"thunk useless\" warning. We thought we have to overwrite with nop;nop;, but this isn't true.\n");
+       WARN("This was the (in)famous \"thunk useless\" warning. We thought we have to overwrite with nop;nop;, but this isn't true.\n");
     }
 
     *thunk++ = 0xb8;    /* movw instance, %ax */
@@ -932,18 +845,18 @@ FARPROC16 WINAPI MakeProcInstance16( FARPROC16 func, HANDLE16 hInstance )
 
 
 /***********************************************************************
- *           FreeProcInstance16  (KERNEL.52)
+ *           FreeProcInstance  (KERNEL.52)
  */
 void WINAPI FreeProcInstance16( FARPROC16 func )
 {
     TRACE("(%08lx)\n", (DWORD)func );
-    TASK_FreeThunk( GetCurrentTask(), (SEGPTR)func );
+    TASK_FreeThunk( (SEGPTR)func );
 }
 
 /**********************************************************************
  *         TASK_GetCodeSegment
- * 
- * Helper function for GetCodeHandle/GetCodeInfo: Retrieve the module 
+ *
+ * Helper function for GetCodeHandle/GetCodeInfo: Retrieve the module
  * and logical segment number of a given code segment.
  *
  * 'proc' either *is* already a pair of module handle and segment number,
@@ -956,12 +869,12 @@ void WINAPI FreeProcInstance16( FARPROC16 func )
  *        the function the snoop code will return to ...
  *
  */
-static BOOL TASK_GetCodeSegment( FARPROC16 proc, NE_MODULE **ppModule, 
+static BOOL TASK_GetCodeSegment( FARPROC16 proc, NE_MODULE **ppModule,
                                  SEGTABLEENTRY **ppSeg, int *pSegNr )
 {
     NE_MODULE *pModule = NULL;
     SEGTABLEENTRY *pSeg = NULL;
-    int segNr;
+    int segNr=0;
 
     /* Try pair of module handle / segment number */
     pModule = (NE_MODULE *) GlobalLock16( HIWORD( proc ) );
@@ -973,9 +886,9 @@ static BOOL TASK_GetCodeSegment( FARPROC16 proc, NE_MODULE **ppModule,
     }
 
     /* Try thunk or function */
-    else 
+    else
     {
-        BYTE *thunk = (BYTE *)PTR_SEG_TO_LIN( proc );
+        BYTE *thunk = MapSL( (SEGPTR)proc );
         WORD selector;
 
         if ((thunk[0] == 0xb8) && (thunk[3] == 0xea))
@@ -1055,7 +968,7 @@ BOOL16 WINAPI GetCodeInfo16( FARPROC16 proc, SEGINFO *segInfo )
 
 
 /**********************************************************************
- *          DefineHandleTable16    (KERNEL.94)
+ *          DefineHandleTable    (KERNEL.94)
  */
 BOOL16 WINAPI DefineHandleTable16( WORD wOffset )
 {
@@ -1073,7 +986,7 @@ HQUEUE16 WINAPI SetTaskQueue16( HTASK16 hTask, HQUEUE16 hQueue )
     TDB *pTask;
 
     if (!hTask) hTask = GetCurrentTask();
-    if (!(pTask = (TDB *)GlobalLock16( hTask ))) return 0;
+    if (!(pTask = TASK_GetPtr( hTask ))) return 0;
 
     hPrev = pTask->hQueue;
     pTask->hQueue = hQueue;
@@ -1090,7 +1003,7 @@ HQUEUE16 WINAPI GetTaskQueue16( HTASK16 hTask )
     TDB *pTask;
 
     if (!hTask) hTask = GetCurrentTask();
-    if (!(pTask = (TDB *)GlobalLock16( hTask ))) return 0;
+    if (!(pTask = TASK_GetPtr( hTask ))) return 0;
     return pTask->hQueue;
 }
 
@@ -1124,7 +1037,7 @@ HQUEUE16 WINAPI GetThreadQueue16( DWORD thread )
     else if ( HIWORD(thread) )
         teb = THREAD_IdToTEB( thread );
     else if ( IsTask16( (HTASK16)thread ) )
-        teb = ((TDB *)GlobalLock16( (HANDLE16)thread ))->teb;
+        teb = (TASK_GetPtr( (HANDLE16)thread ))->teb;
 
     return (HQUEUE16)(teb? teb->queue : 0);
 }
@@ -1132,7 +1045,7 @@ HQUEUE16 WINAPI GetThreadQueue16( DWORD thread )
 /***********************************************************************
  *           SetFastQueue  (KERNEL.624)
  */
-VOID WINAPI SetFastQueue16( DWORD thread, HANDLE hQueue )
+VOID WINAPI SetFastQueue16( DWORD thread, HQUEUE16 hQueue )
 {
     TEB *teb = NULL;
     if ( !thread )
@@ -1140,26 +1053,20 @@ VOID WINAPI SetFastQueue16( DWORD thread, HANDLE hQueue )
     else if ( HIWORD(thread) )
         teb = THREAD_IdToTEB( thread );
     else if ( IsTask16( (HTASK16)thread ) )
-        teb = ((TDB *)GlobalLock16( (HANDLE16)thread ))->teb;
+        teb = (TASK_GetPtr( (HANDLE16)thread ))->teb;
 
-    if ( teb ) teb->queue = (HQUEUE16) hQueue;
+    if ( teb ) teb->queue = hQueue;
 }
 
 /***********************************************************************
  *           GetFastQueue  (KERNEL.625)
  */
-HANDLE WINAPI GetFastQueue16( void )
+HQUEUE16 WINAPI GetFastQueue16( void )
 {
-    TEB *teb = NtCurrentTeb();
-    if (!teb) return 0;
-
-    if (!teb->queue)
-        Callout.InitThreadInput16( 0, THREAD_IsWin16(teb)? 4 : 5 );
+    HQUEUE16 ret = NtCurrentTeb()->queue;
 
-    if (!teb->queue)
-        FIXME("(): should initialize thread-local queue, expect failure!\n" );
-
-    return (HANDLE)teb->queue;
+    if (!ret) FIXME("(): should initialize thread-local queue, expect failure!\n" );
+    return ret;
 }
 
 /***********************************************************************
@@ -1172,7 +1079,7 @@ void WINAPI SwitchStackTo16( WORD seg, WORD ptr, WORD top )
     INSTANCEDATA *pData;
     UINT16 copySize;
 
-    if (!(pTask = (TDB *)GlobalLock16( GetCurrentTask() ))) return;
+    if (!(pTask = TASK_GetCurrent())) return;
     if (!(pData = (INSTANCEDATA *)GlobalLock16( seg ))) return;
     TRACE("old=%04x:%04x new=%04x:%04x\n",
           SELECTOROF( pTask->teb->cur_stack ),
@@ -1184,7 +1091,7 @@ void WINAPI SwitchStackTo16( WORD seg, WORD ptr, WORD top )
     /* pop frame + args and push bp */
     pData->old_ss_sp   = pTask->teb->cur_stack + sizeof(STACK16FRAME)
                            + 2 * sizeof(WORD);
-    *(WORD *)PTR_SEG_TO_LIN(pData->old_ss_sp) = oldFrame->bp;
+    *(WORD *)MapSL(pData->old_ss_sp) = oldFrame->bp;
     pData->stacktop    = top;
     pData->stackmin    = ptr;
     pData->stackbottom = ptr;
@@ -1196,14 +1103,14 @@ void WINAPI SwitchStackTo16( WORD seg, WORD ptr, WORD top )
      */
     copySize = oldFrame->bp - OFFSETOF(pData->old_ss_sp);
     copySize += 3 * sizeof(WORD) + sizeof(STACK16FRAME);
-    pTask->teb->cur_stack = PTR_SEG_OFF_TO_SEGPTR( seg, ptr - copySize );
+    pTask->teb->cur_stack = MAKESEGPTR( seg, ptr - copySize );
     newFrame = THREAD_STACK16( pTask->teb );
 
     /* Copy the stack frame and the local variables to the new stack */
 
     memmove( newFrame, oldFrame, copySize );
     newFrame->bp = ptr;
-    *(WORD *)PTR_SEG_OFF_TO_LIN( seg, ptr ) = 0;  /* clear previous bp */
+    *(WORD *)MapSL( MAKESEGPTR( seg, ptr ) ) = 0;  /* clear previous bp */
 }
 
 
@@ -1229,14 +1136,14 @@ void WINAPI SwitchStackBack16( CONTEXT86 *context )
 
     /* Pop bp from the previous stack */
 
-    BP_reg(context) = *(WORD *)PTR_SEG_TO_LIN(pData->old_ss_sp);
+    context->Ebp = (context->Ebp & ~0xffff) | *(WORD *)MapSL(pData->old_ss_sp);
     pData->old_ss_sp += sizeof(WORD);
 
     /* Switch back to the old stack */
 
     NtCurrentTeb()->cur_stack = pData->old_ss_sp - sizeof(STACK16FRAME);
-    SS_reg(context)  = SELECTOROF(pData->old_ss_sp);
-    ESP_reg(context) = OFFSETOF(pData->old_ss_sp) - sizeof(DWORD); /*ret addr*/
+    context->SegSs = SELECTOROF(pData->old_ss_sp);
+    context->Esp   = OFFSETOF(pData->old_ss_sp) - sizeof(DWORD); /*ret addr*/
     pData->old_ss_sp = 0;
 
     /* Build a stack frame for the return */
@@ -1250,7 +1157,7 @@ void WINAPI SwitchStackBack16( CONTEXT86 *context )
 
 
 /***********************************************************************
- *           GetTaskQueueDS16  (KERNEL.118)
+ *           GetTaskQueueDS  (KERNEL.118)
  */
 void WINAPI GetTaskQueueDS16(void)
 {
@@ -1259,7 +1166,7 @@ void WINAPI GetTaskQueueDS16(void)
 
 
 /***********************************************************************
- *           GetTaskQueueES16  (KERNEL.119)
+ *           GetTaskQueueES  (KERNEL.119)
  */
 void WINAPI GetTaskQueueES16(void)
 {
@@ -1268,13 +1175,16 @@ void WINAPI GetTaskQueueES16(void)
 
 
 /***********************************************************************
- *           GetCurrentTask   (KERNEL.36)
+ *           GetCurrentTask   (KERNEL32.@)
  */
 HTASK16 WINAPI GetCurrentTask(void)
 {
     return NtCurrentTeb()->htask16;
 }
 
+/***********************************************************************
+ *           GetCurrentTask   (KERNEL.36)
+ */
 DWORD WINAPI WIN16_GetCurrentTask(void)
 {
     /* This is the version used by relay code; the first task is */
@@ -1292,13 +1202,13 @@ DWORD WINAPI GetCurrentPDB16(void)
 {
     TDB *pTask;
 
-    if (!(pTask = (TDB *)GlobalLock16( GetCurrentTask() ))) return 0;
+    if (!(pTask = TASK_GetCurrent())) return 0;
     return MAKELONG(pTask->hPDB, 0); /* FIXME */
 }
 
 
 /***********************************************************************
- *           GetCurPID16   (KERNEL.157)
+ *           GetCurPID   (KERNEL.157)
  */
 DWORD WINAPI GetCurPID16( DWORD unused )
 {
@@ -1326,35 +1236,23 @@ WORD WINAPI GetExeVersion16(void)
 {
     TDB *pTask;
 
-    if (!(pTask = (TDB *)GlobalLock16( GetCurrentTask() ))) return 0;
+    if (!(pTask = TASK_GetCurrent())) return 0;
     return pTask->version;
 }
 
 
 /***********************************************************************
- *           SetErrorMode16   (KERNEL.107)
+ *           SetErrorMode   (KERNEL.107)
  */
 UINT16 WINAPI SetErrorMode16( UINT16 mode )
 {
     TDB *pTask;
-    if (!(pTask = (TDB *)GlobalLock16( GetCurrentTask() ))) return 0;
+    if (!(pTask = TASK_GetCurrent())) return 0;
     pTask->error_mode = mode;
     return SetErrorMode( mode );
 }
 
 
-/***********************************************************************
- *           GetDOSEnvironment   (KERNEL.131)
- */
-SEGPTR WINAPI GetDOSEnvironment16(void)
-{
-    TDB *pTask;
-
-    if (!(pTask = (TDB *)GlobalLock16( GetCurrentTask() ))) return 0;
-    return PTR_SEG_OFF_TO_SEGPTR( pTask->pdb.environment, 0 );
-}
-
-
 /***********************************************************************
  *           GetNumTasks   (KERNEL.152)
  */
@@ -1374,7 +1272,7 @@ HINSTANCE16 WINAPI GetTaskDS16(void)
 {
     TDB *pTask;
 
-    if (!(pTask = (TDB *)GlobalLock16( GetCurrentTask() ))) return 0;
+    if (!(pTask = TASK_GetCurrent())) return 0;
     return GlobalHandleToSel16(pTask->hInstance);
 }
 
@@ -1386,7 +1284,7 @@ WORD WINAPI GetDummyModuleHandleDS16(void)
     TDB *pTask;
     WORD selector;
 
-    if (!(pTask = (TDB *)GlobalLock16( GetCurrentTask() ))) return 0;
+    if (!(pTask = TASK_GetCurrent())) return 0;
     if (!(pTask->flags & TDBF_WIN32)) return 0;
     selector = GlobalHandleToSel16( pTask->hModule );
     CURRENT_DS = selector;
@@ -1400,14 +1298,14 @@ BOOL16 WINAPI IsTask16( HTASK16 hTask )
 {
     TDB *pTask;
 
-    if (!(pTask = (TDB *)GlobalLock16( hTask ))) return FALSE;
+    if (!(pTask = TASK_GetPtr( hTask ))) return FALSE;
     if (GlobalSize16( hTask ) < sizeof(TDB)) return FALSE;
     return (pTask->magic == TDB_MAGIC);
 }
 
 
 /***********************************************************************
- *           IsWinOldApTask16   (KERNEL.158)
+ *           IsWinOldApTask   (KERNEL.158)
  */
 BOOL16 WINAPI IsWinOldApTask16( HTASK16 hTask )
 {
@@ -1424,7 +1322,7 @@ FARPROC16 WINAPI SetTaskSignalProc( HTASK16 hTask, FARPROC16 proc )
     FARPROC16 oldProc;
 
     if (!hTask) hTask = GetCurrentTask();
-    if (!(pTask = (TDB *)GlobalLock16( hTask ))) return NULL;
+    if (!(pTask = TASK_GetPtr( hTask ))) return NULL;
     oldProc = pTask->userhandler;
     pTask->userhandler = proc;
     return oldProc;
@@ -1438,11 +1336,11 @@ extern WORD CALLBACK TASK_CallTo16_word_wwwww(FARPROC16,WORD,WORD,WORD,WORD,WORD
 /* ### stop build ### */
 void TASK_CallTaskSignalProc( UINT16 uCode, HANDLE16 hTaskOrModule )
 {
-    TDB *pTask = (TDB *)GlobalLock16( GetCurrentTask() );
+    TDB *pTask = TASK_GetCurrent();
     if ( !pTask || !pTask->userhandler ) return;
 
-    TASK_CallTo16_word_wwwww( pTask->userhandler, 
-                              hTaskOrModule, uCode, 0, 
+    TASK_CallTo16_word_wwwww( pTask->userhandler,
+                              hTaskOrModule, uCode, 0,
                               pTask->hInstance, pTask->hQueue );
 }
 
@@ -1461,7 +1359,7 @@ WORD WINAPI SetSigHandler16( FARPROC16 newhandler, FARPROC16* oldhandler,
     {
         TDB *pTask;
 
-        if (!(pTask = (TDB *)GlobalLock16( GetCurrentTask() ))) return 0;
+        if (!(pTask = TASK_GetCurrent())) return 0;
         if (oldmode) *oldmode = pTask->signal_flags;
         pTask->signal_flags = newmode;
         if (oldhandler) *oldhandler = pTask->sighandler;
@@ -1481,13 +1379,13 @@ VOID WINAPI GlobalNotify16( FARPROC16 proc )
 {
     TDB *pTask;
 
-    if (!(pTask = (TDB *)GlobalLock16( GetCurrentTask() ))) return;
+    if (!(pTask = TASK_GetCurrent())) return;
     pTask->discardhandler = proc;
 }
 
 
 /***********************************************************************
- *           GetExePtr   (KERNEL.133)
+ *           GetExePtrHelper
  */
 static inline HMODULE16 GetExePtrHelper( HANDLE16 handle, HTASK16 *hTask )
 {
@@ -1504,7 +1402,7 @@ static inline HMODULE16 GetExePtrHelper( HANDLE16 handle, HTASK16 *hTask )
     *hTask = hFirstTask;
     while (*hTask)
     {
-        TDB *pTask = (TDB *)GlobalLock16( *hTask );
+        TDB *pTask = TASK_GetPtr( *hTask );
         if ((*hTask == handle) ||
             (pTask->hInstance == handle) ||
             (pTask->hQueue == handle) ||
@@ -1523,7 +1421,7 @@ static inline HMODULE16 GetExePtrHelper( HANDLE16 handle, HTASK16 *hTask )
     *hTask = hFirstTask;
     while (*hTask)
     {
-        TDB *pTask = (TDB *)GlobalLock16( *hTask );
+        TDB *pTask = TASK_GetPtr( *hTask );
         if ((*hTask == owner) ||
             (pTask->hInstance == owner) ||
             (pTask->hQueue == owner) ||
@@ -1534,6 +1432,9 @@ static inline HMODULE16 GetExePtrHelper( HANDLE16 handle, HTASK16 *hTask )
     return 0;
 }
 
+/***********************************************************************
+ *           GetExePtr   (KERNEL.133)
+ */
 HMODULE16 WINAPI WIN16_GetExePtr( HANDLE16 handle )
 {
     HTASK16 hTask = 0;
@@ -1544,6 +1445,10 @@ HMODULE16 WINAPI WIN16_GetExePtr( HANDLE16 handle )
     return hModule;
 }
 
+
+/***********************************************************************
+ *           K228   (KERNEL.228)
+ */
 HMODULE16 WINAPI GetExePtr( HANDLE16 handle )
 {
     HTASK16 hTask = 0;
@@ -1571,9 +1476,16 @@ BOOL16 WINAPI TaskNext16( TASKENTRY *lpte )
 
     TRACE_(toolhelp)("(%p): task=%04x\n", lpte, lpte->hNext );
     if (!lpte->hNext) return FALSE;
-    pTask = (TDB *)GlobalLock16( lpte->hNext );
-    if (!pTask || pTask->magic != TDB_MAGIC) return FALSE;
-    pInstData = (INSTANCEDATA *)PTR_SEG_OFF_TO_LIN( GlobalHandleToSel16(pTask->hInstance), 0 );
+
+    /* make sure that task and hInstance are valid (skip initial Wine task !) */
+    while (1) {
+        pTask = TASK_GetPtr( lpte->hNext );
+        if (!pTask || pTask->magic != TDB_MAGIC) return FALSE;
+        if (pTask->hInstance)
+            break;
+        lpte->hNext = pTask->hNext;
+    }
+    pInstData = MapSL( MAKESEGPTR( GlobalHandleToSel16(pTask->hInstance), 0 ) );
     lpte->hTask         = lpte->hNext;
     lpte->hTaskParent   = pTask->hParent;
     lpte->hInst         = pTask->hInstance;
@@ -1602,24 +1514,76 @@ BOOL16 WINAPI TaskFindHandle16( TASKENTRY *lpte, HTASK16 hTask )
 }
 
 
+typedef INT (WINAPI *MessageBoxA_funcptr)(HWND hWnd, LPCSTR text, LPCSTR title, UINT type);
+
+/**************************************************************************
+ *           FatalAppExit   (KERNEL.137)
+ */
+void WINAPI FatalAppExit16( UINT16 action, LPCSTR str )
+{
+    TDB *pTask = TASK_GetCurrent();
+
+    if (!pTask || !(pTask->error_mode & SEM_NOGPFAULTERRORBOX))
+    {
+        HMODULE mod = GetModuleHandleA( "user32.dll" );
+        if (mod)
+        {
+            MessageBoxA_funcptr pMessageBoxA = (MessageBoxA_funcptr)GetProcAddress( mod, "MessageBoxA" );
+            if (pMessageBoxA)
+            {
+                pMessageBoxA( 0, str, NULL, MB_SYSTEMMODAL | MB_OK );
+                goto done;
+            }
+        }
+        ERR( "%s\n", debugstr_a(str) );
+    }
+ done:
+    ExitThread(0xff);
+}
+
+
 /***********************************************************************
- *           GetAppCompatFlags16   (KERNEL.354)
+ *           TerminateApp   (TOOLHELP.77)
+ *
+ * See "Undocumented Windows".
  */
-DWORD WINAPI GetAppCompatFlags16( HTASK16 hTask )
+void WINAPI TerminateApp16(HTASK16 hTask, WORD wFlags)
 {
-    return GetAppCompatFlags( hTask );
+    if (hTask && hTask != GetCurrentTask())
+    {
+        FIXME("cannot terminate task %x\n", hTask);
+        return;
+    }
+
+    if (wFlags & NO_UAE_BOX)
+    {
+        UINT16 old_mode;
+        old_mode = SetErrorMode16(0);
+        SetErrorMode16(old_mode|SEM_NOGPFAULTERRORBOX);
+    }
+    FatalAppExit16( 0, NULL );
+
+    /* hmm, we're still alive ?? */
+
+    /* check undocumented flag */
+    if (!(wFlags & 0x8000))
+        TASK_CallTaskSignalProc( USIG16_TERMINATION, hTask );
+
+    /* UndocWin says to call int 0x21/0x4c exit=0xff here,
+       but let's just call ExitThread */
+    ExitThread(0xff);
 }
 
 
 /***********************************************************************
- *           GetAppCompatFlags   (USER32.206)
+ *           GetAppCompatFlags   (KERNEL.354)
  */
-DWORD WINAPI GetAppCompatFlags( HTASK hTask )
+DWORD WINAPI GetAppCompatFlags16( HTASK16 hTask )
 {
     TDB *pTask;
 
     if (!hTask) hTask = GetCurrentTask();
-    if (!(pTask=(TDB *)GlobalLock16( (HTASK16)hTask ))) return 0;
+    if (!(pTask=TASK_GetPtr( hTask ))) return 0;
     if (GlobalSize16(hTask) < sizeof(TDB)) return 0;
     return pTask->compat_flags;
 }