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 * Change the object pointer of a handle, and increment the refcount.
221 BOOL32
HANDLE_SetObjPtr( PDB32
*pdb
, HANDLE32 handle
, K32OBJ
*ptr
,
227 if ((handle
> 0) && (handle
< pdb
->handle_table
->count
))
229 HANDLE_ENTRY
*entry
= &pdb
->handle_table
->entries
[handle
];
230 K32OBJ
*old_ptr
= entry
->ptr
;
231 K32OBJ_IncCount( ptr
);
232 entry
->access
= access
;
234 if (old_ptr
) K32OBJ_DecCount( old_ptr
);
238 if (!ret
) SetLastError( ERROR_INVALID_HANDLE
);
243 /*********************************************************************
246 static BOOL32
HANDLE_GetAccess( PDB32
*pdb
, HANDLE32 handle
, LPDWORD access
)
251 if ((handle
> 0) && (handle
< pdb
->handle_table
->count
))
253 HANDLE_ENTRY
*entry
= &pdb
->handle_table
->entries
[handle
];
256 *access
= entry
->access
& ~RESERVED_ALL
;
261 if (!ret
) SetLastError( ERROR_INVALID_HANDLE
);
266 /*********************************************************************
269 static BOOL32
HANDLE_Close( PDB32
*pdb
, HANDLE32 handle
)
275 if ((handle
> 0) && (handle
< pdb
->handle_table
->count
))
277 HANDLE_ENTRY
*entry
= &pdb
->handle_table
->entries
[handle
];
278 if ((ptr
= entry
->ptr
))
280 if (!(entry
->access
& RESERVED_CLOSE_PROTECT
))
284 if (entry
->server
!= -1)
285 CLIENT_CloseHandle( entry
->server
);
286 K32OBJ_DecCount( ptr
);
289 /* FIXME: else SetLastError */
293 if (!ret
) SetLastError( ERROR_INVALID_HANDLE
);
298 /*********************************************************************
301 * Close all handles pointing to a given object (or all handles of the
302 * process if the object is NULL)
304 void HANDLE_CloseAll( PDB32
*pdb
, K32OBJ
*obj
)
311 entry
= pdb
->handle_table
->entries
;
312 for (handle
= 0; handle
< pdb
->handle_table
->count
; handle
++, entry
++)
314 if (!(ptr
= entry
->ptr
)) continue; /* empty slot */
315 if (obj
&& (ptr
!= obj
)) continue; /* not the right object */
318 if (entry
->server
!= -1) CLIENT_CloseHandle( entry
->server
);
319 K32OBJ_DecCount( ptr
);
325 /*********************************************************************
326 * CloseHandle (KERNEL32.23)
328 BOOL32 WINAPI
CloseHandle( HANDLE32 handle
)
330 return HANDLE_Close( PROCESS_Current(), handle
);
334 /*********************************************************************
335 * GetHandleInformation (KERNEL32.336)
337 BOOL32 WINAPI
GetHandleInformation( HANDLE32 handle
, LPDWORD flags
)
340 PDB32
*pdb
= PROCESS_Current();
343 if ((handle
> 0) && (handle
< pdb
->handle_table
->count
))
345 HANDLE_ENTRY
*entry
= &pdb
->handle_table
->entries
[handle
];
349 *flags
= (entry
->access
& RESERVED_ALL
) >> RESERVED_SHIFT
;
354 if (!ret
) SetLastError( ERROR_INVALID_HANDLE
);
359 /*********************************************************************
360 * SetHandleInformation (KERNEL32.653)
362 BOOL32 WINAPI
SetHandleInformation( HANDLE32 handle
, DWORD mask
, DWORD flags
)
365 PDB32
*pdb
= PROCESS_Current();
367 mask
= (mask
<< RESERVED_SHIFT
) & RESERVED_ALL
;
368 flags
= (flags
<< RESERVED_SHIFT
) & RESERVED_ALL
;
370 if ((handle
> 0) && (handle
< pdb
->handle_table
->count
))
372 HANDLE_ENTRY
*entry
= &pdb
->handle_table
->entries
[handle
];
375 entry
->access
= (entry
->access
& ~mask
) | flags
;
380 if (!ret
) SetLastError( ERROR_INVALID_HANDLE
);
385 /*********************************************************************
386 * DuplicateHandle (KERNEL32.192)
388 BOOL32 WINAPI
DuplicateHandle( HANDLE32 source_process
, HANDLE32 source
,
389 HANDLE32 dest_process
, HANDLE32
*dest
,
390 DWORD access
, BOOL32 inherit
, DWORD options
)
392 PDB32
*src_pdb
= NULL
, *dst_pdb
= NULL
;
396 int src_process
, src_handle
, dst_process
, dst_handle
;
400 if (!(src_pdb
= PROCESS_GetPtr( source_process
, PROCESS_DUP_HANDLE
, &src_process
)))
402 if (!(obj
= HANDLE_GetObjPtr( src_pdb
, source
, K32OBJ_UNKNOWN
, 0, &src_handle
)))
405 /* Now that we are sure the source is valid, handle the options */
407 if (options
& DUPLICATE_SAME_ACCESS
)
408 HANDLE_GetAccess( src_pdb
, source
, &access
);
409 if (options
& DUPLICATE_CLOSE_SOURCE
)
410 HANDLE_Close( src_pdb
, source
);
412 /* And duplicate the handle in the dest process */
414 if (!(dst_pdb
= PROCESS_GetPtr( dest_process
, PROCESS_DUP_HANDLE
, &dst_process
)))
417 if ((src_process
!= -1) && (src_handle
!= -1) && (dst_process
!= -1))
418 dst_handle
= CLIENT_DuplicateHandle( src_process
, src_handle
, dst_process
, -1,
419 access
, inherit
, options
);
423 if ((handle
= HANDLE_Alloc( dst_pdb
, obj
, access
, inherit
,
424 dst_handle
)) != INVALID_HANDLE_VALUE32
)
426 if (dest
) *dest
= handle
;
431 if (dst_pdb
) K32OBJ_DecCount( &dst_pdb
->header
);
432 if (obj
) K32OBJ_DecCount( obj
);
433 if (src_pdb
) K32OBJ_DecCount( &src_pdb
->header
);
439 /***********************************************************************
440 * ConvertToGlobalHandle (KERNEL32)
442 HANDLE32 WINAPI
ConvertToGlobalHandle(HANDLE32 hSrc
)
444 int src_handle
, dst_handle
;
449 if (HANDLE_IS_GLOBAL(hSrc
))
452 if (!(obj
= HANDLE_GetObjPtr( PROCESS_Current(), hSrc
, K32OBJ_UNKNOWN
, 0, &src_handle
)))
455 HANDLE_GetAccess( PROCESS_Current(), hSrc
, &access
);
457 if (src_handle
!= -1)
458 dst_handle
= CLIENT_DuplicateHandle( GetCurrentProcess(), src_handle
, -1, -1, 0, FALSE
,
459 DUP_HANDLE_MAKE_GLOBAL
| DUP_HANDLE_SAME_ACCESS
);
463 if ((handle
= HANDLE_Alloc( PROCESS_Initial(), obj
, access
, FALSE
,
464 dst_handle
)) != INVALID_HANDLE_VALUE32
)
465 handle
= HANDLE_LOCAL_TO_GLOBAL(handle
);