tags:

views:

203

answers:

2

Sometimes our application needs to draw very long strings (e.g. 6,000 chars) using ExtTextOut. Sometimes ExtTextOut fails and returns zero and GetLastError returns zero as well.

To re-create the situation create a simple MFC Single Document application and then set the OnDraw to be:

void CTestExtTextView::OnDraw(CDC* pDC)
{
 CTestExtTextDoc* pDoc = GetDocument();
 ASSERT_VALID(pDoc);
 if (!pDoc)
  return;

 LOGFONT lfDetail = {0};
 lfDetail.lfHeight = -(::MulDiv(100, pDC->GetDeviceCaps(LOGPIXELSY), 720));
 lfDetail.lfCharSet = ANSI_CHARSET;
 lfDetail.lfOutPrecision = OUT_DEFAULT_PRECIS;
 lfDetail.lfQuality = CLEARTYPE_QUALITY;
 lfDetail.lfWeight = 400;
 _tcscpy_s(lfDetail.lfFaceName, LF_FACESIZE, _T("Arial"));

 CFont font;
 font.CreateFontIndirectW( &lfDetail );

 CFont * pold = pDC->SelectObject( &font );

 CString str = L"2 <office:document-content xmlns:office=\"urn:oasis:names:tc:opendocument:xmlns:office:1.0\" xmlns:style=\"urn:oasis:names:tc:opendocument:xmlns:style:1.0\" xmlns:text=\"urn:oasis:names:tc:opendocument:xmlns:text:1.0\" xmlns:table=\"urn:oasis:names:tc:opendocument:xmlns:table:1.0\" xmlns:draw=\"urn:oasis:names:tc:opendocument:xmlns:drawing:1.0\" xmlns:fo=\"urn:oasis:names:tc:opendocument:xmlns:xsl-fo-compatible:1.0\" xmlns:xlink=\"http://www.w3.org/1999/xlink\" xmlns:dc=\"http://purl.org/dc/elements/1.1/\" xmlns:meta=\"urn:oasis:names:tc:opendocument:xmlns:meta:1.0\" xmlns:number=\"urn:oasis:names:tc:opendocument:xmlns:datastyle:1.0\" xmlns:presentation=\"urn:oasis:names:tc:opendocument:xmlns:presentation:1.0\" xmlns:svg=\"urn:oasis:names:tc:opendocument:xmlns:svg-compatible:1.0\" xmlns:chart=\"urn:oasis:names:tc:opendocument:xmlns:chart:1.0\" xmlns:dr3d=\"urn:oasis:names:tc:opendocument:xmlns:dr3d:1.0\" xmlns:math=\"http://www.w3.org/1998/Math/MathML\" xmlns:form=\"urn:oasis:names:tc:opendocument:xmlns:form:1.0\" xmlns:script=\"urn:oasis:names:tc:opendocument:xmlns:script:1.0\" xmlns:ooo=\"http://openoffice.org/2004/office\" xmlns:ooow=\"http://openoffice.org/2004/writer\" xmlns:oooc=\"http://openoffice.org/2004/calc\" xmlns:dom=\"http://www.w3.org/2001/xml-events\" xmlns:xforms=\"http://www.w3.org/2002/xforms\" xmlns:xsd=\"http://www.w3.org/2001/XMLSchema\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" office:version=\"1.1\"><office:scripts/><office:font-face-decls><style:font-face style:name=\"Arial\" svg:font-family=\"Arial\" style:font-family-generic=\"swiss\" style:font-pitch=\"variable\"/><style:font-face style:name=\"Arial Unicode MS\" svg:font-family=\"&apos;Arial Unicode MS&apos;\" style:font-family-generic=\"system\" style:font-pitch=\"variable\"/><style:font-face style:name=\"Tahoma\" svg:font-family=\"Tahoma\" style:font-family-generic=\"system\" style:font-pitch=\"variable\"/></office:font-face-decls><office:automatic-styles><style:style style:name=\"co1\" style:family=\"table-column\"><style:table-column-properties fo:break-before=\"auto\" style:column-width=\"6.659cm\"/></style:style><style:style style:name=\"co2\" style:family=\"table-column\"><style:table-column-properties fo:break-before=\"auto\" style:column-width=\"7.408cm\"/></style:style><style:style style:name=\"co3\" style:family=\"table-column\"><style:table-column-properties fo:break-before=\"auto\" style:column-width=\"7.02cm\"/></style:style><style:style style:name=\"co4\" style:family=\"table-column\"><style:table-column-properties fo:break-before=\"auto\" style:column-width=\"7.214cm\"/></style:style><style:style style:name=\"co5\" style:family=\"table-column\"><style:table-column-properties fo:break-before=\"auto\" style:column-width=\"2.267cm\"/></style:style><style:style style:name=\"ro1\" style:family=\"table-row\"><style:table-row-properties style:row-height=\"0.473cm\" fo:break-before=\"auto\" style:use-optimal-row-height=\"true\"/></style:style><style:style style:name=\"ro2\" style:family=\"table-row\"><style:table-row-properties style:row-height=\"0.453cm\" fo:break-before=\"auto\" style:use-optimal-row-height=\"true\"/></style:style><style:style style:name=\"ta1\" style:family=\"table\" style:master-page-name=\"Default\"><style:table-properties table:display=\"true\" style:writing-mode=\"lr-tb\"/></style:style><style:style style:name=\"T1\" style:family=\"text\"><style:text-properties style:text-position=\"super 58%\"/></style:style></office:automatic-styles><office:body><office:spreadsheet><table:table table:name=\"Sheet1\" table:style-name=\"ta1\" table:print=\"false\"><office:forms form:automatic-focus=\"false\" form:apply-design-mode=\"false\"/><table:table-column table:style-name=\"co1\" table:default-cell-style-name=\"Default\"/><table:table-column table:style-name=\"co2\" table:default-cell-style-name=\"Default\"/><table:table-column table:style-name=\"co3\" table:default-cell-style-name=\"Default\"/><table:table-column table:style-name=\"co4\" table:default-cell-style-name=\"Default\"/><table:table-row table:style-name=\"ro1\"><table:table-cell office:value-type=\"string\"><text:p>Sample text for ExtTextOut</text:p></table:table-cell><table:table-cell office:value-type=\"string\"><text:p>Second Column Sample Text</text:p></table:table-cell><table:table-cell office:value-type=\"string\"><text:p>3<text:span text:style-name=\"T1\">rd</text:span> Column</text:p></table:table-cell><table:table-cell office:value-type=\"string\"><text:p>A More Lengthly bit of text just to make sure we increase the size of the line to something that might make ExtTextOut fail. It doesn&apos;t actually fail if we switch to Anti-Aliased Fonts. Not sure why. It also doesn&apos;t fail if we make the text shorter.</text:p></table:table-cell></table:table-row><table:table-row table:style-name=\"ro1\"><table:table-cell office:value-type=\"string\"><text:p>Sample text for ExtTextOut</text:p></table:table-cell><table:table-cell office:value-type=\"string\"><text:p>Second Column Sample Text</text:p></table:table-cell><table:table-cell office:value-type=\"string\"><text:p>3<text:span text:style-name=\"T1\">rd</text:span> Column</text:p></table:table-cell><table:table-cell office:value-type=\"string\"><text:p>A More Lengthly bit of text just to make sure we increase the size of the line to something that might make ExtTextOut fail. It doesn&apos;t actually fail if we switch to Anti-Aliased Fonts. Not sure why. It also doesn&apos;t fail if we make the text shorter.</text:p></table:table-cell></table:table-row><table:table-row table:style-name=\"ro1\"><table:table-cell office:value-type=\"string\"><text:p>Sample text for ExtTextOut</text:p></table:table-cell><table:table-cell office:value-type=\"string\"><text:p>Second Column Sample Text</text:p></table:table-cell><table:table-cell office:value-type=\"string\">";
 pDC->ExtTextOutW( 0,0, NULL, NULL, str, NULL );
 pDC->ExtTextOutW( 0,50, NULL, NULL, CString(L"But this will print out"), NULL );

 pDC->SelectObject( pold );
}

When you run the application you should see a single line 'But this will print out' half-way down the screen. If you set lfQuality = ANTIALIASED_QUALITY then it does actually print something out but just doesn't look right.

I've tested this on Vista and XP.

Any ideas?

+3  A: 

I created a simple font:

CFont font;
font.CreatePointFont(720, _T("Times New Roman"));
CFont * pold = pDC->SelectObject( &font );

Then initialized a string until it failed to print. 761 characters worked, 762 failed:

CString str('a', 761); // Works
CString str('a', 762); // Fails

I tried a different font, it failed at a higher number of characters. Didn't make sense until I took the size of each string:

CSize s = pDC->GetTextExtent(str);

The width of both strings was ~32700; right near the 16-bit signed limit of 32767.

I was under the impression the 16-bit co-ordinate limitation was bumped to 32-bits starting with NT, so I have no clue why this wouldn't work on XP or Vista. I can vaguely remember a KB article on the subject, but I can't find it.

I tried using TextOut and DrawText and got the same results.

I then tried drawing a couple of lines to ensure they worked beyond the 16-bit limit:

pDC->MoveTo(10,0);
pDC->LineTo(10,38000);
pDC->MoveTo(10,38000);
pDC->LineTo(100, 38000);

and it worked fine, so my guess is there's a bug in the text based GDI functions.

Fat Elvis
Many thanks for your test results and opinion.
snowdude
A: 

Further experimentation revealed that it doesn't appear to be specifically down to the length of the line or the resulting width, i.e. some lines with more characters and wider width would print just fine (e.g. a line with 7,365 chars and 40,360 width printed fine whereas a different line with 6,572 chars and 36,113 width failed). However, those same longer lines could be made to fail by changing something like the background colour of the line.

Which leads me to believe that this might be due to the complexity of the text line rather than just the length of the line and there is possibly an internal time-out, ie if ExtTextOut sees that it is taking too long then it just quits without printing any output.

Our solution was to chop up each line into 500 character chunks. So instead of a single ExtTextOut for a 6,000 chars line there are 12 ExtTextOuts each printing at the end of the last. This seems to work perfectly with very little performance hit and allows us to print very large lines (I stopped testing after 60,000 chars).

snowdude