I have a very simple class which inherits from System.Windows.Forms.Form and removes the WS_CAPTION window style. It works in Windows XP & 7 perfectly. In windows 10 a piece of the titlebar is still drawn and it ends up looking ugly when using a custom titlebar control.
I know there are likely several ways to accomplish this kind of look, but I've chosen this for multiple reasons. I'm not interested in the alternative methods--that's not the intention of my question here.
My question is what is causing such a difference between the way this is rendered in windows 10 vs windows 7? The difference is not merely stylistic. It appears that the titlebar is still being rendered in some capacity even though the WS_CAPTION flag has been removed.
class BorderlessForm : System.Windows.Forms.Form
{
protected override System.Windows.Forms.CreateParams CreateParams
{
get
{
var _CreateParams = base.CreateParams;
_CreateParams.Style &= ~0x00C00000; // remove WS_CAPTION
return _CreateParams;
}
}
}
Windows 7 screenshot (desired appearance consistent with MSDN description):
Windows 10 screenshot (undesirable appearance inconsistent with MSDN description):
What you are observing is not a title bar but sizing border.
My question is what is causing such a difference between the way this is rendered in windows 10 vs windows 7?
The cause is different look and feel implementation on different versions of Windows.
In case you are interested how to get rid of the sizing border even on Windows 10: Remove the WS_THICKFRAME flag.
Alternatively (and perhaps more preferable) you can change your form's FormBorderStyle to some other value. Test whatever works best for you.
However there is nothing what defines the overall form border precisely. It's up to the look and feel (theme). Technically you cannot expect that form's border won't differ under different implementation. You can only ensure by testing.
Related
I have two UWP apps and after testing them out with Continuum I noticed the app bar of the OS (the bar with the Start button) at the bottom of the screen (it can be at each of the 4 edges of the screen, of course) was covering part of my app.
Now, I'm already using ApplicationView.GetForCurrentView().SetDesiredBoundsMode(ApplicationViewBoundsMode.UseVisible) before calling Window.Current.Activate(), but that doesn't seem to solve the issue.
1) Why is it that setting the DesiredBoundsMode property doesn't seem to work here? Shouldn't that automatically resize the window
content to the visible bounds (ie. excluding system overlays like the
navigation bar or the app bar)?
The workaround I'm using for now on Windows 10 Mobile devices is to subscribe to the VisibleBoundsChanged event and then manually adjust the margins of my Window.Current.Content item to make sure it doesn't show anything behind covered areas of the screen.
Basically, I use the Window.Current.Bounds property and the ApplicationView.VisibleBounds property to calculate the occluded areas on the different edges of the app window, and increase the margins from there.
2) Is there a proper/better way to do this?
I mean, I'm quite sure there's another method that should be used to avoid this issue (considering there are tons of different situations like Continuum, navigation bar etc... that I don't think are supposed to be manually handled one by one).
Thank you for your help!
Use the subscription to the event VisibleBoundsChanged. This is the best solution that I found.
var curr = ApplicationView.GetForCurrentView();
if (curr.IsFullScreenMode == true)
{
ApplicationView.PreferredLaunchWindowingMode = ApplicationViewWindowingMode.FullScreen;
curr.FullScreenSystemOverlayMode = FullScreenSystemOverlayMode.Minimal;
}
else
{
ApplicationView.PreferredLaunchWindowingMode = ApplicationViewWindowingMode.Auto;
curr.FullScreenSystemOverlayMode = FullScreenSystemOverlayMode.Standard;
}
I've been writing a custom drawn tab control for a few days now and for the most part everything is pretty and it does an amazing job ... except when I use it on my Windows 10 computer (at run-time).
I've gone back to the most basic few lines of code to trace the error and I can't for the life of me figure this out.
Below is the only code being used, in a nutshell I'm designing a horizontal aligned tab control.
using System.Drawing;
using System.Windows.Forms;
namespace WindowsFormsApplication1.UI
{
class TabControlTest : TabControl
{
public TabControlTest()
{
Alignment = TabAlignment.Left;
SizeMode = TabSizeMode.Fixed;
}
}
}
I've simply added the custom tab control to the form, added a couple of group boxes for reference purposes and changed the background colour of the form to grey so you can clearly see the tab control.
Now, at design time the 2 group boxes (1 in the tab control, 1 on the form) align perfectly.
But at run-time I see a very different result.
As you can see the tab part of the control is now larger than it was at design time and the resulting change means the contexts of the tab have also moved.
If I do this on a Windows 7 computer everything is displayed as it appears at design time, as it should!
I've added ImageSize but it makes no difference.
ItemSize = new System.Drawing.Size(30, 150);
I've reinstalled VS on my (Win10) development machine. I'm at a loss to explain why and how to resolve this.
Any/all help would be immensely appreciated.
Looking at your tab width in your comparison images, I believe this is another issue caused by automatic Windows control scaling. I found that it is the dpiAware option is automatically set when it's run from within Visual Studio and then reverts back to the default Windows Scaling that windows Implements when outside Visual Studio.
To prevent that auto-scaling when run outside Visual Studio altogether you need to Notify the OS that you're application is dpiAware by calling the Win32 P/Invoke SetProcessDPIAware() method from within your Main() before Application.Run() is called, like the example below demonstrates. This will let your controls use the native resolution which your designing the coordinates from.
static class Program
{
[System.Runtime.InteropServices.DllImport("user32.dll")]
private static extern bool SetProcessDPIAware();
static void Main(string[] args)
{
if (Environment.OSVersion.Version.Major >= 6)
SetProcessDPIAware();
Application.Run(new UIMonitor());
}
}
Alternatively, if you want to keep the scaling, you may be able to set the GroupBox location based off the Width of the Tab Control instead of a specific location. (Or by using some combination of Control measurements instead of exact picel placement.)
This is a follow-up to my earlier question Draw Custom Buttons on Windows Vista/7 Aero Titlebar.
I revisited the topic quite recently and found this article which is essentially a hack to 'drawing' buttons on Aero-enabled title bar (Windows Vista & 7). What the code does is to create a transparent window over the current one and places the buttons on it, giving the impression of additional buttons on the title bar. The only problem is the buttons look like regular WinForms buttons!
My question is, how do I read the windows shell style (aka theme) in order to create buttons styled just like those in the Control Box (see image)?
I'd like answers to be in .NET (VB.NET or C#). I'm okay with unmanaged code.
So if I understand you correctly, you want to read what Windows 7 calls the "Window Color" aspect of the current theme.
Acording to MSDN http://msdn.microsoft.com/en-us/magazine/cc163435.aspx, you want DwmGetColorizationColor: "retrieves the current color that is being used for DWM glass composition. This value is based on the current color scheme. Changing the setting causes a WM_WMCOLORIZATIONCOLORCHANGED notification."
[DllImport("dwmapi.dll", PreserveSig = false)]
public static extern void DwmGetColorizationColor(out int pcrColorization, [MarshalAs(UnmanagedType.Bool)]out bool pfOpaqueBlend);
"You can check to see the composition color and opacity by calling the DwmGetColorizationColor function. If this function succeeds, it will set a GDI+ ARGB color value and a Boolean indicating whether the color is opaque. Just like changing the Aero scheme in the control panel, there's a message broadcast when the composition color has changed. WM_DWMCOLORIZATIONCOLORCHANGED is sent when this happens, but in this case the parameters tell you what the new color and opacity are."
I am trying to take a screenshot of an application and I would like to make the parts of the rectangle that are not part of the applications region be transparent. So for instance on a standard windows application I would like to make the rounded corners transparent.
I wrote a quick test application which works on on XP (or vista/windows 7 with aero turned off):
protected override void OnPaint(PaintEventArgs e)
{
base.OnPaint(e);
Graphics g = e.Graphics;
// Just find a window to test with
IntPtr hwnd = FindWindowByCaption(IntPtr.Zero, "Calculator");
WINDOWINFO info = new WINDOWINFO();
info.cbSize = (uint)Marshal.SizeOf(info);
GetWindowInfo(hwnd, ref info);
Rectangle r = Rectangle.FromLTRB(info.rcWindow.Left, info.rcWindow.Top, info.rcWindow.Right, info.rcWindow.Bottom);
IntPtr hrgn = CreateRectRgn(info.rcWindow.Left, info.rcWindow.Top, info.rcWindow.Right, info.rcWindow.Bottom);
GetWindowRgn(hwnd, hrgn);
// fill a rectangle which would be where I would probably
// write some mask color
g.FillRectangle(Brushes.Red, r);
// fill the region over the top, all I am trying to do here
// is show the contrast between the applications region and
// the rectangle that the region would be placed in
Region region = Region.FromHrgn(hrgn);
region.Translate(info.rcWindow.Left, info.rcWindow.Top);
g.FillRegion(Brushes.Blue, region);
}
When I run this test app on XP (or Vista/Windows 7 with Aero off), I get something like this, which is great because I can eek an xor mask out of this that can be used later with BitBlt.
removed dead Imageshack link - Screenshot
Here is the problem, on Vista or Windows 7 with Aero enabled, there isn't necessarily a region on the window, in fact in most cases there isn't. Can anybody help me figure out some way to build a mask like this on these platforms?
Here are some of the approaches I have already tried...
1. Using the PrintWindow function: This doesn't work because it gives back a screenshot taken of the window with Aero off and this window is a different shape from the window returned with Aero on
2 Using the Desktop Window Manager API to get a full size thumbnail: This didn't work because it draws directly to the screen and from what I can tell you can't get a screenshot directly out of this api. Yeah, I could open a window with a pink background, show the thumbnail, take a screenshot then hide this temporary window but thats a horrible user experience and a complete hack I would rather not have my name on.
3. Using Graphics.CopyFromScreen or some other pinvoke variant of this: This doesn't work because I can't assume that the window I need information from is at the top of the z-order on the screen.
Right now, the best solution I can think of is to special case Aero on Windows 7 and Vista to manually rub out the corners by hard coding some graphics paths I paint out but this solution would suck since any application that performs custom skinning will break this.
Can you think of another or better solution?
If you are here, thanks for taking time to read this post, I appreciate any help or direction that you can offer!
If you are looking for a finished application, there is 7capture, which captures also the translucency, so images can be saved to PNG format for later compositing.
EDIT:
The original question and comments indicate you are looking to produce a region on Windows Vista/7 that you can then use to mask out parts the captured image, as is done with Windows XP and non-Aero UIs. Using a region is not going to give you the result you are looking for, since the window outline is not computed as a region, but as an image with variable transparency - RGBA. The Alpha channel in that image is your mask, but it's not an on-off mask like a region, but a gradual mask with a range of values from pixels being fully included to being fully masked out.
Although it uses undocumented APIs, the code at http://spazzarama.wordpress.com/2009/02/12/screen-capture-with-vista-dwm/ will capture to a RGBA buffer which you can then use to render or save the image with the shadow and other translucency effects intact.
In DwmCapture.cs Change
BackBufferFormat = Format.X8R8G8B8
to
BackBufferFormat = Format.A8R8G8B8
(X8->A8)
And you should then be able to access both the usual RGB data plus transparency from the captured buffer. This can then be saved as a PNG or other format with alpha-channel for composing.
Removed idea that is terrible but would have been awesome back in the '90s
You say that using the DWM API only allows you to capture directly to the screen... could you create a window offscreen (say, X = -100000px, Y = -100000px) but visible (maybe even hidden?) and draw the screenshot to it? Since when using the DWM each window has a backing texture, I'm thinking it might still get drawn fine even though the target isn't directly onscreen.
Also, if you want to go the DirectX route and access the actual DX texture backing the window, I found a few leads that might help (especially the first link):
http://spazzarama.wordpress.com/2009/02/12/screen-capture-with-vista-dwm/
http://channel9.msdn.com/forums/TechOff/251261-Help-Getting-the-shared-window-texture-out-of-DWM-/
http://web.archive.org/web/20080625183653/http://www.aeroxp.org/board/index.php?showtopic=6286
http://www.youtube.com/watch?v=hRTgFTMnT_U
Using Graphics.CopyFromScreen or some other pinvoke variant of this:
This doesn't work because I can't
assume that the window I need
information from is at the top of the
z-order on the screen.
If you know which window you need the information from, can you bring it to the front, call Graphics.CopyFromScreen, and then reset its z-index? I know from experience that Aero does odd things when items are in the background in order to make their glass interface work correctly (partial rendering etc). This may not be great UX; however, it would be a special case and used only when Aero is turned on.
You can take a look at the source code of AeroShot, as described on the main page, it can capture rounded edges and with the Aero Glass transparency effect and save it to a PNG file. It's written in C#.
I am writing a windows application with C# in visual studio .net 2005.
In the form , there are some control with transparent Background; the form opens maximised and with full screen background.
The application runs very slow with high CPU usage.
Why is this?
1. Solution using property DoubleBuffered
Sidenote: Only works if you have access to the control as DoubleBuffered is a protected property of Control. Similar as solution 2 (see code behind).
// from within the control class
this.DoubleBuffered = true;
// from the designer, in case you are utilizing images
control.BackgroundImageLayout = System.Windows.Forms.ImageLayout.None;
System.Windows.Forms.Control.DoubleBuffered
System.Windows.Forms.Control.BackgroundImageLayout
2. Alternative solution using SetStyle + OptimizedDoubleBuffer:
Sidenote: The control paints itself, window message WM_ERASEBKGND is ignored to reduce flicker, and the control is first drawn to a buffer rather than directly to the screen.
control.SetStyle(UserPaint | AllPaintingInWmPaint | OptimizedDoubleBuffer, true);
System.Windows.Forms.Control.SetStyle(ControlStyles, Boolean)
System.Windows.Forms.Control.ControlStyles
3. Alternative solution using SetStyle + DoubleBuffer:
Sidenote: Similar as OptimizedDoubleBuffer, due to legacy reasons it remained in the codebase.
control.SetStyle(UserPaint | AllPaintingInWmPaint | OptimizedDoubleBuffer, true);
System.Windows.Forms.Control.SetStyle(ControlStyles, Boolean)
System.Windows.Forms.Control.ControlStyles
Thats because the GDI+ transparency implemented in .NET 2 is not ideally implemented, as Bob Powell explains.