WaldErcer WaldErcer - 1 month ago 12
C++ Question

How to reopen a closed window with the Windows API

I'm making a buttons in a main window ( hwnd ) that when you click on a button it opens new window ( hwndSec ) that can be controlled by the main window !
when i click on a button, the hwndSec showed up ! and while i'm clicking on the other buttons it can be modified ... but when i close it and attempt to reopen it again it doesn't response ! so the buttons become useless !

This a simple example of a single button just to open the window then trying to open it again.

The setting i set for hwndSec:

wincl.hInstance = hInstance;
wincl.lpszClassName = "HwndSecClass";
wincl.lpfnWndProc = WindowProcedureSec;
wincl.style = CS_DBLCLKS;
wincl.cbSize = sizeof (WNDCLASSEX);

/* Use default icon and mouse-pointer */
wincl.hIcon = LoadIcon (NULL, IDI_APPLICATION);
wincl.hIconSm = LoadIcon (NULL, IDI_APPLICATION);
wincl.hCursor = LoadCursor (NULL, IDC_ARROW);
wincl.lpszMenuName = NULL;
wincl.cbClsExtra = 0;
wincl.cbWndExtra = 0;
wincl.hbrBackground = (HBRUSH) COLOR_BACKGROUND;

if (!RegisterClassEx (&wincl))
return 0;

hwnd = CreateWindowEx (
0,
wincl.lpszClassName,
_T("Window 2"),
WS_OVERLAPPEDWINDOW,
CW_USEDEFAULT,
CW_USEDEFAULT,
500,
500,
HWND_DESKTOP,
NULL,
hInstance,
NULL
);


i make two window procedures :

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


when i click a button i call this fonction :

ShowWindow(hwndSec,SW_SHOW);


and then the second window appear normally , when i close the window it doesn't came back to appear again.

LRESULT CALLBACK WindowProcedure (HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
{
switch (message) /* handle the messages */
{
case WM_CREATE:
CreateWindow("BUTTON",
"open",
WS_CHILD | WS_VISIBLE ,
200,100,
100,50,
hwnd,
(HMENU) ID_BUTTON,
NULL,
NULL);
break;
case WM_COMMAND:
switch(LOWORD(wParam))
{
case ID_BUTTON :
//printf("%s",(char*)GetLastError());
ShowWindow(hwndSec,SW_SHOW);
break;
}
break;
case WM_DESTROY:
PostQuitMessage (0);
break;
default:
return DefWindowProc (hwnd, message, wParam, lParam);
}

return 0;
}


LRESULT CALLBACK WindowProcedureSec (HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
switch (message)
{
case WM_DESTROY:
PostMessage(hwnd, WM_CLOSE, 0, 0);
break;
default:
return DefWindowProc (hwnd, message, wParam, lParam);
}
return 0;
}

Answer

When a window is being closed, it receives a WM_CLOSE message. If that message is passed to DefWindowProc(), the default behavior is to destroy the window:

An application can prompt the user for confirmation, prior to destroying a window, by processing the WM_CLOSE message and calling the DestroyWindow function only if the user confirms the choice.

By default, the DefWindowProc function calls the DestroyWindow function to destroy the window.

This is further discussed on MSDN:

Closing the Window

So, you will have to re-create your secondary window with CreateWindow/Ex() each time you want to show it after it has been closed:

LRESULT CALLBACK WindowProcedure (HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
{
    switch (message)
    {
    ...
    case WM_COMMAND:
        switch (LOWORD(wParam))
        {
        case ID_BUTTON :
            if (!hwndSec)
            {
                hwndSec = CreateWindowEx(
                    0,
                    _T("HwndSecClass"),
                    _T("Window 2"),
                    WS_OVERLAPPEDWINDOW,
                    CW_USEDEFAULT,
                    CW_USEDEFAULT,
                    500,
                    500,
                    HWND_DESKTOP,
                    NULL,
                    hInstance,
                    NULL
                );
            }
            ShowWindow(hwndSec, SW_SHOW);
            break;
        }
        break;
    ...
    }

    return 0;
}

LRESULT CALLBACK WindowProcedureSec (HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
{
    switch (message)
    {
    case WM_DESTROY:
        hwndSec = NULL;
        break;
    }

    return DefWindowProc(hwnd, message, wParam, lParam);
}

If you don't want to do that, then you need to make the secondary window handle the WM_CLOSE message and not pass it to DefWindowProc(). For instance, call ShowWindow(SW_HIDE) instead, and then you can later call ShowWindow(SH_SHOW) when needed

LRESULT CALLBACK WindowProcedure (HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
{
    switch (message)
    {
    ...
    case WM_COMMAND:
        switch (LOWORD(wParam))
        {
        case ID_BUTTON :
            ShowWindow(hwndSec, SW_SHOW);
            break;
        }
        break;
    ...
    }

    return 0;
}


LRESULT CALLBACK WindowProcedureSec (HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
{
    switch (message)
    {
    case WM_CLOSE:
        ShowWindow(hwnd, SW_HIDE);
        break;

    default:
        return DefWindowProc(hwnd, message, wParam, lParam);
    }

    return 0;
}