MFC/C++ Bring window to top no longer works - c++

I have a 32-bit application built on MFC/C++. It was ported from Visual C++ (6.0) to Studio 2015.
The application needs to come to the top when new data appears. On a couple of my customer systems the window does not come to the front as another application seems to want to stay on top. This code (in MainFrm.cpp) was working fine prior to the 2015 port (same "topmost" source code).
...
HWND hCurrWnd;
int iMyTID;
int iCurrTID;
hCurrWnd = ::GetForegroundWindow();
iMyTID = GetCurrentThreadId();
iCurrTID = GetWindowThreadProcessId(hCurrWnd,0);
::AttachThreadInput(iCurrTID, iMyTID, TRUE);
::SetWindowPos(m_hWnd, HWND_TOPMOST, 0, 0, 0, 0, SWP_NOSIZE | SWP_NOMOVE);
::SetWindowPos(m_hWnd, HWND_NOTOPMOST, 0, 0, 0, 0, SWP_SHOWWINDOW | SWP_NOSIZE | SWP_NOMOVE);
::SetForegroundWindow(m_hWnd);
::SetFocus(m_hWnd);
::SetActiveWindow(m_hWnd);
::AttachThreadInput(iCurrTID, iMyTID, FALSE);
...
Is there another, more robust method for forcing a window to the top in MFC?

Use MFC functions direct, not the underlying WinApi.
I tested this in Win10 with VS2019.
RESULT CMainFrame::OnNewDataReceived_UM( WPARAM wParam, LPARAM lParam )
{
:
if (IsIconic())
ShowWindow(SW_RESTORE);
SetForegroundWindow();
:
}
returen TRUE;
}

Related

Open Qt MainWindow on top of every other window in single instance Qt application version 5.11.1 in Visual Studio

I have made single instance running Qt application (Qt version 5.11.1) in Visual Studio. Once it executed the first time, my main window will open and I am closing it. It keeps running in the background.
When I run .exe the second time, I want to open the previous mainWindow which I opened the first time.
I am enumerating available windows title and I am getting "Test Window" title. but using this HWND I am trying to set in the foreground on top of every other window using SetForegroundWindow(hwnd);.
BOOL CALLBACK EnumWindowsProc(HWND hwnd, LPARAM lParam)
{
if (IsWindowVisible(hwnd)) // check whether window is visible
{
char wnd_title[256];
GetWindowText(hwnd, wnd_title, sizeof(wnd_title));
MessageBox(0, wnd_title, "Installation Error", MB_OK | MB_ICONEXCLAMATION);
if (strcmp(wnd_title, "Test Window") == 0)
{
SetForegroundWindow(hwnd);
int err = GetLastError();
string msg = "error code " + std::to_string(err);
MessageBox(0, msg.c_str(),"Installation Error ", MB_OK | MB_ICONEXCLAMATION);
return false;
}
}
return true; // function must return true if you want to continue enumeration
}
How do I open on Qt MainWindow on top of all other windows when I run second time.
check out the project QtSingleApplication found in https://github.com/qtproject/qt-solutions.
In QtSingleApplication class there is a method named activateWindow. In the Loader Example this method gets called whenever a second instance of the program is run.
To make the main window go on top when you try to open a second instance you've got to modify this method like this.
void QtSingleApplication::activateWindow()
{
if (actWin) {
actWin->setWindowState(actWin->windowState() & ~Qt::WindowMinimized);
actWin->activateWindow();
actWin->raise();
//winapi call
SetWindowPos((HWND)actWin->winId() , HWND_TOPMOST, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE);
//hack to prevent sticking window to the fore
SetWindowPos((HWND)actWin->winId() , HWND_NOTOPMOST, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE);
}
}
Warning: this is a windows-only solution and it works on my machine. Be also sure to include windows.h in the implementation.
[edit] My code had the problem that once activated, window stayed to the fore. This hack sort of fixes it.

Make aplication always on Bottom (pinned to desktop, behind all other apps) in C++/WinAPI [duplicate]

Does anybody know how to make a 'always-on-bottom'-windows, or a window pinned to the desktop? It should receive focus and mouseclicks, but should stay at the bottom of the Z-order. It would also be great if it could stay on the desktop even when user do a minimize all or show desktop operation.
Both delphi and c# solutions (or partial solutions/hints) would be great.
Warning It was suggested that you can accomplish this by calling SetParent and setting the window to be a child of the Desktop. If you do this, you cause the Win32 Window Manager to combine the input queue of the Desktop to your child window, this is a bad thing - Raymond Chen explains why.
Also, keep in mind that calling SetWindowPos with HWND_BOTTOM is incomplete. You need to do this whenever your window is changing zorder. Handle the WM_WINDOWPOSCHANGING event, look at SWP_NOZORDER for more info.
SetWindowPos can make windows AlwaysOnTop. Most likely it can give the opposite result. Try something along these lines:
[DllImport("user32.dll")]
static extern bool SetWindowPos(IntPtr hWnd, IntPtr hWndInsertAfter, int X,
int Y, int cx, int cy, uint uFlags);
public const uint SWP_NOSIZE = 0x0001;
public const uint SWP_NOMOVE = 0x0002;
public const uint SWP_NOACTIVATE = 0x0010;
public const int HWND_BOTTOM = 1;
SetWindowPos(hWnd, HWND_BOTTOM, 0, 0, 0, 0, SWP_NOSIZE | SWP_NOMOVE | SWP_NOACTIVATE);
Note:
Haven't tested this approach (for making windows always on bottom)
If it happens to work, then most likely the show desktop operation will hide the window. So maybe you should go even deeper into this 'nice' API.
EDIT: Done some searching along these lines to confirm whether it will do the trick and found something interesting - a duplicate.
Here is solution for ATL window.
If you can apply to c#, it will help you.
BEGIN_MSG_MAP(...)
...
MESSAGE_HANDLER(WM_WINDOWPOSCHANGING, OnWindowPosChanging)
...
END_MSG_MAP()
LRESULT OnWindowPosChanging(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled)
{
if (_bStayOnBottom)
{
auto pwpos = (WINDOWPOS*)lParam;
pwpos->hwndInsertAfter = HWND_BOTTOM;
pwpos->flags &= (~SWP_NOZORDER);
}
return 0;
}

how to change the position of the child window inside the parent window and show the toolbar?

I have the following code which passes a window handler form OpenCV window to win32 handler, therefore I can show the grabbed images from camera to the screen and the images will show as a child window of my main API.
but the problem is that when I want to add a tooldbar to my program, the image window handler comes at the top of the toolbar. how can I sort this out?
//create a window and set the handler from openCV to win32
cv::namedWindow("test",cv::WINDOW_AUTOSIZE);
hWnd2 = (HWND) cvGetWindowHandle("test");
hParent = ::GetParent(hWnd2);
::SetParent(hWnd2, hWnd);
::ShowWindow(hParent, SW_HIDE);
_liveCapturing=true;
lastPicNr = 0;
SetWindowTextW(hStatus, L"Live Capturing ... ");
if(FullScreen()){
::ShowWindow(hWnd, SW_MAXIMIZE);
}
code for the toolbar :
HWND CreateToolbar(HWND hwnd){
HWND hTbar = CreateWindowEx(0, TOOLBARCLASSNAME, NULL, WS_CHILD | WS_VISIBLE | CCS_TOP , 0, 0, 0, 0, hwnd, (HMENU)12, GetModuleHandle(NULL), NULL);
SendMessage(hTbar, TB_BUTTONSTRUCTSIZE, (WPARAM)sizeof(TBBUTTON), 0);
TBBUTTON tbb[3];
TBADDBITMAP tbab;
tbab.hInst = HINST_COMMCTRL;
tbab.nID = IDB_STD_SMALL_COLOR;
SendMessage(hTbar, TB_ADDBITMAP, 0, (LPARAM)&tbab);
return hTbar;
}
Probably you have found the solution a long time ago, but i want to post my anwers in case other users need it.
You can simply add the OpenCV window with the same code you have to a child window in your window (which you set it position in advance). For example you can add it to a static text window (label) ...
If you want to move the OpenCV window, call SetWindowPos() with the desired coordinates.
SetWindowPos(hWnd2, 0, 0, 30, 0, 0, SWP_NOSIZE | SWP_NOZORDER);

Win32 SetForegroundWindow unreliable

I have a rather complex series of applications which depend on the ability to switch applications in the foreground.
My problem is, every 5 or 6 times of switching the applications in the foreground, it simply fails to bring the application forward. GetLastError does not report any issues. Often times I see the correct application flash in the foreground for a moment then the previous application is visible.
I have a Manager application which I have source for, it spawns and controls about 4 applications which I do not have source for. one of the applications it spawns/controls is also a manager which spawns/controls about 5 applications.
This is a sort of kiosk design so the user wont even have a keyboard or mouse, just a touch screen.
I have tried every combination of the Win32 calls to control them I am just out of ideas.
My first attempt was:
SetWindowPos(hApp, HWND_TOPMOST, NULL, NULL, NULL, NULL, SWP_NOMOVE | SWP_NOSIZE);
SetWindowPos(hApp, HWND_NOTOPMOST, NULL, NULL, NULL, NULL, SWP_NOMOVE | SWP_NOSIZE);
My second attempt was:
SetForegroundWindow(hApp);
SetActiveWindow(hApp);
SetFocus(hApp);
my third attempt:
DWORD dwThreadID = GetWindowThreadProcessId(hApp, NULL);
AttachThreadInput( dwThreadID, GetCurrentThreadId(), true);
SetForegroundWindow(hApp);
SetActiveWindow(hApp);
SetFocus(hApp);
AttachThreadInput( dwThreadID, GetCurrentThreadId(), false);
my forth attempt:
DWORD dwThreadID = GetWindowThreadProcessId(hApp, NULL);
AttachThreadInput( dwThreadID, GetCurrentThreadId(), true);
SetWindowPos(hApp, HWND_TOPMOST, NULL, NULL, NULL, NULL, SWP_NOMOVE | SWP_NOSIZE);
SetWindowPos(hApp, HWND_NOTOPMOST, NULL, NULL, NULL, NULL, SWP_NOMOVE | SWP_NOSIZE);
SetForegroundWindow(hApp);
SetActiveWindow(hApp);
SetFocus(hApp);
AttachThreadInput( dwThreadID, GetCurrentThreadId(), false);
I feel like I am missing an important gotcha when it comes to window switching. I know that only the foreground process can switch windows around but as my main Manager program is spawning and starting all the other processes which I need to control, I feel like it should be capable of moving these windows around. Any suggestions or advice is appreciated.
I was having the same issue and I didn't want to mess up with threads. On experimenting I observed a simple hack to make SetForegroundWindow() work in the expected manner. Here is what I did:
Minimize the window if its not already minimized
Restore the minimized window
Call SetForegroundWindow(), and your window will be on top
Your AttachThreadInput() hack is (I think) a known way to defeat the focus stealing counter-measures in Windows. You are using the wrong handle though, you want to attach to the thread that currently has the focus. Which won't be hApp, you wouldn't need this code otherwise.
Use GetForegroundWindow() to get the handle to the window with the focus.
AttachThreadInput(
GetWindowThreadProcessId(GetForegroundWindow(), NULL),
GetCurrentThreadId(), TRUE
);
Although I think the 2nd argument needs to be thread ID of hApp. Because you don't want to shove your own window if I understood correctly. Not sure if that can work.
The easiest solution in C# to bring a window in the foreground:
Once you have the handle for the window, you can simply call:
SetWindowPos(handle, new IntPtr(0), 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE | SWP_SHOWWINDOW);
ShowWindow(handle, 5);
SetForegroundWindow(handle);
// If it is minimized, show the window
if (IsIconic(handle))
{
ShowWindow(handle, 3);
}
where
const int SWP_NOMOVE = 0x0002;
const int SWP_NOSIZE = 0x0001;
const int SWP_SHOWWINDOW = 0x0040;
Some windows are locked with setforeground(...),
you need to unlock them. This sequence is useful with any window:
HWND needTopWindow=FindWindow(TEXT("classname"), TEXT("window name"));
the classname and window name you can retrieve with ranorexspy from e.g.
nanoware.cz
if(!::IsWindow(needTopWindow)) return;
BYTE keyState[256] = {0};
//to unlock SetForegroundWindow we need to imitate Alt pressing
if(::GetKeyboardState((LPBYTE)&keyState))
{
if(!(keyState[VK_MENU] & 0x80))
{
::keybd_event(VK_MENU, 0, KEYEVENTF_EXTENDEDKEY | 0, 0);
}
}
::SetForegroundWindow(needTopWindow);
if(::GetKeyboardState((LPBYTE)&keyState))
{
if(!(keyState[VK_MENU] & 0x80))
{
::keybd_event(VK_MENU, 0, KEYEVENTF_EXTENDEDKEY | KEYEVENTF_KEYUP, 0);
}
}
DWORD dwThreadID = GetWindowThreadProcessId(needTopWindow, NULL);
AttachThreadInput( dwThreadID, GetCurrentThreadId(), true);
SetWindowPos(needTopWindow, HWND_TOPMOST, NULL, NULL, NULL, NULL, SWP_NOMOVE | SWP_NOSIZE);
SetWindowPos(needTopWindow, HWND_NOTOPMOST, NULL, NULL, NULL, NULL, SWP_NOMOVE | SWP_NOSIZE);
SetForegroundWindow(needTopWindow);
SetActiveWindow(needTopWindow);
SetFocus(needTopWindow);
AttachThreadInput( dwThreadID, GetCurrentThreadId(), false);
We had a similar problem a couple of years ago. We could solve it by the following function call:
SystemParametersInfo(SPI_SETFOREGROUNDLOCKTIMEOUT, 0, 0, SPIF_UPDATEINIFILE);
Give it a try. See the documentation here.
Try pushing the other application windows to the background first.
Also its a bit strange that you use SetWindowPos (SWP) to push a window to the foreground then push it out of the forgreound before using SetForegroundWindow to bring it back foward. Personally I've always used the SWP method without any issue ... but I've always pushed the other windows to the bottom as well.
You also need to consider the chances of window being minimized. If the window or various application are minimized then SetForegroundWindow(hApp) won't work. To be safe use ShowWindow(hApp, 9); I prefer value 9. Have a look at its documentation and choose which you find fit for you.

Unicode tooltips not showing up

I am trying to display unicode tooltips in my application window, however they do not seem to display. Non-unicode text shows up correctly but as soon as I try doing unicode no tooltip shows up. The following is what I am currently doing, any help is appreciated thank you.
HWND parentHwnd = pickInfo->getViewer().getCachedHwnd();
CWnd *pWnd = CWnd::FromHandlePermanent(parentHwnd);
HINSTANCE hInstance = GetModuleHandle(NULL);
if (isUnicode)
m_toolInfoW.lpszText = L"This tooltip does not show up at all.";
else
m_toolInfoA.lpszText = "Non unicode text";
if (!m_bTooltipInitialized){
::SendMessage(m_tooltipHwnd, WM_DESTROY, 0,0);
if(isUnicode)
m_tooltipHwnd = CreateWindowExW(WS_EX_TOPMOST,
TOOLTIPS_CLASSW, NULL,
WS_POPUP | TTS_NOPREFIX | TTS_ALWAYSTIP,
CW_USEDEFAULT, CW_USEDEFAULT,
CW_USEDEFAULT, CW_USEDEFAULT,
parentHwnd, NULL, hInstance, NULL);
else
m_tooltipHwnd = CreateWindowEx(WS_EX_TOPMOST,
TOOLTIPS_CLASS, NULL,
WS_POPUP | TTS_NOPREFIX | TTS_ALWAYSTIP,
CW_USEDEFAULT, CW_USEDEFAULT,
CW_USEDEFAULT, CW_USEDEFAULT,
parentHwnd, NULL, hInstance, NULL);
if (GetLastError() != 0)
return;
::SetWindowPos(m_tooltipHwnd, HWND_TOPMOST,
0, 0, 0, 0,
SWP_NOMOVE | SWP_NOSIZE | SWP_NOACTIVATE);
// Set the max text width before multi-line tooltip is used.
::SendMessage(m_tooltipHwnd, TTM_SETMAXTIPWIDTH, 0, m_nMaxWinTooltipWidth);
if (isUnicode){
m_toolInfoW.uFlags = TTF_SUBCLASS | TTF_IDISHWND | TTF_TRACK;
m_toolInfoW.hinst = hInstance;
m_toolInfoW.hwnd = parentHwnd;
m_toolInfoW.uId = (UINT_PTR)parentHwnd;
::GetClientRect (parentHwnd, &m_toolInfoW.rect);
::SendMessage(m_tooltipHwnd, TTM_ADDTOOLW, 0, (LPARAM) (LPTOOLINFOW) &m_toolInfoW);
::SendMessage(m_tooltipHwnd, TTM_ACTIVATE, TRUE, (LPARAM)(LPTOOLINFOW) &m_toolInfoW);
}
else{
m_toolInfoA.uFlags = TTF_SUBCLASS | TTF_IDISHWND;
m_toolInfoA.hinst = hInstance;
m_toolInfoA.hwnd = parentHwnd;
m_toolInfoA.uId = (UINT_PTR)parentHwnd;
::GetClientRect (parentHwnd, &m_toolInfoA.rect);
::SendMessage(m_tooltipHwnd, TTM_ADDTOOL, 0, (LPARAM) (LPTOOLINFO) &m_toolInfoA);
::SendMessage(m_tooltipHwnd, TTM_ACTIVATE, TRUE, (LPARAM)(LPTOOLINFO) &m_toolInfoA);
}
m_bTooltipInitialized = true;
}
if (isUnicode)
::SendMessage(m_tooltipHwnd, TTM_UPDATETIPTEXTW, 0, (LPARAM) (LPTOOLINFOW) &m_toolInfoW);
else
::SendMessage(m_tooltipHwnd, TTM_UPDATETIPTEXT, 0, (LPARAM) (LPTOOLINFO) &m_toolInfoA);
//Repaint the screen so that the area beneath the previous location of the tooltip is restored correctly.
::UpdateWindow(pWnd->GetParentOwner()->GetSafeHwnd());
pWnd = NULL;
The problem is that you try to use common controls version 6, but you does not get to use it.
More in details,
typedef struct tagTOOLINFOW {
UINT cbSize;
UINT uFlags;
HWND hwnd;
UINT_PTR uId;
RECT rect;
HINSTANCE hinst;
LPWSTR lpszText;
LPARAM lParam;
#if (NTDDI_VERSION >= NTDDI_WINXP)
void *lpReserved;
#endif
} TTTOOLINFOW, NEAR *PTOOLINFOW, *LPTTTOOLINFOW;
for xp+, the header file CommCtrl.h assume you'll use comctl version 6, but if you does not enable it explictly with manifest file, you'll still use the old comctl version 5.x. Then here comes the problem, the size of TOOLINFO of version 5.x is different to version 6.x.
So if you need to use comctl version 5 under windows xp+, you should init TOOLINFO with follwing code,
TOOLINFO ti;
ti.cbSize = sizeof(TOOLINFO) - 4;
Otherwise, you should enable visual-style look with manifest file or prgram directive:
#pragma comment(linker,"\"/manifestdependency:type='win32' \
name='Microsoft.Windows.Common-Controls' version='6.0.0.0' \
processorArchitecture='*' publicKeyToken='6595b64144ccf1df' language='*'\"")
Finally, I'd recommand you always enable visual-look in xp+. Here are the comparision of visual effects:
Note: If you use ANSI/MBCS to compile the program, the sizeof(TOOLINFO) will be 48, which have already remove the lpReserved member. So ANSI version would works, but UNICODE would fail.
Good explanation and a solution that will work by Jichao above, but hard-wiring the size of the TOOLINFO structure will fix only the tooltips. If the problem is that the program was compiled with common controls 6.0+ in mind, but may be run on (say) a Windows XP system with 6.0+ either not installed, or not fully installed (like someone installed IE, but never used or updated it), then the more general solution is to restrict the application to using only 5.x common controls.
As can be seen here, there are more things that have structure size changes than just tooltips.
What I did to insure that everything would work on Windows XP is put the following at the very top of my program, before any includes (in the case of visual studio, a good place would be at the top of targetver.h if you have one):
#define _WIN32_WINNT 0x0500
In the Unicode case you have TTF_TRACK, which I believe requires you to manually show or hide the tooltip. In the ANSI case, you don't have that option.
http://msdn.microsoft.com/en-us/library/bb760252(VS.85).aspx
Scroll down to "Implementing Tracking Tooltips".