|
Collecting Printing InformationDepending on the expected workflow of your application, there are a number of ways that you may wish to approach obtaining the original One method is to obtain a list of available printers, and ask the user to choose one. This is acceptable if print options mean little to the consumer of your application; simply printing is the goal. Choosing From Available Printers demonstrates this method. The second method is to ask the user to select a printer and print settings using the standard Print & Page Setup dialog boxes. This allows the user to set other options, such as page size and layout, as well as select the printer itself. In this case, you may also wish to save all print settings in addition to the printer selection. Obtaining Print settings via the Print & Page Setup Dialogs demonstrates this method. In either case, the entire point is to save and restore this printer selection from your preferences. This is demonstrated in Saving and Loading Print Settings. Choosing From Available PrintersYou can obtain a list of available printers by calling Note: The list that is returned by Listing 1: Obtaining the list of available printers OSStatus CreatePMPrintersAndPrinterNames( CFArrayRef *outPrinters, CFArrayRef *outPrinterNames ) { *outPrinters = NULL; *outPrinterNames = NULL; // Obtain the list of PMPrinters OSStatus err = PMServerCreatePrinterList( kPMServerLocal, outPrinters ); if( err == noErr ) { CFIndex i, count = CFArrayGetCount( printers ); // Create another array to hold the printer names. You may use this to create a menu or list for // the user to select a printer. CFMutableArrayRef printerNames = CFArrayCreateMutable( NULL, count, kCFTypeArrayCallBacks ); if( printerNames ) { for(i = 0; i < count; ++i) { PMPrinter printer = (PMPrinter)CFArrayGetValueAtIndex( printers, i ); CFStringRef name = PMPrinterGetName( printer ); CFArrayAppendValue( printerNames, name ); } } *outPrinterNames = printerNames; } return err; } Obtaining Print settings via the Print & Page Setup DialogsMore flexibility is available however if you allow the user to select a printer and print settings using the standard Print Dialog. By doing so you allow the user to customize all of the print settings for the print job and save these settings as a template for future print jobs. After the user prints for the first time you can simply save the print settings and use them again later. Listing 2 shows you how to display a Print Dialog and obtain the printer and print settings in order to reuse them again later. Listing 2: Saving Printer information from a Print Dialog OSStatus CreatePageFormat( PMPageFormat * outFormat ) { PMPrintSession printSession; OSStatus err; Boolean accepted; // In order to create the Page Format we're going to // ask the user to setup that page format using Page Setup. *outFormat = NULL; err = PMCreateSession( &printSession ); if( !err ) { // We could create a session, so create and default the page format. err = PMCreatePageFormat( outFormat ); if( !err ) err = PMSessionDefaultPageFormat( printSession, *outFormat ); // Present the Page Setup dialog, if the user cancels or there // is an error, we'll dispose of the created page format, // return a NULL format, and whatever error may have been returned // from PMSessionPageSetupDialog. err = PMSessionPageSetupDialog( printSession, *outFormat, &accepted ); if( err || !accepted ) { PMRelease( *outFormat ); *outFormat = NULL; } PMRelease( printSession ); } return err; } OSStatus CreatePrintSettings( PMPageFormat ioFormat, PMPrinter * outPrinter, PMPrintSettings * outSettings) { PMPrintSession printSession; OSStatus err; Boolean accepted = false; *outPrinter = NULL; *outSettings = NULL; // In order to create the Print Settings & select a printer we'll // ask the user to create their settings using the Print dialog. err = PMCreateSession( &printSession ); if( !err ) { // Validate the Page Format against the current Printer, which may update // that format. err = PMSessionValidatePageFormat( printSession, ioFormat, kPMDontWantBoolean ); // Create and default the print settings if( !err ) err = PMCreatePrintSettings( outSettings ); if( !err ) err = PMSessionDefaultPrintSettings( printSession, *outSettings ); // Present the Print dialog. if( !err ) err = PMSessionPrintDialog( printSession, *outSettings, ioFormat, &accepted ); if( !err && accepted ) { // If the user accepted, then we'll retain the printer selected // so that it survives the scope of this session. // If there is an error getting the printer, then it will // remain NULL err = PMSessionGetCurrentPrinter( printSession, outPrinter ); if( !err ) PMRetain( *outPrinter ); } else { // We got an error, or the user canceled the operation // so we'll release our settings and NULL them out. // The PMPrinter hasn't been set yet, so it will remain NULL. PMRelease( *outSettings ); *outSettings = NULL; } PMRelease( printSession ); } return err; } Saving and Loading Print SettingsThe simplest way to save a reference to the printer that your user has selected previously is via CFPreferences. The Printer ID is returned via a WARNING: Because the user can easily change their printer configuration during runtime, your code should be prepared for the situation where the printer that you are using does not exist. In this case your code should ask the user to select a new printer. You can see one way of checking validity in Validating a Printer ID Listing 3: Saving Print Settings to your Preferences OSStatus SavePrintSettings( PMPrintSession inSession, PMPrintSettings inSettings, PMPageFormat inFormat ) { CFStringRef printerID; PMPrinter printer; CFDataRef flatSettings, flatFormat; OSStatus err, tempErr; // We need the current printer from the print session before we can do anything else // If we get an error retrieving it, then we will simply return that error and do nothing else err = PMSessionGetCurrentPrinter( inSession, &printer ); if( err == noErr ) { // If PMSessionGetCurrentPrinter returns successfully, then the printer is valid // for as long as the session is valid, therefore we will assume that the printer name is valid. printerID = PMPrinterGetID( printer ); CFPreferencesSetAppValue( kPrinterID, printerID, kCFPreferencesCurrentApplication ); CFRelease( printerID ); tempErr = PMFlattenPrintSettingsToCFData( inSettings, &flatSettings ); if( tempErr == noErr ) { // If we can flatten the print settings, then save them to preferences CFPreferencesSetAppValue( kPrintSettings, flatSettings, kCFPreferencesCurrentApplication ); CFRelease( flatSettings ); } else { // If we cannot flatten print settings, then remove them from preferences CFPreferencesSetAppValue( kPrintSettings, NULL, kCFPreferencesCurrentApplication ); } tempErr = PMFlattenPageFormatToCFData( inFormat, &flatFormat ); if( tempErr == noErr ) { // If we can flatten the the page format, then save them to preferences // if we could not, then we can reuse them with another printer CFPreferencesSetAppValue( kPageFormat, flatFormat, kCFPreferencesCurrentApplication ); CFRelease( flatFormat ); } } return err; } Listing 4: Recovering Print Settings from your Preferences void CopyPrintSettings( CFStringRef * outPrinterID, PMPrintSettings * outSettings, PMPageFormat * outFormat ) { CFDataRef flatSettings, flatFormat; *outPrinterID = CFPreferencesCopyAppValue( kPrinterID, kCFPreferencesCurrentApplication ); *outSettings = NULL; *outFormat = NULL; // load the printer ID via CFPreferences if( *outPrinterID != NULL ) { flatSettings = CFPreferencesCopyAppValue( kPrintSettings, kCFPreferencesCurrentApplication ); flatFormat = CFPreferencesCopyAppValue( kPageFormat, kCFPreferencesCurrentApplication ); // Ignoring errors unflattening, as if there is an error the corresponding setting // will be NULL, indicating that it wasn't available. if( flatSettings != NULL ) { PMUnflattenPrintSettings( flatSettings, outSettings ); CFRelease( flatSettings ); } if( flatFormat != NULL ) { PMUnflattenPageFormatWithCFData( flatFormat, outFormat ); CFRelease( flatFormat ); } } } Validating a Printer IDSince the user is able to reconfigure their printing setup at anytime, even while your application is running, in order to provide a seamless experience, you will need to validate the printer that you plan to print with prior to every printing operation. In order to do this, you need to try to recreate the Listing 5: Checking the Printer ID is valid // This function demonstrates one way to validate a printer. // A more sensible method of doing this would be to attempt // to create the printer, use it on success, and ask the // user to update their settings on failure. Boolean IsValidPrinter( CFStringRef inPrinterID ) { PMPrinter printer = PMPrinterCreateFromPrinterID( inPrinterID ); Boolean valid = printer != NULL; // It is safe to pass NULL to PMRelease, as we'd just get an error // since we just want to make sure that a non-NULL printer gets // released, we can safely ignore that error. PMRelease( printer ); return valid; } Document Revision History
Posted: 2007-03-29 |
|