Registering Window Class Multiple Times

Started by
4 comments, last by Rattrap 9 years, 3 months ago

I was recently taking a critical look at some of the basic Win32 classes that I have in Hieroglyph 3, and I want to move to a more proper implementation of my Win32RenderWindow class. Basically the class manages an HWND, handles the initialization (window class registration + window creation) and shutdown, and then map the useful Win32 API calls around the managed HWND. None of this is very special, and I'm sure most games / engines have similar code there.

While looking around for some good examples of RAII based management of an HWND, I found this gem of a post: Simple Main Window Class. The code in the post is of quite good quality, and sheds light on some of the dark corners of handling Win32 windows. However, I have a question about something I saw in there... The author goes to great lengths to generate a unique window class name for each instance of the Window class. This is done with some template meta programming to append a value to the end of a string, and it seems to work fine in practice (he even ensures that it works for different platforms - both x86 and x64 work correctly). So whenever multiple windows are created, they each have their own unique window class to use.

In Hieroglyph 3, I simply register the window class once during the initialization of each window. This hasn't ever given me any troubles, since all of the windows use the same Window Procedure function to handle messages (it basically just looks up a pointer to a handler object and forwards the message call). After about 30 minutes looking through the Win32 documentation, I haven't seen anything that indicates that registering the same class multiple times causes any harm. In addition, the docs say that all of a process's window classes are automatically deregistered when the process ends.

So finally the question: is it worth it to add a complex method of generating unique window class names? It seems like a major complication to something that could potentially be very simple - but if there is a good motivating factor behind it, then of course I can go down a similar path. Any advice from the windows experts out there? What do you guys do???

Advertisement
If you're not worried about thread safety... I would typically keep the atom returned by RegisterClassEx in a static variable stored in the individual class. In the constructor, I would just test to see if it was 0 or not to see if the call to RegisterClassEx needed to be called.

You can add a mutex if you need thread safety as well.

"I can't believe I'm defending logic to a turing machine." - Kent Woolworth [Other Space]

Thanks for the response - that is certainly a viable option. At the moment, I don't currently foresee the need for thread safety, but I always try not to go with solutions that would preclude thread safety either. Your mutex suggestion would also work if I went down that path, but I will likely try to stay away from static variables if possible. That just gets really messy if you allow sub-classes of the Window (for example to have a different style, or perhaps handle events differently).

Still, that is one usable solution to choose from. Is there any other suggestions and/or recommendations?


That just gets really messy if you allow sub-classes of the Window (for example to have a different style, or perhaps handle events differently).

As far as the static variable, you could try calling GetClassInfoEx to see if it already exists and get the atom for local scope use in creating a window. You could do this with just a const string (to ensure the same name is used). The catch here (if you want to be thread) is you still would want some kind of static atomic flag/mutex to make sure two separate threads aren't trying to perform the same action at the same time.

As far as handling events differently, that doesn't tend to revolve around the atom/class itself, but the window handle passed to the window procedure. I've generally gone with a master shared window procedure in a base Control class that can make calls to a class instance (stored in the window handle using SetWindowLongPtr during the handling of WM_CREATE) and virtual functions or a delegate based system. Both of these are handled at the instance level, so the atom only was really needed for the CreateWindowEx call. Otherwise you might have to create separate window procedures for both classes, which that would probably be very messy with a lot of shared code.

It shouldn't be too messy if you actually derived a c++ from a parent class. At the derived class's scope, a static variable of the same name should hide the parent's, thus it should always reference to the local one. If for some reason you actually needed the atom at the window procedure level, you could just call GetClassLongPtr with the window handle to retrieve just about anything that was passed when RegisterClassEx was called.

"I can't believe I'm defending logic to a turing machine." - Kent Woolworth [Other Space]


As far as the static variable, you could try calling GetClassInfoEx to see if it already exists and get the atom for local scope use in creating a window. You could do this with just a const string (to ensure the same name is used). The catch here (if you want to be thread) is you still would want some kind of static atomic flag/mutex to make sure two separate threads aren't trying to perform the same action at the same time.

That is another good idea that I didn't consider before. Even though it has the same mutex requirements, it works more with the data stored in the Win32 API instead of a static.


As far as handling events differently, that doesn't tend to revolve around the atom/class itself, but the window handle passed to the window procedure. I've generally gone with a master shared window procedure in a base Control class that can make calls to a class instance (stored in the window handle using SetWindowLongPtr during the handling of WM_CREATE) and virtual functions or a delegate based system. Both of these are handled at the instance level, so the atom only was really needed for the CreateWindowEx call. Otherwise you might have to create separate window procedures for both classes, which that would probably be very messy with a lot of shared code.

I actually use the same type of system using the SetWindowLongPtr and having a handler object that gets looked up for each HWND. So that's true that the event handling is not a big reason for subclassing. Even so, I would prefer to not preclude subclassing for any reason if at all possible.


It shouldn't be too messy if you actually derived a c++ from a parent class. At the derived class's scope, a static variable of the same name should hide the parent's, thus it should always reference to the local one. If for some reason you actually needed the atom at the window procedure level, you could just call GetClassLongPtr with the window handle to retrieve just about anything that was passed when RegisterClassEx was called.

This is also a great point - which minimizes the 'messiness' of having multiple static variables. I was just wondering - do you use this type of a system in practice, or is this one solution that you see working due to the topic's question?

Also, is anyone aware of an issue with simply registering the same class multiple times?

This is also a great point - which minimizes the 'messiness' of having multiple static variables. I was just wondering - do you use this type of a system in practice, or is this one solution that you see working due to the topic's question?


In general, I have not found to many cases where I derived a C++ window class from another complete class. I generally just have a base abstract Control class (with a lot of built in functionality, but can't be instantiated) and many complete children classes. I tend to model then off of the .NET classes.

For example:

Control -> Form
Control -> Button
Control -> Label

"I can't believe I'm defending logic to a turing machine." - Kent Woolworth [Other Space]

This topic is closed to new replies.

Advertisement