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 /***********************************************************************
195 * HANDLE_GetServerHandle
197 * Retrieve the server handle associated to an object.
199 int HANDLE_GetServerHandle( PDB32
*pdb
, HANDLE32 handle
,
200 K32OBJ_TYPE type
, DWORD access
)
206 if ((obj
= HANDLE_GetObjPtr( pdb
, handle
, type
, access
, &server_handle
)))
207 K32OBJ_DecCount( obj
);
211 return server_handle
;
215 /*********************************************************************
218 static BOOL32
HANDLE_GetAccess( PDB32
*pdb
, HANDLE32 handle
, LPDWORD access
)
223 if ((handle
> 0) && (handle
< pdb
->handle_table
->count
))
225 HANDLE_ENTRY
*entry
= &pdb
->handle_table
->entries
[handle
];
228 *access
= entry
->access
& ~RESERVED_ALL
;
233 if (!ret
) SetLastError( ERROR_INVALID_HANDLE
);
238 /*********************************************************************
241 static BOOL32
HANDLE_Close( PDB32
*pdb
, HANDLE32 handle
)
246 if (HANDLE_IS_GLOBAL( handle
))
248 handle
= HANDLE_GLOBAL_TO_LOCAL( handle
);
249 pdb
= PROCESS_Initial();
252 if ((handle
> 0) && (handle
< pdb
->handle_table
->count
))
254 HANDLE_ENTRY
*entry
= &pdb
->handle_table
->entries
[handle
];
255 if ((ptr
= entry
->ptr
))
257 if (!(entry
->access
& RESERVED_CLOSE_PROTECT
))
261 if (entry
->server
!= -1)
262 CLIENT_CloseHandle( entry
->server
);
263 K32OBJ_DecCount( ptr
);
266 /* FIXME: else SetLastError */
270 if (!ret
) SetLastError( ERROR_INVALID_HANDLE
);
275 /*********************************************************************
278 * Close all handles pointing to a given object (or all handles of the
279 * process if the object is NULL)
281 void HANDLE_CloseAll( PDB32
*pdb
, K32OBJ
*obj
)
288 entry
= pdb
->handle_table
->entries
;
289 for (handle
= 0; handle
< pdb
->handle_table
->count
; handle
++, entry
++)
291 if (!(ptr
= entry
->ptr
)) continue; /* empty slot */
292 if (obj
&& (ptr
!= obj
)) continue; /* not the right object */
295 if (entry
->server
!= -1) CLIENT_CloseHandle( entry
->server
);
296 K32OBJ_DecCount( ptr
);
302 /*********************************************************************
303 * CloseHandle (KERNEL32.23)
305 BOOL32 WINAPI
CloseHandle( HANDLE32 handle
)
307 return HANDLE_Close( PROCESS_Current(), handle
);
311 /*********************************************************************
312 * GetHandleInformation (KERNEL32.336)
314 BOOL32 WINAPI
GetHandleInformation( HANDLE32 handle
, LPDWORD flags
)
317 PDB32
*pdb
= PROCESS_Current();
320 if ((handle
> 0) && (handle
< pdb
->handle_table
->count
))
322 HANDLE_ENTRY
*entry
= &pdb
->handle_table
->entries
[handle
];
326 *flags
= (entry
->access
& RESERVED_ALL
) >> RESERVED_SHIFT
;
331 if (!ret
) SetLastError( ERROR_INVALID_HANDLE
);
336 /*********************************************************************
337 * SetHandleInformation (KERNEL32.653)
339 BOOL32 WINAPI
SetHandleInformation( HANDLE32 handle
, DWORD mask
, DWORD flags
)
342 PDB32
*pdb
= PROCESS_Current();
344 mask
= (mask
<< RESERVED_SHIFT
) & RESERVED_ALL
;
345 flags
= (flags
<< RESERVED_SHIFT
) & RESERVED_ALL
;
347 if ((handle
> 0) && (handle
< pdb
->handle_table
->count
))
349 HANDLE_ENTRY
*entry
= &pdb
->handle_table
->entries
[handle
];
352 entry
->access
= (entry
->access
& ~mask
) | flags
;
357 if (!ret
) SetLastError( ERROR_INVALID_HANDLE
);
362 /*********************************************************************
363 * DuplicateHandle (KERNEL32.192)
365 BOOL32 WINAPI
DuplicateHandle( HANDLE32 source_process
, HANDLE32 source
,
366 HANDLE32 dest_process
, HANDLE32
*dest
,
367 DWORD access
, BOOL32 inherit
, DWORD options
)
369 PDB32
*src_pdb
= NULL
, *dst_pdb
= NULL
;
373 int src_process
, src_handle
, dst_process
, dst_handle
;
377 if (!(src_pdb
= PROCESS_GetPtr( source_process
, PROCESS_DUP_HANDLE
, &src_process
)))
379 if (!(obj
= HANDLE_GetObjPtr( src_pdb
, source
, K32OBJ_UNKNOWN
, 0, &src_handle
)))
382 /* Now that we are sure the source is valid, handle the options */
384 if (options
& DUPLICATE_SAME_ACCESS
)
385 HANDLE_GetAccess( src_pdb
, source
, &access
);
386 if (options
& DUPLICATE_CLOSE_SOURCE
)
387 HANDLE_Close( src_pdb
, source
);
389 /* And duplicate the handle in the dest process */
391 if (!(dst_pdb
= PROCESS_GetPtr( dest_process
, PROCESS_DUP_HANDLE
, &dst_process
)))
394 if ((src_process
!= -1) && (src_handle
!= -1) && (dst_process
!= -1))
395 dst_handle
= CLIENT_DuplicateHandle( src_process
, src_handle
, dst_process
, -1,
396 access
, inherit
, options
);
400 if ((handle
= HANDLE_Alloc( dst_pdb
, obj
, access
, inherit
,
401 dst_handle
)) != INVALID_HANDLE_VALUE32
)
403 if (dest
) *dest
= handle
;
408 if (dst_pdb
) K32OBJ_DecCount( &dst_pdb
->header
);
409 if (obj
) K32OBJ_DecCount( obj
);
410 if (src_pdb
) K32OBJ_DecCount( &src_pdb
->header
);
416 /***********************************************************************
417 * ConvertToGlobalHandle (KERNEL32)
419 HANDLE32 WINAPI
ConvertToGlobalHandle(HANDLE32 hSrc
)
421 int src_handle
, dst_handle
;
426 if (HANDLE_IS_GLOBAL(hSrc
))
429 if (!(obj
= HANDLE_GetObjPtr( PROCESS_Current(), hSrc
, K32OBJ_UNKNOWN
, 0, &src_handle
)))
432 HANDLE_GetAccess( PROCESS_Current(), hSrc
, &access
);
434 if (src_handle
!= -1)
435 dst_handle
= CLIENT_DuplicateHandle( GetCurrentProcess(), src_handle
, -1, -1, 0, FALSE
,
436 DUP_HANDLE_MAKE_GLOBAL
| DUP_HANDLE_SAME_ACCESS
);
440 if ((handle
= HANDLE_Alloc( PROCESS_Initial(), obj
, access
, FALSE
,
441 dst_handle
)) != INVALID_HANDLE_VALUE32
)
442 handle
= HANDLE_LOCAL_TO_GLOBAL(handle
);