Developer --> Technical Publications

     


Using Session Functions

/*------------------------------------------------------------------------------

    This sample code is the Carbon equivalent of the Classic print loop
    documented in Tech Note 1092 "A Print Loop That Cares ...".  This code
    illustrates the use of the Carbon Printing Manager's session APIs.

    You may incorporate this sample code into your applications without
    restriction, though the sample code has been provided "AS IS" and the
    responsibility for its operation is 100% yours.  However, what you are
    not permitted to do is to redistribute the source as "Apple Sample Code"
    after having made changes. If you're going to re-distribute the source,
    we require that you make it clear in the source that the code was
    descended from Apple Sample Code, but that you've made changes.

    Copyright © 1998-1999 Apple Computer, Inc., All Rights Reserved
	
    Change History:
        17 Oct 99   pd  Updated for Carbon 1.1 SDK to use session APIs
        13 Sep 99   pd  Updated for Carbon 1.0 SDK
        11 Apr 99   dk  Original version for Developer Preview 1

------------------------------------------------------------------------------*/

#define TARGET_API_MAC_CARBON 1
/*------------------------------------------------------------------------------
    Includes
------------------------------------------------------------------------------*/
#include <Quickdraw.h>
#include <Fonts.h>
#include <Resources.h>
#include <PMApplication.h>
#include <NumberFormatting.h>   // for NumToString


/*------------------------------------------------------------------------------
    Globals
------------------------------------------------------------------------------*/
short   gAppResFile = 0;        // application's resource file
Handle  gflatPageFormat = nil;  // used in FlattenAndSavePageFormat


/*------------------------------------------------------------------------------
    Prototypes
------------------------------------------------------------------------------*/
int         main(void);
OSStatus    DoPageSetupDialog(PMPrintSession printSession, PMPageFormat* pageFormat);
OSStatus    DoPrintDialog(PMPrintSession printSession, PMPageFormat pageFormat,
                PMPrintSettings* printSettings);
void        DoPrintLoop(PMPrintSession printSession, PMPageFormat pageFormat,
                PMPrintSettings printSettings);
OSStatus    FlattenAndSavePageFormat(PMPageFormat pageFormat);
OSStatus    LoadAndUnflattenPageFormat(PMPageFormat* pageFormat);
UInt32      DetermineNumberOfPagesInDoc(PMRect rect);
void        DrawPage(PMRect pageRect, UInt32 pageNumber);
pascal void pIdleProc(void);
void        PostPrintingErrors(OSStatus status);


/*------------------------------------------------------------------------------
    Function: main
	
    Parameters:
        <none>
	

    Description:
        Uses PMCreateSession/PMRelease instead of PMBegin/PMEnd.  Note that the two
        printing objects, PMPageSetup and PMPrintSettings are valid outside the
        printing session.  This is not the case with PMBegin/PMEnd.  Note also
        that no nesting of printing sessions is allowed for Carbon applications
        running under MacOS 8 or 9.
        In this sample code, we show where an old print record could be read in and
        converted.  This is followed by displaying the Page Setup dialog, then the
        Print dialog, and finally we print the page(s) of the document.
	
------------------------------------------------------------------------------*/
int main(void)
{
    OSStatus        status = noErr;
    GrafPtr         oldPort;
    PMPageFormat    pageFormat = kPMNoPageFormat;
    PMPrintSettings printSettings = kPMNoPrintSettings;
    PMPrintSession  printSession;
    Handle          gOldPrintRecord = nil;  // placeholder for old print record

    //  Standard Toolbox initialization.
    InitCursor();
	
    //  Save the old QD grafport.
    GetPort(&oldPort);
	
    //  Save the current resource file so that it can be used in pIdleProc.
    gAppResFile = CurResFile();
	
    //  Initialize the printing manager and create a printing session.
    status = PMCreateSession(&printSession);
    if (status != noErr) return 0;  // pointless to continue if PMCreateSession fails
	
    //  If your application has an old print record, it can be converted into new
    //  PMPageFormat and PMPrintSettings objects.  In this sample code, we skip this
    //  step.
    if (gOldPrintRecord != nil)
        status = PMSessionConvertOldPrintRecord(printSession, gOldPrintRecord,
                    &printSettings, &pageFormat);


    //  Display the Page Setup dialog.
    if (status == noErr)
        status = DoPageSetupDialog(printSession, &pageFormat);
	
    //  Display the Print dialog.
    if (status == noErr)
        status = DoPrintDialog(printSession, pageFormat, &printSettings);
	
    //  Execute the print loop.
    if (status == noErr)
        DoPrintLoop(printSession, pageFormat, printSettings);
			
    //  Release the PageFormat and PrintSettings objects.  PMRelease decrements the
    //  ref count of the allocated objects.  We let the Printing Manager decide when
    //  to release the allocated memory.
    if (pageFormat != kPMNoPageFormat)
        (void)PMRelease(&pageFormat);
    if (printSettings != kPMNoPrintSettings)
        (void)PMRelease(&printSettings);
	
    //  Terminate the current printing session. 
    (void)PMRelease(&printSession);
	
    //  Restore the original QD grafport.
    SetPort(oldPort);
	
    return 0;
	
}   // main


/*------------------------------------------------------------------------------
    Function: DoPageSetupDialog
	
    Parameters:
        printSession    -   current printing session
        pageFormat      -   a PageFormat object addr
	
    Description:
        If the caller passes in an empty PageFormat object, create a new one,
        otherwise validate the one provided by the caller.
        Invokes the Page Setup dialog and checks for Cancel.
        Flattens the PageFormat object so it can be saved with the document.
        Note that the PageFormat object is modified by this function.
	
------------------------------------------------------------------------------*/
OSStatus DoPageSetupDialog(PMPrintSession printSession, PMPageFormat* pageFormat)
{
    OSStatus    status;
    Boolean     accepted;
	
    //  Set up a valid PageFormat object.
    if (*pageFormat == kPMNoPageFormat)
    {
        status = PMCreatePageFormat(pageFormat);
		
        //  Note that PMPageFormat is not session-specific, but calling
        //  PMSessionDefaultPageFormat assigns values specific to the printer
        //  associated with the current printing session.
        if ((status == noErr) && (*pageFormat != kPMNoPageFormat))
            status = PMSessionDefaultPageFormat(printSession, *pageFormat);
    }
    else
        status = PMSessionValidatePageFormat(printSession, *pageFormat,
                    kPMDontWantBoolean);

    //  Display the Page Setup dialog.
    if (status == noErr)
    {
        status = PMSessionPageSetupDialog(printSession, *pageFormat, &accepted);
        if (!accepted)
            status = kPMCancel; // user clicked Cancel button
    }   
				
    //  If the user did not cancel, flatten and save the PageFormat object
    //  with our document.
    if (status == noErr)
        status = FlattenAndSavePageFormat(*pageFormat);

    return status;
	
}   //  DoPageSetupDialog
/*------------------------------------------------------------------------------
    Function: DoPrintDialog
		
    Parameters:
        printSession    -   current printing session
        pageFormat      -   a PageFormat object addr
        printSettings   -   a PrintSettings object addr
			
    Description:
        If the caller passes an empty PrintSettings object, create a new one,
        otherwise validate the one provided by the caller.
        Invokes the Print dialog and checks for Cancel.
        Note that the PrintSettings object is modified by this function.
		
------------------------------------------------------------------------------*/
OSStatus DoPrintDialog(PMPrintSession printSession, PMPageFormat pageFormat,
                PMPrintSettings* printSettings)
{
    OSStatus    status;
    Boolean     accepted;
    UInt32      minPage = 1,
                maxPage = 9999;
	
    //  In this sample code the caller provides a valid PageFormat reference but in
    //  your application you may want to load and unflatten the PageFormat object
    //  that was saved at PageSetup time.  See LoadAndUnflattenPageFormat below.
	
    //  Set up a valid PrintSettings object.
    if (*printSettings == kPMNoPrintSettings)
    {
        status = PMCreatePrintSettings(printSettings);

        //  Note that PMPrintSettings is not session-specific, but calling
        //  PMSessionDefaultPrintSettings assigns values specific to the printer
        //  associated with the current printing session.
        if ((status == noErr) && (*printSettings != kPMNoPrintSettings))
            status = PMSessionDefaultPrintSettings(printSession, *printSettings);
    }
    else
        status = PMSessionValidatePrintSettings(printSession, *printSettings,
                    kPMDontWantBoolean);
    //  Set a valid page range before displaying the Print dialog
    if (status == noErr)
        status = PMSetPageRange(*printSettings, minPage, maxPage);

    //  Display the Print dialog.
    if (status == noErr)
    {
        status = PMSessionPrintDialog(printSession, *printSettings, pageFormat,
                    &accepted);
        if (!accepted)
            status = kPMCancel; // user clicked Cancel button
    }
		
    return status;
	
}   //  DoPrintDialog

/*------------------------------------------------------------------------------
    Function: DoPrintLoop
	
    Parameters:
        printSession    -   current printing session
        pageFormat      -   a PageFormat object addr
        printSettings   -   a PrintSettings object addr
	
    Description:
        Assumes the caller provides validated PageFormat and PrintSettings
        objects.
        Calculates a valid page range and prints each page by calling DrawPage.

------------------------------------------------------------------------------*/
void    DoPrintLoop(PMPrintSession printSession, PMPageFormat pageFormat,
            PMPrintSettings printSettings)
{
    OSStatus    status,
                printError;
    PMRect      pageRect;
    UInt32      realNumberOfPagesinDoc,
                pageNumber,
                firstPage,
                lastPage;
    //  PMGetAdjustedPaperRect returns the paper size taking into account rotation,
    //  resolution, and scaling settings.  Note this is the paper size selected
    //  the Page Setup dialog.  It is not guaranteed to be the same as the paper
    //  size selected in the Print dialog on Mac OS X.
    status = PMGetAdjustedPaperRect(pageFormat, &pageRect);
	
    //  PMGetAdjustedPageRect returns the page size taking into account rotation,
    //  resolution, and scaling settings.  Note this is the imageable area of the
    //  paper selected in the Page Setup dialog.
    //  DetermineNumberOfPagesInDoc returns the number of pages required to print
    //  the document.
    if (status == noErr)
    {
        status = PMGetAdjustedPageRect(pageFormat, &pageRect);
        if (status == noErr)
            realNumberOfPagesinDoc = DetermineNumberOfPagesInDoc(pageRect);
    }

    //  Get the user's selection for first and last pages
    if (status == noErr)
    {
        status = PMGetFirstPage(printSettings, &firstPage);
        if (status == noErr)
            status = PMGetLastPage(printSettings, &lastPage);
    }

    //  Check that the selected page range does not go beyond the actual
    //  number of pages in the document.
    if (status == noErr)
    {
        if (realNumberOfPagesinDoc < lastPage)
            lastPage = realNumberOfPagesinDoc;
    }

    //  Tell the Printing Manager to call our idle proc.
    if (status == noErr)
        status = PMSessionSetIdleProc(printSession, NewPMIdleProc(pIdleProc));

    //  NOTE:  We don't have to worry about the number of copies.  The Printing
    //  Manager handles this.  So we just iterate through the document from the
    //  first page to be printed, to the last.
    if (status == noErr)
    {
        //  Establish a graphics context for drawing the document's pages.
        //  Although it's not used in this sample code, PMGetGrafPtr can be called
        //  get the QD grafport.
        status = PMSessionBeginDocument(printSession, printSettings, pageFormat);
        if (status == noErr)
        {
            //  Print all the pages in the document.  Note that we spool all pages
            //  and rely upon the Printing Manager to print the correct page range.
            //  In this sample code we assume the total number of pages in the
            //  document is equal to "lastPage".
            pageNumber = 1;
            while ((pageNumber <= lastPage) && (PMSessionError() == noErr))
            {
                //  NOTE:  We don't have to deal with the old Printing Manager's
                //  128-page boundary limit anymore.
				
                //  Set up a page for printing.
                status = PMSessionBeginPage(printSession, pageFormat, &pageRect);
                if (status != noErr)
                    break;
					
                //  Draw the page.
                DrawPage(pageRect, pageNumber);
				
                //  Close the page.
                status = PMSessionEndPage(printSession);
                if (status != noErr)
                    break;
					
                //  And loop.
                pageNumber++;
            }
			
            // Close the printing port
            (void)PMSessionEndDocument(printSession);
        }
    }


    //  Only report a printing error once we have completed the print loop. This
    //  ensures that every PMSessionBegin... call is followed by a matching
    //  PMSessionEnd... call, so the Printing Manager can release all temporary
    //  memory and close properly.
    printError = PMSessionError();
    if (printError != noErr)
        PostPrintingErrors(printError);
		
}   //  DoPrintLoop

/*------------------------------------------------------------------------------
    Function: FlattenAndSavePageFormat
	
    Parameters:
        pageFormat  -   a PageFormat object
	
    Description:
        Flattens a PageFormat object so it can be saved with the document.
        Assumes caller passes a validated PageFormat object.
		
------------------------------------------------------------------------------*/
OSStatus FlattenAndSavePageFormat(PMPageFormat pageFormat)
{
    OSStatusstatus;
    Handle  flatFormatHandle = nil;
	
    //  Flatten the PageFormat object to memory.
    status = PMFlattenPageFormat(pageFormat, &flatFormatHandle);
	
    //  Write the PageFormat data to file.
    //  In this sample code we simply copy it to a global.
    gflatPageFormat = flatFormatHandle;

    return status;
}   //  FlattenAndSavePageFormat

/*------------------------------------------------------------------------------
    Function: LoadAndUnflattenPageFormat
	
    Parameters:
        pageFormat  -   a PageFormat object read from a document file
    Description:
        Gets flattened PageFormat data from the document and returns a PageFormat
        object. The function is not called in this sample code but your application
        will need to retrieve PageFormat data saved with documents.
		
------------------------------------------------------------------------------*/
OSStatus LoadAndUnflattenPageFormat(PMPageFormat* pageFormat)
{
    OSStatus    status;
    Handle      flatFormatHandle = nil;

    //  Read the PageFormat flattened data from file.
    //  In this sample code we simply copy it from a global.
    flatFormatHandle = gflatPageFormat;

    //  Convert the PageFormat flattened data into a PageFormat object.
    status = PMUnflattenPageFormat(flatFormatHandle, pageFormat);
	
    return status;
}   //  LoadAndUnflattenPageFormat


/*------------------------------------------------------------------------------
    Function: DetermineNumberOfPagesInDoc
	
    Parameters:
        pageRect    -   size of the document, from PMGetAdjustedPageRect
	
    Description:
        Compares the size of the document with the number of pages in the
        PageFormat object to calculate the number of pages required to print
        the document.
		
------------------------------------------------------------------------------*/
UInt32 DetermineNumberOfPagesInDoc(PMRect pageRect) 
{
#pragma unused (pageRect)
    //  In this sample code we simply return a hard coded number.
    return 1;
}   //  DetermineNumberOfPagesinDoc

/*------------------------------------------------------------------------------
    Function: DrawPage
	
    Parameters:
        pageRect    -   size of the page we're drawing
        pageNumber  -   the logical page number in the document
	
    Description:
        Draws the contents of a single page.
		
------------------------------------------------------------------------------*/
void DrawPage(PMRect pageRect, UInt32 pageNumber)
{
    Str255      pageString;

    //  In this sample code we simply write the word "Page" followed by the
    //  page number onto each page.

    MoveTo((short)(pageRect.left + (pageRect.right - pageRect.left) / 2),
        (short)(pageRect.bottom - (pageRect.bottom - pageRect.top) / 2));
    DrawString("\pPage ");
    NumToString((long)pageNumber, pageString);
    DrawString(pageString);
}   //  DrawPage


/*------------------------------------------------------------------------------
    Function: pIdleProc
	
    Parameters:
        <none>
	
    Description:
        This routine is called by the Printing Manager while the print job is
        being spooled (background printing) or printed (foreground printing).
        Since most print drivers display their own progress dialog boxes, there is
        little need for applications to use the idle proc for progress reporting.
		
------------------------------------------------------------------------------*/
pascal void pIdleProc(void)
{
    //  Save the current resource file.
    short   curRes = CurResFile();

    //  Set the application's resource file.
    UseResFile(gAppResFile);
	
    //  Do something useful.
	
    //  Restore the resource file.
    UseResFile(curRes);
	
}   //  pIdleProc


/*------------------------------------------------------------------------------
    Function: PostPrintingErrors
	
    Parameters:
        status  -   error code
	
    Description:
        This is where we could post an alert to report any problem encountered
        by the Printing Manager.
		
------------------------------------------------------------------------------*/
void PostPrintingErrors(OSStatus status)
{
#pragma unused (status)
}   //  PostPrintingErrors

© 2000 Apple Computer, Inc. (Last Updated 03 July 2000)