If ever you stumble across a wireless network with the name ‘myLGNet’ and have need to access it, the default password is ‘123456789a’.
When I created a user account at AirAsia’s website a little while ago, I was surprised to be told to choose a password with a minimum length of 16 characters*. I suspect that the average user’s password doesn’t approach that length (perhaps it would be better if it did). In any case, I duly typed in my combination of letters and numbers and went about my business, happy to believe that such an onerous requirement said something about AirAsia’s commitment to security.
A month down the track, I went back to the website only to find I’d forgotten which password I had chosen – for whatever reason, my browser had not saved my credentials. After a few guesses, I gave up clicked the ‘Forgot Password’ link (making sure nobody was looking; I must not be the only one embarrassed to have to have to rely on that feature). I typed in my email address and received a message shortly afterwards.
Lo and behold, there was my 17-character password in plain text, staring right at me.
Oh, well – if someone happens to steal their database, at least it won’t be any of my usual passwords that they find – those are shorter than 16 characters 🙂
(*I see that the requirement is now for only 8 characters.)
Part of the beauty of the Windows Presentation Foundation is that it is designed to be resolution independent – that is, a WPF application should scale perfectly no matter the system’s DPI setting (excluding any bitmap graphics, which mightn’t look as nice as the vector parts).
Instead of measuring things in pixels, WPF uses Device Independent Units (DIUs). If you only ever use 96 DPI (100%), you won’t notice the difference: at that setting, 1 pixel is the same as 1 DIU. Increase the system DPI, though, and this will no longer hold true. For example, at 120 DPI (125%), 1 DIU will be represented as 1.25 pixels. At 144 DPI (150%), 1 DIU = 1.5 pixels. At 192 DPI (200%), 1 DIU = 2 pixels.
Notice that at 120 DPI and 144 DPI, the number of pixels in 1 DIU is not an integer. In cases like these – when edges fall in the middle of screen pixels – WPF uses anti-aliasing by default. This can, however, result in lines that seem blurry (after all, that’s what anti-aliasing does). If this behaviour is undesirable, one can use UIElement’s SnapsToDevicePixels property.
WPF’s built-in handling of DPI scaling is great: in most cases, it should be transparent to both the programmer and user.
Sometimes, though, one might want to measure lengths in pixels, not DIUs. For example, Keiki’s custom window border for when the DWM (Aero) is disabled needs to be 1 pixel thick at any DPI (this is how the system’s notification area applications look). So, how can we specify this?
First, we need to get the system’s DPI setting:
// get the handle of the window
HwndSource windowhandlesource = PresentationSource.FromVisual(this) as HwndSource;
// work out the current screen's DPI
Matrix screenmatrix = windowhandlesource.CompositionTarget.TransformToDevice;
double dpiX = screenmatrix.M11;
double dpiY = screenmatrix.M22;
dpiX and dpiY will hold values like 1.0 (96 DPI), 1.25 (120 DPI), 1.5 (144 DPI) and 2.0 (192 DPI).
To specify a pixel measurement, we simply divide the DIU measurement by the DPI factor (dpiX and dpiY should always be the same – at least in Windows 7 and earlier):
WindowBorder.Margin = new Thickness(3 / dpiX);
This will make the margin 3 pixels thick at any DPI. (For example, at 120 DPI, dpiX = 1.25. 3 / 1.25 = 2.4 DIUs. 2.4 DIUs will be converted by WPF to 3 pixels.)
Fedir Nepyivoda has a neat solution to this problem: instead of manually converting DIU measurements, he created a PixelBorder control (inheriting from Border) that overrides MeasureOverride. Have a look here.
The GetSystemMetrics function in Windows retrieves system metrics and configuration settings. One such metric is the recommended size (width and height) of ‘small icons’:
Small icons typically appear in window captions and in small icon view.
Another place where small icons show up is the notification area.
MSDN contains a guide to Creating DPI-Aware Applications. It notes the challenge posed by raster graphics and different DPIs. Unlike vector graphics, which can scale without a loss in quality, distinct raster images must be created for different resolutions in order to avoid unpleasant scaling artefacts. (In fact, this is perhaps overstating the benefits of vector graphics: the level of detail suitable for a high-resolution image is not necessarily suitable for a low-resolution image, so using the same vector for all sizes doesn’t always make sense.) Windows icons, as of Windows 7, contain only raster graphics.
Small Icon Sizes
The small icon size varies according to the system DPI and OS version:
|DPI Setting||Windows 7, XP||Windows Vista|
|96 (Default, 100%)||16×16||16×16|
The sizes for Windows Vista (apart from the size at 96 DPI) don’t make much sense – they don’t match up with the DPI scaling ratio. It is possible that this was a mistake, hence the change in Windows 7.
So, if you want to make sure your small icon (e.g. notify icon) looks beautiful under the widest possible range of systems, you should ideally include the images with the sizes 16×16, 20×20, 22×22, 24×24, 26×26, 32×32 and 36×36. If that sounds like a lot of work (it shouldn’t be with a high quality tool like Axialis IconWorkshop), Microsoft’s own recommendation is to include 16×16 and 32×32 pixel icons. Keep in mind, though, that scaling either of those sizes to 20×20 or 22×22 pixels can result in a rather awful-looking icon. While it is still rare to see anything but the default setting of 96 DPI, this will not be the case forever.
WinForms Icon Sizes
When using the System.Drawing.Icon class, it is a good idea to use one of the constructors that takes the icon size as a parameter.
Windows Forms conveniently exposes a property called SmallIconSize in the SystemInformation class. This property gives us a System.Drawing.Size corresponding to values listed above, which we can put straight into our icon constructor:
System.Drawing.Icon icon = new System.Drawing.Icon(iconstream, System.Windows.Forms.SystemInformation.SmallIconSize);
Both WPF and WinForms wrap around the Win32 GetSystemMetrics function taking the arguments SM_CXSMICON (small icon width) and SM_CYSMICON (small icon height).
Over the past month I’ve looked at how to implement a Windows 7-style notification area application in WPF.
I covered 6 different topics:
- Part 1: Removing Border Resize
- Part 2: Notify Icon Position – Windows 7
- Part 3: Taskbar Position
- Part 4: Multiple Monitors & Working Area
- Part 5: Fixing Aero Border Padding
- Part 6: Notify Icon Position – Pre-Windows 7
As promised, I’ve put together a small sample project to illustrate all this code working together (with some added polish):
42,775 bytes; SHA-1: 513E998F4CCFC8C5BB6CA9F8001DA204C80FDF3A
The code has a good level of documentation, but I recommend you read the above posts to understand the ideas behind it.