* 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)
static UINT16 nTaskCount = 0;
-static HTASK initial_task;
+static HTASK16 initial_task;
/***********************************************************************
* TASK_InstallTHHook
*/
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
*/
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;
}
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--;
*
* 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;
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;
}
base += pThunk->free;
pThunk->free = *(WORD *)((BYTE *)pThunk + pThunk->free);
- return PTR_SEG_OFF_TO_SEGPTR( sel, base );
+ return MAKESEGPTR( sel, base );
}
*
* 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;
* 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;
/* 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;
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 */
/* 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);
/* 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
*/
TDB *pTask;
HGLOBAL16 hPDB;
- if (!(pTask = (TDB *)GlobalLock16( hTask ))) return;
+ if (!(pTask = TASK_GetPtr( hTask ))) return;
hPDB = pTask->hPDB;
pTask->magic = 0xdead; /* invalidate signature */
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)
*
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 );
* 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;
}
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;
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;
}
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;
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 );
}
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--;
}
*/
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)
{
*/
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();
}
/***********************************************************************
}
/***********************************************************************
- * MakeProcInstance16 (KERNEL.51)
+ * MakeProcInstance (KERNEL.51)
*/
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;
}
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);
}
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 */
/***********************************************************************
- * 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,
* 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 ) );
}
/* 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))
/**********************************************************************
- * DefineHandleTable16 (KERNEL.94)
+ * DefineHandleTable (KERNEL.94)
*/
BOOL16 WINAPI DefineHandleTable16( WORD wOffset )
{
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;
TDB *pTask;
if (!hTask) hTask = GetCurrentTask();
- if (!(pTask = (TDB *)GlobalLock16( hTask ))) return 0;
+ if (!(pTask = TASK_GetPtr( hTask ))) return 0;
return pTask->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;
return (HQUEUE16)(teb? teb->queue : 0);
}
/***********************************************************************
* SetFastQueue (KERNEL.624)
*/
-VOID WINAPI SetFastQueue16( DWORD thread, HANDLE hQueue )
+VOID WINAPI SetFastQueue16( DWORD thread, HQUEUE16 hQueue )
{
TEB *teb = NULL;
if ( !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;
- 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;
}
/***********************************************************************
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 ),
/* 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;
*/
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 */
}
/* 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 */
/***********************************************************************
- * GetTaskQueueDS16 (KERNEL.118)
+ * GetTaskQueueDS (KERNEL.118)
*/
void WINAPI GetTaskQueueDS16(void)
{
/***********************************************************************
- * GetTaskQueueES16 (KERNEL.119)
+ * GetTaskQueueES (KERNEL.119)
*/
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 */
{
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 )
{
{
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)
*/
{
TDB *pTask;
- if (!(pTask = (TDB *)GlobalLock16( GetCurrentTask() ))) return 0;
+ if (!(pTask = TASK_GetCurrent())) return 0;
return GlobalHandleToSel16(pTask->hInstance);
}
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;
{
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 )
{
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;
/* ### 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 );
}
{
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;
{
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 )
{
*hTask = hFirstTask;
while (*hTask)
{
- TDB *pTask = (TDB *)GlobalLock16( *hTask );
+ TDB *pTask = TASK_GetPtr( *hTask );
if ((*hTask == handle) ||
(pTask->hInstance == handle) ||
(pTask->hQueue == handle) ||
*hTask = hFirstTask;
while (*hTask)
{
- TDB *pTask = (TDB *)GlobalLock16( *hTask );
+ TDB *pTask = TASK_GetPtr( *hTask );
if ((*hTask == owner) ||
(pTask->hInstance == owner) ||
(pTask->hQueue == owner) ||
return 0;
}
+/***********************************************************************
+ * GetExePtr (KERNEL.133)
+ */
HMODULE16 WINAPI WIN16_GetExePtr( HANDLE16 handle )
{
HTASK16 hTask = 0;
return hModule;
}
+
+/***********************************************************************
+ * K228 (KERNEL.228)
+ */
HMODULE16 WINAPI GetExePtr( HANDLE16 handle )
{
HTASK16 hTask = 0;
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;
}
+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;
}