Jump to content
  • Advertisement
Sign in to follow this  
Psychopathetica

Child Window Issues

This topic is 1815 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Recommended Posts

Hi. I'm creating my first Child Window using Visual C++ 2010 but have a couple issues. First of all, when you close out of the child window, it closes out of the entire program rather than just close the window! I would like for it to close independently, so closing the main program will close the entire program. But since I'm some what a noob, I don't know how to. Secondly, I have a black background, and when I drag the child window, theres somewhat a miniature flicker with the edges of the child window. Its minor but somewhat a nuisance and I would like for it to not flicker. Here is the code I have as a basic layout with the 2 problems I have and thanks in advance :)

 

#include <windows.h>

HWND hWnd;
HWND hChildWnd;
MSG msg;
WNDCLASSEX wc;
HBRUSH brush;
HINSTANCE hChildInstance = NULL;

LRESULT CALLBACK WindowProcedure (HWND, UINT, WPARAM, LPARAM);

#define ID_FILE_EXIT 1000

int WINAPI WinMain (HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpszArgument, int nCmdShow)
{
    wc.cbSize        = sizeof(WNDCLASSEX);
    wc.style         = CS_VREDRAW|CS_HREDRAW|CS_OWNDC;
    wc.lpfnWndProc   = WindowProcedure;
    wc.cbClsExtra    = 0;
    wc.cbWndExtra    = 0;
    wc.hInstance     = hInstance;
    wc.hIcon         = NULL;
    wc.hCursor       = LoadCursor(NULL, IDC_ARROW);
    wc.hbrBackground = CreateSolidBrush(RGB(0, 0, 0));
    wc.lpszMenuName  = NULL;
    wc.lpszClassName = "Window";
    wc.hIconSm       = NULL;
    RegisterClassEx(&wc);
    hWnd = CreateWindowEx (0, "Window", "Parent Window", WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, CW_USEDEFAULT, 800, 600, HWND_DESKTOP, NULL, hInstance, NULL);
    hChildWnd = CreateWindowEx (WS_EX_CLIENTEDGE, "Window", "Child Window", WS_OVERLAPPEDWINDOW | WS_CHILD | WS_VISIBLE, CW_USEDEFAULT, CW_USEDEFAULT, 640, 480, hWnd, NULL, hChildInstance, NULL);
    ShowWindow (hWnd, SW_SHOWMAXIMIZED);
    while (1)
    {
        if (PeekMessage(&msg,NULL,0,0,PM_REMOVE) > 0)
        {
            if (WM_QUIT == msg.message) break;
            TranslateMessage (&msg);
            DispatchMessage (&msg);
        }
        
    }
    return msg.wParam;
}

LRESULT CALLBACK WindowProcedure (HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
    switch (msg)
    {
        case WM_CREATE:
        {
            HMENU hFile = CreateMenu();
            HMENU hExit = CreateMenu();
            AppendMenu(hFile, MF_POPUP, (UINT_PTR)hExit, "File");
            AppendMenu(hExit, MF_STRING, ID_FILE_EXIT, "Exit");
            SetMenu(hWnd, hFile);
            break;
        }
        case WM_COMMAND:
        {
            switch(LOWORD(wParam))
            {
                case ID_FILE_EXIT:
                {
                    DestroyWindow(hWnd);
                    return(0);
                    break;
                }
            }
            break;
        }
        case WM_DESTROY:
            PostQuitMessage (0);
            break;
        case WM_KEYDOWN:
            if(wParam == VK_ESCAPE)
            {
                DestroyWindow(hWnd);
                return(0);
            }
            break;
        default:
            return DefWindowProc (hWnd, msg, wParam, lParam);
    }
    return 0;
}

Share this post


Link to post
Share on other sites
Advertisement
PostQuitMessage is the reason the program is exiting - you only need to do that on the main window's WndProc. In the code above, it looks like you've told both windows to use the same WndProc. You could make a second WndProc or store some data using SetWindowLong(GWL_USERDATA) to make sure that only the main window uses PostQuitMessage.

As far as flicker goes, I haven't done Win32 in a long time and only know how to do it in WinForms. Google for "Win32 flicker" and you should find a lot of tutorials on what you need to do. Edited by Nypyren

Share this post


Link to post
Share on other sites

Well you may be right but commenting out "if (WM_QUIT == msg.message) break;" will allow me to close the child window ok. But closing the program doesnt close all the way since I commented that out. It closes but doesnt fully close. If you run it from IDE the stop button is still clickable after closing it. If you run it from file, closing it will cause it to still be in the process list even though you closed it. However if you dont comment out "if (WM_QUIT == msg.message)", it closes all the way as should, but the child window affects it as well. So it looks like that message will have to be somewhere else or I have to code it differently. Problem is, what do I do?

Edited by Psychopathetica

Share this post


Link to post
Share on other sites
That's exactly right. PostQuitMessage just sends WM_QUIT to the message loop. So if you don't exit the loop when you get it, your program will still run, even with no visible windows. The fact that the loop is still looping is controlling whether the program exits or not.

This is a good thing - it means you can choose to leave a program running in the background without a window, which is what programs like virus scanners do. It even means you can make an app that never opens any windows in the first place!


Ok, I got off on a tangent; Back to your original goal. One possible solution is:

- Make a copy of your window procedure function and rename it to something else.
- Make a second window class (WNDCLASSEX wcChild; or something like that) and have that window class use the second window procedure instead.
- In the second window procedure, don't handle WM_DESTROY at all.

If I'm remembering how win32 operates correctly, this will make it so that closing the child window does not close the app, but closing the main one does. Edited by Nypyren

Share this post


Link to post
Share on other sites

I don't think I did it right. But I think I have to make a separate msg. Not sure. Its doing the same thing. And the 2nd window didnt receive a different color background and remained black:

#include <windows.h>

HWND hWnd;
HWND hChildWnd;
MSG msg;
WNDCLASSEX wc;
WNDCLASSEX wcChild;
HBRUSH brush;
HINSTANCE hChildInstance = NULL;

LRESULT CALLBACK WindowProcedure (HWND, UINT, WPARAM, LPARAM);
LRESULT CALLBACK ChildWindowProcedure (HWND, UINT, WPARAM, LPARAM);

#define ID_FILE_EXIT 1000

int WINAPI WinMain (HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpszArgument, int nCmdShow)
{
    wc.cbSize        = sizeof(WNDCLASSEX);
    wc.style         = CS_VREDRAW|CS_HREDRAW|CS_OWNDC;
    wc.lpfnWndProc   = WindowProcedure;
    wc.cbClsExtra    = 0;
    wc.cbWndExtra    = 0;
    wc.hInstance     = hInstance;
    wc.hIcon         = NULL;
    wc.hCursor       = LoadCursor(NULL, IDC_ARROW);
    wc.hbrBackground = CreateSolidBrush(RGB(0, 0, 0));
    wc.lpszMenuName  = NULL;
    wc.lpszClassName = "Window";
    wc.hIconSm       = NULL;
    RegisterClassEx(&wc);
    hWnd = CreateWindowEx (0, "Window", "Parent Window", WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, CW_USEDEFAULT, 800, 600, HWND_DESKTOP, NULL, hInstance, NULL);
    
    wcChild.cbSize        = sizeof(WNDCLASSEX);
    wcChild.style         = CS_VREDRAW|CS_HREDRAW|CS_OWNDC;
    wcChild.lpfnWndProc   = ChildWindowProcedure;
    wcChild.cbClsExtra    = 0;
    wcChild.cbWndExtra    = 0;
    wcChild.hInstance     = hChildInstance;
    wcChild.hIcon         = NULL;
    wcChild.hCursor       = LoadCursor(NULL, IDC_ARROW);
    wcChild.hbrBackground = CreateSolidBrush(RGB(255, 0, 0));
    wcChild.lpszMenuName  = NULL;
    wcChild.lpszClassName = "Window";
    wcChild.hIconSm       = NULL;
    RegisterClassEx(&wcChild);
    hChildWnd = CreateWindowEx (WS_EX_CLIENTEDGE, "Window", "Child Window", WS_OVERLAPPEDWINDOW | WS_CHILD | WS_VISIBLE, CW_USEDEFAULT, CW_USEDEFAULT, 640, 480, hWnd, NULL, hChildInstance, NULL);
    ShowWindow (hWnd, SW_SHOWMAXIMIZED);
    
    while (1)
    {
        if (PeekMessage(&msg,hWnd,0,0,PM_REMOVE) > 0)
        {
            if (WM_QUIT == msg.message) break;
            TranslateMessage (&msg);
            DispatchMessage (&msg);
        }
        
    }
    return msg.wParam;
}

LRESULT CALLBACK WindowProcedure (HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
    switch (msg)
    {
        case WM_CREATE:
        {
            HMENU hFile = CreateMenu();
            HMENU hExit = CreateMenu();
            AppendMenu(hFile, MF_POPUP, (UINT_PTR)hExit, "File");
            AppendMenu(hExit, MF_STRING, ID_FILE_EXIT, "Exit");
            SetMenu(hWnd, hFile);
            break;
        }
        case WM_COMMAND:
        {
            switch(LOWORD(wParam))
            {
                case ID_FILE_EXIT:
                {
                    DestroyWindow(hWnd);
                    return(0);
                    break;
                }
            }
            break;
        }
        case WM_DESTROY:
            PostQuitMessage (0);
            break;
        case WM_KEYDOWN:
            if(wParam == VK_ESCAPE)
            {
                DestroyWindow(hWnd);
                return(0);
            }
            break;
        default:
            return DefWindowProc (hWnd, msg, wParam, lParam);
    }
    return 0;
}

LRESULT CALLBACK ChildWindowProcedure (HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
    switch (msg)
    {
        default:
            return DefWindowProc (hWnd, msg, wParam, lParam);
    }
    return 0;
}
Edited by Psychopathetica

Share this post


Link to post
Share on other sites
You should read up on the MSDN documentation for the APIs you are using. Several of your parameters are wrong or probably not what you expect.

Share this post


Link to post
Share on other sites
OK so in your latest code the most important problem is your window class names.

Notice the lines:
 
wc.lpszClassName = "Window";

wcChild.lpszClassName = "Window";
The way CreateWindowEx knows which one to use is the one you ask for in the second parameter:
hChildWnd = CreateWindowEx(..., "Window", ...);
You need to give each window class a unique name, or else the RegisterClassEx function will fail. (It's failing because a class called "Window" already exists, but you aren't checking to see if it failed or not - this is a common problem with APIs that return error codes instead of throwing an exception; It's very easy to totally forget the possibility that a function can fail).

First off, for the child window, just try changing "Window" in both spots to "ChildWindow". Edited by Nypyren

Share this post


Link to post
Share on other sites

OMG! That wast it!  Wow even the background color changed to the one I wanted. And the flickering is gone!!! I should slap myself for missing that. Thank you so much =D

 

[EDIT] Well its kind of gone. It only flickers if both windows are the same color I believe. Either that or it was the border of the window that was flickering not the window itself. Yeah it was the border flickering. Thats kind of odd.

Edited by Psychopathetica

Share this post


Link to post
Share on other sites
Sign in to follow this  

  • Advertisement
×

Important Information

By using GameDev.net, you agree to our community Guidelines, Terms of Use, and Privacy Policy.

We are the game development community.

Whether you are an indie, hobbyist, AAA developer, or just trying to learn, GameDev.net is the place for you to learn, share, and connect with the games industry. Learn more About Us or sign up!

Sign me up!