Convert dialog units + font info into pixels?

I am trying to scan a variety of binary resource files (.res files) for dialog box resources that match a certain size restriction in PIXELS.  The problem is that the dialog resource structures supply dialog resource sizes in abstracted dialog units which the OS then converts to pixels at run-time depending on certain modes and the font used.

I start out with the following information:
dialog_units_x - dialog width in dialog units
dialog_units_y - dialog height in dialog units
font typeface name (UNICODE string)
font point size

I want to translate this information into the width and height of the dialog in PIXELS.  According to MSDN, the conversion factor is like this:
dialog_pixels_x = (dialog_units_x * average_font_character_width_pixels) / 4
dialog_pixels_y = (dialog_units_y * average_font_character_height_pixels) / 8

My problem is determining the average font character width and height in pixels from the font face and point size.  I have tried using a CFont and doing something like this:

CFont MyFont;
MyFont.CreatePointFont(pointsize*10, typeface);

Unfortunately, the data in the LOGFONT structure is also in abstracted/special units rather than pixels.  I think what I probably need is the information in a TEXTMETRIC structure, but I can't tell how to get from a pointsize and typeface name to a TEXTMETRIC structure.  Any ideas?

My program is a command-line app using MFC (for data structures and some API encapsulation like CFont, etc) and I plan to run it under Windows 2000, NT, and XP to analyze .res files that are used to build Windows CE images.
Who is Participating?

Improve company productivity with a Business Account.Sign Up

jkrConnect With a Mentor Commented:
Argl, it seems that things are more difficult than I thought :o)

If you want to use "non-standard" fonts with dialogs, you need a DLGTEMPLATEEX struct to specify which one... as this isn't available that easy (and I got the impression that you prefer to use MFC), why not overriding 'CDialog::OnSetFont()'?
Well, you can always obtain the actual text size in pixels using 'GetTextExtentPoint32()'
Get 10% Off Your First Squarespace Website

Ready to showcase your work, publish content or promote your business online? With Squarespace’s award-winning templates and 24/7 customer service, getting started is simple. Head to and use offer code ‘EXPERTS’ to get 10% off your first purchase.

risAuthor Commented:
I've noticed both of those functions, but I can't figure out how I should use them to achieve my goal.  The problem is that both functions (GetTextExtentPoint32 and GetDialogBaseUnits) return information based on a device context, not on arbitrary font information.  So - keeping in mind that I'm in a command-line environment - how do I get a handle to a device context that is set up with the font that I want to test?
>>how do I get a handle to a device context that is set up
>>with the font that I want to test?

By creating an invisible window (simply don't call 'ShowWindow()') and selecting the font used into the device context. That all can be done from a console app.
risAuthor Commented:
GetDialogBaseUnits is a particularly nice function for what I want.  Unfortunately, it only works on the system font, and I need to do it on arbitrary fonts other than the system font, making it completely useless for my needs.  At least with the other ones you could change the font on your device context (however that is achieved) and get applicable information...
>>Unfortunately, it only works on the system font

That's why they have created 'MapDialogRect()' (
risAuthor Commented:
Oh duh, create an invisible window.  Of course, Why didn't I think of that??  Thanks, I'll try it!
risAuthor Commented:
I tried your suggestion but without success.  Here's the problem:

I create an invisible dialog like this:

CDialog* pMyDialog = new CDialog;

It all returns success codes so it seems to work.  Before calling MapDialogRect I need to change the font on the dialog, because my whole problem is to convert dialog units to pixels using ARBITRARY font settings.  So I create a CFont object like this:

CFont DesiredFont;
DesiredFont.CreatePointFont(nDesiredPointSize * 10, szDesiredFontFace);

Everything works, or at least returns success codes, to this point.  So now I need to set my dialog to use my desired font, so I do this:


Now unfortunately CWnd::SetFont returns void so there's no immediate way to know that it worked.  At first I assumed that it must not be able to fail, but the results of my program were indicating that it probably was failing, so I added some test code like this:

LOGFONT DesiredFontInfo;
LOGFONT ActualFontInfo;

At this point, an examination of ActualFontInfo compared to DesiredFontInfo shows that CWnd::SetFont() failed.  None of the font attributes from DesiredFont make it into the actual font loaded in the dialog.  Which means that when I get to my data conversion call:

MapDialogRect(pMyDialog->GetSafeHWnd(), pRect);

It succeeds, but it uses the default system font only.

What else can I do?  Do I need to set the font differently?  Create the dialog differently?  Any thoughts?  I assume that since the SetFont call is silently failing that none of the other API calls I could use will work either because they will meet the same limitation of working on the default system font only rather than my arbitrarily selected font.
Why are you using a dialog? A simple window would do it...
risAuthor Commented:
From the MSDN documentation on MapDialogRect():

[in] Handle to a dialog box. This function accepts only handles returned by one of the dialog box creation functions; handles for other windows are not valid.
risAuthor Commented:
I tried using a CWnd instead, but I can't create the window.  CWnd::CreateEx always fails because "the handle is not valid"  My function call looks like this:

    TEXT("Conversion Window"),

What am I doing wrong?  I have tried changing all of the parameters.  The only window handle I pass it is the parent window handle, which has to be NULL to indicate the desktop.  I fear that it won't create because I am in a command line environment and it knows that... The CDialog method created OK, but do you think the font couldn't be set because the window is invisible? or because I am in a command line environment? or for some other reason?
risAuthor Commented:
Hey good idea using DLGTEMPLATEEX to create the dialog with the appropriate font through CDialog::CreateIndirect().  That worked!  Even though CDialog::SetFont() would silently fail after creation, CDialog::CreateIndirect will create the dialog with any font I want. Following that, calls to MapDialogRect work correctly for translating the dialog units into pixels.

So thanks!  I have it working now.  I really appreciate your help on this!!
Question has a verified solution.

Are you are experiencing a similar issue? Get a personalized answer when you ask a related question.

Have a better answer? Share it in a comment.

All Courses

From novice to tech pro — start learning today.