Robert, Is there any way I can get this routine working in a non-appearance compliant application? My MacWise application is not appearance compliant but does use "Tlbx Appearance.Incl" When I try to paste the "'------------CarbonPrinting.incl--------------" section of the code into my project, it fails trying to use the GetWindowProperty function. Error: Functions must be defined before using... in file MacWise:CARBONPRINTING.INCL at line 40 in MYGETDOCUMENTNUMPAGESINDOC •err = fn GetWindowProperty•( w, _kMyAppSignature, _kMyPageFormatProperty, ¬ Rich Love - Carnation Software MacWise Terminal emulation for Macintosh richlove@... http://www.carnation-software.com 512 858-9234 On Jan 7, 2004, at 8:40 PM, Robert Purves wrote: > >>> could post this demo if there is interest. > >> I'm interested. > >> I'm quite sure there is absolutely no interest, that's probably why >> many of us are awaiting eagerly for the demo now ;-) > >> Consider this interest * 10. > >> YES! > > Ah, you silver-tongued devils, you have charmed me into it... > Here is the printing demo, fresh from my keyboard and therefore, as > experience teaches us, likely to have a bug or two. > > Robert P. > > '---------------------- > '~'A > ' Runtime : Rntm Appearance.Incl > ' CPU : Carbon > '~'B > /* > A multi-document Carbon printing demo based on Apple documentation > > - Page Setup dialog (sheet in OS X) > - Print dialog (sheet in OS X) > - saving the page format with a document > - obtaining page format from a saved document file. > > Works in MacOS 8/9 and OS X. > > Makes no use of FB runtime printing commands > (def page, def lPrint, route _toPrinter... are not sheet-compatible). > > SetWindowProperty and GetWindowProperty are used in many places > to attach arbitrary data to windows. > > There are no global variables, and so this code should adapt easily. > (Some routines make use of 'static' variables for their > internal use, which have to be declared as FB globals). > > The section delimited thus: > '------------CarbonPrinting.incl-------------- > .. > .. > '------------CarbonPrinting.incl-------------- > could be saved as a separate file for inclusion in your project. > > Robert P. 8 January 2004 > */ > > _kMyAppSignature = _"MyAp" > _kMyDocType = _"TEXT" > > _kMyPageFormatResType = _"PagF" > _kMyPageFormatResID = 128 > > // window property codes (for Set/GetWindowProperty) > _kMyPageFormatProperty = _kMyPageFormatResType > _kMyPrintSettingsProperty = _"PrtS" > _kMyDocContentProperty = _"Cntt" > > // Carbon PM error codes > _kPMNoDefaultPrinter = -30872 > _kPMNotImplemented = -30873 > > toolbox fn CopyWindowTitleAsCFString( WindowRef inWindow, ¬ > CFStringRef * outString ) = OSStatus > toolbox fn ActiveNonFloatingWindow() = WindowRef > > end globals > > > // customize to suit... > local mode > local fn MyGetDocumentNumPagesInDoc( w as WindowRef ) > '~'1 > dim as PMPageFormat @ pageFormat > dim as PMRect pageRect > dim as UInt32 numPages > dim as OSStatus err, ignore > > numPages = 0 > err = fn GetWindowProperty( w, _kMyAppSignature, > _kMyPageFormatProperty, ¬ > sizeof( PMPageFormat ), #_nil, @pageFormat ) > long if ( err == _noErr ) > err = fn PMGetAdjustedPageRect( pageFormat, @pageRect ) > long if ( err == _noErr ) > // whatever you calculate from the pageRect and doc contents... > numPages = 1 > end if > end if > > end fn = numPages > > > // customize to suit... > local mode > local fn MyPageDrawProc( w as WindowRef, pageRect as ^Rect, pageNumber > as UInt32 ) > '~'1 > dim as Str255 content > dim as OSStatus ignore > > print %(5,15) "Adjusted page rect is"; > print pageRect.left "," pageRect.top " - " pageRect.right "," > pageRect.bottom > print "The FB window number of this document is" usr WPtr2WNum( w ) > > ignore = fn GetWindowProperty( w, _kMyAppSignature, > _kMyDocContentProperty, ¬ > sizeof( Str255 ), #0, @content ) > print content // the text data > > end fn = _noErr > > > // customize to suit... > local mode > local fn ReportPMError( err as OSStatus ) > '~'1 > dim as Str255 msg > dim as OSErr ignore > > select err > case _kPMNoDefaultPrinter > msg = "No default printer specified" > case else > msg = "Printing error" > end select > ignore = fn StandardAlert( _kAlertNoteAlert, "Error code " + str$( err > ), msg, 0, #0 ) > end fn > > > > '------------CarbonPrinting.incl-------------- > local mode > local fn MyHandleToResource( dataH as handle, resType as OSType, ¬ > resID as short, resName as Str255, resFile as short ) > '~'1 > dim as Handle rH, @ copyDataH > dim as short curResFile > dim as OSErr err > > err = _noErr > curResFile = fn CurResFile > UseResFile( resFile ) > > SetResLoad( _false ) > rH = fn Get1Resource( resType, resID ) > SetResLoad( _zTrue ) > long if ( rH ) // existing resource > RemoveResource( rH ) // remove it > err = fn ResError > long if ( err ) // failed to remove > ReleaseResource( rH ) // dump resource handle > xelse > DisposeHandle( rH ) // dump plain handle > end if > end if > > copyDataH = dataH > if ( err == _noErr ) then err = fn HandToHand( copyDataH ) // copy the > data > long if ( err == _noErr ) > AddResource( copyDataH, resType, resID, resName ) > err = fn ResError > long if ( err == _noErr ) > SetResAttrs( copyDataH, _resPurgeable% ) > ChangedResource( copyDataH ) > ReleaseResource( copyDataH ) // dump resource handle > xelse > DisposeHandle( copyDataH ) // dump plain handle > end if > end if > > UseResFile( curResFile ) // restore resource chain > > end fn = err > > > local mode > local fn MyFlattenAndSavePageFormat( w as WindowRef, resFile as short ) > '~'1 > dim as OSStatus err > dim as Handle @ flatFormatHandle > dim as PMPageFormat @ pageFormat > > // get the page format from the window > err = fn GetWindowProperty( w, _kMyAppSignature, > _kMyPageFormatProperty, ¬ > sizeof( PMPageFormat ), #_nil, @pageFormat ) > long if ( err == _noErr ) > // flatten (into XML form) > err = fn PMFlattenPageFormat( pageFormat, @flatFormatHandle ) > long if ( err == _noErr ) > // save as resource > err = fn MyHandleToResource( flatFormatHandle, _kMyPageFormatResType, ¬ > _kMyPageFormatResID, "PageFormat", resFile ) > DisposeHandle( flatFormatHandle ) > end if > end if > end fn = err > > > local mode > local fn MyLoadAndUnflattenPageFormat( w as WindowRef, resFile as > short ) > '~'1 > dim as OSStatus err, ignore > dim as Handle @ flatFormatHandle > dim as PMPageFormat @ pageFormat > dim as short curResFile > > curResFile = fn CurResFile > UseResFile( resFile ) > // retrieve flattened (XML) page format from resource > flatFormatHandle = fn Get1Resource( _kMyPageFormatProperty, > _kMyPageFormatResID ) > > long if ( flatFormatHandle ) > // unflatten (convert to opaque form) for PrintManager > err = fn PMUnflattenPageFormat( flatFormatHandle, pageFormat ) > ReleaseResource( flatFormatHandle ) > long if ( err == _noErr ) > // attach to window > ignore = fn SetWindowProperty( w, _kMyAppSignature, > _kMyPageFormatProperty,¬ > sizeof( PMPageFormat ), @pageFormat ) // save in window > end if > end if > UseResFile( curResFile ) // restore resource chain > > end fn > > > > local fn MyDoPrintLoop( printSession as PMPrintSession, pageFormat as > PMPageFormat, ¬ > printSettings as PMPrintSettings, w as WindowRef ) > '~'1 > dim as OSStatus err, tempErr > dim as UInt32 pageNumber, totalDocPages, @ firstPage, lastPage > dim as CGrafPtr @ oldPort, printingContext > dim as Rect pageRect > dim as Ptr ignore > > totalDocPages = fn MyGetDocumentNumPagesInDoc( w ) > err = fn PMGetFirstPage( printSettings, @firstPage ) > if ( err == _noErr ) then err = fn PMGetLastPage( printSettings, > @lastPage ) > if ( err == _noErr and lastPage > totalDocPages ) then lastPage = > totalDocPages > if ( err == _noErr ) then err = fn PMSetLastPage( printSettings, > lastPage, _false ) > long if ( err == _noErr ) > err = fn PMSessionBeginDocument( printSession, printSettings, > pageFormat ) > long if ( err == _noErr ) > pageNumber = firstPage > > // loop until all pages printed or an error occurs > while ( pageNumber <= lastPage and err == _noErr and ¬ > fn PMSessionError( printSession ) == _noErr ) > err = fn PMSessionBeginPage( printSession, pageFormat, #0 ) > long if ( err == _noErr ) > GetPort( @oldPort ) > // set up the printing port (graphics context) > err = fn PMSessionGetGraphicsContext( printSession, ¬ > kPMGraphicsContextQuickdraw, @printingContext ) > long if ( err == _noErr ) > SetPort( printingContext ) > ignore = fn GetPortBounds( printingContext, @pageRect ) // adjusted > page rect > // draw a page > err = fn MyPageDrawProc( w, pageRect, pageNumber ) > SetPort( oldPort ) > end if > tempErr = fn PMSessionEndPage( printSession ) > if ( err == _noErr ) then err = tempErr > end if > pageNumber++ > wend > > tempErr = fn PMSessionEndDocument( printSession ) > if ( err == _noErr ) then err = tempErr > if ( err == _noErr ) then err = fn PMSessionError( printSession ) > end if > end if > > end fn = err > > > local mode > local fn MySetupPageFormatForPrinting( printSession as PMPrintSession, > ¬ > w as WindowRef, pageFormatP as ^PMPageFormat ) > '~'1 > dim as OSStatus err, ignore > dim as PMPageFormat @ pageFormat > > // see if there's already a page format attached to the window > err = fn GetWindowProperty( w, _kMyAppSignature, > _kMyPageFormatProperty, ¬ > sizeof( PMPageFormat ), #_nil, @pageFormat ) > long if ( err ) // not previously stored as WindowProperty > err = fn PMCreatePageFormat( @pageFormat ) > long if ( err == _noErr ) > err = fn PMSessionDefaultPageFormat( printSession, pageFormat ) > long if ( err == _noErr ) // attach the default page format to the > window > ignore = fn SetWindowProperty( w, _kMyAppSignature, > _kMyPageFormatProperty, ¬ > sizeof( PMPageFormat ), @pageFormat ) > xelse // error; release the page format that we created above > ignore = fn PMRelease( pageFormat ) > pageFormat = 0 > end if > end if > xelse // page format was available as WindowProperty > err = fn PMSessionValidatePageFormat( printSession, pageFormat, > #_kPMDontWantBoolean ) > long if ( err ) // failed to validate > ignore = fn RemoveWindowProperty( w, _kMyAppSignature, > _kMyPageFormatProperty ) > ignore = fn PMRelease( pageFormat ) > pageFormat = 0 > end if > end if > > pageFormatP.nil& = pageFormat // return format to caller > > end fn = err > > > > > > long if 0 > // called when the page setup dialog or sheet is dismissed > "MyPageSetupDoneRoutine" > enterproc fn MyPageSetupDoneRoutine( printSession as PMPrintSession, ¬ > w as WindowRef, accepted as Boolean ) > '~'1 > dim as OSStatus ignore > // The essential task is to release the print session. > // You could do other things here, such as re-paginating the document > // if accepted != false. > ignore = fn PMRelease( printSession ) > end fn > > // called when the print dialog or sheet is dismissed > "MyPrintDialogDoneRoutine" > enterproc fn MyPrintDialogDoneRoutine( printSession as PMPrintSession, > ¬ > w as WindowRef, accepted as Boolean ) > '~'1 > dim as OSStatus err, ignore, tempErr > dim as PMPageFormat @ pageFormat > dim as PMPrintSettings @ printSettings > > err = fn GetWindowProperty( w, _kMyAppSignature, > _kMyPrintSettingsProperty, ¬ > sizeof( PMPrintSettings ), #_nil, @printSettings ) > long if ( err == _noErr ) > err = fn GetWindowProperty( w, _kMyAppSignature, > _kMyPageFormatProperty, ¬ > sizeof( PMPageFormat ), #_nil, @pageFormat ) > long if ( err == _noErr ) > // go print the document > if ( accepted ) then err = fn MyDoPrintLoop( printSession, ¬ > pageFormat, printSettings, w ) > // dump the print settings > tempErr = fn PMRelease( printSettings ) > if ( err == _noErr ) then err = tempErr > ignore = fn RemoveWindowProperty( w, _kMyAppSignature, > _kMyPrintSettingsProperty ) > end if > end if > // release the print session > tempErr = fn PMRelease( printSession ) > if ( err == _noErr ) then err = tempErr > if ( err ) then fn ReportPMError( err ) > > end fn > > end if > > local fn MyDoPrint( w as WindowRef ) > '~'1 > dim as OSStatus err,ignore > dim as PMPrintSettings @ printSettings > dim as PMPageFormat @ pageFormat > dim as UInt32 minPage, maxPage > dim as PMPrintSession @ printSession > dim as CFStringRef @ windowTitleRef > dim as Boolean sheetsAreAvailable, @ accepted > begin globals > dim as Ptr sPrintSheetDoneUPP // 'static' variable > end globals > > if ( w == 0 ) then exit fn > > long if ( sPrintSheetDoneUPP == _nil ) // set up the call-back routine > sPrintSheetDoneUPP = fn NewPMSheetDoneUPP( ¬ > [proc "MyPrintDialogDoneRoutine" + _FBprocToProcPtrOffset] ) > end if > > printSettings = 0 > pageFormat = 0 > > err = fn PMCreateSession( @printSession ) > long if ( err == _noErr ) > // get default or previously-set page format > err = fn MySetupPageFormatForPrinting( printSession, w, @pageFormat ) > long if ( err == _noErr ) > err = fn PMCreatePrintSettings( @printSettings ) > long if ( err == _noErr ) > // Apple recommends that the Print dialog should always show default > values > err = fn PMSessionDefaultPrintSettings( printSession, printSettings ) > long if ( err == _noErr ) > // set up the job name > err = fn CopyWindowTitleAsCFString( w, @windowTitleRef ) > long if ( err == _noErr ) > err = fn PMSetJobNameCFString( printSettings, windowTitleRef ) > CFRelease( windowTitleRef ) > end if > end if > end if > > long if ( err == _noErr ) > // set the default page range > minPage = 1 > maxPage = fn MyGetDocumentNumPagesInDoc( w ) > err = fn PMSetPageRange( printSettings, minPage, maxPage ) > end if > > long if ( err == _noErr ) > // attach print settings to window > // for use in MyPrintDialogDoneRoutine and MyDoPrintLoop > ignore = fn SetWindowProperty( w, _kMyAppSignature, > _kMyPrintSettingsProperty, ¬ > sizeof( PMPrintSettings ), @printSettings ) > > sheetsAreAvailable = _zTrue > err = fn PMSessionUseSheets( printSession, w, sPrintSheetDoneUPP ) > long if ( err == _kPMNotImplemented ) // we are in MacOS 8/9 > err = _noErr > sheetsAreAvailable = _false > end if > long if ( err == _noErr ) > // show the Print dialog > err = fn PMSessionPrintDialog( printSession, printSettings, > pageFormat, @accepted ) > long if ( err == _noErr and sheetsAreAvailable == _false ) > // if no sheets, we get here after the print dialog is dismissed > fn MyPrintDialogDoneRoutine( printSession, w, accepted ) > end if > end if > end if > end if > long if ( err ) > // dump various things now, because MyPrintDialogDoneRoutine won't get > called > long if ( printSettings ) > ignore = fn RemoveWindowProperty( w, _kMyAppSignature, > _kMyPrintSettingsProperty ) > ignore = fn PMRelease( printSettings ) > end if > ignore = fn PMRelease( printSession ) > end if > end if > if ( err ) then fn ReportPMError( err ) > > end fn = err > > > local fn MyDoPageSetup( w as WindowRef ) > '~'1 > dim as PMPrintSession @ printSession > dim as PMPageFormat @ pageFormat > dim as OSStatus err, ignore > dim as Boolean sheetsAreAvailable, @ accepted > begin globals > dim as Ptr sPageSetupSheetDoneUPP // 'static' variable > end globals > > if ( w == 0 ) then exit fn > > long if ( sPageSetupSheetDoneUPP == _nil ) // set up the call-back > routine > sPageSetupSheetDoneUPP = fn NewPMSheetDoneUPP( [proc > "MyPageSetupDoneRoutine" + _FBprocToProcPtrOffset] ) > end if > > err = fn PMCreateSession( @printSession ) > long if ( err == _noErr ) > // get default or previously-set page format > err = fn MySetupPageFormatForPrinting( printSession, w, @pageFormat ) > > long if ( err == _noErr ) > sheetsAreAvailable = _zTrue > err = fn PMSessionUseSheets( printSession, w, sPageSetupSheetDoneUPP ) > long if ( err == _kPMNotImplemented ) // we are in MacOS 8/9 > sheetsAreAvailable = _false > err = _noErr > end if > > long if ( err == _noErr ) > // show the page setup dialog > cursor _arrowCursor > err = fn PMSessionPageSetupDialog( printSession, pageFormat, @accepted > ) > long if ( err == _noErr and sheetsAreAvailable == _false ) > // if no sheets, we get here after the page dialog is dismissed > fn MyPageSetupDoneRoutine( printSession, w, accepted ) > end if > end if > > end if > > end if > long if ( err ) > // release the print session, because MyPageSetupDoneRoutine won't be > called > ignore = fn PMRelease( printSession ) > fn ReportPMError( err ) > end if > end fn = err > '------------CarbonPrinting.incl-------------- > > > > /* > Below is a primitive document demo, This is *not* state-of-the-art > menu, file and window code, but merely shows how to use the routines: > MyLoadAndUnflattenPageFormat > MyFlattenAndSavePageFormat > MyDoPageSetup > MyDoPrint > */ > > // return a number for window title "Untitled xx" > local fn NextNewWindowCount > '~'1 > begin globals > dim as long sNewWindowCount // 'static' var > end globals > sNewWindowCount++ > end fn = sNewWindowCount > > > local mode > local fn NextFBWindowNum > '~'1 > dim as long wNum > wNum = 0 > do > wNum++ > until ( window( -wNum ) == 0 ) // first available (not currently used) > FB wNum > end fn = wNum > > > local mode > local fn DoOpenDocument > '~'1 > dim as WindowRef w > dim as Str255 content > dim as FSSpec f > dim as OSStatus ignore > dim as short resFile > > long if ( files$( _FSSpecOpen,,, f ) != "" ) > // here we should really check if the doc is open already > > window fn NextFBWindowNum, f.name // create a new window > > open "I", 1, @f // read the data fork > input #1, content > close 1 > > // attach the data fork's data to the window > w = window( _wndRef ) > ignore = fn SetWindowProperty( w, _kMyAppSignature, > _kMyDocContentProperty, ¬ > sizeof( Str255 ), @content ) > > // get the page format, if any, from the resource fork, if there is one > resFile = fn FspOpenResFile( f, _fsRdPerm ) > long if ( resFile ) > fn MyLoadAndUnflattenPageFormat( w, resFile ) > CloseResFile( resFile ) > end if > end if > > end fn > > > local mode > local fn DoSaveDocument( w as WindowRef ) > '~'1 > dim as FSSpec f > dim as Str255 wTitle > dim as Str255 content > dim as long wNum > dim as OSStatus ignore > dim as short resFile > > long if ( w ) > GetWTitle( w, @wTitle ) > long if ( files$( _FSSpecSave,, wTitle, f ) != "" ) > ignore = fn GetWindowProperty( w, _kMyAppSignature, > _kMyDocContentProperty, ¬ > sizeof( Str255 ), #0, @content ) > // save the document's text-content to the file's data fork > open "O", 1, @f > print #1, content > close 1 > > //make sure we have a resource fork, and set creator/type > FspCreateResFile( f, _kMyAppSignature, _kMyDocType, _smSystemScript ) > // save the page format, if any, in the resource fork > resFile = fn FspOpenResFile( f, _fsRdWrPerm ) > long if ( resFile ) > fn MyFlattenAndSavePageFormat( w, resFile ) > CloseResFile( resFile ) > end if > > // set the window's title to the file's save name > wNum = usr WPtr2WNum( w ) > window wNum, f.name > end if > end if > > end fn > > > local mode > local fn BuildNewWindow > '~'1 > dim as long untitledNum > dim as Str255 wTitle > dim as Str255 content > dim as OSStatus err > > wTitle = "Untitled" > untitledNum = fn NextNewWindowCount > if ( untitledNum > 1 ) then wTitle += str$( untitledNum ) > window fn NextFBWindowNum, wTitle > // invent some text > content = "Some text..." > // attach it to the window as a WindowProperty > err = fn SetWindowProperty( window( _wndRef ), _kMyAppSignature, > _kMyDocContentProperty, ¬ > sizeof( Str255 ), @content ) > > end fn > > > local mode > local fn DoCloseWindow( w as WindowRef ) > '~'1 > dim as long wNum > > long if ( w ) > wNum = usr WPtr2WNum( w ) > // here we should really check if doc is dirty and if so, offer to > save it > window close wNum > end if > > end fn > > > local mode > local fn DoDrawWindow( wNum as long ) > '~'1 > dim as Str255 content > dim as OSStatus ignore > dim as WindowRef @ w > > long if ( w ) > get window wNum, w > ignore = fn GetWindowProperty( w, _kMyAppSignature, > _kMyDocContentProperty, ¬ > sizeof( Str255 ), #0, @content ) > print %(5, 15) content > end if > > end fn > > > local mode > local fn HandleMenu > '~'1 > dim as OSStatus err > > select menu(0) > case 1 > select menu(1) > case 1 : fn BuildNewWindow > case 2 : fn DoOpenDocument > case 4 : fn DoCloseWindow( fn ActiveNonFloatingWindow() ) > case 5 : fn DoSaveDocument( fn ActiveNonFloatingWindow() ) > case 7 : fn MyDoPageSetup( fn ActiveNonFloatingWindow() ) > case 8 : fn MyDoPrint( fn ActiveNonFloatingWindow() ) > case else > end > end select > end select > menu > end fn > > local mode > local fn HandleDialog > '~'1 > dim as long evnt, ref > > evnt = dialog(0) > ref = dialog(evnt) > select evnt > case _wndRefresh > fn DoDrawWindow( ref ) > case _wndClick > window ref > case _wndClose > window close ref > end select > end fn > > > // Main program > '~'1 > dim as OSStatus ignore > dim as MenuRef @ windowMenu > > on menu fn HandleMenu > on dialog fn HandleDialog > > menu 1, 0, 1, "File" > menu 1, 1, 1, "New/N" > menu 1, 2, 1, "Open…/O" > menu 1, 3, 0, "-" > menu 1, 4, 1, "Close/W" > menu 1, 5, 1, "Save As…/S" > menu 1, 6, 0, "-" > menu 1, 7, 1, "Page Setup…/P" > ignore = fn SetMenuItemModifiers( fn GetMenuHandle( 1 ), 7, > _kMenuShiftModifier ) > menu 1, 8, 1, "Print…/P" > menu 1, 9, 0, "-" > menu 1, 10, 1, "Quit/Q" > > ignore = fn CreateStandardWindowMenu( 0, windowMenu ) > InsertMenu( windowMenu, 0 ) > > fn BuildNewWindow > > do > HandleEvents > until 0 > > //kill resources "plst", 0 // force Classic in OS X > '---------------------- > > > -- > >