{"id":28423,"date":"2007-01-12T10:00:02","date_gmt":"2007-01-12T10:00:02","guid":{"rendered":"https:\/\/blogs.msdn.microsoft.com\/oldnewthing\/2007\/01\/12\/how-do-i-print-the-contents-of-a-rich-text-control\/"},"modified":"2007-01-12T10:00:02","modified_gmt":"2007-01-12T10:00:02","slug":"how-do-i-print-the-contents-of-a-rich-text-control","status":"publish","type":"post","link":"https:\/\/devblogs.microsoft.com\/oldnewthing\/20070112-02\/?p=28423","title":{"rendered":"How do I print the contents of a rich text control?"},"content":{"rendered":"<p>\nFor some reason, people are really puzzled by rich edit printing.\nI&#8217;m no expert on printing, but even I was able to figure it out.\nThe kernel is the <code>EM_FORMATRANGE<\/code> message.\nEach time you call it, a little bit more of the rich text control\nis printed, and the message returns the index of the first\nunprinted character,\nwhich you can pass back in to print the next chunk.\n<\/p>\n<p>\nThe rest is just setting up and tearing down.\n<\/p>\n<pre>\nBOOL PrintRTF(HWND hwnd, HDC hdc)\n{\n int cxPhysOffset = GetDeviceCaps(hdc, PHYSICALOFFSETX);\n int cyPhysOffset = GetDeviceCaps(hdc, PHYSICALOFFSETY);\n int cxPhys = GetDeviceCaps(hdc, PHYSICALWIDTH);\n int cyPhys = GetDeviceCaps(hdc, PHYSICALHEIGHT);\n SendMessage(hwnd, EM_SETTARGETDEVICE, (WPARAM)hdc, cxPhys);\n FORMATRANGE fr;\n fr.hdc = hdc;\n fr.hdcTarget = hdc;\n fr.rc.left = cxPhysOffset;\n fr.rc.right = cxPhysOffset + cxPhys;\n fr.rc.top = cyPhysOffset;\n fr.rc.bottom = cyPhysOffset + cyPhys;\n SendMessage(hwnd, EM_SETSEL, 0, (LPARAM)-1);\n SendMessage(hwnd, EM_EXGETSEL, 0, (LPARAM)&amp;fr.chrg);\n BOOL fSuccess = TRUE;\n while (fr.chrg.cpMin &lt; fr.chrg.cpMax &amp;&amp; fSuccess) {\n  fSuccess = StartPage(hdc) &gt; 0;\n  if (!fSuccess) break;\n  int cpMin = SendMessage(hwnd, EM_FORMATRANGE, TRUE, (LPARAM)&amp;fr);\n  if (cpMin &lt;= fr.chrg.cpMin) {\n   fSuccess = FALSE;\n   break;\n  }\n  fr.chrg.cpMin = cpMin;\n  fSuccess = EndPage(hdc) &gt; 0;\n }\n SendMessage(hwnd, EM_FORMATRANGE, FALSE, 0);\n return fSuccess;\n}\n<\/pre>\n<p>\nWe start by getting the dimensions of the page and\ntelling the rich edit control what we intend to render to\nby using the <code>EM_SETTARGETDEVICE<\/code> message.\nNext, we need to fill out our <code>FORMATRANGE<\/code>,\nwhich we do by specifying the <code>HDC<\/code> we are\nrendering to, as well as the paper dimensions.\nBut what about the character range?\nWe are lazy and let the rich edit control take care of it for us:\nWe select all the text and then ask the rich edit control to\ntell us what we just selected, which comes back in the form\nof a <code>CHARRANGE<\/code>, which is exactly what we needed.\n<\/p>\n<p>\nNext comes the printing loop.\nWhile there is still text to print (and we haven&#8217;t encountered\nan error), we start a new page,\nask the rich edit control to render that page,\nremember where the next page should begin,\nand end the current page.\nThere&#8217;s a little sanity check in there to make sure that the\nrich edit control made forward progress; if not, then we&#8217;ll\nend up in an infinite loop spewing out blank pages!\n(I have no idea whether this is theoretically possible, but I&#8217;m\ngoing to protect against it just the same.)\n<\/p>\n<p>\nOnce the printing loop is complete, we clean up by sending\none last <code>EM_FORMATRANGE<\/code> message to tell the\nrich edit control that we&#8217;re all done and it can discard the\ninformation it cached.\n<\/p>\n<p>\nWe can take all the information we&#8217;ve learned over the\npast few days to make a simple &#8220;print RTF&#8221; program.\n<\/p>\n<pre>\nint CALLBACK\n_tWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,\n          LPTSTR lpCmdLine, int nShowCmd)\n{\n LoadLibrary(TEXT(\"riched20.dll\"));\n HWND hwndRTF = CreateWindow(RICHEDIT_CLASS, NULL,\n                     ES_MULTILINE | WS_OVERLAPPEDWINDOW,\n                     CW_USEDEFAULT, CW_USEDEFAULT,\n                     CW_USEDEFAULT, CW_USEDEFAULT,\n                     NULL, 0, 0, 0);\n if (hwndRTF) {\n  SendMessage(hwndRTF, EM_EXLIMITTEXT, 0, -1);\n  if (FillRichEditFromFile(hwndRTF, lpCmdLine)) {\n   PRINTDLG pd = { sizeof(pd) };\n   pd.Flags = PD_RETURNDC | PD_RETURNDEFAULT;\n   if (PrintDlg(&amp;pd)) {\n    DOCINFO di = { sizeof(di) };\n    di.lpszDocName = TEXT(\"Sample Printout\");\n    if (StartDoc(pd.hDC, &amp;di) &gt; 0) {\n     if (PrintRTF(hwndRTF, pd.hDC)) {\n      EndDoc(pd.hDC);\n     } else {\n      AbortDoc(pd.hDC);\n     }\n    }\n    GlobalFree(pd.hDevMode);\n    GlobalFree(pd.hDevNames);\n    DeleteDC(pd.hDC);\n   }\n  }\n  DestroyWindow(hwndRTF);\n }\n return 0;\n}\n<\/pre>\n<p>\nThere&#8217;s not really much going on here; it&#8217;s all just glue and\nnecessary typing.\n<\/p>\n<p>\nWe create a rich edit control and fill it with the file\npassed on the command line.\nWe then ask the <code>PrintDlg<\/code> function to give us a\nDC to the user&#8217;s default printer.\nWe give the document a title, start the document, print the rich\ntext into the document, and then end the document (or abort it\nif something went wrong during printing).\nA little cleaning up, and we&#8217;re all done.\nA tiny program to print an arbitrary RTF document with\nno fanfare whatsoever.\n<\/p>\n<p>\nSee?\nIt&#8217;s not so hard.\nOnce you find <code>EM_FORMATRANGE<\/code> the rest is just doing\nthe obvious.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>For some reason, people are really puzzled by rich edit printing. I&#8217;m no expert on printing, but even I was able to figure it out. The kernel is the EM_FORMATRANGE message. Each time you call it, a little bit more of the rich text control is printed, and the message returns the index of the [&hellip;]<\/p>\n","protected":false},"author":1069,"featured_media":111744,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"_acf_changed":false,"footnotes":""},"categories":[1],"tags":[25],"class_list":["post-28423","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-oldnewthing","tag-code"],"acf":[],"blog_post_summary":"<p>For some reason, people are really puzzled by rich edit printing. I&#8217;m no expert on printing, but even I was able to figure it out. The kernel is the EM_FORMATRANGE message. Each time you call it, a little bit more of the rich text control is printed, and the message returns the index of the [&hellip;]<\/p>\n","_links":{"self":[{"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/posts\/28423","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/users\/1069"}],"replies":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/comments?post=28423"}],"version-history":[{"count":0,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/posts\/28423\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/media\/111744"}],"wp:attachment":[{"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/media?parent=28423"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/categories?post=28423"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/tags?post=28423"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}