WinApi, hide cursor inside window client area - winapi

I want hide cursor inside window client area without borders and title bar (it is simple opengl application). So, function
ShowCursor(FALSE);
is not suitable. After some searching the winapi i find this solution:
//when create window class for application window
WNDCLASSEX WndClass;
//...
BYTE CursorMaskAND[] = { 0xFF };
BYTE CursorMaskXOR[] = { 0x00 };
WndClass.hCursor = CreateCursor(NULL, 0,0,1,1, CursorMaskAND, CursorMaskXOR);
Is this a good way to solve this typical task? What way is the best?

MSDN says that you can set the WNDCLASSEX hCursor field to NULL, in which case you must explicitly set the cursor in your window procedure (which means handling the WM_SETCURSOR message). For example:
if (Msg == WM_SETCURSOR && LOWORD(lParam) == HTCLIENT)
{
SetCursor(NULL);
return TRUE;
}
// Remainder of window procedure code
Checking for HTCLIENT ensures that the cursor is only hidden in the client area, and that the window frame and caption will use the correct cursors.

The SetCursor() call you're using doesn't take a BOOL - it takes an HCURSOR. So you're calling SetCursor( NULL ) which means "hide that cursor". What I found in the old days on Windows is that this is video driver dependent and many drivers don't respect it. The most consistent way to handle this is to make a transparent cursor resource in your app, and return a handle to that cursor in the WM_SETCURSOR message from your main window.

I found that first setting hCursor to NULL:
wc.hCursor = NULL;
and then setting the cursor to NULL:
SetCursor(NULL);
will make it disappear.
From MSDN, I read that the application will set its own cursor by default if one is not defined in hCursor. That's what the first line of code is doing.
Then, after the application sets its own cursor, I mess with it with the second line of code. Or at least, I think that's what happens.

Related

Any suggestions to effectively update the status bar of an application?

The status bar window of this program needs to be updated every time the user press a key that is likely to move the caret of the EDIT control, and the code below works like a charm! In a nutshell, pressing a key on the keyboard will update some values and send a message "ECM_GETLINEINFOS" that is next processed in the main window procedure (code below)
However, there is flickering that is not disturbing, of course, but I wonder if it's related to how I set the text on the status bar (maybe too many updates ?) or just a problem with the drawing part.
PS: The flickering occurs on the text, not the status bar in itself, so that is why I'm questioning how I should manage the update of my window.
constexpr int failed_val = -1;
LRESULT MainWindow::HandleMessage(UINT msg, WPARAM wParam, LPARAM lParam)
{
switch (msg)
{
// Custom message sent by an EDIT control, I
// use this message to tell the status bar it must update its text.
case CEM_GETLINEINFO:
{
const size_t buffSz = 24;
std::wstring buffer(buffSz, L'\0');
int line = LOWORD(wParam);
int column = HIWORD(wParam);
int count = _snwprintf_s(buffer.data(), buffer.size(),
_TRUNCATE, L"Ln %d, Col %d", line, column);
if (count != failed_val) {
// Param 1 : The text to be displayed
// Param 2 : Which status bar part
m_statusBar->SetText(buffer, 0);
}
}
return 0;
}
}
Just as Flicker-Free Displays Using an Off-Screen DC directed by the answer said,
What makes this window flicker when we update it frequently? The
answer is that Windows asks the window procedure to repaint the window
as a two-step process. First, it sends a WM_ERASEBKGND message and
then a WM_PAINT message. The default handling for the WM_ERASEBKGND
message is to fill the area with the current window background color.
So the sequence of events is first to fill the area with solid color
and then to draw the text on top. The net result of doing this
frequently is that the window state alternates between its erased
state and its drawn stateā€”it flickers.
And
To prevent the control from flickering when we update it frequently,
we need to make two changes to how the control handles messages.
First, we need to prevent Windows from providing the default handling
of WM_ERASEBKGND messages. Secondly, we need to handle WM_PAINT
messages so that the background is painted with the window background
color and so that the changes to the control's client area happen at
once.
A status bar flicker free solution in .NET: Searching Visual Studio .NET style status bar. Or Simple Mode Status Bars could be enough.

Disable cursor changing to SizeWE for some items in Win32 header

I need to prevent resizing of some items in a Win32 header control. No problem to process the HDN_BEGINTRACK notification message and cancel it - the problem is in the cursor indicating that the item can be resized. For instance, if the first item can't be resized, I see this:
, but I'd prefer to see this:
I can ignore the cursor change by suppressing the WM_SETCURSOR message, but the problem is how to know the header item WM_SETCURSOR is generated for. I can detect the item under the mouse pointer in WM_MOUSEMOVE using the HDM_HITTEST message, but WM_MOUSEMOVE is sent to window procedure only after WM_SETCURSOR. I analyzed all notification messages for the Win32 header control, and it seems, it does not have an equivalent of the MouseEnter event that is sent to the window procedure before WM_SETCURSOR.
Any ideas how to solve this problem?
You need to sub-class the header control if you haven't already.
In the sub-class, intercept the WM_SETCURSOR message, and use GetMessagePos() to get the coordinates of the mouse. These are in screen coordinates, so you need to convert them to client coordinates for the header control hit test.
// in the window sub-class
if (uMsg == WM_SETCURSOR)
{
DWORD dwPos = GetMessagePos();
HDHITTESTINFO hti;
hti.pt.x = GET_X_LPARAM(dwPos);
hti.pt.y = GET_Y_LPARAM(dwPos);
ScreenToClient(hWnd, &hti.pt);
SendMessage(hWnd, HDM_HITTEST, 0, reinterpret_cast<LPARAM>(&hti));
if (...) // test for items we want to block
{
SetCursor(LoadCursor(0, IDC_ARROW));
return TRUE;
}
// pass through to regular WndProc
}

Get the last ShowWindow state for a window in winapi

When you click a window in your taskbar (Windows users) it will retain it's last state - maximised or normal scalable window. I'm trying to do a similar thing, but programatically and without the window gaining focus (eg. becoming foreground and disturbing my current activity in another window).
Can I do that? Current window state can be obtained using this API call:
//Empty Window placement structure
WinDefExt.WINDOWPLACEMENT placement = new WinDefExt.WINDOWPLACEMENT();
//winapi call to external User32.dll file
UserExt.GetWindowPlacement(hwnd, placement);
//showCmd should be equal to one of the SW_ constants (here: https://msdn.microsoft.com/en-us/library/windows/desktop/ms633548%28v=vs.85%29.aspx)
placement.showCmd;
ShowWindow isn't a "state", it's an "action". There's no GetShowState command. You can infer a value from the current state of the window, but there's no way to find out the actual last value used with ShowWindow.
if (!IsWindowVisible(hWnd))
swState = SW_HIDE;
else
if (IsIconic(hWnd))
swState = SW_MINIMIZE;
else
if (IsZoomed(hWnd))
swState = SW_MAXIMIZE;
else
{
// not hidden, minimized or zoomed, so we are a normal visible window
// last ShowWindow flag could have been SW_RESTORE, SW_SHOW, SW_SHOWNA, etc
// no way to tell
swState = SW_SHOW;
}

How to get the specific foreground window of the application

Can I somehow get the specific foreground window of the application? For example, not the HWND of the whole Skype application, but some currently selected internal window of this application (maybe it's chat window's text edit).
Thanks in advance.
You can use EnumChildWindows.
Basically, it goes through the child windows of a given window until you find the one that has the characteristics you want. And - it is good to know that the "parent" of all application windows is HWND_DESKTOP
Here is code:
EnumChildWindows(HWND_PARENT,findChildWithClass,(LPARAM)"NetUIHWND");
And somewhere else:
BOOL CALLBACK findChildWithClass(HWND hwndTest,LPARAM lParam) {
char *pszClass = (char *)lParam;
char szClass[64];
GetClassName(hwndTest,szClass,64);
if ( strlen(szClass) < 1 ) return TRUE;
if ( 0 == _strnicmp(pszClass,szClass,min(strlen(pszClass),strlen(szClass))) ) {
hwndFoundChild = hwndTest;
return FALSE;
}
EnumChildWindows(hwndTest,findChildWithClass,lParam);
if ( hwndFoundChild )
return FALSE;
return TRUE;
}
So, the function "findChildWithClass" will be repeatedly called by Windows with the handle to the next child of the specified parent.
When the characteristics of that child window match what you are looking for, in this case class name, the function sets the value of a global static and returns FALSE to indicate the enumeration should stop.
You can get the class name of any window using Spy++, in this case, I used spy++ to find the name of the MS Word frame window. However, since the particular code will also look at every child of every child sent to it - you could have also found an "inner" window of MS Word using it. Also - you don't have to use class name, perhaps something else (window contents ?) is unique to the application you are trying to discover the window for ( Skype ? )

How can I notify an application of a programmatically set scrollbar value?

My code involves standard Scroll Bar control and it happens that I need to change its value programmatically in some cases. I do this using SetScrollInfo function, as in this example:
void setScrollBarValue( HWND scrollBar, int value )
{
SCROLLINFO si = { sizeof( SCROLLINFO ); }
si.fMask = SIF_POS;
si.nPos = value;
::SetScrollInfo( scrollBar, SB_CTL, &si, true /* redraw */ );
}
This appears to work fine (the thumb of the scrollbar moves around) but it fails to notify the rest of the application of the new scrollbar value. For instance, an edit control which uses the scroll bar (much like in the Windows notepad application) fails to scroll around because it doesn't get notified about the new scrollbar value.
In case it matters: the scrollbar I'm modifying is not in the same process as the above
setScrollBarValue function.
Does anybody know how to achieve this?
Edit: I found out how to do this with default window scrollbars (those of type SB_VERT or SB_HORZ). I can send the WM_HSCROLL and WM_VSCROLL to the window like this:
::SendMessage( windowContainingScrollBar,
WM_HSCROLL,
MAKEWPARAM( SB_THUMBPOSITION, si.nPos ), NULL );
However, in my case the scroll bar has a window handle of its own (it has the type SB_CTL). This means that I don't know the orientation of the scroll bar (so I cannot tell whether to send WM_HSCROLL or WM_VSCROLL) and I don't know what window to send the message to.
Try sending the WM_VSCROLL message after calling SetScrollInfo().

Resources