Execute code after a window is displayed - winapi

I'm working on a windows application where I'm implementing the whole event loop and everything like that myself (there's a reason for that). In one place, I need to execute some code AFTER a window is shown. Normally, when the window is created, I do some initialisation when WM_CREATE message is received. WM_SHOWWINDOW is sent just BEFORE the window is displayed. However I need to get some code executed right AFTER the window is displayed for the first time. I can't seem to find a notification message sent AFTER the window is shown. Could it be that there isn't one?
Of course, I can keep a boolean - FirstRun - indicating whether or not I had performed my logic, and then execute the code when WM_ACTIVATE is received, provided the boolean is TRUE, then set FirstRun to FALSE so that the code is not execute the next time I am receive WM_ACTIVATE, but this seems somewhat unnatural to me.
It's been ages since I did win32 programming on this level, so can't remember much of it. What is the best approach here?

There is no special notification, but in many cases you can use this trick:
LRESULT CALLBACK MainWndProc(
HWND hwnd, // handle to window
UINT uMsg, // message identifier
WPARAM wParam, // first message parameter
LPARAM lParam) // second message parameter
{
switch (uMsg)
{
case WM_USER + 100:
//window is just displayed, do some actions
return DefWindowProc(hwnd, uMsg, wParam, lParam);
case WM_CREATE:
PostMessage(hwnd, WM_USER + 100, 0, 0);
return DefWindowProc(hwnd, uMsg, wParam, lParam);
default:
return DefWindowProc(hwnd, uMsg, wParam, lParam);
}
return 0;
}

There isn't one because that's what WM_SHOWWINDOW is for. Once that mesage is passed to the default message handling procedure, the window will be shown. The best thing you could do is poll with IsWindowVisible via some sort of timer.
Your program design seems flawed though to have to rely on something like this. What are you trying to do?

As long as you are implementing the whole event loop and everything like that yourself, you can handle this directly in WinMain() like this:
HWND hWnd = CreateWindow(...);
if (!hWnd) return 0;
ShowWindow(hWnd, nCmdShow);
UpdateWindow(hWnd);
OnWindowJustDisplayed(); // here
MSG msg;
while (GetMessage(&msg, NULL, 0, 0))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}

Related

dispatchmessage function didn't execute WM_TIMER message when PostMessage

i am learning win32 thesedays
and playing with PostMessage function.
tricky thing i found was when posting WM_TIMER message into window message queue, window didn't receive any message.
if only receive when i set lparam to 0, otherwise not working at all
the code here.
and also i tested with sendmessage which is totally fine either ways.
LRESULT CALLBACK WndProc(HWND hWnd, UINT msg, WPARAM wparam, LPARAM lparam)
{
switch (msg)
{
case WM_CREATE:
{
//PostMessage(hWnd, WM_TIMER, 0, 0); // receive msg
PostMessage(hWnd, WM_TIMER, 0, 1); // not receiving
}
return 0;
case WM_TIMER:
{
switch (wparam)
{
case 0:
{
HDC dc = GetDC(hWnd);
Ellipse(dc, 70, 70, 120, 120);
ReleaseDC(hWnd, dc);
}
break;
}
return 0;
}
}
return DefWindowProc(hWnd, msg, wparam, lparam);
}
would be amazing if somebody explain why this is happening.
just hope i am missing some basic concept of windows processing system.
According to the WM_TIMER documentation:
lParam [in]
A pointer to an application-defined callback function that was passed to the SetTimer function when the timer was installed.
So, when you use PostMessage(hWnd, WM_TIMER, 0, 0), you pass 0 (as a null pointer) to lParam.
According to the SetTimer documentation:
A pointer to the function to be notified when the time-out value elapses. For more information about the function, see TimerProc. If lpTimerFunc is NULL, the system posts a WM_TIMER message to the application queue. The hwnd member of the message's MSG structure contains the value of the hWnd parameter.
This means when DispatchMessage() sees the WM_TIMER message with its lParam set to 0, it will simply deliver the message as-is to the window message procedure of the window specified by hWnd.
But, when you use PostMessage(hWnd, WM_TIMER, 0, 1); instead, you are passing 1 as the lParam, so it is treated as a pointer to a timer callback function. This means when DispatchMessage() sees the WM_TIMER message with its lParam set to non-zero, it will not deliver the message to the window message procedure of hWnd, it will instead try to actually call the function pointed to by lParam, which is obviously illegal in this case. The system cannot call a function through this invalid pointer.
According to the DispatchMessage() documentation:
The MSG structure must contain valid message values. If the lpmsg parameter points to a WM_TIMER message and the lParam parameter of the WM_TIMER message is not NULL, lParam points to a function that is called instead of the window procedure.

stop win32 window to be minimized programatically

i want to stop my win32 window to be minimized programatically , so I did below but its not working. please let me know any other solution or if i am doing something wrong here.
for testing I am minimizing my window after 2 sec& trying to catch that that and maximize my window again. but its not working as expected.
below is the code.
case WM_SYSCOMMAND:
if ((wParam & 0xFFF0) == SC_MINIMIZE)
{
ShowWindow(hWnd, SW_SHOWMAXIMIZED);
UpdateWindow(hWnd);
}
else
DefWindowProc(hWnd, message, wParam, lParam);
break;
default:
return DefWindowProc(hWnd, message, wParam, lParam);
}
return 0;
}
//show & hide for every 2sec
VOID CALLBACK timerelapsed(HWND hWnd, UINT, UINT_PTR, DWORD)
{
ShowWindow(hWnd, SW_SHOWMINIMIZED);
}
Read the documentation for WM_WINDOWPOSCHANGING. In particular:
An application can prevent changes to the window by setting or clearing the appropriate bits in the flags member of WINDOWPOS.

Encapsulate Win32 in a class - pass class pointer in CreateWindow

I viewed many tutorials and posts on this subject, and they all say I pass the class instance pointer (this) in my CreateWindowEx() function, and then store it in the window procedure function, when the WM_NCCREATE message is sent. I guess this is because WM_NCCREATE is supposedly the first message that gets sent to the window procedure since a window is created.
A few questions/notes:
From debugging I came to know that actually WM_GETMINMAXINFO is the first sent message, before WM_NCCREATE (at least on my machine). Does this mean I should listen for this message instead of WM_NCCREATE?
According to this popular article, the reason everyone calls SetWindowLongPtr() after the message WM_NCCREATE is received is because
If the value does not exist by the time WM_NCCREATE is called then,
by some mysterious Windows behavior that I still don't understand, the
value never gets inserted.
I tried to do exactly that (that is, call SetWindowLongPtr() after CreateWindowEx()). It turns out to be just fine. The application runs okay. Below is my code, please tell me if there's something wrong with this approach.
void GLWin32::CreateWindow(...)
{
...
_hwnd = CreateWindowEx(NULL, _wndclassex.lpszClassName, title.c_str(), WS_OVERLAPPEDWINDOW, x, y, width, height, NULL, NULL, _hinstance, NULL);
SetWindowLongPtr(_hwnd, GWL_USERDATA, reinterpret_cast<LONG_PTR>(this));
...
}
//static window procedure for all instances of this class
LRESULT CALLBACK GLWin32::_msgRouter(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam)
{
LONG l = GetWindowLongPtr(hwnd, GWLP_USERDATA);
GLWin32* thisPtr = reinterpret_cast<GLWin32*>(l);
if (thisPtr)
return thisPtr->_winProc(msg, wparam, lparam);
else
return DefWindowProc(hwnd, msg, wparam, lparam);
}
LRESULT GLWin32::_winProc(UINT msg, WPARAM wparam, LPARAM lparam)
{
switch (msg)
{
case WM_CLOSE:
{
PostQuitMessage(0);
return 0;
}
}
return DefWindowProc(_hwnd, msg, wparam, lparam);
}
Why is my approach not used instead of the popular approach?
The problem with this approach is that if you want to use the instance when processing any of the window creation messages (including "ordinary" messages that are sent as part of the creation process), you won't have access to it.
Suppose you want to create a button when processing WM_CREATE (typical scenario) and you want to set the button text to some instance member value. You want something like:
LRESULT GLWin32::_winProc(UINT msg, WPARAM wparam, LPARAM lparam)
{
switch (msg)
{
case WM_CREATE:
{
CreateWindow("BUTTON", this->buttonText, WS_VISIBLE | WS_CHILD,
10, 10, 50, 30, this->hwnd, NULL, this->hInstance, NULL);
return 0;
}
}
return DefWindowProc(_hwnd, msg, wparam, lparam);
}
Problem is, when WM_CREATE is processed (before CreateWindowEx returns), SetWindowLongPtr wasn't called yet and the instance pointer is missing, so _winProc isn't being called at all.

C++ Win32 PostQuitMessage(0) not working? CPU # 100%

OK so I have my main window procedure (simplified):
LRESULT CALLBACK WndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
switch(msg)
{
case WM_CREATE:
{
if(!loadFiles())
SendMessage(hwnd, WM_CLOSE, 0, 0);
}
break;
case WM_CLOSE:
DestroyWindow(hwnd);
return 0;
break;
case WM_DESTROY:
PostQuitMessage(0);
return 0;
break;
default:
return DefWindowProc(hwnd, msg, wParam, lParam);
}
return 0;
}
loadFiles() is a function to read some text files. If the files are missing, it posts an error message and then returns false. I handle this by sending the WM_CLOSE message, which sends WM_DESTROY? The program calls PostQuitMessage(0) and.. nothing. The process is still sitting in background, now using 100% CPU on core 1. Here is my message loop :
MSG Msg;
while(GetMessage(&Msg, NULL, 0, 0) > 0)
{
TranslateMessage(&Msg);
DispatchMessage(&Msg);
}
return Msg.wParam;
Very simple, I've looked around and seen people using all kinds of different loops, most with PeekMessage() function.. its worth noting I have several child windows containing different controls, I show and hide them when the user selects different tabs, but I don't think it matters because PostQuitMessage(0) is supposed to post WM_QUIT to the message queue, which destroys the child windows aswell right? Any help? Thanks
According to MSDN WM_CREATE is sent during CreateWindow. So you are destroying the window right during creation. I am not sure that this is supposed to work. Also, why so complicated? The documentation says
If an application processes this message, it should return zero to
continue creation of the window. If the application returns –1, the
window is destroyed and the CreateWindowEx or CreateWindow function
returns a NULL handle.
So just return -1 in case loadFiles() fails and handle CreateWindow returning NULL accordingly.

SetWindowsHookEx HCBT_CREATEWND GetWindowText

Anyboby knows how to get text of a created window? I set hook on CreateWindow, but GetWindowText returns empty string.
hCBTHook = SetWindowsHookEx(WH_CBT, (HOOKPROC) &CBTHook, g_appInstance, 0);
LRESULT CALLBACK CBTHook(int nCode, WPARAM wParam, LPARAM lParam)
{
if(nCode == HCBT_CREATEWND)
{
HWND hwnd = (HWND)wParam;
CHAR buf[256];
GetWindowText(hwnd, buf, 256);
}
return CallNextHookEx(hCBTHook, nCode, wParam, lParam);
}
"The system calls the hook procedure before sending the WM_CREATE or WM_NCCREATE message to the window."
The window may not have text yet, your callback is invoked very early in the process of window creation. The name of the window gets passed in as part of the CREATESTRUCT message sent with WM_CREATE which would be the earliest the window could do something about having text. Even to hard code something, it would have to be in WM_NCCREATE, which still hasn't happened yet when your callback is called.
However, the callback itself also gets passed the the CREATESTRUCT. If the name that was passed to CreateWindow is what you are after, that's available to you as well.

Resources