4 * Copyright 1995 Alexandre Julliard
17 #include "selectors.h"
23 /* Min. number of thunks allocated when creating a new segment */
26 /* 32-bit stack size for each task */
27 /* Must not be greater than 64k, or MAKE_SEGPTR won't work */
28 #define STACK32_SIZE 0x10000
31 static HTASK hFirstTask
= 0;
32 static HTASK hCurrentTask
= 0;
33 static HTASK hTaskToKill
= 0;
34 static WORD nTaskCount
= 0;
36 /* TASK_Reschedule() 16-bit entry point */
37 static FARPROC TASK_RescheduleProc
;
39 #define TASK_SCHEDULE() CallTo16_word_(TASK_RescheduleProc,0)
42 /***********************************************************************
47 TASK_RescheduleProc
= (FARPROC
)GetWndProcEntry16( "TASK_Reschedule" );
52 /***********************************************************************
55 static void TASK_LinkTask( HTASK hTask
)
60 if (!(pTask
= (TDB
*)GlobalLock( hTask
))) return;
61 prevTask
= &hFirstTask
;
64 TDB
*prevTaskPtr
= (TDB
*)GlobalLock( *prevTask
);
65 if (prevTaskPtr
->priority
>= pTask
->priority
) break;
66 prevTask
= &prevTaskPtr
->hNext
;
68 pTask
->hNext
= *prevTask
;
74 /***********************************************************************
77 static void TASK_UnlinkTask( HTASK hTask
)
82 prevTask
= &hFirstTask
;
83 while (*prevTask
&& (*prevTask
!= hTask
))
85 pTask
= (TDB
*)GlobalLock( *prevTask
);
86 prevTask
= &pTask
->hNext
;
90 pTask
= (TDB
*)GlobalLock( *prevTask
);
91 *prevTask
= pTask
->hNext
;
98 /***********************************************************************
101 * Create a thunk free-list in segment 'handle', starting from offset 'offset'
102 * and containing 'count' entries.
104 static void TASK_CreateThunks( HGLOBAL handle
, WORD offset
, WORD count
)
110 pThunk
= (THUNKS
*)((BYTE
*)GlobalLock( handle
) + offset
);
112 pThunk
->magic
= THUNK_MAGIC
;
113 pThunk
->free
= (int)&pThunk
->thunks
- (int)pThunk
;
115 for (i
= 0; i
< count
-1; i
++)
117 free
+= 8; /* Offset of next thunk */
118 pThunk
->thunks
[4*i
] = free
;
120 pThunk
->thunks
[4*i
] = 0; /* Last thunk */
124 /***********************************************************************
127 * Allocate a thunk for MakeProcInstance().
129 static SEGPTR
TASK_AllocThunk( HTASK hTask
)
135 if (!(pTask
= (TDB
*)GlobalLock( hTask
))) return 0;
136 sel
= pTask
->hCSAlias
;
137 pThunk
= &pTask
->thunks
;
138 base
= (int)pThunk
- (int)pTask
;
139 while (!pThunk
->free
)
142 if (!sel
) /* Allocate a new segment */
144 sel
= GLOBAL_Alloc( GMEM_FIXED
, sizeof(THUNKS
) + (MIN_THUNKS
-1)*8,
145 pTask
->hPDB
, TRUE
, FALSE
, FALSE
);
146 if (!sel
) return (SEGPTR
)0;
147 TASK_CreateThunks( sel
, 0, MIN_THUNKS
);
150 pThunk
= (THUNKS
*)GlobalLock( sel
);
153 base
+= pThunk
->free
;
154 pThunk
->free
= *(WORD
*)((BYTE
*)pThunk
+ pThunk
->free
);
155 return MAKELONG( base
, sel
);
159 /***********************************************************************
162 * Free a MakeProcInstance() thunk.
164 static BOOL
TASK_FreeThunk( HTASK hTask
, SEGPTR thunk
)
170 if (!(pTask
= (TDB
*)GlobalLock( hTask
))) return 0;
171 sel
= pTask
->hCSAlias
;
172 pThunk
= &pTask
->thunks
;
173 base
= (int)pThunk
- (int)pTask
;
174 while (sel
&& (sel
!= HIWORD(thunk
)))
177 pThunk
= (THUNKS
*)GlobalLock( sel
);
180 if (!sel
) return FALSE
;
181 *(WORD
*)((BYTE
*)pThunk
+ LOWORD(thunk
) - base
) = pThunk
->free
;
182 pThunk
->free
= LOWORD(thunk
) - base
;
187 /***********************************************************************
190 * 32-bit entry point for a new task. This function is responsible for
191 * setting up the registers and jumping to the 16-bit entry point.
193 static void TASK_CallToStart(void)
195 int cs_reg
, ds_reg
, ip_reg
;
196 TDB
*pTask
= (TDB
*)GlobalLock( hCurrentTask
);
197 NE_MODULE
*pModule
= (NE_MODULE
*)GlobalLock( pTask
->hModule
);
198 SEGTABLEENTRY
*pSegTable
= NE_SEG_TABLE( pModule
);
200 /* Registers at initialization must be:
202 * bx stack size in bytes
203 * cx heap size in bytes
204 * si previous app instance
205 * di current app instance
207 * es selector to the PSP
208 * ds dgroup of the application
210 * sp top of the stack
213 cs_reg
= pSegTable
[pModule
->cs
- 1].selector
;
214 ip_reg
= pModule
->ip
;
215 ds_reg
= pSegTable
[pModule
->dgroup
- 1].selector
;
216 IF1632_Saved16_ss
= pTask
->ss
;
217 IF1632_Saved16_sp
= pTask
->sp
;
218 dprintf_task( stddeb
, "Starting main program: cs:ip=%04x:%04x ds=%04x ss:sp=%04x:%04x\n",
219 cs_reg
, ip_reg
, ds_reg
,
220 IF1632_Saved16_ss
, IF1632_Saved16_sp
);
221 CallTo16_regs_( (FARPROC
)(cs_reg
<< 16 | ip_reg
), ds_reg
,
222 pTask
->hPDB
/*es*/, 0 /*bp*/, 0 /*ax*/,
223 pModule
->stack_size
/*bx*/, pModule
->heap_size
/*cx*/,
224 0 /*dx*/, 0 /*si*/, ds_reg
/*di*/ );
225 /* This should never return */
226 fprintf( stderr
, "TASK_CallToStart: Main program returned!\n" );
231 /***********************************************************************
234 HTASK
TASK_CreateTask( HMODULE hModule
, HANDLE hInstance
, HANDLE hPrevInstance
,
235 HANDLE hEnvironment
, char *cmdLine
, WORD cmdShow
)
240 SEGTABLEENTRY
*pSegTable
;
242 char *stack16Top
, *stack32Top
;
243 STACK16FRAME
*frame16
;
244 STACK32FRAME
*frame32
;
245 extern DWORD CALL16_RetAddr_word
;
247 if (!(pModule
= (NE_MODULE
*)GlobalLock( hModule
))) return 0;
248 pSegTable
= NE_SEG_TABLE( pModule
);
250 /* Allocate the task structure */
252 hTask
= GLOBAL_Alloc( GMEM_FIXED
| GMEM_ZEROINIT
, sizeof(TDB
),
253 hModule
, FALSE
, FALSE
, FALSE
);
254 if (!hTask
) return 0;
255 pTask
= (TDB
*)GlobalLock( hTask
);
257 /* Fill the task structure */
259 pTask
->nEvents
= 1; /* So the task can be started */
260 pTask
->hSelf
= hTask
;
262 pTask
->version
= pModule
->expected_version
;
263 pTask
->hInstance
= hInstance
;
264 pTask
->hPrevInstance
= hPrevInstance
;
265 pTask
->hModule
= hModule
;
266 pTask
->hParent
= hCurrentTask
;
267 pTask
->curdrive
= 'C' - 'A' + 0x80;
268 pTask
->magic
= TDB_MAGIC
;
269 pTask
->nCmdShow
= cmdShow
;
270 strcpy( pTask
->curdir
, "WINDOWS" );
272 /* Create the thunks block */
274 TASK_CreateThunks( hTask
, (int)&pTask
->thunks
- (int)pTask
, 7 );
276 /* Copy the module name */
278 name
= MODULE_GetModuleName( hModule
);
279 strncpy( pTask
->module_name
, name
, sizeof(pTask
->module_name
) );
283 pTask
->pdb
.int20
= 0x20cd;
284 pTask
->pdb
.dispatcher
[0] = 0x9a;
285 *(DWORD
*)&pTask
->pdb
.dispatcher
[1] = MODULE_GetEntryPoint( GetModuleHandle("KERNEL"), 102 ); /* KERNEL.102 is DOS3Call() */
286 pTask
->pdb
.savedint22
= MODULE_GetEntryPoint( GetModuleHandle("KERNEL"),
287 137 ); /* KERNEL.137 is FatalAppExit() */
288 pTask
->pdb
.savedint23
= pTask
->pdb
.savedint22
;
289 pTask
->pdb
.savedint24
= pTask
->pdb
.savedint22
;
290 pTask
->pdb
.environment
= hEnvironment
;
291 strncpy( pTask
->pdb
.cmdLine
+ 1, cmdLine
, 126 );
292 pTask
->pdb
.cmdLine
[127] = '\0';
293 pTask
->pdb
.cmdLine
[0] = strlen( pTask
->pdb
.cmdLine
+ 1 );
295 /* Get the compatibility flags */
297 pTask
->compat_flags
= GetProfileInt( name
, "Compatibility", 0 );
299 /* Allocate a selector for the PDB */
301 pTask
->hPDB
= GLOBAL_CreateBlock( GMEM_FIXED
, &pTask
->pdb
, sizeof(PDB
),
302 hModule
, FALSE
, FALSE
, FALSE
);
304 /* Allocate a code segment alias for the TDB */
306 pTask
->hCSAlias
= GLOBAL_CreateBlock( GMEM_FIXED
, (void *)pTask
,
307 sizeof(TDB
), pTask
->hPDB
, TRUE
,
310 /* Set the owner of the environment block */
312 FarSetOwner( pTask
->pdb
.environment
, pTask
->hPDB
);
314 /* Default DTA overwrites command-line */
316 pTask
->dta
= MAKELONG( (int)&pTask
->pdb
.cmdLine
- (int)&pTask
->pdb
,
319 /* Allocate the 32-bit stack */
321 pTask
->hStack32
= GLOBAL_Alloc( GMEM_FIXED
, STACK32_SIZE
, pTask
->hPDB
,
322 FALSE
, FALSE
, FALSE
);
324 /* Create the 32-bit stack frame */
326 stack32Top
= (char*)GlobalLock(pTask
->hStack32
) + STACK32_SIZE
;
327 frame32
= (STACK32FRAME
*)stack32Top
- 1;
328 frame32
->saved_esp
= (DWORD
)stack32Top
;
335 frame32
->retaddr
= (DWORD
)TASK_CallToStart
;
336 frame32
->codeselector
= WINE_CODE_SELECTOR
;
337 pTask
->esp
= (DWORD
)frame32
;
339 /* Create the 16-bit stack frame */
341 pTask
->ss
= hInstance
;
342 pTask
->sp
= (pModule
->sp
!= 0) ? pModule
->sp
:
343 pSegTable
[pModule
->ss
-1].minsize
+ pModule
->stack_size
;
344 stack16Top
= (char *)PTR_SEG_OFF_TO_LIN( pTask
->ss
, pTask
->sp
);
345 frame16
= (STACK16FRAME
*)stack16Top
- 1;
346 frame16
->saved_ss
= pTask
->ss
;
347 frame16
->saved_sp
= pTask
->sp
;
348 frame16
->ds
= pTask
->hInstance
;
349 frame16
->entry_point
= 0;
350 frame16
->ordinal_number
= 1;
353 frame16
->ip
= LOWORD( CALL16_RetAddr_word
);
354 frame16
->cs
= HIWORD( CALL16_RetAddr_word
);
355 pTask
->sp
-= sizeof(STACK16FRAME
);
357 /* If there's no 16-bit stack yet, use a part of the new task stack */
358 /* This is only needed to have a stack to switch from on the first */
359 /* call to DirectedYield(). */
361 if (!IF1632_Saved16_ss
)
363 IF1632_Saved16_ss
= pTask
->ss
;
364 IF1632_Saved16_sp
= pTask
->sp
;
367 /* Add the task to the linked list */
369 TASK_LinkTask( hTask
);
371 dprintf_task( stddeb
, "CreateTask: module='%s' cmdline='%s' task=%04x\n",
372 name
, cmdLine
, hTask
);
378 /***********************************************************************
381 void TASK_DeleteTask( HTASK hTask
)
385 if (!(pTask
= (TDB
*)GlobalLock( hTask
))) return;
387 /* Free the task module */
389 FreeModule( pTask
->hModule
);
391 /* Free all memory used by this task (including the 32-bit stack, */
392 /* the environment block and the thunk segments). */
394 GlobalFreeAll( pTask
->hPDB
);
396 /* Free the selector aliases */
398 GLOBAL_FreeBlock( pTask
->hCSAlias
);
399 GLOBAL_FreeBlock( pTask
->hPDB
);
401 /* Free the task structure itself */
407 /***********************************************************************
408 * TASK_KillCurrentTask
410 * Kill the currently running task. As it's not possible to kill the
411 * current task like this, it is simply marked for destruction, and will
412 * be killed when either TASK_Reschedule or this function is called again
413 * in the context of another task.
415 void TASK_KillCurrentTask( int exitCode
)
417 if (hTaskToKill
&& (hTaskToKill
!= hCurrentTask
))
419 /* If another task is already marked for destruction, */
420 /* we call kill it now, as we are in another context. */
421 TASK_DeleteTask( hTaskToKill
);
426 dprintf_task( stddeb
, "Killing the last task, exiting\n" );
430 /* Remove the task from the list to be sure we never switch back to it */
431 TASK_UnlinkTask( hCurrentTask
);
433 hTaskToKill
= hCurrentTask
;
435 /* We never return from Yield() */
439 /***********************************************************************
442 * This is where all the magic of task-switching happens!
444 * This function should only be called via the TASK_SCHEDULE() macro, to make
445 * sure that all the context is saved correctly.
447 void TASK_Reschedule(void)
449 TDB
*pOldTask
= NULL
, *pNewTask
;
452 /* First check if there's a task to kill */
454 if (hTaskToKill
&& (hTaskToKill
!= hCurrentTask
))
455 TASK_DeleteTask( hTaskToKill
);
457 /* Find a task to yield to */
459 pOldTask
= (TDB
*)GlobalLock( hCurrentTask
);
460 if (pOldTask
&& pOldTask
->hYieldTo
)
462 /* If a task is stored in hYieldTo of the current task (put there */
463 /* by DirectedYield), yield to it only if it has events pending. */
464 hTask
= pOldTask
->hYieldTo
;
465 if (!(pNewTask
= (TDB
*)GlobalLock( hTask
)) || !pNewTask
->nEvents
)
474 pNewTask
= (TDB
*)GlobalLock( hTask
);
475 if (pNewTask
->nEvents
&& (hTask
!= hCurrentTask
)) break;
476 hTask
= pNewTask
->hNext
;
480 /* If there's a task to kill, switch to any other task, */
481 /* even if it doesn't have events pending. */
483 if (!hTask
&& hTaskToKill
) hTask
= hFirstTask
;
485 if (!hTask
) return; /* Do nothing */
487 pNewTask
= (TDB
*)GlobalLock( hTask
);
488 dprintf_task( stddeb
, "Switching to task %04x (%.8s)\n",
489 hTask
, pNewTask
->module_name
);
491 /* Save the stacks of the previous task (if any) */
495 pOldTask
->ss
= IF1632_Saved16_ss
;
496 pOldTask
->sp
= IF1632_Saved16_sp
;
497 pOldTask
->esp
= IF1632_Saved32_esp
;
500 /* Make the task the last in the linked list (round-robin scheduling) */
502 pNewTask
->priority
++;
503 TASK_UnlinkTask( hTask
);
504 TASK_LinkTask( hTask
);
505 pNewTask
->priority
--;
507 /* Switch to the new stack */
509 hCurrentTask
= hTask
;
510 IF1632_Saved16_ss
= pNewTask
->ss
;
511 IF1632_Saved16_sp
= pNewTask
->sp
;
512 IF1632_Saved32_esp
= pNewTask
->esp
;
513 IF1632_Stack32_base
= WIN16_GlobalLock( pNewTask
->hStack32
);
517 /***********************************************************************
518 * InitTask (KERNEL.91)
520 void InitTask( struct sigcontext_struct context
)
526 if (!(pTask
= (TDB
*)GlobalLock( hCurrentTask
))) return;
527 if (!(pModule
= (NE_MODULE
*)GlobalLock( pTask
->hModule
))) return;
529 NE_InitializeDLLs( pTask
->hModule
);
531 /* Registers on return are:
532 * ax 1 if OK, 0 on error
533 * cx stack limit in bytes
534 * dx cmdShow parameter
535 * si instance handle of the previous instance
536 * di instance handle of the new task
537 * es:bx pointer to command-line inside PSP
540 context
.sc_ebx
= 0x81;
541 context
.sc_ecx
= pModule
->stack_size
;
542 context
.sc_edx
= pTask
->nCmdShow
;
543 context
.sc_esi
= pTask
->hPrevInstance
;
544 context
.sc_edi
= pTask
->hInstance
;
545 context
.sc_es
= pTask
->hPDB
;
549 /***********************************************************************
550 * WaitEvent (KERNEL.30)
552 BOOL
WaitEvent( HTASK hTask
)
556 if (!hTask
) hTask
= hCurrentTask
;
557 pTask
= (TDB
*)GlobalLock( hTask
);
558 if (pTask
->nEvents
> 0)
564 /* When we get back here, we have an event */
570 /***********************************************************************
571 * PostEvent (KERNEL.31)
573 void PostEvent( HTASK hTask
)
577 if (!hTask
) hTask
= hCurrentTask
;
578 if (!(pTask
= (TDB
*)GlobalLock( hTask
))) return;
583 /***********************************************************************
584 * SetPriority (KERNEL.32)
586 void SetPriority( HTASK hTask
, int delta
)
591 if (!hTask
) hTask
= hCurrentTask
;
592 if (!(pTask
= (TDB
*)GlobalLock( hTask
))) return;
593 newpriority
= pTask
->priority
+ delta
;
594 if (newpriority
< -32) newpriority
= -32;
595 else if (newpriority
> 15) newpriority
= 15;
597 pTask
->priority
= newpriority
+ 1;
598 TASK_UnlinkTask( hTask
);
599 TASK_LinkTask( hTask
);
604 /***********************************************************************
605 * OldYield (KERNEL.117)
611 pCurTask
= (TDB
*)GlobalLock( hCurrentTask
);
612 if (pCurTask
) pCurTask
->nEvents
++; /* Make sure we get back here */
614 if (pCurTask
) pCurTask
->nEvents
--;
618 /***********************************************************************
619 * DirectedYield (KERNEL.150)
621 void DirectedYield( HTASK hTask
)
625 if ((pCurTask
= (TDB
*)GlobalLock( hCurrentTask
)) != NULL
)
626 pCurTask
->hYieldTo
= hTask
;
632 /***********************************************************************
641 /***********************************************************************
642 * MakeProcInstance (KERNEL.51)
644 FARPROC
MakeProcInstance( FARPROC func
, HANDLE hInstance
)
649 thunkaddr
= TASK_AllocThunk( hCurrentTask
);
650 if (!thunkaddr
) return (FARPROC
)0;
651 thunk
= PTR_SEG_TO_LIN( thunkaddr
);
653 dprintf_task( stddeb
, "MakeProcInstance(%08lx,%04x): got thunk %08lx\n",
654 (SEGPTR
)func
, hInstance
, (SEGPTR
)thunkaddr
);
656 *thunk
++ = 0xb8; /* movw instance, %ax */
657 *thunk
++ = (BYTE
)(hInstance
& 0xff);
658 *thunk
++ = (BYTE
)(hInstance
>> 8);
659 *thunk
++ = 0xea; /* ljmp func */
660 *(DWORD
*)thunk
= (DWORD
)func
;
661 return (FARPROC
)thunkaddr
;
665 /***********************************************************************
666 * FreeProcInstance (KERNEL.52)
668 void FreeProcInstance( FARPROC func
)
670 dprintf_task( stddeb
, "FreeProcInstance(%08lx)\n", (SEGPTR
)func
);
671 TASK_FreeThunk( hCurrentTask
, (SEGPTR
)func
);
675 /**********************************************************************
676 * GetCodeHandle (KERNEL.93)
678 HANDLE
GetCodeHandle( FARPROC proc
)
681 BYTE
*thunk
= (BYTE
*)PTR_SEG_TO_LIN( proc
);
683 /* Return the code segment containing 'proc'. */
684 /* Not sure if this is really correct (shouldn't matter that much). */
686 /* Check if it is really a thunk */
687 if ((thunk
[0] == 0xb8) && (thunk
[3] == 0xea))
688 handle
= GlobalHandle( thunk
[6] + (thunk
[7] << 8) );
690 handle
= GlobalHandle( HIWORD(proc
) );
692 printf( "STUB: GetCodeHandle(%08lx) returning %04x\n",
693 (DWORD
)proc
, handle
);
698 /***********************************************************************
699 * SetTaskQueue (KERNEL.34)
701 HGLOBAL
SetTaskQueue( HANDLE hTask
, HGLOBAL hQueue
)
706 if (!hTask
) hTask
= hCurrentTask
;
707 if (!(pTask
= (TDB
*)GlobalLock( hTask
))) return 0;
708 hPrev
= pTask
->hQueue
;
709 pTask
->hQueue
= hQueue
;
714 /***********************************************************************
715 * GetTaskQueue (KERNEL.35)
717 HGLOBAL
GetTaskQueue( HANDLE hTask
)
721 if (!hTask
) hTask
= hCurrentTask
;
722 if (!(pTask
= (TDB
*)GlobalLock( hTask
))) return 0;
723 return pTask
->hQueue
;
727 /***********************************************************************
728 * GetCurrentTask (KERNEL.36)
730 HTASK
GetCurrentTask(void)
732 /* Undocumented: first task is returned in high word */
733 return MAKELONG( hCurrentTask
, hFirstTask
);
737 /***********************************************************************
738 * GetCurrentPDB (KERNEL.37)
740 WORD
GetCurrentPDB(void)
744 if (!(pTask
= (TDB
*)GlobalLock( hCurrentTask
))) return 0;
749 /***********************************************************************
750 * GetNumTasks (KERNEL.152)
752 WORD
GetNumTasks(void)
758 /***********************************************************************
759 * GetTaskDS (KERNEL.155)
765 if (!(pTask
= (TDB
*)GlobalLock( hCurrentTask
))) return 0;
766 return pTask
->hInstance
;
770 /***********************************************************************
771 * IsTask (KERNEL.320)
773 BOOL
IsTask( HTASK hTask
)
777 if (!(pTask
= (TDB
*)GlobalLock( hTask
))) return FALSE
;
778 if (GlobalSize( hTask
) < sizeof(TDB
)) return FALSE
;
779 return (pTask
->magic
== TDB_MAGIC
);
783 /***********************************************************************
784 * GetExePtr (KERNEL.133)
786 HMODULE
GetExePtr( HANDLE handle
)
792 /* Check for module handle */
794 if (!(ptr
= GlobalLock( handle
))) return 0;
795 if (((NE_MODULE
*)ptr
)->magic
== NE_SIGNATURE
) return handle
;
797 /* Check the owner for module handle */
799 owner
= FarGetOwner( handle
);
800 if (!(ptr
= GlobalLock( owner
))) return 0;
801 if (((NE_MODULE
*)ptr
)->magic
== NE_SIGNATURE
) return owner
;
803 /* Search for this handle and its owner inside all tasks */
808 TDB
*pTask
= (TDB
*)GlobalLock( hTask
);
809 if ((hTask
== handle
) ||
810 (pTask
->hInstance
== handle
) ||
811 (pTask
->hQueue
== handle
) ||
812 (pTask
->hPDB
== handle
)) return pTask
->hModule
;
813 if ((hTask
== owner
) ||
814 (pTask
->hInstance
== owner
) ||
815 (pTask
->hQueue
== owner
) ||
816 (pTask
->hPDB
== owner
)) return pTask
->hModule
;
822 /***********************************************************************
823 * TaskFirst (TOOLHELP.63)
825 BOOL
TaskFirst( TASKENTRY
*lpte
)
827 lpte
->hNext
= hFirstTask
;
828 return TaskNext( lpte
);
832 /***********************************************************************
833 * TaskNext (TOOLHELP.64)
835 BOOL
TaskNext( TASKENTRY
*lpte
)
838 INSTANCEDATA
*pInstData
;
840 dprintf_toolhelp( stddeb
, "TaskNext(%p): task=%04x\n", lpte
, lpte
->hNext
);
841 if (!lpte
->hNext
) return FALSE
;
842 pTask
= (TDB
*)GlobalLock( lpte
->hNext
);
843 if (!pTask
|| pTask
->magic
!= TDB_MAGIC
) return FALSE
;
844 pInstData
= (INSTANCEDATA
*)PTR_SEG_OFF_TO_LIN( pTask
->hInstance
, 0 );
845 lpte
->hTask
= lpte
->hNext
;
846 lpte
->hTaskParent
= pTask
->hParent
;
847 lpte
->hInst
= pTask
->hInstance
;
848 lpte
->hModule
= pTask
->hModule
;
849 lpte
->wSS
= pTask
->ss
;
850 lpte
->wSP
= pTask
->sp
;
851 lpte
->wStackTop
= pInstData
->stacktop
;
852 lpte
->wStackMinimum
= pInstData
->stackmin
;
853 lpte
->wStackBottom
= pInstData
->stackbottom
;
854 lpte
->wcEvents
= pTask
->nEvents
;
855 lpte
->hQueue
= pTask
->hQueue
;
856 strncpy( lpte
->szModule
, pTask
->module_name
, 8 );
857 lpte
->szModule
[8] = '\0';
858 lpte
->wPSPOffset
= 0x100; /*??*/
859 lpte
->hNext
= pTask
->hNext
;
864 /***********************************************************************
865 * TaskFindHandle (TOOLHELP.65)
867 BOOL
TaskFindHandle( TASKENTRY
*lpte
, HTASK hTask
)
870 return TaskNext( lpte
);