rtf Printing in ActiveX Control

Posted on 2006-04-27
Medium Priority
Last Modified: 2011-09-20
I have created an ActiveX control which provides the local printers as properties and which prints RAW data onto one of them (the data comes from a server in base64).

I'd like to be able to print RTF format (which I'm assured is plain 7-bit text commands) along the lines of (Javascript) :-

   var printer = new ActiveXObject("RatSoft.RatPrint.1");

   printer.printerName = "Epson 700";


where string is a RTF string (eg: {\rtf1\ansi\ansicpg1252\deff0\deflang1031{\f.......)

How do I proceed?

Question by:BigRat
  • 4
  • 2
LVL 86

Accepted Solution

jkr earned 750 total points
ID: 16554564
Can you use a 'CRichEditCtrl' in your aActiveX (it does not have to be displayed, however it would make handling of both RTF and printing a lot easier)? The outline would be to

    BOOL            bCtrlReady;

    CRichEditCtrl*  pCtrl;
    EDITSTREAM      esIn;

    esIn.dwCookie       =   ( DWORD) [pointer to RTF text];
    esIn.pfnCallback    =   ReadStreamCallBack; // just copes the text from 'dwCookie' to a buffer

    lBytes  =   pCtrl->StreamIn ( SF_RTF, esIn);

    HDC hPrinter = CreateDC(pDriver,pPrinter,pPort,NULL);

    FORMATERANGE fr; // set that up

    pCtrl->FormatRange( &fr, TRUE);

    pCtrl->DisplayBand( &rect);

    pCtrl->DestroyWindow ();

    delete  pCtrl;

LVL 27

Author Comment

ID: 16560680
>>Can you use a 'CRichEditCtrl' in your aActiveX

If I remember rightly this control is wrapped by WordPad so I don't need to install anything additional. So yes.

I don't understand the FORMATTERRANGE and the Rect bit. I thought that an RTF document was complete? I don't want any user interaction, it should just print the contents.
LVL 86

Expert Comment

ID: 16598417
Sorry for the delay, but I simply forgot :-(

The article at http://www.codeproject.com/printing/richeditprint.asp ("How to print the content of a Rich Edit Control") describes how to handle these, I only used the control itself (as an invisible window) for RTF<->Text conversion.

BTW, the missing part in the above is 'ReadStreamCallBack()' which basically would be

ReadStreamCallBack  (   DWORD   dwCookie,
                        LPBYTE  pbBuff,
                        LONG    cb, // number of bytes to read or write
                        LONG*   pcb // pointer to number of bytes transferred
    BOOL    bRC =   TRUE;

    char* pRtf =    ( char*) dwCookie;

    *pcb = strlen ( pRtf)

    CopyMemory  (   pbBuff, pRtf,   strlen ( pRtf));

    return  (   0);

for the simple case that the buffer is big enough.
Technology Partners: We Want Your Opinion!

We value your feedback.

Take our survey and automatically be enter to win anyone of the following:
Yeti Cooler, Amazon eGift Card, and Movie eGift Card!

LVL 27

Author Comment

ID: 16604393
Hmmmm. I downloaded the project code and built the program with VS 6.0. When I open any RTF file (eg: save from WordPad or one of the license texts on my XP) it shows nothing and prints a blank page on my OKI printer.
LVL 27

Author Comment

ID: 16604412
I'll try it later on my Win2000 at home.
LVL 27

Author Comment

ID: 16783237
I'm afraid jkr's code did not really help, since I'm writing a simple ActiveX control without MFC. I have gotten so far :-

// local print procedure
int Print(HDC hPrinterDC, HWND hRTFWnd, LPPRINTDLG pd)
      int nHorizRes   = GetDeviceCaps(hPrinterDC, HORZRES),
          nVertRes    = GetDeviceCaps(hPrinterDC, VERTRES),
          nLogPixelsX = GetDeviceCaps(hPrinterDC, LOGPIXELSX),
          nLogPixelsY = GetDeviceCaps(hPrinterDC, LOGPIXELSY);
      LONG lTextLength;   // Length of document.
      LONG lTextPrinted;  // Amount of document printed.

      // Ensure the printer DC is in MM_TEXT mode.
      if(!::SetMapMode ( hPrinterDC, MM_TEXT))
            return HRESULT_FROM_WIN32(::GetLastError());

      // Rendering to the same DC we are measuring.
      ZeroMemory(&fr, sizeof(fr));
      fr.hdc = fr.hdcTarget = hPrinterDC;

      // Set up the page.
      fr.rcPage.left     = fr.rcPage.top = 0;
      fr.rcPage.right    = ::MulDiv(nHorizRes, 1440, nLogPixelsX);
      fr.rcPage.bottom   = ::MulDiv(nVertRes, 1440, nLogPixelsY);

      // Set up 1" margins all around.
      fr.rc.left   = fr.rcPage.left + 1440;  // 1440 TWIPS = 1 inch.
      fr.rc.top    = fr.rcPage.top + 1440;
      fr.rc.right  = fr.rcPage.right - 1440;
      fr.rc.bottom = fr.rcPage.bottom - 1440;

      // Default the range of text to print as the entire document.
      fr.chrg.cpMin = 0;
      fr.chrg.cpMax = -1;

      // Set up the print job (standard printing stuff here).
    DOCINFO DocInfo1;
      ZeroMemory(&DocInfo1, sizeof(DocInfo1));
      DocInfo1.cbSize       = sizeof(DOCINFO);
    DocInfo1.lpszDocName  = L"Bibdia";
    DocInfo1.lpszOutput   = NULL;
    DocInfo1.lpszDatatype = NULL;
      DocInfo1.fwType       = 0;

      // Start the document.
      if(::StartDoc(hPrinterDC, (DOCINFO*)&DocInfo1)<=0)
            return HRESULT_FROM_WIN32(::GetLastError());

      // Find out real size of the document in characters.
      GETTEXTLENGTHEX getTextLengthEx;

      getTextLengthEx.flags = GTL_PRECISE;
      getTextLengthEx.codepage = CP_ACP;

      lTextLength = SendMessage ( hRTFWnd, EM_GETTEXTLENGTHEX,
                                                      (WPARAM)&getTextLengthEx, 0);

            // Start the page.
                  return HRESULT_FROM_WIN32(::GetLastError());

            // Print as much text as can fit on a page. The return value is
            // the index of the first character on the next page. Using TRUE
            // for the wParam parameter causes the text to be printed.

            lTextPrinted = SendMessage(hRTFWnd,

            // Print last page.
                  return HRESULT_FROM_WIN32(::GetLastError());

            // If there is more text to print, adjust the range of characters
            // to start printing at the first character of the next page.
            if (lTextPrinted < lTextLength)
                  fr.chrg.cpMin = lTextPrinted;
                  fr.chrg.cpMax = -1;
      } while (lTextPrinted < lTextLength);

      // Tell the control to release cached information.
      SendMessage(hRTFWnd, EM_FORMATRANGE, 0, (LPARAM)NULL);

      if(::EndDoc (hPrinterDC)<=0)
            return HRESULT_FROM_WIN32(::GetLastError());
      return S_OK;


which works reasonably. I now have to incorporate collation, multiple copies and working out how many pages there are in order to fill in the Print Dialog box.
LVL 20

Expert Comment

ID: 16783303
Then why did you accept the answer here? :)

Featured Post

How to Use the Help Bell

Need to boost the visibility of your question for solutions? Use the Experts Exchange Help Bell to confirm priority levels and contact subject-matter experts for question attention.  Check out this how-to article for more information.

Question has a verified solution.

If you are experiencing a similar issue, please ask a related question

This article shows you how to optimize memory allocations in C++ using placement new. Applicable especially to usecases dealing with creation of large number of objects. A brief on problem: Lets take example problem for simplicity: - I have a G…
Go is an acronym of golang, is a programming language developed Google in 2007. Go is a new language that is mostly in the C family, with significant input from Pascal/Modula/Oberon family. Hence Go arisen as low-level language with fast compilation…
The goal of the video will be to teach the user the concept of local variables and scope. An example of a locally defined variable will be given as well as an explanation of what scope is in C++. The local variable and concept of scope will be relat…
The viewer will learn how to clear a vector as well as how to detect empty vectors in C++.
Suggested Courses

840 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question