If I want to find out about anything in Windows, you have to go through one of the bazillion Enum functions. These creatures take a callback function which they invoke with information on what is being enumerated, along with a variable (typically a void *) that contains data where you can put the results of the information (for example putting it on a list).
Interestingly, there are a few exceptions to the rule. File I/O tends to be of a different character – FindFirstFile(Ex), FindNextFile, FindClose. Of course the person writing the API could have added the word ‘File’ to the end of ‘FindClose’. That way they would all have a matching function style. But there’s no accounting for taste.
We wander over to the C++ (or practically all OO languages) and the design immediately changes to an enumerator. For C++ it’s the iterator, You get an enumerator in Java (and C#). The Enumerator doesn’t look like the old create another stub function to implement this handler trick, the handling code is inside a set of braces ({}).
I presume it’s the vagaries of the different teams working on the solutions to the problem and the fact that at the time people were designing the solutions they didn’t think there was a better way. With the enumerator, the caller keeps the state of the enumeration to themselves, they pass the current item and a pointer to the handling function. When the enumeration is finished you are guaranteed that there is no remaining state left over and that all the handles are cleaned up before you return to the caller.
It seems to be more of a caller vs. callee cleanup exercise. Nowadays we have scoped destruction of objects and garbage collection to deal with the state destruction. What’s more it means that you still aren’t depending on the potential binary instability of the oo function call definition. The typical OO implementation uses an implied this parameter passed to methods to carry the object information. It allows clever developers to create functions that mimic OO methods without actually being functions of the objects themselves.
If you’re clever, you can replace VMT entries with functions of your own creation that can be written in C. Convenient that.
An annoyance of programming Windows is that WinMain must be a static function. If you want to have a WinMain method, you need to perform trickery. One of the most regular methods of doing this is to use SetWindowLongPtr and store the address of the object in the private window information. This has the potential of being quite expensive. Every time you invoke the method you have to issue a GetWindowLongPtr call to extract the pointer, and then indirectly invoke the object’s implementation of WinMain.
There is a more evil mechanism that uses self rewriting code. But that’s for another time.