Initializing a Child Window

In a program that I am creating, a child window loads an image file and displays the image. However, I can find no equivalent for "ON_CREATE", in a child window. How do I load the file and initialize the variables in this child window? Or, does this need to be done in the Main WndProc(), and somehow passed to the child?
One needs to draw a distinction between a 'child window', and a 'child window control', because the answer to your question depends on which you have. In terms of definitions, 'child window' is a more general and inclusive term. It could include classes that you created in your application and on which you called RegisterClassEx(), and later instantiated with CreateWindowEx() calls. In this case you would indeed have WM_CREATE messages within the Window Procedure of your application.

In the case of 'Child Window Controls' these could be any of the Windows Standard Controls, the Common Controls, Custom Controls, or even ActiveX Controls. In this case you wouldn't have access to the WM_CREATE message because it is within internal Windows code - likely in user32.lib or something called from there, or ComCtl32.lib, or wherever. Of course, with subclassing, you may be able to access that internal Window Procedure, but I don't believe this is the time to discuss that in terms of your question. Thing is, if you have some kind of 'child window control' whose purpose is to display images, there would be some kind of 'control interface' to easily allow for that. For example, take an "edit" control. Its purpose is to enter or display text. The provided interface for that would be the GetWindowText() and SetWindowYText() functions. You don't need to wear yourself out trying to get access to the internal Window Procedure of an "edit" control, in order to use its provided functionality.

I've never had to work with image files in my long career of dealing with Win32 coding so I'm not sure which pre-existing control would be right for you. Way back in my pre - .NET Visual Basic 4 to 6 days in the 1990s I recall Visual Basic had an "Image Control' in its 'Toolbox'. In that 'Drag and Drop' visual design environment one could drag an icon representing the Image Control onto a Form, and in the 'Properties Window' set a path to a *.bmp file or whatever kind of image file one wanted the control to load and display. It seems like everybody but me knows about this stuff around this site and most other C++ sites, but like I said, I'm kind of a number crunching, database, and data entry kind of guy. Maybe someone can jump in and tell you which control to use. I could be wrong, but I don't think any of the Standard Windows Controls are designed for that. Possibly one of the Common Controls.

I more or less assumed Anachronon that you would do your drawing of your mathematically generated surface within some kind of blank window you created in your application with the RegisterClassEx() / CreateWindowEx() functions. In that case, you would be able to generate data for the shape in a WM_CREATE handler, but it would have to actually be drawn I think in a WM_PAINT handler.
Since you are the 'Content Creator' I don't believe some specialized image displaying control is your answer. There's no image out there somewhere that you can acquire that serves your needs. You need to create it and draw it yourself. That's kind of what I created that "Pane" Class for in the Scroll Controls app. You need to get rid of my controls in that example and draw your shape there. There is a Window Procedure in that app that processes WM_CREATE messages.
Hey Freddie1. My bad. I forgot to declare a couple of my critical variables as "static"! So, I kept getting an "uninitialized variable" error---even though I had clearly initialized them in "WM_CREATE". Because they were not static, their values were being lost, every time that they went out of scope. Don't know how I missed that. My brain must have been tired, yesterday. The child window works properly now.

To answer the other question, this child is a user-defined and registered class. I haven't gotten to the control-class windows yet---other than defining them, and getting them to display. Hopefully, this afternoon...

I do have one other question though. I am getting that annoying "flicker" in the child window, whenever I resize the main window. The size of the child changes with the size of the main window. Any way to prevent that flicker? I tried the trick of returning "TRUE" from "WM_ERASEBKGND". But, that doesn't work with the child window.
Last edited on
OK, I found the solution to the flickering problem. In addition to adding "TRUE" to "WM_ERASEBKGND" in the ChildProc(), I needed to add "WS_CLIPCHILDREN" to the styles of the main window. Here it is in the CreateWindow() function:

1
2
hwnd = CreateWindow(szAppName, szAppTitle, WS_OVERLAPPEDWINDOW | WS_CLIPCHILDREN,
 CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, 0, 0, hInstance, 0);


Here is my next question: Currently, I am creating the image object in the WM_CREATE case of the ChildProc(). I wish to create the image object in the main WndProc(), and then pass the object pointer to the child, after the child has been created. Basically, the child is acting as a viewport in the main window. If possible, I would like to pass that pointer only once---not every time that the child is repainted.
I believe that I may have found a way to send data from the WndProc() to the ChildProc() (or vice-versa). The trick appears to be in the "SendMessage()" function. Here is an oversimplified version of the possible code:

1
2
3
struct U {int a, int b, int c} v;

SendMessage(hwndChild, WM_USER, 0, (LPARAM)&v);


Now, when the child window receives the message, the variables can be initialized:

1
2
3
4
5
6
case WM_USER:
     struct U* w;
     w=(struct U*) lparam;
     a=w->a;
     b=w->b;
     c=w->c;


Of course the typedef of "struct U" needs to be declared globally. However, the struct variables 'v' and 'w' are both local.

Any number of unique messages can be sent, using "WM_USER+1", "WM_USER+2", "WM_USER+3", all the way up to "WM_USER+0xbfff".

It's a bit late today. So, I'll have to wait until tomorrow, to try this.
Last edited on
I've never done that, but if it works, it works. In general, sharing data between different windows without using global variables isn't a problem in Windows. In every significant Windows program I code I create a structure or class - let's call it 'ProgramData', or even simpler, AppData. In perhaps the most complicated program I've ever written, I called it 'MainWindowData'.

Anyway, I make a call to a memory allocation function such as GlobalAlloc() or HeapAlloc() to allocate one of these. That way, the 'duration' of the data will be the duration of the program, or until I release it. Then I store the pointer to the data in either window properties (GetProp()/SetProp()), or, as you've seen me do, using .cbWndExtra bytes and SetWindowLong()/GetWindowLong(). Note that the HWND of wherever the data is stored is needed to access it. But in your case, where, if I have it right, your drawing will be done in a child of the main app window, the child can get the data stored in the parent by simply calling the GetParent() function. In some of my more complicated apps where you've got parents, grandparents and great grandparents, it may be necessary to GetParent(GetParent(HWND)), or something like that.

I was wondering when you would get to this point where you would be wondering how to do these kinds of things. You seem to be making good progress.

Something I expect you've ignored up to this point is the lpCreateParams, the last parameter of the CreateWindow() / CreateWindowEx() call. That's a real super biggie! Its a critical part of about everything I do. Generally, when I create additional program windows based on additional Window Classes, I pass the HWND of the main window into the new window through these CREATEPARAMS. That way, the new additional window will have access to my 'ProgramData' struct stored in the Main Window.
Thanks Freddie1. My trick worked! I was looking to do more than just pass an object pointer to the child window (in this case, an image object). I also needed the child proc to pick up the pointer, and initialize all of the related variables (in this case, width and height). Putting in the message handler, "case WM_USER:" allowed me to do this one-time task. Now, the image can be scrolled and resized by the parent, while being displayed in the child---without the child having to repeatedly retrieve and calculate the same data.

I will definitely have to look into "lpCreateParams", "GetProp()", and "SetProp()". I may need those later, for the arrays of structs, that I will be using in my program. But, one thing at a time.
Topic archived. No new replies allowed.