The correct way to determine if a file is a directory.

By , November 30, 2016 1:41 pm

After writing for Microsoft’s Windows platform for 20 years I thought I knew all I could know about GetFileAttributes(). Until I found a rather odd and subtle bug in some code that interacted with data supplied by the user of the software. A call would succeed that I expected to fail. Naturally this meant the software didn’t make the right choices and instead of being presented with an helpful dialog explaining what had failed, the software sat silently in a corner humming to itself waiting for the user to work out what had happened. The failure was that I was presenting incorrect data to GetFileAttributes() assuming that it would always fail for bad input. How wrong I was!

I thought I’d write up what can go wrong with GetFileAttributes().

It’s tempting to test if a file is a directory by writing code like this:

if ((GetFileAttributes(fileName) & FILE_ATTRIBUTE_DIRECTORY) != 0)
    // file is a directory

The above looks logically correct. But there are problems with it.

First, a refresher on file attribute values…

File Attributes

The list of defined file attributes is in WinNT.h. The values are shown below.

#define FILE_ATTRIBUTE_READONLY             0x00000001  
#define FILE_ATTRIBUTE_HIDDEN               0x00000002  
#define FILE_ATTRIBUTE_SYSTEM               0x00000004  
#define FILE_ATTRIBUTE_DIRECTORY            0x00000010  
#define FILE_ATTRIBUTE_ARCHIVE              0x00000020  
#define FILE_ATTRIBUTE_DEVICE               0x00000040  
#define FILE_ATTRIBUTE_NORMAL               0x00000080  
#define FILE_ATTRIBUTE_TEMPORARY            0x00000100  
#define FILE_ATTRIBUTE_SPARSE_FILE          0x00000200  
#define FILE_ATTRIBUTE_REPARSE_POINT        0x00000400  
#define FILE_ATTRIBUTE_COMPRESSED           0x00000800  
#define FILE_ATTRIBUTE_OFFLINE              0x00001000  
#define FILE_ATTRIBUTE_ENCRYPTED            0x00004000  
#define FILE_ATTRIBUTE_VIRTUAL              0x00010000  

Rather strangely, the invalid attributes flag is defined in a different file, WinBase.h.


Problem 1

What if GetFileAttributes() fails? If the file doesn’t exist, the call fails. If the filename specifies a computer name, the call fails. See GetFileAttributes() documentation for more informtion. When GetFileAttributes() fails it returns INVALID_FILE_ATTRIBUTES. This error status passes the above test. OK, so add an additional check and the code becomes

DWORD attribs;

attribs = GetFileAttributes(fileName);
if ((attribs != INVALID_FILE_ATTRIBUTES) &&
    ((attribs & FILE_ATTRIBUTE_DIRECTORY) != 0))
    // file is a directory

Problem 2

Even with the above file-does-not-exist problem solved there is another problem. The file could be a directory, but it could be a directory that you don’t want. For example what if you’ve allowed the user to specify the directory name and they typed _T(“/”), or what if your filename creation code has a bug in it that fails when passed an empty name, resulting in a calculated filename of _T(“\”). What then?

In these cases the following calls all return 0x16.


0x16 means hidden (0x02), system (0x04), directory (0x10).

It’s a reasonable bet that in your code, any code looking for a directory to use is probably not looking for a hidden directory and almost certainly not intending to use a system directory. OK, time for a new implementation.

DWORD attribs;

attribs = GetFileAttributes(fileName);
if ((attribs != INVALID_FILE_ATTRIBUTES) &&         // check if a valid file
    ((attribs & FILE_ATTRIBUTE_DIRECTORY) != 0) &&  // file is a directory
    ((attribs & FILE_ATTRIBUTE_HIDDEN) == 0) &&     // file is not hidden
    ((attribs & FILE_ATTRIBUTE_SYSTEM) == 0))       // file is not system
    // file is a directory that isn't hidden and isn't system

What about files, rather than directories?

It’s natural to think about implementing checks for if a filename identifies a file rather than a directory. You test for this in exactly the same way but looking for different attributes. You’ll want to exclude FILE_ATTRIBUTE_DIRECTORY and then depending on the job your code is doing you’ll want to consider excluding files depending upon the following attributes:


and of course, you might also want to consider FILE_ATTRIBUTE_HIDDEN and FILE_ATTRIBUTE_SYSTEM.

Additional reading

Microsoft documentation on GetFileAttributes().

Why is GetFileAttributes the way old-timers test file existence? Old New Thing.

How to make your MFC (or non MFC) program support high DPI monitors. The easy way.

By , November 29, 2016 10:35 am

A few years ago Microsoft introduced support for very high resolution monitors. Such monitors might have nearly 4000 pixels horizontally and over 2000 pixels vertically. This provides wonderful scope for editing photographs and providing great graphics. But at your normal scaling the text on your displays starts looking a bit small. This is typical if you’ve specified your text height in pixels. Which from what I’ve seen is how a lot of people (most?) do it. “Oh, 14 look looks OK, I’ll go with that”. Looks fab for a 21 year. No so good for your customers over 40 though, most of them are wearing glasses, and so will you be when you get there (or contacts, you know what I mean).

This approach isn’t going to work with high DPI displays. You need to think in terms of point sizes for text, like you would if you are printing a document. Once you have an appropriate point size for your normal non-scaled (non high-DPI) display you can then just get the correct font height in pixels (based on the point size) and multiply by a scale factor to determine the correct column width for any columns in grids, or any graphics that need scaling.

Getting the scale factor

Non scaled monitors are deemed to be monitors that display at 96 DPI. From this the following table follows:

DPI scaling
96 100%
120 125%
144 150%
192 200%

You can calculate a scale factor for the whole system, or a scale factor per monitor – if you have monitors with different display facilities. The ability to calculate a scale factor per monitor only works on Windows 8.1 and Windows 10 onwards. You can find out more about this using the GetDpiForMonitor() function. For the purposes of this discussion we will only cover getting the system scale factor.

If you are thinking of doing per-monitor scaling, you might be well served by first doing system wide scaling, because it is simpler and will introduce you to most of the problems you will face, but in an easier to manage problem space than per-monitor scaling. Stepping from a working system wide scaling to per monitor scaling should be a lot easier than going from non-scaling to per-monitor scaling in one go.

double getSystemScaleFactor()				// returns 1.0 for no scaling
	// some simple caching to speed things up

	static int		calculatedScale = FALSE;
	static double	scale = 0;

	if (calculatedScale)
		return scale;

	// get DPI for the system

	HDC		hdc;

	hdc = ::GetDC(NULL);

	UINT	dpiX = 96;		// default DPI

	dpiX = GetDeviceCaps(hdc, LOGPIXELSX);

	scale = (double)dpiX / 96.0;
	if (scale < 1.0)
		scale = 1.0;		// prevent funny business with super large monitors returning very low DPI values

	::ReleaseDC(NULL, hdc);

	calculatedScale = TRUE;
	return scale;

We also need some supporting functions that will assist us during the following phases.

  • We need to be able to calculate a font point size based on a font pixel height.

  • We need to be able to calculate a font pixel height based on a font point size.

Getting a font point size


double getFontPointSize(HDC		hDC,
			DWORD	pixelSize)
	LONG	pixPerInch = GetDeviceCaps(hDC, LOGPIXELSY);
	double	points = (pixelSize * 72.0) / pixPerInch;

	return points;


double getFontPointSize(CDC		*dc,
			DWORD	pixelSize)
	if (dc == NULL)
		return getFontPointSizeForDefaultDC(pixelSize);
		return getFontPointSize(dc->GetSafeHdc(), pixelSize);

Getting a font pixel height

LONG getFontHeightForDefaultDC(double	pointSize)		// returns font height for the appropriate screen
	// this function can be optimized by using a simple cache on the point size (worth it in some situations!)

	HDC		hdc;

	hdc = ::GetDC(NULL);
	height = getFontHeight(hdc, pointSize);
	::ReleaseDC(NULL, hdc);
LONG getFontHeight(HDC		hDC,
		   double	pointSize)		// returns font height for the appropriate screen
	LONG	pixPerInch = GetDeviceCaps(hDC, LOGPIXELSY);
	LONG	lfHeight = (LONG)((pointSize * (double)pixPerInch) / 72.0);

	return lfHeight;
LONG getFontHeight(CDC		*dc,			// can be NULL for default screen
		   double	pointSize)		// returns font height for the appropriate screen
	if (dc == NULL)
		return getFontHeightForDefaultDC(pointSize);
		return getFontHeight(dc->GetSafeHdc(), pointSize);

Updating your code

Versions of MFC since Visual Studio 2010 support MFC scaling, although nothing happens by default. You still have to supply the scale factor for the fonts in use. These fonts will mainly be for any text drawn on graphics displays and for any owner drawn controls such as lists and grid controls which sit on top of huge amounts of data that can't be reliably stored inside the control. You need to find the places where you create fonts and set the font height. Often this will be when you create a font or when you set the lfHeight member of a LOGFONT structure. Once we have these locations we can update the code.

The sequence of operations to update your code is as follows:

  • You need to find each location where a font height is set.

  • For each location you need to calculate the point height and replace the integer height with a call to calculate a height based on a point height.

  • For each location verify that the calculated height is correct for a non-scaled display.

  • For each location verify that the font now scales with the display.

Because the new height calculated by getFontHeight() is based on a point size we don't need to worry about scaling the returned value with getSystemScaleFactor(), the point size is relative to how we view the display, so is automatically the correct scale.


Search for uses of the MFC method CFont::CreateFont(), or the Win32 function ::CreateFont(). The first parameter is the height of the font.

#define FONT_SIZE		16


font.CreateFont(FONT_SIZE,		// default height
		0,			// default width

We need to know what point size of the specified font equates to our chosen (above) font height of 16 pixels. The font height may change according to the font face, italics, weight etc. So you do need to check this for each one and not just rely on it being what you think it is. This is why I haven't provided a table of values for you to plug in.

We can calculate the font point size using the following code, passing in the device context of the appropriate display.

double testPointSize;

testPointSize = getFontPointSize(hDC, FONT_SIZE);

Just add the code before the call to CreateFont, build it, put a breakpoint there and when it stops in the debugger make a note of the value testPointSize. In our tests, a point size of 11.0 gave us a pixel height of 16 (FONT_SIZE).

Once we know testPointSize we can update the code, as shown below. We notated our code with info about how it was tested to help anyone that ends up at this code wondering why these sizes are used. People won't always search the version history and disk space is cheap. Comments help. Use them.

LONG	lfHeight;

lfHeight = getFontHeight(GetDC(), 11.0);		// aiming for lfHeight == 16 (at "small" 1920x1080);

// set font for tab control

font.CreateFont(lfHeight,		// default height (used to be hard coded at 16)
		0,			// default width

If the above font is going to be created many times, caching the value of getSystemScaleFactor() and/or caching the fonts created will be a good idea.


Search for uses of the MFC method CFont::CreateFontIndirect(), or the Win32 function ::CreateFontIndirect(). With this usage you are interested in the lfHeight value of the LOGFONT structure passed to CreateFontIndirect. The procedure is identical as for CreateFont() described above.

Before scaling:

pDispInfo->item.lfFont.lfWeight = FW_NORMAL;
pDispInfo->item.lfFont.lfHeight = -11;

After scaling:

pDispInfo->item.lfFont.lfWeight = FW_NORMAL;
pDispInfo->item.lfFont.lfHeight = -getFontHeightForDefaultDC(8.5);		// aiming for lfHeight == -11 (at "small" 1920x1080);

Alternative implementation

Ignore point sizes and just multiply your existing font pixel heights by getSystemScaleFactor(). This is less work to implement, but results in lots of calls to getSystemScaleFactor() throughout your code base. If you eventually decide to implement per-monitor scaling I think you will regret choosing this implementation method.

pDispInfo->item.lfFont.lfWeight = FW_NORMAL;
pDispInfo->item.lfFont.lfHeight = -11 * getSystemScaleFactor();

Setting column widths

If you are setting column widths in a grid control you'll need to scale these appropriately.

Before scaling:

m_Grid.SetColumnWidth(0, 200);
m_Grid.SetColumnWidth(1, 400);

After scaling:

 double scaleFactor;

scaleFactor = getSystemScaleFactor();
m_Grid.SetColumnWidth(0, (UINT)(200 * scaleFactor));
m_Grid.SetColumnWidth(1, (UINT)(400 * scaleFactor));

Implementation note: For per-monitor scaling you'll need to update these calls to get the scale factor for the appropriate monitor.

How to test

To test you don't need to purchase a high DPI monitor. Although if you do have a high DPI monitor you will be more aware of the issues your high DPI using users have.

  • Change the text scaling size from 100% to another value.

  • Right click on the Windows desktop.

  • Choose Screen Resolution from the context menu.

  • Click the link Make text and other items larger or smaller.

  • Change the text size slider larger or smaller as appropriate. Notice that as you change it a warning notice is displayed about different scaling results. Click Apply. Now close the dialog box.

When you click Apply you should notice the text and graphics scale up or down in relation to the choice you made. "Aha! I've done it!" you think. Not so fast. This is just Windows pretending everything is OK. You'll notice some of the items that have been scaled up don't look so perfect, a bit blurry. This is because this is Windows virtualising the scaling. This also means that many of the fonts you need to change will have been automatically changed for you - for this session only! Don't let this fool you into thinking your job is done. If you want to see what they'll look like for your customers you need to log out and then log back in. You don't need to shutdown the computer or reboot it. Just log out and then log in (not lock the screen and log in!).

When you log in, start your application. Now look at the text you are updating to be responsive to scaling. Has it scaled? Yes? Great! No? You must have missed something. Failed to update it to work from point sizes? Columns too narrow? Forgot to add the multiply by scaling factor? Debug as necessary. Just add developer.

When you've got this working, you're going to have to go back to normal font size (same procedure as before, but just move the text slider all the way to the left), then log out and log in. Now do your tests for the next font. Rinse and repeat. You are going to be logging out and logging back in a lot during this work. Or purchase a modern laptop with a QHD screen or a nice QHD monitor (or better!).

Optimisations and improvements

We've placed all the helper functions I described in their own namespace to separate them from the rest of the code.

We've also used some caches to improve the query time of some requests. We didn't find this bothersome until we had a grid with a lot of items (about a million) that wanted to do a specific query. We thought the delay was unacceptable. Adding a cache fixed that quite simply.

Per Monitor DPI.
You could look into supporting different DPI values for each monitor. See the GetDpiForMonitor() link we mentioned earlier in the article.

You may also need to scale icons (in toolbars etc) accordingly. In practice we haven't found this to be a huge problem so long as your non-scaled icons are reasonably large. Ideally you could scale your icons, but we've found scaling icons to be the least important thing for users of our software. What they really want is legible text, hence our focus on that in this article.

X and Y scaling.
If you've been paying attention you've noticed that getSystemScaleFactor() returns the horizontal scale factor. We've used this everywhere, for both scaling of font heights (vertical) and scaling of column widths (horizontal). You could choose to calculate a vertical scale factor and use that for the scaling of font heights.

The vertical scale factor should be the same (barring any hardware restrictions) to the horizontal scale factor in order to preserve image integrity - so we haven't bothered to calculate a vertical scaling factor. In practice we've been happy with the results returned from using one scale factor.


Now you know everything you need to know to get your Win32 or MFC program displaying well on high DPI displays. There's a lot of great information about this on the web, but reading it can make it seem quite daunting, when in actual fact it's very straight forward. We recommend changing one font at a time, then test, then check with a scaled display, then move on to the next font. Don't try to do them all at once.

If you're testing without a high DPI display, once you think it's all good to go, show it to some of your customers that have high DPI displays that have been bending your ear about supporting high DPI displays. They'll be pleased to tell you what isn't quite right. Across all our applications, we missed on thing that a customer spotted.

I'd also like to extend a big Thank You to Anna Jayne Metcalfe at Riverblade for some helpful pointers when we started this work. Riverblade make the excellent Visual Lint static analysis tool analyser, an excellent complement to our dynamic analysis tools.

Further Reading

Writing Win32 applications and high DPI.

MFC applications default to being DPI aware.

Getting the DPI per Monitor.

Getting the Logical Monitor Width.

High DPI Tutorial.

We’ve been quiet for a while, sorry about that.

By , November 28, 2016 3:29 pm


It’s been a while since we posted anything on the blog. If you weren’t a customer, regularly receiving our software update emails you might think we weren’t going anything.

That’s an oversight on our part. We’re hoping to rectify this over the next few months, posting more useful information both here and in the library.

_tempnam and friends

Our most recent update has been to update C++ Memory Validator provide memory tracking for the _tempnam group of functions. These are _tempnam, _tempnam_dbg, _wtempnam, _wtempnam_dbg.

This support is for all supported compilers, from Visual Studio 2015, Visual Studio 2013, Visual Studio 2012, Visual Studio 2010, Visual Studio 2008, Visual Studio 2005, Visual Studio 2003, Visual Studio 2002, Visual Studio 6. Delphi and C++ Builder, Metrowerks compiler, MingW compiler.

.Net support, for the future

Internal versions of C++ Coverage Validator can provide code coverage statistics for .Net (C#, VB.Net, J#, F#, etc) as well as native languages (C++, C, Delphi, Fortran 95, etc).

Internal versions of C++ Performance Validator can provide performance profiling statistics for .Net (C#, VB.Net, J#, F#, etc) as well as native languages (C++, C, Delphi, Fortran 95, etc).

UX improvements

All tools, free and paid, have had the UX for filename and directory editing improved so that if a filename doesn’t exist it is displayed in red and if it does exist it is displayed in it’s normal colour (typically black). See screenshots (from Windows 8.1).

Non existent filename:

Existing filename:

Panorama Theme by Themocracy