Windows in a class

Started by
13 comments, last by mk83 22 years, 5 months ago
Hi Guys,

I managed to get it working, I''m not really sure why or how, maybe someone will be able to explain, for some reason, ( I think it may have some thing to do with scope !)

wServerWindow TestWindow(Temp);

does not work, but this does :

wServerWindow* TestWindow;
TestWindow = new wServerWindow(Temp);

If anyone can explain why, I would appreciate it!

Thanks,
MK83
Advertisement
Doh! I can''t believe we missed this!

When you declare a variable inside a function (or any code block) it by default belongs to the ''automatic'' storage class. This means that memory is allocatated for it (from the stack) when that block is entered and then freed up when the block is exited.

What was happening originally, when you were using

wServerWindow TestWindow(Temp);

was that an instance of this class was constructed on entering the function and subsequently destroyed on exit. Also, the HWND you are storing in ''Temp'' will be undefined when the wServerWindow instance is created.

When you change the code to

wServerWindow* TestWindow = new wServerWindow(Temp);

the POINTER is automatically allocated (from the stack) on entering the function but the actual class instance is allocated dynamically (from the heap) when that line of code is reached. When the function exits, the POINTER is destroyed but the class instance lives on. Unfortunately you now have no pointer to that instance, causing a memory leak (as you can''t delete it).

What you need to do is keep a list of pointers to the child windows created by a parent - you can then delete the children when the parent is deleted.


= Just Some Suggestions =

Unrelated to the issue you are having, but suggestions for your code...

You may want to wrap your RegisterClass(&wc); and population of the wc structure with a if statement to make sure you don''t reregister the class at runtime rather than at compile time and catch any errors RegisterClass would pass back. something like...

if (!GetClassInfo(hInstance, "Main Window Class", &wc))
{
WNDCLASS wc;
// ... stuff inbetween ...
if (!RegisterClass(&wc))
throw "Error registering window class";
}
Same goes for your second class. Rather then trying creation and then failing if you aren''t registered you can just check to see if you are registered. This way you can actually catch the real errors when they occur.


To simplify the use of your class from within your callback you may want to change the way you do things. Rather than having to get the stored this pointer and use ThisWindow->GetHandle() and such, you can create a simple wrapper function that will allow you to have your window procedure as a standard function rather than a static function.

LRESULT CALLBACK wMainWindow::WindowProc(HWND hwnd, // handle of window
UINT uMsg, // message identifier
WPARAM wParam, // first message parameter
LPARAM lParam // second message parameter
){
MainWindow* ThisWindow = (wMainWindow*) GetWindowLong (hwnd, GWL_USERDATA);
if (ThisWindow)
return (ThisWindow->ProcessMessage (hWnd, uMessage, wParam, lParam));
else // else call the default proc
return (DefWindowProc (hWnd, uMessage, wParam, lParam));
}

This replaces the windowProc you have already and is declared static in your class.
Now you just create a class called ProcessMessage that takes the same parameters as a normal window procedure, but make it a nonstatic part of your class. This greatly simplifies things since you don''t have to use ThisWindow-> anymore. This works well with message crackers too. If you have no idea what they are you may want to investigate them (http://www.acm.uiuc.edu/windevils/windevils97/workshop/98/6/).
The only problem I have had with this is that you either can''t process your WM_CREATE message (since it may be sent before the SetWindowLong is called) or you have to add special code for WM_CREATE. This isn''t a problem for me, I never use WM_CREATE, but you can work around this by processing the WM_CREATE in the WindowProc and passing the this pointer into your CreateWindow call so you end up being able to call the same ProcessMessage function.

Good Luck
Yep thats the one, that method is the best ive found of encapsulating a window in a class. If you try to keep EVERYTHING concerning a window in a class, then you have to make winproc static, which mean you cannot easily subclass or even do multiple instances of a window. I tried to get round this but it got very messed up, very quickly. Keeping a winproc function out of classes means that you have to have a little more code not in objects but the trade off is that the whole system becomes infinatly more useable and less error prone. If anyones interested ive included a semi-complete set of windows wrappers, which i wrote for the fun of it a while back, it is usable - just need error checking and someone to write the wrappers for some more controls.

http://hades.itl.net/~leg27/winwrap.zip

Andy
"I create a window in this class by handing it the handle of the first window I have created and using GetWindowLong(ParentWindow, GWL_HINSTANCE) to get the instance of the program."

You might also want to to look into GetModuleHandle(NULL) as it does the same thing ie HMODULE == HINSTANCE

This topic is closed to new replies.

Advertisement