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
> 0) && (handle
<= pdb
->handle_table
->count
))
160 HANDLE_ENTRY
*entry
= &pdb
->handle_table
->entries
[handle
];
161 if ((entry
->access
& access
) != access
)
162 WARN(win32
, "Handle %08x bad access (acc=%08lx req=%08lx)\n",
163 handle
, entry
->access
, access
);
165 if (server_handle
) *server_handle
= entry
->server
;
167 else if (handle
== CURRENT_THREAD_PSEUDOHANDLE
)
169 ptr
= (K32OBJ
*)THREAD_Current();
170 if (server_handle
) *server_handle
= CURRENT_THREAD_PSEUDOHANDLE
;
172 else if (handle
== CURRENT_PROCESS_PSEUDOHANDLE
)
174 ptr
= (K32OBJ
*)PROCESS_Current();
175 if (server_handle
) *server_handle
= CURRENT_PROCESS_PSEUDOHANDLE
;
178 if (ptr
&& ((type
== K32OBJ_UNKNOWN
) || (ptr
->type
== type
)))
179 K32OBJ_IncCount( ptr
);
184 if (!ptr
) SetLastError( ERROR_INVALID_HANDLE
);
189 /***********************************************************************
192 * Change the object pointer of a handle, and increment the refcount.
195 BOOL32
HANDLE_SetObjPtr( PDB32
*pdb
, HANDLE32 handle
, K32OBJ
*ptr
,
201 if ((handle
> 0) && (handle
<= pdb
->handle_table
->count
))
203 HANDLE_ENTRY
*entry
= &pdb
->handle_table
->entries
[handle
];
204 K32OBJ
*old_ptr
= entry
->ptr
;
205 K32OBJ_IncCount( ptr
);
206 entry
->access
= access
;
208 if (old_ptr
) K32OBJ_DecCount( old_ptr
);
212 if (!ret
) SetLastError( ERROR_INVALID_HANDLE
);
217 /*********************************************************************
220 static BOOL32
HANDLE_GetAccess( PDB32
*pdb
, HANDLE32 handle
, LPDWORD access
)
225 if ((handle
> 0) && (handle
<= pdb
->handle_table
->count
))
227 HANDLE_ENTRY
*entry
= &pdb
->handle_table
->entries
[handle
];
230 *access
= entry
->access
& ~RESERVED_ALL
;
235 if (!ret
) SetLastError( ERROR_INVALID_HANDLE
);
240 /*********************************************************************
243 static BOOL32
HANDLE_Close( PDB32
*pdb
, HANDLE32 handle
)
249 if ((handle
> 0) && (handle
<= pdb
->handle_table
->count
))
251 HANDLE_ENTRY
*entry
= &pdb
->handle_table
->entries
[handle
];
252 if ((ptr
= entry
->ptr
))
254 if (!(entry
->access
& RESERVED_CLOSE_PROTECT
))
258 if (entry
->server
!= -1)
259 CLIENT_CloseHandle( entry
->server
);
260 K32OBJ_DecCount( ptr
);
263 /* FIXME: else SetLastError */
267 if (!ret
) SetLastError( ERROR_INVALID_HANDLE
);
272 /*********************************************************************
275 * Close all handles pointing to a given object (or all handles of the
276 * process if the object is NULL)
278 void HANDLE_CloseAll( PDB32
*pdb
, K32OBJ
*obj
)
285 entry
= pdb
->handle_table
->entries
;
286 for (handle
= 0; handle
< pdb
->handle_table
->count
; handle
++, entry
++)
288 if (!(ptr
= entry
->ptr
)) continue; /* empty slot */
289 if (obj
&& (ptr
!= obj
)) continue; /* not the right object */
292 if (entry
->server
!= -1) CLIENT_CloseHandle( entry
->server
);
293 K32OBJ_DecCount( ptr
);
299 /*********************************************************************
300 * CloseHandle (KERNEL32.23)
302 BOOL32 WINAPI
CloseHandle( HANDLE32 handle
)
304 return HANDLE_Close( PROCESS_Current(), handle
);
308 /*********************************************************************
309 * GetHandleInformation (KERNEL32.336)
311 BOOL32 WINAPI
GetHandleInformation( HANDLE32 handle
, LPDWORD flags
)
314 PDB32
*pdb
= PROCESS_Current();
317 if ((handle
> 0) && (handle
<= pdb
->handle_table
->count
))
319 HANDLE_ENTRY
*entry
= &pdb
->handle_table
->entries
[handle
];
323 *flags
= (entry
->access
& RESERVED_ALL
) >> RESERVED_SHIFT
;
328 if (!ret
) SetLastError( ERROR_INVALID_HANDLE
);
333 /*********************************************************************
334 * SetHandleInformation (KERNEL32.653)
336 BOOL32 WINAPI
SetHandleInformation( HANDLE32 handle
, DWORD mask
, DWORD flags
)
339 PDB32
*pdb
= PROCESS_Current();
341 mask
= (mask
<< RESERVED_SHIFT
) & RESERVED_ALL
;
342 flags
= (flags
<< RESERVED_SHIFT
) & RESERVED_ALL
;
344 if ((handle
> 0) && (handle
<= pdb
->handle_table
->count
))
346 HANDLE_ENTRY
*entry
= &pdb
->handle_table
->entries
[handle
];
349 entry
->access
= (entry
->access
& ~mask
) | flags
;
354 if (!ret
) SetLastError( ERROR_INVALID_HANDLE
);
359 /*********************************************************************
360 * DuplicateHandle (KERNEL32.192)
362 BOOL32 WINAPI
DuplicateHandle( HANDLE32 source_process
, HANDLE32 source
,
363 HANDLE32 dest_process
, HANDLE32
*dest
,
364 DWORD access
, BOOL32 inherit
, DWORD options
)
366 PDB32
*src_pdb
= NULL
, *dst_pdb
= NULL
;
370 int src_process
, src_handle
, dst_process
, dst_handle
;
374 if (!(src_pdb
= PROCESS_GetPtr( source_process
, PROCESS_DUP_HANDLE
, &src_process
)))
376 if (!(obj
= HANDLE_GetObjPtr( src_pdb
, source
, K32OBJ_UNKNOWN
, 0, &src_handle
)))
379 /* Now that we are sure the source is valid, handle the options */
381 if (options
& DUPLICATE_SAME_ACCESS
)
382 HANDLE_GetAccess( src_pdb
, source
, &access
);
383 if (options
& DUPLICATE_CLOSE_SOURCE
)
384 HANDLE_Close( src_pdb
, source
);
386 /* And duplicate the handle in the dest process */
388 if (!(dst_pdb
= PROCESS_GetPtr( dest_process
, PROCESS_DUP_HANDLE
, &dst_process
)))
391 if ((src_process
!= -1) && (src_handle
!= -1) && (dst_process
!= -1))
392 dst_handle
= CLIENT_DuplicateHandle( src_process
, src_handle
, dst_process
, -1,
393 access
, inherit
, options
);
397 if ((handle
= HANDLE_Alloc( dst_pdb
, obj
, access
, inherit
,
398 dst_handle
)) != INVALID_HANDLE_VALUE32
)
400 if (dest
) *dest
= handle
;
405 if (dst_pdb
) K32OBJ_DecCount( &dst_pdb
->header
);
406 if (obj
) K32OBJ_DecCount( obj
);
407 if (src_pdb
) K32OBJ_DecCount( &src_pdb
->header
);