Release 980104
[wine/multimedia.git] / loader / task.c
blob110a79958693bba741161fac1800c1b39fcf955d
1 /*
2 * Task functions
4 * Copyright 1995 Alexandre Julliard
5 */
7 #include <stdio.h>
8 #include <stdlib.h>
9 #include <string.h>
11 #include "windows.h"
12 #include "user.h"
13 #include "callback.h"
14 #include "drive.h"
15 #include "file.h"
16 #include "global.h"
17 #include "instance.h"
18 #include "message.h"
19 #include "miscemu.h"
20 #include "module.h"
21 #include "neexe.h"
22 #include "peexe.h"
23 #include "pe_image.h"
24 #include "process.h"
25 #include "queue.h"
26 #include "selectors.h"
27 #include "stackframe.h"
28 #include "thread.h"
29 #include "toolhelp.h"
30 #include "winnt.h"
31 #include "thread.h"
32 #include "stddebug.h"
33 #include "debug.h"
34 #include "dde_proc.h"
36 /* Min. number of thunks allocated when creating a new segment */
37 #define MIN_THUNKS 32
39 extern INT32 WINSOCK_DeleteTaskWSI( TDB* pTask, struct _WSINFO* );
40 extern BOOL32 MODULE_FreeModule( HMODULE16 hModule, TDB* ptaskContext );
41 extern void PE_InitTls( PDB32 *pdb32 );
43 /* Saved 16-bit stack for current process (Win16 only) */
44 DWORD IF1632_Saved16_ss_sp = 0;
46 /* Pointer to function to switch to a larger stack */
47 int (*IF1632_CallLargeStack)( int (*func)(), void *arg ) = NULL;
49 static HTASK16 hFirstTask = 0;
50 static HTASK16 hCurrentTask = 0;
51 static HTASK16 hTaskToKill = 0;
52 static HTASK16 hLockedTask = 0;
53 static UINT16 nTaskCount = 0;
54 static HGLOBAL16 hDOSEnvironment = 0;
56 static HGLOBAL16 TASK_CreateDOSEnvironment(void);
57 static void TASK_YieldToSystem(TDB*);
59 static THDB TASK_SystemTHDB;
60 /***********************************************************************
61 * TASK_Init
63 BOOL32 TASK_Init(void)
65 if (!(hDOSEnvironment = TASK_CreateDOSEnvironment()))
66 fprintf( stderr, "Not enough memory for DOS Environment\n" );
67 TASK_SystemTHDB.teb_sel = SELECTOR_AllocBlock( &TASK_SystemTHDB, 0x1000, SEGMENT_DATA, TRUE, FALSE );
68 SET_FS( TASK_SystemTHDB.teb_sel );
69 return (hDOSEnvironment != 0);
73 /***********************************************************************
74 * TASK_GetNextTask
76 HTASK16 TASK_GetNextTask( HTASK16 hTask )
78 TDB* pTask = (TDB*)GlobalLock16(hTask);
80 if (pTask->hNext) return pTask->hNext;
81 return (hFirstTask != hTask) ? hFirstTask : 0;
85 /***********************************************************************
86 * TASK_CreateDOSEnvironment
88 * Create the original DOS environment.
90 static HGLOBAL16 TASK_CreateDOSEnvironment(void)
92 static const char program_name[] = "KRNL386.EXE";
93 char **e, *p;
94 int initial_size, size, i, winpathlen, sysdirlen;
95 HGLOBAL16 handle;
97 extern char **environ;
99 /* DOS environment format:
100 * ASCIIZ string 1
101 * ASCIIZ string 2
102 * ...
103 * ASCIIZ string n
104 * ASCIIZ PATH=xxx
105 * BYTE 0
106 * WORD 1
107 * ASCIIZ program name (e.g. C:\WINDOWS\SYSTEM\KRNL386.EXE)
110 /* First compute the size of the fixed part of the environment */
112 for (i = winpathlen = 0; ; i++)
114 int len = DIR_GetDosPath( i, NULL, 0 );
115 if (!len) break;
116 winpathlen += len + 1;
118 if (!winpathlen) winpathlen = 1;
119 sysdirlen = GetSystemDirectory32A( NULL, 0 ) + 1;
120 initial_size = 5 + winpathlen + /* PATH=xxxx */
121 1 + /* BYTE 0 at end */
122 sizeof(WORD) + /* WORD 1 */
123 sysdirlen + /* program directory */
124 strlen(program_name) + 1; /* program name */
126 /* Compute the total size of the Unix environment (except path) */
128 for (e = environ, size = initial_size; *e; e++)
130 if (lstrncmpi32A(*e, "path=", 5))
132 int len = strlen(*e) + 1;
133 if (size + len >= 32767)
135 fprintf( stderr, "Warning: environment larger than 32k.\n" );
136 break;
138 size += len;
143 /* Now allocate the environment */
145 if (!(handle = GlobalAlloc16( GMEM_FIXED, size ))) return 0;
146 p = (char *)GlobalLock16( handle );
148 /* And fill it with the Unix environment */
150 for (e = environ, size = initial_size; *e; e++)
152 if (lstrncmpi32A(*e, "path=", 5))
154 int len = strlen(*e) + 1;
155 if (size + len >= 32767) break;
156 strcpy( p, *e );
157 size += len;
158 p += len;
162 /* Now add the path */
164 strcpy( p, "PATH=" );
165 for (i = 0, p += 5; ; i++)
167 if (!DIR_GetDosPath( i, p, winpathlen )) break;
168 p += strlen(p);
169 *p++ = ';';
171 if (p[-1] == ';') p[-1] = '\0';
172 else p++;
174 /* Now add the program name */
176 *p++ = '\0';
177 PUT_WORD( p, 1 );
178 p += sizeof(WORD);
179 GetSystemDirectory32A( p, sysdirlen );
180 strcat( p, "\\" );
181 strcat( p, program_name );
183 /* Display it */
185 p = (char *) GlobalLock16( handle );
186 dprintf_task(stddeb, "Master DOS environment at %p\n", p);
187 for (; *p; p += strlen(p) + 1) dprintf_task(stddeb, " %s\n", p);
188 dprintf_task( stddeb, "Progname: %s\n", p+3 );
190 return handle;
194 /***********************************************************************
195 * TASK_LinkTask
197 static void TASK_LinkTask( HTASK16 hTask )
199 HTASK16 *prevTask;
200 TDB *pTask;
202 if (!(pTask = (TDB *)GlobalLock16( hTask ))) return;
203 prevTask = &hFirstTask;
204 while (*prevTask)
206 TDB *prevTaskPtr = (TDB *)GlobalLock16( *prevTask );
207 if (prevTaskPtr->priority >= pTask->priority) break;
208 prevTask = &prevTaskPtr->hNext;
210 pTask->hNext = *prevTask;
211 *prevTask = hTask;
212 nTaskCount++;
216 /***********************************************************************
217 * TASK_UnlinkTask
219 static void TASK_UnlinkTask( HTASK16 hTask )
221 HTASK16 *prevTask;
222 TDB *pTask;
224 prevTask = &hFirstTask;
225 while (*prevTask && (*prevTask != hTask))
227 pTask = (TDB *)GlobalLock16( *prevTask );
228 prevTask = &pTask->hNext;
230 if (*prevTask)
232 pTask = (TDB *)GlobalLock16( *prevTask );
233 *prevTask = pTask->hNext;
234 pTask->hNext = 0;
235 nTaskCount--;
240 /***********************************************************************
241 * TASK_CreateThunks
243 * Create a thunk free-list in segment 'handle', starting from offset 'offset'
244 * and containing 'count' entries.
246 static void TASK_CreateThunks( HGLOBAL16 handle, WORD offset, WORD count )
248 int i;
249 WORD free;
250 THUNKS *pThunk;
252 pThunk = (THUNKS *)((BYTE *)GlobalLock16( handle ) + offset);
253 pThunk->next = 0;
254 pThunk->magic = THUNK_MAGIC;
255 pThunk->free = (int)&pThunk->thunks - (int)pThunk;
256 free = pThunk->free;
257 for (i = 0; i < count-1; i++)
259 free += 8; /* Offset of next thunk */
260 pThunk->thunks[4*i] = free;
262 pThunk->thunks[4*i] = 0; /* Last thunk */
266 /***********************************************************************
267 * TASK_AllocThunk
269 * Allocate a thunk for MakeProcInstance().
271 static SEGPTR TASK_AllocThunk( HTASK16 hTask )
273 TDB *pTask;
274 THUNKS *pThunk;
275 WORD sel, base;
277 if (!(pTask = (TDB *)GlobalLock16( hTask ))) return 0;
278 sel = pTask->hCSAlias;
279 pThunk = &pTask->thunks;
280 base = (int)pThunk - (int)pTask;
281 while (!pThunk->free)
283 sel = pThunk->next;
284 if (!sel) /* Allocate a new segment */
286 sel = GLOBAL_Alloc( GMEM_FIXED, sizeof(THUNKS) + (MIN_THUNKS-1)*8,
287 pTask->hPDB, TRUE, FALSE, FALSE );
288 if (!sel) return (SEGPTR)0;
289 TASK_CreateThunks( sel, 0, MIN_THUNKS );
290 pThunk->next = sel;
292 pThunk = (THUNKS *)GlobalLock16( sel );
293 base = 0;
295 base += pThunk->free;
296 pThunk->free = *(WORD *)((BYTE *)pThunk + pThunk->free);
297 return PTR_SEG_OFF_TO_SEGPTR( sel, base );
301 /***********************************************************************
302 * TASK_FreeThunk
304 * Free a MakeProcInstance() thunk.
306 static BOOL32 TASK_FreeThunk( HTASK16 hTask, SEGPTR thunk )
308 TDB *pTask;
309 THUNKS *pThunk;
310 WORD sel, base;
312 if (!(pTask = (TDB *)GlobalLock16( hTask ))) return 0;
313 sel = pTask->hCSAlias;
314 pThunk = &pTask->thunks;
315 base = (int)pThunk - (int)pTask;
316 while (sel && (sel != HIWORD(thunk)))
318 sel = pThunk->next;
319 pThunk = (THUNKS *)GlobalLock16( sel );
320 base = 0;
322 if (!sel) return FALSE;
323 *(WORD *)((BYTE *)pThunk + LOWORD(thunk) - base) = pThunk->free;
324 pThunk->free = LOWORD(thunk) - base;
325 return TRUE;
329 /***********************************************************************
330 * TASK_CallToStart
332 * 32-bit entry point for a new task. This function is responsible for
333 * setting up the registers and jumping to the 16-bit entry point.
335 static void TASK_CallToStart(void)
337 int exit_code = 1;
338 TDB *pTask = (TDB *)GlobalLock16( hCurrentTask );
339 NE_MODULE *pModule = MODULE_GetPtr( pTask->hModule );
340 SEGTABLEENTRY *pSegTable = NE_SEG_TABLE( pModule );
342 IF1632_Saved16_ss_sp = pTask->ss_sp;
343 SET_CUR_THREAD( pTask->thdb );
344 if (pModule->flags & NE_FFLAGS_WIN32)
346 /* FIXME: all this is an ugly hack */
348 extern void InitTask( CONTEXT *context );
350 FARPROC32 entry = (FARPROC32)RVA_PTR( pCurrentProcess->exe_modref->module, OptionalHeader.AddressOfEntryPoint );
352 InitTask( NULL );
353 InitApp( pTask->hModule );
354 PE_InitializeDLLs( pCurrentProcess, DLL_PROCESS_ATTACH, (LPVOID)-1 );
355 dprintf_relay( stddeb, "CallTo32(entryproc=%p)\n", entry );
356 exit_code = entry();
357 TASK_KillCurrentTask( exit_code );
359 else
361 /* Registers at initialization must be:
362 * ax zero
363 * bx stack size in bytes
364 * cx heap size in bytes
365 * si previous app instance
366 * di current app instance
367 * bp zero
368 * es selector to the PSP
369 * ds dgroup of the application
370 * ss stack selector
371 * sp top of the stack
373 CONTEXT context;
375 memset( &context, 0, sizeof(context) );
376 CS_reg(&context) = pSegTable[pModule->cs - 1].selector;
377 DS_reg(&context) = pSegTable[pModule->dgroup - 1].selector;
378 ES_reg(&context) = pTask->hPDB;
379 EIP_reg(&context) = pModule->ip;
380 EBX_reg(&context) = pModule->stack_size;
381 ECX_reg(&context) = pModule->heap_size;
382 EDI_reg(&context) = context.SegDs;
384 dprintf_task( stddeb, "Starting main program: cs:ip=%04lx:%04x ds=%04lx ss:sp=%04x:%04x\n",
385 CS_reg(&context), IP_reg(&context), DS_reg(&context),
386 SELECTOROF(IF1632_Saved16_ss_sp),
387 OFFSETOF(IF1632_Saved16_ss_sp) );
389 Callbacks->CallRegisterShortProc( &context, 0 );
390 /* This should never return */
391 fprintf( stderr, "TASK_CallToStart: Main program returned!\n" );
392 TASK_KillCurrentTask( 1 );
397 /***********************************************************************
398 * TASK_CreateTask
400 HTASK16 TASK_CreateTask( HMODULE16 hModule, HINSTANCE16 hInstance,
401 HINSTANCE16 hPrevInstance, HANDLE16 hEnvironment,
402 LPCSTR cmdLine, UINT16 cmdShow )
404 HTASK16 hTask;
405 TDB *pTask;
406 PDB32 *pdb32;
407 HGLOBAL16 hParentEnv;
408 NE_MODULE *pModule;
409 SEGTABLEENTRY *pSegTable;
410 LPSTR name;
411 WORD sp;
412 char *stack32Top;
413 STACK16FRAME *frame16;
414 STACK32FRAME *frame32;
416 if (!(pModule = MODULE_GetPtr( hModule ))) return 0;
417 pSegTable = NE_SEG_TABLE( pModule );
419 /* Allocate the task structure */
421 hTask = GLOBAL_Alloc( GMEM_FIXED | GMEM_ZEROINIT, sizeof(TDB),
422 hModule, FALSE, FALSE, FALSE );
423 if (!hTask) return 0;
424 pTask = (TDB *)GlobalLock16( hTask );
426 /* Allocate the new environment block */
428 if (!(hParentEnv = hEnvironment))
430 TDB *pParent = (TDB *)GlobalLock16( hCurrentTask );
431 hParentEnv = pParent ? pParent->pdb.environment : hDOSEnvironment;
433 /* FIXME: do we really need to make a copy also when */
434 /* we don't use the parent environment? */
435 if (!(hEnvironment = GlobalAlloc16( GMEM_FIXED, GlobalSize16(hParentEnv))))
437 GlobalFree16( hTask );
438 return 0;
440 memcpy( GlobalLock16( hEnvironment ), GlobalLock16( hParentEnv ),
441 GlobalSize16( hParentEnv ) );
443 /* Fill the task structure */
445 pTask->nEvents = 1; /* So the task can be started */
446 pTask->hSelf = hTask;
447 pTask->flags = 0;
449 if (pModule->flags & NE_FFLAGS_WIN32)
450 pTask->flags |= TDBF_WIN32;
452 pTask->version = pModule->expected_version;
453 pTask->hInstance = hInstance;
454 pTask->hPrevInstance = hPrevInstance;
455 pTask->hModule = hModule;
456 pTask->hParent = hCurrentTask;
457 pTask->magic = TDB_MAGIC;
458 pTask->nCmdShow = cmdShow;
459 pTask->curdrive = DRIVE_GetCurrentDrive() | 0x80;
460 strcpy( pTask->curdir, "\\" );
461 lstrcpyn32A( pTask->curdir + 1, DRIVE_GetDosCwd( DRIVE_GetCurrentDrive() ),
462 sizeof(pTask->curdir) - 1 );
464 /* Create the thunks block */
466 TASK_CreateThunks( hTask, (int)&pTask->thunks - (int)pTask, 7 );
468 /* Copy the module name */
470 name = MODULE_GetModuleName( hModule );
471 strncpy( pTask->module_name, name, sizeof(pTask->module_name) );
473 /* Allocate a selector for the PDB */
475 pTask->hPDB = GLOBAL_CreateBlock( GMEM_FIXED, &pTask->pdb, sizeof(PDB),
476 hModule, FALSE, FALSE, FALSE, NULL );
478 /* Fill the PDB */
480 pTask->pdb.int20 = 0x20cd;
481 pTask->pdb.dispatcher[0] = 0x9a; /* ljmp */
482 PUT_DWORD(&pTask->pdb.dispatcher[1], (DWORD)MODULE_GetEntryPoint(
483 GetModuleHandle16("KERNEL"), 102 )); /* KERNEL.102 is DOS3Call() */
484 pTask->pdb.savedint22 = INT_GetHandler( 0x22 );
485 pTask->pdb.savedint23 = INT_GetHandler( 0x23 );
486 pTask->pdb.savedint24 = INT_GetHandler( 0x24 );
487 pTask->pdb.fileHandlesPtr =
488 PTR_SEG_OFF_TO_SEGPTR( GlobalHandleToSel(pTask->hPDB),
489 (int)&((PDB *)0)->fileHandles );
490 pTask->pdb.hFileHandles = 0;
491 memset( pTask->pdb.fileHandles, 0xff, sizeof(pTask->pdb.fileHandles) );
492 pTask->pdb.environment = hEnvironment;
493 pTask->pdb.nbFiles = 20;
494 lstrcpyn32A( pTask->pdb.cmdLine, cmdLine, 127 );
496 /* Get the compatibility flags */
498 pTask->compat_flags = GetProfileInt32A( "Compatibility", name, 0 );
500 /* Allocate a code segment alias for the TDB */
502 pTask->hCSAlias = GLOBAL_CreateBlock( GMEM_FIXED, (void *)pTask,
503 sizeof(TDB), pTask->hPDB, TRUE,
504 FALSE, FALSE, NULL );
506 /* Set the owner of the environment block */
508 FarSetOwner( pTask->pdb.environment, pTask->hPDB );
510 /* Default DTA overwrites command-line */
512 pTask->dta = PTR_SEG_OFF_TO_SEGPTR( pTask->hPDB,
513 (int)&pTask->pdb.cmdLine - (int)&pTask->pdb );
515 /* Create the Win32 part of the task */
517 pCurrentProcess = pdb32 = PROCESS_Create( pTask, cmdLine );
518 /* FIXME: check for pdb32 == NULL. */
519 pdb32->task = hTask;
520 if (pModule->flags & NE_FFLAGS_WIN32)
523 LPTHREAD_START_ROUTINE start =
524 (LPTHREAD_START_ROUTINE)(
525 pCurrentProcess->exe_modref->load_addr +
526 pCurrentProcess->exe_modref->pe_module->pe_header->OptionalHeader.AddressOfEntryPoint);
528 pTask->thdb = THREAD_Create( pdb32,
529 PE_HEADER(pModule->module32)->OptionalHeader.SizeOfStackReserve,
530 NULL, NULL );
531 /* FIXME: should not be done here */
532 PE_InitTls( pdb32 );
534 else
535 pTask->thdb = THREAD_Create( pdb32, 0, NULL, NULL );
537 /* FIXME: check for pTask->thdb == NULL. */
538 SET_CUR_THREAD( pTask->thdb );
540 /* Create the 32-bit stack frame */
542 stack32Top = (char*)pTask->thdb->teb.stack_top;
543 frame32 = (STACK32FRAME *)stack32Top - 1;
544 frame32->edi = 0;
545 frame32->esi = 0;
546 frame32->edx = 0;
547 frame32->ecx = 0;
548 frame32->ebx = 0;
549 frame32->retaddr = (DWORD)TASK_CallToStart;
550 /* The remaining fields will be initialized in TASK_Reschedule */
552 /* Create the 16-bit stack frame */
554 if (!(sp = pModule->sp))
555 sp = pSegTable[pModule->ss-1].minsize + pModule->stack_size;
556 sp &= ~1;
557 pTask->ss_sp = PTR_SEG_OFF_TO_SEGPTR( hInstance, sp );
558 pTask->ss_sp -= sizeof(STACK16FRAME) + sizeof(DWORD) /* for saved %esp */;
559 frame16 = (STACK16FRAME *)PTR_SEG_TO_LIN( pTask->ss_sp );
560 frame16->saved_ss_sp = 0;
561 frame16->ebp = sp + (int)&((STACK16FRAME *)0)->bp;
562 frame16->bp = LOWORD(frame16->ebp);
563 frame16->ds = frame16->es = pTask->hInstance;
564 frame16->entry_point = 0;
565 frame16->entry_cs = 0;
566 /* The remaining fields will be initialized in TASK_Reschedule */
568 *(STACK32FRAME **)(frame16 + 1) = frame32; /* Store the 32-bit %esp */
570 /* If there's no 16-bit stack yet, use a part of the new task stack */
571 /* This is only needed to have a stack to switch from on the first */
572 /* call to DirectedYield(). */
574 if (!IF1632_Saved16_ss_sp) IF1632_Saved16_ss_sp = pTask->ss_sp;
576 /* Add the task to the linked list */
578 TASK_LinkTask( hTask );
580 dprintf_task( stddeb, "CreateTask: module='%s' cmdline='%s' task=%04x\n",
581 name, cmdLine, hTask );
583 return hTask;
587 /***********************************************************************
588 * TASK_DeleteTask
590 static void TASK_DeleteTask( HTASK16 hTask )
592 TDB *pTask;
593 HGLOBAL16 hPDB;
595 if (!(pTask = (TDB *)GlobalLock16( hTask ))) return;
596 hPDB = pTask->hPDB;
598 /* Delete the Win32 part of the task */
600 K32OBJ_DecCount( &pTask->thdb->process->header );
601 K32OBJ_DecCount( &pTask->thdb->header );
603 /* Free the task module */
605 MODULE_FreeModule( pTask->hModule, pTask );
607 /* Free the selector aliases */
609 GLOBAL_FreeBlock( pTask->hCSAlias );
610 GLOBAL_FreeBlock( pTask->hPDB );
612 /* Free the task structure itself */
614 GlobalFree16( hTask );
616 /* Free all memory used by this task (including the 32-bit stack, */
617 /* the environment block and the thunk segments). */
619 GlobalFreeAll( hPDB );
623 /***********************************************************************
624 * TASK_KillCurrentTask
626 * Kill the currently running task. As it's not possible to kill the
627 * current task like this, it is simply marked for destruction, and will
628 * be killed when either TASK_Reschedule or this function is called again
629 * in the context of another task.
631 void TASK_KillCurrentTask( INT16 exitCode )
633 TDB* pTask = (TDB*) GlobalLock16( hCurrentTask );
634 if (!pTask) USER_ExitWindows(); /* No current task yet */
636 dprintf_task(stddeb, "Killing task %04x\n", hCurrentTask );
638 /* Delete active sockets */
640 if( pTask->pwsi )
641 WINSOCK_DeleteTaskWSI( pTask, pTask->pwsi );
643 /* Perform USER cleanup */
645 if (pTask->userhandler)
646 pTask->userhandler( hCurrentTask, USIG_TERMINATION, 0,
647 pTask->hInstance, pTask->hQueue );
649 if (hTaskToKill && (hTaskToKill != hCurrentTask))
651 /* If another task is already marked for destruction, */
652 /* we can kill it now, as we are in another context. */
653 TASK_DeleteTask( hTaskToKill );
656 if (nTaskCount <= 1)
658 dprintf_task( stddeb, "\nthis is the last task, exiting\n" );
659 USER_ExitWindows();
662 /* Remove the task from the list to be sure we never switch back to it */
663 TASK_UnlinkTask( hCurrentTask );
664 if( nTaskCount )
666 TDB* p = (TDB *)GlobalLock16( hFirstTask );
667 while( p )
669 if( p->hYieldTo == hCurrentTask ) p->hYieldTo = 0;
670 p = (TDB *)GlobalLock16( p->hNext );
674 hTaskToKill = hCurrentTask;
675 hLockedTask = 0;
677 pTask->nEvents = 0;
678 TASK_YieldToSystem(pTask);
680 /* We should never return from this Yield() */
682 fprintf(stderr,"Return of the living dead %04x!!!\n", hCurrentTask);
683 exit(1);
686 /***********************************************************************
687 * TASK_Reschedule
689 * This is where all the magic of task-switching happens!
691 * Note: This function should only be called via the TASK_YieldToSystem()
692 * wrapper, to make sure that all the context is saved correctly.
694 * It must not call functions that may yield control.
696 void TASK_Reschedule(void)
698 TDB *pOldTask = NULL, *pNewTask;
699 HTASK16 hTask = 0;
700 STACK16FRAME *newframe16;
702 #ifdef CONFIG_IPC
703 dde_reschedule();
704 #endif
705 /* First check if there's a task to kill */
707 if (hTaskToKill && (hTaskToKill != hCurrentTask))
709 TASK_DeleteTask( hTaskToKill );
710 hTaskToKill = 0;
713 /* Find a task to yield to */
715 pOldTask = (TDB *)GlobalLock16( hCurrentTask );
716 if (pOldTask && pOldTask->hYieldTo)
718 /* check for DirectedYield() */
720 hTask = pOldTask->hYieldTo;
721 pNewTask = (TDB *)GlobalLock16( hTask );
722 if( !pNewTask || !pNewTask->nEvents) hTask = 0;
723 pOldTask->hYieldTo = 0;
726 /* extract hardware events only! */
728 if (!hTask) EVENT_WaitNetEvent( FALSE, TRUE );
730 while (!hTask)
732 /* Find a task that has an event pending */
734 hTask = hFirstTask;
735 while (hTask)
737 pNewTask = (TDB *)GlobalLock16( hTask );
739 dprintf_task( stddeb, "\ttask = %04x, events = %i\n", hTask, pNewTask->nEvents);
741 if (pNewTask->nEvents) break;
742 hTask = pNewTask->hNext;
744 if (hLockedTask && (hTask != hLockedTask)) hTask = 0;
745 if (hTask) break;
747 /* No task found, wait for some events to come in */
749 EVENT_WaitNetEvent( TRUE, TRUE );
752 if (hTask == hCurrentTask)
754 dprintf_task( stddeb, "returning to the current task(%04x)\n", hTask );
755 return; /* Nothing to do */
757 pNewTask = (TDB *)GlobalLock16( hTask );
758 dprintf_task( stddeb, "Switching to task %04x (%.8s)\n",
759 hTask, pNewTask->module_name );
761 /* Save the stack of the previous task (if any) */
763 if (pOldTask) pOldTask->ss_sp = IF1632_Saved16_ss_sp;
765 /* Make the task the last in the linked list (round-robin scheduling) */
767 pNewTask->priority++;
768 TASK_UnlinkTask( hTask );
769 TASK_LinkTask( hTask );
770 pNewTask->priority--;
772 /* Finish initializing the new task stack if necessary */
774 newframe16 = (STACK16FRAME *)PTR_SEG_TO_LIN( pNewTask->ss_sp );
775 if (!newframe16->entry_cs)
777 STACK16FRAME *oldframe16 = CURRENT_STACK16;
778 STACK32FRAME *oldframe32 = *(STACK32FRAME **)(oldframe16 + 1);
779 STACK32FRAME *newframe32 = *(STACK32FRAME **)(newframe16 + 1);
780 newframe16->entry_ip = oldframe16->entry_ip;
781 newframe16->entry_cs = oldframe16->entry_cs;
782 newframe16->ip = oldframe16->ip;
783 newframe16->cs = oldframe16->cs;
784 newframe32->ebp = oldframe32->ebp;
785 newframe32->restore_addr = oldframe32->restore_addr;
786 newframe32->codeselector = oldframe32->codeselector;
789 /* Switch to the new stack */
791 hCurrentTask = hTask;
792 SET_CUR_THREAD( pNewTask->thdb );
793 pCurrentProcess = pNewTask->thdb->process;
794 IF1632_Saved16_ss_sp = pNewTask->ss_sp;
798 /***********************************************************************
799 * TASK_YieldToSystem
801 * Scheduler interface, this way we ensure that all "unsafe" events are
802 * processed outside the scheduler.
804 void TASK_YieldToSystem(TDB* pTask)
806 MESSAGEQUEUE* pQ;
808 Callbacks->CallTaskRescheduleProc();
810 if( pTask )
812 pQ = (MESSAGEQUEUE*)GlobalLock16(pTask->hQueue);
813 if( pQ && pQ->flags & QUEUE_FLAG_XEVENT &&
814 !(pQ->wakeBits & (QS_SENDMESSAGE | QS_SMRESULT)) )
816 pQ->flags &= ~QUEUE_FLAG_XEVENT;
817 EVENT_WaitNetEvent( FALSE, FALSE );
823 /***********************************************************************
824 * InitTask (KERNEL.91)
826 * Called by the application startup code.
828 void WINAPI InitTask( CONTEXT *context )
830 TDB *pTask;
831 NE_MODULE *pModule;
832 SEGTABLEENTRY *pSegTable;
833 INSTANCEDATA *pinstance;
834 LONG stacklow, stackhi;
836 if (context) EAX_reg(context) = 0;
837 if (!(pTask = (TDB *)GlobalLock16( hCurrentTask ))) return;
838 if (!(pModule = MODULE_GetPtr( pTask->hModule ))) return;
840 /* This is a hack to install task USER signal handler before
841 * implicitly loaded DLLs are initialized (see windows/user.c) */
843 pTask->userhandler = (USERSIGNALPROC)&USER_SignalProc;
845 /* Initialize implicitly loaded DLLs */
846 NE_InitializeDLLs( pTask->hModule );
848 if (context)
850 /* Registers on return are:
851 * ax 1 if OK, 0 on error
852 * cx stack limit in bytes
853 * dx cmdShow parameter
854 * si instance handle of the previous instance
855 * di instance handle of the new task
856 * es:bx pointer to command-line inside PSP
858 EAX_reg(context) = 1;
859 EBX_reg(context) = 0x81;
860 ECX_reg(context) = pModule->stack_size;
861 EDX_reg(context) = pTask->nCmdShow;
862 ESI_reg(context) = (DWORD)pTask->hPrevInstance;
863 EDI_reg(context) = (DWORD)pTask->hInstance;
864 ES_reg (context) = (WORD)pTask->hPDB;
867 /* Initialize the local heap */
868 if ( pModule->heap_size )
870 LocalInit( pTask->hInstance, 0, pModule->heap_size );
873 /* Initialize the INSTANCEDATA structure */
874 pSegTable = NE_SEG_TABLE( pModule );
875 stacklow = pSegTable[pModule->ss - 1].minsize;
876 stackhi = stacklow + pModule->stack_size;
877 if (stackhi > 0xffff) stackhi = 0xffff;
878 pinstance = (INSTANCEDATA *)PTR_SEG_OFF_TO_LIN(CURRENT_DS, 0);
879 pinstance->stackbottom = stackhi; /* yup, that's right. Confused me too. */
880 pinstance->stacktop = stacklow;
881 pinstance->stackmin = OFFSETOF(IF1632_Saved16_ss_sp);
885 /***********************************************************************
886 * WaitEvent (KERNEL.30)
888 BOOL16 WINAPI WaitEvent( HTASK16 hTask )
890 TDB *pTask;
892 if (!hTask) hTask = hCurrentTask;
893 pTask = (TDB *)GlobalLock16( hTask );
894 if (pTask->nEvents > 0)
896 pTask->nEvents--;
897 return FALSE;
899 TASK_YieldToSystem(pTask);
901 /* When we get back here, we have an event */
903 if (pTask->nEvents > 0) pTask->nEvents--;
904 return TRUE;
908 /***********************************************************************
909 * PostEvent (KERNEL.31)
911 void WINAPI PostEvent( HTASK16 hTask )
913 TDB *pTask;
915 if (!hTask) hTask = hCurrentTask;
916 if (!(pTask = (TDB *)GlobalLock16( hTask ))) return;
917 pTask->nEvents++;
921 /***********************************************************************
922 * SetPriority (KERNEL.32)
924 void WINAPI SetPriority( HTASK16 hTask, INT16 delta )
926 TDB *pTask;
927 INT16 newpriority;
929 if (!hTask) hTask = hCurrentTask;
930 if (!(pTask = (TDB *)GlobalLock16( hTask ))) return;
931 newpriority = pTask->priority + delta;
932 if (newpriority < -32) newpriority = -32;
933 else if (newpriority > 15) newpriority = 15;
935 pTask->priority = newpriority + 1;
936 TASK_UnlinkTask( hTask );
937 TASK_LinkTask( hTask );
938 pTask->priority--;
942 /***********************************************************************
943 * LockCurrentTask (KERNEL.33)
945 HTASK16 WINAPI LockCurrentTask( BOOL16 bLock )
947 if (bLock) hLockedTask = hCurrentTask;
948 else hLockedTask = 0;
949 return hLockedTask;
953 /***********************************************************************
954 * IsTaskLocked (KERNEL.122)
956 HTASK16 WINAPI IsTaskLocked(void)
958 return hLockedTask;
962 /***********************************************************************
963 * OldYield (KERNEL.117)
965 void WINAPI OldYield(void)
967 TDB *pCurTask;
969 pCurTask = (TDB *)GlobalLock16( hCurrentTask );
970 if (pCurTask) pCurTask->nEvents++; /* Make sure we get back here */
971 TASK_YieldToSystem(pCurTask);
972 if (pCurTask) pCurTask->nEvents--;
976 /***********************************************************************
977 * DirectedYield (KERNEL.150)
979 void WINAPI DirectedYield( HTASK16 hTask )
981 TDB *pCurTask = (TDB *)GlobalLock16( hCurrentTask );
982 pCurTask->hYieldTo = hTask;
983 OldYield();
987 /***********************************************************************
988 * UserYield (USER.332)
990 void WINAPI UserYield(void)
992 TDB *pCurTask = (TDB *)GlobalLock16( hCurrentTask );
993 MESSAGEQUEUE *queue = (MESSAGEQUEUE *)GlobalLock16( pCurTask->hQueue );
994 /* Handle sent messages */
995 while (queue && (queue->wakeBits & QS_SENDMESSAGE))
996 QUEUE_ReceiveMessage( queue );
998 OldYield();
1000 queue = (MESSAGEQUEUE *)GlobalLock16( pCurTask->hQueue );
1001 while (queue && (queue->wakeBits & QS_SENDMESSAGE))
1002 QUEUE_ReceiveMessage( queue );
1006 /***********************************************************************
1007 * Yield16 (KERNEL.29)
1009 void WINAPI Yield16(void)
1011 TDB *pCurTask = (TDB *)GlobalLock16( hCurrentTask );
1012 if (pCurTask) pCurTask->hYieldTo = 0;
1013 if (pCurTask && pCurTask->hQueue) UserYield();
1014 else OldYield();
1018 /***********************************************************************
1019 * MakeProcInstance16 (KERNEL.51)
1021 FARPROC16 WINAPI MakeProcInstance16( FARPROC16 func, HANDLE16 hInstance )
1023 BYTE *thunk,*lfunc;
1024 SEGPTR thunkaddr;
1026 if (__winelib) return func; /* func can be called directly in Winelib */
1027 thunkaddr = TASK_AllocThunk( hCurrentTask );
1028 if (!thunkaddr) return (FARPROC16)0;
1029 thunk = PTR_SEG_TO_LIN( thunkaddr );
1030 lfunc = PTR_SEG_TO_LIN( func );
1032 dprintf_task( stddeb, "MakeProcInstance(%08lx,%04x): got thunk %08lx\n",
1033 (DWORD)func, hInstance, (DWORD)thunkaddr );
1034 if (((lfunc[0]==0x8c) && (lfunc[1]==0xd8)) ||
1035 ((lfunc[0]==0x1e) && (lfunc[1]==0x58))
1037 fprintf(stderr,"FIXME: MakeProcInstance16 thunk would be useless for %p, overwriting with nop;nop;\n", func );
1038 lfunc[0]=0x90; /* nop */
1039 lfunc[1]=0x90; /* nop */
1042 *thunk++ = 0xb8; /* movw instance, %ax */
1043 *thunk++ = (BYTE)(hInstance & 0xff);
1044 *thunk++ = (BYTE)(hInstance >> 8);
1045 *thunk++ = 0xea; /* ljmp func */
1046 *(DWORD *)thunk = (DWORD)func;
1047 return (FARPROC16)thunkaddr;
1051 /***********************************************************************
1052 * FreeProcInstance16 (KERNEL.52)
1054 void WINAPI FreeProcInstance16( FARPROC16 func )
1056 dprintf_task( stddeb, "FreeProcInstance(%08lx)\n", (DWORD)func );
1057 if (!__winelib) TASK_FreeThunk( hCurrentTask, (SEGPTR)func );
1061 /**********************************************************************
1062 * GetCodeHandle (KERNEL.93)
1064 HANDLE16 WINAPI GetCodeHandle( FARPROC16 proc )
1066 HANDLE16 handle;
1067 BYTE *thunk = (BYTE *)PTR_SEG_TO_LIN( proc );
1069 if (__winelib) return 0;
1071 /* Return the code segment containing 'proc'. */
1072 /* Not sure if this is really correct (shouldn't matter that much). */
1074 /* Check if it is really a thunk */
1075 if ((thunk[0] == 0xb8) && (thunk[3] == 0xea))
1076 handle = GlobalHandle16( thunk[6] + (thunk[7] << 8) );
1077 else
1078 handle = GlobalHandle16( HIWORD(proc) );
1080 return handle;
1084 /**********************************************************************
1085 * DefineHandleTable16 (KERNEL.94)
1087 BOOL16 WINAPI DefineHandleTable16( WORD wOffset )
1089 return TRUE; /* FIXME */
1093 /***********************************************************************
1094 * SetTaskQueue (KERNEL.34)
1096 HQUEUE16 WINAPI SetTaskQueue( HTASK16 hTask, HQUEUE16 hQueue )
1098 HQUEUE16 hPrev;
1099 TDB *pTask;
1101 if (!hTask) hTask = hCurrentTask;
1102 if (!(pTask = (TDB *)GlobalLock16( hTask ))) return 0;
1104 hPrev = pTask->hQueue;
1105 pTask->hQueue = hQueue;
1107 TIMER_SwitchQueue( hPrev, hQueue );
1109 return hPrev;
1113 /***********************************************************************
1114 * GetTaskQueue (KERNEL.35)
1116 HQUEUE16 WINAPI GetTaskQueue( HTASK16 hTask )
1118 TDB *pTask;
1120 if (!hTask) hTask = hCurrentTask;
1121 if (!(pTask = (TDB *)GlobalLock16( hTask ))) return 0;
1122 return pTask->hQueue;
1126 /***********************************************************************
1127 * SwitchStackTo (KERNEL.108)
1129 void WINAPI SwitchStackTo( WORD seg, WORD ptr, WORD top )
1131 TDB *pTask;
1132 STACK16FRAME *oldFrame, *newFrame;
1133 INSTANCEDATA *pData;
1134 UINT16 copySize;
1136 if (!(pTask = (TDB *)GlobalLock16( hCurrentTask ))) return;
1137 if (!(pData = (INSTANCEDATA *)GlobalLock16( seg ))) return;
1138 dprintf_task( stddeb, "SwitchStackTo: old=%04x:%04x new=%04x:%04x\n",
1139 SELECTOROF(IF1632_Saved16_ss_sp),
1140 OFFSETOF(IF1632_Saved16_ss_sp), seg, ptr );
1142 /* Save the old stack */
1144 oldFrame = CURRENT_STACK16;
1145 pData->old_ss_sp = IF1632_Saved16_ss_sp;
1146 pData->stacktop = top;
1147 pData->stackmin = ptr;
1148 pData->stackbottom = ptr;
1150 /* Switch to the new stack */
1152 /* Note: we need to take the 3 arguments into account; otherwise,
1153 * the stack will underflow upon return from this function.
1155 IF1632_Saved16_ss_sp = PTR_SEG_OFF_TO_SEGPTR( seg,
1156 ptr - sizeof(STACK16FRAME) - 3 * sizeof(WORD) );
1157 newFrame = CURRENT_STACK16;
1159 /* Copy the stack frame and the local variables to the new stack */
1161 copySize = oldFrame->bp - OFFSETOF(pData->old_ss_sp);
1162 memmove( newFrame, oldFrame, MAX( copySize, sizeof(STACK16FRAME) ));
1166 /***********************************************************************
1167 * SwitchStackBack (KERNEL.109)
1169 * Note: the function is declared as 'register' in the spec file in order
1170 * to make sure all registers are preserved, but we don't use them in any
1171 * way, so we don't need a CONTEXT* argument.
1173 void WINAPI SwitchStackBack(void)
1175 TDB *pTask;
1176 STACK16FRAME *oldFrame, *newFrame;
1177 INSTANCEDATA *pData;
1179 if (!(pTask = (TDB *)GlobalLock16( hCurrentTask ))) return;
1180 if (!(pData = (INSTANCEDATA *)GlobalLock16(SELECTOROF(IF1632_Saved16_ss_sp))))
1181 return;
1182 if (!pData->old_ss_sp)
1184 fprintf( stderr, "SwitchStackBack: no previous SwitchStackTo\n" );
1185 return;
1187 dprintf_task( stddeb, "SwitchStackBack: restoring stack %04x:%04x\n",
1188 SELECTOROF(pData->old_ss_sp), OFFSETOF(pData->old_ss_sp) );
1190 oldFrame = CURRENT_STACK16;
1192 /* Switch back to the old stack */
1194 IF1632_Saved16_ss_sp = pData->old_ss_sp;
1195 pData->old_ss_sp = 0;
1197 /* Build a stack frame for the return */
1199 newFrame = CURRENT_STACK16;
1200 newFrame->saved_ss_sp = oldFrame->saved_ss_sp;
1201 if (debugging_relay)
1203 newFrame->entry_ip = oldFrame->entry_ip;
1204 newFrame->entry_cs = oldFrame->entry_cs;
1209 /***********************************************************************
1210 * GetTaskQueueDS (KERNEL.118)
1212 void WINAPI GetTaskQueueDS( CONTEXT *context )
1214 DS_reg(context) = GlobalHandleToSel( GetTaskQueue(0) );
1218 /***********************************************************************
1219 * GetTaskQueueES (KERNEL.119)
1221 void WINAPI GetTaskQueueES( CONTEXT *context )
1223 ES_reg(context) = GlobalHandleToSel( GetTaskQueue(0) );
1227 /***********************************************************************
1228 * GetCurrentTask (KERNEL.36)
1230 HTASK16 WINAPI GetCurrentTask(void)
1232 return hCurrentTask;
1235 DWORD WINAPI WIN16_GetCurrentTask(void)
1237 /* This is the version used by relay code; the first task is */
1238 /* returned in the high word of the result */
1239 return MAKELONG( hCurrentTask, hFirstTask );
1243 /***********************************************************************
1244 * GetCurrentPDB (KERNEL.37)
1246 HANDLE16 WINAPI GetCurrentPDB(void)
1248 TDB *pTask;
1250 if (!(pTask = (TDB *)GlobalLock16( hCurrentTask ))) return 0;
1251 return pTask->hPDB;
1255 /***********************************************************************
1256 * GetInstanceData (KERNEL.54)
1258 INT16 WINAPI GetInstanceData( HINSTANCE16 instance, WORD buffer, INT16 len )
1260 char *ptr = (char *)GlobalLock16( instance );
1261 if (!ptr || !len) return 0;
1262 if ((int)buffer + len >= 0x10000) len = 0x10000 - buffer;
1263 memcpy( (char *)GlobalLock16(CURRENT_DS) + buffer, ptr + buffer, len );
1264 return len;
1268 /***********************************************************************
1269 * GetExeVersion (KERNEL.105)
1271 WORD WINAPI GetExeVersion(void)
1273 TDB *pTask;
1275 if (!(pTask = (TDB *)GlobalLock16( hCurrentTask ))) return 0;
1276 return pTask->version;
1280 /***********************************************************************
1281 * SetErrorMode16 (KERNEL.107)
1283 UINT16 WINAPI SetErrorMode16( UINT16 mode )
1285 TDB *pTask;
1286 UINT16 oldMode;
1288 if (!(pTask = (TDB *)GlobalLock16( hCurrentTask ))) return 0;
1289 oldMode = pTask->error_mode;
1290 pTask->error_mode = mode;
1291 pTask->thdb->process->error_mode = mode;
1292 return oldMode;
1296 /***********************************************************************
1297 * SetErrorMode32 (KERNEL32.486)
1299 UINT32 WINAPI SetErrorMode32( UINT32 mode )
1301 return SetErrorMode16( (UINT16)mode );
1305 /***********************************************************************
1306 * GetDOSEnvironment (KERNEL.131)
1308 SEGPTR WINAPI GetDOSEnvironment(void)
1310 TDB *pTask;
1312 if (!(pTask = (TDB *)GlobalLock16( hCurrentTask ))) return 0;
1313 return (SEGPTR)WIN16_GlobalLock16( pTask->pdb.environment );
1317 /***********************************************************************
1318 * GetNumTasks (KERNEL.152)
1320 UINT16 WINAPI GetNumTasks(void)
1322 return nTaskCount;
1326 /***********************************************************************
1327 * GetTaskDS (KERNEL.155)
1329 * Note: this function apparently returns a DWORD with LOWORD == HIWORD.
1330 * I don't think we need to bother with this.
1332 HINSTANCE16 WINAPI GetTaskDS(void)
1334 TDB *pTask;
1336 if (!(pTask = (TDB *)GlobalLock16( hCurrentTask ))) return 0;
1337 return pTask->hInstance;
1341 /***********************************************************************
1342 * IsTask (KERNEL.320)
1344 BOOL16 WINAPI IsTask( HTASK16 hTask )
1346 TDB *pTask;
1348 if (!(pTask = (TDB *)GlobalLock16( hTask ))) return FALSE;
1349 if (GlobalSize16( hTask ) < sizeof(TDB)) return FALSE;
1350 return (pTask->magic == TDB_MAGIC);
1354 /***********************************************************************
1355 * SetTaskSignalProc (KERNEL.38)
1357 * Real 16-bit interface is provided by the THUNK_SetTaskSignalProc.
1359 FARPROC16 WINAPI SetTaskSignalProc( HTASK16 hTask, FARPROC16 proc )
1361 TDB *pTask;
1362 FARPROC16 oldProc;
1364 if (!hTask) hTask = hCurrentTask;
1365 if (!(pTask = (TDB *)GlobalLock16( hTask ))) return NULL;
1366 oldProc = (FARPROC16)pTask->userhandler;
1367 pTask->userhandler = (USERSIGNALPROC)proc;
1368 return oldProc;
1372 /***********************************************************************
1373 * SetSigHandler (KERNEL.140)
1375 WORD WINAPI SetSigHandler( FARPROC16 newhandler, FARPROC16* oldhandler,
1376 UINT16 *oldmode, UINT16 newmode, UINT16 flag )
1378 fprintf(stdnimp,"SetSigHandler(%p,%p,%p,%d,%d), unimplemented.\n",
1379 newhandler,oldhandler,oldmode,newmode,flag );
1381 if (flag != 1) return 0;
1382 if (!newmode) newhandler = NULL; /* Default handler */
1383 if (newmode != 4)
1385 TDB *pTask;
1387 if (!(pTask = (TDB *)GlobalLock16( hCurrentTask ))) return 0;
1388 if (oldmode) *oldmode = pTask->signal_flags;
1389 pTask->signal_flags = newmode;
1390 if (oldhandler) *oldhandler = pTask->sighandler;
1391 pTask->sighandler = newhandler;
1393 return 0;
1397 /***********************************************************************
1398 * GlobalNotify (KERNEL.154)
1400 VOID WINAPI GlobalNotify( FARPROC16 proc )
1402 TDB *pTask;
1404 if (!(pTask = (TDB *)GlobalLock16( hCurrentTask ))) return;
1405 pTask->discardhandler = proc;
1409 /***********************************************************************
1410 * GetExePtr (KERNEL.133)
1412 HMODULE16 WINAPI GetExePtr( HANDLE16 handle )
1414 char *ptr;
1415 HTASK16 hTask;
1416 HANDLE16 owner;
1418 /* Check for module handle */
1420 if (!(ptr = GlobalLock16( handle ))) return 0;
1421 if (((NE_MODULE *)ptr)->magic == IMAGE_OS2_SIGNATURE) return handle;
1423 /* Check the owner for module handle */
1425 owner = FarGetOwner( handle );
1426 if (!(ptr = GlobalLock16( owner ))) return 0;
1427 if (((NE_MODULE *)ptr)->magic == IMAGE_OS2_SIGNATURE) return owner;
1429 /* Search for this handle and its owner inside all tasks */
1431 hTask = hFirstTask;
1432 while (hTask)
1434 TDB *pTask = (TDB *)GlobalLock16( hTask );
1435 if ((hTask == handle) ||
1436 (pTask->hInstance == handle) ||
1437 (pTask->hQueue == handle) ||
1438 (pTask->hPDB == handle)) return pTask->hModule;
1439 if ((hTask == owner) ||
1440 (pTask->hInstance == owner) ||
1441 (pTask->hQueue == owner) ||
1442 (pTask->hPDB == owner)) return pTask->hModule;
1443 hTask = pTask->hNext;
1445 return 0;
1448 /***********************************************************************
1449 * TaskFirst (TOOLHELP.63)
1451 BOOL16 WINAPI TaskFirst( TASKENTRY *lpte )
1453 lpte->hNext = hFirstTask;
1454 return TaskNext( lpte );
1458 /***********************************************************************
1459 * TaskNext (TOOLHELP.64)
1461 BOOL16 WINAPI TaskNext( TASKENTRY *lpte )
1463 TDB *pTask;
1464 INSTANCEDATA *pInstData;
1466 dprintf_toolhelp( stddeb, "TaskNext(%p): task=%04x\n", lpte, lpte->hNext );
1467 if (!lpte->hNext) return FALSE;
1468 pTask = (TDB *)GlobalLock16( lpte->hNext );
1469 if (!pTask || pTask->magic != TDB_MAGIC) return FALSE;
1470 pInstData = (INSTANCEDATA *)PTR_SEG_OFF_TO_LIN( pTask->hInstance, 0 );
1471 lpte->hTask = lpte->hNext;
1472 lpte->hTaskParent = pTask->hParent;
1473 lpte->hInst = pTask->hInstance;
1474 lpte->hModule = pTask->hModule;
1475 lpte->wSS = SELECTOROF( pTask->ss_sp );
1476 lpte->wSP = OFFSETOF( pTask->ss_sp );
1477 lpte->wStackTop = pInstData->stacktop;
1478 lpte->wStackMinimum = pInstData->stackmin;
1479 lpte->wStackBottom = pInstData->stackbottom;
1480 lpte->wcEvents = pTask->nEvents;
1481 lpte->hQueue = pTask->hQueue;
1482 strncpy( lpte->szModule, pTask->module_name, 8 );
1483 lpte->szModule[8] = '\0';
1484 lpte->wPSPOffset = 0x100; /*??*/
1485 lpte->hNext = pTask->hNext;
1486 return TRUE;
1490 /***********************************************************************
1491 * TaskFindHandle (TOOLHELP.65)
1493 BOOL16 WINAPI TaskFindHandle( TASKENTRY *lpte, HTASK16 hTask )
1495 lpte->hNext = hTask;
1496 return TaskNext( lpte );
1500 /***********************************************************************
1501 * GetAppCompatFlags16 (KERNEL.354)
1503 DWORD WINAPI GetAppCompatFlags16( HTASK16 hTask )
1505 return GetAppCompatFlags32( hTask );
1509 /***********************************************************************
1510 * GetAppCompatFlags32 (USER32.205)
1512 DWORD WINAPI GetAppCompatFlags32( HTASK32 hTask )
1514 TDB *pTask;
1516 if (!hTask) hTask = GetCurrentTask();
1517 if (!(pTask=(TDB *)GlobalLock16( (HTASK16)hTask ))) return 0;
1518 if (GlobalSize16(hTask) < sizeof(TDB)) return 0;
1519 return pTask->compat_flags;