I thought that the red x button could not be greyed out? Well...

closed account (3pj6b7Xj)
The following code creates a windows application with a greyed out X button, it also prevents the window from being sized -WS_SIZEBOX, I just figured out you sould use - to indicate what you don't want happening on the windows style...however, on the window class style if you specify CS_NOCLOSE the red X button on the upper right corner is greyed out...to help quit the application, there is a button inside the client area, clicking the button sends a WM_QUIT message which ends the program.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
#include <windows.h>

#define MSGEVENT Msg.message
#define BUTTON1 4866

/*  Declare Windows procedure  */
LRESULT CALLBACK CtAppDefProc (HWND, UINT, WPARAM, LPARAM);

int WINAPI WinMain
(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpszArgs, int iWindowState)
{
    HWND hWnd;               /* This is the handle for our window */
    MSG Msg;            /* Here messages to the application are saved */
    WNDCLASSEX wincex;        /* Data structure for the windowclass */

    /* The Window structure */
    wincex.hInstance = hInstance;
    wincex.lpszClassName = "WindowClassEx";
    wincex.lpfnWndProc = CtAppDefProc;      /* This function is called by windows */
    wincex.style = CS_HREDRAW | CS_VREDRAW | CS_NOCLOSE;                 /* Disables the RED X button! */
    wincex.cbSize = sizeof (WNDCLASSEX);

    /* Use default icon and mouse-pointer */
    wincex.hIcon = LoadIcon (NULL, IDI_APPLICATION);
    wincex.hIconSm = LoadIcon (NULL, IDI_APPLICATION);
    wincex.hCursor = LoadCursor (NULL, IDC_ARROW);
    wincex.lpszMenuName = NULL;                 /* No menu */
    wincex.cbClsExtra = 0;                      /* No extra bytes after the window class */
    wincex.cbWndExtra = 0;                      /* structure or the window instance */
    /* Use Windows's default color as the background of the window */
    wincex.hbrBackground = (HBRUSH) GetStockObject(WHITE_BRUSH);

    /* Register the window class, and if it fails quit the program */
    if (!RegisterClassEx (&wincex))
        return 0;

    /* The class is registered, let's create the program*/
    hWnd = CreateWindowEx (
           0,                   /* Extended possibilites for variation */
           wincex.lpszClassName,         /* Classname */
           "Windows App",       /* Title Text */
           WS_OVERLAPPEDWINDOW -WS_SIZEBOX,  /* Prevent re-sizing of the client window!  */
           CW_USEDEFAULT,       /* Windows decides the position */
           CW_USEDEFAULT,       /* where the window ends up on the screen */
           640,                 /* The programs width */
           480,                 /* and height in pixels */
           HWND_DESKTOP,        /* The window is a child-window to desktop */
           NULL,                /* No menu */
           hInstance,       /* Program Instance handler */
           NULL                 /* No Window Creation data */
           );

    /* Make the window visible on the screen */
    ShowWindow (hWnd,iWindowState);

    /* Create a button. */
    HWND button1 = CreateWindow("button","Close Me!",WS_CHILD,100,100,100,100,hWnd,(HMENU)BUTTON1,GetModuleHandle(NULL),0);
    ShowWindow(button1,SW_SHOW); /* Display button in window. */
    
    bool bQuit = false;

    /* Run the message loop. It will run while bQuit is false. */
    while (!bQuit)
    {
        while (PeekMessage (&Msg, NULL, 0, 0,PM_REMOVE))
        {
            if (MSGEVENT == WM_QUIT) bQuit = true;
            /* Translate virtual-key messages into character messages */
            TranslateMessage(&Msg);
            /* Send message to WindowProcedure */
            DispatchMessage(&Msg);
        }
    }

    return 0; /* bye bye. */
}

/*  This function is called by the Windows function DispatchMessage()  */
LRESULT CALLBACK CtAppDefProc (HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
    switch (message) /* handle the messages */
    {
        case WM_COMMAND:
            if(LOWORD(wParam) == BUTTON1)
                PostQuitMessage(0);

        case WM_SYSCOMMAND:
            if((wParam & 0xFFF0) == SC_CLOSE) PostQuitMessage(0);

        default: /* for messages that we don't deal with */
            return DefWindowProc (hWnd, message, wParam, lParam);
    }

    return 0;
}


Just wondering why some people say it is not possible when clearly it is. I've also been able to do it in run time using SetWindowLong but its a little more involved.

By the way, this is my first app that creates a button and handles an event, lol. I didn't think buttons were so simple to create!
Last edited on
I don't see why anyone would say that. The closest thing that I can think of would be that you can't stop a process from being terminated and even that's possible with the use of a driver.
If I ever started someone's app and I couldn't close it with the x button, first I'd try to stop it with task manager, if that didn't work I'd pull the plug. And I'd never use it again.
closed account (3pj6b7Xj)
LOL, this was just an experiment tho.
Glad you are making progress! Merry Christmas!
whateverstyle - WS_SIZEBOX will only work if whateverstyle is inclusive of WS_SIZEBOX. If whteverstyle does not include WS_SIZEBOX, doing the above will do "weird things" by seemingly randomly switching on/off unrelated flags (it's not really random, but whatever)

The proper way to remove a flag is with the & and ~ operators:

1
2
3
4
5
// to combine two styles
foo = STYLE1 | STYLE2;  // combines STYLE1 and STYLE2

// to remove a style
foo = STYLES & ~STYLE1;  // removes STYLE1 from STYLES 


Anyway I didn't try the program out because I'm lazy, but I can't fathom why you'd ever want to disable the close button.

But congrats nonetheless.
Last edited on
If you wanted to be annoying, or if you were currently doing something uninterruptible.
Edit:
Say you're writing a program to write to the MBR. Half-way through writing, the user closes the program. They now have a clobbered MBR and an unbootable system. Obviously it's unlikely that it would take you long enough to write 512 bytes on modern hardware that the user would actually have time to try to exit, but the point still stands. Of course, you could give them a warning saying "Writing MBR\nWARNING: do not close the program during writing! Doing so may render your system unbootable." but many people ignore dialogues.
Last edited on
if you were currently doing something uninterruptible.


That's just the thing -- nothing should be uninterruptable.
See my edit. In some situations, your program can't afford to exit.
Remember that the close button doesn't immediately close the program -- it only gives the user a way to indicate they want the program to close. The close message wouldn't even be processed until the message pump cycles.

Obviously it's unlikely that it would take you long enough to write 512 bytes on modern hardware that the user would actually have time to try to exit, but the point still stands.


That point doesn't really stand, though, because it's an unrealistic scenario.

In reality, any large "uninterruptable" operation should be interruptable with damage control. If the user does something that begins a long operation, they should always have the option to abort.

Simply not giving the user the option to exit is a bad design in any program. About the only time I can find it to be acceptable would be in something like an OS installer.
closed account (D80DSL3A)
Full screen apps such as video games have no "red X" for quitting.
I write my games so there is a "quit" button on each menu and so that the "Esc" key will get the user to a menu during level play (aborting the level).

As Disch pointed out, the "red X" doesn't automatically close the program anyways. It just causes a WM_DESTROY message to be posted for your program to handle. This is essential. It gives your program a chance to call a cleanup function so that allocated resources may be deleted, drawing surfaces can be released, and your graphics package (and maybe sound) can be shutdown in an orderly manner. Your app can then PostQuitMessage(0); which finally causes the program to be terminated.
Yes, you're right.
well there are lots of ways to do this, when the user clicks the x button, it just sends a WM_CLOSE to the wndproc, defwindowproc will handle this by doing DestroyWindow(hwnd), so you can also disable it by doing somethign like this:

1
2
case WM_CLOSE:
		return 0;


or to completely get rid of the system menu, just put your window styles as:
WS_CAPTION

to get rid of the title bar completely put the style as:
WS_POPUP

The good thing about CS_NOCLOSE though, is taht is disables alt+F4 aswell.


i also noticed taht in windows 7, you can right click windows in the taskbar at the bottom to close them, and it ignores the programs system menu.

You can add this to the windows extended style to stop it from appearing in the taskbar:
WS_EX_TOOLWINDOW
Last edited on
I've never seen bit styles removed with either the - or ~ symbol. I've verified that subtracting it out works if the bit is set to begin with, but other bits will certainly be altered if that bit isn't presently set. Far better in my opinion to use the 'exclusive or' procedure to 'zor' it out.
closed account (3pj6b7Xj)
Thanks for the input guys, i've put your suggestions to use and i've had great success! Thanks all! :)
Topic archived. No new replies allowed.