I maintain a C++ application that uses flash ocx to play SWF file.
When user hovers on button in SWF, flash internally makes a call to WinAPI SetCursor function to set IDC_HAND cursor - I can see that when I monitor WinAPI calls to cursor-related function via API Monitor V2 (rohitab.com). However, in my case the cursor is not changing, i.e. stays IDC_ARROW.
The application itself does not call SetCursor at all. The window of the application processes WM_SETCURSOR message as following, i.e. does not restore the cursor:
case WM_SETCURSOR:
{
static bool restoreCursor = false;
if (LOWORD(lParam) != HTCLIENT)
{
restoreCursor = true;
}
if (restoreCursor)
{
restoreCursor = false;
// DefWindowProc will set the cursor
break;
}
return 1;
}
Can anyone please let me know who can reset/change cursor shape in this case?
Update: The interesting part is the fact that I have 2 similar setups that produce the opposite results.
The application I maintain actually installs a WH_GETMESSAGE hook on "SysListView32" and launches a thread that creates Flash player. So the setup is not that straight-forward.
However, if I just create a simple example that creates a player at, basically, winmain, then the code above works perfectly and cursor gets changed.
So it appears that something does reset the cursor state in the first case. How to find out what resets the cursor?
OK, the real answer on this question is that non-GUI thread cannot change the cursor directly.
See the comments in the bottom of the page
http://msdn.microsoft.com/en-us/library/windows/desktop/ms648393%28v=vs.85%29.aspx
Another solution can be detouring/hooking the SetCursor function to ours that just sends a user message to GUI thread, signalling to set the cursor.
Both solutions have their pros and, of-course :), cons.
Your window (the parent) gets a crack at overriding the cursor and returning TRUE (1) indicated that you handled it and halts further processing. The arrow is probably coming from your WNDCLASS registration or from DefWindowProc.
So, it seems to me that you'd want to return FALSE to allow the child button a crack at actually setting the cursor. Or, remove handing WM_SETCURSOR altogether.
Related
In an older MFC application I have to perform a network connect request to another computer which may take a number of seconds in the case of incorrect computer name before the request times out. So I am starting up a worker thread to make the initial connection so that the user interface is still responsive.
The network connect request is triggered by the user selecting a menu item which brings up a dialog to fill in the target computer information. When the user clicks the Ok button on the dialog, the network connection request is processed using the worker thread.
What I want to do is to change the mouse cursor to a wait indicator and then remove the wait indicator once the connection is actually made or the attempt times out.
What I am running into is that the mouse cursor is remaining a pointer and the mouse cursor is not changing to a wait indicator.
What I originally thought was that I could just change the mouse cursor using the BeginWaitCursor() function. However that has no effect that I can see.
Further reading indicates that I also need to have an override of the afx_msg BOOL OnSetCursor(CWnd* pWnd, UINT nHitTest, UINT message) method of the CScrollView class however I can't seem to find anything helpful that describes what I need to do in that method. The OnSetCursor() method seems to be called for a variety of reasons and just moving the mouse causes a breakpoint in that method to be triggered.
It looks like that in the OnSetCursor() method I should detect the current application state and based on that use the SetCursor() function to set one of the possible mouse cursor styles which have been previously loaded with LoadCursor(). See Prevent MFC application to change cursor back to default icon as well as Change cursor for the duration of a thread
However I am unsure at to whether that is how it is actually done and what the parameters that are provided with the OnSetCursor() actually mean and how to use them.
In the second of the two above SO postings it appears a global is being used to decide if the default CView::OnSetCursor() method is being called or not.
First declare the following global variables:
BOOL bConnecting = FALSE; // TRUE if connecting, set by your application
HCURSOR hOldCursor = NULL; // Cursor backup
When you need to display the hourglass cursor call:
bConnecting = TRUE;
hOldCursor = SetCursor(LoadCursor(NULL, IDC_WAIT));
Once the connection is established (or failed) call:
bConnecting = FALSE;
SetCursor(hOldCursor);
// Alternatively you can call SetCursor(LoadCursor(NULL, IDC_ARROW)); - no need to backup the cursor then
// Or even not restore the cursor at all, it will be reset on the first WM_MOUSEMOVE message (after bConnecting is set to FALSE)
You also need to override OnSetCursor():
BOOL CMainFrame::OnSetCursor(CWnd* pWnd, UINT nHitTest, UINT message)
{
if (bConnecting) return TRUE; // Prevent MFC changing the cursor
// else call the default
return CFrameWndEx::OnSetCursor(pWnd, nHitTest, message);
}
And add the ON_WM_SETCURSOR() directive to the message map for CMainFrame in order to enable the OnSetCursor() message handler.
The "main-frame" is the parent of all windows in an MFC Application, and that's why we override OnSetCursor() for it. It affects all other windows.
In the MFC environment you can also use the BeginWaitCursor(), RestoreWaitCursor(), and EndWaitCursor() functions. These are CCmdTarget methods and can be accessed using AfxGetApp() as well as any CWnd derived class.
Note that using a global variable in a multi-threaded environment with both UI thread and worker threads, depending on how the global is used and accessed by the threads, you may create a race condition.
#Constantine's OnSetCursor implementation didn't work for me (VC++ 2013; Win 10) - wait cursor still went back to arrow after starting a thread. But I resolved my issue with following code.
BOOL CMainFrame::OnSetCursor(CWnd* pWnd, UINT nHitTest, UINT message)
{
if (bConnecting) {
SetCursor(LoadCursor(NULL, IDC_WAIT));
return TRUE; // Prevent MFC changing the cursor
}
// else call the default
return CFrameWndEx::OnSetCursor(pWnd, nHitTest, message);
}
Note that that all opened dialogs or views should have the OnSetCursor if you want to display wait cursor when hovering on the views.
I currently have a small game which runs in a win32 window. I just noticed that when I hold the top of the window (the bar which has the closing button) it freezes my application. I would like to disable this as it manages to completely destroy my application (timers continue to count).
It seems that with even the most minimalistic settings for creation of the window it still has this feature. How can I disable this? I currently have:
HWND hWnd = CreateWindowW( L"Game",L"Game",
0x00000000L | 0x00080000L,
wr.left,
wr.top,
wr.right-wr.left,
wr.bottom-wr.top,
NULL,
NULL,
wc.hInstance,
NULL );
I read that my thread is ignored while dragging, if I am forced into using 2 threads could someone please provide a small example of usage?
Or should I stop the timers? (what message should I catch, and would it even be catched?)
Update
I am using instances of my time class to handle timings which looks something like:
Timer::Timer() {
__int64 frequency;
QueryPerformanceFrequency( (LARGE_INTEGER*)&frequency );
invFreqMilli = 1.0f / (float)((double)frequency / 1000.0);
StartWatch();
}
void Timer::StartWatch() {
startCount = 0;
currentCount = 0;
watchStopped = false;
QueryPerformanceCounter( (LARGE_INTEGER*)&startCount );
}
My Win32 message loop contains: mousemove, keyup and keydown.
When DefWindowProc handles WM_SYSCOMMAND with either SC_MOVE or SC_SIZE in the wParam, it enters a loop until the user stops it by releasing the mouse button, or pressing either enter or escape. It does this because it allows the program to render both the client area (where your widgets or game or whatever is drawn) and the borders and caption area by handling WM_PAINT and WM_NCPAINT messages (you should still receive these events in your Window Procedure).
It works fine for normal Windows apps, which do most of their processing inside of their Window Procedure as a result of receiving messages. It only effects programs which do processing outside of the Window Procedure, such as games (which are usually fullscreen and not affected anyway).
However, there is a way around it: handle WM_SYSCOMMAND yourself, resize or move yourself. This requires a good deal of effort, but may prove to be worth it. Alternatively, you could use setjmp/longjmp to escape from the Window Procedure when WM_SIZING is sent, or Windows Fibers along the same lines; these are hackish solutions though.
I solved it (using the first method) this past weekend, if you're interested I have released the code to the public domain on sourceforge. Just make sure to read the README, especially the caveat section. Here it is: https://sourceforge.net/projects/win32loopl/
Since the title bar to the user that he/she can move the window, you could remove that title bar and borders altogether. See "opening a window that has no title bar with win32" for an example.
When the game launches or is paused, you could show your own UI elements to allow the user to move the game window in these specific situations but only then.
You can check for the size/move loop using the WM_ENTERSIZEMOVE and WM_EXITSIZEMOVE messages.
I originally had an ActiveX control that registered a Windows timer (with SetTimer()) that fires every few seconds. That worked fine so far. Now in order to implement a full screen mode, I added a child window to my control that is supposed to show the content while the control itself manages all the ActiveX stuff.
The problem that I have with this approach is that my WM_TIMER suddenly stops firing at some time. I have traced it back to UIDeactivate() being called on my control but I don't know why this method is called (I believe it has something to do with losing focus) when it wasn't called before.
I would also like to know why my WM_TIMER events suddenly stop while everything else still seems to work fine. And what could it have to do with showing the content in a child window instead of on the ActiveX control itself?
Timers stops for a reason. Which might be:
You do stop timer by KillTimer call
Your window is re-created and timer is not re-enabled
Your control is windowless and you actually don't have a HWND handle
There is a collision in timer identifiers, there is something else (e.g. internal subclassed window) out there to use the same identifier, it sets, kill the timer and you no longer see WM_TIMER messages you enabled earlier
The window thread is busy (frozen) with some activity which does not include message dispatching, so timer itself exists, is healthy and alive, just no messages sent
The things to do - without yet additional information on the issue on hands:
Check threads of your window, and your Set/KillTimer calls to make sure they all make sense together
Use Spy++ tool to check messages posted for your window and/or in the thread of the interest, to find out if you really have WM_TIMERs missing, or they just don't reach your code; also you might see other interesting messages around
Here's an excerpt from ATL implementation of CComControlBase (I would guess that your control inherits from that). Check the part marked with <<<<<<<<<<<:
inline HRESULT CComControlBase::IOleInPlaceObject_InPlaceDeactivate(void)
{
if (!m_bInPlaceActive)
return S_OK;
if(m_bUIActive) {
CComPtr<IOleInPlaceObject> pIPO;
ControlQueryInterface(__uuidof(IOleInPlaceObject), (void**)&pIPO);
ATLENSURE(pIPO != NULL);
pIPO->UIDeactivate();
}
m_bInPlaceActive = FALSE;
// if we have a window, tell it to go away.
//
if (m_hWndCD)
{
ATLTRACE(atlTraceControls,2,_T("Destroying Window\n"));
if (::IsWindow(m_hWndCD))
DestroyWindow(m_hWndCD); <<<<<<<<<<<<<<<<<<<<<<<<<<<
m_hWndCD = NULL;
}
if (m_spInPlaceSite)
m_spInPlaceSite->OnInPlaceDeactivate();
return S_OK;
}
On deactivation, the control window gets destroyed. Therefore it can't process WM_TIMER anymore.
This is a more concrete question that is connected with my previous one.
I have an application that uses a timer. The code is written the way the my WM_TIMER handler call a DialogBoxParam(...) with some custom message handler (let's call it DlgProc).
This is done somewhat the following way:
case WM_TIMER:
{
// Routine, that displays a special message box
DisplayMessageBox(...);
return 0;
}
Now, if I make DlgProc handle the messages like this (see the code), this would result in tons of dialog boxes (one per WM_TIMER call).
switch (msg)
{
case WM_INITDIALOG:
// (...)
return TRUE;
case WM_COMMAND:
// (...)
return TRUE;
return FALSE;
}
But if I add a dummy WM_PAINT handler (return TRUE;) to my DlgProc, this results in exactly one shown DialogBox and 100% CPU load (that's because I receive tons of WM_PAINT messages).
Q:
What can be done here if I want my application to show exactly ONE dialog box and have no CPU load for WM_PAINT processing? (I mean like, have behaviour similiar to draw unique dialog box and fully pause the parent window).
Also it would be great if someone explains what actually happens in this situation and why do I receive gazillions of WM_PAINT messages to my dialog box and why their processing (with return TRUE) results in preventing the other dialog boxes creation.
Thank you.
1) You should disable the timer after the first WM_TIMER signal is caught if you want to show only one single dialog box. You can do this using KillTimer().
2) Windows wants to keep the GUI up-to-date. Whenever a region on the screen should be updated, it is invalidated using InvalidateRect or InvalidateRgn. Now, for every "invalid" screen part, WM_PAINT is called in order to make in "valid" again.
If you don't do it (or just parts of it), Windows will call WM_PAINT again ... and again. One way is to call ValidateRect. In many cases BeginPaint() and EndPaint() are used to do the job.
3) Maybe most important: you should not just return FALSE! Try DefWindowProc() for windows and DefDlgProc() for dialogs. They will also take care of WM_PAINT appropriately.
It's not that you registered for WM_PAINT, something must cause it (even if you don't add WM_PAINT: handler), look for re/draw functions (like InvalidateRect())
So I've got an application whose window behavior I would like to behave more like Photoshop CS. In Photoshop CS, the document windows always stay behind the tool windows, but are still top level windows. For MDI child windows, since the document window is actually a child, you can't move it outside of the main window. In CS, though, you can move your image to a different monitor fine, which is a big advantage over docked applications like Visual Studio, and over regular MDI applications.
Anyway, here's my research so far. I've tried to intercept the WM_MOUSEACTIVATE message, and use the DeferWindowPos commands to do my own ordering of the window, and then return MA_NOACTIVATEANDEAT, but that causes the window to not be activated properly, and I believe there are other commands that "activate" a window without calling WM_MOUSEACTIVATE (like SetFocus() I think), so that method probably won't work anyway.
I believe Windows' procedure for "activating" a window is
1. notify the unactivated window with the WM_NCACTIVATE and WM_ACTIVATE messages
2. move the window to the top of the z-order (sending WM_POSCHANGING, WM_POSCHANGED and repaint messages)
3. notify the newly activated window with WM_NCACTIVATE and WM_ACTIVATE messages.
It seems the cleanest way to do it would be to intercept the first WM_ACTIVATE message, and somehow notify Windows that you're going to override their way of doing the z-ordering, and then use the DeferWindowPos commands, but I can't figure out how to do it that way. It seems once Windows sends the WM_ACTIVATE message, it's already going to do the reordering its own way, so any DeferWindowPos commands I use are overridden.
Right now I've got a basic implementation quasy-working that makes the tool windows topmost when the app is activated, but then makes them non-topmost when it's not, but it's very quirky (it sometimes gets on top of other windows like the task manager, whereas Photoshop CS doesn't do that, so I think Photoshop somehow does it differently) and it just seems like there would be a more intuitive way of doing it.
Anyway, does anyone know how Photoshop CS does it, or a better way than using topmost?
I havn't seen anything remarkable about Photoshop CS that requries anything close to this level of hacking that can't instead be done simply by specifying the correct owner window relationships when creating windows. i.e. any window that must be shown above some other window specifies that window as its owner when being created - if you have multiple document windows, each one gets its own set of owned child windows that you can dynamically show and hide as the document window gains and looses activation.
You can try handle WM_WINDOWPOSCHANGING event to prevent overlaping another windows (with pseudo-topmost flag). So you are avoiding all problems with setting/clearing TopMost flag.
public class BaseForm : Form
{
public virtual int TopMostLevel
{
get { return 0; }
}
[DllImport("user32.dll")]
[return: MarshalAs(UnmanagedType.Bool)]
static extern bool EnumThreadWindows(uint dwThreadId, Win32Callback lpEnumFunc, IntPtr lParam);
/// <summary>
/// Get process window handles sorted by z order from top to bottom.
/// </summary>
public static IEnumerable<IntPtr> GetWindowsSortedByZOrder()
{
List<IntPtr> handles = new List<IntPtr>();
EnumThreadWindows(GetCurrentThreadId(),
(hWnd, lparam) =>
{
handles.Add(hWnd);
return true;
}, IntPtr.Zero);
return handles;
}
protected override void WndProc(ref Message m)
{
if (m.Msg == (int)WindowsMessages.WM_WINDOWPOSCHANGING)
{
//Looking for Window at the bottom of Z-order, but with TopMostLevel > this.TopMostLevel
foreach (IntPtr handle in GetWindowsSortedByZOrder().Reverse())
{
var window = FromHandle(handle) as BaseForm;
if (window != null && this.TopMostLevel < window.TopMostLevel)
{
//changing hwndInsertAfter field in WindowPos structure
if (IntPtr.Size == 4)
{
Marshal.WriteInt32(m.LParam, IntPtr.Size, window.Handle.ToInt32());
}
else if (IntPtr.Size == 8)
{
Marshal.WriteInt64(m.LParam, IntPtr.Size, window.Handle.ToInt64());
}
break;
}
}
}
base.WndProc(ref m);
}
}
public class FormWithLevel1 : BaseForm
{
public override int TopMostLevel
{
get { return 1; }
}
}
So, FormWithLevel1 will be always over any BaseForm. You can add any number of Z-order Levels. Windows on the same level behave as usual, but will be always under Windows with level Current+1 and over Windows with level Current-1.
Not being familiar to Photoshop CS it is bit hard to know exactly what look and feel you are trying to achieve.
But I would have thought if you created a modeless dialog window as you tool window and you made sure it had the WS_POPUP style then the resulting tool window would not be clipped to the main parent window and Windows would automatically manage the z-Order making sure that the tool window stayed on top of the parent window.
And as the tool window dialog is modeless it would not interfere with the main window.
Managing Window Z-Order Like Photoshop CS
You should create the toolwindow with the image as the parent so that windows manage the zorder. There is no need to set WS_POPUP or WS_EX_TOOLWINDOW. Those flags only control the rendering of the window.
Call CreateWindowEx with the hwnd of the image window as the parent.
In reply to Chris and Emmanuel, the problem with using the owner window feature is that a window can only be owned by one other window, and you can't change who owns a window. So if tool windows A and B always need to be on top of document windows C and D, then when doc window C is active, I want it to own windows A and B so that A and B will always be on top of it. But when I activate doc window D, I would have to change ownership of tool windows A and B to D, or else they will go behind window D (since they're owned by window C). However, Windows doesn't allow you to change ownership of a window, so that option isn't available.
For now I've got it working with the topmost feature, but it is a hack at best. I do get some consolation in the fact that GIMP has tried themselves to emulate Photoshop with their version 2.6, but even their implementation occasionally acts quirky, which leads me to believe that their implementation was a hack as well.
Have you tried to make the tool windows topmost when the main window receives focus, and non-topmost when it loses focus? It sounds like you've already started to look at this sort of solution... but much more elaborate.
As a note, it seems to be quite well documented that tool windows exhibit unexpected behavior when it comes to z-ordering. I haven't found anything on MSDN to confirm it, but it could be that Windows manages them specially.
I would imagine they've, since they're not using .NET, rolled their own windowing code over the many years of its existence and it is now, like Amazon's original OBIDOS, so custom to their product that off-the-shelf (aka .NET's MDI support) just aren't going to come close.
I don't like answering without a real answer, but likely you'd have to spend a lot of time and effort to get something similar if Photoshop-like is truly your goal. Is it worth your time? Just remember many programmers over many years and versions have come together to get Photoshop's simple-seeming windowing behavior to work just right and to feel natural to you.
It looks like you're already having to delve pretty deep into Win32 API functions and values to even glimpse at a "solution" and that should be your first red flag. Is it eventually possible? Probably. But depending on your needs and your time and a lot of other factors only you could decide, it may not be practical.