Hey. I can’t find an explanatory enough explaination about handle. All I’ve understood is that it handles things. I’ve seen a tutorial using it to convert an Image to an Icon, but it doesn’t explain what it is ! Thanks.
The Windows API uses C, not C#. C is not an object-oriented language. But the way the Windows API is designed works sort of like an object-oriented language. Handles are part of how that works.
Think about what happens in .NET when I create an object.
The first line creates a Dog
object. The second line creates a different one. The third line tells C#: “I want you to call the Bark()
method of the object the variable example2
refers to.
In Windows API, we’d probably write something like this:
(The below is oversimplified, but explains what’s going on at a high level.)
The hDog
type here is “handle to a dog”. When CreateDog()
is called, some data is created to represent “a dog” in a private dictionary. The hDog
handle that is returned is the key into that private dictionary. DogBark()
is a method that makes a dog bark, but it needs to know which dog. So it takes a handle to a dog so it can ask the private dictionary for the dog’s data it needs to make that dog bark.
So “handles” are just how C libraries like the Windows API represent objects in a language that isn’t object-oriented. We don’t commonly interact with them in C#. We only tend to need to use them if we want to do something that .NET doesn’t do for us, so we have to use a .NET feature called “PInvoke” to interact with the Windows API. This can get complicated, as the memory these handles represent are outside of the .NET Garbage Collector’s control, so we become responsible for properly managing it.
So if I understood, handles are a way for Windows API to handle OOP stuff. But why should I it to (for example) convert a Bitmap to an Icon ?
I thought PInvoke is used to call C++ methods from within the .Net runtime?
I thought that inside a process one could use pointers to objects, but pointers cannot be passed between two processes because of memory protection. You could do this in DOS and probably AmigaOS. So it seems that in windows or linux one could create an object and get a pointer to it, but dereference would lead to a protection fault. So instead the pointer is a parameter to a syscall. The OS can then access memory without protection.
Then there is this concept of Keys in tables of databases. Somehow I don’t get a pointer to the data-row in SQLite. Instead there is one indirection to allow SQLite to defragment memory.
I write “pointer”, but I know pointers have the special meaning, that they do not only point to an object, but an also ( like a database cursor ) advance to the next object in an array. Though, this value type objects need to have all the same size for this to work.
A Handle is a reference to a windows resource. The Windows API is more low-level than C#, so when you create an object, like a Bitmap or a file, or a Window, you get a Handle with which you can use to interact with the resource.
Certain methods take handles that work with specific types of objects. You cannot ShowWindow on a Bitmap handle, for example.
In C# you are used to object oriented programming, where you can call an object’s method by using dot notation, as mentioned in other answers.
This is really just syntactic sugar.
All methods in C# take a hidden parameter, this
, which specifies which instance of the object you want to execute the method on. This is really obvious when you get down to reflection and IL. After all, in machine code, there is no such thing as an object, only addresses, data, and executable code.
So the Windows API is all a bunch of functions where you usually pass a reference to the object you want it to work with, the this
of the Windows API.
Windows objects are unmanaged, i.e. they don’t have the benefit of C# garbage collection, so if you create a resource, you have to make sure to release it after you’re done with it.
C# devs
null reference exceptions