After switching to Windows 10, I've noticed that when selecting a lower than normal screen resolution, the panel fit mode will default to "Maintain Aspect Ratio" meaning black bars appear. Every single time I do this, I have to manually set the panel fit mode to "Scale Full Screen".
I do this very frequently so I'd like to automate the process. I can adjust the resolution fine but cannot fine any API whatsoever to adjust the panel fit. Using a registry monitor, I've found that the setting changes some DWM keys. I'm assuming that some function will need to be called programmatically afterwards to apply the changes.
I've found nothing in the DWM API on MSDN, but I could've missed something.
What am I looking for?
Related
Is there a way to use the Windows APIs to detect if a particular monitor is a projector (beamer) rather than a screen?
(I'm writing a projection mapping desktop application, and I'd like it to automatically detect if a projector is attached and active to allow the user to compare the reality to the preview.)
I've used both EnumDisplayMonitors and EnumDisplayDevices to find the monitors, but I can't find any flag or other indication of the type of the display. I've looked in the DEVMODE and the DISPLAY_DEVICE and the registry keys the latter points to. I don't see a DeviceCapabilities or GetDeviceCaps call that can distinguish between a screen and a projector. I also looked in the device manager to see if there was a property that distinguishes my regular monitor from the projector, but I couldn't find anything. So maybe there's no way to do it.
But, the Screen Resolution control panel applet identifies the projector as "PROJECTOR" while identifying my primary monitor as "Dell U3011." Using EnumDisplayDevices, I can get the "Dell U3011" string from the DISPLAY_DEVICE, but, for the projector, I get just "Generic PnP Monitor." Somehow, the applet must be looking somewhere else to get that "PROJECTOR" string or it shows "PROJECTOR" for any Generic PnP Monitor that seems to be a projector. So where does it look and how does it know?
I believe the answer is that there is no reliable way to do it.
The "PROJECTOR" string that the control panel showed was arbitrary text that the system pulled from the EDID information. As far as I can tell, Windows doesn't actually "know" whether a monitor is a projector or an LCD panel or a CRT tube.
The EDID information doesn't seem to have a flag to indicate whether this is a projector. I saw a note that projectors will typically set one or both of the physical image dimensions (the ones measured in centimeters) to zero. But that was in a description of EDID 1.4, and most of my devices use EDID 1.3. Indeed, none of the projectors that I tried have a 0 for any physical dimension, so it's not a reliable signal.
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.
I should design a dialog with size 640*480 ,which can be used on 800*600 resolution.
At present my dialog size is 411*292 ,look wise this itself looks good enough ,but actually I was
asked to design dialog with the size I mentioned above.I tried that also but that dialog is too biger
than my earlier dialog of 411*292 size.
while using in 800*600 resolution or my dialog seems to be bigger and not able to see some of my controls
This is size of my dialog,
IDD_DIALOG_MYPAGE DIALOGEX 0, 0, 411, 292
can anyone please let me know how to design a dialog with 640*480 (which should not be bigger).
And how can I make my application to fit to any resolution so that all the controls on the dialog should be visible.
Dialogs are scaled in Dialog Units and Dialog Units scale upon the current UI settings and depend upon the System font. So if the user selects a larger UI representation your Dialog will grow too.
Best advise 1 I could give: Size all you controls by youself. Pick a font you like. Set it to the Control, calculate the positions ofthe new controls and use SetWindowPos/MoveWindow.
Only in this case you have full Control.
You may also use a fixed font size in the Dialog resource, but alos this font scales upon the DPI untis selected for the Screen...
So best advise 2 I could give: Scale upon the DPI/UI Settings and Show the dialog n a size that the user wants too, thats what a normal dialog will do...
You're in for a world of pain. If I understand correctly, you're being asked to make a dialog that will always be 640*480 pixels. It seems like whoever is asking hasn't kept up with UI development since 1995. 'Pixels' are meaningless in 2014. First, the units in resource files are in 'DLUs', 'Dialog Length Units'. See e.g. http://blogs.msdn.com/b/oldnewthing/archive/2004/02/17/74811.aspx and support.microsoft.com/kb/125681 for some starters on how to convert one to the other. However, with high DPI displays these methods are insufficient. Now it doesn't just depend on the size of the system font any more, but also on the settings the user has selected for how big to display 'things' on various monitors, whether to differentiate between monitors at all, etc. See for a start http://msdn.microsoft.com/en-us/library/windows/desktop/dn469266%28v=vs.85%29.aspx . But beware, because there are updates to these API's - e.g. Win7, Win8 and Win8.1 all have new features in this regards.
All of this of course doesn't help you. It's not terribly hard to make a dialog that will fit on 640x480 and up; just make it as small as possible. But this part: "And how can I make my application to fit to any resolution so that all the controls on the dialog should be visible." is really difficult. Does 'any' mean 'also smaller than 640x480'? And does 'fit' mean that it should look 'native' also on higher resolutions? Should the dialog be resizable? You can either go with the simple and robust approach suggested by xMRi above, or you will have to ask whoever is writing your spec to be more clear about what they want, keeping in mind all the things I outlined above.
I am writing an application in C++ using WinAPI.
I have a ListView of items with checkboxes and a scrollbar. Sometimes I need to disable the whole thing. When I call EnableWindow() to do that, the behavior of ListView is ok. It gets disabled, none of the contents are accessible any more. However checkboxes and scrollbar still look normal (not grayed out as the rest of the element).
Is it possible to grey out all parts within the ListView?
Enabled
Disabled
Normal disabled checkbox looks liks this: <- this is how I would expect to see checkboxes in the ListView, same applies to the scrollbar.
Regarding the checkboxes, the documentation for LVS_EX_CHECKBOXES says:
When set to this style, the control creates and sets a state image list with two images using DrawFrameControl. State image 1 is the unchecked box, and state image 2 is the checked box. Setting the state image to zero removes the check box.
You can therefore just change those images at indices 1 and 2 in the image list to their properly disabled variants when you are disabling the whole control.
The process itself of course varies depending on the framework you are using (if any), but generally will be along the lines of creating an Image List of SM_CXSMICON×SM_CYSMICON icons, creating a bitmap (2*SM_CXSMICON × SM_CYSMICON) pixels big, selecting it into a Memory DC for drawing, calling DrawFrameControl(..., DFC_BUTTON, DFCS_BUTTONCHECK | DFCS_FLAT | ..., ...) twice as appropriate, then using that bitmap in the Image List (and saving the previous IL to restore when the window is enabled again).
Regarding the scroll bar, you cannot get access to the implicit scrollbar as a separate window, so I don't think you can easily make it look more disabled without resorting to more custom drawing hacks for the non-client area of the List View.
Or creating an explicit scroll bar control yourself, but then you need to make sure it behaves the same as the original one, changes when the list view items change, respects right-to-left locale and so on.
It might be a bit of a challenge to get all the offsets and possibly transparency right even for the custom checkbox images described above. Even though this is how the List View control itself does it, it might not be worth the effort in the end.
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.