2 * Win32 process handles
4 * Copyright 1998 Alexandre Julliard
15 #define HTABLE_SIZE 0x30 /* Handle table initial size */
16 #define HTABLE_INC 0x10 /* Handle table increment */
18 /* Reserved access rights */
19 #define RESERVED_ALL (0x0007 << RESERVED_SHIFT)
20 #define RESERVED_SHIFT 25
21 #define RESERVED_INHERIT (HANDLE_FLAG_INHERIT<<RESERVED_SHIFT)
22 #define RESERVED_CLOSE_PROTECT (HANDLE_FLAG_PROTECT_FROM_CLOSE<<RESERVED_SHIFT)
25 /***********************************************************************
28 static BOOL32 HANDLE_GrowTable( PDB32 *process, INT32 incr )
33 table = process->handle_table;
34 table = HeapReAlloc( process->system_heap,
35 HEAP_ZERO_MEMORY | HEAP_NO_SERIALIZE, table,
36 sizeof(HANDLE_TABLE) +
37 (table->count + incr - 1) * sizeof(HANDLE_ENTRY) );
41 process->handle_table = table;
44 return (table != NULL);
48 /***********************************************************************
51 * Create a process handle table, optionally inheriting the parent's handles.
53 BOOL32 HANDLE_CreateTable( PDB32 *pdb, BOOL32 inherit )
57 /* Process must not already have a handle table */
58 assert( !pdb->handle_table );
60 /* If this is the first process, simply allocate a table */
61 if (!pdb->parent) inherit = FALSE;
64 size = inherit ? pdb->parent->handle_table->count : HTABLE_SIZE;
65 if ((pdb->handle_table = HeapAlloc( pdb->system_heap,
66 HEAP_ZERO_MEMORY | HEAP_NO_SERIALIZE,
67 sizeof(HANDLE_TABLE) +
68 (size-1) * sizeof(HANDLE_ENTRY) )))
70 pdb->handle_table->count = size;
73 HANDLE_ENTRY *src = pdb->parent->handle_table->entries;
74 HANDLE_ENTRY *dst = pdb->handle_table->entries;
77 for (h = 0; h < size; h++, src++, dst++)
79 /* Check if handle is valid and inheritable */
80 if (src->ptr && (src->access & RESERVED_INHERIT))
82 dst->access = src->access;
84 K32OBJ_IncCount( dst->ptr );
88 /* Handle 1 is the process itself (unless the parent decided otherwise) */
89 if (!pdb->handle_table->entries[1].ptr)
91 pdb->handle_table->entries[1].ptr = &pdb->header;
92 pdb->handle_table->entries[1].access = PROCESS_ALL_ACCESS;
93 K32OBJ_IncCount( &pdb->header );
97 return (pdb->handle_table != NULL);
101 /***********************************************************************
104 * Allocate a handle for a kernel object and increment its refcount.
106 HANDLE32 HANDLE_Alloc( PDB32 *pdb, K32OBJ *ptr, DWORD access, BOOL32 inherit )
113 /* Set the inherit reserved flag */
114 access &= ~RESERVED_ALL;
115 if (inherit) access |= RESERVED_INHERIT;
118 K32OBJ_IncCount( ptr );
119 /* Don't try to allocate handle 0 */
120 entry = pdb->handle_table->entries + 1;
121 for (h = 1; h < pdb->handle_table->count; h++, entry++)
122 if (!entry->ptr) break;
123 if ((h < pdb->handle_table->count) || HANDLE_GrowTable( pdb, HTABLE_INC ))
125 entry = &pdb->handle_table->entries[h];
126 entry->access = access;
131 K32OBJ_DecCount( ptr );
133 SetLastError( ERROR_OUTOFMEMORY );
134 return INVALID_HANDLE_VALUE32;
138 /***********************************************************************
141 * Retrieve a pointer to a kernel object and increments its reference count.
142 * The refcount must be decremented when the pointer is no longer used.
144 K32OBJ *HANDLE_GetObjPtr( PDB32 *pdb, HANDLE32 handle,
145 K32OBJ_TYPE type, DWORD access )
150 if ((handle > 0) && (handle <= pdb->handle_table->count))
152 HANDLE_ENTRY *entry = &pdb->handle_table->entries[handle];
153 if ((entry->access & access) != access)
154 WARN(win32, "Handle %08x bad access (acc=%08lx req=%08lx)\n",
155 handle, entry->access, access );
157 if (ptr && ((type == K32OBJ_UNKNOWN) || (ptr->type == type)))
158 K32OBJ_IncCount( ptr );
163 if (!ptr) SetLastError( ERROR_INVALID_HANDLE );
168 /***********************************************************************
171 * Change the object pointer of a handle, and increment the refcount.
174 BOOL32 HANDLE_SetObjPtr( PDB32 *pdb, HANDLE32 handle, K32OBJ *ptr,
180 if ((handle > 0) && (handle <= pdb->handle_table->count))
182 HANDLE_ENTRY *entry = &pdb->handle_table->entries[handle];
183 K32OBJ *old_ptr = entry->ptr;
184 K32OBJ_IncCount( ptr );
185 entry->access = access;
187 if (old_ptr) K32OBJ_DecCount( old_ptr );
191 if (!ret) SetLastError( ERROR_INVALID_HANDLE );
196 /*********************************************************************
199 static BOOL32 HANDLE_GetAccess( PDB32 *pdb, HANDLE32 handle, LPDWORD access )
204 if ((handle > 0) && (handle <= pdb->handle_table->count))
206 HANDLE_ENTRY *entry = &pdb->handle_table->entries[handle];
209 *access = entry->access & ~RESERVED_ALL;
214 if (!ret) SetLastError( ERROR_INVALID_HANDLE );
219 /*********************************************************************
222 static BOOL32 HANDLE_Close( PDB32 *pdb, HANDLE32 handle )
228 if ((handle > 0) && (handle <= pdb->handle_table->count))
230 HANDLE_ENTRY *entry = &pdb->handle_table->entries[handle];
231 if ((ptr = entry->ptr))
233 if (!(entry->access & RESERVED_CLOSE_PROTECT))
237 K32OBJ_DecCount( ptr );
240 /* FIXME: else SetLastError */
244 if (!ret) SetLastError( ERROR_INVALID_HANDLE );
249 /*********************************************************************
252 * Close all handles pointing to a given object (or all handles of the
253 * process if the object is NULL)
255 void HANDLE_CloseAll( PDB32 *pdb, K32OBJ *obj )
262 entry = pdb->handle_table->entries;
263 for (handle = 0; handle < pdb->handle_table->count; handle++, entry++)
265 if (!(ptr = entry->ptr)) continue; /* empty slot */
266 if (obj && (ptr != obj)) continue; /* not the right object */
269 K32OBJ_DecCount( ptr );
275 /*********************************************************************
276 * CloseHandle (KERNEL32.23)
278 BOOL32 WINAPI CloseHandle( HANDLE32 handle )
280 return HANDLE_Close( PROCESS_Current(), handle );
284 /*********************************************************************
285 * GetHandleInformation (KERNEL32.336)
287 BOOL32 WINAPI GetHandleInformation( HANDLE32 handle, LPDWORD flags )
290 PDB32 *pdb = PROCESS_Current();
293 if ((handle > 0) && (handle <= pdb->handle_table->count))
295 HANDLE_ENTRY *entry = &pdb->handle_table->entries[handle];
299 *flags = (entry->access & RESERVED_ALL) >> RESERVED_SHIFT;
304 if (!ret) SetLastError( ERROR_INVALID_HANDLE );
309 /*********************************************************************
310 * SetHandleInformation (KERNEL32.653)
312 BOOL32 WINAPI SetHandleInformation( HANDLE32 handle, DWORD mask, DWORD flags )
315 PDB32 *pdb = PROCESS_Current();
317 mask = (mask << RESERVED_SHIFT) & RESERVED_ALL;
318 flags = (flags << RESERVED_SHIFT) & RESERVED_ALL;
320 if ((handle > 0) && (handle <= pdb->handle_table->count))
322 HANDLE_ENTRY *entry = &pdb->handle_table->entries[handle];
325 entry->access = (entry->access & ~mask) | flags;
330 if (!ret) SetLastError( ERROR_INVALID_HANDLE );
335 /*********************************************************************
336 * DuplicateHandle (KERNEL32.192)
338 BOOL32 WINAPI DuplicateHandle( HANDLE32 source_process, HANDLE32 source,
339 HANDLE32 dest_process, HANDLE32 *dest,
340 DWORD access, BOOL32 inherit, DWORD options )
342 PDB32 *src_pdb = NULL, *dst_pdb = NULL;
349 if (!(src_pdb = PROCESS_GetPtr( source_process, PROCESS_DUP_HANDLE )))
351 if (!(obj = HANDLE_GetObjPtr( src_pdb, source, K32OBJ_UNKNOWN, 0 )))
354 /* Now that we are sure the source is valid, handle the options */
356 if (options & DUPLICATE_CLOSE_SOURCE)
357 HANDLE_Close( src_pdb, source );
358 if (options & DUPLICATE_SAME_ACCESS)
359 HANDLE_GetAccess( src_pdb, source, &access );
361 /* And duplicate the handle in the dest process */
363 if (!(dst_pdb = PROCESS_GetPtr( dest_process, PROCESS_DUP_HANDLE )))
365 if ((handle = HANDLE_Alloc( dst_pdb, obj,
366 access, inherit )) != INVALID_HANDLE_VALUE32)
368 if (dest) *dest = handle;
373 if (dst_pdb) K32OBJ_DecCount( &dst_pdb->header );
374 if (obj) K32OBJ_DecCount( obj );
375 if (src_pdb) K32OBJ_DecCount( &src_pdb->header );