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_wid th_pixels) / 4
dialog_pixels_y = (dialog_units_y * average_font_character_hei ght_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(poi ntsize*10, typeface);
MyFont.GetLogFont(&MyLogFo nt);
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.
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_wid
dialog_pixels_y = (dialog_units_y * average_font_character_hei
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(poi
MyFont.GetLogFont(&MyLogFo
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.
Well, you can always obtain the actual text size in pixels using 'GetTextExtentPoint32()'
BTW - see also http://msdn.microsoft.com/library/default.asp?url=/library/en-us/gdi/fontext_56yb.asp ("String Widths and Heights")
http://msdn.microsoft.com/library/default.asp?url=/library/en-us/wcesdkr/htm/_wcesdk_win32_getdialogbaseunits.asp ("GetDialogBaseUnits") could be interesting for what you want to do...
http://msdn.microsoft.com/library/default.asp?url=/library/en-us/wcesdkr/htm/_wcesdk_win32_getdialogbaseunits.asp ("GetDialogBaseUnits") could be interesting for what you want to do...
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.
>>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.
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)
That's why they have created 'MapDialogRect()' (http://msdn.microsoft.com/library/default.asp?url=/library/en-us/winui/dlgboxes_4hf8.asp)
ASKER
Oh duh, create an invisible window. Of course, Why didn't I think of that?? Thanks, I'll try it!
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_BLAN K_DIALOG_T EMPLATE);
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.CreatePointFon t(nDesired PointSize * 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(&Desire dFont);
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(&De siredFontI nfo);
pMyDialog->GetFont()->GetL ogFont(&Ac tualFontIn fo);
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->G etSafeHWnd (), 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.
I create an invisible dialog like this:
CDialog* pMyDialog = new CDialog;
pMyDialog->Create(IDD_BLAN
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.CreatePointFon
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(&Desire
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(&De
pMyDialog->GetFont()->GetL
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->G
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...
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.
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.
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?
m_pPixelConversionWindow->
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
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
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!!
So thanks! I have it working now. I really appreciate your help on this!!