2 * Win32 process handles
4 * Copyright 1998 Alexandre Julliard
17 #define HTABLE_SIZE 0x30 /* Handle table initial size */
18 #define HTABLE_INC 0x10 /* Handle table increment */
20 /* Reserved access rights */
21 #define RESERVED_ALL (0x0007 << RESERVED_SHIFT)
22 #define RESERVED_SHIFT 25
23 #define RESERVED_INHERIT (HANDLE_FLAG_INHERIT<<RESERVED_SHIFT)
24 #define RESERVED_CLOSE_PROTECT (HANDLE_FLAG_PROTECT_FROM_CLOSE<<RESERVED_SHIFT)
27 /***********************************************************************
30 static BOOL32
HANDLE_GrowTable( PDB32
*process
, INT32 incr
)
35 table
= process
->handle_table
;
36 table
= HeapReAlloc( process
->system_heap
,
37 HEAP_ZERO_MEMORY
| HEAP_NO_SERIALIZE
, table
,
38 sizeof(HANDLE_TABLE
) +
39 (table
->count
+ incr
- 1) * sizeof(HANDLE_ENTRY
) );
43 process
->handle_table
= table
;
46 return (table
!= NULL
);
50 /***********************************************************************
53 * Create a process handle table, optionally inheriting the parent's handles.
55 BOOL32
HANDLE_CreateTable( PDB32
*pdb
, BOOL32 inherit
)
59 /* Process must not already have a handle table */
60 assert( !pdb
->handle_table
);
62 /* If this is the first process, simply allocate a table */
63 if (!pdb
->parent
) inherit
= FALSE
;
66 size
= inherit
? pdb
->parent
->handle_table
->count
: HTABLE_SIZE
;
67 if ((pdb
->handle_table
= HeapAlloc( pdb
->system_heap
,
68 HEAP_ZERO_MEMORY
| HEAP_NO_SERIALIZE
,
69 sizeof(HANDLE_TABLE
) +
70 (size
-1) * sizeof(HANDLE_ENTRY
) )))
72 pdb
->handle_table
->count
= size
;
75 HANDLE_ENTRY
*src
= pdb
->parent
->handle_table
->entries
;
76 HANDLE_ENTRY
*dst
= pdb
->handle_table
->entries
;
79 for (h
= 0; h
< size
; h
++, src
++, dst
++)
81 /* Check if handle is valid and inheritable */
82 if (src
->ptr
&& (src
->access
& RESERVED_INHERIT
))
84 dst
->access
= src
->access
;
86 dst
->server
= src
->server
;
87 K32OBJ_IncCount( dst
->ptr
);
91 /* Handle 1 is the process itself (unless the parent decided otherwise) */
92 if (!pdb
->handle_table
->entries
[1].ptr
)
94 pdb
->handle_table
->entries
[1].ptr
= &pdb
->header
;
95 pdb
->handle_table
->entries
[1].access
= PROCESS_ALL_ACCESS
;
96 pdb
->handle_table
->entries
[1].server
= -1; /* FIXME */
97 K32OBJ_IncCount( &pdb
->header
);
101 return (pdb
->handle_table
!= NULL
);
105 /***********************************************************************
108 * Allocate a handle for a kernel object and increment its refcount.
110 HANDLE32
HANDLE_Alloc( PDB32
*pdb
, K32OBJ
*ptr
, DWORD access
,
111 BOOL32 inherit
, int server_handle
)
118 /* Set the inherit reserved flag */
119 access
&= ~RESERVED_ALL
;
120 if (inherit
) access
|= RESERVED_INHERIT
;
123 K32OBJ_IncCount( ptr
);
124 /* Don't try to allocate handle 0 */
125 entry
= pdb
->handle_table
->entries
+ 1;
126 for (h
= 1; h
< pdb
->handle_table
->count
; h
++, entry
++)
127 if (!entry
->ptr
) break;
128 if ((h
< pdb
->handle_table
->count
) || HANDLE_GrowTable( pdb
, HTABLE_INC
))
130 entry
= &pdb
->handle_table
->entries
[h
];
131 entry
->access
= access
;
133 entry
->server
= server_handle
;
137 K32OBJ_DecCount( ptr
);
139 if (server_handle
!= -1) CLIENT_CloseHandle( server_handle
);
140 SetLastError( ERROR_OUTOFMEMORY
);
141 return INVALID_HANDLE_VALUE32
;
145 /***********************************************************************
148 * Retrieve a pointer to a kernel object and increments its reference count.
149 * The refcount must be decremented when the pointer is no longer used.
151 K32OBJ
*HANDLE_GetObjPtr( PDB32
*pdb
, HANDLE32 handle
,
152 K32OBJ_TYPE type
, DWORD access
,
158 if (HANDLE_IS_GLOBAL( handle
))
160 handle
= HANDLE_GLOBAL_TO_LOCAL( handle
);
161 pdb
= PROCESS_Initial();
163 if ((handle
> 0) && (handle
< pdb
->handle_table
->count
))
165 HANDLE_ENTRY
*entry
= &pdb
->handle_table
->entries
[handle
];
166 if ((entry
->access
& access
) != access
)
167 WARN(win32
, "Handle %08x bad access (acc=%08lx req=%08lx)\n",
168 handle
, entry
->access
, access
);
170 if (server_handle
) *server_handle
= entry
->server
;
172 else if (handle
== CURRENT_THREAD_PSEUDOHANDLE
)
174 ptr
= (K32OBJ
*)THREAD_Current();
175 if (server_handle
) *server_handle
= CURRENT_THREAD_PSEUDOHANDLE
;
177 else if (handle
== CURRENT_PROCESS_PSEUDOHANDLE
)
179 ptr
= (K32OBJ
*)PROCESS_Current();
180 if (server_handle
) *server_handle
= CURRENT_PROCESS_PSEUDOHANDLE
;
183 if (ptr
&& ((type
== K32OBJ_UNKNOWN
) || (ptr
->type
== type
)))
184 K32OBJ_IncCount( ptr
);
189 if (!ptr
) SetLastError( ERROR_INVALID_HANDLE
);
194 /***********************************************************************
197 * Change the object pointer of a handle, and increment the refcount.
200 BOOL32
HANDLE_SetObjPtr( PDB32
*pdb
, HANDLE32 handle
, K32OBJ
*ptr
,
206 if ((handle
> 0) && (handle
< pdb
->handle_table
->count
))
208 HANDLE_ENTRY
*entry
= &pdb
->handle_table
->entries
[handle
];
209 K32OBJ
*old_ptr
= entry
->ptr
;
210 K32OBJ_IncCount( ptr
);
211 entry
->access
= access
;
213 if (old_ptr
) K32OBJ_DecCount( old_ptr
);
217 if (!ret
) SetLastError( ERROR_INVALID_HANDLE
);
222 /*********************************************************************
225 static BOOL32
HANDLE_GetAccess( PDB32
*pdb
, HANDLE32 handle
, LPDWORD access
)
230 if ((handle
> 0) && (handle
< pdb
->handle_table
->count
))
232 HANDLE_ENTRY
*entry
= &pdb
->handle_table
->entries
[handle
];
235 *access
= entry
->access
& ~RESERVED_ALL
;
240 if (!ret
) SetLastError( ERROR_INVALID_HANDLE
);
245 /*********************************************************************
248 static BOOL32
HANDLE_Close( PDB32
*pdb
, HANDLE32 handle
)
254 if ((handle
> 0) && (handle
< pdb
->handle_table
->count
))
256 HANDLE_ENTRY
*entry
= &pdb
->handle_table
->entries
[handle
];
257 if ((ptr
= entry
->ptr
))
259 if (!(entry
->access
& RESERVED_CLOSE_PROTECT
))
263 if (entry
->server
!= -1)
264 CLIENT_CloseHandle( entry
->server
);
265 K32OBJ_DecCount( ptr
);
268 /* FIXME: else SetLastError */
272 if (!ret
) SetLastError( ERROR_INVALID_HANDLE
);
277 /*********************************************************************
280 * Close all handles pointing to a given object (or all handles of the
281 * process if the object is NULL)
283 void HANDLE_CloseAll( PDB32
*pdb
, K32OBJ
*obj
)
290 entry
= pdb
->handle_table
->entries
;
291 for (handle
= 0; handle
< pdb
->handle_table
->count
; handle
++, entry
++)
293 if (!(ptr
= entry
->ptr
)) continue; /* empty slot */
294 if (obj
&& (ptr
!= obj
)) continue; /* not the right object */
297 if (entry
->server
!= -1) CLIENT_CloseHandle( entry
->server
);
298 K32OBJ_DecCount( ptr
);
304 /*********************************************************************
305 * CloseHandle (KERNEL32.23)
307 BOOL32 WINAPI
CloseHandle( HANDLE32 handle
)
309 return HANDLE_Close( PROCESS_Current(), handle
);
313 /*********************************************************************
314 * GetHandleInformation (KERNEL32.336)
316 BOOL32 WINAPI
GetHandleInformation( HANDLE32 handle
, LPDWORD flags
)
319 PDB32
*pdb
= PROCESS_Current();
322 if ((handle
> 0) && (handle
< pdb
->handle_table
->count
))
324 HANDLE_ENTRY
*entry
= &pdb
->handle_table
->entries
[handle
];
328 *flags
= (entry
->access
& RESERVED_ALL
) >> RESERVED_SHIFT
;
333 if (!ret
) SetLastError( ERROR_INVALID_HANDLE
);
338 /*********************************************************************
339 * SetHandleInformation (KERNEL32.653)
341 BOOL32 WINAPI
SetHandleInformation( HANDLE32 handle
, DWORD mask
, DWORD flags
)
344 PDB32
*pdb
= PROCESS_Current();
346 mask
= (mask
<< RESERVED_SHIFT
) & RESERVED_ALL
;
347 flags
= (flags
<< RESERVED_SHIFT
) & RESERVED_ALL
;
349 if ((handle
> 0) && (handle
< pdb
->handle_table
->count
))
351 HANDLE_ENTRY
*entry
= &pdb
->handle_table
->entries
[handle
];
354 entry
->access
= (entry
->access
& ~mask
) | flags
;
359 if (!ret
) SetLastError( ERROR_INVALID_HANDLE
);
364 /*********************************************************************
365 * DuplicateHandle (KERNEL32.192)
367 BOOL32 WINAPI
DuplicateHandle( HANDLE32 source_process
, HANDLE32 source
,
368 HANDLE32 dest_process
, HANDLE32
*dest
,
369 DWORD access
, BOOL32 inherit
, DWORD options
)
371 PDB32
*src_pdb
= NULL
, *dst_pdb
= NULL
;
375 int src_process
, src_handle
, dst_process
, dst_handle
;
379 if (!(src_pdb
= PROCESS_GetPtr( source_process
, PROCESS_DUP_HANDLE
, &src_process
)))
381 if (!(obj
= HANDLE_GetObjPtr( src_pdb
, source
, K32OBJ_UNKNOWN
, 0, &src_handle
)))
384 /* Now that we are sure the source is valid, handle the options */
386 if (options
& DUPLICATE_SAME_ACCESS
)
387 HANDLE_GetAccess( src_pdb
, source
, &access
);
388 if (options
& DUPLICATE_CLOSE_SOURCE
)
389 HANDLE_Close( src_pdb
, source
);
391 /* And duplicate the handle in the dest process */
393 if (!(dst_pdb
= PROCESS_GetPtr( dest_process
, PROCESS_DUP_HANDLE
, &dst_process
)))
396 if ((src_process
!= -1) && (src_handle
!= -1) && (dst_process
!= -1))
397 dst_handle
= CLIENT_DuplicateHandle( src_process
, src_handle
, dst_process
, -1,
398 access
, inherit
, options
);
402 if ((handle
= HANDLE_Alloc( dst_pdb
, obj
, access
, inherit
,
403 dst_handle
)) != INVALID_HANDLE_VALUE32
)
405 if (dest
) *dest
= handle
;
410 if (dst_pdb
) K32OBJ_DecCount( &dst_pdb
->header
);
411 if (obj
) K32OBJ_DecCount( obj
);
412 if (src_pdb
) K32OBJ_DecCount( &src_pdb
->header
);