Introduction to Windows API
- Author
- Moise Medici
- Updated
- 23 Jan 2026 · Completed
Handles
A HANDLE type is nothing more than a pointer. It is defined as a PVOID meaning a pointer to void (void * in C). How can something be a pointer to void? This is a way to say that the pointer returned can be of any type, depending on the function that returned it. Internally it is mapped to a specific kernel object that the user does not need to care about. Of course, that might make it a bit harder to understand which type of HANDLE needs to be passed to a function; however, the documentation does a decent job in explaining it. A couple of examples of functions returning a HANDLE are:
HANDLE OpenProcess( [in] DWORD dwDesiredAccess, [in] BOOL bInheritHandle, [in] DWORD dwProcessId);
HANDLE CreateMutexA( [in, optional] LPSECURITY_ATTRIBUTES lpMutexAttributes, [in] BOOL bInitialOwner, [in, optional] LPCSTR lpName);
HANDLE CreateFileA( [in] LPCSTR lpFileName, [in] DWORD dwDesiredAccess, [in] DWORD dwShareMode, [in, optional] LPSECURITY_ATTRIBUTES lpSecurityAttributes, [in] DWORD dwCreationDisposition, [in] DWORD dwFlagsAndAttributes, [in, optional] HANDLE hTemplateFile);Three completely different meanings for the same object. Handles can be used to track down chains of execution; for example, if a sample opens multiple files and performs operations on them, the execution path might become hard to follow. However, looking at the HANDLE ID in the debugger usually helps.
Using a single unified object (HANDLE) for all the API calls that return a pointer type is a newer approach from Microsoft; previously, each function was returning a different HANDLE type, and some still do for backwards compatibility. For example RegCreateKeyExA 6, which returns a HKEY handle.
LSTATUS RegCreateKeyExA( [in] HKEY hKey, [in] LPCSTR lpSubKey, DWORD Reserved, [in, optional] LPSTR lpClass, [in] DWORD dwOptions, [in] REGSAM samDesired, [in, optional] const LPSECURITY_ATTRIBUTES lpSecurityAttributes, [out] PHKEY phkResult, [out, optional] LPDWORD lpdwDisposition);Once a handle is not needed anymore it is usually closed either with CloseHandle 7 or with a specific close function like InternetCloseHandle 8. There are some cases, like the HANDLE populated by EnumProcessModules that must not be closed, as specified in the documentation 9:
Do not call CloseHandle on any of the handles returned by this function. The information comes from a snapshot, so there are no resources to be freed.
So, when encountering phrases like “a handle to a file” or “a handle to a process”, this can be read as “something that uniquely defines and points to the file/process”. It is possible to act on it; for example WriteFile 10 expects as first argument a HANDLE representing the file it can write to:
BOOL WriteFile( [in] HANDLE hFile, [in] LPCVOID lpBuffer, [in] DWORD nNumberOfBytesToWrite, [out, optional] LPDWORD lpNumberOfBytesWritten, [in, out, optional] LPOVERLAPPED lpOverlapped);