www.digitalmars.com         C & C++   DMDScript  

c++ - Printer output problem

reply "Heinz-Peter Nuettgens" <hnuettgens t-online.de> writes:
Hi,

there is a problem occurring, when I try to send data via fopen(..;
fwrite(.. to a stream leading to a printer port, for example "LPT1".

It's working, if everything is alright, BUT when printer isn't ready (no
paper or some other prob) or even not present, the following behaviour
occurrs: fopen takes some time, but works, and the following fwrite call
never returns and causes the application to hang.

I know that this way to output data is quite old fashioned. But how can I
avoid such a problem? I think there should be some timeout in the fwrite
routines, after which they abort and return to the calling program.

Best wishes

and condolences for what happened last tuesday
I saw it on tv but still can't believe what I saw

Heinz-Peter
Sep 18 2001
parent reply Arjan Knepper <arjan jak.nl> writes:
Hope this helps:

See MSDN KB:Windows Development
HOWTO: Print a Document
ID: Q139652



--------------------------------------------------------------------------------

The information in this article applies to:

Microsoft Win32 Application Programming Interface (API), used with:
Microsoft Windows NT, versions 3.5, 3.51
Microsoft Windows 95
Microsoft Windows CE Services version 2.0

--------------------------------------------------------------------------------



SUMMARY
This article describes each of the seven steps required to print a document
to a printer in Windows programming. Note that while Windows CE version 2.0
and later do provide printing support, you need to consider the following:

Windows CE provides no support for spooling or printing multiple copies.


Some PRINTDLG structure members have different names in Windows CE.


You need to use the PD_RETURNDEFAULTDC flag instead of
PD_RETURNDEFAULTPD_RETURNDC.





MORE INFORMATION

Obtain a Printer Device Context. To draw graphics or text on the printer
device, an application needs to obtain a printer device context. The
PrintDlg() function can be used to obtain the printer DC. PrintDlg() can
display a Print Dialog box to allow the user to select a printer, or it can
return information about the default printer. In addition to other
information about the printer, PrintDlg() returns a printer device context in
the PRINTDLG structure when PD_RETURNDC is specified as one of the flags.
This device context matches the selections the user made in the dialog box.
The GetPrinterDC function in the sample code at the end of this article
illustrates the use of PrintDlg() to obtain a printer DC.

If you want to create a printer DC without displaying the Print dialog box,
then you need to specify PD_RETURNDEFAULT | PD_RETURNDC flags as shown in the
sample code in this article. The PD_RETURNDEFAULT flag is used to retrieve
information about the default printer without displaying the Print dialog
box. PD_RETURNDC flag is used to direct PrintDlg to automatically create a
device or information context for the printer.


Setup the Abort function. An application must use the SetAbortProc function
to set the application-defined Abort function that allows a print job to be
canceled during spooling. In the AbortProc function, the abort procedure can
check the error code to see if an error occurred while printing. The error
code is zero if no error has occurred.


Use StartDoc() to Start the Print Job. The StartDoc function starts a print
job. A DOCINFO structure is initialized and passed to the StartDoc function.
It is a good idea to initialize the DOCINFO structure by filling it with
zeros. For more information, please see the following article in the
Microsoft Knowledge Base:
Q135119 PRB: StartDoc() Fails with Non-Zeroed DOCINFO
The InitDocStruct function illustrated later in this article performs this
initialization.


Call StartPage(). The StartPage function prepares the printer driver to
accept data. For example:

   StartPage( hDC );



Draw on the Device Context. Draw graphics or text on the printer device. For
example, DrawStuff() illustrates how to draw text on the printer DC.


Call EndPage(). The EndPage function informs the device that the application
has finished writing to a page. This function is typically used to direct the
device driver to advance to a new page. To print multiple pages, Steps 4, 5,
and 6 must be used for every page of the document as in this example:

   for( i = START_PAGE; i <= END_PAGE; i++)
     {
       StartPage();
       DrawStuff();
       EndPage();
     }



Call EndDoc(). The EndDoc function ends a print job. For additional
information on this topic, please refer to the Win32 SDK documentation
Overviews section.


Sample Code
The following PrintStuff() function illustrates the printing process:

   /*==============================================*/
   /* Sample code :  Typical printing process      */
   /* =============================================*/

   void PrintStuff( HWND hWndParent )
   {
       HDC        hDC;
       DOCINFO    di;

       // Need a printer DC to print to.
       hDC = GetPrinterDC();

       // Did you get a good DC?
       if( !hdc)
       {
           MessageBox(NULL, "Error creating DC", "Error",
                                       MB_APPLMODAL | MB_OK );
           return;
       }

       // You always have to use an AbortProc().
       if( SetAbortProc( hDC, AbortProc ) == SP_ERROR )
       {
           MessageBox( NULL, "Error setting up AbortProc",
                                       "Error", MB_APPLMODAL | MB_OK);
           return;
       }

       // Init the DOCINFO and start the document.
       InitDocStruct( &di, "MyDoc");
       StartDoc( hDC, &di );

       // Print one page.
       StartPage( hDC );
       DrawStuff( hDC );
       EndPage( hDC );

       // Indicate end of document.
       EndDoc( hDC );

       // Clean up
       DeleteDC( hDC );
   }

   /*===============================*/
   /* Obtain printer device context */
   /* ==============================*/
   HDC GetPrinterDC(void)
   {
       PRINTDLG pdlg;

       // Initialize the PRINTDLG structure.
       memset( &pdlg, 0, sizeof( PRINTDLG ) );
       pdlg.lStructSize = sizeof( PRINTDLG );
       // Set the flag to return printer DC.
       pdlg.Flags = PD_RETURNDEFAULT | PD_RETURNDC;

       // Invoke the printer dialog box.
       PrintDlg( &pdlg );
       // hDC member of the PRINTDLG structure contains
       // the printer DC.
       return pdlg.hDC;
   }

   /*===============================*/
   /* The Abort Procudure           */
   /* ==============================*/
   BOOL CALLBACK AbortProc( HDC hDC, int Error )
   {
       MSG   msg;
       while( PeekMessage( &msg, NULL, 0, 0, PM_REMOVE ) )
       {
           TranslateMessage( &msg );
           DispatchMessage( &msg );
       }
       return TRUE;
   }

   /*===============================*/
   /* Initialize DOCINFO structure  */
   /* ==============================*/
   void InitDocStruct( DOCINFO* di, char* docname)
   {
       // Always zero it before using it.
       memset( di, 0, sizeof( DOCINFO ) );
       // Fill in the required members.
       di->cbSize = sizeof( DOCINFO );
       di->lpszDocName = docname;
   }

   /*===============================*/
   /* Drawing on the DC             */
   /* ==============================*/
   void DrawStuff( HDC hdc)
   {
       // This is the function that does draws on a given DC.
       // You are printing text here.
       TextOut(hdc, 0,0, "Test Printing", lstrlen( "Test Printing" ) );
   }

Additional query words:

Keywords : kbcode kbGDI kbNTOS350 kbNTOS351 kbPrinting kbWinCE kbWinOS95
kbDSupport
Version : winnt:3.5,3.51
Platform : winnt
Issue type : kbhowto



Last Reviewed: July 6, 1999
 2000 Microsoft Corporation. All rights reserved. Terms of Use.



Heinz-Peter Nuettgens wrote:

 Hi,

 there is a problem occurring, when I try to send data via fopen(..;
 fwrite(.. to a stream leading to a printer port, for example "LPT1".

 It's working, if everything is alright, BUT when printer isn't ready (no
 paper or some other prob) or even not present, the following behaviour
 occurrs: fopen takes some time, but works, and the following fwrite call
 never returns and causes the application to hang.

 I know that this way to output data is quite old fashioned. But how can I
 avoid such a problem? I think there should be some timeout in the fwrite
 routines, after which they abort and return to the calling program.

 Best wishes

 and condolences for what happened last tuesday
 I saw it on tv but still can't believe what I saw

 Heinz-Peter

Sep 18 2001
parent reply "Heinz-Peter Nuettgens" <hnuettgens t-online.de> writes:
Hi Arjan,

thank you for your suggestion. But my problem isn't the output to the
printer. I am using the described way in other parts of the program, which
do it right even when a printer error occurs.

BUT I just want to do standard old fashioned stream output to the printer,
just to print a few lines of text without positioning, scaling, handling DCs
and more.

If the printer is ready, the output works like it should. But if there is
any error condition, the whole thread stops running. That shouldn't be,
imho. I think the stdlib should be able to return an error condition and
shouldn't wait for Godot to come. :-((

Heinz-Peter


"Arjan Knepper" <arjan jak.nl> schrieb im Newsbeitrag
news:3BA72CCA.B6FFCAC4 jak.nl...
 Hope this helps:

 See MSDN KB:Windows Development
 HOWTO: Print a Document
 ID: Q139652



 --------------------------------------------------------------------------

 The information in this article applies to:

 Microsoft Win32 Application Programming Interface (API), used with:
 Microsoft Windows NT, versions 3.5, 3.51
 Microsoft Windows 95
 Microsoft Windows CE Services version 2.0

 --------------------------------------------------------------------------

 SUMMARY
 This article describes each of the seven steps required to print a

 to a printer in Windows programming. Note that while Windows CE version

 and later do provide printing support, you need to consider the following:

 Windows CE provides no support for spooling or printing multiple copies.


 Some PRINTDLG structure members have different names in Windows CE.


 You need to use the PD_RETURNDEFAULTDC flag instead of
 PD_RETURNDEFAULTPD_RETURNDC.





 MORE INFORMATION

 Obtain a Printer Device Context. To draw graphics or text on the printer
 device, an application needs to obtain a printer device context. The
 PrintDlg() function can be used to obtain the printer DC. PrintDlg() can
 display a Print Dialog box to allow the user to select a printer, or it

 return information about the default printer. In addition to other
 information about the printer, PrintDlg() returns a printer device context

 the PRINTDLG structure when PD_RETURNDC is specified as one of the flags.
 This device context matches the selections the user made in the dialog

 The GetPrinterDC function in the sample code at the end of this article
 illustrates the use of PrintDlg() to obtain a printer DC.

 If you want to create a printer DC without displaying the Print dialog

 then you need to specify PD_RETURNDEFAULT | PD_RETURNDC flags as shown in

 sample code in this article. The PD_RETURNDEFAULT flag is used to retrieve
 information about the default printer without displaying the Print dialog
 box. PD_RETURNDC flag is used to direct PrintDlg to automatically create a
 device or information context for the printer.


 Setup the Abort function. An application must use the SetAbortProc

 to set the application-defined Abort function that allows a print job to

 canceled during spooling. In the AbortProc function, the abort procedure

 check the error code to see if an error occurred while printing. The error
 code is zero if no error has occurred.


 Use StartDoc() to Start the Print Job. The StartDoc function starts a

 job. A DOCINFO structure is initialized and passed to the StartDoc

 It is a good idea to initialize the DOCINFO structure by filling it with
 zeros. For more information, please see the following article in the
 Microsoft Knowledge Base:
 Q135119 PRB: StartDoc() Fails with Non-Zeroed DOCINFO
 The InitDocStruct function illustrated later in this article performs this
 initialization.


 Call StartPage(). The StartPage function prepares the printer driver to
 accept data. For example:

    StartPage( hDC );



 Draw on the Device Context. Draw graphics or text on the printer device.

 example, DrawStuff() illustrates how to draw text on the printer DC.


 Call EndPage(). The EndPage function informs the device that the

 has finished writing to a page. This function is typically used to direct

 device driver to advance to a new page. To print multiple pages, Steps 4,

 and 6 must be used for every page of the document as in this example:

    for( i = START_PAGE; i <= END_PAGE; i++)
      {
        StartPage();
        DrawStuff();
        EndPage();
      }



 Call EndDoc(). The EndDoc function ends a print job. For additional
 information on this topic, please refer to the Win32 SDK documentation
 Overviews section.


 Sample Code
 The following PrintStuff() function illustrates the printing process:

    /*==============================================*/
    /* Sample code :  Typical printing process      */
    /* =============================================*/

    void PrintStuff( HWND hWndParent )
    {
        HDC        hDC;
        DOCINFO    di;

        // Need a printer DC to print to.
        hDC = GetPrinterDC();

        // Did you get a good DC?
        if( !hdc)
        {
            MessageBox(NULL, "Error creating DC", "Error",
                                        MB_APPLMODAL | MB_OK );
            return;
        }

        // You always have to use an AbortProc().
        if( SetAbortProc( hDC, AbortProc ) == SP_ERROR )
        {
            MessageBox( NULL, "Error setting up AbortProc",
                                        "Error", MB_APPLMODAL | MB_OK);
            return;
        }

        // Init the DOCINFO and start the document.
        InitDocStruct( &di, "MyDoc");
        StartDoc( hDC, &di );

        // Print one page.
        StartPage( hDC );
        DrawStuff( hDC );
        EndPage( hDC );

        // Indicate end of document.
        EndDoc( hDC );

        // Clean up
        DeleteDC( hDC );
    }

    /*===============================*/
    /* Obtain printer device context */
    /* ==============================*/
    HDC GetPrinterDC(void)
    {
        PRINTDLG pdlg;

        // Initialize the PRINTDLG structure.
        memset( &pdlg, 0, sizeof( PRINTDLG ) );
        pdlg.lStructSize = sizeof( PRINTDLG );
        // Set the flag to return printer DC.
        pdlg.Flags = PD_RETURNDEFAULT | PD_RETURNDC;

        // Invoke the printer dialog box.
        PrintDlg( &pdlg );
        // hDC member of the PRINTDLG structure contains
        // the printer DC.
        return pdlg.hDC;
    }

    /*===============================*/
    /* The Abort Procudure           */
    /* ==============================*/
    BOOL CALLBACK AbortProc( HDC hDC, int Error )
    {
        MSG   msg;
        while( PeekMessage( &msg, NULL, 0, 0, PM_REMOVE ) )
        {
            TranslateMessage( &msg );
            DispatchMessage( &msg );
        }
        return TRUE;
    }

    /*===============================*/
    /* Initialize DOCINFO structure  */
    /* ==============================*/
    void InitDocStruct( DOCINFO* di, char* docname)
    {
        // Always zero it before using it.
        memset( di, 0, sizeof( DOCINFO ) );
        // Fill in the required members.
        di->cbSize = sizeof( DOCINFO );
        di->lpszDocName = docname;
    }

    /*===============================*/
    /* Drawing on the DC             */
    /* ==============================*/
    void DrawStuff( HDC hdc)
    {
        // This is the function that does draws on a given DC.
        // You are printing text here.
        TextOut(hdc, 0,0, "Test Printing", lstrlen( "Test Printing" ) );
    }

 Additional query words:

 Keywords : kbcode kbGDI kbNTOS350 kbNTOS351 kbPrinting kbWinCE kbWinOS95
 kbDSupport
 Version : winnt:3.5,3.51
 Platform : winnt
 Issue type : kbhowto



 Last Reviewed: July 6, 1999
  2000 Microsoft Corporation. All rights reserved. Terms of Use.



 Heinz-Peter Nuettgens wrote:

 Hi,

 there is a problem occurring, when I try to send data via fopen(..;
 fwrite(.. to a stream leading to a printer port, for example "LPT1".

 It's working, if everything is alright, BUT when printer isn't ready (no
 paper or some other prob) or even not present, the following behaviour
 occurrs: fopen takes some time, but works, and the following fwrite call
 never returns and causes the application to hang.

 I know that this way to output data is quite old fashioned. But how can


 avoid such a problem? I think there should be some timeout in the fwrite
 routines, after which they abort and return to the calling program.

 Best wishes

 and condolences for what happened last tuesday
 I saw it on tv but still can't believe what I saw

 Heinz-Peter


Sep 18 2001
next sibling parent "Walter" <walter digitalmars.com> writes:
I'm afraid the stdprn is only suitable for primitive writes to the printer.
More advanced control over it means you'll need to write some code...

Heinz-Peter Nuettgens wrote in message <9o7sjd$2ir4$1 digitaldaemon.com>...
Hi Arjan,

thank you for your suggestion. But my problem isn't the output to the
printer. I am using the described way in other parts of the program, which
do it right even when a printer error occurs.

BUT I just want to do standard old fashioned stream output to the printer,
just to print a few lines of text without positioning, scaling, handling

and more.

If the printer is ready, the output works like it should. But if there is
any error condition, the whole thread stops running. That shouldn't be,
imho. I think the stdlib should be able to return an error condition and
shouldn't wait for Godot to come. :-((

Heinz-Peter


"Arjan Knepper" <arjan jak.nl> schrieb im Newsbeitrag
news:3BA72CCA.B6FFCAC4 jak.nl...
 Hope this helps:

 See MSDN KB:Windows Development
 HOWTO: Print a Document
 ID: Q139652



 -------------------------------------------------------------------------


------
 The information in this article applies to:

 Microsoft Win32 Application Programming Interface (API), used with:
 Microsoft Windows NT, versions 3.5, 3.51
 Microsoft Windows 95
 Microsoft Windows CE Services version 2.0

 -------------------------------------------------------------------------


------
 SUMMARY
 This article describes each of the seven steps required to print a

 to a printer in Windows programming. Note that while Windows CE version

 and later do provide printing support, you need to consider the


 Windows CE provides no support for spooling or printing multiple copies.


 Some PRINTDLG structure members have different names in Windows CE.


 You need to use the PD_RETURNDEFAULTDC flag instead of
 PD_RETURNDEFAULTPD_RETURNDC.





 MORE INFORMATION

 Obtain a Printer Device Context. To draw graphics or text on the printer
 device, an application needs to obtain a printer device context. The
 PrintDlg() function can be used to obtain the printer DC. PrintDlg() can
 display a Print Dialog box to allow the user to select a printer, or it

 return information about the default printer. In addition to other
 information about the printer, PrintDlg() returns a printer device


in
 the PRINTDLG structure when PD_RETURNDC is specified as one of the flags.
 This device context matches the selections the user made in the dialog

 The GetPrinterDC function in the sample code at the end of this article
 illustrates the use of PrintDlg() to obtain a printer DC.

 If you want to create a printer DC without displaying the Print dialog

 then you need to specify PD_RETURNDEFAULT | PD_RETURNDC flags as shown in

 sample code in this article. The PD_RETURNDEFAULT flag is used to


 information about the default printer without displaying the Print dialog
 box. PD_RETURNDC flag is used to direct PrintDlg to automatically create


 device or information context for the printer.


 Setup the Abort function. An application must use the SetAbortProc

 to set the application-defined Abort function that allows a print job to

 canceled during spooling. In the AbortProc function, the abort procedure

 check the error code to see if an error occurred while printing. The


 code is zero if no error has occurred.


 Use StartDoc() to Start the Print Job. The StartDoc function starts a

 job. A DOCINFO structure is initialized and passed to the StartDoc

 It is a good idea to initialize the DOCINFO structure by filling it with
 zeros. For more information, please see the following article in the
 Microsoft Knowledge Base:
 Q135119 PRB: StartDoc() Fails with Non-Zeroed DOCINFO
 The InitDocStruct function illustrated later in this article performs


 initialization.


 Call StartPage(). The StartPage function prepares the printer driver to
 accept data. For example:

    StartPage( hDC );



 Draw on the Device Context. Draw graphics or text on the printer device.

 example, DrawStuff() illustrates how to draw text on the printer DC.


 Call EndPage(). The EndPage function informs the device that the

 has finished writing to a page. This function is typically used to direct

 device driver to advance to a new page. To print multiple pages, Steps 4,

 and 6 must be used for every page of the document as in this example:

    for( i = START_PAGE; i <= END_PAGE; i++)
      {
        StartPage();
        DrawStuff();
        EndPage();
      }



 Call EndDoc(). The EndDoc function ends a print job. For additional
 information on this topic, please refer to the Win32 SDK documentation
 Overviews section.


 Sample Code
 The following PrintStuff() function illustrates the printing process:

    /*==============================================*/
    /* Sample code :  Typical printing process      */
    /* =============================================*/

    void PrintStuff( HWND hWndParent )
    {
        HDC        hDC;
        DOCINFO    di;

        // Need a printer DC to print to.
        hDC = GetPrinterDC();

        // Did you get a good DC?
        if( !hdc)
        {
            MessageBox(NULL, "Error creating DC", "Error",
                                        MB_APPLMODAL | MB_OK );
            return;
        }

        // You always have to use an AbortProc().
        if( SetAbortProc( hDC, AbortProc ) == SP_ERROR )
        {
            MessageBox( NULL, "Error setting up AbortProc",
                                        "Error", MB_APPLMODAL | MB_OK);
            return;
        }

        // Init the DOCINFO and start the document.
        InitDocStruct( &di, "MyDoc");
        StartDoc( hDC, &di );

        // Print one page.
        StartPage( hDC );
        DrawStuff( hDC );
        EndPage( hDC );

        // Indicate end of document.
        EndDoc( hDC );

        // Clean up
        DeleteDC( hDC );
    }

    /*===============================*/
    /* Obtain printer device context */
    /* ==============================*/
    HDC GetPrinterDC(void)
    {
        PRINTDLG pdlg;

        // Initialize the PRINTDLG structure.
        memset( &pdlg, 0, sizeof( PRINTDLG ) );
        pdlg.lStructSize = sizeof( PRINTDLG );
        // Set the flag to return printer DC.
        pdlg.Flags = PD_RETURNDEFAULT | PD_RETURNDC;

        // Invoke the printer dialog box.
        PrintDlg( &pdlg );
        // hDC member of the PRINTDLG structure contains
        // the printer DC.
        return pdlg.hDC;
    }

    /*===============================*/
    /* The Abort Procudure           */
    /* ==============================*/
    BOOL CALLBACK AbortProc( HDC hDC, int Error )
    {
        MSG   msg;
        while( PeekMessage( &msg, NULL, 0, 0, PM_REMOVE ) )
        {
            TranslateMessage( &msg );
            DispatchMessage( &msg );
        }
        return TRUE;
    }

    /*===============================*/
    /* Initialize DOCINFO structure  */
    /* ==============================*/
    void InitDocStruct( DOCINFO* di, char* docname)
    {
        // Always zero it before using it.
        memset( di, 0, sizeof( DOCINFO ) );
        // Fill in the required members.
        di->cbSize = sizeof( DOCINFO );
        di->lpszDocName = docname;
    }

    /*===============================*/
    /* Drawing on the DC             */
    /* ==============================*/
    void DrawStuff( HDC hdc)
    {
        // This is the function that does draws on a given DC.
        // You are printing text here.
        TextOut(hdc, 0,0, "Test Printing", lstrlen( "Test Printing" ) );
    }

 Additional query words:

 Keywords : kbcode kbGDI kbNTOS350 kbNTOS351 kbPrinting kbWinCE kbWinOS95
 kbDSupport
 Version : winnt:3.5,3.51
 Platform : winnt
 Issue type : kbhowto



 Last Reviewed: July 6, 1999
  2000 Microsoft Corporation. All rights reserved. Terms of Use.



 Heinz-Peter Nuettgens wrote:

 Hi,

 there is a problem occurring, when I try to send data via fopen(..;
 fwrite(.. to a stream leading to a printer port, for example "LPT1".

 It's working, if everything is alright, BUT when printer isn't ready



 paper or some other prob) or even not present, the following behaviour
 occurrs: fopen takes some time, but works, and the following fwrite



 never returns and causes the application to hang.

 I know that this way to output data is quite old fashioned. But how can


 avoid such a problem? I think there should be some timeout in the



 routines, after which they abort and return to the calling program.

 Best wishes

 and condolences for what happened last tuesday
 I saw it on tv but still can't believe what I saw

 Heinz-Peter



Sep 18 2001
prev sibling parent Cesar Rabak <csrabak uol.com.br> writes:
Heinz-Peter Nuettgens wrote:
 
 Hi Arjan,
 
 thank you for your suggestion. But my problem isn't the output to the
 printer. I am using the described way in other parts of the program, which
 do it right even when a printer error occurs.
 
 BUT I just want to do standard old fashioned stream output to the printer,
 just to print a few lines of text without positioning, scaling, handling DCs
 and more.
 
 If the printer is ready, the output works like it should. But if there is
 any error condition, the whole thread stops running. That shouldn't be,
 imho. I think the stdlib should be able to return an error condition and
 shouldn't wait for Godot to come. :-((
 

You've been stuck by a maze of paradigm clashes... Standard C (and it library) does not offer any portable primitive to ascertain the status of the printer. In the old days, programming in DOS mode, to be able to inform to the user such additional information we needed to resort to some platfform specific calls (something related to the BIOS), and IIRC, at least Microsoft had a _bios_printer call which allowed to these raw checks. This obviously will not work if you're using the Win32 API. If you think the call to fprintf are OK, I would suggest you browse the Win API around the terrain Jan pointed out and create a simple wrapper function to do printer_check or similar and give a better behaviour to your application. Perhaps, you could inspire yourself in the functionality ot _bios_printer call. HTH Cesar
Sep 22 2001