Settin printer Fonts in C++ - Size problem

I am trying to set the font used to print within my application using the Windows API. I am using Microsoft Visual C++ Version 4.

I am using the following code to select and create a font:
      CHOOSEFONT cf;
      LOGFONT lf;
      HFONT hfont;

      /* Initialize members of the CHOOSEFONT structure. */

      cf.lStructSize = sizeof(CHOOSEFONT);
      cf.hwndOwner = (HWND)NULL;
      cf.hDC = hDC;
      cf.lpLogFont = &lf;
      cf.iPointSize = 0;
      cf.Flags = CF_SCREENFONTS;
      cf.rgbColors = RGB(0,0,0);
      cf.lCustData = 0L;
      cf.lpfnHook = (LPCFHOOKPROC)NULL;
      cf.lpTemplateName = (LPSTR)NULL;
      cf.hInstance = (HINSTANCE) NULL;
      cf.lpszStyle = (LPSTR)NULL;
      cf.nFontType = SCREEN_FONTTYPE;
      cf.nSizeMin = 0;
      cf.nSizeMax = 0;

      /* Display the CHOOSEFONT common-dialog box. */


      /* Create a logical font based on the user's   */
      /* selection and return a handle identifying   */
      /* that font.                                  */

      hfont = CreateFontIndirect(cf.lpLogFont);

      return hfont;

which I have taken direct from the online Help.  This seems to set the correct style but the point size is incorrect.  If I select Arial 10 point when prompted, the resulatant print appears to be more like Arial 13 point.  Arial 8 point is more like 10 point and so on for all sizes.  I have printed from my app and from Microsoft Word to the same printer to compare fonts and all fonts from my application are larger than anticipated.  This applies for all fonts, not just the Arial style.  I have also tried different printers but achieve the same result.

Using this line:
lfHeight = -MulDiv(PointSize, GetDeviceCaps(hDC, LOGPIXELSY), 72);
(again from the online help) and setting the lfHeight member of the struct used above produces HUGE fonts.  I made sure the mapping mode was set to MM_TEXT for this but still did not resolve the problem.

Is there another way I shluld be setting fonts in order to get the correct size that the user expects?

Please Note:  We are not using MFC in our application which is why I am going direct to the API.

Any help would be greatly appreciated.

Thanks in advance

Sean Hannan
Who is Participating?

[Webinar] Streamline your web hosting managementRegister Today

chensuConnect With a Mentor Commented:
I think that is because you are using screen fonts. You should use CF_TTONLY or CF_WYSIWYG | CF_BOTH | CF_SCALABLEONLY instead of CF_SCREENFONTS, use REGULAR_FONTTYPE instead of SCREEN_FONTTYPE.
Did you use the DC from Printer ?
PointSize specifies th font size in units of 1/10 of a point.

So you must use

lfHeight = -MulDiv(PointSize/10, GetDeviceCaps(hDC, LOGPIXELSY), 72);
Free Tool: IP Lookup

Get more info about an IP address or domain name, such as organization, abuse contacts and geolocation.

One of a set of tools we are providing to everyone as a way of saying thank you for being a part of the community.

WoodsterAuthor Commented:
Oliver - The font is larger than expected regardless of whether I use the printers DC or simply pass in NULL.

Nick - I am aware of the font size being specified in 1/10th of a point.  This is not the problem as the point size is not passed in to the CreateFont or CreateFontIndirect functions.  The LOGFONT struct is what is being passed in and this contains lfHeight and lfWidth members.
WoodsterAuthor Commented:
Anything other than CF_SCREEN_FONTS presents an error on the call to ChooseFonts:
"There are no fonts installed.Open the fonts folder from the control panel to install fonts."

Changing SCREEN_FONTTYPE to either REGULAR_FONTTYPE or PRINTER_FONTTYPE makes no difference.

After the call to ChooseFont, cf.iPointSize = selected point size * 10 and lf.lfHeight = cf.iPointSize / 10 * 4 / 3 regardless of the point size selected of the hdc being used in the cf struct (cf is the CHOOSEFONT struct, lf is the LOGFONT struct)
Do you have true type fonts installed on the computer?
WoodsterAuthor Commented:
Yes, There are numerous True Type fonts installed.  This same error message occurs if I use the CF_PRINTERFONTS flag.  Currently running Windows NT Workstation 4.  I have been testing with Arial and Times New Roman so far, both of which are true type fonts.
That's weird. Can you try it on other computers?
WoodsterAuthor Commented:
Have tried it on a separate Windows 95 PC and the same error is presented.  The flags used currently are:
cf.Flags = CF_TTONLY
WoodsterAuthor Commented:
I am guessing that the larger than expected size is being caused by the lfHeight member being too large.  The fact that it is 4/3 times larger than the pointsize seems to indicate that it is being scaled to the screen (4:3 being the x:y ratio).  Is this a fair assumption or just coincidence?

I am using a 3rd party library to handle most of the windows stuff so have had no previous experience with direct handling of DC's.  I have managed to simplify the creation of the printer DC to:

memset(&pd, 0, sizeof(PRINTDLG));
pd.lStructSize = sizeof(PRINTDLG);                        pd.Flags |= (PD_RETURNDC | PD_NOSELECTION | PD_DISABLEPRINTTOFILE);

and am passing pd.hDC to the ChooseFont function.  Has the printer DC been set up correctly?  The font is the same size on the printer (and on the screen - just that the screen font is the expected size and the printer font is larger than expected) REGARDLESS of whether I use pd.hDC or NULL in the call to ChooseFont.
Have you tried creating a font directly instead of using the font common dialog box?
WoodsterAuthor Commented:
No - I haven't.  As I only have limited Windows API experience I am unsure as to what parameters to pass in to either CreateFont or CreateFontIndirect.  Thoes that are being returned from ChooseFont appear to be incorrect judgint by the output and I have found no other examples showing manual creation of a font.  Any code snippets here would be appreciated so I can test it out.  Could you also point me to some info on how to create and print a print  job containing a simple 1 or 2 lines direct to the printer which would enable me to bypass any problems that may be thrown up by the application framework we are currently using.
The simplest example of CreateFontIndirect is

// Use defaults for most parameters
LOGFONT lf = { 0 };
lf.lfHeight = -::MulDiv(PointSize, ::GetDeviceCaps(hDC, LOGPIXELSY), 72);
::lstrcpy(lf.lfFaceName, _T("Arial"));

HFONT fnt = ::CreateFontIndirect(&lf);

For printing, see

Printing a Document

Creating a Printer Device Context

(Use StartDoc, EndDoc instead of Escape)
Also check out some GDI samples that come with Visual C++.
WoodsterAuthor Commented:
Thanks for the pointers to the printer code.  I think I have tracked down the source of the problem.  It appears to be in the application framework we are using.  If I create the font manually as in your code above, AND call SetMapMode(MM_TEXT) I can make it all work fine.

Looking in the code for the 3rd party libraries, each call to BeginPage in turn calls
SetWindowExt(hdc, columns, columns);
SetViewportExt(hdc, xResolution, xResolution);

where columns is a public member variable and

int xResolution = GetDeviceCaps(hdc, HORZRES);

If I call SetMapMode(MM_TEXT) AFTER each call to the BeginPage function of the 3rd party framework, everything is just great.

If I am working with the MM_TEXT mapping mode, will a call to GetDeviceCaps(HORZRES) and (VERTRES) return the area of the page LESS margins or do I have to account for user defined margins via a different call.  As I understand it, MM_TEXT works in pixels as does the return value for the above calls so it should be a simple matter of subtraction to determine printing area.  Is this correct?
>will a call to GetDeviceCaps(HORZRES) and (VERTRES) return the area of the page LESS margins

I think so. But you'd better test it.
WoodsterAuthor Commented:
OK,  I was able to determine all the parameters I required and am able to determine the print area ok (or so it would seem so far!)

Thanks for help and references.
All Courses

From novice to tech pro — start learning today.