4 * Copyright 1995 Alexandre Julliard
18 #include "selectors.h"
24 /* Min. number of thunks allocated when creating a new segment */
27 /* 32-bit stack size for each task */
28 /* Must not be greater than 64k, or MAKE_SEGPTR won't work */
29 #define STACK32_SIZE 0x10000
32 static HTASK hFirstTask
= 0;
33 static HTASK hCurrentTask
= 0;
34 static HTASK hTaskToKill
= 0;
35 static HTASK hLockedTask
= 0;
36 static WORD nTaskCount
= 0;
38 /* TASK_Reschedule() 16-bit entry point */
39 static FARPROC TASK_RescheduleProc
;
41 #define TASK_SCHEDULE() CallTo16_word_(TASK_RescheduleProc,0)
44 /***********************************************************************
49 TASK_RescheduleProc
= (FARPROC
)GetWndProcEntry16( "TASK_Reschedule" );
54 /***********************************************************************
57 static void TASK_LinkTask( HTASK hTask
)
62 if (!(pTask
= (TDB
*)GlobalLock( hTask
))) return;
63 prevTask
= &hFirstTask
;
66 TDB
*prevTaskPtr
= (TDB
*)GlobalLock( *prevTask
);
67 if (prevTaskPtr
->priority
>= pTask
->priority
) break;
68 prevTask
= &prevTaskPtr
->hNext
;
70 pTask
->hNext
= *prevTask
;
76 /***********************************************************************
79 static void TASK_UnlinkTask( HTASK hTask
)
84 prevTask
= &hFirstTask
;
85 while (*prevTask
&& (*prevTask
!= hTask
))
87 pTask
= (TDB
*)GlobalLock( *prevTask
);
88 prevTask
= &pTask
->hNext
;
92 pTask
= (TDB
*)GlobalLock( *prevTask
);
93 *prevTask
= pTask
->hNext
;
100 /***********************************************************************
103 * Create a thunk free-list in segment 'handle', starting from offset 'offset'
104 * and containing 'count' entries.
106 static void TASK_CreateThunks( HGLOBAL handle
, WORD offset
, WORD count
)
112 pThunk
= (THUNKS
*)((BYTE
*)GlobalLock( handle
) + offset
);
114 pThunk
->magic
= THUNK_MAGIC
;
115 pThunk
->free
= (int)&pThunk
->thunks
- (int)pThunk
;
117 for (i
= 0; i
< count
-1; i
++)
119 free
+= 8; /* Offset of next thunk */
120 pThunk
->thunks
[4*i
] = free
;
122 pThunk
->thunks
[4*i
] = 0; /* Last thunk */
126 /***********************************************************************
129 * Allocate a thunk for MakeProcInstance().
131 static SEGPTR
TASK_AllocThunk( HTASK hTask
)
137 if (!(pTask
= (TDB
*)GlobalLock( hTask
))) return 0;
138 sel
= pTask
->hCSAlias
;
139 pThunk
= &pTask
->thunks
;
140 base
= (int)pThunk
- (int)pTask
;
141 while (!pThunk
->free
)
144 if (!sel
) /* Allocate a new segment */
146 sel
= GLOBAL_Alloc( GMEM_FIXED
, sizeof(THUNKS
) + (MIN_THUNKS
-1)*8,
147 pTask
->hPDB
, TRUE
, FALSE
, FALSE
);
148 if (!sel
) return (SEGPTR
)0;
149 TASK_CreateThunks( sel
, 0, MIN_THUNKS
);
152 pThunk
= (THUNKS
*)GlobalLock( sel
);
155 base
+= pThunk
->free
;
156 pThunk
->free
= *(WORD
*)((BYTE
*)pThunk
+ pThunk
->free
);
157 return MAKELONG( base
, sel
);
161 /***********************************************************************
164 * Free a MakeProcInstance() thunk.
166 static BOOL
TASK_FreeThunk( HTASK hTask
, SEGPTR thunk
)
172 if (!(pTask
= (TDB
*)GlobalLock( hTask
))) return 0;
173 sel
= pTask
->hCSAlias
;
174 pThunk
= &pTask
->thunks
;
175 base
= (int)pThunk
- (int)pTask
;
176 while (sel
&& (sel
!= HIWORD(thunk
)))
179 pThunk
= (THUNKS
*)GlobalLock( sel
);
182 if (!sel
) return FALSE
;
183 *(WORD
*)((BYTE
*)pThunk
+ LOWORD(thunk
) - base
) = pThunk
->free
;
184 pThunk
->free
= LOWORD(thunk
) - base
;
189 /***********************************************************************
192 * 32-bit entry point for a new task. This function is responsible for
193 * setting up the registers and jumping to the 16-bit entry point.
195 static void TASK_CallToStart(void)
197 int cs_reg
, ds_reg
, ip_reg
;
198 TDB
*pTask
= (TDB
*)GlobalLock( hCurrentTask
);
199 NE_MODULE
*pModule
= (NE_MODULE
*)GlobalLock( pTask
->hModule
);
200 SEGTABLEENTRY
*pSegTable
= NE_SEG_TABLE( pModule
);
202 /* Registers at initialization must be:
204 * bx stack size in bytes
205 * cx heap size in bytes
206 * si previous app instance
207 * di current app instance
209 * es selector to the PSP
210 * ds dgroup of the application
212 * sp top of the stack
215 cs_reg
= pSegTable
[pModule
->cs
- 1].selector
;
216 ip_reg
= pModule
->ip
;
217 ds_reg
= pSegTable
[pModule
->dgroup
- 1].selector
;
218 IF1632_Saved16_ss
= pTask
->ss
;
219 IF1632_Saved16_sp
= pTask
->sp
;
220 dprintf_task( stddeb
, "Starting main program: cs:ip=%04x:%04x ds=%04x ss:sp=%04x:%04x\n",
221 cs_reg
, ip_reg
, ds_reg
,
222 IF1632_Saved16_ss
, IF1632_Saved16_sp
);
223 CallTo16_regs_( (FARPROC
)(cs_reg
<< 16 | ip_reg
), ds_reg
,
224 pTask
->hPDB
/*es*/, 0 /*bp*/, 0 /*ax*/,
225 pModule
->stack_size
/*bx*/, pModule
->heap_size
/*cx*/,
226 0 /*dx*/, 0 /*si*/, ds_reg
/*di*/ );
227 /* This should never return */
228 fprintf( stderr
, "TASK_CallToStart: Main program returned!\n" );
233 /***********************************************************************
236 HTASK
TASK_CreateTask( HMODULE hModule
, HANDLE hInstance
, HANDLE hPrevInstance
,
237 HANDLE hEnvironment
, char *cmdLine
, WORD cmdShow
)
242 SEGTABLEENTRY
*pSegTable
;
244 char *stack16Top
, *stack32Top
;
245 STACK16FRAME
*frame16
;
246 STACK32FRAME
*frame32
;
247 extern DWORD CALL16_RetAddr_word
;
249 if (!(pModule
= (NE_MODULE
*)GlobalLock( hModule
))) return 0;
250 pSegTable
= NE_SEG_TABLE( pModule
);
252 /* Allocate the task structure */
254 hTask
= GLOBAL_Alloc( GMEM_FIXED
| GMEM_ZEROINIT
, sizeof(TDB
),
255 hModule
, FALSE
, FALSE
, FALSE
);
256 if (!hTask
) return 0;
257 pTask
= (TDB
*)GlobalLock( hTask
);
259 /* Fill the task structure */
261 pTask
->nEvents
= 1; /* So the task can be started */
262 pTask
->hSelf
= hTask
;
264 pTask
->version
= pModule
->expected_version
;
265 pTask
->hInstance
= hInstance
;
266 pTask
->hPrevInstance
= hPrevInstance
;
267 pTask
->hModule
= hModule
;
268 pTask
->hParent
= hCurrentTask
;
269 pTask
->curdrive
= 'C' - 'A' + 0x80;
270 pTask
->magic
= TDB_MAGIC
;
271 pTask
->nCmdShow
= cmdShow
;
272 strcpy( pTask
->curdir
, "WINDOWS" );
274 /* Create the thunks block */
276 TASK_CreateThunks( hTask
, (int)&pTask
->thunks
- (int)pTask
, 7 );
278 /* Copy the module name */
280 name
= MODULE_GetModuleName( hModule
);
281 strncpy( pTask
->module_name
, name
, sizeof(pTask
->module_name
) );
285 pTask
->pdb
.int20
= 0x20cd;
286 pTask
->pdb
.dispatcher
[0] = 0x9a; /* ljmp */
287 *(DWORD
*)&pTask
->pdb
.dispatcher
[1] = MODULE_GetEntryPoint( GetModuleHandle("KERNEL"), 102 ); /* KERNEL.102 is DOS3Call() */
288 pTask
->pdb
.savedint22
= INT_GetHandler( 0x22 );
289 pTask
->pdb
.savedint23
= INT_GetHandler( 0x23 );
290 pTask
->pdb
.savedint24
= INT_GetHandler( 0x24 );
291 pTask
->pdb
.environment
= hEnvironment
;
292 strncpy( pTask
->pdb
.cmdLine
+ 1, cmdLine
, 126 );
293 pTask
->pdb
.cmdLine
[127] = '\0';
294 pTask
->pdb
.cmdLine
[0] = strlen( pTask
->pdb
.cmdLine
+ 1 );
296 /* Get the compatibility flags */
298 pTask
->compat_flags
= GetProfileInt( name
, "Compatibility", 0 );
300 /* Allocate a selector for the PDB */
302 pTask
->hPDB
= GLOBAL_CreateBlock( GMEM_FIXED
, &pTask
->pdb
, sizeof(PDB
),
303 hModule
, FALSE
, FALSE
, FALSE
);
305 /* Allocate a code segment alias for the TDB */
307 pTask
->hCSAlias
= GLOBAL_CreateBlock( GMEM_FIXED
, (void *)pTask
,
308 sizeof(TDB
), pTask
->hPDB
, TRUE
,
311 /* Set the owner of the environment block */
313 FarSetOwner( pTask
->pdb
.environment
, pTask
->hPDB
);
315 /* Default DTA overwrites command-line */
317 pTask
->dta
= MAKELONG( (int)&pTask
->pdb
.cmdLine
- (int)&pTask
->pdb
,
320 /* Allocate the 32-bit stack */
322 pTask
->hStack32
= GLOBAL_Alloc( GMEM_FIXED
, STACK32_SIZE
, pTask
->hPDB
,
323 FALSE
, FALSE
, FALSE
);
325 /* Create the 32-bit stack frame */
327 stack32Top
= (char*)GlobalLock(pTask
->hStack32
) + STACK32_SIZE
;
328 frame32
= (STACK32FRAME
*)stack32Top
- 1;
329 frame32
->saved_esp
= (DWORD
)stack32Top
;
336 frame32
->retaddr
= (DWORD
)TASK_CallToStart
;
337 frame32
->codeselector
= WINE_CODE_SELECTOR
;
338 pTask
->esp
= (DWORD
)frame32
;
340 /* Create the 16-bit stack frame */
342 pTask
->ss
= hInstance
;
343 pTask
->sp
= (pModule
->sp
!= 0) ? pModule
->sp
:
344 pSegTable
[pModule
->ss
-1].minsize
+ pModule
->stack_size
;
345 stack16Top
= (char *)PTR_SEG_OFF_TO_LIN( pTask
->ss
, pTask
->sp
);
346 frame16
= (STACK16FRAME
*)stack16Top
- 1;
347 frame16
->saved_ss
= pTask
->ss
;
348 frame16
->saved_sp
= pTask
->sp
;
349 frame16
->ds
= pTask
->hInstance
;
350 frame16
->entry_point
= 0;
351 frame16
->ordinal_number
= 24; /* WINPROCS.24 is TASK_Reschedule */
352 frame16
->dll_id
= 24; /* WINPROCS */
354 frame16
->ip
= LOWORD( CALL16_RetAddr_word
);
355 frame16
->cs
= HIWORD( CALL16_RetAddr_word
);
356 pTask
->sp
-= sizeof(STACK16FRAME
);
358 /* If there's no 16-bit stack yet, use a part of the new task stack */
359 /* This is only needed to have a stack to switch from on the first */
360 /* call to DirectedYield(). */
362 if (!IF1632_Saved16_ss
)
364 IF1632_Saved16_ss
= pTask
->ss
;
365 IF1632_Saved16_sp
= pTask
->sp
;
368 /* Add the task to the linked list */
370 TASK_LinkTask( hTask
);
372 dprintf_task( stddeb
, "CreateTask: module='%s' cmdline='%s' task=%04x\n",
373 name
, cmdLine
, hTask
);
379 /***********************************************************************
382 void TASK_DeleteTask( HTASK hTask
)
386 if (!(pTask
= (TDB
*)GlobalLock( hTask
))) return;
388 /* Free the task module */
390 FreeModule( pTask
->hModule
);
392 /* Free all memory used by this task (including the 32-bit stack, */
393 /* the environment block and the thunk segments). */
395 GlobalFreeAll( pTask
->hPDB
);
397 /* Free the selector aliases */
399 GLOBAL_FreeBlock( pTask
->hCSAlias
);
400 GLOBAL_FreeBlock( pTask
->hPDB
);
402 /* Free the task structure itself */
408 /***********************************************************************
409 * TASK_KillCurrentTask
411 * Kill the currently running task. As it's not possible to kill the
412 * current task like this, it is simply marked for destruction, and will
413 * be killed when either TASK_Reschedule or this function is called again
414 * in the context of another task.
416 void TASK_KillCurrentTask( int exitCode
)
418 if (hTaskToKill
&& (hTaskToKill
!= hCurrentTask
))
420 /* If another task is already marked for destruction, */
421 /* we call kill it now, as we are in another context. */
422 TASK_DeleteTask( hTaskToKill
);
427 dprintf_task( stddeb
, "Killing the last task, exiting\n" );
431 /* Remove the task from the list to be sure we never switch back to it */
432 TASK_UnlinkTask( hCurrentTask
);
434 hTaskToKill
= hCurrentTask
;
437 /* We never return from Yield() */
441 /***********************************************************************
444 * This is where all the magic of task-switching happens!
446 * This function should only be called via the TASK_SCHEDULE() macro, to make
447 * sure that all the context is saved correctly.
449 void TASK_Reschedule(void)
451 TDB
*pOldTask
= NULL
, *pNewTask
;
454 /* First check if there's a task to kill */
456 if (hTaskToKill
&& (hTaskToKill
!= hCurrentTask
))
457 TASK_DeleteTask( hTaskToKill
);
459 /* If current task is locked, simply return */
461 if (hLockedTask
) return;
463 /* Find a task to yield to */
465 pOldTask
= (TDB
*)GlobalLock( hCurrentTask
);
466 if (pOldTask
&& pOldTask
->hYieldTo
)
468 /* If a task is stored in hYieldTo of the current task (put there */
469 /* by DirectedYield), yield to it only if it has events pending. */
470 hTask
= pOldTask
->hYieldTo
;
471 if (!(pNewTask
= (TDB
*)GlobalLock( hTask
)) || !pNewTask
->nEvents
)
480 pNewTask
= (TDB
*)GlobalLock( hTask
);
481 if (pNewTask
->nEvents
&& (hTask
!= hCurrentTask
)) break;
482 hTask
= pNewTask
->hNext
;
486 /* If there's a task to kill, switch to any other task, */
487 /* even if it doesn't have events pending. */
489 if (!hTask
&& hTaskToKill
) hTask
= hFirstTask
;
491 if (!hTask
) return; /* Do nothing */
493 pNewTask
= (TDB
*)GlobalLock( hTask
);
494 dprintf_task( stddeb
, "Switching to task %04x (%.8s)\n",
495 hTask
, pNewTask
->module_name
);
497 /* Save the stacks of the previous task (if any) */
501 pOldTask
->ss
= IF1632_Saved16_ss
;
502 pOldTask
->sp
= IF1632_Saved16_sp
;
503 pOldTask
->esp
= IF1632_Saved32_esp
;
505 else IF1632_Original32_esp
= IF1632_Saved32_esp
;
507 /* Make the task the last in the linked list (round-robin scheduling) */
509 pNewTask
->priority
++;
510 TASK_UnlinkTask( hTask
);
511 TASK_LinkTask( hTask
);
512 pNewTask
->priority
--;
514 /* Switch to the new stack */
516 hCurrentTask
= hTask
;
517 IF1632_Saved16_ss
= pNewTask
->ss
;
518 IF1632_Saved16_sp
= pNewTask
->sp
;
519 IF1632_Saved32_esp
= pNewTask
->esp
;
520 IF1632_Stack32_base
= WIN16_GlobalLock( pNewTask
->hStack32
);
524 /***********************************************************************
525 * InitTask (KERNEL.91)
527 void InitTask( struct sigcontext_struct context
)
529 static int firstTask
= 1;
532 SEGTABLEENTRY
*pSegTable
;
533 INSTANCEDATA
*pinstance
;
534 LONG stacklow
, stackhi
;
537 if (!(pTask
= (TDB
*)GlobalLock( hCurrentTask
))) return;
538 if (!(pModule
= (NE_MODULE
*)GlobalLock( pTask
->hModule
))) return;
542 extern BOOL
WIDGETS_Init(void);
543 extern BOOL
WIN_CreateDesktopWindow(void);
545 /* Perform global initialisations that need a task context */
547 /* Initialize built-in window classes */
548 if (!WIDGETS_Init()) return;
550 /* Create desktop window */
551 if (!WIN_CreateDesktopWindow()) return;
556 NE_InitializeDLLs( pTask
->hModule
);
558 /* Registers on return are:
559 * ax 1 if OK, 0 on error
560 * cx stack limit in bytes
561 * dx cmdShow parameter
562 * si instance handle of the previous instance
563 * di instance handle of the new task
564 * es:bx pointer to command-line inside PSP
567 context
.sc_ebx
= 0x81;
568 context
.sc_ecx
= pModule
->stack_size
;
569 context
.sc_edx
= pTask
->nCmdShow
;
570 context
.sc_esi
= pTask
->hPrevInstance
;
571 context
.sc_edi
= pTask
->hInstance
;
572 context
.sc_es
= pTask
->hPDB
;
574 /* Initialize the local heap */
575 if ( pModule
->heap_size
)
577 LocalInit( pTask
->hInstance
, 0, pModule
->heap_size
);
581 /* Initialize the INSTANCEDATA structure */
582 pSegTable
= NE_SEG_TABLE( pModule
);
583 stacklow
= pSegTable
[pModule
->ss
- 1].minsize
;
584 stackhi
= stacklow
+ pModule
->stack_size
;
585 if (stackhi
> 0xffff) stackhi
= 0xffff;
586 pinstance
= (INSTANCEDATA
*)PTR_SEG_OFF_TO_LIN(CURRENT_DS
, 0);
587 pinstance
->stackbottom
= stackhi
; /* yup, that's right. Confused me too. */
588 pinstance
->stacktop
= stacklow
;
589 pinstance
->stackmin
= IF1632_Saved16_sp
;
593 /***********************************************************************
594 * WaitEvent (KERNEL.30)
596 BOOL
WaitEvent( HTASK hTask
)
600 if (!hTask
) hTask
= hCurrentTask
;
601 pTask
= (TDB
*)GlobalLock( hTask
);
602 if (pTask
->nEvents
> 0)
608 /* When we get back here, we have an event (or the task is the only one) */
609 if (pTask
->nEvents
> 0) pTask
->nEvents
--;
614 /***********************************************************************
615 * PostEvent (KERNEL.31)
617 void PostEvent( HTASK hTask
)
621 if (!hTask
) hTask
= hCurrentTask
;
622 if (!(pTask
= (TDB
*)GlobalLock( hTask
))) return;
627 /***********************************************************************
628 * SetPriority (KERNEL.32)
630 void SetPriority( HTASK hTask
, int delta
)
635 if (!hTask
) hTask
= hCurrentTask
;
636 if (!(pTask
= (TDB
*)GlobalLock( hTask
))) return;
637 newpriority
= pTask
->priority
+ delta
;
638 if (newpriority
< -32) newpriority
= -32;
639 else if (newpriority
> 15) newpriority
= 15;
641 pTask
->priority
= newpriority
+ 1;
642 TASK_UnlinkTask( hTask
);
643 TASK_LinkTask( hTask
);
648 /***********************************************************************
649 * LockCurrentTask (KERNEL.33)
651 HTASK
LockCurrentTask( BOOL bLock
)
653 if (bLock
) hLockedTask
= hCurrentTask
;
654 else hLockedTask
= 0;
659 /***********************************************************************
660 * IsTaskLocked (KERNEL.122)
662 WORD
IsTaskLocked(void)
668 /***********************************************************************
669 * OldYield (KERNEL.117)
675 pCurTask
= (TDB
*)GlobalLock( hCurrentTask
);
676 if (pCurTask
) pCurTask
->nEvents
++; /* Make sure we get back here */
678 if (pCurTask
) pCurTask
->nEvents
--;
682 /***********************************************************************
683 * DirectedYield (KERNEL.150)
685 void DirectedYield( HTASK hTask
)
689 if ((pCurTask
= (TDB
*)GlobalLock( hCurrentTask
)) != NULL
)
690 pCurTask
->hYieldTo
= hTask
;
696 /***********************************************************************
705 /***********************************************************************
706 * MakeProcInstance (KERNEL.51)
708 FARPROC
MakeProcInstance( FARPROC func
, HANDLE hInstance
)
713 thunkaddr
= TASK_AllocThunk( hCurrentTask
);
714 if (!thunkaddr
) return (FARPROC
)0;
715 thunk
= PTR_SEG_TO_LIN( thunkaddr
);
717 dprintf_task( stddeb
, "MakeProcInstance(%08lx,%04x): got thunk %08lx\n",
718 (SEGPTR
)func
, hInstance
, (SEGPTR
)thunkaddr
);
720 *thunk
++ = 0xb8; /* movw instance, %ax */
721 *thunk
++ = (BYTE
)(hInstance
& 0xff);
722 *thunk
++ = (BYTE
)(hInstance
>> 8);
723 *thunk
++ = 0xea; /* ljmp func */
724 *(DWORD
*)thunk
= (DWORD
)func
;
725 return (FARPROC
)thunkaddr
;
729 /***********************************************************************
730 * FreeProcInstance (KERNEL.52)
732 void FreeProcInstance( FARPROC func
)
734 dprintf_task( stddeb
, "FreeProcInstance(%08lx)\n", (SEGPTR
)func
);
735 TASK_FreeThunk( hCurrentTask
, (SEGPTR
)func
);
739 /**********************************************************************
740 * GetCodeHandle (KERNEL.93)
742 HANDLE
GetCodeHandle( FARPROC proc
)
745 BYTE
*thunk
= (BYTE
*)PTR_SEG_TO_LIN( proc
);
747 /* Return the code segment containing 'proc'. */
748 /* Not sure if this is really correct (shouldn't matter that much). */
750 /* Check if it is really a thunk */
751 if ((thunk
[0] == 0xb8) && (thunk
[3] == 0xea))
752 handle
= GlobalHandle( thunk
[6] + (thunk
[7] << 8) );
754 handle
= GlobalHandle( HIWORD(proc
) );
756 printf( "STUB: GetCodeHandle(%08lx) returning %04x\n",
757 (DWORD
)proc
, handle
);
762 /***********************************************************************
763 * SetTaskQueue (KERNEL.34)
765 HGLOBAL
SetTaskQueue( HANDLE hTask
, HGLOBAL hQueue
)
770 if (!hTask
) hTask
= hCurrentTask
;
771 if (!(pTask
= (TDB
*)GlobalLock( hTask
))) return 0;
772 hPrev
= pTask
->hQueue
;
773 pTask
->hQueue
= hQueue
;
778 /***********************************************************************
779 * GetTaskQueue (KERNEL.35)
781 HGLOBAL
GetTaskQueue( HANDLE hTask
)
785 if (!hTask
) hTask
= hCurrentTask
;
786 if (!(pTask
= (TDB
*)GlobalLock( hTask
))) return 0;
787 return pTask
->hQueue
;
791 /***********************************************************************
792 * GetCurrentTask (KERNEL.36)
794 HTASK
GetCurrentTask(void)
796 /* Undocumented: first task is returned in high word */
797 return MAKELONG( hCurrentTask
, hFirstTask
);
801 /***********************************************************************
802 * GetCurrentPDB (KERNEL.37)
804 WORD
GetCurrentPDB(void)
808 if (!(pTask
= (TDB
*)GlobalLock( hCurrentTask
))) return 0;
813 /***********************************************************************
814 * GetInstanceData (KERNEL.54)
816 int GetInstanceData( HANDLE instance
, WORD buffer
, int len
)
818 char *ptr
= (char *)GlobalLock( instance
);
819 if (!ptr
|| !len
) return 0;
820 if ((int)buffer
+ len
>= 0x10000) len
= 0x10000 - buffer
;
821 memcpy( ptr
+ buffer
, (char *)GlobalLock( CURRENT_DS
) + buffer
, len
);
826 /***********************************************************************
827 * GetNumTasks (KERNEL.152)
829 WORD
GetNumTasks(void)
835 /***********************************************************************
836 * GetTaskDS (KERNEL.155)
842 if (!(pTask
= (TDB
*)GlobalLock( hCurrentTask
))) return 0;
843 return pTask
->hInstance
;
847 /***********************************************************************
848 * IsTask (KERNEL.320)
850 BOOL
IsTask( HTASK hTask
)
854 if (!(pTask
= (TDB
*)GlobalLock( hTask
))) return FALSE
;
855 if (GlobalSize( hTask
) < sizeof(TDB
)) return FALSE
;
856 return (pTask
->magic
== TDB_MAGIC
);
860 /***********************************************************************
861 * GetExePtr (KERNEL.133)
863 HMODULE
GetExePtr( HANDLE handle
)
869 /* Check for module handle */
871 if (!(ptr
= GlobalLock( handle
))) return 0;
872 if (((NE_MODULE
*)ptr
)->magic
== NE_SIGNATURE
) return handle
;
874 /* Check the owner for module handle */
876 owner
= FarGetOwner( handle
);
877 if (!(ptr
= GlobalLock( owner
))) return 0;
878 if (((NE_MODULE
*)ptr
)->magic
== NE_SIGNATURE
) return owner
;
880 /* Search for this handle and its owner inside all tasks */
885 TDB
*pTask
= (TDB
*)GlobalLock( hTask
);
886 if ((hTask
== handle
) ||
887 (pTask
->hInstance
== handle
) ||
888 (pTask
->hQueue
== handle
) ||
889 (pTask
->hPDB
== handle
)) return pTask
->hModule
;
890 if ((hTask
== owner
) ||
891 (pTask
->hInstance
== owner
) ||
892 (pTask
->hQueue
== owner
) ||
893 (pTask
->hPDB
== owner
)) return pTask
->hModule
;
899 /***********************************************************************
900 * TaskFirst (TOOLHELP.63)
902 BOOL
TaskFirst( TASKENTRY
*lpte
)
904 lpte
->hNext
= hFirstTask
;
905 return TaskNext( lpte
);
909 /***********************************************************************
910 * TaskNext (TOOLHELP.64)
912 BOOL
TaskNext( TASKENTRY
*lpte
)
915 INSTANCEDATA
*pInstData
;
917 dprintf_toolhelp( stddeb
, "TaskNext(%p): task=%04x\n", lpte
, lpte
->hNext
);
918 if (!lpte
->hNext
) return FALSE
;
919 pTask
= (TDB
*)GlobalLock( lpte
->hNext
);
920 if (!pTask
|| pTask
->magic
!= TDB_MAGIC
) return FALSE
;
921 pInstData
= (INSTANCEDATA
*)PTR_SEG_OFF_TO_LIN( pTask
->hInstance
, 0 );
922 lpte
->hTask
= lpte
->hNext
;
923 lpte
->hTaskParent
= pTask
->hParent
;
924 lpte
->hInst
= pTask
->hInstance
;
925 lpte
->hModule
= pTask
->hModule
;
926 lpte
->wSS
= pTask
->ss
;
927 lpte
->wSP
= pTask
->sp
;
928 lpte
->wStackTop
= pInstData
->stacktop
;
929 lpte
->wStackMinimum
= pInstData
->stackmin
;
930 lpte
->wStackBottom
= pInstData
->stackbottom
;
931 lpte
->wcEvents
= pTask
->nEvents
;
932 lpte
->hQueue
= pTask
->hQueue
;
933 strncpy( lpte
->szModule
, pTask
->module_name
, 8 );
934 lpte
->szModule
[8] = '\0';
935 lpte
->wPSPOffset
= 0x100; /*??*/
936 lpte
->hNext
= pTask
->hNext
;
941 /***********************************************************************
942 * TaskFindHandle (TOOLHELP.65)
944 BOOL
TaskFindHandle( TASKENTRY
*lpte
, HTASK hTask
)
947 return TaskNext( lpte
);