Get HWND of a window i clicked on - c++

I'm making a program, with c++ and winapi, where you can click a button, then select a window and it changes the transparency of that window.
I have no problems of making the window transparent, but i can't get the hwnd of a window.
When I use this function the program just crashes (No errors are being printed to the console).
HWND getHWND(HWND self)
{
HWND found = GetForegroundWindow();
if(found == self || found == NULL)
return getHWND(self);
return found;
}
I tried using this, but I don't like it, because the user has only 2 seconds to click on another window. (I'know I could use a bigger delay, but then it might be to much.. so this isn't optimal)
HWND getHWND()
{
Sleep(2000);
return GetForegroundWindow();
}

Don't poll for the active window, especially not with a recursive function. Just let the OS notify you when a window is clicked.
When the user clicks on your button, you can use SetCapture(), or a mouse hook via SetWindowsHookEx(), to direct subsequent mouse clicks to your app even if they are clicking on someone else's window. When you detect a click, release the capture/hook, and then use WindowFromPoint() to get the HWND at the location of the click.

Related

A message box that never loses focus

A message box created with
MessageBox (NULL, "Text", "Title", MB_ICONINFORMATION | MB_SYSTEMMODAL);
stays on top of other windows, but it loses keyboard focus when the user clicks another window.
How could I create a message box (or an Edit box or a dialog box) that never loses keyboard focus, so if I try to switch to another window using [ALT-TAB] or mouse or any other method, or if another application running in a background opens its own Edit box, the keyboard focus would jump back to my message / Edit box?
The standard MessageBox function doesn't have such an option, so I tried a custom Edit box. I experimented with WM_SETFOCUS, WM_KILLFOCUS, WM_NCACTIVATE, SetForegroundWindow, SetFocus, but had no luck so far. When I open another window, the keyboard focus stubbornly goes to that window.
RegisterHotKey(0,1,MOD_ALT,VK_TAB); //disables alt+tab until message box returns
SetTimer(hwnd,1,100,0); //0.1 sec is enough for message box window creation
MessageBox(0,"Text","Title",MB_ICONINFORMATION|MB_SYSTEMMODAL); //since it's system modal, main message loop will wait for it to return
ClipCursor(0); //frees cursor
UnregisterHotKey(0,1); //enables alt+tab again
Here we use a timer to clip cursor so that user won't be able to click outside of the message box. I left title part of the messagebox outside of the clip area because clicking there negates cursor clipping.
case WM_TIMER:
{
KillTimer(hwnd,1);
RECT rc;
GetWindowRect(FindWindow(0,"Title"),&rc);
rc.top+=22; //title area left out of clip area
ClipCursor(&rc); //user cannot move their mouse outside of the message box
break;
}
This however can't block Ctrl + Alt + Del but does what you ask.

Client area erased on WM_NCACTIVATE when DPI Aware, fullscreen and frameless

I'm writing a program which needs a DPI aware, borderless fullscreen top-level OpenGL window.
The program has only this main window for 99% of the time.
The problem I'm having is the client area of the window is erased by windows when the window becomes inactive.
This only occurs when DPI aware, fullscreen and borderless(i.e. zero non-client area).
I have found a workaround to this, by catching WM_NCACTIVATE and returning 0 which prevents windows from processing the NC redraw. It seems that the windows non-client redraw procedure erases the client area if the non-client area is zero.
But, when I create a DialogBox (child of main hWnd), it causes the main window to become inactive (obviously).
If I return 0 from WM_NCACTIVATE, mouse and keyboard events do not get passed to the dialog box proc so the program becomes locked.
Using a global flag I can deactivate the workaround before creating the dialog, then redraw my main GL screen on WM_INITDIALOG but this causes a rather ugly screen flash that I'm trying to prevent.
So my question is: How do I prevent windows from erasing my client are of main wnd, without suppressing WM_NCACTIVATE?
Alternately: How to avoid the window erase, delay, then redraw flash that occurs when creating the dialog?
FYI,
The code I'm using to create the main window, run the message loop and draw a GL scene is essentially pinched from the HeNe examples.
I know these are very dated, but I find them easy to build from.
I've changed the HeNe code to WinMain() and perform my OpenGL drawing only as the program requires (outside of the main loop and outside of WM_PAINT).
Redrawing the scene and SwapBuffers() inside of WM_PAINT and WM_NCPAINT does not fix the problem.
To make the window fullscreen, I use Raymond Chen's code:
https://devblogs.microsoft.com/oldnewthing/20100412-00/?p=14353
I have also tried c-smile's code to make fullscreen, which behaves identically to Raymond Chen's:
Windows 10, DPI scaling and fullscreen
For the record, I'm using PerMonitor V2 but it dosent seem to matter which mode I use. Ive tried setting using both API and manifest file.
VS2019 v142; SDK 10.0.18362.0
I resolved this for a Qt application on Win10. My program is DPI aware and borderless, but is not fullscreen. Nevertheless, I had the same issue where:
I would get an unpleasant flicker when activating/deactivating the window
Unconditionally returning true for WM_NCACTIVATE WndProc calls would fix the flicker but would prevent dialogs capturing input
The flicker occurs without WM_NCPAINT having been called; there is no opportunity to prevent the redraw.
To resolve this, I had to change how I remove the non-client area. Previously I was using a Qt-specific function on window creation like so:
setWindowFlag(Qt::FramelessWindowHint);
I removed that and added a handler for WM_NCCALCSIZE calls which unconditionally returns 0. That removed the non-client area and, for whatever reason, doesn't cause the redraw on activation despite not having a handler for WM_NCACTIVATE.
In short, the only thing I do to remove the non-client rect is handle WM_NCCALCSIZE. I don't call into any WINAPI functions. I don't override WM_NCACTIVATE because doing so prevents dialogs from working correctly.
Here's my WndProc in full. This is for a Qt application, but nativeEvent is just a thin wrapper around the native WndProc.
bool MainWindow::nativeEvent(const QByteArray& eventType, void* message, long* result)
{
MSG* msg = static_cast<MSG*>(message);
LRESULT hitTestResult = 0;
auto handled = DwmDefWindowProc(msg->hwnd, msg->message, msg->wParam, msg->lParam, result);
if (handled)
return true;
static bool resizing = false;
switch (msg->message)
{
case WM_NCHITTEST:
*result = HitTestNCA(msg->hwnd, msg->wParam, msg->lParam, this);
if (*result != HTNOWHERE)
return true;
return false;
case WM_NCCALCSIZE:
// Setting the result to zero removes the non-client rect. This is
// a hardcoded Microsoft thing.
*result = 0;
return true;
default:
return false;
}
// Unreachable
}

SW_SHOWNOACTIVATE does not work if program is minimized by clicking the taskbar button

My application can receive a message from another application. If the app is minimized, I want to restore it to the previous state without giving focus to it.
I'm doing it by calling
::ShowWindow(hWnd, SW_SHOWNOACTIVATE);
It works well if the app was minimized using the Minimize button in the title bar, but if the app was minimized by clicking its button in the Windows task bar, then the app will receive focus.
Can this be fixed or worked around?
You could do the following HWND hwndForegroundWindow = GetForegroundWindow() before your ShowWindow function call. Afterwards you can restore the foreground window with SetForegroundWindow(hwndForegroundWindow). It depends on what you mean with focus though, foreground window and focus are something different (For element focus use GetFocus and SetFocus).

Undock a child window from main application

let's say i have a big application with a few child windows inside of it. ( example )
Now, i am trying to undock one of those "inside windows" to a new serperated window, which i can move all over the place!
What i have done so far:
HWND oldHWND = SetParent(hwnd, NULL);
SendMessage(oldHWND, WM_SYSCOMMAND, SC_CLOSE, 0);
All this works very well, but i am not able to move the new window and i am not able to close it, because there is no window frame and no close button.
Do you have any suggestions for me?
Thank you very much!
Register a suitable window class for your undocked "floating" window with a frame/close button etc, and then make the undocked window a child of that.

Hiding an MFC dialog box

Ok so I am using this code to hide the taskbar icon of a dialog based MFC application(VC++). The taskbar icon and the dialog box hide whenever I click on the cross or the close buttons. But I can’t get this one thing right. Whenever I hit the close or the cross button from title bar, the dialog box first flickers and shows a sort of intermediate dialog box and then hides. This is very annoying. I am posting my code here after two days of vain effort. So guys please help me. Thanks in advance.
void CMyAppDlg::OnBnClickedCancel()
{
// TODO: Add your control notification handler code here
CWnd* pWnd;
pWnd = AfxGetMainWnd();
RemoveTaskbarIcon(pWnd);
pWnd->ModifyStyle(WS_VISIBLE, 0);
mVisible = FALSE;
}
BOOL CMyAppDlg::RemoveTaskbarIcon(CWnd* pWnd)
{
LPCTSTR pstrOwnerClass = AfxRegisterWndClass(0);
// Create static invisible window
if (!::IsWindow(mWndInvisible.m_hWnd))
{
if (!mWndInvisible.CreateEx(0, pstrOwnerClass, _T(""),
WS_POPUP,
CW_USEDEFAULT,
CW_USEDEFAULT,
CW_USEDEFAULT,
CW_USEDEFAULT,
NULL, 0))
return FALSE;
}
pWnd->SetParent(&mWndInvisible);
return TRUE;
}
Here are the screen shots of dialog box. When I press the close or cross button, the dialog box which looks like this in the first place turns into this for like less than half a second and then disappears (hides).
If you show your dialog using CDialog::DoModal() the framework will make sure your dialog is shown. There is only one way to prevent a modal dialog from being shown:
BEGIN_MESSAGE_MAP(CMyDialog, CDialog)
ON_WM_WINDOWPOSCHANGING()
END_MESSAGE_MAP()
BOOL CHiddenDialog::OnInitDialog()
{
CDialog::OnInitDialog();
m_visible = FALSE;
return TRUE;
}
void CHiddenDialog::OnWindowPosChanging(WINDOWPOS FAR* lpwndpos)
{
if (!m_visible)
lpwndpos->flags &= ~SWP_SHOWWINDOW;
CDialog::OnWindowPosChanging(lpwndpos);
}
I think Paul DiLascia recommended the following. This is for modal dialogs only.
The following code can be put in OnInitDialog to move the dialog off-screen. You will need to implement a method for moving it back on-screen when appropriate.
CRect DialogRect;
GetWindowRect(&DialogRect);
int DialogWidth = DialogRect.Width();
int DialogHeight = DialogRect.Height();
MoveWindow(0-DialogWidth, 0-DialogHeight, DialogWidth, DialogHeight);
The answer from l33t looks good and is probably better but this is an alternative.
Maybe an obvious thing, but what happens when you do the hide before you reparent the dialog? Also what if you don't directly modify the window style but use ShowWindow(SW_HIDE)?
Finally, have you tried switching the dialog's window style to WS_CHILD before calling SetParent() and/or maybe moving it out of the client area so that the window isn't shown any more (MoveWindow(-1000, -1000) or something like that).