I'm trying to debug this problem in a library where a set of controls are not being updated to be disabled. I've drilled down to a point where I've hit a black box. A mfc120ud.dll!CCmdUI::DoUpdate() call will then call CCmdUI::Enable(). It'll then go through a bunch of calls one through ntdll.dll and 4 through user32.dll for which I have no source for and then sometimes stick its head our coming back to mfc123ud.dll or sometimes not.
I don't know why the WM_PAINT message gets invoked sometimes. Does anyone know?
Your call stack shows the reason.
CCmdUI::DoUodate finally calls CCmdUI::Enable.
Look into the CCmdUI::Enable code of the MFC. There are cases that WM_NEXTDLGCTL is called or EnableWindow. WM_NEXTDLGCTL may cause a focus change. It depends how the controls will handle this message. It is possible that they directly call UpdateWindow or RedrawWindow to reflect changes to the UI, instead of just calling Invalidate(Rec). There may be a control inside your ribbon that receives the WM_PAINT message.
The call to EnableMenuItem should be safe and I am sure that it doesn't cause a WM_PAINT call.
Related
I'm working on an MFC app. I have a class inheriting from CWinApp which tries to open an AfxMessageBox inside its InitInstance function.
When the AfxMessageBox function is called, no message-box is visible, but I hear a Windows bell sound. If I press Alt, the message box appears. Why isn't the AfxMessageBox appearing immediately?
This question mentions a similar issue, but the answer only refers to the non-MFC function MessageBox, not AfxMessageBox which is what I'm using:
MFC MessageBox Not Showing at Top Of All Windows
Update 1
I'm working on a minimal reproducible example, but it's tricky because this is part of a large application with poor encapsulation.
In my app, it appears that a call to the function ProcessShellCommand() is causing AfxMessageBox to stop working. However, calls to AfxMessageBox work correctly both before and after ProcessShellCommand in a newly-created MFC application.
It looks like some consequence of calling ProcessShellCommand is causing AfxMessageBox to behave differently, but I'm not sure how to identify all the consequences of calling ProcessShellCommand. When I'm debugging, the particular call to ProcessShellCommand includes a filename, so the file-open command is causing the app's CView to be launched.
In the OnInitialUpdate code for my CView-inheriting class, AfxMessageBox functions correctly. The best transition point I can identify between AfxMessageBox working, and not working, is when the CView's OnInitialUpdate function returns from it being called by ProcessShellCommand.
Update 2
It seems that m_pMainWnd is NULL before the call to ProcessShellCommand (while AfxMessageBox is working as expected), and non-NULL after the call to ProcessShellCommand.
Based on this discussion:
Why would a message box be not displaying?
, I tried printing out the message-queue contents before and after the call to ProcessShellCommand. Before, the message-queue only contains a single message. Afterwards, the message-queue printout loop is full of WM_PAINT and it never terminates until I press Alt. This makes me think that I'm running into a message-pump-related issue rather than something related to e.g. visibility state.
---------- More observations ------------
It looks like the call to AfxMessageBox stops inside win32u.dll; I determined this by hitting the 'pause execution' button while waiting for the message-box to appear. Here's the call-stack and debug screenshot:
It turns out that my CWinApp had a CFrameWnd class that I had forgotten about; I was focusing too much on the CView class.
In the CFrameWnd class, in the BEGIN_MESSAGE_MAP block, there was an ON_WM_TIMER(). I removed this from the message-map to test, and the AfxMessageBox() worked as expected.
When I create a fresh SDI application, there is no ON_WM_PAINT() in the message-map block, so I think this may have been added incorrectly. The class itself does not implement OnPaint(), so I guess this caused some unhandled WM_PAINT messages to be floating around.
It's a bit surprising that this doesn't lead to a compiler error; as I understand it, having ON_WM_PAINT() only makes sense if there's a corresponding OnPaint() function.
I'm trying to use SendMessage to post mouse clicks to a background window (Chrome), which works fine, but brings the window to front after every click. Is there any way to avoid that?
Before anyone says this is a duplicate question, please make sure that the other topic actually mentions not activating the target window, because I couldn't find any.
Update: aha, hiding the window does the trick, almost. It receives simulated mouse/keyboard events as intended, and doesn't show up on screen. However, I can just barely use my own mouse to navigate around the computer, and keyboard input is completely disrupted.
So my question is, how does sending messages to a window affect other applications? Since I'm not actually simulating mouse/keyboard events, shouldn't the other windows be completely oblivious to this?
Is it possibly related to the window calling SetCapture when it receives WM_LBUTTONDOWN? And how would I avoid that, other than hooking the API call (which would be very, very ugly for such a small task)?
The default handling provided by the system (via DefWindowProc) causes windows to come to the front (when clicked on) as a response to the WM_MOUSEACTIVATE message, not WM_LBUTTONDOWN.
The fact that Chrome comes to the front in response to WM_LBUTTONDOWN suggests that it's something Chrome is specifically doing, rather than default system behaviour that you might be able to prevent in some way.
The source code to Chrome is available; I suggest you have a look at it and see if it is indeed something Chrome is doing itself. If so, the only practical way you would be able to prevent it (short of compiling your own version of Chrome) is to inject code into Chrome's process and sub-class its main window procedure.
When handling the WM_PAINT message, I omitted the BeginPaint and EndPaint calls, and the CPU usage shot up to 100%. Why is this?
I'm also using worker threads... but they do something different and seem to have no influence on this matter.
Also, can I use the device context from GetDC() rather than BeginPaint? They seem to have different values so I thought they had different jobs.
Sorry if I sound like an idiot - I'm new to WinAPI, C++ and just the world of logic in general...
Thanks
This is entirely normal. Windows generates the WM_PAINT message when your window's update region in not empty. What you are supposed to do is mark it empty again. You do so, for example, by calling Begin/EndPaint().
If you don't then Windows immediately generates yet another WM_PAINT message, still trying to get the update region emptied. Your thread will burn 100% core, idly processing WM_PAINT messages and not actually getting the job done. Maybe you are actually painting, Windows just doesn't know what you painted and doesn't try to guess at it.
Using Begin/EndPaint() is very much the sane way to get that job done. It isn't the only way, you could also call ValidateRect() or ValidateRgn(). As long as you are "new to winapi", I'd very strongly recommend you do this the normal way.
Not sure if this is the case, but beginpaint and endpaint also validates drawn region of window, if you dont use them then windows is not aware that you have redrawn this region.You can call ValidateRect function to inform of the fact that window was redrawn.
Not sure if this will help in your case, you can read more on tjis in following so
Difference between GetDC() and BeginPaint()
GDI issues the WM_PAINT message to update a part of the window. BeginPaint/EndPaint() informs gdi that the handler is doing that job. In absence of a BeginPaint() for the specified region, until the window is updated (by someone) WM_PAINT messages will be generated. This is the reason you need BeginPaint/EndPaint() in a WM_PAINT handler and in absence of which you see a high CPU utilization.
GetDC() is not a substitute for Begin+EndPaint() because of the reason mentioned in my previous paragraph.
I have a custom control, which owns an edit box and moves it around, etc. The edit-box is typically modified with a wodge of code like this:
edit.MoveWindow( &rc );
edit.SetWindowText( text );
edit.SetLimitText( N );
edit.ShowWindow(SW_SHOW);
edit.SetFocus();
edit.SetSel(0, CB_ERR);
RECT rc is in coordinates local to the custom control, edit is created with the custom control as parent. I'm not even sure this is definitely the problem, but when triggering this code sometimes it is nice and smooth, other times my entire desktop appears to flicker like it's being redrawn. I can't see I'm explicitly calling Invalidate(Rect) anywhere.
Any ideas?
It's not going to be any of the code that you are showing us. A whole desktop flash is nearly always somewhere in your code that is calling InvalidateRect(NULL,...) so keep digging.
Several of these calls will result in messages being sent to the parent window of the edit, most likely the InvalidateRect is happening while handling that message.
If I was a betting man, I'd bet on the SetFocus() call as the one that's triggering the repaint.
I am having trouble getting a global system hook to work. I want to be notified whenever a window is moving, as early as possible, and change the window size. This means the CBT hook HCBT_MOVESIZE won't cut it, it only happens after the window has been moved. I want to hook the actual movement of the window, and be able to change the window size during the move.
The hooks are set from a DLL, and the callback function is within that DLL. This is what I've tried.
WH_CALLWNDPROC. It does alert me when a window is moved (WM_MOVING is received for windows from other applications), but I cannot change the contents of the message.
WH_CALLWNDPROCRET Same as WH_CALLWNDPROC.
CBT hook HCBT_MOVESIZE. Event happens to late.
WH_GETMESSAGE. Never receive WM_MOVE, WM_MOVING or WM_WINDOWPOSCHANGING. This hook would allow me to change the messages.
Update: Windows event hooks seem to allow me to capture it:
hWinEventHook = SetWinEventHook(EVENT_SYSTEM_MOVESIZESTART,
EVENT_SYSTEM_MOVESIZEEND, NULL, WinEventProc,
0, 0, WINEVENT_OUTOFCONTEXT | WINEVENT_SKIPOWNPROCESS);
However, this creates a different problem: changing the size of the window using SetWindowPos() does not work (it changes size alright, but immediately changes back to its previous size), even though I use SWP_NOSENDCHANGING. Ideas?
Update 2: Subclassing seems to work, however Visual Studio crashes after each program run (so does a lot of other windows). It works well if I place breakpoints and walk through the "unsubclassing", but not when I let the program run by itself. Ideas?
I have a CBT hook (it was there from earlier), and whenever HCBT_ACTIVATE is sent for a new window, I remove any previous subclassing using SetWindowLongPtr() (this has to run on 64-bit as well), and then subclass the new window. If I put a breakpoint anywhere, and immediately resume the session when it breaks, everything works fine. However, when I do not have any breakpoints, Visual Studio crashes when the program exits.
Hm, I would've thought that HCBT_MOVESIZE is precisely what you want, given that the MSDN says this about CBT hooks:
The system calls this function before activating, creating, destroying,
minimizing, maximizing, moving, or sizing a window.
and in particular:
HCBT_MOVESIZE
A window is about to be moved or sized.
(these quotes were taken from http://msdn.microsoft.com/en-us/library/ms644977%28VS.85%29.aspx)
...so I'd have thought that you get the HCBT_MOVESIZE call in time. The hook function which handles HCBT_MOVESIZE is also allowed to return an integer so that the system can determine whether the operation is allowed or should be prevented. Hence, given that the HCBT_MOVESIZE hook should get an option to prevent the operation, I'd say it's called before the move event occurred.
Are you really sure the hook function is called after the move event? If you do a GetWindowRect call on the particular handle within your hook function, does the returned rect equal the rectangle which is passed to the hook function?
Hooks are pretty heavy. You only want to use them when you absolutely have to.
That said, you could use one of the basic hooks simply as a way to get into the process. Once in the process, you could subclass the window you're interested in and handle the sizing messages in your subclass proc rather than trying to catch everything at the hook level.
Depending on what you want to do in response to the resize, you might need some interprocess communication.