Window Message Loop

Pages: 12
closed account (G26pX9L8)
Hallo all,

I have a function that should be called afer the window is loaded. Now I am using "case WM_CREATE" but that's not working when you want to run a function after the window is created. Can somebody help me?
Do you not at some point call CreateWindow or CreateWindowEx function?

Just put your function after that one.

(Although technically speaking, when you get the WM_CREATE message, the window has been created - it is just not visible yet).
Last edited on
closed account (G26pX9L8)
OK and when is it visible?
After the call to ShowWindow.
After the call to UpdateWindow.

http://www.winprog.org/tutorial/simple_window.html

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
//...

// Step 2: Creating the Window
    hwnd = CreateWindowEx(
        WS_EX_CLIENTEDGE,
        g_szClassName,
        "The title of my window",
        WS_OVERLAPPEDWINDOW,
        CW_USEDEFAULT, CW_USEDEFAULT, 240, 120,
        NULL, NULL, hInstance, NULL);

    if(hwnd == NULL)
    {
        MessageBox(NULL, "Window Creation Failed!", "Error!",
            MB_ICONEXCLAMATION | MB_OK);
        return 0;
    }

    ShowWindow(hwnd, nCmdShow);
    UpdateWindow(hwnd);

//... 
Last edited on
Whenever you call CreateWindow() or CreateDialog() or DialogBox(), etc., WM_CREATE is automatically called by these functions.

You handle the WM_CREATE message that is called by these functions in the main window or dialog procedure, which is a CALLBACK procedure.

Note: the main window procedure is NOT WinMain(), but the CALLBACK function procedure.

If you don't understand what I'm talking about then you need to start with the very basics, which you can find here --

http://www.winprog.org/tutorial/
Last edited on
closed account (G26pX9L8)
@Lamblion
I'm through, but I still call the function from the callback already? My only question is what message should I use. If I use the WM_CREATE it is not working, but all those messages are called after the UpdateWindoe() right?
How about WM_PAINT?

http://msdn.microsoft.com/en-us/library/dd145167%28VS.85%29.aspx

EDIT: But I guess you'll also have to use some bool variable, let's say first_paint, to be able to distinguish the first WM_PAINT message from the rest, as you want your function to be only called upon receiving the first WM_PAINT message. Initialize your variable to true, and in you WndProc function do something like this:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
LRESULT CALLBACK WndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
    switch(msg)
    {
        case WM_PAINT:
            if (first_paint)
            {
                first_paint=false;
                my_function();
            }
        break;
        case WM_CLOSE:
            DestroyWindow(hwnd);
        break;
        case WM_DESTROY:
            PostQuitMessage(0);
        break;
        default:
            return DefWindowProc(hwnd, msg, wParam, lParam);
    }
    return 0;
}
Last edited on
Once you use CreateWindow() or CreateDialog() or DialogBox(), etc., the WM_CREATE in the CALLBACK procedure is the first thing that happens. For example --

1
2
3
4
5
6
7
8
9
10
CreateWindowEx(...)
ShowWindow(...)

LRESULT CALLBACK(...main procedure)

     switch (msg)
     {
          case WM_CREATE:
              do stuff;
     }


In this example WM_CREATE is called before ShowWindow()

If you want to do additional painting, then you will have to handle that with WM_PAINT or other functions.
Last edited on
Ok, I didn't do it well before, take a look at this:

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
bool first_paint=true;
void my_function(HWND & hwnd)
{
    MessageBox(hwnd,"asdf","1234",MB_OK|MB_SETFOREGROUND);
}

//...

LRESULT CALLBACK WindowProcedure (HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
{
    switch (message)                  /* handle the messages */
    {
        case WM_PAINT:
        {
            PAINTSTRUCT psPaint;
            /*HDC hdc =*/ BeginPaint( hwnd, &psPaint );

            if (first_paint)
            {
                first_paint=false;
                my_function(hwnd);
            }

            EndPaint (hwnd, &psPaint);
        }
        break;

        case WM_DESTROY:
            PostQuitMessage (0);       /* send a WM_QUIT to the message queue */
        break;
        default:                      /* for messages that we don't deal with */
            return DefWindowProc (hwnd, message, wParam, lParam);
    }

    return 0;
}
Last edited on
In your code WindowProcedure() doesn't get called. MessageBox() does nothing to WindowProcedure().

You should buy Charles Petzold's book. It is not only THE bible for Windows Programming, but it has NUMEROUS examples of employing WM_PAINT. Even though this book is eleven years old, it is utterly indispensible for introducing Windows programming to beginner and intermediate programmers. You can find it here --

http://www.amazon.com/Programming-Windows-Microsoft-Charles-Petzold/dp/157231995X/ref=sr_1_1?ie=UTF8&s=books&qid=1276552040&sr=1-1
Last edited on
In your code WindowProcedure() doesn't get called.

That's how my WndProc is named in my app. I use Code::Blocks/gcc. Here is the full source, compile it and see for yourself.

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
96
97
98
99
100
101
102
103
104
105
106
107
#include <windows.h>

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

/*  Make the class name into a global variable  */
char szClassName[ ] = "CodeBlocksWindowsApp";

bool first_paint=true;
void my_function(HWND & hwnd)
{
    MessageBox(hwnd,"asdf","1234",MB_OK|MB_SETFOREGROUND);
}

int WINAPI WinMain (HINSTANCE hThisInstance,
                     HINSTANCE hPrevInstance,
                     LPSTR lpszArgument,
                     int nCmdShow)
{
    HWND hwnd;               /* This is the handle for our window */
    MSG messages;            /* Here messages to the application are saved */
    WNDCLASSEX wincl;        /* Data structure for the windowclass */

    /* The Window structure */
    wincl.hInstance = hThisInstance;
    wincl.lpszClassName = szClassName;
    wincl.lpfnWndProc = WindowProcedure;      /* This function is called by windows */
    wincl.style = CS_DBLCLKS;                 /* Catch double-clicks */
    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;                 /* No menu */
    wincl.cbClsExtra = 0;                      /* No extra bytes after the window class */
    wincl.cbWndExtra = 0;                      /* structure or the window instance */
    /* Use Windows's default colour as the background of the window */
    wincl.hbrBackground = (HBRUSH) COLOR_BACKGROUND;

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

    /* The class is registered, let's create the program*/
    hwnd = CreateWindowEx (
           0,                   /* Extended possibilites for variation */
           szClassName,         /* Classname */
           "Code::Blocks Template Windows App",       /* Title Text */
           WS_OVERLAPPEDWINDOW, /* default window */
           CW_USEDEFAULT,       /* Windows decides the position */
           CW_USEDEFAULT,       /* where the window ends up on the screen */
           544,                 /* The programs width */
           375,                 /* and height in pixels */
           HWND_DESKTOP,        /* The window is a child-window to desktop */
           NULL,                /* No menu */
           hThisInstance,       /* Program Instance handler */
           NULL                 /* No Window Creation data */
           );

    /* Make the window visible on the screen */
    ShowWindow (hwnd, nCmdShow);

    /* Run the message loop. It will run until GetMessage() returns 0 */
    while (GetMessage (&messages, NULL, 0, 0))
    {
        /* Translate virtual-key messages into character messages */
        TranslateMessage(&messages);
        /* Send message to WindowProcedure */
        DispatchMessage(&messages);
    }

    /* The program return-value is 0 - The value that PostQuitMessage() gave */
    return messages.wParam;
}


/*  This function is called by the Windows function DispatchMessage()  */

LRESULT CALLBACK WindowProcedure (HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
{
    switch (message)                  /* handle the messages */
    {
        case WM_PAINT:
        {
            PAINTSTRUCT psPaint;
            /*HDC hdc = */BeginPaint( hwnd, &psPaint );

            if (first_paint)
            {
                first_paint=false;
                my_function(hwnd);
            }

            EndPaint (hwnd, &psPaint);
        }
            break;

        case WM_DESTROY:
            PostQuitMessage (0);       /* send a WM_QUIT to the message queue */
            break;
        default:                      /* for messages that we don't deal with */
            return DefWindowProc (hwnd, message, wParam, lParam);
    }

    return 0;
}

Last edited on
Maybe You should just get rid of this Windows Notifications thoughts... if it has to be run once after the window shows up, do it right after the ShowWindow() or CreateWindow(Ex) (WS_VISIBLE)...

If it has to be over and over again, then come back to the Notifications and use WM_PAINT or Hook the WM_SHOWWINDOW , let it pass, and post your own WM_USER+x after...
Well, this seems to work:

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
#include <windows.h>

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

/*  Make the class name into a global variable  */
char szClassName[ ] = "CodeBlocksWindowsApp";

void my_function(HWND & hwnd)
{
    MessageBox(hwnd,"asdf","1234",MB_OK|MB_SETFOREGROUND);
}

int WINAPI WinMain (HINSTANCE hThisInstance,
                     HINSTANCE hPrevInstance,
                     LPSTR lpszArgument,
                     int nCmdShow)
{
    HWND hwnd;               /* This is the handle for our window */
    MSG messages;            /* Here messages to the application are saved */
    WNDCLASSEX wincl;        /* Data structure for the windowclass */

    /* The Window structure */
    wincl.hInstance = hThisInstance;
    wincl.lpszClassName = szClassName;
    wincl.lpfnWndProc = WindowProcedure;      /* This function is called by windows */
    wincl.style = CS_DBLCLKS;                 /* Catch double-clicks */
    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;                 /* No menu */
    wincl.cbClsExtra = 0;                      /* No extra bytes after the window class */
    wincl.cbWndExtra = 0;                      /* structure or the window instance */
    /* Use Windows's default colour as the background of the window */
    wincl.hbrBackground = (HBRUSH) COLOR_BACKGROUND;

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

    /* The class is registered, let's create the program*/
    hwnd = CreateWindowEx (
           0,                   /* Extended possibilites for variation */
           szClassName,         /* Classname */
           "Code::Blocks Template Windows App",       /* Title Text */
           WS_OVERLAPPEDWINDOW, /* default window */
           CW_USEDEFAULT,       /* Windows decides the position */
           CW_USEDEFAULT,       /* where the window ends up on the screen */
           544,                 /* The programs width */
           375,                 /* and height in pixels */
           HWND_DESKTOP,        /* The window is a child-window to desktop */
           NULL,                /* No menu */
           hThisInstance,       /* Program Instance handler */
           NULL                 /* No Window Creation data */
           );

    /* Make the window visible on the screen */
    ShowWindow (hwnd, nCmdShow);
    
    my_function(hwnd);

    /* Run the message loop. It will run until GetMessage() returns 0 */
    while (GetMessage (&messages, NULL, 0, 0))
    {
        /* Translate virtual-key messages into character messages */
        TranslateMessage(&messages);
        /* Send message to WindowProcedure */
        DispatchMessage(&messages);
    }

    /* The program return-value is 0 - The value that PostQuitMessage() gave */
    return messages.wParam;
}


/*  This function is called by the Windows function DispatchMessage()  */

LRESULT CALLBACK WindowProcedure (HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
{
    switch (message)                  /* handle the messages */
    {
        case WM_DESTROY:
            PostQuitMessage (0);       /* send a WM_QUIT to the message queue */
            break;
        default:                      /* for messages that we don't deal with */
            return DefWindowProc (hwnd, message, wParam, lParam);
    }

    return 0;
}

But, does ShowWindow actually draw the window on screen or does it simply post a WM_PAINT message on the app's message queue? If it's the first then it's ok. But I think it's the latter, and in this case the fact that I got my MessageBox after the window was drawn was just pure luck... It could as well not happen...
Last edited on
closed account (z05DSL3A)
ShowWindow posts a WM_SHOWWINDOW Message, this is then handled by DefWindowProc function. From there a WM_PAINT message may be raised, and so on.

Window Notifications
http://msdn.microsoft.com/en-us/library/ff468922(VS.85).aspx
Ah, this is settled then. This is the way to go for what the OP wants:

http://cplusplus.com/forum/windows/25039/#msg132926

EDIT: Oh, and if you want to get rid of that nasty if statement, I suppose you can do something like this:

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
//...

void my_function(HWND & hwnd);
void my_first_paint_handler(HWND & hwnd);
void my_other_paint_handler(HWND & hwnd);

void (*my_paint_handler)(HWND&)=my_first_paint_handler;

void my_function(HWND & hwnd)
{
    MessageBox(hwnd,"asdf","1234",MB_OK|MB_SETFOREGROUND);
}

void my_first_paint_handler(HWND & hwnd)
{
    my_paint_handler=my_other_paint_handler;

    PAINTSTRUCT psPaint;
    HDC hdc = BeginPaint( hwnd, &psPaint );

    my_function(hwnd);

    EndPaint (hwnd, &psPaint);
}

void my_other_paint_handler(HWND & hwnd)
{
    PAINTSTRUCT psPaint;
    HDC hdc = BeginPaint( hwnd, &psPaint );

    //WM_PAINT handling here...

    EndPaint (hwnd, &psPaint);
}

//...

LRESULT CALLBACK WindowProcedure (HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
{
    switch (message)                  /* handle the messages */
    {
        case WM_PAINT:
            my_paint_handler(hwnd);
            break;

        case WM_DESTROY:
            PostQuitMessage (0);       /* send a WM_QUIT to the message queue */
            break;
        default:                      /* for messages that we don't deal with */
            return DefWindowProc (hwnd, message, wParam, lParam);
    }

    return 0;
}

//... 
Last edited on
closed account (G26pX9L8)
I read all the posts and now i don't know what to do further. I think that book is nice but i prefer books in dutch (because am from the netherlands) so maby later. So what is the best choice to do now? I have a simple log system that only needs to show some functions output in a listbox (see previous topics).
closed account (G26pX9L8)
Can anyone suggest me a good idea?
Explain to us, what exactly the programm is supposed to do (in order, and if something shall be repeated, tell it!)...
closed account (G26pX9L8)
The program should be a log system that shows the output of de functions. And some functions have a loop which never an end to the message loop. That means the program waits to the loop end before it draws the window, but the loop never ends.

Btw, i tested all the code above but when i add a Sleep() it is not working again. I hope its clear now.
Don´t handle the WM_PAINT -Message, if you don´t need to do drawings on your own...

Just add data to your edit/static control and let windows do the rest...
Pages: 12