From: Joseph M. Newcomer on
As pointed out, that divide-by-10 is a total disaster. Remove it.
joe

On Wed, 23 Dec 2009 06:26:01 -0800, Cameron_C <CameronC(a)discussions.microsoft.com> wrote:

>Thanks Joe,
>I removed the coding for the 42/13, and tried with the
> lfIniDefaults.lfHeight = -MulDiv(m_lfReportHeader.lfHeight/10,
>m_dc.GetDeviceCaps(LOGPIXELSY), 72);
>This gave me some print that was about a 2 point font. With glasses I could
>almost read some of it.
>But this is progress, at least something is printing.
>
>I also just found that if I use SetBkMode(TRANSPARENT) just before I begin
>to print, the report appears on my HP Photosmart printer. (Found it by
>accident when I accidentally uncommented the wrong line).
>
>When I print, I get a printer dc, then I define the fonts. The I select the
>font I want and I drawtext.
>
>This works fine on one printer. And, since I added the SetBkMode it works on
>another (although I have no understanding of why this would be). But still
>fails to print on my little Brother printer.
>
>One more curiousity, when I create font defaults, I do the following:
> CFont cfPrinterFont;
> m_bFlag = m_pApp->CreatePrinterDC(m_dc);
>
> /* Establish Default Font characteristics for the Reports */
> cfPrinterFont.Attach(::GetStockObject(DEVICE_DEFAULT_FONT));
> LOGFONT lf;
> cfPrinterFont.GetLogFont(&lf);
>
> lf.lfHeight *= 10;
> cfPrinterFont.Detach();
>
> cfPrinterFont.CreatePointFontIndirect(&lf, &m_dc);
> cfPrinterFont.GetLogFont(&m_lfReportHeader);
>Now, later when I try to use the LOGFONT, I get characters that are the
>expected height, but are so thin they are unrecognizable.
***
Never set lfWidth. Leave it 0 (default). Otherwise, you get the strange effects you are
seeing.

You can download my font explorer and play with it, but you will see that lfWidth is not a
good value to use.
****
>So, I reset the lfWidth to zero, in this LOGFONT structure, before I
>CreatePointFontIndirect.
>And, at least then I can see the characters.
>Why does the width need to be 0 (which requests the default)? I thought if I
>requested the DEVICE_DEFAULT_FONT for the printer DC, I would get all of the
>values I needed?
****
TrueType/OpenType fonts will adjust themselves by horizontal scaling to conform to the
lfWidth if you do not default it.
****
>Are there any other values I get in the LOGFONT that I should reset before
>creating a font?
>
>And then one more question.
>Maybe this is not an appropraite technique? I use a CFontDialog to allow the
>Users to select the fonts for the reports.
> LOGFONT lf = m_pPrinterControl->m_lfReportHeader;
> lf.lfHeight = -MulDiv(m_pPrinterControl->m_lfReportHeader.lfHeight/10,
>m_pDC->GetDeviceCaps(LOGPIXELSY), 72);
> CFontDialog fdHeader(&lf,
> CF_PRINTERFONTS | CF_EFFECTS | CF_INITTOLOGFONTSTRUCT | CF_ENABLEHOOK
>| CF_FORCEFONTEXIST,
> m_pDC);
>
>Should the m_DC refer to the printerDC? Or to the display DC.
>I think it has to be the display but I am not sure?
****
Ideally, the printer DC for selecting printer fonts. Again, get rid of the /10 (note this
is integer divide, so 18/10 = 1, which leads to your problems). But generally, if you use
the display, the fonts are available for the display. This dichotomy predates the
TrueType world, and in those days it allowed you to specify native printer fonts for
dot-matrix printers and primitive inkjet and laser printers. It is generally no longer an
issue.
joe
****
>
>Thanks,
>
>
>"Joseph M. Newcomer" wrote:
>
>> See below...
>> On Tue, 22 Dec 2009 05:27:01 -0800, Cameron_C <CameronC(a)discussions.microsoft.com> wrote:
>>
>> >Hello Everyone.
>> >I have been struggling with this item for some time.
>> >For a while I was content to ignore it, but it has finally made it to the
>> >top of my list.
>> >I have an application where the User may choose reporting fonts.
>> >Three fonts. One for the header, one for the body, and one for the footer of
>> >the various reports. I save the LOGFONT structures for later use.
>> >At the time I do a StartDocument I grab the LOGFONT structures I had
>> >previously saved, and CreatePointFontIndirect to create the fonts.
>> >As I walk through the code in debug mode, everything seems to work fine.
>> >However, the printing works perfectly on an HP 9040DN, but no details appear
>> >when I print to a Brother or the HP Photosmart I have. The graphics boxes do
>> >appear though.
>> >
>> >Anyway my first question relates to the voodoo-like black magic of scaling
>> >the font.
>> >I want a ten point font. I select a ten point font from the CFontDialog, and
>> >save it. Later, when I want to create the font I call
>> >CreatePointFontIndirect, and I pass a value that is in tenths of a point. So,
>> >now I would pass 100, for my ten point font.
>> ****
>> The truth is that the font is scaled to the display. If you want to use that font on a
>> printer, you must scale it to the printer.
>>
>> Typically, you want to use CFont::CreatePointFontIndirect and for the second parameter
>> pass in your printer DC for printing and either NULL or your display DC for display.
>> *****
>> >From experience this never worked. After poking through various web sites, I
>> >found someone had success with using a "Cook''s Constant" of 42/13. So, I
>> >have taken my value of 100, and multipled by 42/13. Is this obtuse or am I
>> >off base here? Anyway, this appears to do the trick, at least for the HP
>> >printer.
>> ****
>> Sounds like sheer luck. I have no idea what this is doing.
>> *****
>> >I checked the Microsoft docs, and they suggest using something along the
>> >lines of -MulDiv(m_lfReportHeader.lfHeight/10,
>> >m_dc.GetDeviceCaps(LOGPIXELSY), 72);
>> >Now, I have tried this with the printers that do not deliver the report as
>> >execpted, and I see no difference. I have not tried this with the HP printer
>> >that is really working.
>> *****
>> It may be a function of the printer dirvers, but it seems obtuse if it is.
>> ****
>> >Here is a code snippet showing how I have created the fonts.
>> > /*
>> > Assign default Report Header Font for the Reports
>> > Note: m_szIniSectionName will refer to the specific Report for the Printer.
>> > m_ProcessIni.m_szIniSectionName will refer to the DEFAULT entries
>> > for the Printer.
>> > */
>> > LOGFONT lfIniDefaults;
>> > BOOL bFlag=FALSE;
>> > TEXTMETRIC myTextMetrics;
>> >
>> > m_ProcessIni.m_szIniKeyName.LoadString(IDS_REPORTHEADERFONT);
>> > bFlag = m_ProcessIni.getKeyValueForFont(&lfIniDefaults,
>> >m_ProcessIni.m_szIniKeyName, m_szIniSectionName);
>> ****
>> Have you considered the Registry for this? My Registry library actually saves some font
>> information automatically. I see no value in parsing font information from a .INI file (I
>> gave up doing that when I abandoned Win16 many years ago)
>> ****
>> > if (!bFlag) // No font information available from the ini file, so save
>> >DEFAULT
>> > {
>> > m_ProcessIni.setKeyValueForFont(m_plfReportHeader,
>> >m_ProcessIni.m_szIniKeyName, m_szIniSectionName);
>> > }
>> > else
>> > {
>> > m_lfReportHeader = lfIniDefaults;
>> > }
>> > lfIniDefaults = m_lfReportHeader;
>> > lfIniDefaults.lfHeight*=(42/13); // I have no idea why this scaling is
>> >required... But it is. Found this in a news group.
>> ****
>> Neither do I, it looks really bogus, like someone discovered some random value which gave
>> the illusion of working so claimed it made sense. 42/13 is silly anyway; 42/13 is 3, and
>> expressed as 42/13 doesn't change the fact it is 3. And I have no idea what 3 does. Now
>> 42.0/13.0, working as a double, e.g.,
>> something =(int)( (double) something * 42.0 / 13.0)
>> might have meaning, but "3" is just silly.
>> ****
>> >// lfIniDefaults.lfHeight = -MulDiv(m_lfReportHeader.lfHeight/10,
>> >m_dc.GetDeviceCaps(LOGPIXELSY), 72);
>> ****
>> If you get rid of the gratutitous *=3, this should work correctly. But it is what
>> CreatePointFontIndirect does. Read the code.
>> ****
>> >
>> > /*
>> > Establish Font characteristics for the Report Header lines.
>> > lfIniDefaults Points to a LOGFONT structure that defines the
>> >characteristics
>> > of the logical font.
>> > The lfHeight member of the LOGFONT structure is measured in tenths of a
>> >point
>> > rather than logical units.
>> > (For instance, set lfHeight to 120 to request a 12-point font.)
>> > CreatePointFontIndirect returns non-zero when successful.
>> > If bFlag is zero, we have a problem!
>> > */
>> > CFont*pOldHeaderFont, *pOldFooterFont, *pOldBodyFont;
>> *****
>> Never use commas in declaration lists. And there is no reason to save old state like
>> "OldHeaderFont"; instead, use CDC::SaveDC and CDC::RestoreDC to mainain the purity of your
>> DC.
>> ****
>> >
>> > m_cfReportHeader.DeleteObject();
>> > bFlag = m_cfReportHeader.CreatePointFontIndirect(&lfIniDefaults, &m_dc);
>> ****
>> OK, you Are using CreatePointFontIndirect, so why all that other stuff which either
>> duplicates it or duplicates it badly?
>> ****
>> > pOldHeaderFont = m_dc.SelectObject(&m_cfReportHeader);
>> ****
>> I have not saved an "old setting" on SelectObject in about 20 years. Use
>> SaveDC/RestoreDC. Otherwise, you get a lot of garbage variables and lose track of them
>> (there are over 30 DC parameters you might want to save the "old" version of!)
>> ****
>> > m_pcfReportHeader = &m_cfReportHeader;
>> *****
>> How in the world does this assigment make any sense whatsoever? It is complete nonsense.
>> Get rid of it.
>> ****
>> > // m_hFontReportHeader is the CGdiObject public data member that stores
>> >the handle
>> > m_hFontReportHeader = (HFONT) pOldHeaderFont->GetSafeHandle();
>> *****
>> This makes even less sense. Why do you need an HFONT anyway? There is something
>> seriously wrong hwere with what you are doing.
>> ****
>> > //m_hFontReportHeader = (HFONT) m_pcfReportHeader->GetSafeHandle();
>> > /* Get Average size of printed text for the Header Font */
>> > m_dc.GetTextMetrics(&myTextMetrics);
>> > m_yLineHeader = myTextMetrics.tmHeight;
>> >
>> >Later when I want to use the font in a report, I select the font, and do a
>> >DrawText.
>> >Here is a code snippet:
>> > pcfOriginal =
>> >ts->_this->PrinterControl.m_dc.SelectObject(ts->_this->PrinterControl.m_pcfReportHeader);
>> ****
>> There is no need to store the original. m_dc.SaveDC() will save the DC state. Get rid of
>> the assignment.
>>
>> What is _this?
>>
>> If this is a subroutine that is being called for each of the headers, just pass the font
>> in as a CFont& and when you need the address, use & on that. This business of having some
>> memver variable which is set to a pointer doesn't make sense.
>> ****
>> > iPrintedHeight=ts->_this->PrinterControl.m_dc.DrawText(szHeader,
>> >rclHeader, DT_TOP|DT_CENTER);
>> > iPrintedHeight=ts->_this->PrinterControl.m_dc.DrawText(szSubHeader,
>> >rclSubHeader, DT_TOP|DT_CENTER);
>> > pcfOriginal =
>> >ts->_this->PrinterControl.m_dc.SelectObject(ts->_this->PrinterControl.m_pcfReportFooter);
>> ****
>> I'm already confused. You set pcfOriginal to one value when you select the header font,
>> and then you overwrite that when you select the footer font (and why would you not simply
>> write
>> &ts->_this->PrinterControl.m_cfReportFooter
>> instead of that silly technique of storing pointer variables which you then use here?) so
>> what is it going to be restored to?
>> ****
>> > iPrintedHeight=ts->_this->PrinterControl.m_dc.DrawText(szFooter,
>> >rclFooter, DT_BOTTOM|DT_CENTER);
>> > szBuffer.Format(_T("Page %d"), ++lPageNumber);
>> > iPrintedHeight=ts->_this->PrinterControl.m_dc.DrawText(szBuffer,
>> >rclFooter, DT_BOTTOM|DT_RIGHT);
>> > pcfOriginal =
>> >ts->_this->PrinterControl.m_dc.SelectObject(ts->_this->PrinterControl.m_pcfReportBody);
>> ****
>> You really need to understand what the & operator does, and where you use it. All those
>> intermediate pointer-to-font variables are completely silly!
>>
>> I note that at no point do you restore the font you changed, that is, I see no
>> ....m_dc.SelectObject(pcfOriginal);
>> and that means that saving the value is pointless. And then you leave the font selected
>> into the DC, which is poor practice. See my essay on SaveDC/RestoreDC on my MVP Tips
>> site.
>> ****
>> >
>> >
>> >One last question, I know that the Fonts are applicable for the DC that has
>> >been selected. When the DC is destroyed, and recreated, do the Fonts need to
>> >be recreated? Do I need to destroy and recreate the fonts every time I
>> >destroy and recreate the DC? Should I?
>> ****
>> Yes. Because if I create a font for my one printer (1200dpi) then close the printer, and
>> then open another DC on the other printer (600 dpi), my fonts would be 2x too large. So
>> it is rare I would create the fonts as member variables at all. I would typically create
>> them in the printing routine handler, and let the normal CFont::~CFont destructor get rid
>> of them when I was done printing. I don;t use global variables when local variables would
>> do. And I'm willing to pass parameters around, including a parameter which is my printing
>> context, e.g.,
>> class PrintingContext {
>> public:
>> CFont Header;
>> CFont Section;
>> CFont MajorTitle;
>> CFont Text;
>> };
>> and initialize those variables. I'd probably have a constructor that took the CDC and
>> created the fonts relative to it. And I'd probably have other things in it such as the
>> current line, current page #, etc., and never, ever, under any conditions imaginable would
>> those be member variables in any view class or anyplace outside this PrintingContext
>> object. Then all my functions would take a PrintingContext& parameter that would give me
>> access to this information. When the printing is done, it goes away, all the fonts go
>> away, and I never see any of them ever again until I need to do another print run. I
>> would have a "generic" LOGFONT structure that I used for storing the data, but it would
>> only be passed in to my font constructors in my PrintingContext object.
>>
>> Localize information as tightly as you can,
>>
>> And never store a pointer-to-something if you can COMPUTE the pointer-to-something on
>> demand. You added meaningless complexity to your class and your code by introducing these
>> pointer variables!
>> joe
>> ****
>> >
>> >Today, I plan to try to sift through SuperPad. I believe it is the Microsoft
>> >sample which may help me out here.
>> >
>> >Thanks for any information, and Merry Christmas!
>> >
>> >.......Cameron
>> Joseph M. Newcomer [MVP]
>> email: newcomer(a)flounder.com
>> Web: http://www.flounder.com
>> MVP Tips: http://www.flounder.com/mvp_tips.htm
>> .
>>
Joseph M. Newcomer [MVP]
email: newcomer(a)flounder.com
Web: http://www.flounder.com
MVP Tips: http://www.flounder.com/mvp_tips.htm
From: Cameron_C on
Hello again,
I think this may relate to using MM_TWIPS rather than MM_TEXT.
When I replaced MM_TEXT with MM_TWIPS, AND I divided the logical font height
(in tenths of a point) by ten, I think I am seeing the correct results. At
least on one printer.


"Stephen Myers" <""StephenMyers"@discuss" wrote:

> Cameron_C wrote:
> > Thanks Joe,
> > I removed the coding for the 42/13, and tried with the
> > lfIniDefaults.lfHeight = -MulDiv(m_lfReportHeader.lfHeight/10,
> > m_dc.GetDeviceCaps(LOGPIXELSY), 72);
>
> Why divide lfHeight by 10? You are about to divide by 72 anyway. Doing
> so creates resolution problem for you. Consider that you will get the
> same font for all starting heights of 10 through 19.
>
> Steve
>
>
> > This gave me some print that was about a 2 point font. With glasses I could
> > almost read some of it.
> > But this is progress, at least something is printing.
> >
> > I also just found that if I use SetBkMode(TRANSPARENT) just before I begin
> > to print, the report appears on my HP Photosmart printer. (Found it by
> > accident when I accidentally uncommented the wrong line).
> >
> > When I print, I get a printer dc, then I define the fonts. The I select the
> > font I want and I drawtext.
> >
> > This works fine on one printer. And, since I added the SetBkMode it works on
> > another (although I have no understanding of why this would be). But still
> > fails to print on my little Brother printer.
> >
> > One more curiousity, when I create font defaults, I do the following:
> > CFont cfPrinterFont;
> > m_bFlag = m_pApp->CreatePrinterDC(m_dc);
> >
> > /* Establish Default Font characteristics for the Reports */
> > cfPrinterFont.Attach(::GetStockObject(DEVICE_DEFAULT_FONT));
> > LOGFONT lf;
> > cfPrinterFont.GetLogFont(&lf);
> >
> > lf.lfHeight *= 10;
> > cfPrinterFont.Detach();
> >
> > cfPrinterFont.CreatePointFontIndirect(&lf, &m_dc);
> > cfPrinterFont.GetLogFont(&m_lfReportHeader);
> > Now, later when I try to use the LOGFONT, I get characters that are the
> > expected height, but are so thin they are unrecognizable.
> > So, I reset the lfWidth to zero, in this LOGFONT structure, before I
> > CreatePointFontIndirect.
> > And, at least then I can see the characters.
> > Why does the width need to be 0 (which requests the default)? I thought if I
> > requested the DEVICE_DEFAULT_FONT for the printer DC, I would get all of the
> > values I needed?
> > Are there any other values I get in the LOGFONT that I should reset before
> > creating a font?
> >
> > And then one more question.
> > Maybe this is not an appropraite technique? I use a CFontDialog to allow the
> > Users to select the fonts for the reports.
> > LOGFONT lf = m_pPrinterControl->m_lfReportHeader;
> > lf.lfHeight = -MulDiv(m_pPrinterControl->m_lfReportHeader.lfHeight/10,
> > m_pDC->GetDeviceCaps(LOGPIXELSY), 72);
> > CFontDialog fdHeader(&lf,
> > CF_PRINTERFONTS | CF_EFFECTS | CF_INITTOLOGFONTSTRUCT | CF_ENABLEHOOK
> > | CF_FORCEFONTEXIST,
> > m_pDC);
> >
> > Should the m_DC refer to the printerDC? Or to the display DC.
> > I think it has to be the display but I am not sure?
> >
> > Thanks,
> >
> >
> > "Joseph M. Newcomer" wrote:
> >
> >> See below...
> >> On Tue, 22 Dec 2009 05:27:01 -0800, Cameron_C <CameronC(a)discussions.microsoft.com> wrote:
> >>
> >>> Hello Everyone.
> >>> I have been struggling with this item for some time.
> >>> For a while I was content to ignore it, but it has finally made it to the
> >>> top of my list.
> >>> I have an application where the User may choose reporting fonts.
> >>> Three fonts. One for the header, one for the body, and one for the footer of
> >>> the various reports. I save the LOGFONT structures for later use.
> >>> At the time I do a StartDocument I grab the LOGFONT structures I had
> >>> previously saved, and CreatePointFontIndirect to create the fonts.
> >>> As I walk through the code in debug mode, everything seems to work fine.
> >>> However, the printing works perfectly on an HP 9040DN, but no details appear
> >>> when I print to a Brother or the HP Photosmart I have. The graphics boxes do
> >>> appear though.
> >>>
> >>> Anyway my first question relates to the voodoo-like black magic of scaling
> >>> the font.
> >>> I want a ten point font. I select a ten point font from the CFontDialog, and
> >>> save it. Later, when I want to create the font I call
> >>> CreatePointFontIndirect, and I pass a value that is in tenths of a point. So,
> >>> now I would pass 100, for my ten point font.
> >> ****
> >> The truth is that the font is scaled to the display. If you want to use that font on a
> >> printer, you must scale it to the printer.
> >>
> >> Typically, you want to use CFont::CreatePointFontIndirect and for the second parameter
> >> pass in your printer DC for printing and either NULL or your display DC for display.
> >> *****
> >> >From experience this never worked. After poking through various web sites, I
> >>> found someone had success with using a "Cook''s Constant" of 42/13. So, I
> >>> have taken my value of 100, and multipled by 42/13. Is this obtuse or am I
> >>> off base here? Anyway, this appears to do the trick, at least for the HP
> >>> printer.
> >> ****
> >> Sounds like sheer luck. I have no idea what this is doing.
> >> *****
> >>> I checked the Microsoft docs, and they suggest using something along the
> >>> lines of -MulDiv(m_lfReportHeader.lfHeight/10,
> >>> m_dc.GetDeviceCaps(LOGPIXELSY), 72);
> >>> Now, I have tried this with the printers that do not deliver the report as
> >>> execpted, and I see no difference. I have not tried this with the HP printer
> >>> that is really working.
> >> *****
> >> It may be a function of the printer dirvers, but it seems obtuse if it is.
> >> ****
> >>> Here is a code snippet showing how I have created the fonts.
> >>> /*
> >>> Assign default Report Header Font for the Reports
> >>> Note: m_szIniSectionName will refer to the specific Report for the Printer.
> >>> m_ProcessIni.m_szIniSectionName will refer to the DEFAULT entries
> >>> for the Printer.
> >>> */
> >>> LOGFONT lfIniDefaults;
> >>> BOOL bFlag=FALSE;
> >>> TEXTMETRIC myTextMetrics;
> >>>
> >>> m_ProcessIni.m_szIniKeyName.LoadString(IDS_REPORTHEADERFONT);
> >>> bFlag = m_ProcessIni.getKeyValueForFont(&lfIniDefaults,
> >>> m_ProcessIni.m_szIniKeyName, m_szIniSectionName);
> >> ****
> >> Have you considered the Registry for this? My Registry library actually saves some font
> >> information automatically. I see no value in parsing font information from a .INI file (I
> >> gave up doing that when I abandoned Win16 many years ago)
> >> ****
> >>> if (!bFlag) // No font information available from the ini file, so save
> >>> DEFAULT
> >>> {
> >>> m_ProcessIni.setKeyValueForFont(m_plfReportHeader,
> >>> m_ProcessIni.m_szIniKeyName, m_szIniSectionName);
> >>> }
> >>> else
> >>> {
> >>> m_lfReportHeader = lfIniDefaults;
> >>> }
> >>> lfIniDefaults = m_lfReportHeader;
> >>> lfIniDefaults.lfHeight*=(42/13); // I have no idea why this scaling is
> >>> required... But it is. Found this in a news group.
> >> ****
> >> Neither do I, it looks really bogus, like someone discovered some random value which gave
> >> the illusion of working so claimed it made sense. 42/13 is silly anyway; 42/13 is 3, and
> >> expressed as 42/13 doesn't change the fact it is 3. And I have no idea what 3 does. Now
> >> 42.0/13.0, working as a double, e.g.,
> >> something =(int)( (double) something * 42.0 / 13.0)
> >> might have meaning, but "3" is just silly.
> >> ****
> >>> // lfIniDefaults.lfHeight = -MulDiv(m_lfReportHeader.lfHeight/10,
> >>> m_dc.GetDeviceCaps(LOGPIXELSY), 72);
> >> ****
> >> If you get rid of the gratutitous *=3, this should work correctly. But it is what
> >> CreatePointFontIndirect does. Read the code.
> >> ****
> >>> /*
> >>> Establish Font characteristics for the Report Header lines.
> >>> lfIniDefaults Points to a LOGFONT structure that defines the
> >>> characteristics
> >>> of the logical font.
> >>> The lfHeight member of the LOGFONT structure is measured in tenths of a
> >>> point
> >>> rather than logical units.
> >>> (For instance, set lfHeight to 120 to request a 12-point font.)
> >>> CreatePointFontIndirect returns non-zero when successful.
> >>> If bFlag is zero, we have a problem!
> >>> */
> >>> CFont*pOldHeaderFont, *pOldFooterFont, *pOldBodyFont;
> >> *****
> >> Never use commas in declaration lists. And there is no reason to save old state like
> >> "OldHeaderFont"; instead, use CDC::SaveDC and CDC::RestoreDC to mainain the purity of your
> >> DC.
> >> ****
> >>> m_cfReportHeader.DeleteObject();
> >>> bFlag = m_cfReportHeader.CreatePointFontIndirect(&lfIniDefaults, &m_dc);
> >> ****
> >> OK, you Are using CreatePointFontIndirect, so why all that other stuff which either
> >> duplicates it or duplicates it badly?
> >> ****
> >>> pOldHeaderFont = m_dc.SelectObject(&m_cfReportHeader);
> >> ****
> >> I have not saved an "old setting" on SelectObject in about 20 years. Use
> >> SaveDC/RestoreDC. Otherwise, you get a lot of garbage variables and lose track of them
> >> (there are over 30 DC parameters you might want to save the "old" version of!)
> >> ****
> >>> m_pcfReportHeader = &m_cfReportHeader;
> >> *****
> >> How in the world does this assigment make any sense whatsoever? It is complete nonsense.
> >> Get rid of it.
> >> ****
> >>> // m_hFontReportHeader is the CGdiObject public data member that stores
> >>> the handle
> >>> m_hFontReportHeader = (HFONT) pOldHeaderFont->GetSafeHandle();
> >> *****
> >> This makes even less sense. Why do you need an HFONT anyway? There is something
> >> seriously wrong hwere with what you are doing.
> >> ****
> >>> //m_hFontReportHeader = (HFONT) m_pcfReportHeader->GetSafeHandle();
> >>> /* Get Average size of printed text for the Header Font */
> >>> m_dc.GetTextMetrics(&myTextMetrics);
> >>> m_yLineHeader = myTextMetrics.tmHeight;
> >>>
> >>> Later when I want to use the font in a report, I select the font, and do a
> >>> DrawText.
> >>> Here is a code snippet:
> >>> pcfOriginal =
> >>> ts->_this->PrinterControl.m_dc.SelectObject(ts->_this->PrinterControl.m_pcfReportHeader);
> >> ****
> >> There is no need to store the original. m_dc.SaveDC() will save the DC state. Get rid of
> >> the assignment.
> >>
> >> What is _this?
> >>
> >> If this is a subroutine that is being called for each of the headers, just pass the font
> >> in as a CFont& and when you need the address, use & on that. This business of having some
> >> memver variable which is set to a pointer doesn't make sense.
> >> ****
> >>> iPrintedHeight=ts->_this->PrinterControl.m_dc.DrawText(szHeader,
> >>> rclHeader, DT_TOP|DT_CENTER);
> >>> iPrintedHeight=ts->_this->PrinterControl.m_dc.DrawText(szSubHeader,
> >>> rclSubHeader, DT_TOP|DT_CENTER);
> >>> pcfOriginal =
> >>> ts->_this->PrinterControl.m_dc.SelectObject(ts->_this->PrinterControl.m_pcfReportFooter);
> >> ****
> >> I'm already confused. You set pcfOriginal to one value when you select the header font,
> >> and then you overwrite that when you select the footer font (and why would you not simply
> >> write
> >> &ts->_this->PrinterControl.m_cfReportFooter
> >> instead of that silly technique of storing pointer variables which you then use here?) so
> >> what is it going to be restored to?
> >> ****
> >>> iPrintedHeight=ts->_this->PrinterControl.m_dc.DrawText(szFooter,
> >>> rclFooter, DT_BOTTOM|DT_CENTER);
> >>> szBuffer.Format(_T("Page %d"), ++lPageNumber);
> >>> iPrintedHeight=ts->_this->PrinterControl.m_dc.DrawText(szBuffer,
> >>> rclFooter, DT_BOTTOM|DT_RIGHT);
> >>> pcfOriginal =
> >>> ts->_this->PrinterControl.m_dc.SelectObject(ts->_this->PrinterControl.m_pcfReportBody);
> >> ****
> >> You really need to understand what the & operator does, and where you use it. All those
> >> intermediate pointer-to-font variables are completely silly!
> >>
> >> I note that at no point do you restore the font you changed, that is, I see no
> >> ....m_dc.SelectObject(pcfOriginal);
> >> and that means that saving the value is pointless. And then you leave the font selected
> >> into the DC, which is poor practice. See my essay on SaveDC/RestoreDC on my MVP Tips
> >> site.
> >> ****
> >>>
> >>> One last question, I know that the Fonts are applicable for the DC that has
> >>> been selected. When the DC is destroyed, and recreated, do the Fonts need to
> >>> be recreated? Do I need to destroy and recreate the fonts every time I
> >>> destroy and recreate the DC? Should I?
> >> ****
> >> Yes. Because if I create a font for my one printer (1200dpi) then close the printer, and
> >> then open another DC on the other printer (600 dpi), my fonts would be 2x too large. So
> >> it is rare I would create the fonts as member variables at all. I would typically create
> >> them in the printing routine handler, and let the normal CFont::~CFont destructor get rid
> >> of them when I was done printing. I don;t use global variables when local variables would
> >> do. And I'm willing to pass parameters around, including a parameter which is my printing
> >> context, e.g.,
> >> class PrintingContext {
> >> public:
> >> CFont Header;
> >> CFont Section;
> >> CFont MajorTitle;
> >> CFont Text;
> >> };
> >> and initialize those variables. I'd probably have a constructor that took the CDC and
> >> created the fonts relative to it. And I'd probably have other things in it such as the
> >> current line, current page #, etc., and never, ever, under any conditions imaginable would
> >> those be member variables in any view class or anyplace outside this PrintingContext
> >> object. Then all my functions would take a PrintingContext& parameter that would give me
> >> access to this information. When the printing is done, it goes away, all the fonts go
> >> away, and I never see any of them ever again until I need to do another print run. I
> >> would have a "generic" LOGFONT structure that I used for storing the data, but it would
> >> only be passed in to my font constructors in my PrintingContext object.
> >>
> >> Localize information as tightly as you can,
> >>
> >> And never store a pointer-to-something if you can COMPUTE the pointer-to-something on
> >> demand. You added meaningless complexity to your class and your code by introducing these
> >> pointer variables!
> >> joe
> >> ****
> >>> Today, I plan to try to sift through SuperPad. I believe it is the Microsoft
> >>> sample which may help me out here.
> >>>
> >>> Thanks for any information, and Merry Christmas!
> >>>
From: Cameron_C on
Thanks Joe.
What value should be in the lfHeight, when I am looking for a six point font?
I know that I should use tenths of a point (so sixty) when I
CreatePointFontIndirect.
But, what do I want to put through the scaling math? Do I need tenths of a
point? Or full point values?
I believe that the MulDiv(a,b,c) is supposed to give me (a*b)/c.
But, do I start with tenths of a point or point values? Six or sixty?
When I use sixty, my font is now about one inch high.
And when I use six, I get something pretty small. Maybe it is six points.
And this is since I changed to set to MM_TWIPS after creating the printer DC.
Maybe I should not use MM_TWIPS?

Thanks,


"Joseph M. Newcomer" wrote:

> As pointed out, that divide-by-10 is a total disaster. Remove it.
> joe
>
> On Wed, 23 Dec 2009 06:26:01 -0800, Cameron_C <CameronC(a)discussions.microsoft.com> wrote:
>
> >Thanks Joe,
> >I removed the coding for the 42/13, and tried with the
> > lfIniDefaults.lfHeight = -MulDiv(m_lfReportHeader.lfHeight/10,
> >m_dc.GetDeviceCaps(LOGPIXELSY), 72);
> >This gave me some print that was about a 2 point font. With glasses I could
> >almost read some of it.
> >But this is progress, at least something is printing.
> >
> >I also just found that if I use SetBkMode(TRANSPARENT) just before I begin
> >to print, the report appears on my HP Photosmart printer. (Found it by
> >accident when I accidentally uncommented the wrong line).
> >
> >When I print, I get a printer dc, then I define the fonts. The I select the
> >font I want and I drawtext.
> >
> >This works fine on one printer. And, since I added the SetBkMode it works on
> >another (although I have no understanding of why this would be). But still
> >fails to print on my little Brother printer.
> >
> >One more curiousity, when I create font defaults, I do the following:
> > CFont cfPrinterFont;
> > m_bFlag = m_pApp->CreatePrinterDC(m_dc);
> >
> > /* Establish Default Font characteristics for the Reports */
> > cfPrinterFont.Attach(::GetStockObject(DEVICE_DEFAULT_FONT));
> > LOGFONT lf;
> > cfPrinterFont.GetLogFont(&lf);
> >
> > lf.lfHeight *= 10;
> > cfPrinterFont.Detach();
> >
> > cfPrinterFont.CreatePointFontIndirect(&lf, &m_dc);
> > cfPrinterFont.GetLogFont(&m_lfReportHeader);
> >Now, later when I try to use the LOGFONT, I get characters that are the
> >expected height, but are so thin they are unrecognizable.
> ***
> Never set lfWidth. Leave it 0 (default). Otherwise, you get the strange effects you are
> seeing.
>
> You can download my font explorer and play with it, but you will see that lfWidth is not a
> good value to use.
> ****
> >So, I reset the lfWidth to zero, in this LOGFONT structure, before I
> >CreatePointFontIndirect.
> >And, at least then I can see the characters.
> >Why does the width need to be 0 (which requests the default)? I thought if I
> >requested the DEVICE_DEFAULT_FONT for the printer DC, I would get all of the
> >values I needed?
> ****
> TrueType/OpenType fonts will adjust themselves by horizontal scaling to conform to the
> lfWidth if you do not default it.
> ****
> >Are there any other values I get in the LOGFONT that I should reset before
> >creating a font?
> >
> >And then one more question.
> >Maybe this is not an appropraite technique? I use a CFontDialog to allow the
> >Users to select the fonts for the reports.
> > LOGFONT lf = m_pPrinterControl->m_lfReportHeader;
> > lf.lfHeight = -MulDiv(m_pPrinterControl->m_lfReportHeader.lfHeight/10,
> >m_pDC->GetDeviceCaps(LOGPIXELSY), 72);
> > CFontDialog fdHeader(&lf,
> > CF_PRINTERFONTS | CF_EFFECTS | CF_INITTOLOGFONTSTRUCT | CF_ENABLEHOOK
> >| CF_FORCEFONTEXIST,
> > m_pDC);
> >
> >Should the m_DC refer to the printerDC? Or to the display DC.
> >I think it has to be the display but I am not sure?
> ****
> Ideally, the printer DC for selecting printer fonts. Again, get rid of the /10 (note this
> is integer divide, so 18/10 = 1, which leads to your problems). But generally, if you use
> the display, the fonts are available for the display. This dichotomy predates the
> TrueType world, and in those days it allowed you to specify native printer fonts for
> dot-matrix printers and primitive inkjet and laser printers. It is generally no longer an
> issue.
> joe
> ****
> >
> >Thanks,
> >
> >
> >"Joseph M. Newcomer" wrote:
> >
> >> See below...
> >> On Tue, 22 Dec 2009 05:27:01 -0800, Cameron_C <CameronC(a)discussions.microsoft.com> wrote:
> >>
> >> >Hello Everyone.
> >> >I have been struggling with this item for some time.
> >> >For a while I was content to ignore it, but it has finally made it to the
> >> >top of my list.
> >> >I have an application where the User may choose reporting fonts.
> >> >Three fonts. One for the header, one for the body, and one for the footer of
> >> >the various reports. I save the LOGFONT structures for later use.
> >> >At the time I do a StartDocument I grab the LOGFONT structures I had
> >> >previously saved, and CreatePointFontIndirect to create the fonts.
> >> >As I walk through the code in debug mode, everything seems to work fine.
> >> >However, the printing works perfectly on an HP 9040DN, but no details appear
> >> >when I print to a Brother or the HP Photosmart I have. The graphics boxes do
> >> >appear though.
> >> >
> >> >Anyway my first question relates to the voodoo-like black magic of scaling
> >> >the font.
> >> >I want a ten point font. I select a ten point font from the CFontDialog, and
> >> >save it. Later, when I want to create the font I call
> >> >CreatePointFontIndirect, and I pass a value that is in tenths of a point. So,
> >> >now I would pass 100, for my ten point font.
> >> ****
> >> The truth is that the font is scaled to the display. If you want to use that font on a
> >> printer, you must scale it to the printer.
> >>
> >> Typically, you want to use CFont::CreatePointFontIndirect and for the second parameter
> >> pass in your printer DC for printing and either NULL or your display DC for display.
> >> *****
> >> >From experience this never worked. After poking through various web sites, I
> >> >found someone had success with using a "Cook''s Constant" of 42/13. So, I
> >> >have taken my value of 100, and multipled by 42/13. Is this obtuse or am I
> >> >off base here? Anyway, this appears to do the trick, at least for the HP
> >> >printer.
> >> ****
> >> Sounds like sheer luck. I have no idea what this is doing.
> >> *****
> >> >I checked the Microsoft docs, and they suggest using something along the
> >> >lines of -MulDiv(m_lfReportHeader.lfHeight/10,
> >> >m_dc.GetDeviceCaps(LOGPIXELSY), 72);
> >> >Now, I have tried this with the printers that do not deliver the report as
> >> >execpted, and I see no difference. I have not tried this with the HP printer
> >> >that is really working.
> >> *****
> >> It may be a function of the printer dirvers, but it seems obtuse if it is.
> >> ****
> >> >Here is a code snippet showing how I have created the fonts.
> >> > /*
> >> > Assign default Report Header Font for the Reports
> >> > Note: m_szIniSectionName will refer to the specific Report for the Printer.
> >> > m_ProcessIni.m_szIniSectionName will refer to the DEFAULT entries
> >> > for the Printer.
> >> > */
> >> > LOGFONT lfIniDefaults;
> >> > BOOL bFlag=FALSE;
> >> > TEXTMETRIC myTextMetrics;
> >> >
> >> > m_ProcessIni.m_szIniKeyName.LoadString(IDS_REPORTHEADERFONT);
> >> > bFlag = m_ProcessIni.getKeyValueForFont(&lfIniDefaults,
> >> >m_ProcessIni.m_szIniKeyName, m_szIniSectionName);
> >> ****
> >> Have you considered the Registry for this? My Registry library actually saves some font
> >> information automatically. I see no value in parsing font information from a .INI file (I
> >> gave up doing that when I abandoned Win16 many years ago)
> >> ****
> >> > if (!bFlag) // No font information available from the ini file, so save
> >> >DEFAULT
> >> > {
> >> > m_ProcessIni.setKeyValueForFont(m_plfReportHeader,
> >> >m_ProcessIni.m_szIniKeyName, m_szIniSectionName);
> >> > }
> >> > else
> >> > {
> >> > m_lfReportHeader = lfIniDefaults;
> >> > }
> >> > lfIniDefaults = m_lfReportHeader;
> >> > lfIniDefaults.lfHeight*=(42/13); // I have no idea why this scaling is
> >> >required... But it is. Found this in a news group.
> >> ****
> >> Neither do I, it looks really bogus, like someone discovered some random value which gave
> >> the illusion of working so claimed it made sense. 42/13 is silly anyway; 42/13 is 3, and
> >> expressed as 42/13 doesn't change the fact it is 3. And I have no idea what 3 does. Now
> >> 42.0/13.0, working as a double, e.g.,
> >> something =(int)( (double) something * 42.0 / 13.0)
> >> might have meaning, but "3" is just silly.
> >> ****
> >> >// lfIniDefaults.lfHeight = -MulDiv(m_lfReportHeader.lfHeight/10,
> >> >m_dc.GetDeviceCaps(LOGPIXELSY), 72);
> >> ****
> >> If you get rid of the gratutitous *=3, this should work correctly. But it is what
> >> CreatePointFontIndirect does. Read the code.
> >> ****
> >> >
> >> > /*
> >> > Establish Font characteristics for the Report Header lines.
> >> > lfIniDefaults Points to a LOGFONT structure that defines the
> >> >characteristics
> >> > of the logical font.
> >> > The lfHeight member of the LOGFONT structure is measured in tenths of a
> >> >point
> >> > rather than logical units.
> >> > (For instance, set lfHeight to 120 to request a 12-point font.)
> >> > CreatePointFontIndirect returns non-zero when successful.
> >> > If bFlag is zero, we have a problem!
> >> > */
> >> > CFont*pOldHeaderFont, *pOldFooterFont, *pOldBodyFont;
> >> *****
> >> Never use commas in declaration lists. And there is no reason to save old state like
> >> "OldHeaderFont"; instead, use CDC::SaveDC and CDC::RestoreDC to mainain the purity of your
> >> DC.
> >> ****
> >> >
> >> > m_cfReportHeader.DeleteObject();
> >> > bFlag = m_cfReportHeader.CreatePointFontIndirect(&lfIniDefaults, &m_dc);
> >> ****
> >> OK, you Are using CreatePointFontIndirect, so why all that other stuff which either
> >> duplicates it or duplicates it badly?
> >> ****
> >> > pOldHeaderFont = m_dc.SelectObject(&m_cfReportHeader);
> >> ****
> >> I have not saved an "old setting" on SelectObject in about 20 years. Use
> >> SaveDC/RestoreDC. Otherwise, you get a lot of garbage variables and lose track of them
> >> (there are over 30 DC parameters you might want to save the "old" version of!)
> >> ****
> >> > m_pcfReportHeader = &m_cfReportHeader;
> >> *****
> >> How in the world does this assigment make any sense whatsoever? It is complete nonsense.
> >> Get rid of it.
> >> ****
> >> > // m_hFontReportHeader is the CGdiObject public data member that stores
> >> >the handle
> >> > m_hFontReportHeader = (HFONT) pOldHeaderFont->GetSafeHandle();
> >> *****
> >> This makes even less sense. Why do you need an HFONT anyway? There is something
> >> seriously wrong hwere with what you are doing.
> >> ****
> >> > //m_hFontReportHeader = (HFONT) m_pcfReportHeader->GetSafeHandle();
> >> > /* Get Average size of printed text for the Header Font */
> >> > m_dc.GetTextMetrics(&myTextMetrics);
> >> > m_yLineHeader = myTextMetrics.tmHeight;
> >> >
> >> >Later when I want to use the font in a report, I select the font, and do a
> >> >DrawText.
> >> >Here is a code snippet:
> >> > pcfOriginal =
> >> >ts->_this->PrinterControl.m_dc.SelectObject(ts->_this->PrinterControl.m_pcfReportHeader);
> >> ****
> >> There is no need to store the original. m_dc.SaveDC() will save the DC state. Get rid of
> >> the assignment.
> >>
> >> What is _this?
> >>
> >> If this is a subroutine that is being called for each of the headers, just pass the font
> >> in as a CFont& and when you need the address, use & on that. This business of having some
> >> memver variable which is set to a pointer doesn't make sense.
> >> ****
> >> > iPrintedHeight=ts->_this->PrinterControl.m_dc.DrawText(szHeader,
> >> >rclHeader, DT_TOP|DT_CENTER);
> >> > iPrintedHeight=ts->_this->PrinterControl.m_dc.DrawText(szSubHeader,
> >> >rclSubHeader, DT_TOP|DT_CENTER);
> >> > pcfOriginal =
> >> >ts->_this->PrinterControl.m_dc.SelectObject(ts->_this->PrinterControl.m_pcfReportFooter);
> >> ****
> >> I'm already confused. You set pcfOriginal to one value when you select the header font,
> >> and then you overwrite that when you select the footer font (and why would you not simply
> >> write
> >> &ts->_this->PrinterControl.m_cfReportFooter
> >> instead of that silly technique of storing pointer variables which you then use here?) so
> >> what is it going to be restored to?
> >> ****
> >> > iPrintedHeight=ts->_this->PrinterControl.m_dc.DrawText(szFooter,
> >> >rclFooter, DT_BOTTOM|DT_CENTER);
> >> > szBuffer.Format(_T("Page %d"), ++lPageNumber);
> >> > iPrintedHeight=ts->_this->PrinterControl.m_dc.DrawText(szBuffer,
> >> >rclFooter, DT_BOTTOM|DT_RIGHT);
> >> > pcfOriginal =
> >> >ts->_this->PrinterControl.m_dc.SelectObject(ts->_this->PrinterControl.m_pcfReportBody);
> >> ****
> >> You really need to understand what the & operator does, and where you use it. All those
> >> intermediate pointer-to-font variables are completely silly!
> >>
> >> I note that at no point do you restore the font you changed, that is, I see no
> >> ....m_dc.SelectObject(pcfOriginal);
> >> and that means that saving the value is pointless. And then you leave the font selected
> >> into the DC, which is poor practice. See my essay on SaveDC/RestoreDC on my MVP Tips
> >> site.
> >> ****
> >> >
> >> >
> >> >One last question, I know that the Fonts are applicable for the DC that has
> >> >been selected. When the DC is destroyed, and recreated, do the Fonts need to
> >> >be recreated? Do I need to destroy and recreate the fonts every time I
> >> >destroy and recreate the DC? Should I?
> >> ****
> >> Yes. Because if I create a font for my one printer (1200dpi) then close the printer, and
> >> then open another DC on the other printer (600 dpi), my fonts would be 2x too large. So
> >> it is rare I would create the fonts as member variables at all. I would typically create
> >> them in the printing routine handler, and let the normal CFont::~CFont destructor get rid
> >> of them when I was done printing. I don;t use global variables when local variables would
> >> do. And I'm willing to pass parameters around, including a parameter which is my printing
> >> context, e.g.,
> >> class PrintingContext {
> >> public:
> >> CFont Header;
> >> CFont Section;
> >> CFont MajorTitle;
> >> CFont Text;
> >> };
> >> and initialize those variables. I'd probably have a constructor that took the CDC and
> >> created the fonts relative to it. And I'd probably have other things in it such as the
> >> current line, current page #, etc., and never, ever, under any conditions imaginable would
From: Stephen Myers on
I don't object to having a divide by 10 in the algorithm. I object to
where you put the divide.

Change the 72 to 720 and you will get values on the same order of
magnitude without throwing away resolution.

Consider MulDiv(19/10,1024,72) vs MulDiv(19,1024,720)
14 vs 27

Steve


Cameron_C wrote:
> Hello again,
> I think this may relate to using MM_TWIPS rather than MM_TEXT.
> When I replaced MM_TEXT with MM_TWIPS, AND I divided the logical font height
> (in tenths of a point) by ten, I think I am seeing the correct results. At
> least on one printer.
>
>
> "Stephen Myers" <""StephenMyers"@discuss" wrote:
>
>> Cameron_C wrote:
>>> Thanks Joe,
>>> I removed the coding for the 42/13, and tried with the
>>> lfIniDefaults.lfHeight = -MulDiv(m_lfReportHeader.lfHeight/10,
>>> m_dc.GetDeviceCaps(LOGPIXELSY), 72);
>> Why divide lfHeight by 10? You are about to divide by 72 anyway. Doing
>> so creates resolution problem for you. Consider that you will get the
>> same font for all starting heights of 10 through 19.
>>
>> Steve
>>
>>
>>> This gave me some print that was about a 2 point font. With glasses I could
>>> almost read some of it.
>>> But this is progress, at least something is printing.
>>>
>>> I also just found that if I use SetBkMode(TRANSPARENT) just before I begin
>>> to print, the report appears on my HP Photosmart printer. (Found it by
>>> accident when I accidentally uncommented the wrong line).
>>>
>>> When I print, I get a printer dc, then I define the fonts. The I select the
>>> font I want and I drawtext.
>>>
>>> This works fine on one printer. And, since I added the SetBkMode it works on
>>> another (although I have no understanding of why this would be). But still
>>> fails to print on my little Brother printer.
>>>
>>> One more curiousity, when I create font defaults, I do the following:
>>> CFont cfPrinterFont;
>>> m_bFlag = m_pApp->CreatePrinterDC(m_dc);
>>>
>>> /* Establish Default Font characteristics for the Reports */
>>> cfPrinterFont.Attach(::GetStockObject(DEVICE_DEFAULT_FONT));
>>> LOGFONT lf;
>>> cfPrinterFont.GetLogFont(&lf);
>>>
>>> lf.lfHeight *= 10;
>>> cfPrinterFont.Detach();
>>>
>>> cfPrinterFont.CreatePointFontIndirect(&lf, &m_dc);
>>> cfPrinterFont.GetLogFont(&m_lfReportHeader);
>>> Now, later when I try to use the LOGFONT, I get characters that are the
>>> expected height, but are so thin they are unrecognizable.
>>> So, I reset the lfWidth to zero, in this LOGFONT structure, before I
>>> CreatePointFontIndirect.
>>> And, at least then I can see the characters.
>>> Why does the width need to be 0 (which requests the default)? I thought if I
>>> requested the DEVICE_DEFAULT_FONT for the printer DC, I would get all of the
>>> values I needed?
>>> Are there any other values I get in the LOGFONT that I should reset before
>>> creating a font?
>>>
>>> And then one more question.
>>> Maybe this is not an appropraite technique? I use a CFontDialog to allow the
>>> Users to select the fonts for the reports.
>>> LOGFONT lf = m_pPrinterControl->m_lfReportHeader;
>>> lf.lfHeight = -MulDiv(m_pPrinterControl->m_lfReportHeader.lfHeight/10,
>>> m_pDC->GetDeviceCaps(LOGPIXELSY), 72);
>>> CFontDialog fdHeader(&lf,
>>> CF_PRINTERFONTS | CF_EFFECTS | CF_INITTOLOGFONTSTRUCT | CF_ENABLEHOOK
>>> | CF_FORCEFONTEXIST,
>>> m_pDC);
>>>
>>> Should the m_DC refer to the printerDC? Or to the display DC.
>>> I think it has to be the display but I am not sure?
>>>
>>> Thanks,
>>>
>>>
>>> "Joseph M. Newcomer" wrote:
>>>
>>>> See below...
>>>> On Tue, 22 Dec 2009 05:27:01 -0800, Cameron_C <CameronC(a)discussions.microsoft.com> wrote:
>>>>
>>>>> Hello Everyone.
>>>>> I have been struggling with this item for some time.
>>>>> For a while I was content to ignore it, but it has finally made it to the
>>>>> top of my list.
>>>>> I have an application where the User may choose reporting fonts.
>>>>> Three fonts. One for the header, one for the body, and one for the footer of
>>>>> the various reports. I save the LOGFONT structures for later use.
>>>>> At the time I do a StartDocument I grab the LOGFONT structures I had
>>>>> previously saved, and CreatePointFontIndirect to create the fonts.
>>>>> As I walk through the code in debug mode, everything seems to work fine.
>>>>> However, the printing works perfectly on an HP 9040DN, but no details appear
>>>>> when I print to a Brother or the HP Photosmart I have. The graphics boxes do
>>>>> appear though.
>>>>>
>>>>> Anyway my first question relates to the voodoo-like black magic of scaling
>>>>> the font.
>>>>> I want a ten point font. I select a ten point font from the CFontDialog, and
>>>>> save it. Later, when I want to create the font I call
>>>>> CreatePointFontIndirect, and I pass a value that is in tenths of a point. So,
>>>>> now I would pass 100, for my ten point font.
>>>> ****
>>>> The truth is that the font is scaled to the display. If you want to use that font on a
>>>> printer, you must scale it to the printer.
>>>>
>>>> Typically, you want to use CFont::CreatePointFontIndirect and for the second parameter
>>>> pass in your printer DC for printing and either NULL or your display DC for display.
>>>> *****
>>>> >From experience this never worked. After poking through various web sites, I
>>>>> found someone had success with using a "Cook''s Constant" of 42/13. So, I
>>>>> have taken my value of 100, and multipled by 42/13. Is this obtuse or am I
>>>>> off base here? Anyway, this appears to do the trick, at least for the HP
>>>>> printer.
>>>> ****
>>>> Sounds like sheer luck. I have no idea what this is doing.
>>>> *****
>>>>> I checked the Microsoft docs, and they suggest using something along the
>>>>> lines of -MulDiv(m_lfReportHeader.lfHeight/10,
>>>>> m_dc.GetDeviceCaps(LOGPIXELSY), 72);
>>>>> Now, I have tried this with the printers that do not deliver the report as
>>>>> execpted, and I see no difference. I have not tried this with the HP printer
>>>>> that is really working.
>>>> *****
>>>> It may be a function of the printer dirvers, but it seems obtuse if it is.
>>>> ****
>>>>> Here is a code snippet showing how I have created the fonts.
>>>>> /*
>>>>> Assign default Report Header Font for the Reports
>>>>> Note: m_szIniSectionName will refer to the specific Report for the Printer.
>>>>> m_ProcessIni.m_szIniSectionName will refer to the DEFAULT entries
>>>>> for the Printer.
>>>>> */
>>>>> LOGFONT lfIniDefaults;
>>>>> BOOL bFlag=FALSE;
>>>>> TEXTMETRIC myTextMetrics;
>>>>>
>>>>> m_ProcessIni.m_szIniKeyName.LoadString(IDS_REPORTHEADERFONT);
>>>>> bFlag = m_ProcessIni.getKeyValueForFont(&lfIniDefaults,
>>>>> m_ProcessIni.m_szIniKeyName, m_szIniSectionName);
>>>> ****
>>>> Have you considered the Registry for this? My Registry library actually saves some font
>>>> information automatically. I see no value in parsing font information from a .INI file (I
>>>> gave up doing that when I abandoned Win16 many years ago)
>>>> ****
>>>>> if (!bFlag) // No font information available from the ini file, so save
>>>>> DEFAULT
>>>>> {
>>>>> m_ProcessIni.setKeyValueForFont(m_plfReportHeader,
>>>>> m_ProcessIni.m_szIniKeyName, m_szIniSectionName);
>>>>> }
>>>>> else
>>>>> {
>>>>> m_lfReportHeader = lfIniDefaults;
>>>>> }
>>>>> lfIniDefaults = m_lfReportHeader;
>>>>> lfIniDefaults.lfHeight*=(42/13); // I have no idea why this scaling is
>>>>> required... But it is. Found this in a news group.
>>>> ****
>>>> Neither do I, it looks really bogus, like someone discovered some random value which gave
>>>> the illusion of working so claimed it made sense. 42/13 is silly anyway; 42/13 is 3, and
>>>> expressed as 42/13 doesn't change the fact it is 3. And I have no idea what 3 does. Now
>>>> 42.0/13.0, working as a double, e.g.,
>>>> something =(int)( (double) something * 42.0 / 13.0)
>>>> might have meaning, but "3" is just silly.
>>>> ****
>>>>> // lfIniDefaults.lfHeight = -MulDiv(m_lfReportHeader.lfHeight/10,
>>>>> m_dc.GetDeviceCaps(LOGPIXELSY), 72);
>>>> ****
>>>> If you get rid of the gratutitous *=3, this should work correctly. But it is what
>>>> CreatePointFontIndirect does. Read the code.
>>>> ****
>>>>> /*
>>>>> Establish Font characteristics for the Report Header lines.
>>>>> lfIniDefaults Points to a LOGFONT structure that defines the
>>>>> characteristics
>>>>> of the logical font.
>>>>> The lfHeight member of the LOGFONT structure is measured in tenths of a
>>>>> point
>>>>> rather than logical units.
>>>>> (For instance, set lfHeight to 120 to request a 12-point font.)
>>>>> CreatePointFontIndirect returns non-zero when successful.
>>>>> If bFlag is zero, we have a problem!
>>>>> */
>>>>> CFont*pOldHeaderFont, *pOldFooterFont, *pOldBodyFont;
>>>> *****
>>>> Never use commas in declaration lists. And there is no reason to save old state like
>>>> "OldHeaderFont"; instead, use CDC::SaveDC and CDC::RestoreDC to mainain the purity of your
>>>> DC.
>>>> ****
>>>>> m_cfReportHeader.DeleteObject();
>>>>> bFlag = m_cfReportHeader.CreatePointFontIndirect(&lfIniDefaults, &m_dc);
>>>> ****
>>>> OK, you Are using CreatePointFontIndirect, so why all that other stuff which either
>>>> duplicates it or duplicates it badly?
>>>> ****
>>>>> pOldHeaderFont = m_dc.SelectObject(&m_cfReportHeader);
>>>> ****
>>>> I have not saved an "old setting" on SelectObject in about 20 years. Use
>>>> SaveDC/RestoreDC. Otherwise, you get a lot of garbage variables and lose track of them
>>>> (there are over 30 DC parameters you might want to save the "old" version of!)
>>>> ****
>>>>> m_pcfReportHeader = &m_cfReportHeader;
>>>> *****
>>>> How in the world does this assigment make any sense whatsoever? It is complete nonsense.
>>>> Get rid of it.
>>>> ****
>>>>> // m_hFontReportHeader is the CGdiObject public data member that stores
>>>>> the handle
>>>>> m_hFontReportHeader = (HFONT) pOldHeaderFont->GetSafeHandle();
>>>> *****
>>>> This makes even less sense. Why do you need an HFONT anyway? There is something
>>>> seriously wrong hwere with what you are doing.
>>>> ****
>>>>> //m_hFontReportHeader = (HFONT) m_pcfReportHeader->GetSafeHandle();
>>>>> /* Get Average size of printed text for the Header Font */
>>>>> m_dc.GetTextMetrics(&myTextMetrics);
>>>>> m_yLineHeader = myTextMetrics.tmHeight;
>>>>>
>>>>> Later when I want to use the font in a report, I select the font, and do a
>>>>> DrawText.
>>>>> Here is a code snippet:
>>>>> pcfOriginal =
>>>>> ts->_this->PrinterControl.m_dc.SelectObject(ts->_this->PrinterControl.m_pcfReportHeader);
>>>> ****
>>>> There is no need to store the original. m_dc.SaveDC() will save the DC state. Get rid of
>>>> the assignment.
>>>>
>>>> What is _this?
>>>>
>>>> If this is a subroutine that is being called for each of the headers, just pass the font
>>>> in as a CFont& and when you need the address, use & on that. This business of having some
>>>> memver variable which is set to a pointer doesn't make sense.
>>>> ****
>>>>> iPrintedHeight=ts->_this->PrinterControl.m_dc.DrawText(szHeader,
>>>>> rclHeader, DT_TOP|DT_CENTER);
>>>>> iPrintedHeight=ts->_this->PrinterControl.m_dc.DrawText(szSubHeader,
>>>>> rclSubHeader, DT_TOP|DT_CENTER);
>>>>> pcfOriginal =
>>>>> ts->_this->PrinterControl.m_dc.SelectObject(ts->_this->PrinterControl.m_pcfReportFooter);
>>>> ****
>>>> I'm already confused. You set pcfOriginal to one value when you select the header font,
>>>> and then you overwrite that when you select the footer font (and why would you not simply
>>>> write
>>>> &ts->_this->PrinterControl.m_cfReportFooter
>>>> instead of that silly technique of storing pointer variables which you then use here?) so
>>>> what is it going to be restored to?
>>>> ****
>>>>> iPrintedHeight=ts->_this->PrinterControl.m_dc.DrawText(szFooter,
>>>>> rclFooter, DT_BOTTOM|DT_CENTER);
>>>>> szBuffer.Format(_T("Page %d"), ++lPageNumber);
>>>>> iPrintedHeight=ts->_this->PrinterControl.m_dc.DrawText(szBuffer,
>>>>> rclFooter, DT_BOTTOM|DT_RIGHT);
>>>>> pcfOriginal =
>>>>> ts->_this->PrinterControl.m_dc.SelectObject(ts->_this->PrinterControl.m_pcfReportBody);
>>>> ****
>>>> You really need to understand what the & operator does, and where you use it. All those
>>>> intermediate pointer-to-font variables are completely silly!
>>>>
>>>> I note that at no point do you restore the font you changed, that is, I see no
>>>> ....m_dc.SelectObject(pcfOriginal);
>>>> and that means that saving the value is pointless. And then you leave the font selected
>>>> into the DC, which is poor practice. See my essay on SaveDC/RestoreDC on my MVP Tips
>>>> site.
>>>> ****
>>>>> One last question, I know that the Fonts are applicable for the DC that has
>>>>> been selected. When the DC is destroyed, and recreated, do the Fonts need to
>>>>> be recreated? Do I need to destroy and recreate the fonts every time I
>>>>> destroy and recreate the DC? Should I?
>>>> ****
>>>> Yes. Because if I create a font for my one printer (1200dpi) then close the printer, and
>>>> then open another DC on the other printer (600 dpi), my fonts would be 2x too large. So
>>>> it is rare I would create the fonts as member variables at all. I would typically create
>>>> them in the printing routine handler, and let the normal CFont::~CFont destructor get rid
>>>> of them when I was done printing. I don;t use global variables when local variables would
>>>> do. And I'm willing to pass parameters around, including a parameter which is my printing
>>>> context, e.g.,
>>>> class PrintingContext {
>>>> public:
>>>> CFont Header;
>>>> CFont Section;
>>>> CFont MajorTitle;
>>>> CFont Text;
>>>> };
>>>> and initialize those variables. I'd probably have a constructor that took the CDC and
>>>> created the fonts relative to it. And I'd probably have other things in it such as the
>>>> current line, current page #, etc., and never, ever, under any conditions imaginable would
>>>> those be member variables in any view class or anyplace outside this PrintingContext
>>>> object. Then all my functions would take a PrintingContext& parameter that would give me
>>>> access to this information. When the printing is done, it goes away, all the fonts go
>>>> away, and I never see any of them ever again until I need to do another print run. I
>>>> would have a "generic" LOGFONT structure that I used for storing the data, but it would
>>>> only be passed in to my font constructors in my PrintingContext object.
>>>>
>>>> Localize information as tightly as you can,
>>>>
>>>> And never store a pointer-to-something if you can COMPUTE the pointer-to-something on
>>>> demand. You added meaningless complexity to your class and your code by introducing these
>>>> pointer variables!
>>>> joe
>>>> ****
>>>>> Today, I plan to try to sift through SuperPad. I believe it is the Microsoft
>>>>> sample which may help me out here.
>>>>>
>>>>> Thanks for any information, and Merry Christmas!
>>>>>
From: Joseph M. Newcomer on
If you are doing a CreatePointFont, then its specification is to give the lfHeight as
decipixels. But that is a feature CreatePointFont (look at its code). So yes, if you are
giving font heights in decipoints, you want the / 10, but you had not actually indicated
that you were using decipoint heights.

If you are doing CreateFontIndirect, you must use the actual height with the muldiv
computation. If you are doing CreatePointFont[Indirect] to a printer DC, the base
computations are already done for you, so you don't want to do them yourself; the result
will not be meaningful.

Your choice of font height representation is yours. But remember that if you are doing
CreateFont[Indirect] you want the height in pixels, not decipixels. If you are doing
CreatePointFont[Indirect], its specificaiton is decipixels, in which case you would not be
doing a muldiv yourself.

Ultimately, you are going to get a font in pixels. To get a 10-point font on a 10ppi
display, there is a 1:1 correspondence,but on a 600dpi display, to get a 10-point font it
would be 10 * (600/72). If you do this in floating point, you get 6000/72, and that is
essentially 83 pixels high. So if you single-step in far enough to
CreatePointFont[Indirect] you should see a real CreateFont creating a font which is the
right number of pixels for your device. An 18-point font would be 18*600/72 or about 150
pixels high. Notice that the order matters. I tend to do computations in floating point
and then round them and convert back to an integer; saves all kinds of hassle with integer
truncation problems.

If you are using MM_TWIPS, then you have 1440 pixels/inch, so an 18-point font is
18*1440/72 = 360 pixels high. GDI takes care of mapping twips-based coordinates to
physical device coordinates.

Note that if you are using a raw printer DC, the assumption is that you are using MM_TEXT.
So if you want to use CreatePointFont[Indirect] and specify a DC, the DC has to be in the
mapping mode you are going to use. Doesn't matter if it is TWIPS, LOENGLISH, HIENGLISH,
LMETRIC, HIMETRIC, or your own custom ISOTROPIC or ANISOTROPIC mapping, whatever mapping
you are going to use for the drawing is what should be set. Generally you do this in
OnPrepareDC, so you would call that at the point where you are about to create the font.

Frankly, I would not waste any effort trying to create the font in advance of printing.
When I got into the OnDraw handler, after PrepareDC is called, that is the only place I
would create the fonts. They would not be member variables of the class; they would be
local variables of the OnDraw function. When I left OnDraw, they would be implicitly
destroyed by the destructors of the local variables. I would have no reason for them to
exist outside the context of OnDraw (or OnPaint).
joe


On Wed, 23 Dec 2009 12:51:01 -0800, Cameron_C <CameronC(a)discussions.microsoft.com> wrote:

>Thanks Joe.
>What value should be in the lfHeight, when I am looking for a six point font?
>I know that I should use tenths of a point (so sixty) when I
>CreatePointFontIndirect.
>But, what do I want to put through the scaling math? Do I need tenths of a
>point? Or full point values?
>I believe that the MulDiv(a,b,c) is supposed to give me (a*b)/c.
>But, do I start with tenths of a point or point values? Six or sixty?
>When I use sixty, my font is now about one inch high.
>And when I use six, I get something pretty small. Maybe it is six points.
>And this is since I changed to set to MM_TWIPS after creating the printer DC.
>Maybe I should not use MM_TWIPS?
>
>Thanks,
>
>
>"Joseph M. Newcomer" wrote:
>
>> As pointed out, that divide-by-10 is a total disaster. Remove it.
>> joe
>>
>> On Wed, 23 Dec 2009 06:26:01 -0800, Cameron_C <CameronC(a)discussions.microsoft.com> wrote:
>>
>> >Thanks Joe,
>> >I removed the coding for the 42/13, and tried with the
>> > lfIniDefaults.lfHeight = -MulDiv(m_lfReportHeader.lfHeight/10,
>> >m_dc.GetDeviceCaps(LOGPIXELSY), 72);
>> >This gave me some print that was about a 2 point font. With glasses I could
>> >almost read some of it.
>> >But this is progress, at least something is printing.
>> >
>> >I also just found that if I use SetBkMode(TRANSPARENT) just before I begin
>> >to print, the report appears on my HP Photosmart printer. (Found it by
>> >accident when I accidentally uncommented the wrong line).
>> >
>> >When I print, I get a printer dc, then I define the fonts. The I select the
>> >font I want and I drawtext.
>> >
>> >This works fine on one printer. And, since I added the SetBkMode it works on
>> >another (although I have no understanding of why this would be). But still
>> >fails to print on my little Brother printer.
>> >
>> >One more curiousity, when I create font defaults, I do the following:
>> > CFont cfPrinterFont;
>> > m_bFlag = m_pApp->CreatePrinterDC(m_dc);
>> >
>> > /* Establish Default Font characteristics for the Reports */
>> > cfPrinterFont.Attach(::GetStockObject(DEVICE_DEFAULT_FONT));
>> > LOGFONT lf;
>> > cfPrinterFont.GetLogFont(&lf);
>> >
>> > lf.lfHeight *= 10;
>> > cfPrinterFont.Detach();
>> >
>> > cfPrinterFont.CreatePointFontIndirect(&lf, &m_dc);
>> > cfPrinterFont.GetLogFont(&m_lfReportHeader);
>> >Now, later when I try to use the LOGFONT, I get characters that are the
>> >expected height, but are so thin they are unrecognizable.
>> ***
>> Never set lfWidth. Leave it 0 (default). Otherwise, you get the strange effects you are
>> seeing.
>>
>> You can download my font explorer and play with it, but you will see that lfWidth is not a
>> good value to use.
>> ****
>> >So, I reset the lfWidth to zero, in this LOGFONT structure, before I
>> >CreatePointFontIndirect.
>> >And, at least then I can see the characters.
>> >Why does the width need to be 0 (which requests the default)? I thought if I
>> >requested the DEVICE_DEFAULT_FONT for the printer DC, I would get all of the
>> >values I needed?
>> ****
>> TrueType/OpenType fonts will adjust themselves by horizontal scaling to conform to the
>> lfWidth if you do not default it.
>> ****
>> >Are there any other values I get in the LOGFONT that I should reset before
>> >creating a font?
>> >
>> >And then one more question.
>> >Maybe this is not an appropraite technique? I use a CFontDialog to allow the
>> >Users to select the fonts for the reports.
>> > LOGFONT lf = m_pPrinterControl->m_lfReportHeader;
>> > lf.lfHeight = -MulDiv(m_pPrinterControl->m_lfReportHeader.lfHeight/10,
>> >m_pDC->GetDeviceCaps(LOGPIXELSY), 72);
>> > CFontDialog fdHeader(&lf,
>> > CF_PRINTERFONTS | CF_EFFECTS | CF_INITTOLOGFONTSTRUCT | CF_ENABLEHOOK
>> >| CF_FORCEFONTEXIST,
>> > m_pDC);
>> >
>> >Should the m_DC refer to the printerDC? Or to the display DC.
>> >I think it has to be the display but I am not sure?
>> ****
>> Ideally, the printer DC for selecting printer fonts. Again, get rid of the /10 (note this
>> is integer divide, so 18/10 = 1, which leads to your problems). But generally, if you use
>> the display, the fonts are available for the display. This dichotomy predates the
>> TrueType world, and in those days it allowed you to specify native printer fonts for
>> dot-matrix printers and primitive inkjet and laser printers. It is generally no longer an
>> issue.
>> joe
>> ****
>> >
>> >Thanks,
>> >
>> >
>> >"Joseph M. Newcomer" wrote:
>> >
>> >> See below...
>> >> On Tue, 22 Dec 2009 05:27:01 -0800, Cameron_C <CameronC(a)discussions.microsoft.com> wrote:
>> >>
>> >> >Hello Everyone.
>> >> >I have been struggling with this item for some time.
>> >> >For a while I was content to ignore it, but it has finally made it to the
>> >> >top of my list.
>> >> >I have an application where the User may choose reporting fonts.
>> >> >Three fonts. One for the header, one for the body, and one for the footer of
>> >> >the various reports. I save the LOGFONT structures for later use.
>> >> >At the time I do a StartDocument I grab the LOGFONT structures I had
>> >> >previously saved, and CreatePointFontIndirect to create the fonts.
>> >> >As I walk through the code in debug mode, everything seems to work fine.
>> >> >However, the printing works perfectly on an HP 9040DN, but no details appear
>> >> >when I print to a Brother or the HP Photosmart I have. The graphics boxes do
>> >> >appear though.
>> >> >
>> >> >Anyway my first question relates to the voodoo-like black magic of scaling
>> >> >the font.
>> >> >I want a ten point font. I select a ten point font from the CFontDialog, and
>> >> >save it. Later, when I want to create the font I call
>> >> >CreatePointFontIndirect, and I pass a value that is in tenths of a point. So,
>> >> >now I would pass 100, for my ten point font.
>> >> ****
>> >> The truth is that the font is scaled to the display. If you want to use that font on a
>> >> printer, you must scale it to the printer.
>> >>
>> >> Typically, you want to use CFont::CreatePointFontIndirect and for the second parameter
>> >> pass in your printer DC for printing and either NULL or your display DC for display.
>> >> *****
>> >> >From experience this never worked. After poking through various web sites, I
>> >> >found someone had success with using a "Cook''s Constant" of 42/13. So, I
>> >> >have taken my value of 100, and multipled by 42/13. Is this obtuse or am I
>> >> >off base here? Anyway, this appears to do the trick, at least for the HP
>> >> >printer.
>> >> ****
>> >> Sounds like sheer luck. I have no idea what this is doing.
>> >> *****
>> >> >I checked the Microsoft docs, and they suggest using something along the
>> >> >lines of -MulDiv(m_lfReportHeader.lfHeight/10,
>> >> >m_dc.GetDeviceCaps(LOGPIXELSY), 72);
>> >> >Now, I have tried this with the printers that do not deliver the report as
>> >> >execpted, and I see no difference. I have not tried this with the HP printer
>> >> >that is really working.
>> >> *****
>> >> It may be a function of the printer dirvers, but it seems obtuse if it is.
>> >> ****
>> >> >Here is a code snippet showing how I have created the fonts.
>> >> > /*
>> >> > Assign default Report Header Font for the Reports
>> >> > Note: m_szIniSectionName will refer to the specific Report for the Printer.
>> >> > m_ProcessIni.m_szIniSectionName will refer to the DEFAULT entries
>> >> > for the Printer.
>> >> > */
>> >> > LOGFONT lfIniDefaults;
>> >> > BOOL bFlag=FALSE;
>> >> > TEXTMETRIC myTextMetrics;
>> >> >
>> >> > m_ProcessIni.m_szIniKeyName.LoadString(IDS_REPORTHEADERFONT);
>> >> > bFlag = m_ProcessIni.getKeyValueForFont(&lfIniDefaults,
>> >> >m_ProcessIni.m_szIniKeyName, m_szIniSectionName);
>> >> ****
>> >> Have you considered the Registry for this? My Registry library actually saves some font
>> >> information automatically. I see no value in parsing font information from a .INI file (I
>> >> gave up doing that when I abandoned Win16 many years ago)
>> >> ****
>> >> > if (!bFlag) // No font information available from the ini file, so save
>> >> >DEFAULT
>> >> > {
>> >> > m_ProcessIni.setKeyValueForFont(m_plfReportHeader,
>> >> >m_ProcessIni.m_szIniKeyName, m_szIniSectionName);
>> >> > }
>> >> > else
>> >> > {
>> >> > m_lfReportHeader = lfIniDefaults;
>> >> > }
>> >> > lfIniDefaults = m_lfReportHeader;
>> >> > lfIniDefaults.lfHeight*=(42/13); // I have no idea why this scaling is
>> >> >required... But it is. Found this in a news group.
>> >> ****
>> >> Neither do I, it looks really bogus, like someone discovered some random value which gave
>> >> the illusion of working so claimed it made sense. 42/13 is silly anyway; 42/13 is 3, and
>> >> expressed as 42/13 doesn't change the fact it is 3. And I have no idea what 3 does. Now
>> >> 42.0/13.0, working as a double, e.g.,
>> >> something =(int)( (double) something * 42.0 / 13.0)
>> >> might have meaning, but "3" is just silly.
>> >> ****
>> >> >// lfIniDefaults.lfHeight = -MulDiv(m_lfReportHeader.lfHeight/10,
>> >> >m_dc.GetDeviceCaps(LOGPIXELSY), 72);
>> >> ****
>> >> If you get rid of the gratutitous *=3, this should work correctly. But it is what
>> >> CreatePointFontIndirect does. Read the code.
>> >> ****
>> >> >
>> >> > /*
>> >> > Establish Font characteristics for the Report Header lines.
>> >> > lfIniDefaults Points to a LOGFONT structure that defines the
>> >> >characteristics
>> >> > of the logical font.
>> >> > The lfHeight member of the LOGFONT structure is measured in tenths of a
>> >> >point
>> >> > rather than logical units.
>> >> > (For instance, set lfHeight to 120 to request a 12-point font.)
>> >> > CreatePointFontIndirect returns non-zero when successful.
>> >> > If bFlag is zero, we have a problem!
>> >> > */
>> >> > CFont*pOldHeaderFont, *pOldFooterFont, *pOldBodyFont;
>> >> *****
>> >> Never use commas in declaration lists. And there is no reason to save old state like
>> >> "OldHeaderFont"; instead, use CDC::SaveDC and CDC::RestoreDC to mainain the purity of your
>> >> DC.
>> >> ****
>> >> >
>> >> > m_cfReportHeader.DeleteObject();
>> >> > bFlag = m_cfReportHeader.CreatePointFontIndirect(&lfIniDefaults, &m_dc);
>> >> ****
>> >> OK, you Are using CreatePointFontIndirect, so why all that other stuff which either
>> >> duplicates it or duplicates it badly?
>> >> ****
>> >> > pOldHeaderFont = m_dc.SelectObject(&m_cfReportHeader);
>> >> ****
>> >> I have not saved an "old setting" on SelectObject in about 20 years. Use
>> >> SaveDC/RestoreDC. Otherwise, you get a lot of garbage variables and lose track of them
>> >> (there are over 30 DC parameters you might want to save the "old" version of!)
>> >> ****
>> >> > m_pcfReportHeader = &m_cfReportHeader;
>> >> *****
>> >> How in the world does this assigment make any sense whatsoever? It is complete nonsense.
>> >> Get rid of it.
>> >> ****
>> >> > // m_hFontReportHeader is the CGdiObject public data member that stores
>> >> >the handle
>> >> > m_hFontReportHeader = (HFONT) pOldHeaderFont->GetSafeHandle();
>> >> *****
>> >> This makes even less sense. Why do you need an HFONT anyway? There is something
>> >> seriously wrong hwere with what you are doing.
>> >> ****
>> >> > //m_hFontReportHeader = (HFONT) m_pcfReportHeader->GetSafeHandle();
>> >> > /* Get Average size of printed text for the Header Font */
>> >> > m_dc.GetTextMetrics(&myTextMetrics);
>> >> > m_yLineHeader = myTextMetrics.tmHeight;
>> >> >
>> >> >Later when I want to use the font in a report, I select the font, and do a
>> >> >DrawText.
>> >> >Here is a code snippet:
>> >> > pcfOriginal =
>> >> >ts->_this->PrinterControl.m_dc.SelectObject(ts->_this->PrinterControl.m_pcfReportHeader);
>> >> ****
>> >> There is no need to store the original. m_dc.SaveDC() will save the DC state. Get rid of
>> >> the assignment.
>> >>
>> >> What is _this?
>> >>
>> >> If this is a subroutine that is being called for each of the headers, just pass the font
>> >> in as a CFont& and when you need the address, use & on that. This business of having some
>> >> memver variable which is set to a pointer doesn't make sense.
>> >> ****
>> >> > iPrintedHeight=ts->_this->PrinterControl.m_dc.DrawText(szHeader,
>> >> >rclHeader, DT_TOP|DT_CENTER);
>> >> > iPrintedHeight=ts->_this->PrinterControl.m_dc.DrawText(szSubHeader,
>> >> >rclSubHeader, DT_TOP|DT_CENTER);
>> >> > pcfOriginal =
>> >> >ts->_this->PrinterControl.m_dc.SelectObject(ts->_this->PrinterControl.m_pcfReportFooter);
>> >> ****
>> >> I'm already confused. You set pcfOriginal to one value when you select the header font,
>> >> and then you overwrite that when you select the footer font (and why would you not simply
>> >> write
>> >> &ts->_this->PrinterControl.m_cfReportFooter
>> >> instead of that silly technique of storing pointer variables which you then use here?) so
>> >> what is it going to be restored to?
>> >> ****
>> >> > iPrintedHeight=ts->_this->PrinterControl.m_dc.DrawText(szFooter,
>> >> >rclFooter, DT_BOTTOM|DT_CENTER);
>> >> > szBuffer.Format(_T("Page %d"), ++lPageNumber);
>> >> > iPrintedHeight=ts->_this->PrinterControl.m_dc.DrawText(szBuffer,
>> >> >rclFooter, DT_BOTTOM|DT_RIGHT);
>> >> > pcfOriginal =
>> >> >ts->_this->PrinterControl.m_dc.SelectObject(ts->_this->PrinterControl.m_pcfReportBody);
>> >> ****
>> >> You really need to understand what the & operator does, and where you use it. All those
>> >> intermediate pointer-to-font variables are completely silly!
>> >>
>> >> I note that at no point do you restore the font you changed, that is, I see no
>> >> ....m_dc.SelectObject(pcfOriginal);
>> >> and that means that saving the value is pointless. And then you leave the font selected
>> >> into the DC, which is poor practice. See my essay on SaveDC/RestoreDC on my MVP Tips
>> >> site.
>> >> ****
>> >> >
>> >> >
>> >> >One last question, I know that the Fonts are applicable for the DC that has
>> >> >been selected. When the DC is destroyed, and recreated, do the Fonts need to
>> >> >be recreated? Do I need to destroy and recreate the fonts every time I
>> >> >destroy and recreate the DC? Should I?
>> >> ****
>> >> Yes. Because if I create a font for my one printer (1200dpi) then close the printer, and
>> >> then open another DC on the other printer (600 dpi), my fonts would be 2x too large. So
>> >> it is rare I would create the fonts as member variables at all. I would typically create
>> >> them in the printing routine handler, and let the normal CFont::~CFont destructor get rid
>> >> of them when I was done printing. I don;t use global variables when local variables would
>> >> do. And I'm willing to pass parameters around, including a parameter which is my printing
>> >> context, e.g.,
>> >> class PrintingContext {
>> >> public:
>> >> CFont Header;
>> >> CFont Section;
>> >> CFont MajorTitle;
>> >> CFont Text;
>> >> };
>> >> and initialize those variables. I'd probably have a constructor that took the CDC and
>> >> created the fonts relative to it. And I'd probably have other things in it such as the
>> >> current line, current page #, etc., and never, ever, under any conditions imaginable would
Joseph M. Newcomer [MVP]
email: newcomer(a)flounder.com
Web: http://www.flounder.com
MVP Tips: http://www.flounder.com/mvp_tips.htm