Object Handles
Drivers and user-mode components access most system-defined objects through handles. Handles are represented by the HANDLE opaque data type. (Note that handles are not used to access device objects or driver objects.)
For most object types, the kernel-mode routine that creates or opens the object provides a handle to the caller. The caller then uses that handle in subsequent operations on the object.
Here is a list of object types that drivers typically use, and the routines that provide handles to objects of that type.
Object type | Corresponding create/open routine | ||||||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
Parameter | Description |
---|---|
-a | Dump information about all types of handles, not just those that refer to files. Other types include ports, Registry keys, synchronization primitives, threads, and processes. |
-c | Closes the specified handle (interpreted as a hexadecimal number). You must specify the process by its PID. WARNING: Closing handles can cause application or system instability. |
-l | Dump the sizes of pagefile-backed sections. |
-y | Don’t prompt for close handle confirmation. |
-s | Print count of each type of handle open. |
-u | Show the owning user name when searching for handles. |
-p | Instead of examining all the handles in the system, this parameter narrows Handle’s scan to those processes that begin with the name process. Thus: handle -p exp would dump the open files for all processes that start with «exp», which would include Explorer. |
name | This parameter is present so that you can direct Handle to search for references to an object with a particular name. For example, if you wanted to know which process (if any) has «c:\windows\system32» open you could type: handle windows\system The name match is case-insensitive and the fragment specified can be anywhere in the paths you are interested in. |
Handle Output
When not in search mode (enabled by specifying a name fragment as a parameter), Handle divides its output into sections for each process it is printing handle information for. Dashed lines are used as a separator, immediately below which you will see the process name and its process id (PID). Beneath the process name are listed handle values (in hexadecimal), the type of object the handle is associated with, and the name of the object if it has one.
When in search mode, Handle prints the process names and id’s are listed on the left side and the names of the objects that had a match are on the right.
More Information
You can find more information on the Object Manager in Windows Internals, 4th Edition or by browsing the Object Manager name-space with WinObj.
Download Handle (887 KB)
What is a Windows Handle?
What is a «Handle» when discussing resources in Windows? How do they work?
7 Answers 7
It’s an abstract reference value to a resource, often memory or an open file, or a pipe.
Properly, in Windows, (and generally in computing) a handle is an abstraction which hides a real memory address from the API user, allowing the system to reorganize physical memory transparently to the program. Resolving a handle into a pointer locks the memory, and releasing the handle invalidates the pointer. In this case think of it as an index into a table of pointers. you use the index for the system API calls, and the system can change the pointer in the table at will.
Alternatively a real pointer may be given as the handle when the API writer intends that the user of the API be insulated from the specifics of what the address returned points to; in this case it must be considered that what the handle points to may change at any time (from API version to version or even from call to call of the API that returns the handle) — the handle should therefore be treated as simply an opaque value meaningful only to the API.
I should add that in any modern operating system, even the so-called «real pointers» are still opaque handles into the virtual memory space of the process, which enables the O/S to manage and rearrange memory without invalidating the pointers within the process.
A HANDLE is a context-specific unique identifier. By context-specific, I mean that a handle obtained from one context cannot necessarily be used in any other aribtrary context that also works on HANDLE s.
For example, GetModuleHandle returns a unique identifier to a currently loaded module. The returned handle can be used in other functions that accept module handles. It cannot be given to functions that require other types of handles. For example, you couldn’t give a handle returned from GetModuleHandle to HeapDestroy and expect it to do something sensible.
The HANDLE itself is just an integral type. Usually, but not necessarily, it is a pointer to some underlying type or memory location. For example, the HANDLE returned by GetModuleHandle is actually a pointer to the base virtual memory address of the module. But there is no rule stating that handles must be pointers. A handle could also just be a simple integer (which could possibly be used by some Win32 API as an index into an array).
HANDLE s are intentionally opaque representations that provide encapsulation and abstraction from internal Win32 resources. This way, the Win32 APIs could potentially change the underlying type behind a HANDLE, without it impacting user code in any way (at least that’s the idea).
Consider these three different internal implementations of a Win32 API that I just made up, and assume that Widget is a struct .
The first example exposes the internal details about the API: it allows the user code to know that GetWidget returns a pointer to a struct Widget . This has a couple of consequences:
- the user code must have access to the header file that defines the Widget struct
- the user code could potentially modify internal parts of the returned Widget struct
Both of these consequences may be undesirable.
The second example hides this internal detail from the user code, by returning just void * . The user code doesn’t need access to the header that defines the Widget struct.
The third example is exactly the same as the second, but we just call the void * a HANDLE instead. Perhaps this discourages user code from trying to figure out exactly what the void * points to.
Why go through this trouble? Consider this fourth example of a newer version of this same API:
Notice that the function’s interface is identical to the third example above. This means that user code can continue to use this new version of the API, without any changes, even though the «behind the scenes» implementation has changed to use the NewImprovedWidget struct instead.
The handles in these example are really just a new, presumably friendlier, name for void * , which is exactly what a HANDLE is in the Win32 API (look it up at MSDN). It provides an opaque wall between the user code and the Win32 library’s internal representations that increases portability, between versions of Windows, of code that uses the Win32 API.
Handle Inheritance
A child process can inherit handles from its parent process. An inherited handle is valid only in the context of the child process. To enable a child process to inherit open handles from its parent process, use the following steps.
- Create the handle with the bInheritHandle member of the SECURITY_ATTRIBUTES structure set to TRUE.
- Create the child process using the CreateProcess function, with the bInheritHandles parameter set to TRUE.
The DuplicateHandle function duplicates a handle to be used in the current process or in another process. If an application duplicates one of its handles for another process, the duplicated handle is valid only in the context of the other process.
A duplicated or inherited handle is a unique value, but it refers to the same object as the original handle. Processes can inherit or duplicate handles to the following types of objects:
- Access Token
- Communications device
- Console input
- Console screen buffer
- Desktop
- Directory
- Event
- File
- File mapping
- Job
- Mailslot
- Mutex
- Pipe
- Process
- Registry key
- Semaphore
- Socket
- Thread
- Timer
- Window station
All other objects are private to the process that created them; their object handles cannot be duplicated or inherited.