without much change set MFC application to maximum resolution - c++

I have an MFC application which is used frequently and works well, it has become an important part of client work and downtime is not at all tolerable.
Problem is that there is change in hardware and old monitors are replaced by LCD monitors so MFC application which is not fitting into size of all monitors, is there a way where in I can simply change MFC settings and recompile without much code change as that will trigger a lengthy test-fix-test cycle.
I would be happy to use a third party tools which would act as an container to this MFC application needing fixed resolution and give me scroll-bars like virtual monitor
Thanks

Two ideas without code change:
1) Just set the resolution of the desktop to another value, such that it's the same as on older monitors.
2) Change the font size in the dialog resources. This will change the size of the whole dialog.
With code change:
1) Use CDC::SetWorldTransform(const XFORM& rXform) to scale the CDC before you paint onto the CDC.
2) Use CDC::SetViewportExt(..), enable the scrollbars in CreateWindow(..), and handle the scroll events by using CDC::SetViewportOrg(..) to move the content of the window.

Related

Limits SetSysColor to one application

I want to change the set of colors used in my software. My research led me to the SetSysColor() function. The problem with this function is that every software on the computer gets affected by the modification, not only the executable I want to modify.
Is there a way, or a alternative, to change the set of colors used by my application without having to redraw everything manually?
In some cases using custom colors may indeed be beneficial (highlighting, notifications, color-coding etc); just don't overdo. There are certain ways in WinAPI (usually accessible in MFC too - through events or direct WIndows message handlers) that let customize the appearance of your application. Look into the documentation for own-drawn controls, custom control colors, WIndows Class brushes, messages like WM_CTLCOLOR and WM_ERASEBKGND, You can also customize the looks of a window's non-client area (eg title-bar, borders etc), although this changes the appearance of your app a lot more drastically. See messages like NC_PAINT and NC_HITTEST.

How do you scale the title bar on a DPI aware win application?

I am making my app dpi-aware per monitor by setting <dpiAware>True/PM</dpiAware> in the manifest file. I can verify with process explorer that this is indeed working or by calling GetProcessDpiAwareness.
This is all working fine and I can scale anything in the client area fine in my code. However, my only problem is that if I drag my app from a system-dpi monitor to a non-system dpi monitor, the title bar and any system menu would either become too big or too small. This isn't the case for most built-in apps (e.g. calc, edge browser, etc..) so there must be away to scale it properly. Does anyone how the devs at MS did this?
The screenshot below should explain my problem better. Also notice, that the padding between the close, min, and max button is different when it's scaled (96dpi).
Sample app I'm attaching a very simple app that is per-monitor dpi aware.
The Windows 10 Anniversary Update (v1607) has added a new API you must call to enable DPI scaling of the non-client areas: EnableNonClientDpiScaling. This function should be called, when WM_NCCREATE is received. The message is sent to the window's procedure callback during window creation.
Example:
case WM_NCCREATE:
{
if (!EnableNonClientDpiScaling(hWnd))
{
// Error handling
return FALSE;
}
return DefWindowProcW(...);
}
If the application's DPI-awareness context is DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE_V2, then calling EnableNonClientDpiScaling should be omitted, as it won't have any effect, although the function will still return successfully.
From the documentation:
Non-client scaling for top-level windows is not enabled by default. You must call this API to enable it for each individual top-level window for which you wish to have the non-client area scale automatically. Once you do, there is no way to disable it. Enabling non-client scaling means that all the areas drawn by the system for the window will automatically scale in response to DPI changes on the window. That includes areas like the caption bar, the scrollbars, and the menu bar. You want to call EnableNonClientDpiScaling when you want the operating system to be responsible for rendering these areas automatically at the correct size based on the API of the monitor.
See this blog post for additional information about DPI scaling changes in Windows 10 AU.
Does anyone how the devs at MS did this?
This has a pretty disappointing answer. Using Alin Constantin's WinCheat and inspecting the top-level window of Calculator, I see a window size of 320x576, and a client size that is also 320x576.
In other words, Microsoft entirely avoids the problem by suppressing the non-client area of the window, putting everything in the client area instead. Making this work well for you may involve custom drawing of the title bar.
Something worth noting is that Calculator and e.g. Windows Explorer don't use the same colour for the title bars. Calculator doing custom drawing of the title bar would explain that perfectly.
UPDATE:
It is enough to add new <dpiAwarness> declaration to manifest to solve all this mess. Example is here.
Remnants of former investigations (obsolete):
More investigations on the subject.
System setup: two monitors, one is 96 dpi another one is 267 dpi (Microsoft Surface 4).
Testing window is moved to secondary 96 dpi monitor:
Here is rendering (wrong, IMO) with <dpiAware>true/pm</dpiAware> in manifest:
Note huge size of caption bar and wrong sizes of window icons.
And here is correct rendering using <dpiAware>true</dpiAware>
And I suspect that MSDN documentation is plainly misleading about values of PROCESS_DPI_AWARENESS. I do not see any differences in messages and styles between <dpiAware>true</dpiAware> and <dpiAware>true/pm</dpiAware>. The later one just makes caption larger. In both case application receives WM_DPICHANGED message while moving between monitors with different DPI.
Sigh.
The documentation says:
Note that the non-client area of a per monitor–DPI aware application is not scaled by Windows, and will appear proportionately smaller on a high DPI display.
The Microsoft apps that you link to deal with this by removing the non-client area and making the client area cover the entire window.

Resize size of Main Window depending on Hardware in Qt?

I have developed my Application with most of the Widgets in Qt Creator's Designer module.
I have hard coded the sizes of my widgets depending on how they appeared on my laptop. Yesterday when I ran the application on my Desktop (lower screen resolution than laptop) some of the Main Window widgets were not visible & on startup there was horizontal scrollbar & I had to scroll to see those widgets; which is not the case on my laptop.
I have 2 problems:
Is it possible to resize all of my widgets (even those which are added run time by code) by using some resize factor? Maybe at startup I will get the screen resolution of Hardware in which application is running & then create a ratio of that with resolution of my laptop. Is it possible to multiply this factor to all widgets without adding code for each widget?
How do I get the resolution of the Screen in which my Application is running?
PS: I would like to know the defacto method of solving this problem...
Thank You.
You could try a function like this:
resize(theDesktop->screenGeometry().width()*PERCENTAGE_OF_MONITOR_WIDTH_FOR_SCREEN, theDesktop->screenGeometry().height()*PERCENTAGE_OF_MONITOR_HEIGHT_FOR_SCREEN);
Resize is a member function of the QWidget class and the PERCENTAGE_OF_MONITOR variables would be whatever percentage of the monitor you want your application to take up.
theDesktop is of the type QDesktopWidget.
You should use Layouts to manage the size policy of your widgets.
Qt layouts automatically position and resize widgets when the amount of space
available for them changes, ensuring that they are consistently
arranged and that the user interface as a whole remains usable."
You could also check this question for more information regarding layout machanisms in Qt.
Qt website has got excelent documentation on the subject. You can start here for more information on working with layouts in Qt Designer.

Expanding Qt interface if necessary

I'm working on a Qt project and I've noticed a persistent problem with some GUI forms. The form looks fine on KDE (bottom picture) and Windows , but when the app runs on anything GNOME3-based (like Unity or GNOME3 itself) some parts of the form are hidden from view. (Top picture, everything below the Sort Ascending radio button is cut off)
The problem seems to be with how Qt layouts handle large font sizes. If the user is using normal-sized system font (<= 10pt) everything works fine. If they are using larger fonts, the form is not large enough to accommodate everything. Other forms affected by this bug are merely crowded, but that isn't as serious as having vital controls out of bounds. The layout doesn't want to resize itself to take advantage of new space if I enlarge the dialog. Is there an easy way to make it do this or do I need to hard-code it? Originally the code prevented dialog resizing during runtime, but restoring that functionality didn't fix the bug. Even if the dialog can expand, the problem is the layout won't expand with it.
Up until now, I've made all affected forms oversized to compensate for this bug, but it looks strange to have the dialogs much bigger than they need to be on Windows and KDE systems where the font is the proper size. Is there a way to cause an affected dialog/layout to resize itself so everything fits properly at runtime? If so, how would the program detect it when parts of the GUI are out of bounds? I would prefer not to force a certain font size (some people may prefer large fonts due to vision problems).
Thanks in advance for help.
The fix for this is using a different approach when displaying forms. A more dynamic way as I'll describe. I've successfully used this approach on Windows with 96 and very high DPI modes (over 120).
1.
Query the OS and get the user's chosen font for a particular system item; say the font used for the window caption or system dialog boxes. Also you could allow the user to choose their font later if they desired. Use True Type fonts when doing this if possible.
2.
Using that font, construct a string object that you'll use for a label or edit control (I don't know what this is for QT, for Windows it is GetTextExtentPoint32) and pass it to a system function to determine the width and height of the string for your environment.
3.
Given the above value, place the control and dynamically resize the form with the padding all around the control as you like. For buttons you might always add a certain percentage of pixels above and below the button to taste.
4.
For graphical elements like Bitmaps and jpegs, again query the OS for the current DPI settings of the monitor and use larger, pre-made resources. Naturally, all text around theses elements will be dynamically placed on the fly.
Note that on Windows you'll need to mark your exe as high dpi aware using a manifest.

Simulate fullscreen

I've seen an application that simulates a fullscreen application by removing the title bar and the window borders. I've done some research and found getWindowLongPtr() for that.
Now my question: How can I find and identify the application and get the appropriate window handle? How can I distinguish multiple instances of the application (running from different locations on disc)?
Just to make "simulate" more precise. If you make an application go fullscreen and you click on a different monitor, it minimizes itself. If the application runs in a window and you click on a different monitor, the window is not changed. If you remove the borders of the window and position it on the left or right monitor, you can still work with the other monitor without minimizing the application. Still it looks like the application running fullscreen on one of the monitors.
As an example: you can set Eve (www.eveonline.com) to fullscreen and windowed mode. In fullscreenmode you can not click on a second monitor without Eve minimizing itself. In window mode you can. There are tools like evemover that allow you to setup your window on one monitor, looking like fullscreen, but being in window mode. That's what I want to archieve. Evemover actually provides some of it's source code, that's why I know that removing the border and setting the position is done using the Win32-API with setWindowLongPtr and setWindowPos.
Many applications use divergent and confusing applications of the phrase "fullscreen".
A fullscreen application simply - occupies the full screen area.
DirectX applications can request a fullscreen exclusive mode. The advantage of this mode to DirectX applications is, with exclusive access to the (full) screen they are then allowed to change the resolution, bit depth etc, as well as gain access to vertical sync synchronized hardware buffering where the screen surface is 'flipped' between display intervals so that 'tearing' does not occur.
Anyway, the windows desktop understands 'fullscreen windows' - windows that occupy the full area of a monitor and have no non client elements. When windows like this are created, things like desktop gadgets and task bars automatically hide themselves. Modern games have come to call this mode 'fullscreen windowed'.
Back to your question: 'FindWindow' is the API used to discover other applications windows. Getting the path to the application that created the window is much harder. GetWindowThreadProcessId can get you the process id of the owning process. OpenProcess will get you a handle that you can pass to QueryFullProcessImageName (implemented on Vista and above) to get the full path to the process.
I think you are refering to applications like window aggregators, that 'plug in' to the system and act from outside the application.
Look at the code for the freeware app PuttyCM (for aggregating Putty (SSH) shell windows as tabs). IIRC, it ensures that the Window pointer passed to the application has the flags already set.
On applications running from different places, you will probably need some way of identifying it - registry entries / install log etc.