Link to home
Start Free TrialLog in
Avatar of ris
ris

asked on

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;
LOGFONT MyLogFont;
MyFont.CreatePointFont(pointsize*10, typeface);
MyFont.GetLogFont(&MyLogFont);

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.
Avatar of jkr
jkr
Flag of Germany image

Well, you can always obtain the actual text size in pixels using 'GetTextExtentPoint32()'
Avatar of ris
ris

ASKER

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.
Avatar of ris

ASKER

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()' (http://msdn.microsoft.com/library/default.asp?url=/library/en-us/winui/dlgboxes_4hf8.asp)
Avatar of ris

ASKER

Oh duh, create an invisible window.  Of course, Why didn't I think of that??  Thanks, I'll try it!
Avatar of ris

ASKER

I tried your suggestion but without success.  Here's the problem:

I create an invisible dialog like this:

CDialog* pMyDialog = new CDialog;
pMyDialog->Create(IDD_BLANK_DIALOG_TEMPLATE);

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:

pMyDialog->SetFont(&DesiredFont);

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;
DesiredFont.GetLogFont(&DesiredFontInfo);
pMyDialog->GetFont()->GetLogFont(&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...
Avatar of ris

ASKER

From the MSDN documentation on MapDialogRect():

hDlg
[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.
Avatar of ris

ASKER

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:

m_pPixelConversionWindow->CreateEx(
    NULL,
    AfxRegisterWndClass(NULL),
    TEXT("Conversion Window"),
    WS_CHILD,
    0,0,1,1,
    NULL,
    NULL)

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?
ASKER CERTIFIED SOLUTION
Avatar of jkr
jkr
Flag of Germany image

Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial
Avatar of ris

ASKER

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!!