4 * Copyright 1996, 1998 Alexandre Julliard
27 static void PROCESS_Destroy( K32OBJ *obj );
29 const K32OBJ_OPS PROCESS_Ops =
31 PROCESS_Destroy /* destroy */
34 /* The initial process PDB */
35 static PDB initial_pdb;
37 static PDB *PROCESS_First = &initial_pdb;
39 /***********************************************************************
42 PDB *PROCESS_Current(void)
44 return THREAD_Current()->process;
47 /***********************************************************************
50 * FIXME: This works only while running all processes in the same
51 * address space (or, at least, the initial process is mapped
52 * into all address spaces as is KERNEL32 in Windows 95)
55 PDB *PROCESS_Initial(void)
60 /***********************************************************************
63 * Retrieve information about a process
65 static BOOL PROCESS_QueryInfo( HANDLE handle,
66 struct get_process_info_reply *reply )
68 struct get_process_info_request req;
69 req.handle = HANDLE_GetServerHandle( PROCESS_Current(), handle,
70 K32OBJ_PROCESS, PROCESS_QUERY_INFORMATION );
71 CLIENT_SendRequest( REQ_GET_PROCESS_INFO, -1, 1, &req, sizeof(req) );
72 return !CLIENT_WaitSimpleReply( reply, sizeof(*reply), NULL );
75 /***********************************************************************
78 * Check if a handle is to the current process
80 BOOL PROCESS_IsCurrent( HANDLE handle )
82 struct get_process_info_reply reply;
83 return (PROCESS_QueryInfo( handle, &reply ) &&
84 (reply.pid == PROCESS_Current()->server_pid));
88 /***********************************************************************
91 * Convert a process id to a PDB, making sure it is valid.
93 PDB *PROCESS_IdToPDB( DWORD id )
97 if (!id) return PROCESS_Current();
101 if ((DWORD)pdb->server_pid == id) return pdb;
104 SetLastError( ERROR_INVALID_PARAMETER );
110 /***********************************************************************
113 * Build the env DB for the initial process
115 static BOOL PROCESS_BuildEnvDB( PDB *pdb )
117 /* Allocate the env DB (FIXME: should not be on the system heap) */
119 if (!(pdb->env_db = HeapAlloc(SystemHeap,HEAP_ZERO_MEMORY,sizeof(ENVDB))))
121 InitializeCriticalSection( &pdb->env_db->section );
123 /* Allocate startup info */
124 if (!(pdb->env_db->startup_info =
125 HeapAlloc( SystemHeap, HEAP_ZERO_MEMORY, sizeof(STARTUPINFOA) )))
128 /* Allocate the standard handles */
130 pdb->env_db->hStdin = FILE_DupUnixHandle( 0, GENERIC_READ );
131 pdb->env_db->hStdout = FILE_DupUnixHandle( 1, GENERIC_WRITE );
132 pdb->env_db->hStderr = FILE_DupUnixHandle( 2, GENERIC_WRITE );
134 /* Build the command-line */
136 pdb->env_db->cmd_line = HEAP_strdupA( SystemHeap, 0, "kernel32" );
138 /* Build the environment strings */
140 return ENV_BuildEnvironment( pdb );
144 /***********************************************************************
145 * PROCESS_InheritEnvDB
147 static BOOL PROCESS_InheritEnvDB( PDB *pdb, LPCSTR cmd_line, LPCSTR env,
148 BOOL inherit_handles, STARTUPINFOA *startup )
150 if (!(pdb->env_db = HeapAlloc(pdb->heap, HEAP_ZERO_MEMORY, sizeof(ENVDB))))
152 InitializeCriticalSection( &pdb->env_db->section );
154 /* Copy the parent environment */
156 if (!ENV_InheritEnvironment( pdb, env )) return FALSE;
158 /* Copy the command line */
160 if (!(pdb->env_db->cmd_line = HEAP_strdupA( pdb->heap, 0, cmd_line )))
163 /* Remember startup info */
164 if (!(pdb->env_db->startup_info =
165 HeapAlloc( pdb->heap, HEAP_ZERO_MEMORY, sizeof(STARTUPINFOA) )))
167 *pdb->env_db->startup_info = *startup;
169 /* Inherit the standard handles */
170 if (pdb->env_db->startup_info->dwFlags & STARTF_USESTDHANDLES)
172 pdb->env_db->hStdin = pdb->env_db->startup_info->hStdInput;
173 pdb->env_db->hStdout = pdb->env_db->startup_info->hStdOutput;
174 pdb->env_db->hStderr = pdb->env_db->startup_info->hStdError;
176 else if (inherit_handles)
178 pdb->env_db->hStdin = pdb->parent->env_db->hStdin;
179 pdb->env_db->hStdout = pdb->parent->env_db->hStdout;
180 pdb->env_db->hStderr = pdb->parent->env_db->hStderr;
182 /* else will be done later on in PROCESS_Create */
188 /***********************************************************************
191 * Free a PDB and all associated storage.
193 static void PROCESS_FreePDB( PDB *pdb )
195 PDB **pptr = &PROCESS_First;
197 pdb->header.type = K32OBJ_UNKNOWN;
198 if (pdb->handle_table) HANDLE_CloseAll( pdb, NULL );
199 ENV_FreeEnvironment( pdb );
200 while (*pptr && (*pptr != pdb)) pptr = &(*pptr)->next;
201 if (*pptr) *pptr = pdb->next;
202 if (pdb->heap && (pdb->heap != pdb->system_heap)) HeapDestroy( pdb->heap );
203 DeleteCriticalSection( &pdb->crit_section );
204 HeapFree( SystemHeap, 0, pdb );
208 /***********************************************************************
211 * Allocate and fill a PDB structure.
212 * Runs in the context of the parent process.
214 static PDB *PROCESS_CreatePDB( PDB *parent, BOOL inherit )
216 PDB *pdb = HeapAlloc( SystemHeap, HEAP_ZERO_MEMORY, sizeof(PDB) );
218 if (!pdb) return NULL;
219 pdb->header.type = K32OBJ_PROCESS;
220 pdb->header.refcount = 1;
221 pdb->exit_code = 0x103; /* STILL_ACTIVE */
223 pdb->running_threads = 1;
224 pdb->ring0_threads = 1;
225 pdb->system_heap = SystemHeap;
226 pdb->parent = parent;
228 pdb->priority = 8; /* Normal */
229 pdb->heap = pdb->system_heap; /* will be changed later on */
230 pdb->next = PROCESS_First;
233 /* Create the handle table */
235 if (!HANDLE_CreateTable( pdb, inherit )) goto error;
239 PROCESS_FreePDB( pdb );
244 /***********************************************************************
245 * PROCESS_FinishCreatePDB
247 * Second part of CreatePDB
249 static BOOL PROCESS_FinishCreatePDB( PDB *pdb )
251 InitializeCriticalSection( &pdb->crit_section );
252 /* Allocate the event */
253 if (!(pdb->load_done_evt = CreateEventA( NULL, TRUE, FALSE, NULL )))
259 /***********************************************************************
262 BOOL PROCESS_Init(void)
266 /* Fill the initial process structure */
267 initial_pdb.header.type = K32OBJ_PROCESS;
268 initial_pdb.header.refcount = 1;
269 initial_pdb.exit_code = 0x103; /* STILL_ACTIVE */
270 initial_pdb.threads = 1;
271 initial_pdb.running_threads = 1;
272 initial_pdb.ring0_threads = 1;
273 initial_pdb.group = &initial_pdb;
274 initial_pdb.priority = 8; /* Normal */
276 /* Initialize virtual memory management */
277 if (!VIRTUAL_Init()) return FALSE;
279 /* Create the system heap */
280 if (!(SystemHeap = HeapCreate( HEAP_GROWABLE, 0x10000, 0 ))) return FALSE;
281 initial_pdb.system_heap = initial_pdb.heap = SystemHeap;
283 /* Create the initial process and thread structures */
284 if (!HANDLE_CreateTable( &initial_pdb, FALSE )) return FALSE;
285 if (!(thdb = THREAD_CreateInitialThread( &initial_pdb ))) return FALSE;
287 /* Remember TEB selector of initial process for emergency use */
288 SYSLEVEL_EmergencyTeb = thdb->teb_sel;
290 /* Create the environment DB of the first process */
291 if (!PROCESS_BuildEnvDB( &initial_pdb )) return FALSE;
293 /* Initialize the first thread */
294 if (CLIENT_InitThread()) return FALSE;
295 if (!PROCESS_FinishCreatePDB( &initial_pdb )) return FALSE;
297 /* Create the SEGPTR heap */
298 if (!(SegptrHeap = HeapCreate( HEAP_WINE_SEGPTR, 0, 0 ))) return FALSE;
304 /***********************************************************************
307 * Create a new process database and associated info.
309 PDB *PROCESS_Create( NE_MODULE *pModule, LPCSTR cmd_line, LPCSTR env,
310 HINSTANCE16 hInstance, HINSTANCE16 hPrevInstance,
311 BOOL inherit, STARTUPINFOA *startup,
312 PROCESS_INFORMATION *info )
315 int server_thandle, server_phandle;
318 PDB *parent = PROCESS_Current();
319 PDB *pdb = PROCESS_CreatePDB( parent, inherit );
321 if (!pdb) return NULL;
322 info->hThread = info->hProcess = INVALID_HANDLE_VALUE;
323 if (!PROCESS_FinishCreatePDB( pdb )) goto error;
325 /* Create the heap */
327 if (pModule->module32)
329 size = PE_HEADER(pModule->module32)->OptionalHeader.SizeOfHeapReserve;
330 commit = PE_HEADER(pModule->module32)->OptionalHeader.SizeOfHeapCommit;
336 pdb->flags |= PDB32_WIN16_PROC; /* This is a Win16 process */
338 if (!(pdb->heap = HeapCreate( HEAP_GROWABLE, size, commit ))) goto error;
339 pdb->heap_list = pdb->heap;
341 /* Inherit the env DB from the parent */
343 if (!PROCESS_InheritEnvDB( pdb, cmd_line, env, inherit, startup )) goto error;
345 /* Create the main thread */
347 if (pModule->module32)
348 size = PE_HEADER(pModule->module32)->OptionalHeader.SizeOfStackReserve;
351 if (!(thdb = THREAD_Create( pdb, size, hInstance == 0,
352 &server_thandle, &server_phandle, NULL, NULL )))
354 if ((info->hThread = HANDLE_Alloc( parent, &thdb->header, THREAD_ALL_ACCESS,
355 FALSE, server_thandle )) == INVALID_HANDLE_VALUE)
357 if ((info->hProcess = HANDLE_Alloc( parent, &pdb->header, PROCESS_ALL_ACCESS,
358 FALSE, server_phandle )) == INVALID_HANDLE_VALUE)
360 info->dwProcessId = (DWORD)pdb->server_pid;
361 info->dwThreadId = (DWORD)thdb->server_tid;
363 /* Duplicate the standard handles */
365 if ((!(pdb->env_db->startup_info->dwFlags & STARTF_USESTDHANDLES)) && !inherit)
367 DuplicateHandle( GetCurrentProcess(), pdb->parent->env_db->hStdin,
368 info->hProcess, &pdb->env_db->hStdin, 0, TRUE, DUPLICATE_SAME_ACCESS );
369 DuplicateHandle( GetCurrentProcess(), pdb->parent->env_db->hStdout,
370 info->hProcess, &pdb->env_db->hStdout, 0, TRUE, DUPLICATE_SAME_ACCESS );
371 DuplicateHandle( GetCurrentProcess(), pdb->parent->env_db->hStderr,
372 info->hProcess, &pdb->env_db->hStderr, 0, TRUE, DUPLICATE_SAME_ACCESS );
375 /* Create a Win16 task for this process */
377 if (startup->dwFlags & STARTF_USESHOWWINDOW)
378 cmdShow = startup->wShowWindow;
380 if ( !TASK_Create( thdb, pModule, hInstance, hPrevInstance, cmdShow) )
384 /* Map system DLLs into this process (from initial process) */
385 /* FIXME: this is a hack */
386 pdb->modref_list = PROCESS_Initial()->modref_list;
392 if (info->hThread != INVALID_HANDLE_VALUE) CloseHandle( info->hThread );
393 if (info->hProcess != INVALID_HANDLE_VALUE) CloseHandle( info->hProcess );
394 if (thdb) K32OBJ_DecCount( &thdb->header );
395 PROCESS_FreePDB( pdb );
400 /***********************************************************************
403 static void PROCESS_Destroy( K32OBJ *ptr )
405 PDB *pdb = (PDB *)ptr;
406 assert( ptr->type == K32OBJ_PROCESS );
408 /* Free everything */
410 ptr->type = K32OBJ_UNKNOWN;
411 PROCESS_FreePDB( pdb );
415 /***********************************************************************
416 * ExitProcess (KERNEL32.100)
418 void WINAPI ExitProcess( DWORD status )
420 PDB *pdb = PROCESS_Current();
421 TDB *pTask = (TDB *)GlobalLock16( pdb->task );
422 if ( pTask ) pTask->nEvents++;
424 if ( pTask && pTask->thdb != THREAD_Current() )
425 ExitThread( status );
428 /* FIXME: should kill all running threads of this process */
429 pdb->exit_code = status;
430 if (pdb->console) FreeConsole();
433 __RESTORE_ES; /* Necessary for Pietrek's showseh example program */
434 TASK_KillCurrentTask( status );
438 /******************************************************************************
439 * TerminateProcess (KERNEL32.684)
441 BOOL WINAPI TerminateProcess( HANDLE handle, DWORD exit_code )
443 struct terminate_process_request req;
445 req.handle = HANDLE_GetServerHandle( PROCESS_Current(), handle,
446 K32OBJ_PROCESS, PROCESS_TERMINATE );
447 req.exit_code = exit_code;
448 CLIENT_SendRequest( REQ_TERMINATE_PROCESS, -1, 1, &req, sizeof(req) );
449 return !CLIENT_WaitReply( NULL, NULL, 0 );
452 /***********************************************************************
453 * GetCurrentProcess (KERNEL32.198)
455 HANDLE WINAPI GetCurrentProcess(void)
457 return CURRENT_PROCESS_PSEUDOHANDLE;
461 /*********************************************************************
462 * OpenProcess (KERNEL32.543)
464 HANDLE WINAPI OpenProcess( DWORD access, BOOL inherit, DWORD id )
467 struct open_process_request req;
468 struct open_process_reply reply;
470 if (!(pdb = PROCESS_IdToPDB( id ))) return 0;
471 req.pid = (void *)id;
473 req.inherit = inherit;
474 CLIENT_SendRequest( REQ_OPEN_PROCESS, -1, 1, &req, sizeof(req) );
475 if (CLIENT_WaitSimpleReply( &reply, sizeof(reply), NULL )) return 0;
476 return HANDLE_Alloc( PROCESS_Current(), &pdb->header, access,
477 inherit, reply.handle );
481 /***********************************************************************
482 * GetCurrentProcessId (KERNEL32.199)
484 DWORD WINAPI GetCurrentProcessId(void)
486 return (DWORD)PROCESS_Current()->server_pid;
490 /***********************************************************************
491 * GetProcessHeap (KERNEL32.259)
493 HANDLE WINAPI GetProcessHeap(void)
495 PDB *pdb = PROCESS_Current();
496 return pdb->heap ? pdb->heap : SystemHeap;
500 /***********************************************************************
501 * GetThreadLocale (KERNEL32.295)
503 LCID WINAPI GetThreadLocale(void)
505 return PROCESS_Current()->locale;
509 /***********************************************************************
510 * SetPriorityClass (KERNEL32.503)
512 BOOL WINAPI SetPriorityClass( HANDLE hprocess, DWORD priorityclass )
514 struct set_process_info_request req;
515 req.handle = HANDLE_GetServerHandle( PROCESS_Current(), hprocess,
516 K32OBJ_PROCESS, PROCESS_SET_INFORMATION );
517 if (req.handle == -1) return FALSE;
518 req.priority = priorityclass;
519 req.mask = SET_PROCESS_INFO_PRIORITY;
520 CLIENT_SendRequest( REQ_SET_PROCESS_INFO, -1, 1, &req, sizeof(req) );
521 return !CLIENT_WaitReply( NULL, NULL, 0 );
525 /***********************************************************************
526 * GetPriorityClass (KERNEL32.250)
528 DWORD WINAPI GetPriorityClass(HANDLE hprocess)
530 struct get_process_info_reply reply;
531 if (!PROCESS_QueryInfo( hprocess, &reply )) return 0;
532 return reply.priority;
536 /***********************************************************************
537 * SetProcessAffinityMask (KERNEL32.662)
539 BOOL WINAPI SetProcessAffinityMask( HANDLE hProcess, DWORD affmask )
541 struct set_process_info_request req;
542 req.handle = HANDLE_GetServerHandle( PROCESS_Current(), hProcess,
543 K32OBJ_PROCESS, PROCESS_SET_INFORMATION );
544 if (req.handle == -1) return FALSE;
545 req.affinity = affmask;
546 req.mask = SET_PROCESS_INFO_AFFINITY;
547 CLIENT_SendRequest( REQ_SET_PROCESS_INFO, -1, 1, &req, sizeof(req) );
548 return !CLIENT_WaitReply( NULL, NULL, 0 );
551 /**********************************************************************
552 * GetProcessAffinityMask (KERNEL32.373)
554 BOOL WINAPI GetProcessAffinityMask( HANDLE hProcess,
555 LPDWORD lpProcessAffinityMask,
556 LPDWORD lpSystemAffinityMask )
558 struct get_process_info_reply reply;
559 if (!PROCESS_QueryInfo( hProcess, &reply )) return FALSE;
560 if (lpProcessAffinityMask) *lpProcessAffinityMask = reply.process_affinity;
561 if (lpSystemAffinityMask) *lpSystemAffinityMask = reply.system_affinity;
566 /***********************************************************************
567 * GetStdHandle (KERNEL32.276)
569 HANDLE WINAPI GetStdHandle( DWORD std_handle )
571 PDB *pdb = PROCESS_Current();
575 case STD_INPUT_HANDLE: return pdb->env_db->hStdin;
576 case STD_OUTPUT_HANDLE: return pdb->env_db->hStdout;
577 case STD_ERROR_HANDLE: return pdb->env_db->hStderr;
579 SetLastError( ERROR_INVALID_PARAMETER );
580 return INVALID_HANDLE_VALUE;
584 /***********************************************************************
585 * SetStdHandle (KERNEL32.506)
587 BOOL WINAPI SetStdHandle( DWORD std_handle, HANDLE handle )
589 PDB *pdb = PROCESS_Current();
590 /* FIXME: should we close the previous handle? */
593 case STD_INPUT_HANDLE:
594 pdb->env_db->hStdin = handle;
596 case STD_OUTPUT_HANDLE:
597 pdb->env_db->hStdout = handle;
599 case STD_ERROR_HANDLE:
600 pdb->env_db->hStderr = handle;
603 SetLastError( ERROR_INVALID_PARAMETER );
607 /***********************************************************************
608 * GetProcessVersion (KERNEL32)
610 DWORD WINAPI GetProcessVersion( DWORD processid )
613 PDB *pdb = PROCESS_IdToPDB( processid );
616 if (!(pTask = (TDB *)GlobalLock16( pdb->task ))) return 0;
617 return (pTask->version&0xff) | (((pTask->version >>8) & 0xff)<<16);
620 /***********************************************************************
621 * GetProcessFlags (KERNEL32)
623 DWORD WINAPI GetProcessFlags( DWORD processid )
625 PDB *pdb = PROCESS_IdToPDB( processid );
630 /***********************************************************************
631 * SetProcessWorkingSetSize [KERNEL32.662]
632 * Sets the min/max working set sizes for a specified process.
635 * hProcess [I] Handle to the process of interest
636 * minset [I] Specifies minimum working set size
637 * maxset [I] Specifies maximum working set size
641 BOOL WINAPI SetProcessWorkingSetSize(HANDLE hProcess,DWORD minset,
644 FIXME(process,"(0x%08x,%ld,%ld): stub - harmless\n",hProcess,minset,maxset);
645 if(( minset == -1) && (maxset == -1)) {
646 /* Trim the working set to zero */
647 /* Swap the process out of physical RAM */
652 /***********************************************************************
653 * GetProcessWorkingSetSize (KERNEL32)
655 BOOL WINAPI GetProcessWorkingSetSize(HANDLE hProcess,LPDWORD minset,
658 FIXME(process,"(0x%08x,%p,%p): stub\n",hProcess,minset,maxset);
659 /* 32 MB working set size */
660 if (minset) *minset = 32*1024*1024;
661 if (maxset) *maxset = 32*1024*1024;
665 /***********************************************************************
666 * SetProcessShutdownParameters (KERNEL32)
668 * CHANGED - James Sutherland (JamesSutherland@gmx.de)
669 * Now tracks changes made (but does not act on these changes)
670 * NOTE: the definition for SHUTDOWN_NORETRY was done on guesswork.
671 * It really shouldn't be here, but I'll move it when it's been checked!
673 #define SHUTDOWN_NORETRY 1
674 static unsigned int shutdown_noretry = 0;
675 static unsigned int shutdown_priority = 0x280L;
676 BOOL WINAPI SetProcessShutdownParameters(DWORD level,DWORD flags)
678 if (flags & SHUTDOWN_NORETRY)
679 shutdown_noretry = 1;
681 shutdown_noretry = 0;
682 if (level > 0x100L && level < 0x3FFL)
683 shutdown_priority = level;
686 ERR(process,"invalid priority level 0x%08lx\n", level);
693 /***********************************************************************
694 * GetProcessShutdownParameters (KERNEL32)
697 BOOL WINAPI GetProcessShutdownParameters( LPDWORD lpdwLevel,
700 (*lpdwLevel) = shutdown_priority;
701 (*lpdwFlags) = (shutdown_noretry * SHUTDOWN_NORETRY);
704 /***********************************************************************
705 * SetProcessPriorityBoost (KERNEL32)
707 BOOL WINAPI SetProcessPriorityBoost(HANDLE hprocess,BOOL disableboost)
709 FIXME(process,"(%d,%d): stub\n",hprocess,disableboost);
710 /* Say we can do it. I doubt the program will notice that we don't. */
714 /***********************************************************************
715 * ReadProcessMemory (KERNEL32)
716 * FIXME: check this, if we ever run win32 binaries in different addressspaces
717 * ... and add a sizecheck
719 BOOL WINAPI ReadProcessMemory( HANDLE hProcess, LPCVOID lpBaseAddress,
720 LPVOID lpBuffer, DWORD nSize,
721 LPDWORD lpNumberOfBytesRead )
723 memcpy(lpBuffer,lpBaseAddress,nSize);
724 if (lpNumberOfBytesRead) *lpNumberOfBytesRead = nSize;
728 /***********************************************************************
729 * WriteProcessMemory (KERNEL32)
730 * FIXME: check this, if we ever run win32 binaries in different addressspaces
731 * ... and add a sizecheck
733 BOOL WINAPI WriteProcessMemory(HANDLE hProcess, LPVOID lpBaseAddress,
734 LPVOID lpBuffer, DWORD nSize,
735 LPDWORD lpNumberOfBytesWritten )
737 memcpy(lpBaseAddress,lpBuffer,nSize);
738 if (lpNumberOfBytesWritten) *lpNumberOfBytesWritten = nSize;
742 /***********************************************************************
743 * RegisterServiceProcess (KERNEL, KERNEL32)
745 * A service process calls this function to ensure that it continues to run
746 * even after a user logged off.
748 DWORD WINAPI RegisterServiceProcess(DWORD dwProcessId, DWORD dwType)
750 /* I don't think that Wine needs to do anything in that function */
751 return 1; /* success */
754 /***********************************************************************
755 * GetExitCodeProcess [KERNEL32.325]
757 * Gets termination status of specified process
763 BOOL WINAPI GetExitCodeProcess(
764 HANDLE hProcess, /* [I] handle to the process */
765 LPDWORD lpExitCode) /* [O] address to receive termination status */
767 struct get_process_info_reply reply;
768 if (!PROCESS_QueryInfo( hProcess, &reply )) return FALSE;
769 if (lpExitCode) *lpExitCode = reply.exit_code;
774 /***********************************************************************
775 * GetProcessHeaps [KERNEL32.376]
777 DWORD WINAPI GetProcessHeaps(DWORD nrofheaps,HANDLE *heaps) {
778 FIXME(win32,"(%ld,%p), incomplete implementation.\n",nrofheaps,heaps);
781 heaps[0] = GetProcessHeap();
782 /* ... probably SystemHeap too ? */
785 /* number of available heaps */
789 /***********************************************************************
790 * PROCESS_SuspendOtherThreads
793 void PROCESS_SuspendOtherThreads(void)
801 pdb = PROCESS_Current();
802 entry = pdb->thread_list->next;
805 if (entry->thread != THREAD_Current() && !THREAD_IsWin16(entry->thread))
807 HANDLE handle = HANDLE_Alloc( PROCESS_Current(),
808 &entry->thread->header,
809 THREAD_ALL_ACCESS, FALSE, -1 );
810 SuspendThread(handle);
813 if (entry == pdb->thread_list) break;
821 /***********************************************************************
822 * PROCESS_ResumeOtherThreads
825 void PROCESS_ResumeOtherThreads(void)
833 pdb = PROCESS_Current();
834 entry = pdb->thread_list->next;
837 if (entry->thread != THREAD_Current() && !THREAD_IsWin16(entry->thread))
839 HANDLE handle = HANDLE_Alloc( PROCESS_Current(),
840 &entry->thread->header,
841 THREAD_ALL_ACCESS, FALSE, -1 );
842 ResumeThread(handle);
845 if (entry == pdb->thread_list) break;