Windows Is Lying To You… With DPI Virtualization

DPI Virtualization in Windows

Windows Vista (and subsequently, Windows 7 & 8) introduced a new feature called DPI Virtualization.

DPI Virtualization means Windows will automatically “resize” your forms and form objects for you, with no coding or resizing required on your part.

Sounds great, doesn’t it? Well, not quite. Remember my “ugly” form in an earlier post, running at 144dpi? It was DPI Virtualized by Windows 7, and the result was a blurry window.

DPI Virtualization also requires the code listing from a previous post to fail, every time. Why? Because when the code asks Windows, “Hey, what’s the current setting?”, Windows Vista, 7 and 8 will always answer “your font factor is 1” (no resizing required) if the user has selected to use DPI Virtualization.

“Whoa, whoa, whoa, Kevin! If the user has selected DPI Virtualization?”

Yes. Windows Vista, 7 and 8 have two different modes of DPI scaling: XP Style, and DPI Virtualization.

Setting the DPI scale mode in Windows 7

Setting the DPI scale mode in Windows 7

If the user changes her DPI setting, and checks the “Use Windows XP style DPI scaling” checkbox, Windows Vista, 7 and 8 will return the expected (truthful) result from the previous code listing – just like XP did.

So, a DPI of 144dpi (150%) with this box unchecked, results in the following:

The correct font factor with XP style scaling turned on

The correct font factor with XP style scaling turned on

And, just like I would do with the XP result from earlier, I would want to resize my forms and form objects, making them 50% larger than “normal.”

But if the user has not checked the box, here’s what Windows tells me about the “font factor” (notice the messagebox is also a bit blurry):

Thanks, Windows, for lying and making my forms blurry

Thanks, Windows, for lying to me and making my forms blurry

Great. The user has selected 144dpi, but my app does not know this because Windows has said, “Don’t worry, no need to resize anything. All is good.”

And my user gets to see “somewhat” resized, yet blurry, forms in my app.

What we need is a “Windows Lie Detector” to make sure Windows stops lying to us.

How do we do this?

We need to tell Windows that the app is “DPI Aware”.

And that’s exactly what we’ll look at in tomorrow’s post.

 

Related Links (With much better explanations)

High DPI Settings In Windows
Fixing Windows Programming

 

From A Hog To Just A Pig With A Simple Windows API Call

One of the first questions I got about the Desktop Alerts was, “How much memory and other system resources does this use?”

This was during the presentation in Chicago in December of 2006. My response was the typical, “Oh, not much at all. It’s very light.”

Well, I fired up Task Manager (in front of everyone in the room), and was shocked to find this tiny little app using 10MB of memory — even when it was just sitting there, doing nothing!

“Hmmm,” I thought, “This thing is a hog.”

Not a huge issue, especially compared to a Catastrophic Failure, so I put it on the backburner (which is to say I promptly forgot all about it — if only my apps could free up memory as easily as my brain does).

I recently worked on an app that uses the Microsoft Web Browser control on a Visual FoxPro form as the primary UI for the app. Works well for the most part, but checking memory usage in Task Manager showed a tremendous amount of resources being hogged by the app, even when the user is just sitting there looking at the screen and doing nothing.

“Hmmm,” I thought, “this thing is a hog, too.”

(I started looking at the app’s memory usage after a couple of users with “programming experience” mentioned it…)

Luckily for me, in January of this year Sergey Berezniker wrote about using the Windows API to lower the memory usage of your application.

Simple, straightforward, and very simple to implement.

I put it in the app, and was amazed by how much memory was saved by a simple function call. I went from about 60MB at application startup to about 8MB.

After 6 months in production, I’ve seen no problems reported about the app that would indicate a problem with this function, so yesterday I decided to look at adding it to the Desktop Alerts.

Here’s a quick sampling of the results (Windows XP Professional Service Pack 3):

1. AlertManager Initialized, waiting for something to do:

Before Change (Hog) After Change (Pig)

2. First Alert created and visible:

Before Change (Hog) After Change (Pig)

3. Three alerts visible on screen:

Before Change (Hog) After Change (Pig)

4. All alerts cleared, AlertManager waiting for next command:

Before Change (Hog) After Change (Pig)

 

So, with one simple Windows API call, we’ve reduced the memory usage by almost 80%, turning this gigantic hog into a smaller pig. I’ve seen similar results in Vista, though the memory usage in Vista was much lower to start with than in XP, so the results of the change aren’t quite as dramatic.

One interesting thing, though. See the User Name column in the screenshots? The user changed from Kevin Ragsdale to SYSTEM. So, not only has a hog become a pig, its name has been changed as well. In Windows Vista, the User Name stays put as Kevin Ragsdale.

Anyone that can explain this to me without causing my head to explode — feel free to explain in the comments.

This API function is available in Windows 2000 and higher so, if you have any OS stragglers you’ll want to bracket the function call with something like this:

IF VAL(OS(3)) >= 5    && Skip if earlier than Windows 2000
   ** Do your thing
ENDIF

And yes, I do have a ton of code “out there” that uses this bracket a lot…

Don’t Be So Hard On Yourself (or, ShellExecute() to the Rescue!)

I’ve got a bad habit of always trying to reinvent the wheel, even when I’ve got a perfectly good wheel right in front of me.

I just wrapped up some work on a Visual FoxPro app that uses a lot of rich-text format (RTF) files, and I was hitting a brick wall when it came to printing the documents.

I tried the FoxWikiGoogle searches, even went back to my KiloFox book (excerpt here), but I just couldn’t find the right method to make the program do what I wanted it to do.

Then I thought, “Hmmm… every Windows computer has an RTF editor, right? And this editor has all the print functionality built-in. Very interesting…

Plus, if the user has word-processing software (Office, OpenOffice, etc.) and it’s properly registered as the handler for RTF files, it’ll have all the print functionality built-in, too.

So, instead of pulling out the remaining few hairs on my head, I decided to go the ShellExecute() route, and set the menu up to open the user’s default RTF application in two different ways:

  • EDIT mode –  (The Print menu item – the user can do what they want with the document, then select the printer, etc.)
  • PRINT mode (The Quick Print menu item – open the app, and print the document to the default Windows printer)
Print menu example

 

So, I went from researching and trying all kinds of workarounds to this:

ShellExecute(FindWindow(0,_SCREEN.Caption),"Open",lcTempFile,"",JUSTPATH(lcTempFile),1)

and

ShellExecute(FindWindow(0,_SCREEN.Caption),"Print",lcTempFile,"",JUSTPATH(lcTempFile),1)

And immediately felt relieved for being just a little less hard on myself…

On a side note, the app uses the CommandBars Library from Alex Grigorjev. I was lucky enough to still have an active subscription when he released Version 7.0 (which includes the Ribbon interface).

VERY HIGHLY RECOMMENDED!!!

More info on the CommandBars library:

Creating a “Fading” Form

I love the Desktop Alerts in Outlook 2003. They provide useful information without interfering with my work. I can’t stand to be working on one thing and suddenly have a MESSAGEBOX appear from another app informing me that it just did something wonderful on my behalf. The Desktop Alerts simply “appear” on my screen for a few seconds, letting me know I have new mail. They even provide some details (name of sender, subject). If I want to read the email immediately, I simply click on the Alert and Outlook opens the message. Otherwise, I can ignore the alert and it will fade away.

I thought something like this would be a great enhancement for some of my clients, so I went about the task of finding out how to make my forms Fade-In, Wait a Few Seconds for User Input, and Fade-Out. I found a solution right away in the Solution Samples that ship with VFP: Transparent Forms.

A couple of Windows API calls can make your form transparent, to the level of transparency you require. The trick to making my form fade-in and out was to add a couple of timer controls to the form. The timers call the SetLayeredWindowAttributes function in a FOR loop, creating the fade-in/fade-out effect.

I put together a simple “splash” screen (you can download it here), which demonstrates the effect. The zip file contains three files: FLASHSPLASH.SCX, FLASHSPLASH.SCT, and 192255.JPG (a gradient JPG that you can set as the form’s picture if you want to).

Two caveats: to create the effects, the user must be running Windows 2000 or higher, and the effects only work on Top-Level forms.

The form contains a few custom properties:

  • lCanFlash: A boolean value (.T. if Windows 2000 or higher, otherwise .F.)
  • nStepUp: An integer which determines how quickly the form will appear (used by the STEP clause in the first timer’s FOR loop). The higher the number, the faster the form fades-in. Defaults to 0.25
  • nStepDown: An integer which determines how quickly the form will disappear (used by the STEP clause in the second timer’s FOR loop). This number must be less than zero! Defaults to -0.25
  • nTransparency: An integer which determines the level of transparency for the form. A value of 25 is a “solid“ form. A value of zero (0) makes the form completely transaparent.

The lCanFlash property has an assign method, which basically DECLAREs the API functions and sets the form as completely transparent (if Windows 2000 or higher). The lCanFlash property is set in the form’s Init() method.

In a nutshell, here’s what the sample form does:

  1. Checks to see if the OS is Win2K or higher. If yes,
    1. Sets the lCanFlash property to .T., which in turn,
    2. DECLAREs the API Functions
    3. Calls the API Functions to make the form completely transparent (invisible)
  2. Turns on the first timer, which uses the form’s custom properties to drive a FOR loop, which calls the SetLayeredWindowAttributes API function — causing the form to gradually appear
  3. Since the sample form is a splash screen, another little FOR loop updates a label control, to make the form look like it’s “doing“ something
  4. Turns on the second timer, which also uses the form’s custom properties to drive a FOR loop, which makes the form gradually disappear
  5. The second timer then Releases the form. The form’s Destroy method issues a CLEAR DLLS command

I have an app which periodically checks a server to see if any of my user’s customer’s have placed orders. If orders are found, they are downloaded for processing, but it’s all done in the background. The user’s typically have no idea an order has been placed unless they stop what they’re doing to either go to a website which shows outstanding orders, or by launching the interactive app.  By adding my own “desktop alerts“ to the system, I can give the user a professional-looking piece of information which shouldn’t interfere with their work.

Hope you like it. Since this is my first attempt to share something with the FoxPro community, any feedback would be greatly appreciated. Once I get done with my “desktop alert“ system, I’ll pass it along.

Sample Form Download

Edited: Probably best to try this out in VFP 7,8 or 9. It’s been so long since I’ve actually “used“ VFP 6, I forgot about the hoops you’ll have to jump through to make this work (like HWND). Thanks Fred for your feedback! – Kevin