According to MSDN, WM_SIZE should be sent to window when window is minimized or restored.
But my application window, which is WTL CDialogImpl never get WM_SIZE when minimize or restore.
I use spy++ to check on it, I can get WM_SYSCOMMAND, WM_WINDOWPOSCHANING, WM_ACTIVE, WM_ACTIVEAPP etc, but no WM_SIZE.
I checked some other WTL example application, I'm able to get WM_SIZE msg when minimize or restore.
My question is why my WTL CDialogImpl window doesn't receive WM_SIZE?
Besides this, is there any other message to indicate the restore or minimize finish?
I mean, in system, most of time, there is animation to show the minimize/restore process. I need a message or event to let app know the animation is done when restore.
thanks!
William L.
As stated in the doc A window receives this message through its WindowProc function so you will not get it through Spy++.
Anyhow the WM_SIZE message is received in a ATL::CDialogImpl derived dialogs at creation, minimization and restoration.
To check it with the WTL AppWizard create a minimal WTL modal Dialog application and add a message map entry for WM_SIZE and a matching OnSize() member:
BEGIN_MSG_MAP(CMainDlg)
MESSAGE_HANDLER(WM_INITDIALOG, OnInitDialog)
MESSAGE_HANDLER(WM_SIZE, OnSize)
//...
END_MSG_MAP()
LRESULT OnSize(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& /*bHandled*/)
{
return 0;
}
Set a breakpoint in OnSize() it will be hit.
Your problem (if any) is elsewhere.
Related
I have a window which serves as an overlay, and only has some part of it non-transparent. The window has extended styles
WS_EX_TOOLWINDOW | WS_EX_TOPMOST | WS_EX_TRANSPARENT | WS_EX_LAYERED
And the transparency is set with:
SetLayeredWindowAttributes(hwnd, RGB(255, 255, 255), 0, LWA_COLORKEY);
I do want to read the mouse events to implement the interactive part of the overlay.
So far i tried catching messages like
WM_MOUSEMOVE,
WM_KEYDOWN,
WM_NCLBUTTONDOWN,
in my WNDPROC and there they didn't fire. I assumed that was due to some of the window extended styles, and by removing one at a time i found out that it was layered window attribute which caused it. Sadly my app does depend on this attribute for its transparency.
Then i tried registering a windows hook for that very process and thread to intercept the mouse events. I don't know the internals of hooks at all - but i thought they get access to the messages before they enter the application's queue hence i hoped i could read them before whatever interferes passes them on. That didn't work sadly.
I registered the hook like so:
app_state.hhook = SetWindowsHookExW(WH_MOUSE,
Some(Self::HOOKPROC),
GetModuleHandleW(null_mut()),
GetCurrentThreadId();
And the actual HOOKPROC was defined like this:
pub unsafe extern "system" fn HOOKPROC(ncode: c_int, wparam: WPARAM, lparam: LPARAM) -> LRESULT {
println!("fired!");
CallNextHookEx(null_mut(), ncode, wparam, lparam)
}
Sadly this didn't output anything to STDOUT, but I do think that hook was registered as unhook function didn't return 0.
My next idea was to put the hook in the process which manages the previous window. However the below doesn't work.
app_state.hhook = SetWindowsHookExW(WH_MOUSE,
Some(Self::HOOKPROC),
GetModuleHandleW(null_mut()),
GetWindowThreadProcessId(
GetWindow(hwnd, GW_HWNDPREV), null_mut())
);
I think that it's due to the fact that i need to place the hook in a separate dll but event if it does work - this solution seem to be very dirty and will probably work in very few cases without requiring elevated privileges. What can i do to achieve the desired via accepted and cohesive code?
Just get rid of the WS_EX_TRANSPARENT style and use WS_EX_LAYERED by itself, and let the OS handle mouse input normally (no hook needed). Fully transparent pixels will fall-through as expected, and the window will receive input messages on non-transparent pixels.
I packaged the winapi CreateWindowEx into a simple class. Since every window sharing a same wndProc(hwnd,msg,wparam,lparam), I put every window created by CreateWindowEx into a map to distribute msg, like this:
wndProc(hwnd, msg, wparam, lparam){
if(map[hwnd]!=nil){
switch(msg){
map[hwnd].wndProc(...)
}
}
}
And each time a window or its parent window being destroyed, remove it from the map:
case WM_DESTROY: delete(map, hwnd)
But things like buttons do not receive WM_DESTROY. I printed all msg in WM_NOTIFY and WM_COMMAND but i got noting.
So how can I remove those child windows form the map at the right time? Or a way distribute the msg without creating a hwnd map?
They certainly do get that message. But their window procedure is inside Windows, not inside your program. So you never see it. Something you can read in the MSDN documentation, note how WM_DESTROY doesn't get any special treatment. Nor generate a notification that your parent window can see.
Short from automatically removing all the child windows when you see the parent window destroyed, subclassing controls is a pretty standard requirement for C++ class library wrappers. Best to not invent your own btw, this has been done many times already.
So how can I remove those child windows form the map at the right time?
You have to subclass every window you create, either with SetWindowLongPtr(GWL_WNDPROC) or SetWindowSubClass(), then you will receive all of the WM_DESTROY messages.
Or a way distribute the msg without creating a hwnd map?
Frameworks like ATL and VCL handle that by dynamically allocating a thunk for each window and putting the object pointer right in the thunk, then use the thunk as the window procedure. That way, whenever the thunk is called, it passes the message directly to its associated object.
I am working on Windows GUI Application.There are 20 Push Buttons on my Window. Against each button click, I want to open up a new window for displaying some information. It can be anything which can display some information but since I am new to all this and I didn’t want to try anything complicated, I decided to go with the idea of creating a pop up window against each button click.
Now the problem that I am facing is that since there are 20 different windows, do I need to create 20 different window callback functions? Though there is only one control in the pop up window i.e. a Close sign, but even for that I need to have a CALLBACK function.
I had been trying with this but now this idea looks senseless. Is there any other option in which I can achieve the desired functionality?
Waiting for help.
If all of the windows should behave the same way, then you can create a single window procedure (what you're calling the CALLBACK function) that is shared by all of the pop-up windows.
Window procedures do not have to be unique to individual windows, but if multiple windows share the same window procedure, they will react identically to all messages that they receive.
For example:
// Message procedure for all pop-up windows.
LRESULT CALLBACK MyPopupWndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
switch (msg)
{
// handle any messages you want here in order to
// customize the behavior of your pop-up window
}
return DefWindowProc(hwnd, msg, wParam, lParam);
}
You specify a pointer to the MyPopupWndProc function when you register the window class for your pop-up windows (using the RegisterClassEx function), and then you pass the name of the registered window class when you call CreateWindowEx to create/display a pop-up window whenever one of the buttons on your main window is clicked.
Of course, if you're just wanting something simple for testing purposes, remember that you can always call the MessageBox function! No window procedures or class registration required.
I know that WM_PAINT tells a window that it needs to repaint itself entirely, but apparently that's not the message that gets sent when it's been covered partially and then the window that was in front of it is no longer in the way and it needs to repaint the dirty portion. Does anyone know what message is sent in this case?
EDIT: Found the problem:
The issue involved a Delphi control I wrote to embed a SDL rendering surface on a Delphi form. SDL has an API to build its renderer on another window's HWND, and it marks it as a "foreign window".
SDL usually handles WM_PAINT internally, so I ended up having to add some code to SDL's WindowProc to forward the message on to the external WindowProc if it's a foreign window. That was working sometimes, but it turns out there was a glitch that was stripping the foreign window flag from the window's data structure, so it was swallowing the message instead of passing it on to my app. Once I fixed that, I started getting the WM_PAINT messages all the time.
Why do you say it's apparently not? WM_PAINT should be called for partial redraws (the updated rect is returned by BeginPaint or GetUpdateRect). If it doesn't appear to be getting called, there may be a bug elsewhere in your app that's preventing it. What are you seeing that leads you to believe that it's not working?
WM_PAINT is sent to indicate that some portion (including the entirity) of the window needs to be repainted.
Call GetUpdateRect() to get a rectangle that bounds the region to be updated. This information is also included in the PAINTSTRUCT (as the rcPaint field) passed to BeginPaint().
The BeginPaint() function returns the rect that requires validation in its 2nd parameter: http://msdn.microsoft.com/en-us/library/dd183362(VS.85).aspx
case WM_PAINT:
{
PAINTSTRUCT psPaint;
HDC hdc = BeginPaint( hwnd, &psPaint );
// psPaint.rcPaint contains invalidated area
EndPaint (hwnd, &psPaint);
}
return 0;
Look at psPaint.rcPaint : http://msdn.microsoft.com/en-us/library/dd162768(VS.85).aspx
I'm pretty certain the Win32 API uses WM_PAINT even for partial repaints. From MSDN:
The WM_PAINT message is sent when the system or another application makes a request to paint a portion of an application's window. [My italics].
That link has the full detail on WM_PAINT but if, as you say, the WM_PAINT message is not being sent for partial redraws, the Spy++ is the tool you need to find out for sure.
Take a look at WM_PRINTCLIENT. There are some circumstances when WM_PAINT is not sent and a WM_PRINTCLIENT message is sent instead. (AnimateWindow for example.)
CoInitialize(NULL) creates an STA by creating a hidden window. How to get an HWND handle for this window?
Function EnumThreadWindows does not work, in an example I tried:
...
CoInitialize(NULL);
EnumThreadWindows(GetCurrentThreadId(), EnumThreadWndProc, 0);
...
BOOL CALLBACK EnumThreadWndProc(HWND hwnd, LPARAM lParam)
{
m_hwnd = hwnd;
return FALSE;
}
Nothing ever enters the EnumThreadWndProc.
Any ideas?
This hidden window is Message-Only Window, It is not visible, has no z-order, cannot be enumerated, and does not receive broadcast messages. The window simply dispatches messages.
To find message-only windows, specify HWND_MESSAGE in the hwndParent parameter of the FindWindowEx function. In addition, FindWindowEx searches message-only windows as well as top-level windows if both the hwndParent and hwndChildAfter parameters are NULL.
Source:
MSDN
Btw, I would be VERY careful here - you really shouldn't be sending window messages to windows you don't own. Your code is highly likely to break in a future version of Windows.