how to make a mfc dialog's height unsizeable? - mfc

i am playing with a MFC github project xtrader on github. I managed to get it up running and having one question i cannot understand.
This project is a dialog based MFC based app, the main dialog xTraderDlg, when i run it, i found the height of the dialog is not sizable, however the width does.
i have being read this source for quite some time and review every place that handles SetWindowPos() or OnSize(). There is not traces how this done. Even i comment out the OnSize() or OnInitDialog(), the height remains unchangeable.
the code has some tricks to save the width and height in a config file and reload it next time it is up. but i believe it doesnot matter.
the code also has this line.
::SetWindowPos(m_hWnd, HWND_TOPMOST, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE);
However even i remove this line the result is still the same. And SWP_NOSIZE wont cause only the height unsizeable. it is a myth to me indeed.
Can anyone advise me why? main dialog code is here.
https://github.com/lpswufe/xTrader/blob/master/xTraderDlg.cpp

This is done in OnGetMinMaxInfo WM_GETMINMAXINFO.

Related

Pin window to desktop / Glue window to desktop / "Always-on-bottom" window

I'm working on a basic desktop app in C++ / Win32.
My goal right now is to create a basic "sticky note" app that would be pinned / glued to the desktop, i.e always in front of the desktop but always behind of any other application.
Really a personal project there, just to fight my bad memory and have my tasks/notes always visible on the desktop so I couldn't miss them when starting the computer & so on.
The behaviour I'm aiming for would be similar to Stardock Fences ("kind of" because I'm not going to store any desktop icon in there, but you hopefully get the idea)
I started with the sample code from the Get Started with Win32 and C++ docs to have the most basic Win32 minimal window setup.
What I got so far :
I managed to keep my window on bottom of every other app and in front of the desktop by calling SetWindowPos in the window procedure (WindowProc), when handling the event WM_SETFOCUS (I first tried with the event WM_WINDOWPOSCHANGING as suggested in this answer but this resulted in an annoying flickering when dragging the window).
case WM_SETFOCUS:
SetWindowPos(hwnd, HWND_BOTTOM, 0, 0, 0, 0, SWP_NOSIZE | SWP_NOMOVE);
return 0;
The problem : my window stays in front of the desktop, except when I click on the "Show Desktop" button in the taskbar (or hit the Windows + D shortcut). As I often use this shortcut myself, I'd like my window to stay over the desktop no matter what.
A not-satisfying-enough-but-still-something I managed to do is to bring back my window in front of the desktop when clicking on any other window after hitting Windows + D (this mostly makes sense with multiple monitors, as opening a random app on the first one for example, will toggle back my own app in front of the desktop on another screen).
I could do this using this time the event WM_SIZE and calling ShowWindow then SetWindowPos, still in the WindowProc
case WM_SIZE:
ShowWindow(hwnd, SW_SHOWNORMAL);
SetWindowPos(hwnd, HWND_BOTTOM, 0, 0, 0, 0, SWP_NOSIZE | SWP_NOMOVE);
return 0;
Not ideal though, as I'd really want my app to always remain in front of the desktop and "survive" to the Show Desktop action.
What I tried :
I checked out those answers but couldn't figure out how to achieve what I want.
How to make 'always-on-bottom'-window
Window “on desktop” : Note on this one, I tried the trick with SetParent like this in the wWinMain
HWND desktop = FindWindow(L"ProgMan", L"Program Manager");
if (desktop == NULL)
{
return 0;
}
ShowWindow(hwnd, nCmdShow);
SetParent(hwnd, desktop);
However, my app isn't visible at all anymore with this, even though the FindWindow didn't return NULL but an actual handle.
Make aplication always on Bottom (pinned to desktop, behind all other apps) in C++/WinAPI [duplicate]
Disable Minimize, Maximize, Close buttons in Win32 I tried those to "intercept" the Show Desktop event but it seems this event doesn't get fired with the Show Desktop action.
Did I miss something ?
As #JonathanPotter pointed out, when hitting Windows + D or the Show Desktop button, the event WM_WINDOWPOSCHANGING gets fired, and the window gets moved to -32 000, -32 000 (its size also gets changed)
NOTE : a window without the style WS_MINIMIZEBOX seems not receiving WINDOWPOSCHANGING event when hitting Windows + D. Thus, no -32 000 coordinates detection in that case... Also noticed the same issue when using the ex style WS_EX_TOOLWINDOW (as this one gets rid of the minimize box, even if you set the style flag WS_MINIMIZEBOX).
Didn't find a solution for that case, so I'm sticking to an overlapped window.
To prevent this movement, just set the flags SWP_NOMOVE and SWP_NOSIZE on the WINDOWPOS structure passed in the lParam
So as a final result, to achieve the wanted behaviour (i.e always behind every other window but always in front of the desktop), the only needed code to add to the doc's sample is the following, placed in the window procedure WindowProc's switch statement :
EDIT : the best place to force the Z order with HWND_BOTTOM thus ensuring the window is always on bottom is also in the WM_WINDOWPOSCHANGING event. Indeed, calling SetWindowPos to force it in the WM_SIZE event when dragging the window over, as I was doing previously, causes some flickering on the window when resizing it, whereas no flickering occurs when setting directly the hwndInsertAfter property of the WINDOWPOS structure in WM_WINDOWPOSCHANGING.
case WM_WINDOWPOSCHANGING:
{
WINDOWPOS* pos = (WINDOWPOS*)lParam;
// Show desktop (Windows + D) results in the window moved to -32000, -32000 and size changed
if (pos->x == -32000) {
// Set the flags to prevent this and "survive" to the desktop toggle
pos->flags |= SWP_NOMOVE | SWP_NOSIZE;
}
// Also force the z order to ensure the window is always on bottom
pos->hwndInsertAfter = HWND_BOTTOM;
return 0;
}
I had the same problem and found a solution via using "autohotkey". autohotkey is a powerful free scripting language for automation in windows that you can download from here. Below scripts are an instance of making sticky notes always on top when you execute it inside a .ahk file (you can copy these codes to a simple notepad and then change .txt to .ahk if you already had installed autohotkey on your computer). by right clicking on .ahk file, you can also see option of Compiling .ahk into .exe which enables you to share it with your other friends too:
#SingleInstance Force
GroupAdd, ontop, Sticky Notes ; you can replace sticky note by any application,
; if you know the name of that application window
; (and its ahk_class for more specific cases).
; for example you can replace "Sticky Notes"
; with "Calculator" to make calculator stay always
; on top.
Loop {
WinWait, ahk_group ontop
WinSet, AlwaysOnTop, On
SoundBeep, 1500
WinWaitClose
SoundBeep, 1000
}
(main codes are credit of mikeyww)

Flags Windows 7 window always on top INCLUDING the Win7 taskbar (Custom error)

I know a few flags that make the window always on top (eg Qt :: ToolTip, Qt :: WindowStaysOnTopHint, Qt :: Popup), but each time the method is the same problem.
By clicking on the start menu, the area tray, empty field between programs and tray - window and so is hiding.
Everything is fine when I switch between different applications and I click anywhere except the above-mentioned places.
Just run other applications that I used to use, so it might be a function of the uninvited Windows.
Code does not make sense given, because at the same time where do dumb mistake, and indeed act as a flag to be apart of this "small" problem.
These things work:
HWND hWnd = reinterpret_cast(this->winId());
SetWindowPos(hWnd, HWND_TOPMOST, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE);
But it turns out that exactly the same as the flag of the subject. : (
Explanation of what exactly is the problem:
http://youtu.be/k5TCtr1hPKY
The solution is, regular exercise such thing:
if(this->isActiveWindow() == false} {
this->raise();
}
Only the minimized window does not always work, but to me it is unnecessary.

Is there a way to guarantee that internet explorer will alway be the topmost window?

I'm trying to force an internet explorer window to be TOPMOST. No other windows should show on top of the internet explorer window. I have to use internet explorer. I'm also running this in Windows 7. Apparently that makes a difference but all the information I found on that is rather vague and basically consists of people shouting "why isn't this easier!". This is my code:
HWND ieWin = FindWindow(TEXT("IEFrame"), 0);
SetFocus(ieWin);
SetWindowPos(ieWin, HWND_TOPMOST, 0, 0, 100, 100, SWP_SHOWWINDOW );
UpdateWindow(GetParent(ieWin));
This is running in a loop so I can force the window to have these settings continuously but it's not helping. Sometimes the above code works and sometimes it doesn't.
No. What if two programs did this?.
After much discussion I did wind up forcing the window to stay on top using a loop. If anyone else really needs to do this in the future they really need to make sure they are following the steps below.
1) Ensure that they will have absolute control over the windows that their user can open. In my case The user will only be able to open my program and internet explorer.
2) The first time you set the IE window to show set it to the foreground.
3) While looping to set the window to TOP_MOST do NOT set the focus to the IE window.
4) Make sure you have SWP_SHOWWINDOW, SWP_NOSIZE, and SWP_NOMOVE. Otherwise that loop will change your window's size and place at every iteration.
And if you can avoid it at all possible, don't ever do this at all :P

Show System Menu From Another Window

The project I'm working on right now is essentially an open source version of Ultramon (the multiple taskbar program). Thus think of the application to be just like the windows taskbar. Buttons for each window, etc. This is coded in C/C++ using WinAPI
I've just started doing it, and have some of the functionality down. However, I'm getting stuck at getting the system menus (eg the menus that you get when you rightclick on a taskbar 'button') showing when and where I want them to.
I'm trying to use:
HMENU menu = GetSystemMenu(item, false);
SetForegroundWindow(hWnd);
TrackPopupMenu(menu, TPM_LEFTALIGN | TPM_BOTTOMALIGN, 0, 0, 0, hWnd, NULL);
PostMessage(hWnd, WM_NULL, 0, 0);
item is the HWND I want the menu for, hWnd is the HWND for the button/item I want the menu to show up on. (its showing at 0, 0 for now, the top left corner of my main monitor).
This code works perfectly every time for a system menu which is customized. Eg: its NOT the standard menu of just "Restore", "Maximize" etc etc, it has some added in menu items. Those menus will always display where I want.
However, the default basic system menus (eg the ones with only Maximize, restore, close etc), will ONLY display for the FIRST time I use them. After that they refuse to show up. Unless I restart the computer, run it again, at which point they work perfectly.
Note: SetForegroundWindow(hWnd); and PostMessage(hWnd, WM_NULL, 0, 0); are in there because I read somewhere that the system menu would only work the first time unless I did that trick of bringing it to the foreground, but it still doesn't work correctly.
So does anyone have any idea how to get this working correctly? Or why it works only the first time after I restart the computer?
Just tested something, it will also show the system menu again for a window if I close the window (eg exiting the program) and re-opening it. But once again, it will only show it once then it stops working.
It might be hacky, but have you tried setting the window focus and then issuing an Alt+Space through something like SendInput?

How do I force my app to come to the front and take focus?

I'm working on an application that happens to be the bootstrap for an installer that I'm also working on. The application makes a few MSI calls to get information that I need for putting together the wizard that is my application's main window, which causes a progress window to open while the info is being gathered and then go away once that's done. Then the wizard is set up and launched. My problem is that the wizard (derived from CPropertySheet) does not want to come to the front and be the active application without me adding in some calls to do so.
I've solved the problem of bringing it to the front with the following code in my OnInitDialog() method:
SetWindowPos(&wndTopMost, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE); // force window to top
SetWindowPos(&wndNoTopMost, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE); // lose the topmost status that the previous line gave us
My problem is that I still haven't figured out how to make the window self-activate (i.e., make itself be the one that has the focus). SetFocus() won't work in this context. I need something that will force the window to the top of the Z-order and activate it, preferably in as few calls as possible.
My guess is that the progress window opened at the beginning by the MSI calls is causing the main window to screw up, but I have no way to prevent that window from appearing. Also, it wouldn't make sense to hide it, because it lets the user know what's going on before the main window arrives.
Andrew isn't completely correct. Windows does try really hard to stop you from stealing focus, but it is possible using the folowing method.
Attach to the thread of the window that currently has focus.
Bring your window into focus.
Detach from the thread.
And the code for that would go something like this:
DWORD dwCurrentThread = GetCurrentThreadId();
DWORD dwFGThread = GetWindowThreadProcessId(GetForegroundWindow(), NULL);
AttachThreadInput(dwCurrentThread, dwFGThread, TRUE);
// Possible actions you may wan to bring the window into focus.
SetForegroundWindow(hwnd);
SetCapture(hwnd);
SetFocus(hwnd);
SetActiveWindow(hwnd);
EnableWindow(hwnd, TRUE);
AttachThreadInput(dwCurrentThread, dwFGThread, FALSE);
You may or may not need to have to run your program with administrative privileges for this to work, but I've used this code personally and it has go the job done.
You can't steal focus. Period.
See this Old New Thing article:
https://blogs.msdn.microsoft.com/oldnewthing/20090220-00/?p=19083
doesn't ShowWindow(youwindow,SW_SHOWNORMAL) work?
-don
You will find that BringWindowToTop or SetForegroundWindow have requirements that must be met before the window will actually be forced to the front over all other windows (applications). If these aren't met, Windows will only flash the application's icon in the taskbar. This article presents a way around that but as 1800 INFORMATION points out, it is not recommended. I guess you'll just have to accept it.
There ARE good reasons for an app to 'steal' focus. My application is a server loading many driver DLLs. Another application, connecting to the server, has a button that sends a message to the server to show detail information in one of those DLLs (owned by the server, not the client app) for convenience. Unfortunately, this popped open window is usually buried under multiple windows.