
Sun Oct 1 15:48:34 1995 Alexandre Julliard <julliard@sunsite.unc> * [controls/menu.c] Fixed GetMenuString() for non-string items. * [debugger/*.c] First attempt to check validity of pointers before memory accesses. For now only segmented pointers are checked. * [debugger/dbg.y] [memory/ldt.c] Added possibility to dump only one segment with 'info segment'. * [include/bitmaps/ocr_*] Added all OEM cursors as XPM bitmaps. * [include/cursoricon.h] [objects/cursoricon.c] Rewrote all cursor and icon management to use the same memory layout as Windows, and to factor common code between icons and cursors. Implemented icon directory lookup to find the best matching icon (i.e. the color one). Implemented CopyCursor() and DumpIcon(). * [loader/module.c] For disabled built-in modules, we now try to load the Windows DLL first, and if this fails we fall back to using the built-in module anyway. * [memory/global.c] Fixed GlobalHandle() to return the correct selector in the high word even if we are passed a handle in the first place. * [miscemu/instr.c] Take into account the size of the operand and of the stack segment when incrementing the stack pointer. Avoid referencing FS_reg and GS_reg on *BSD. * [objects/dib.c] All DIB functions now accept a BITMAPCOREHEADER format bitmap. Monochrome DIBs are created as monochrome bitmap iff they are black and white. * [objects/oembitmap.c] Added support for OEM cursors, changed OBM_LoadIcon to use the new icon memory layout. * [rc/sysres_Fr.rc] Added French [Fr] language support. * [win32/environment.c] Fixed GetCommandLineA() to use current PDB. * [windows/event.c] [windows/winpos.c] Simulate a mouse motion event upon SetWindowPos() to force the cursor to be set correctly. Sat Sep 30 17:49:32 Cameron Heide (heide@ee.ualberta.ca) * [win32/*] New Win32 kernel functions: GetACP, GetCPInfo, GetEnvironmentVariableA, GetFileType, GetLastError, GetOEMCP, GetStartupInfoA, GetTimeZoneInformation, SetEnvironmentVariable, SetFilePointer, SetLastError, VirtualAlloc, VirtualFree, WriteFile. Completed implementations of GetCommandLineA. * [include/kernel32.h] New file. * [loader/main.c] Call initialization function for Win32 data (doesn't currently do anything). * [misc/main.c] Implemented GetEnvironmentVariableA, SetEnvironmentVariableA. Sat Sep 30 00:26:56 1995 Niels de Carpentier <niels@cindy.et.tudelft.nl> * [windows/winpos.c][miscemu/emulate.c][loader/module.c] [misc/commdlg.c] Misc. bug fixes Fri Sep 29 16:16:13 1995 Jim Peterson <jspeter@birch.ee.vt.edu> * [*/*] For Winelib, explicit casts have been placed where warnings were usually generated. printf formats which give the format for printing a handle as "%04x" or something similar have been changed to use the NPFMT macro defined in include/wintypes.h. Some times, explicit casts were also necessary. Parameter, field, and variable declarations have been made more exact, such as converting 'WORD wParam' to 'WPARAM wParam' or 'WORD hFont' to 'HFONT hFont'. Any call of the form GetWindowWord(hwnd,GWW_HINSTANCE) has been replaced with a call to WIN_GetWindowInstance(hwnd). * [controls/combo.c] Added WINELIB32 support in CLBoxGetCombo(). * [include/dialog.h] Commented out the '#ifndef WINELIB' around the '#pragma pack(1)'. winelib needs the packing as well (e.g. when accessing resources like sysres_DIALOG_SHELL_ABOUT_MSGBOX). * [include/windows.h] Got rid of the F[a-k] macros, which were cluttering up the global namespace. * [include/windows.h] [windows/defwnd.c] Added Win32 messages WM_CTLCOLOR*. * [include/wintypes.h] Put in preprocessor '#define WINELIB32' if appropriate and changed the types of some typedefs (WPARAM, HANDLE) based on this. * [loader/module.c] [toolkit/miscstubs.c] Added #ifdef'd portion in LoadModule to handle loading a WINElib module (already loaded, just init values). '#ifdef'ed out the definition for GetWndProcEntry16 and added a new version to toolkit/miscstubs.c. * [misc/shell.c] Adjusted the lengths of AppName and AppMisc from 512,512 to 128,906. Same amount of total storage, but much more reasonable. Also, changed calls to strcpy() in ShellAbout() to calls to strncpy() instead. This was a difficult bug to track down, but the AppMisc field was being initialized with the contributers text, which was much larger than 512 characters. * [toolkit/atom.c] New file for atom-handling functions. Copied from memory/atom.c and then heavily modified. Right now, it's just a linked list of atoms. Consider it as a hash table with just one entry. It's easily changed later. * [toolkit/heap.c] Commented out the heap functions with a "#ifdef WINELIB16" and put in a Win32 version (which is basically a modified copy). * [toolkit/sup.c] [toolkit/miscstubs.c] Moved the stuff I put in toolkit/sup.c into toolkit/miscstubs.c and added quite a few more stubs. * [toolkit/winmain.c] Rearranged startup code in _WinMain. I think this will work. * [toolkit/Makefile.in] Added targets for 'hello' and 'hello2' in case anyone cares to try out the sample programs. Wed Sep 27 23:13:43 1995 Anand Kumria <akumria@ozemail.com.au> * [miscemu/int2f.c] [miscemu/vxd.c] [if1632/winprocs.spec] First attempt at support for some VxDs. Comm, Shell and Pagefile. Tue Sep 26 21:34:45 1995 Hans de Graaff <graaff@twi72.twi.tudelft.nl> * [misc/dos_fs.c] DOS_SimplifyPath: Also remove "/./" from path. (Happens when starting applications like 'wine ./excel.exe') Sat Sep 23 23:32:40 1995 Morten Welinder <terra@diku.dk> * [configure.in] Avoid relative path for wine.ini. * [rc/sysres_Da.rc] Support for Danish [Da] language. * [misc/main.c] [miscemu/cpu.c] Return the processor we're running on correctly. * [miscemu/int2f.c] Minor stuff in int 0x2f, function 0x16. Sat Sep 23 1995 17:58:04 Marcus Meissner <msmeissn@faui01.informatik.uni-erlangen.de> * [misc/shell.c] [misc/main.c] Implement saving and loading of the registry database (needed for OLE). Very experimental. Fixed ShellExecute(). * [miscemu/int21.c] EEXIST is not a critical error condition for mkdir(). Fri Sep 22 01:33:34 1995 Alex Korobka <alex@phm6.pharm.sunysb.edu> * [include/shell.h] [misc/shell.c] Implemented 4 drag/drop functions with documented functionality. * [multimedia/time.c] "Fixed" MMSysTimeCallback kludge so Excel5 loads up without crashing. * [*/*] Added new files, more message definitions, structures, debug info, etc. Rewrote message logging functions to produce output similar to WinSight. Check out -debugmsg +message option. * [misc/file.c] Fixed GetDriveType return value. * [windows/message.c] Hooks are invoked in normal order. * [miscemu/*] Added some functions and interrupts. * [misc/shell.c] Implemented Drag... functions. Thu Sep 21 23:50:12 1995 Jukka Iivonen <iivonen@cc.helsinki.fi> * [rc/sysres_Fi.rc] [rc/sysres.rc] First attempt at Finnish [Fi] language support.
1152 lines
31 KiB
C
1152 lines
31 KiB
C
/*
|
|
* Task functions
|
|
*
|
|
* Copyright 1995 Alexandre Julliard
|
|
*/
|
|
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
#include "windows.h"
|
|
#include "task.h"
|
|
#include "callback.h"
|
|
#include "dos_fs.h"
|
|
#include "debugger.h"
|
|
#include "global.h"
|
|
#include "instance.h"
|
|
#include "miscemu.h"
|
|
#include "module.h"
|
|
#include "neexe.h"
|
|
#include "options.h"
|
|
#include "selectors.h"
|
|
#include "toolhelp.h"
|
|
#include "stddebug.h"
|
|
#include "debug.h"
|
|
#include "dde_proc.h"
|
|
|
|
/* Min. number of thunks allocated when creating a new segment */
|
|
#define MIN_THUNKS 32
|
|
|
|
/* 32-bit stack size for each task */
|
|
/* Must not be greater than 64k, or MAKE_SEGPTR won't work */
|
|
#define STACK32_SIZE 0x10000
|
|
|
|
|
|
static HTASK hFirstTask = 0;
|
|
static HTASK hCurrentTask = 0;
|
|
static HTASK hTaskToKill = 0;
|
|
static HTASK hLockedTask = 0;
|
|
static WORD nTaskCount = 0;
|
|
static HANDLE hDOSEnvironment = 0;
|
|
|
|
/* TASK_Reschedule() 16-bit entry point */
|
|
static FARPROC TASK_RescheduleProc;
|
|
|
|
#ifdef WINELIB
|
|
#define TASK_SCHEDULE() TASK_Reschedule();
|
|
#else
|
|
#define TASK_SCHEDULE() CallTo16_word_(TASK_RescheduleProc,0)
|
|
#endif
|
|
|
|
|
|
static HANDLE TASK_CreateDOSEnvironment(void);
|
|
|
|
/***********************************************************************
|
|
* TASK_Init
|
|
*/
|
|
BOOL TASK_Init(void)
|
|
{
|
|
TASK_RescheduleProc = (FARPROC)GetWndProcEntry16( "TASK_Reschedule" );
|
|
if (!(hDOSEnvironment = TASK_CreateDOSEnvironment()))
|
|
fprintf( stderr, "Not enough memory for DOS Environment\n" );
|
|
return (hDOSEnvironment != 0);
|
|
}
|
|
|
|
|
|
/***********************************************************************
|
|
* TASK_CreateDOSEnvironment
|
|
*
|
|
* Create the original DOS environment.
|
|
*/
|
|
static HANDLE TASK_CreateDOSEnvironment(void)
|
|
{
|
|
static const char program_name[] = "KRNL386.EXE";
|
|
char **e, *p;
|
|
int initial_size, size;
|
|
HANDLE handle;
|
|
|
|
extern char **environ;
|
|
extern char WindowsDirectory[], SystemDirectory[];
|
|
|
|
/* DOS environment format:
|
|
* ASCIIZ string 1
|
|
* ASCIIZ string 2
|
|
* ...
|
|
* ASCIIZ string n
|
|
* ASCIIZ PATH=xxx
|
|
* ASCIIZ windir=xxx
|
|
* BYTE 0
|
|
* WORD 1
|
|
* ASCIIZ program name (e.g. C:\WINDOWS\SYSTEM\KRNL386.EXE)
|
|
*/
|
|
|
|
/* First compute the size of the fixed part of the environment */
|
|
|
|
initial_size = 5 + /* PATH= */
|
|
strlen(WindowsPath) + 1 + /* path value */
|
|
7 + /* windir= */
|
|
strlen(WindowsDirectory) + 1 + /* windir value */
|
|
1 + /* BYTE 0 at end */
|
|
sizeof(WORD) + /* WORD 1 */
|
|
strlen(SystemDirectory) + 1 + /* program directory */
|
|
strlen(program_name) + 1; /* program name */
|
|
|
|
/* Compute the total size of the Unix environment (except path) */
|
|
|
|
for (e = environ, size = initial_size; *e; e++)
|
|
{
|
|
if (strncasecmp(*e, "path=", 5))
|
|
{
|
|
int len = strlen(*e) + 1;
|
|
if (size + len >= 32767)
|
|
{
|
|
fprintf( stderr, "Warning: environment larger than 32k.\n" );
|
|
break;
|
|
}
|
|
size += len;
|
|
}
|
|
}
|
|
|
|
|
|
/* Now allocate the environment */
|
|
|
|
if (!(handle = GlobalAlloc( GMEM_FIXED, size ))) return 0;
|
|
p = (char *)GlobalLock( handle );
|
|
|
|
/* And fill it with the Unix environment */
|
|
|
|
for (e = environ, size = initial_size; *e; e++)
|
|
{
|
|
if (strncasecmp(*e, "path=", 5))
|
|
{
|
|
int len = strlen(*e) + 1;
|
|
if (size + len >= 32767) break;
|
|
strcpy( p, *e );
|
|
size += len;
|
|
p += len;
|
|
}
|
|
}
|
|
|
|
/* Now add the path and Windows directory */
|
|
|
|
strcpy( p, "PATH=" );
|
|
strcat( p, WindowsPath );
|
|
p += strlen(p) + 1;
|
|
|
|
strcpy( p, "windir=" );
|
|
strcat( p, WindowsDirectory );
|
|
p += strlen(p) + 1;
|
|
|
|
/* Now add the program name */
|
|
|
|
*p++ = '\0';
|
|
*(WORD *)p = 1;
|
|
p += sizeof(WORD);
|
|
strcpy( p, SystemDirectory );
|
|
strcat( p, "\\" );
|
|
strcat( p, program_name );
|
|
|
|
/* Display it */
|
|
|
|
p = (char *) GlobalLock( handle );
|
|
dprintf_task(stddeb, "Master DOS environment at %p\n", p);
|
|
for (; *p; p += strlen(p) + 1) dprintf_task(stddeb, " %s\n", p);
|
|
dprintf_task( stddeb, "Progname: %s\n", p+3 );
|
|
|
|
return handle;
|
|
}
|
|
|
|
|
|
/***********************************************************************
|
|
* TASK_LinkTask
|
|
*/
|
|
static void TASK_LinkTask( HTASK hTask )
|
|
{
|
|
HTASK *prevTask;
|
|
TDB *pTask;
|
|
|
|
if (!(pTask = (TDB *)GlobalLock( hTask ))) return;
|
|
prevTask = &hFirstTask;
|
|
while (*prevTask)
|
|
{
|
|
TDB *prevTaskPtr = (TDB *)GlobalLock( *prevTask );
|
|
if (prevTaskPtr->priority >= pTask->priority) break;
|
|
prevTask = &prevTaskPtr->hNext;
|
|
}
|
|
pTask->hNext = *prevTask;
|
|
*prevTask = hTask;
|
|
nTaskCount++;
|
|
}
|
|
|
|
|
|
/***********************************************************************
|
|
* TASK_UnlinkTask
|
|
*/
|
|
static void TASK_UnlinkTask( HTASK hTask )
|
|
{
|
|
HTASK *prevTask;
|
|
TDB *pTask;
|
|
|
|
prevTask = &hFirstTask;
|
|
while (*prevTask && (*prevTask != hTask))
|
|
{
|
|
pTask = (TDB *)GlobalLock( *prevTask );
|
|
prevTask = &pTask->hNext;
|
|
}
|
|
if (*prevTask)
|
|
{
|
|
pTask = (TDB *)GlobalLock( *prevTask );
|
|
*prevTask = pTask->hNext;
|
|
pTask->hNext = 0;
|
|
nTaskCount--;
|
|
}
|
|
}
|
|
|
|
|
|
/***********************************************************************
|
|
* TASK_CreateThunks
|
|
*
|
|
* Create a thunk free-list in segment 'handle', starting from offset 'offset'
|
|
* and containing 'count' entries.
|
|
*/
|
|
static void TASK_CreateThunks( HGLOBAL handle, WORD offset, WORD count )
|
|
{
|
|
int i;
|
|
WORD free;
|
|
THUNKS *pThunk;
|
|
|
|
pThunk = (THUNKS *)((BYTE *)GlobalLock( handle ) + offset);
|
|
pThunk->next = 0;
|
|
pThunk->magic = THUNK_MAGIC;
|
|
pThunk->free = (int)&pThunk->thunks - (int)pThunk;
|
|
free = pThunk->free;
|
|
for (i = 0; i < count-1; i++)
|
|
{
|
|
free += 8; /* Offset of next thunk */
|
|
pThunk->thunks[4*i] = free;
|
|
}
|
|
pThunk->thunks[4*i] = 0; /* Last thunk */
|
|
}
|
|
|
|
|
|
/***********************************************************************
|
|
* TASK_AllocThunk
|
|
*
|
|
* Allocate a thunk for MakeProcInstance().
|
|
*/
|
|
static SEGPTR TASK_AllocThunk( HTASK hTask )
|
|
{
|
|
TDB *pTask;
|
|
THUNKS *pThunk;
|
|
WORD sel, base;
|
|
|
|
if (!(pTask = (TDB *)GlobalLock( hTask ))) return 0;
|
|
sel = pTask->hCSAlias;
|
|
pThunk = &pTask->thunks;
|
|
base = (int)pThunk - (int)pTask;
|
|
while (!pThunk->free)
|
|
{
|
|
sel = pThunk->next;
|
|
if (!sel) /* Allocate a new segment */
|
|
{
|
|
sel = GLOBAL_Alloc( GMEM_FIXED, sizeof(THUNKS) + (MIN_THUNKS-1)*8,
|
|
pTask->hPDB, TRUE, FALSE, FALSE );
|
|
if (!sel) return (SEGPTR)0;
|
|
TASK_CreateThunks( sel, 0, MIN_THUNKS );
|
|
pThunk->next = sel;
|
|
}
|
|
pThunk = (THUNKS *)GlobalLock( sel );
|
|
base = 0;
|
|
}
|
|
base += pThunk->free;
|
|
pThunk->free = *(WORD *)((BYTE *)pThunk + pThunk->free);
|
|
return MAKELONG( base, sel );
|
|
}
|
|
|
|
|
|
/***********************************************************************
|
|
* TASK_FreeThunk
|
|
*
|
|
* Free a MakeProcInstance() thunk.
|
|
*/
|
|
static BOOL TASK_FreeThunk( HTASK hTask, SEGPTR thunk )
|
|
{
|
|
TDB *pTask;
|
|
THUNKS *pThunk;
|
|
WORD sel, base;
|
|
|
|
if (!(pTask = (TDB *)GlobalLock( hTask ))) return 0;
|
|
sel = pTask->hCSAlias;
|
|
pThunk = &pTask->thunks;
|
|
base = (int)pThunk - (int)pTask;
|
|
while (sel && (sel != HIWORD(thunk)))
|
|
{
|
|
sel = pThunk->next;
|
|
pThunk = (THUNKS *)GlobalLock( sel );
|
|
base = 0;
|
|
}
|
|
if (!sel) return FALSE;
|
|
*(WORD *)((BYTE *)pThunk + LOWORD(thunk) - base) = pThunk->free;
|
|
pThunk->free = LOWORD(thunk) - base;
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
/***********************************************************************
|
|
* TASK_CallToStart
|
|
*
|
|
* 32-bit entry point for a new task. This function is responsible for
|
|
* setting up the registers and jumping to the 16-bit entry point.
|
|
*/
|
|
static void TASK_CallToStart(void)
|
|
{
|
|
int cs_reg, ds_reg, ip_reg;
|
|
TDB *pTask = (TDB *)GlobalLock( hCurrentTask );
|
|
NE_MODULE *pModule = (NE_MODULE *)GlobalLock( pTask->hModule );
|
|
SEGTABLEENTRY *pSegTable = NE_SEG_TABLE( pModule );
|
|
|
|
/* Registers at initialization must be:
|
|
* ax zero
|
|
* bx stack size in bytes
|
|
* cx heap size in bytes
|
|
* si previous app instance
|
|
* di current app instance
|
|
* bp zero
|
|
* es selector to the PSP
|
|
* ds dgroup of the application
|
|
* ss stack selector
|
|
* sp top of the stack
|
|
*/
|
|
|
|
cs_reg = pSegTable[pModule->cs - 1].selector;
|
|
ip_reg = pModule->ip;
|
|
ds_reg = pSegTable[pModule->dgroup - 1].selector;
|
|
#ifndef WINELIB
|
|
/* JBP: I doubt a CallTo16_regs_ is possible in libwine.a, and IF1632 is not
|
|
* allowed.
|
|
*/
|
|
IF1632_Saved16_ss = pTask->ss;
|
|
IF1632_Saved16_sp = pTask->sp;
|
|
dprintf_task( stddeb, "Starting main program: cs:ip=%04x:%04x ds=%04x ss:sp=%04x:%04x\n",
|
|
cs_reg, ip_reg, ds_reg,
|
|
IF1632_Saved16_ss, IF1632_Saved16_sp);
|
|
|
|
CallTo16_regs_( (FARPROC)(cs_reg << 16 | ip_reg), ds_reg,
|
|
pTask->hPDB /*es*/, 0 /*bp*/, 0 /*ax*/,
|
|
pModule->stack_size /*bx*/, pModule->heap_size /*cx*/,
|
|
0 /*dx*/, 0 /*si*/, ds_reg /*di*/ );
|
|
#else
|
|
fprintf(stderr, "JBP: Ignoring main program: cs:ip=%04x:%04x ds=%04x ss:sp=%04x:%04x\n",
|
|
cs_reg, ip_reg, ds_reg,
|
|
pTask->ss, pTask->sp);
|
|
#endif
|
|
/* This should never return */
|
|
fprintf( stderr, "TASK_CallToStart: Main program returned!\n" );
|
|
TASK_KillCurrentTask( 1 );
|
|
}
|
|
|
|
|
|
/***********************************************************************
|
|
* TASK_CreateTask
|
|
*/
|
|
HTASK TASK_CreateTask( HMODULE hModule, HANDLE hInstance, HANDLE hPrevInstance,
|
|
HANDLE hEnvironment, char *cmdLine, WORD cmdShow )
|
|
{
|
|
HTASK hTask;
|
|
TDB *pTask;
|
|
HANDLE hParentEnv;
|
|
NE_MODULE *pModule;
|
|
SEGTABLEENTRY *pSegTable;
|
|
LPSTR name;
|
|
char filename[256];
|
|
#ifndef WINELIB32
|
|
char *stack16Top, *stack32Top;
|
|
STACK16FRAME *frame16;
|
|
STACK32FRAME *frame32;
|
|
extern DWORD CALL16_RetAddr_word;
|
|
#endif
|
|
|
|
if (!(pModule = (NE_MODULE *)GlobalLock( hModule ))) return 0;
|
|
pSegTable = NE_SEG_TABLE( pModule );
|
|
|
|
/* Allocate the task structure */
|
|
|
|
hTask = GLOBAL_Alloc( GMEM_FIXED | GMEM_ZEROINIT, sizeof(TDB),
|
|
hModule, FALSE, FALSE, FALSE );
|
|
if (!hTask) return 0;
|
|
pTask = (TDB *)GlobalLock( hTask );
|
|
|
|
/* Allocate the new environment block */
|
|
|
|
if (!(hParentEnv = hEnvironment))
|
|
{
|
|
TDB *pParent = (TDB *)GlobalLock( hCurrentTask );
|
|
hParentEnv = pParent ? pParent->pdb.environment : hDOSEnvironment;
|
|
}
|
|
/* FIXME: do we really need to make a copy also when */
|
|
/* we don't use the parent environment? */
|
|
if (!(hEnvironment = GlobalAlloc( GMEM_FIXED, GlobalSize( hParentEnv ) )))
|
|
{
|
|
GlobalFree( hTask );
|
|
return 0;
|
|
}
|
|
memcpy( GlobalLock( hEnvironment ), GlobalLock( hParentEnv ),
|
|
GlobalSize( hParentEnv ) );
|
|
|
|
/* Get current directory */
|
|
|
|
GetModuleFileName( hModule, filename, sizeof(filename) );
|
|
name = strrchr(filename, '\\');
|
|
if (name) *(name+1) = 0;
|
|
|
|
/* Fill the task structure */
|
|
|
|
pTask->nEvents = 1; /* So the task can be started */
|
|
pTask->hSelf = hTask;
|
|
pTask->flags = 0;
|
|
pTask->version = pModule->expected_version;
|
|
pTask->hInstance = hInstance;
|
|
pTask->hPrevInstance = hPrevInstance;
|
|
pTask->hModule = hModule;
|
|
pTask->hParent = hCurrentTask;
|
|
pTask->curdrive = filename[0] - 'A' + 0x80;
|
|
pTask->magic = TDB_MAGIC;
|
|
pTask->nCmdShow = cmdShow;
|
|
strcpy( pTask->curdir, filename+2 );
|
|
|
|
/* Create the thunks block */
|
|
|
|
TASK_CreateThunks( hTask, (int)&pTask->thunks - (int)pTask, 7 );
|
|
|
|
/* Copy the module name */
|
|
|
|
name = MODULE_GetModuleName( hModule );
|
|
strncpy( pTask->module_name, name, sizeof(pTask->module_name) );
|
|
|
|
/* Fill the PDB */
|
|
|
|
pTask->pdb.int20 = 0x20cd;
|
|
pTask->pdb.dispatcher[0] = 0x9a; /* ljmp */
|
|
*(DWORD *)&pTask->pdb.dispatcher[1] = MODULE_GetEntryPoint( GetModuleHandle("KERNEL"), 102 ); /* KERNEL.102 is DOS3Call() */
|
|
#ifndef WINELIB
|
|
pTask->pdb.savedint22 = INT_GetHandler( 0x22 );
|
|
pTask->pdb.savedint23 = INT_GetHandler( 0x23 );
|
|
pTask->pdb.savedint24 = INT_GetHandler( 0x24 );
|
|
#endif
|
|
pTask->pdb.environment = hEnvironment;
|
|
strncpy( pTask->pdb.cmdLine + 1, cmdLine, 126 );
|
|
pTask->pdb.cmdLine[127] = '\0';
|
|
pTask->pdb.cmdLine[0] = strlen( pTask->pdb.cmdLine + 1 );
|
|
|
|
/* Get the compatibility flags */
|
|
|
|
pTask->compat_flags = GetProfileInt( name, "Compatibility", 0 );
|
|
|
|
/* Allocate a selector for the PDB */
|
|
|
|
pTask->hPDB = GLOBAL_CreateBlock( GMEM_FIXED, &pTask->pdb, sizeof(PDB),
|
|
hModule, FALSE, FALSE, FALSE, NULL );
|
|
|
|
/* 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 */
|
|
|
|
FarSetOwner( pTask->pdb.environment, pTask->hPDB );
|
|
|
|
/* Default DTA overwrites command-line */
|
|
|
|
pTask->dta = MAKELONG( (int)&pTask->pdb.cmdLine - (int)&pTask->pdb,
|
|
pTask->hPDB );
|
|
|
|
/* Allocate the 32-bit stack */
|
|
|
|
#ifndef WINELIB
|
|
pTask->hStack32 = GLOBAL_Alloc( GMEM_FIXED, STACK32_SIZE, pTask->hPDB,
|
|
FALSE, FALSE, FALSE );
|
|
|
|
/* Create the 32-bit stack frame */
|
|
|
|
*(DWORD *)GlobalLock(pTask->hStack32) = 0xDEADBEEF;
|
|
stack32Top = (char*)GlobalLock(pTask->hStack32) + STACK32_SIZE;
|
|
frame32 = (STACK32FRAME *)stack32Top - 1;
|
|
frame32->saved_esp = (DWORD)stack32Top;
|
|
frame32->edi = 0;
|
|
frame32->esi = 0;
|
|
frame32->edx = 0;
|
|
frame32->ecx = 0;
|
|
frame32->ebx = 0;
|
|
frame32->ebp = 0;
|
|
frame32->retaddr = (DWORD)TASK_CallToStart;
|
|
frame32->codeselector = WINE_CODE_SELECTOR;
|
|
pTask->esp = (DWORD)frame32;
|
|
|
|
/* Create the 16-bit stack frame */
|
|
|
|
pTask->ss = hInstance;
|
|
pTask->sp = ((pModule->sp != 0) ? pModule->sp :
|
|
pSegTable[pModule->ss-1].minsize + pModule->stack_size) & ~1;
|
|
stack16Top = (char *)PTR_SEG_OFF_TO_LIN( pTask->ss, pTask->sp );
|
|
frame16 = (STACK16FRAME *)stack16Top - 1;
|
|
frame16->saved_ss = 0; /*pTask->ss;*/
|
|
frame16->saved_sp = 0; /*pTask->sp;*/
|
|
frame16->ds = frame16->es = pTask->hInstance;
|
|
frame16->entry_point = 0;
|
|
frame16->ordinal_number = 24; /* WINPROCS.24 is TASK_Reschedule */
|
|
frame16->dll_id = 24; /* WINPROCS */
|
|
frame16->bp = 0;
|
|
frame16->ip = LOWORD( CALL16_RetAddr_word );
|
|
frame16->cs = HIWORD( CALL16_RetAddr_word );
|
|
pTask->sp -= sizeof(STACK16FRAME);
|
|
|
|
/* If there's no 16-bit stack yet, use a part of the new task stack */
|
|
/* This is only needed to have a stack to switch from on the first */
|
|
/* call to DirectedYield(). */
|
|
|
|
if (!IF1632_Saved16_ss)
|
|
{
|
|
IF1632_Saved16_ss = pTask->ss;
|
|
IF1632_Saved16_sp = pTask->sp;
|
|
}
|
|
|
|
/* Add a breakpoint at the start of the task */
|
|
|
|
if (Options.debug)
|
|
{
|
|
DBG_ADDR addr = { pSegTable[pModule->cs-1].selector, pModule->ip };
|
|
fprintf( stderr, "Task '%s': ", name );
|
|
DEBUG_AddBreakpoint( &addr );
|
|
}
|
|
#endif
|
|
|
|
/* Add the task to the linked list */
|
|
|
|
TASK_LinkTask( hTask );
|
|
|
|
dprintf_task( stddeb, "CreateTask: module='%s' cmdline='%s' task="NPFMT"\n",
|
|
name, cmdLine, hTask );
|
|
|
|
return hTask;
|
|
}
|
|
|
|
|
|
/***********************************************************************
|
|
* TASK_DeleteTask
|
|
*/
|
|
static void TASK_DeleteTask( HTASK hTask )
|
|
{
|
|
TDB *pTask;
|
|
|
|
if (!(pTask = (TDB *)GlobalLock( hTask ))) return;
|
|
|
|
/* Free the task module */
|
|
|
|
FreeModule( pTask->hModule );
|
|
|
|
/* Free all memory used by this task (including the 32-bit stack, */
|
|
/* the environment block and the thunk segments). */
|
|
|
|
GlobalFreeAll( pTask->hPDB );
|
|
|
|
/* Free the selector aliases */
|
|
|
|
GLOBAL_FreeBlock( pTask->hCSAlias );
|
|
GLOBAL_FreeBlock( pTask->hPDB );
|
|
|
|
/* Free the task structure itself */
|
|
|
|
GlobalFree( hTask );
|
|
}
|
|
|
|
|
|
/***********************************************************************
|
|
* TASK_KillCurrentTask
|
|
*
|
|
* Kill the currently running task. As it's not possible to kill the
|
|
* current task like this, it is simply marked for destruction, and will
|
|
* be killed when either TASK_Reschedule or this function is called again
|
|
* in the context of another task.
|
|
*/
|
|
void TASK_KillCurrentTask( int exitCode )
|
|
{
|
|
if (hTaskToKill && (hTaskToKill != hCurrentTask))
|
|
{
|
|
/* If another task is already marked for destruction, */
|
|
/* we call kill it now, as we are in another context. */
|
|
TASK_DeleteTask( hTaskToKill );
|
|
}
|
|
|
|
if (nTaskCount <= 1)
|
|
{
|
|
dprintf_task( stddeb, "Killing the last task, exiting\n" );
|
|
exit(0);
|
|
}
|
|
|
|
/* Remove the task from the list to be sure we never switch back to it */
|
|
TASK_UnlinkTask( hCurrentTask );
|
|
|
|
hTaskToKill = hCurrentTask;
|
|
hLockedTask = 0;
|
|
Yield();
|
|
/* We never return from Yield() */
|
|
}
|
|
|
|
|
|
/***********************************************************************
|
|
* TASK_Reschedule
|
|
*
|
|
* This is where all the magic of task-switching happens!
|
|
*
|
|
* This function should only be called via the TASK_SCHEDULE() macro, to make
|
|
* sure that all the context is saved correctly.
|
|
*/
|
|
void TASK_Reschedule(void)
|
|
{
|
|
TDB *pOldTask = NULL, *pNewTask;
|
|
HTASK hTask = 0;
|
|
|
|
#ifdef CONFIG_IPC
|
|
dde_reschedule();
|
|
#endif
|
|
/* First check if there's a task to kill */
|
|
|
|
if (hTaskToKill && (hTaskToKill != hCurrentTask))
|
|
{
|
|
TASK_DeleteTask( hTaskToKill );
|
|
hTaskToKill = 0;
|
|
}
|
|
|
|
/* If current task is locked, simply return */
|
|
|
|
if (hLockedTask) return;
|
|
|
|
/* Find a task to yield to */
|
|
|
|
pOldTask = (TDB *)GlobalLock( hCurrentTask );
|
|
if (pOldTask && pOldTask->hYieldTo)
|
|
{
|
|
/* If a task is stored in hYieldTo of the current task (put there */
|
|
/* by DirectedYield), yield to it only if it has events pending. */
|
|
hTask = pOldTask->hYieldTo;
|
|
if (!(pNewTask = (TDB *)GlobalLock( hTask )) || !pNewTask->nEvents)
|
|
hTask = 0;
|
|
}
|
|
|
|
if (!hTask)
|
|
{
|
|
hTask = hFirstTask;
|
|
while (hTask)
|
|
{
|
|
pNewTask = (TDB *)GlobalLock( hTask );
|
|
if (pNewTask->nEvents && (hTask != hCurrentTask)) break;
|
|
hTask = pNewTask->hNext;
|
|
}
|
|
}
|
|
|
|
/* If there's a task to kill, switch to any other task, */
|
|
/* even if it doesn't have events pending. */
|
|
|
|
if (!hTask && hTaskToKill) hTask = hFirstTask;
|
|
|
|
if (!hTask) return; /* Do nothing */
|
|
|
|
pNewTask = (TDB *)GlobalLock( hTask );
|
|
dprintf_task( stddeb, "Switching to task "NPFMT" (%.8s)\n",
|
|
hTask, pNewTask->module_name );
|
|
|
|
/* Save the stacks of the previous task (if any) */
|
|
|
|
#ifndef WINELIB /* FIXME: JBP: IF1632 not allowed in libwine.a */
|
|
if (pOldTask)
|
|
{
|
|
pOldTask->ss = IF1632_Saved16_ss;
|
|
pOldTask->sp = IF1632_Saved16_sp;
|
|
pOldTask->esp = IF1632_Saved32_esp;
|
|
}
|
|
else IF1632_Original32_esp = IF1632_Saved32_esp;
|
|
#endif
|
|
|
|
/* Make the task the last in the linked list (round-robin scheduling) */
|
|
|
|
pNewTask->priority++;
|
|
TASK_UnlinkTask( hTask );
|
|
TASK_LinkTask( hTask );
|
|
pNewTask->priority--;
|
|
|
|
/* Switch to the new stack */
|
|
|
|
hCurrentTask = hTask;
|
|
#ifndef WINELIB /* FIXME: JBP: IF1632 not allowed in libwine.a */
|
|
IF1632_Saved16_ss = pNewTask->ss;
|
|
IF1632_Saved16_sp = pNewTask->sp;
|
|
IF1632_Saved32_esp = pNewTask->esp;
|
|
IF1632_Stack32_base = WIN16_GlobalLock( pNewTask->hStack32 );
|
|
#endif
|
|
}
|
|
|
|
|
|
/***********************************************************************
|
|
* InitTask (KERNEL.91)
|
|
*/
|
|
void InitTask( struct sigcontext_struct context )
|
|
{
|
|
static int firstTask = 1;
|
|
TDB *pTask;
|
|
NE_MODULE *pModule;
|
|
SEGTABLEENTRY *pSegTable;
|
|
INSTANCEDATA *pinstance;
|
|
LONG stacklow, stackhi;
|
|
|
|
context.sc_eax = 0;
|
|
if (!(pTask = (TDB *)GlobalLock( hCurrentTask ))) return;
|
|
if (!(pModule = (NE_MODULE *)GlobalLock( pTask->hModule ))) return;
|
|
|
|
if (firstTask)
|
|
{
|
|
extern BOOL WIDGETS_Init(void);
|
|
extern BOOL WIN_CreateDesktopWindow(void);
|
|
|
|
/* Perform global initialisations that need a task context */
|
|
|
|
/* Initialize built-in window classes */
|
|
if (!WIDGETS_Init()) return;
|
|
|
|
/* Create desktop window */
|
|
if (!WIN_CreateDesktopWindow()) return;
|
|
|
|
firstTask = 0;
|
|
}
|
|
|
|
NE_InitializeDLLs( pTask->hModule );
|
|
|
|
/* Registers on return are:
|
|
* ax 1 if OK, 0 on error
|
|
* cx stack limit in bytes
|
|
* dx cmdShow parameter
|
|
* si instance handle of the previous instance
|
|
* di instance handle of the new task
|
|
* es:bx pointer to command-line inside PSP
|
|
*/
|
|
context.sc_eax = 1;
|
|
context.sc_ebx = 0x81;
|
|
context.sc_ecx = pModule->stack_size;
|
|
context.sc_edx = pTask->nCmdShow;
|
|
context.sc_esi = (DWORD)pTask->hPrevInstance;
|
|
context.sc_edi = (DWORD)pTask->hInstance;
|
|
context.sc_es = (WORD)pTask->hPDB;
|
|
|
|
/* Initialize the local heap */
|
|
if ( pModule->heap_size )
|
|
{
|
|
LocalInit( pTask->hInstance, 0, pModule->heap_size );
|
|
}
|
|
|
|
|
|
/* Initialize the INSTANCEDATA structure */
|
|
pSegTable = NE_SEG_TABLE( pModule );
|
|
stacklow = pSegTable[pModule->ss - 1].minsize;
|
|
stackhi = stacklow + pModule->stack_size;
|
|
if (stackhi > 0xffff) stackhi = 0xffff;
|
|
pinstance = (INSTANCEDATA *)PTR_SEG_OFF_TO_LIN(CURRENT_DS, 0);
|
|
pinstance->stackbottom = stackhi; /* yup, that's right. Confused me too. */
|
|
pinstance->stacktop = stacklow;
|
|
#ifndef WINELIB /* FIXME: JBP: IF1632 not allowed in libwine.a */
|
|
pinstance->stackmin = IF1632_Saved16_sp;
|
|
#endif
|
|
}
|
|
|
|
|
|
/***********************************************************************
|
|
* WaitEvent (KERNEL.30)
|
|
*/
|
|
BOOL WaitEvent( HTASK hTask )
|
|
{
|
|
TDB *pTask;
|
|
|
|
if (!hTask) hTask = hCurrentTask;
|
|
pTask = (TDB *)GlobalLock( hTask );
|
|
if (pTask->nEvents > 0)
|
|
{
|
|
pTask->nEvents--;
|
|
return FALSE;
|
|
}
|
|
TASK_SCHEDULE();
|
|
/* When we get back here, we have an event (or the task is the only one) */
|
|
if (pTask->nEvents > 0) pTask->nEvents--;
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
/***********************************************************************
|
|
* PostEvent (KERNEL.31)
|
|
*/
|
|
void PostEvent( HTASK hTask )
|
|
{
|
|
TDB *pTask;
|
|
|
|
if (!hTask) hTask = hCurrentTask;
|
|
if (!(pTask = (TDB *)GlobalLock( hTask ))) return;
|
|
pTask->nEvents++;
|
|
}
|
|
|
|
|
|
/***********************************************************************
|
|
* SetPriority (KERNEL.32)
|
|
*/
|
|
void SetPriority( HTASK hTask, int delta )
|
|
{
|
|
TDB *pTask;
|
|
int newpriority;
|
|
|
|
if (!hTask) hTask = hCurrentTask;
|
|
if (!(pTask = (TDB *)GlobalLock( 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 );
|
|
pTask->priority--;
|
|
}
|
|
|
|
|
|
/***********************************************************************
|
|
* LockCurrentTask (KERNEL.33)
|
|
*/
|
|
HTASK LockCurrentTask( BOOL bLock )
|
|
{
|
|
if (bLock) hLockedTask = hCurrentTask;
|
|
else hLockedTask = 0;
|
|
return hLockedTask;
|
|
}
|
|
|
|
|
|
/***********************************************************************
|
|
* IsTaskLocked (KERNEL.122)
|
|
*/
|
|
WORD IsTaskLocked(void)
|
|
{
|
|
return hLockedTask;
|
|
}
|
|
|
|
|
|
/***********************************************************************
|
|
* OldYield (KERNEL.117)
|
|
*/
|
|
void OldYield(void)
|
|
{
|
|
TDB *pCurTask;
|
|
|
|
pCurTask = (TDB *)GlobalLock( hCurrentTask );
|
|
if (pCurTask) pCurTask->nEvents++; /* Make sure we get back here */
|
|
TASK_SCHEDULE();
|
|
if (pCurTask) pCurTask->nEvents--;
|
|
}
|
|
|
|
|
|
/***********************************************************************
|
|
* DirectedYield (KERNEL.150)
|
|
*/
|
|
void DirectedYield( HTASK hTask )
|
|
{
|
|
TDB *pCurTask;
|
|
|
|
if ((pCurTask = (TDB *)GlobalLock( hCurrentTask )) != NULL)
|
|
pCurTask->hYieldTo = hTask;
|
|
|
|
OldYield();
|
|
}
|
|
|
|
|
|
/***********************************************************************
|
|
* Yield (KERNEL.29)
|
|
*/
|
|
void Yield(void)
|
|
{
|
|
DirectedYield( 0 );
|
|
}
|
|
|
|
|
|
/***********************************************************************
|
|
* MakeProcInstance (KERNEL.51)
|
|
*/
|
|
FARPROC MakeProcInstance( FARPROC func, HANDLE hInstance )
|
|
{
|
|
BYTE *thunk;
|
|
SEGPTR thunkaddr;
|
|
|
|
thunkaddr = TASK_AllocThunk( hCurrentTask );
|
|
if (!thunkaddr) return (FARPROC)0;
|
|
thunk = PTR_SEG_TO_LIN( thunkaddr );
|
|
|
|
dprintf_task( stddeb, "MakeProcInstance(%08lx,"NPFMT"): got thunk %08lx\n",
|
|
(SEGPTR)func, hInstance, (SEGPTR)thunkaddr );
|
|
|
|
*thunk++ = 0xb8; /* movw instance, %ax */
|
|
#ifndef WINELIB
|
|
*thunk++ = (BYTE)(hInstance & 0xff);
|
|
*thunk++ = (BYTE)(hInstance >> 8);
|
|
#endif
|
|
*thunk++ = 0xea; /* ljmp func */
|
|
*(DWORD *)thunk = (DWORD)func;
|
|
return (FARPROC)thunkaddr;
|
|
}
|
|
|
|
|
|
/***********************************************************************
|
|
* FreeProcInstance (KERNEL.52)
|
|
*/
|
|
void FreeProcInstance( FARPROC func )
|
|
{
|
|
dprintf_task( stddeb, "FreeProcInstance(%08lx)\n", (SEGPTR)func );
|
|
TASK_FreeThunk( hCurrentTask, (SEGPTR)func );
|
|
}
|
|
|
|
|
|
/**********************************************************************
|
|
* GetCodeHandle (KERNEL.93)
|
|
*/
|
|
HANDLE GetCodeHandle( FARPROC proc )
|
|
{
|
|
HANDLE handle;
|
|
BYTE *thunk = (BYTE *)PTR_SEG_TO_LIN( proc );
|
|
|
|
/* Return the code segment containing 'proc'. */
|
|
/* Not sure if this is really correct (shouldn't matter that much). */
|
|
|
|
/* Check if it is really a thunk */
|
|
if ((thunk[0] == 0xb8) && (thunk[3] == 0xea))
|
|
handle = GlobalHandle( thunk[6] + (thunk[7] << 8) );
|
|
else
|
|
handle = GlobalHandle( HIWORD(proc) );
|
|
|
|
printf( "STUB: GetCodeHandle(%08lx) returning "NPFMT"\n",
|
|
(DWORD)proc, handle );
|
|
return handle;
|
|
}
|
|
|
|
|
|
/***********************************************************************
|
|
* SetTaskQueue (KERNEL.34)
|
|
*/
|
|
HGLOBAL SetTaskQueue( HANDLE hTask, HGLOBAL hQueue )
|
|
{
|
|
HGLOBAL hPrev;
|
|
TDB *pTask;
|
|
|
|
if (!hTask) hTask = hCurrentTask;
|
|
if (!(pTask = (TDB *)GlobalLock( hTask ))) return 0;
|
|
hPrev = pTask->hQueue;
|
|
pTask->hQueue = hQueue;
|
|
return hPrev;
|
|
}
|
|
|
|
|
|
/***********************************************************************
|
|
* GetTaskQueue (KERNEL.35)
|
|
*/
|
|
HGLOBAL GetTaskQueue( HANDLE hTask )
|
|
{
|
|
TDB *pTask;
|
|
|
|
if (!hTask) hTask = hCurrentTask;
|
|
if (!(pTask = (TDB *)GlobalLock( hTask ))) return 0;
|
|
return pTask->hQueue;
|
|
}
|
|
|
|
|
|
/***********************************************************************
|
|
* GetCurrentTask (KERNEL.36)
|
|
*/
|
|
HTASK GetCurrentTask(void)
|
|
{
|
|
/* Undocumented: first task is returned in high word */
|
|
#ifdef WINELIB32
|
|
return hCurrentTask;
|
|
#else
|
|
return MAKELONG( hCurrentTask, hFirstTask );
|
|
#endif
|
|
}
|
|
|
|
|
|
/***********************************************************************
|
|
* GetCurrentPDB (KERNEL.37)
|
|
*/
|
|
HANDLE GetCurrentPDB(void)
|
|
{
|
|
TDB *pTask;
|
|
|
|
if (!(pTask = (TDB *)GlobalLock( hCurrentTask ))) return 0;
|
|
return pTask->hPDB;
|
|
}
|
|
|
|
|
|
/***********************************************************************
|
|
* GetInstanceData (KERNEL.54)
|
|
*/
|
|
int GetInstanceData( HANDLE instance, WORD buffer, int len )
|
|
{
|
|
char *ptr = (char *)GlobalLock( instance );
|
|
if (!ptr || !len) return 0;
|
|
if ((int)buffer + len >= 0x10000) len = 0x10000 - buffer;
|
|
memcpy( ptr + buffer, (char *)GlobalLock( CURRENT_DS ) + buffer, len );
|
|
return len;
|
|
}
|
|
|
|
|
|
/***********************************************************************
|
|
* GetDOSEnvironment (KERNEL.131)
|
|
*/
|
|
SEGPTR GetDOSEnvironment(void)
|
|
{
|
|
TDB *pTask;
|
|
|
|
if (!(pTask = (TDB *)GlobalLock( hCurrentTask ))) return 0;
|
|
return (SEGPTR)WIN16_GlobalLock( pTask->pdb.environment );
|
|
}
|
|
|
|
|
|
/***********************************************************************
|
|
* GetNumTasks (KERNEL.152)
|
|
*/
|
|
WORD GetNumTasks(void)
|
|
{
|
|
return nTaskCount;
|
|
}
|
|
|
|
|
|
/***********************************************************************
|
|
* GetTaskDS (KERNEL.155)
|
|
*/
|
|
HINSTANCE GetTaskDS(void)
|
|
{
|
|
TDB *pTask;
|
|
|
|
if (!(pTask = (TDB *)GlobalLock( hCurrentTask ))) return 0;
|
|
return pTask->hInstance;
|
|
}
|
|
|
|
|
|
/***********************************************************************
|
|
* IsTask (KERNEL.320)
|
|
*/
|
|
BOOL IsTask( HTASK hTask )
|
|
{
|
|
TDB *pTask;
|
|
|
|
if (!(pTask = (TDB *)GlobalLock( hTask ))) return FALSE;
|
|
if (GlobalSize( hTask ) < sizeof(TDB)) return FALSE;
|
|
return (pTask->magic == TDB_MAGIC);
|
|
}
|
|
|
|
|
|
/***********************************************************************
|
|
* GetExePtr (KERNEL.133)
|
|
*/
|
|
HMODULE GetExePtr( HANDLE handle )
|
|
{
|
|
char *ptr;
|
|
HTASK hTask;
|
|
HANDLE owner;
|
|
|
|
/* Check for module handle */
|
|
|
|
if (!(ptr = GlobalLock( handle ))) return 0;
|
|
if (((NE_MODULE *)ptr)->magic == NE_SIGNATURE) return handle;
|
|
|
|
/* Check the owner for module handle */
|
|
|
|
#ifndef WINELIB
|
|
owner = FarGetOwner( handle );
|
|
#else
|
|
owner = NULL;
|
|
fprintf(stderr,"JBP: FarGetOwner() ignored.\n");
|
|
#endif
|
|
if (!(ptr = GlobalLock( owner ))) return 0;
|
|
if (((NE_MODULE *)ptr)->magic == NE_SIGNATURE) return owner;
|
|
|
|
/* Search for this handle and its owner inside all tasks */
|
|
|
|
hTask = hFirstTask;
|
|
while (hTask)
|
|
{
|
|
TDB *pTask = (TDB *)GlobalLock( hTask );
|
|
if ((hTask == handle) ||
|
|
(pTask->hInstance == handle) ||
|
|
(pTask->hQueue == handle) ||
|
|
(pTask->hPDB == handle)) return pTask->hModule;
|
|
if ((hTask == owner) ||
|
|
(pTask->hInstance == owner) ||
|
|
(pTask->hQueue == owner) ||
|
|
(pTask->hPDB == owner)) return pTask->hModule;
|
|
hTask = pTask->hNext;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
|
|
/***********************************************************************
|
|
* TaskFirst (TOOLHELP.63)
|
|
*/
|
|
BOOL TaskFirst( TASKENTRY *lpte )
|
|
{
|
|
lpte->hNext = hFirstTask;
|
|
return TaskNext( lpte );
|
|
}
|
|
|
|
|
|
/***********************************************************************
|
|
* TaskNext (TOOLHELP.64)
|
|
*/
|
|
BOOL TaskNext( TASKENTRY *lpte )
|
|
{
|
|
TDB *pTask;
|
|
INSTANCEDATA *pInstData;
|
|
|
|
dprintf_toolhelp( stddeb, "TaskNext(%p): task="NPFMT"\n", lpte, lpte->hNext );
|
|
if (!lpte->hNext) return FALSE;
|
|
pTask = (TDB *)GlobalLock( lpte->hNext );
|
|
if (!pTask || pTask->magic != TDB_MAGIC) return FALSE;
|
|
pInstData = (INSTANCEDATA *)PTR_SEG_OFF_TO_LIN( pTask->hInstance, 0 );
|
|
lpte->hTask = lpte->hNext;
|
|
lpte->hTaskParent = pTask->hParent;
|
|
lpte->hInst = pTask->hInstance;
|
|
lpte->hModule = pTask->hModule;
|
|
lpte->wSS = pTask->ss;
|
|
lpte->wSP = pTask->sp;
|
|
lpte->wStackTop = pInstData->stacktop;
|
|
lpte->wStackMinimum = pInstData->stackmin;
|
|
lpte->wStackBottom = pInstData->stackbottom;
|
|
lpte->wcEvents = pTask->nEvents;
|
|
lpte->hQueue = pTask->hQueue;
|
|
strncpy( lpte->szModule, pTask->module_name, 8 );
|
|
lpte->szModule[8] = '\0';
|
|
lpte->wPSPOffset = 0x100; /*??*/
|
|
lpte->hNext = pTask->hNext;
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
/***********************************************************************
|
|
* TaskFindHandle (TOOLHELP.65)
|
|
*/
|
|
BOOL TaskFindHandle( TASKENTRY *lpte, HTASK hTask )
|
|
{
|
|
lpte->hNext = hTask;
|
|
return TaskNext( lpte );
|
|
}
|