4 * Copyright 1996 Alexandre Julliard
17 PDB32
*pCurrentProcess
= NULL
;
19 #define HTABLE_SIZE 0x30 /* Handle table initial size */
20 #define HTABLE_INC 0x10 /* Handle table increment */
22 #define BOOT_HTABLE_SIZE 5
24 static HANDLE_ENTRY boot_handles
[BOOT_HTABLE_SIZE
];
26 /***********************************************************************
27 * PROCESS_AllocHandleTable
29 static HANDLE_TABLE
*PROCESS_AllocHandleTable( PDB32
*process
)
31 HANDLE_TABLE
*table
= HeapAlloc( process
->system_heap
, HEAP_ZERO_MEMORY
,
32 sizeof(HANDLE_TABLE
) +
33 (HTABLE_SIZE
-1) * sizeof(HANDLE_ENTRY
) );
34 if (!table
) return NULL
;
35 table
->count
= HTABLE_SIZE
;
40 /***********************************************************************
41 * PROCESS_GrowHandleTable
43 static BOOL32
PROCESS_GrowHandleTable( PDB32
*process
)
45 HANDLE_TABLE
*table
= process
->handle_table
;
46 table
= HeapReAlloc( process
->system_heap
, HEAP_ZERO_MEMORY
, table
,
47 sizeof(HANDLE_TABLE
) +
48 (table
->count
+HTABLE_INC
-1) * sizeof(HANDLE_ENTRY
) );
49 if (!table
) return FALSE
;
50 table
->count
+= HTABLE_INC
;
51 process
->handle_table
= table
;
56 /***********************************************************************
57 * PROCESS_AllocBootHandle
59 * Allocate a handle from the boot table.
61 static HANDLE32
PROCESS_AllocBootHandle( K32OBJ
*ptr
, DWORD flags
)
64 for (h
= 0; h
< BOOT_HTABLE_SIZE
; h
++)
65 if (!boot_handles
[h
].ptr
) break;
66 assert( h
< BOOT_HTABLE_SIZE
);
67 K32OBJ_IncCount( ptr
);
68 boot_handles
[h
].flags
= flags
;
69 boot_handles
[h
].ptr
= ptr
;
70 return h
+ 1; /* Avoid handle 0 */
74 /***********************************************************************
75 * PROCESS_CloseBootHandle
77 * Close a handle from the boot table.
79 static BOOL32
PROCESS_CloseBootHandle( HANDLE32 handle
)
81 HANDLE_ENTRY
*entry
= &boot_handles
[handle
- 1];
82 assert( (handle
> 0) && (handle
<= BOOT_HTABLE_SIZE
) );
84 K32OBJ_DecCount( entry
->ptr
);
91 /***********************************************************************
92 * PROCESS_GetBootObjPtr
94 * Get a handle ptr from the boot table.
96 static K32OBJ
*PROCESS_GetBootObjPtr( HANDLE32 handle
, K32OBJ_TYPE type
)
100 assert( (handle
> 0) && (handle
<= BOOT_HTABLE_SIZE
) );
101 ptr
= boot_handles
[handle
- 1].ptr
;
102 assert (ptr
&& (ptr
->type
== type
));
103 K32OBJ_IncCount( ptr
);
108 /***********************************************************************
109 * PROCESS_SetBootObjPtr
111 * Set a handle ptr from the boot table.
113 static BOOL32
PROCESS_SetBootObjPtr( HANDLE32 handle
, K32OBJ
*ptr
, DWORD flags
)
117 assert( (handle
> 0) && (handle
<= BOOT_HTABLE_SIZE
) );
118 K32OBJ_IncCount( ptr
);
119 if ((old_ptr
= boot_handles
[handle
- 1].ptr
)) K32OBJ_DecCount( old_ptr
);
120 boot_handles
[handle
- 1].flags
= flags
;
121 boot_handles
[handle
- 1].ptr
= ptr
;
126 /***********************************************************************
127 * PROCESS_AllocHandle
129 * Allocate a handle for a kernel object and increment its refcount.
131 HANDLE32
PROCESS_AllocHandle( K32OBJ
*ptr
, DWORD flags
)
137 if (!pCurrentProcess
) return PROCESS_AllocBootHandle( ptr
, flags
);
138 EnterCriticalSection( &pCurrentProcess
->crit_section
);
139 K32OBJ_IncCount( ptr
);
140 entry
= pCurrentProcess
->handle_table
->entries
;
141 for (h
= 0; h
< pCurrentProcess
->handle_table
->count
; h
++, entry
++)
142 if (!entry
->ptr
) break;
143 if ((h
< pCurrentProcess
->handle_table
->count
) ||
144 PROCESS_GrowHandleTable( pCurrentProcess
))
146 entry
->flags
= flags
;
148 LeaveCriticalSection( &pCurrentProcess
->crit_section
);
149 return h
+ 1; /* Avoid handle 0 */
151 LeaveCriticalSection( &pCurrentProcess
->crit_section
);
152 SetLastError( ERROR_OUTOFMEMORY
);
153 K32OBJ_DecCount( ptr
);
154 return INVALID_HANDLE_VALUE32
;
158 /***********************************************************************
161 * Retrieve a pointer to a kernel object and increments its reference count.
162 * The refcount must be decremented when the pointer is no longer used.
164 K32OBJ
*PROCESS_GetObjPtr( HANDLE32 handle
, K32OBJ_TYPE type
)
167 if (!pCurrentProcess
) return PROCESS_GetBootObjPtr( handle
, type
);
168 EnterCriticalSection( &pCurrentProcess
->crit_section
);
170 if ((handle
> 0) && (handle
<= pCurrentProcess
->handle_table
->count
))
171 ptr
= pCurrentProcess
->handle_table
->entries
[handle
- 1].ptr
;
172 else if (handle
== 0x7fffffff) ptr
= &pCurrentProcess
->header
;
174 if (ptr
&& ((type
== K32OBJ_UNKNOWN
) || (ptr
->type
== type
)))
175 K32OBJ_IncCount( ptr
);
178 LeaveCriticalSection( &pCurrentProcess
->crit_section
);
179 if (!ptr
) SetLastError( ERROR_INVALID_HANDLE
);
184 /***********************************************************************
187 * Change the object pointer of a handle, and increment the refcount.
190 BOOL32
PROCESS_SetObjPtr( HANDLE32 handle
, K32OBJ
*ptr
, DWORD flags
)
193 K32OBJ
*old_ptr
= NULL
;
195 if (!pCurrentProcess
) return PROCESS_SetBootObjPtr( handle
, ptr
, flags
);
196 EnterCriticalSection( &pCurrentProcess
->crit_section
);
197 if ((handle
> 0) && (handle
<= pCurrentProcess
->handle_table
->count
))
199 HANDLE_ENTRY
*entry
= &pCurrentProcess
->handle_table
->entries
[handle
-1];
200 old_ptr
= entry
->ptr
;
201 K32OBJ_IncCount( ptr
);
202 entry
->flags
= flags
;
207 SetLastError( ERROR_INVALID_HANDLE
);
210 LeaveCriticalSection( &pCurrentProcess
->crit_section
);
211 if (old_ptr
) K32OBJ_DecCount( old_ptr
);
216 /*********************************************************************
217 * CloseHandle (KERNEL32.23)
219 BOOL32
CloseHandle( HANDLE32 handle
)
224 if (!pCurrentProcess
) return PROCESS_CloseBootHandle( handle
);
225 EnterCriticalSection( &pCurrentProcess
->crit_section
);
226 if ((handle
> 0) && (handle
<= pCurrentProcess
->handle_table
->count
))
228 HANDLE_ENTRY
*entry
= &pCurrentProcess
->handle_table
->entries
[handle
-1];
229 if ((ptr
= entry
->ptr
))
236 LeaveCriticalSection( &pCurrentProcess
->crit_section
);
237 if (!ret
) SetLastError( ERROR_INVALID_HANDLE
);
238 if (ptr
) K32OBJ_DecCount( ptr
);
243 static int pstr_cmp( const void *ps1
, const void *ps2
)
245 return lstrcmpi32A( *(LPSTR
*)ps1
, *(LPSTR
*)ps2
);
248 /***********************************************************************
251 static BOOL32
PROCESS_FillEnvDB( PDB32
*pdb
, TDB
*pTask
)
255 LPSTR
*pp
, *array
= NULL
;
257 /* Copy the Win16 environment, sorting it in the process */
259 env
= p
= GlobalLock16( pTask
->pdb
.environment
);
260 for (p
= env
; *p
; p
+= strlen(p
) + 1) count
++;
261 pdb
->env_db
->env_size
= (p
- env
) + 1;
262 pdb
->env_db
->environ
= HeapAlloc( pdb
->heap
, 0, pdb
->env_db
->env_size
);
263 if (!pdb
->env_db
->environ
) goto error
;
264 if (!(array
= HeapAlloc( pdb
->heap
, 0, count
* sizeof(array
[0]) )))
266 for (p
= env
, pp
= array
; *p
; p
+= strlen(p
) + 1) *pp
++ = p
;
267 qsort( array
, count
, sizeof(LPSTR
), pstr_cmp
);
268 p
= pdb
->env_db
->environ
;
269 for (pp
= array
; count
; count
--, pp
++)
275 HeapFree( pdb
->heap
, 0, array
);
281 if (array
) HeapFree( pdb
->heap
, 0, array
);
282 if (pdb
->env_db
->environ
) HeapFree( pdb
->heap
, 0, pdb
->env_db
->environ
);
287 /***********************************************************************
290 PDB32
*PROCESS_Create( TDB
*pTask
)
292 PDB32
*pdb
= HeapAlloc( SystemHeap
, HEAP_ZERO_MEMORY
, sizeof(PDB32
) );
293 if (!pdb
) return NULL
;
294 pdb
->header
.type
= K32OBJ_PROCESS
;
295 pdb
->header
.refcount
= 1;
296 pdb
->exit_code
= 0x103; /* STILL_ACTIVE */
298 pdb
->running_threads
= 1;
299 pdb
->ring0_threads
= 1;
300 pdb
->system_heap
= SystemHeap
;
301 pdb
->parent
= pCurrentProcess
;
303 pdb
->priority
= 8; /* Normal */
304 pdb
->heap_list
= pdb
->heap
;
305 InitializeCriticalSection( &pdb
->crit_section
);
306 if (!(pdb
->heap
= HeapCreate( HEAP_GROWABLE
, 0x10000, 0 ))) goto error
;
307 if (!(pdb
->env_db
= HeapAlloc(pdb
->heap
, HEAP_ZERO_MEMORY
, sizeof(ENVDB
))))
309 if (!(pdb
->handle_table
= PROCESS_AllocHandleTable( pdb
))) goto error
;
310 if (!PROCESS_FillEnvDB( pdb
, pTask
)) goto error
;
314 if (pdb
->env_db
) HeapFree( pdb
->heap
, 0, pdb
->env_db
);
315 if (pdb
->handle_table
) HeapFree( pdb
->system_heap
, 0, pdb
->handle_table
);
316 if (pdb
->heap
) HeapDestroy( pdb
->heap
);
317 DeleteCriticalSection( &pdb
->crit_section
);
318 HeapFree( SystemHeap
, 0, pdb
);
323 /***********************************************************************
326 void PROCESS_Destroy( K32OBJ
*ptr
)
328 PDB32
*pdb
= (PDB32
*)ptr
;
330 assert( ptr
->type
== K32OBJ_PROCESS
);
332 /* Close all handles */
333 for (handle
= 0; handle
< pdb
->handle_table
->count
; handle
++)
334 if (pdb
->handle_table
->entries
[handle
].ptr
) CloseHandle( handle
);
336 /* Free everything */
338 ptr
->type
= K32OBJ_UNKNOWN
;
339 HeapFree( pdb
->heap
, 0, pdb
->env_db
);
340 HeapFree( pdb
->system_heap
, 0, pdb
->handle_table
);
341 HeapDestroy( pdb
->heap
);
342 DeleteCriticalSection( &pdb
->crit_section
);
343 HeapFree( SystemHeap
, 0, pdb
);
347 /***********************************************************************
348 * ExitProcess (KERNEL32.100)
350 void ExitProcess( DWORD status
)
352 TASK_KillCurrentTask( status
);
356 /***********************************************************************
357 * GetCurrentProcess (KERNEL32.198)
359 HANDLE32
GetCurrentProcess(void)
365 /***********************************************************************
366 * GetCurrentProcessId (KERNEL32.199)
368 DWORD
GetCurrentProcessId(void)
370 return (DWORD
)pCurrentProcess
;
374 /***********************************************************************
375 * GetEnvironmentStrings32A (KERNEL32.210) (KERNEL32.211)
377 LPSTR
GetEnvironmentStrings32A(void)
379 assert( pCurrentProcess
);
380 return pCurrentProcess
->env_db
->environ
;
384 /***********************************************************************
385 * GetEnvironmentStrings32W (KERNEL32.212)
387 LPWSTR
GetEnvironmentStrings32W(void)
393 assert( pCurrentProcess
);
394 size
= HeapSize( GetProcessHeap(), 0, pCurrentProcess
->env_db
->environ
);
395 if (!(ret
= HeapAlloc( GetProcessHeap(), 0, size
* sizeof(WCHAR
) )))
397 pA
= pCurrentProcess
->env_db
->environ
;
401 lstrcpyAtoW( pW
, pA
);
411 /***********************************************************************
412 * FreeEnvironmentStrings32A (KERNEL32.141)
414 BOOL32
FreeEnvironmentStrings32A( LPSTR ptr
)
416 assert( pCurrentProcess
);
417 if (ptr
!= pCurrentProcess
->env_db
->environ
)
419 SetLastError( ERROR_INVALID_PARAMETER
);
426 /***********************************************************************
427 * FreeEnvironmentStrings32W (KERNEL32.142)
429 BOOL32
FreeEnvironmentStrings32W( LPWSTR ptr
)
431 assert( pCurrentProcess
);
432 return HeapFree( GetProcessHeap(), 0, ptr
);
436 /***********************************************************************
437 * GetEnvironmentVariable32A (KERNEL32.213)
439 DWORD
GetEnvironmentVariable32A( LPCSTR name
, LPSTR value
, DWORD size
)
444 assert( pCurrentProcess
);
445 p
= pCurrentProcess
->env_db
->environ
;
448 SetLastError( ERROR_INVALID_PARAMETER
);
454 res
= lstrncmpi32A( name
, p
, len
);
455 if (res
< 0) goto not_found
;
456 if (!res
&& (p
[len
] == '=')) break;
459 if (!*p
) goto not_found
;
460 if (value
) lstrcpyn32A( value
, p
+ len
+ 1, size
);
463 return 0; /* FIXME: SetLastError */
467 /***********************************************************************
468 * GetEnvironmentVariable32W (KERNEL32.214)
470 DWORD
GetEnvironmentVariable32W( LPCWSTR nameW
, LPWSTR valW
, DWORD size
)
472 LPSTR name
= HEAP_strdupWtoA( GetProcessHeap(), 0, nameW
);
473 LPSTR val
= HeapAlloc( GetProcessHeap(), 0, size
);
474 DWORD res
= GetEnvironmentVariable32A( name
, val
, size
);
475 HeapFree( GetProcessHeap(), 0, name
);
476 if (valW
) lstrcpynAtoW( valW
, val
, size
);
477 HeapFree( GetProcessHeap(), 0, val
);
482 /***********************************************************************
483 * SetEnvironmentVariable32A (KERNEL32.484)
485 BOOL32
SetEnvironmentVariable32A( LPCSTR name
, LPCSTR value
)
487 INT32 size
, len
, res
;
488 LPSTR p
, env
, new_env
;
490 assert( pCurrentProcess
);
491 env
= p
= pCurrentProcess
->env_db
->environ
;
493 /* Find a place to insert the string */
499 res
= lstrncmpi32A( name
, p
, len
);
501 if (!res
&& (p
[len
] == '=')) break;
505 if (!value
&& res
) /* Value to remove doesn't exist already */
508 /* Realloc the buffer */
510 len
= value
? strlen(name
) + strlen(value
) + 2 : 0;
511 if (!res
) len
-= strlen(p
) + 1; /* The name already exists */
512 size
= pCurrentProcess
->env_db
->env_size
+ len
;
513 if (!(new_env
= HeapReAlloc( GetProcessHeap(), 0, env
, size
)))
515 p
= new_env
+ (p
- env
);
517 /* Set the new string */
519 memmove( p
+ len
, p
, pCurrentProcess
->env_db
->env_size
- (p
-new_env
) );
526 pCurrentProcess
->env_db
->env_size
= size
;
527 pCurrentProcess
->env_db
->environ
= new_env
;
532 /***********************************************************************
533 * SetEnvironmentVariable32W (KERNEL32.485)
535 BOOL32
SetEnvironmentVariable32W( LPCWSTR name
, LPCWSTR value
)
537 LPSTR nameA
= HEAP_strdupWtoA( GetProcessHeap(), 0, name
);
538 LPSTR valueA
= HEAP_strdupWtoA( GetProcessHeap(), 0, value
);
539 BOOL32 ret
= SetEnvironmentVariable32A( nameA
, valueA
);
540 HeapFree( GetProcessHeap(), 0, nameA
);
541 HeapFree( GetProcessHeap(), 0, valueA
);
546 /***********************************************************************
547 * ExpandEnvironmentVariablesA (KERNEL32.103)
549 DWORD
ExpandEnvironmentStrings32A( LPCSTR src
, LPSTR dst
, DWORD len
) {
552 HANDLE32 heap
= GetProcessHeap();
553 LPSTR xdst
= HeapAlloc(heap
,0,10);
557 fprintf(stderr
,"ExpandEnvironmentStrings32A(%s)\n",src
);
560 memset(dst
,'\0',len
);
561 #define CHECK_FREE(n) { \
562 DWORD _needed = (n); \
564 while (cursize-(d-xdst)<_needed) { \
565 DWORD ind = d-xdst; \
568 xdst=(LPSTR)HeapReAlloc(heap,0,xdst,cursize);\
577 end
= s
;do { end
++; } while (*end
&& *end
!='%');
579 LPSTR x
= HeapAlloc(heap
,0,end
-s
+1);
582 lstrcpyn32A(x
,s
+1,end
-s
-1);
585 /* put expanded variable directly into
586 * destination string, so we don't have
587 * to use temporary buffers.
589 ret
= GetEnvironmentVariable32A(x
,buf
,2);
591 ret
= GetEnvironmentVariable32A(x
,d
,d
-xdst
);
595 CHECK_FREE(strlen(x
)+2);
612 ret
= lstrlen32A(xdst
)+1;
614 lstrcpy32A(dst
,xdst
);
615 HeapFree(heap
,0,xdst
);
619 /***********************************************************************
620 * ExpandEnvironmentVariablesA (KERNEL32.104)
622 DWORD
ExpandEnvironmentStrings32W( LPCWSTR src
, LPWSTR dst
, DWORD len
) {
623 HANDLE32 heap
= GetProcessHeap();
624 LPSTR srcA
= HEAP_strdupWtoA(heap
,0,src
);
625 LPSTR dstA
= HeapAlloc(heap
,0,len
);
626 DWORD ret
= ExpandEnvironmentStrings32A(srcA
,dstA
,len
);
628 lstrcpyAtoW(dst
,dstA
);
629 HeapFree(heap
,0,dstA
);
630 HeapFree(heap
,0,srcA
);
634 /***********************************************************************
635 * GetProcessHeap (KERNEL32.259)
637 HANDLE32
GetProcessHeap(void)
639 if (!pCurrentProcess
) return SystemHeap
; /* For the boot-up code */
640 return pCurrentProcess
->heap
;
644 /***********************************************************************
645 * GetThreadLocale (KERNEL32.295)
647 LCID
GetThreadLocale(void)
649 return pCurrentProcess
->locale
;
653 /***********************************************************************
654 * SetPriorityClass (KERNEL32.503)
656 BOOL32
SetPriorityClass( HANDLE32 hprocess
, DWORD priorityclass
)
660 pdb
= (PDB32
*)PROCESS_GetObjPtr(hprocess
,K32OBJ_PROCESS
);
661 if (!pdb
) return FALSE
;
662 switch (priorityclass
)
664 case NORMAL_PRIORITY_CLASS
:
665 pdb
->priority
= 0x00000008;
667 case IDLE_PRIORITY_CLASS
:
668 pdb
->priority
= 0x00000004;
670 case HIGH_PRIORITY_CLASS
:
671 pdb
->priority
= 0x0000000d;
673 case REALTIME_PRIORITY_CLASS
:
674 pdb
->priority
= 0x00000018;
677 fprintf(stderr
,"SetPriorityClass: unknown priority class %ld\n",priorityclass
);
680 K32OBJ_DecCount((K32OBJ
*)pdb
);
685 /***********************************************************************
686 * GetPriorityClass (KERNEL32.250)
688 DWORD
GetPriorityClass(HANDLE32 hprocess
)
693 pdb
= (PDB32
*)PROCESS_GetObjPtr(hprocess
,K32OBJ_PROCESS
);
697 switch (pdb
->priority
)
700 ret
= NORMAL_PRIORITY_CLASS
;
703 ret
= IDLE_PRIORITY_CLASS
;
706 ret
= HIGH_PRIORITY_CLASS
;
709 ret
= REALTIME_PRIORITY_CLASS
;
712 fprintf(stderr
,"GetPriorityClass: unknown priority %ld\n",pdb
->priority
);
714 K32OBJ_DecCount((K32OBJ
*)pdb
);
720 /***********************************************************************
721 * GetStdHandle (KERNEL32.276)
723 * FIXME: These should be allocated when a console is created, or inherited
726 HANDLE32
GetStdHandle( DWORD std_handle
)
731 assert( pCurrentProcess
);
734 case STD_INPUT_HANDLE
:
735 if (pCurrentProcess
->env_db
->hStdin
)
736 return pCurrentProcess
->env_db
->hStdin
;
739 case STD_OUTPUT_HANDLE
:
740 if (pCurrentProcess
->env_db
->hStdout
)
741 return pCurrentProcess
->env_db
->hStdout
;
744 case STD_ERROR_HANDLE
:
745 if (pCurrentProcess
->env_db
->hStderr
)
746 return pCurrentProcess
->env_db
->hStderr
;
750 SetLastError( ERROR_INVALID_PARAMETER
);
751 return INVALID_HANDLE_VALUE32
;
753 hFile
= FILE_DupUnixHandle( fd
);
754 if (hFile
!= HFILE_ERROR32
)
756 FILE_SetFileType( hFile
, FILE_TYPE_CHAR
);
759 case STD_INPUT_HANDLE
: pCurrentProcess
->env_db
->hStdin
=hFile
; break;
760 case STD_OUTPUT_HANDLE
: pCurrentProcess
->env_db
->hStdout
=hFile
; break;
761 case STD_ERROR_HANDLE
: pCurrentProcess
->env_db
->hStderr
=hFile
; break;
768 /***********************************************************************
769 * SetStdHandle (KERNEL32.506)
771 BOOL32
SetStdHandle( DWORD std_handle
, HANDLE32 handle
)
773 assert( pCurrentProcess
);
776 case STD_INPUT_HANDLE
:
777 pCurrentProcess
->env_db
->hStdin
= handle
;
779 case STD_OUTPUT_HANDLE
:
780 pCurrentProcess
->env_db
->hStdout
= handle
;
782 case STD_ERROR_HANDLE
:
783 pCurrentProcess
->env_db
->hStderr
= handle
;
786 SetLastError( ERROR_INVALID_PARAMETER
);