1. What is a handle?
In Windows, the handle is a 32-bit unsigned integer value corresponding to object one by one. An object can be mapped to a unique handle, and a handle can also be mapped to a unique object.
2. Why do we need a handle?
More specifically, Windows requires a handle. Windows needs to provide programmers with the necessary programming interfaces that allow programmers to access, create, and destroy objects. However, for the sake of encapsulation, Windows does not want to return a pointer to the programmer. The pointer contains too much information. First, the pointer gives the exact location of the object's storage, and secondly, to manipulate a pointer, the programmer must know the internal structure of the object The pointer refers to, that is, Windows must expose the data structure to the programmer, which may be hidden by the operating system from the programmer. If COM technology hides the data from the user, exposes only the interface and allows manipulation of the data by an interface-defined method, the handle allows you to manipulate the data in your own way, but Windows does not expose your data directly to you. The direct manipulation of data is required by the programmer, without exposing the data is required by Windows, the handle encapsulation method implements the picking.
3. How does a handle map to an object?
Behind the package, there must be a place where decoding can be implemented to enable the conversion of handles and objects. In Windows, there are two ways of mapping:
A. Congruent mapping. That is, the handle itself is a pointer. Mapping here is just a type conversion. In this case, a process instance handle or a module handle, and a resource handle, and so on.
B. Table-based mapping. This is the most common mapping mechanism between the object pointer and the handle. The operating system creates the table and saves all the objects to consider. When you need to create a new object, you first find the empty entry in the table, and then add the data that represents the object into it. When an object is deleted, its data members and its entry in the table are freed.
4. Definition and implementation of a handle
We take the GDI object as an example to discuss. When you create a GDI object, you get a handle to the object. The object of the handle may be one of the Hbrush, Hpen, Hfont, or HDC, depending on the type of GDI object you create.
But the most common type of GDI object is hgdiobj. Hgdiobj is defined as a null pointer. The actual compilation type definition for Hpen differs depending on the compilation time macro strict.
If strcit has been defined, Hpen is:
struct HPEN__ {int unused};
typedef struct HPEN__* Hpen;
If strict is not defined, Hpen is defined as:
typedef void *handle;
typedef HANDLE HPEN;
The above code is a detail-oriented programmer closest to the handle, so let's focus on it. There's a little bit of finesse here. If you define a strict macro, Hpen is a pointer to a structure that has a single unused field, otherwise hpen is a null pointer. The C + + compiler allows any type of pointer to be passed as an empty point, or vice versa. Two non-null pointers of different types are incompatible. In the strict version, compiling an incorrect mix of GDI object handles would give a warning that improper mixing of non-GDI handles, such as HWND and HMENU, would also give a warning that the program would be more strict checked by the compiler.
The next analysis may not be interesting to you, but it reveals the handle more profoundly. For GDI handles, although the Windows header file defines it as a pointer, if you examine the values of these handles carefully, it is not like a pointer at all, which is why I say it is just a 32-bit integer value without a character. A handle is a pointer to a case, and this sentence still applies. Let's randomly generate some handles, such as you use Getstockobject () to get some handles, and you'll find that their values are always in the range 0x01900011 to 0xba040389. The former points to an unassigned, invalid area in the user area, which points to the kernel address space. In addition, you may find that the value between the two handles may be only a difference of 1, which also means that the GDI handle is not a pointer.
Unlike most people imagine, a handle is not a simple index value. For GDI object handles, the GDI handle consists of a 8-bit, 1-bit heap object tag (indicating whether the object was created in the heap), 7-bit object type information, and a 0-bit index with a height of 4 bits 16.
3 3 2 2 2 2 2 2 2 2 2 2 1 1 1 1 1 1 1 1 1 1 0 0 0 0 0 0 0 0 0 0
1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0
| 8-bit reference count | heap | Object Type 7 | 16-bit Index |
Standard
Remember
As you can see here, for GDI, it uses only 16 bits as the index. This means that a process can only create a maximum of less than 64K handles and, in fact, is subject to some other limitations, and the entire WINDWOS system can probably hold about 16384 (0x4000) GDI objects.
Handle (Handle)