' ddocIBasic32.iwb ' IBasic test program for dDoc Print and Preview ' Requires IWBasic to run or compile ' Copyright 1995-1998, Don Dickinson, All rights reserved ' Ported to IBasic by Dennis Comninos (dncom@mweb.co.za) ' Adapted for IWB by Brian Pugh ' NOTE FOR IBASIC USERS ' First get the defaultdDoc directory from the win.ini file. This is required for the ' declares and other files. This routine is executed only once and must be placed before ' the declares contained in the dDoc interface. It could be placed within the dDoc Interface ' but is placed here so as not to disturb the interface's flow. In a live application, the ' IBasic programmer may replace this with a GETSTARTPATH if required. The dDoc Interface ' can then be modified so that the first declare is concatenated with a GETSTARTPATH or, ' gDDOCPath_Decl can be set to the required path ' If it is required to run the demo from the IBasic IDE, then "uncomment" the statement marked ' below to create a null gDDOCPath_Decl autodefine "off" $include "windowssdk.inc" $use "ddoc32.lib" STRING returnVal,iniFile,iniSec,iniItem,defaultVal INT mynum,maxiniLen STRING gDDOCPath,gDDOCPath_Decl iniFile="win.ini" iniSec="dDoc samples" iniItem="dDoc" defaultVal = "not there" maxiniLen=255 mynum = GetPrivateProfileStringA(iniSec,iniItem,defaultVal,returnVal,maxiniLen,iniFile) IF returnVal = "not there" gDDOCPath = GETSTARTPATH ELSE gDDOCPath = RTRIM$(LTRIM$(returnVal)) IF RIGHT$(gDDOCPath,1) <> "\\" THEN gDDOCPath = gDDOCPath + "\\" gDDOCPath_Decl = gDDOCPath + "lib\\" gDDOCPath_Decl = "" ' uncomment if you wish to run from IBasic IDE. Change it to a comment if you wish to compile ENDIF ' +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ ' Start of dDoc Interface ' IBasic 32-bit call interface for the dDoc Print and Preview Engine ' Copyright 1998, Don Dickinson, All Rights Reserved. ' ' This source code may not be redistributed in any means, electronic or paper, ' without express written permission from the author, Don Dickinson. ' dDoc Print and Preview is based on a vb3 report viewer written in VB3 ' by David W. Metzger of WinRep Software. It would not exist without his ' support and inventiveness. Dave writes software for Manufacturer's Representatives ' called WinRep. If you are interested in software to track Invoices, ' Purchases Orders, and Commissions, WinRep is the leading Windows solution. ' WinRep Software also produces EDI, POS, and Quoting Software for Sales Agencies. ' If you are interested in WinRep, please contact ddickinson@winrep.com or ' dmetzger@winrep.com for more information. ' Ported to IBasic by Dennis Comninos (dncom@mweb.co.za) ' Errors returned by dpStartDoc '================================================================== CONST DDOC_NOHANDLES = -1 CONST DDOC_BADFILE = -2 CONST DDOC_FILEEXISTS = -3 ' Status Codes returned by dpMailInit '================================================================== CONST DDOC_MAIL_SUCCESS = 0 CONST DDOC_MAIL_FNF = 1 CONST DDOC_MAIL_LNF = 2 CONST DDOC_MAIL_NOH = 3 CONST DDOC_MAIL_HEIGHT_INVALID = 4 CONST DDOC_MAIL_WIDTH_INVALID = 5 CONST DDOC_MAIL_LABHEIGHT_INVALID = 6 CONST DDOC_MAIL_LABWIDTH_INVALID = 7 CONST DDOC_MAIL_COL_INVALID = 8 CONST DDOC_MAIL_ROW_INVALID = 9 CONST DDOC_MAIL_LINES_INVALID = 10 ' Unit of measure constants as passed to dpStartDoc '================================================================== CONST DDOC_INCH = 0 CONST DDOC_CM = 1 ' Orientation Constants for use with dpStartDoc '================================================================== CONST DDOC_PORTRAIT = 0 CONST DDOC_LANDSCAPE = 1 ' Paper Bin Constants used in dpStartDoc and dpNewPage '================================================================== CONST DDOC_BIN_UPPER = 1 CONST DDOC_BIN_FIRST = DDOC_BIN_UPPER CONST DDOC_BIN_ONLYONE = 1 CONST DDOC_BIN_LOWER = 2 CONST DDOC_BIN_MIDDLE = 3 CONST DDOC_BIN_MANUAL = 4 CONST DDOC_BIN_ENVELOPE = 5 CONST DDOC_BIN_ENVMANUAL = 6 CONST DDOC_BIN_AUTO = 7 CONST DDOC_BIN_TRACTOR = 8 CONST DDOC_BIN_SMALLFMT = 9 CONST DDOC_BIN_LARGEFMT = 10 CONST DDOC_BIN_LARGECAPACITY = 11 CONST DDOC_BIN_CASSETTE = 14 CONST DDOC_BIN_LAST = DDOC_BIN_CASSETTE ' Paper Size Constants used in dpStartDoc and dpNewPage '================================================================== CONST DDOC_PAPER_LETTER = 1 :' Letter 8 1/2 x 11 in CONST DDOC_PAPER_LETTERSMALL = 2 :' Letter Small 8 1/2 x 11 in CONST DDOC_PAPER_TABLOID = 3 :' Tabloid 11 x 17 in CONST DDOC_PAPER_LEDGER = 4 :' Ledger 17 x 11 in CONST DDOC_PAPER_LEGAL = 5 :' Legal 8 1/2 x 14 in CONST DDOC_PAPER_STATEMENT = 6 :' Statement 5 1/2 x 8 1/2 in CONST DDOC_PAPER_EXECUTIVE = 7 :' Executive"7 1/2 x 10 in CONST DDOC_PAPER_A3 = 8 :' A3 297 x 420 mm CONST DDOC_PAPER_A4 = 9 :' A4 210 x 297 mm CONST DDOC_PAPER_A4SMALL = 10 :' A4 Small 210 x 297 mm CONST DDOC_PAPER_A5 = 11 :' A5 148 x 210 mm CONST DDOC_PAPER_B4 = 12 :' B4 250 x 354 CONST DDOC_PAPER_B5 = 13 :' B5 182 x 257 mm CONST DDOC_PAPER_FOLIO = 14 :' Folio 8 1/2 x 13 in CONST DDOC_PAPER_QUARTO = 15 :' Quarto 215 x 275 mm CONST DDOC_PAPER_10x14 = 16 :' 10x14 in CONST DDOC_PAPER_11X17 = 17 :' 11x17 in CONST DDOC_PAPER_NOTE = 18 :' Note 8 1/2 x 11 in CONST DDOC_ENV_9 = 19 :' Envelope #9 3 7/8 x 8 7/8 CONST DDOC_ENV_10 = 20 :' Envelope #10 4 1/8 x 9 1/2 CONST DDOC_ENV_11 = 21 :' Envelope #11 4 1/2 x 10 3/8 CONST DDOC_ENV_12 = 22 :' Envelope #12 4 \276 x 11 CONST DDOC_ENV_14 = 23 :' Envelope #14 5 x 11 1/2 CONST DDOC_ENV_DL = 27 :' Envelope DL 110 x 220mm CONST DDOC_ENV_C5 = 28 :' Envelope C5 162 x 229 mm CONST DDOC_ENV_C3 = 29 :' Envelope C3 324 x 458 mm CONST DDOC_ENV_C4 = 30 :' Envelope C4 229 x 324 mm CONST DDOC_ENV_C6 = 31 :' Envelope C6 114 x 162 mm CONST DDOC_ENV_C65 = 32 :' Envelope C65 114 x 229 mm CONST DDOC_ENV_B4 = 33 :' Envelope B4 250 x 353 mm CONST DDOC_ENV_B5 = 34 :' Envelope B5 176 x 250 mm CONST DDOC_ENV_B6 = 35 :' Envelope B6 176 x 125 mm CONST DDOC_ENV_ITALY = 36 :' Envelope 110 x 230 mm CONST DDOC_ENV_MONARCH = 37 :' Envelope Monarch 3.875 x 7.5 in CONST DDOC_ENV_PERSONAL = 38 :' 6 3/4 Envelope 3 5/8 x 6 1/2 in CONST DDOC_FANFOLD_US = 39 :' US Std Fanfold 14 7/8 x 11 in CONST DDOC_FANFOLD_STD_GERMAN = 40 :' German Std Fanfold 8 1/2 x 12 in CONST DDOC_FANFOLD_LGL_GERMAN = 41 :' German Legal Fanfold 8 1/2 x 13 in ' dpStartDoc Option Constants '================================================================== CONST DDOC_ALLOWMAPI = 4 CONST DDOC_ZOOMWIDTH = 64 CONST DDOC_ZOOMFIT = 128 CONST DDOC_ZOOM75 = 256 CONST DDOC_ZOOM100 = 512 CONST DDOC_ZOOM125 = 1024 ' Font Style Bit-wise constats for the dpFont call '================================================================== CONST DDOC_FONTNORMAL = 0 CONST DDOC_FONTBOLD = 1 CONST DDOC_FONTITALIC = 2 CONST DDOC_FONTUNDERLINE = 4 CONST DDOC_FONTSTRIKEOUT = 8 ' dpEndDoc Option constants '================================================================== CONST DDOC_END_VIEW = 0 CONST DDOC_END_PRINT = 1 CONST DDOC_END_CLOSE = 2 CONST DDOC_END_DELETE = 4 ' Text alignment constants for dpText, dpPageNo, dpPageCount '================================================================== CONST DDOC_LEFT = 0 CONST DDOC_CENTER = 1 CONST DDOC_RIGHT = 2 CONST DDOC_DECIMAL = 3 ' Error codes for dpSelfExtract '================================================================== CONST DDOC_INPUT_NOT_FOUND = -5 CONST DDOC_OUTPUT_EXISTS = -4 CONST DDOC_ERR_OPEN_INPUT = -3 CONST DDOC_ERROR_OPEN_OUTPUT = -2 CONST DDOC_ERROR_OPEN_STUB = -1 CONST DDOC_SUCCESS = 0 ' Button codes to Assign hints (captions) to buttons ' these will normally be used only by International users ' to replace the English INTs on the screen. Used by ' the dpCaption function '============================================================================ CONST DDOC_INIT_INTS = 0 :' Initialization flag CONST DDOC_MENU_FILE = 1 :' File Menu CONST DDOC_MENU_DOC = 2 :' Document Menu CONST DDOC_BTN_EXIT = 3 :' Exit button hint and exit menu CONST DDOC_BTN_FIRST = 4 :' First Button hint and menu CONST DDOC_BTN_PREV = 5 :' Previous Button hint and menu CONST DDOC_BTN_NEXT = 6 :' Next button hint and menu CONST DDOC_BTN_LAST = 7 :' Last Button hint and menu CONST DDOC_BTN_JUMP = 8 :' Jump Button hint and menu CONST DDOC_BTN_PRINT = 9 :' Print hint and menu CONST DDOC_INT_ZOOM = 10 :' Zoom label caption CONST DDOC_INT_ZOOMFIT = 11 :' Zoom Fit INT in drop down CONST DDOC_INT_ZOOMWIDTH = 12 :' Zoom Width in drop down CONST DDOC_INT_DOCINDEX = 13 :' INT Document index CONST DDOC_INT_PAGE = 14 :' Page CONST DDOC_INT_OF = 15 :' of CONST DDOC_DLG_JUMP_TITLE = 16 :' jump dialog title CONST DDOC_DLG_JUMP_TEXT = 17 :' dialog jump text CONST DDOC_BTN_CANCEL = 18 :' cancel button CONST DDOC_BTN_OK = 19 :' ok button CONST DDOC_DLG_PW_TITLE = 20 :' passINT box title CONST DDOC_DLG_PW_TEXT = 21 :' passINT text in dialog CONST DDOC_DLG_PW_INVALID = 22 :' passINT is invalid (try again) CONST DDOC_DLG_PW_CANCEL = 23 :' passINT invalid (3 strikes and you:'re out) CONST DDOC_BTN_EMAIL = 24 :' email button ' Document generation '================================================================== 'DECLARE gDDOCPath_Decl+"dDoc32.dll",dpStartDoc(hParent:INT,zTitle:STRING,zFile:STRING,iUOM:INT,iPaper:INT,iOrient:INT,iBin:INT,iOptions:INT),INT DECLARE IMPORT,dpStartDoc(hParent:INT,zTitle:STRING,zFile:STRING,iUOM:INT,iPaper:INT,iOrient:INT,iBin:INT,iOptions:INT),INT DECLARE IMPORT,dpNewPage(iHandle:INT,iPaper:INT,iOrient:INT,iBin:INT) DECLARE IMPORT,dpBookmark(iHandle:INT,zBookmark:STRING) DECLARE IMPORT,dpEndDoc(iHandle:INT,iOptions:INT) DECLARE IMPORT,dpGetFileName(iHandle:INT,zDoc:STRING,iLen:INT) DECLARE IMPORT,dpChangeINTs(iHandle:INT,iWhich:INT,zText:STRING) DECLARE IMPORT,dpSelfExtract(zInputFile:STRING,zDDOC:STRING,zOutEXE:STRING),INT DECLARE IMPORT,dpSetPassINT(iHandle:INT,zPassINT:STRING) ' Font and Text Functions '================================================================== DECLARE IMPORT,dpFont(iHandle:INT,iStyle:INT,Size:FLOAT,iColor:INT,zFontName:STRING) DECLARE IMPORT,dpText(iHandle:INT,x:FLOAT,y:FLOAT,iAlign:INT,zText:STRING) DECLARE IMPORT,dpWrapText(iHandle:INT,x:FLOAT,y:FLOAT,x2:FLOAT,y2:FLOAT,leading:FLOAT,zText:STRING),INT DECLARE IMPORT,dpWrapCount(iHandle:INT),INT DECLARE IMPORT,dpAngleText(iHandle:INT,x:FLOAT,y:FLOAT,iAngle:INT,zText:STRING) DECLARE IMPORT,dpPageNo(iHandle:INT,x:FLOAT,y:FLOAT,iAlign:INT,iAngle:INT) DECLARE IMPORT,dpPageCount(iHandle:INT,x:FLOAT,y:FLOAT,iAlign:INT,iAngle:INT) ' Lines and Graphics '================================================================== DECLARE IMPORT,dpLine(iHandle:INT,x:FLOAT,y:FLOAT,x2:FLOAT,y2:FLOAT,w:FLOAT,c:INT) DECLARE IMPORT,dpRect(iHandle:INT,x:FLOAT,y:FLOAT,x2:FLOAT,y2:FLOAT,w:FLOAT,iFillColor:INT,iBorderColor:INT) DECLARE IMPORT,dpGraphic(iHandle:INT,x:FLOAT,y:FLOAT,x2:FLOAT,y2:FLOAT,zFileName:STRING) DECLARE IMPORT,dpEmbedGraphic(iHandle:INT,x:FLOAT,y:FLOAT,x2:FLOAT,y2:FLOAT,zFileName:STRING) ' Mailing Label API '================================================================== DECLARE IMPORT,dpMailInit(iHandle:INT,szIniFile:STRING,szIniSection:STRING,nAlign:INT),INT DECLARE IMPORT,dpLabelLines(iHandle:INT),INT DECLARE IMPORT,dpLabelsPerPage(iHandle:INT),INT DECLARE IMPORT,dpLabelText(iHandle:INT,szLabelLine:STRING) DECLARE IMPORT,dpNextLabel(iHandle:INT) DECLARE IMPORT,dpSetLabelLine(iHandle:INT,nLabelLine:INT) DECLARE IMPORT,dpSetLabel(iHandle:INT,nLabelNumber:INT) DECLARE IMPORT,dpPrintTemplate(iHandle:INT,LabAlign:INT) DECLARE IMPORT,dpLabelX(iHandle:INT,sngX:FLOAT) DECLARE IMPORT,dpLabelY(iHandle:INT,sngY:FLOAT) ' End of dDoc Interface '++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ ' *********** START OF DEMO SOURCE *********** ' NOTE TO IBASIC USERS!! ' Do not be put off by the number of lines of code. Remember that this is a demo ' showing off and demonstrating most of the features of dDoc. In a real application, ' few of the calls given in this demo will be used. ' The variables fws1,...fws9 were used in the IBasic port to work around a problem with ' IBasic (v2.02B) in respect of the passing of single and double precision variables to ' a dll. Were it not for this problem, the fws variables would not be needed further ' cutting down on code requirements. ' This port focused on the conversion of dDoc for use with IBasic. The standard dDoc demo ' version and demo source were used for the port. The registered version of dDoc has more ' features such as faxing and email facilities. ' Dennis Comninos (December, 2003) ' Constants for the controls '------------------------------------------------------------------------ SETID "btnBasic",101 SETID "btnFancy",102 SETID "btnWrap",103 SETID "btnGraphic",104 SETID "btnBookmark",105 SETID "btnLabels",106 SETID "btnQuit",107 SETID "optPreview",108 SETID "optPrint",109 ' Needed Color Constants (VB compatible) '--------------------------------------------------------------------------- CONST vbBlack = 0x0 CONST vbRed = 0xFF CONST vbGreen = 0xFF00 CONST vbYellow = 0xFFFF CONST vbBlue = 0xFF0000 CONST vbMagenta = 0xDA0AFF CONST vbCyan = 0xFFFF00 CONST vbWhite = 0xFFFFFF CONST vbGrey = 0xC0C0C0 CONST LIGHT_SHADE = 0xE0E0E0 ' Globals '------------------------------------------------------------------------ DEF hFile:INT DEF gPreview:INT :' Flag to tell us whether we print or preview. DEF endCode:INT DEF iHandle:INT DEF a:INT 'DEF e:DOUBLE DEF lh,cy:FLOAT 'DEF x,y:FLOAT DEF iLeft:INT DEF zTemp[300]:ISTRING DEF iLen,iLinesPrinted,iPrinted:INT DEF zText[2000]:ISTRING DEF fws1,fws2,fws3,fws4,fws5,fws6,fws7,fws8:FLOAT 'DEF fws9:FLOAT DEF xFmt:STRING DEF el:INT INT angle DEF myfile:FILE DEF xFile:STRING DIALOG dlgDemo CREATEDIALOG dlgDemo,0,0,424,369,0x80C80080,0,"dDoc Print and Preview Engine Demo",&msubDemoHandler CONTROL dlgDemo,@STATIC,"dDoc Print and Preview Engine",30,13,190,27,0x5000010B,1 CONTROL dlgDemo,@STATIC,"Copyright 1995-1998 by Don Dickinson All rights reserved",30,39,309,20,0x5000010B,2 CONTROL dlgDemo,@GROUPBOX," Click on the buttons below to demonstrate features ",16,70,394,280,0x50000007,3 CONTROL dlgDemo,@BUTTON,"The Basics",32,100,170,25,0x50000000,@btnBasic CONTROL dlgDemo,@BUTTON,"Fancy Text",32,140,170,25,0x50000000,@btnFancy CONTROL dlgDemo,@BUTTON,"Wrapping Text",32,180,170,25,0x50000000,@btnWrap CONTROL dlgDemo,@BUTTON,"Lines, Rectangles and Bitmaps",32,220,170,25,0x50000000,@btnGraphic CONTROL dlgDemo,@BUTTON,"Bookmarks and other fun",32,260,170,25,0x50000000,@btnBookmark CONTROL dlgDemo,@BUTTON,"Mailing Labels",32,300,170,25,0x50000000,@btnLabels CONTROL dlgDemo,@BUTTON,"Quit",220,300,170,25,0x50000000,@btnQuit CONTROL dlgDemo,@GROUPBOX," Print or Preview? ",261,95,116,70,0x50000007,4 CONTROL dlgDemo,@RADIOBUTTON,"Print",274,115,70,20,@GROUP,@optPrint CONTROL dlgDemo,@RADIOBUTTON,"Preview",274,135,70,20,0,@optPreview SHOWDIALOG dlgDemo WAITUNTIL IsWindowClosed(dlgDemo) END SUB msubDemoHandler(),INT SELECT @MESSAGE CASE @IDINITDIALOG SETFONT dlgDemo, "Arial", 10, 5, 0,1 SETFONT dlgDemo, "Arial", 9, 5, 0,3 SETFONT dlgDemo, "Arial", 9, 5, 0,4 SETSTATE dlgDemo, @optPreview,1 gPreview = 1 CENTERWINDOW dlgDemo CASE @IDCLOSEWINDOW CLOSEDIALOG dlgDemo,@IDOK CASE @IDCONTROL SELECT @CONTROLID CASE @btnBasic GOSUB Demo_Basic CASE @btnFancy GOSUB Demo_Fancy CASE @btnWrap GOSUB Demo_Wrap CASE @btnGraphic GOSUB Demo_Graphic CASE @btnBookMark GOSUB Demo_BookMark CASE @btnLabels GOSUB Demo_Labels CASE @optPreview gPreview = 1 endCode = DDOC_END_VIEW + DDOC_END_DELETE CASE @optPrint gPreview = 0 endCode = DDOC_END_PRINT + DDOC_END_DELETE CASE @btnQuit CLOSEDIALOG dlgDemo,@IDOK ENDSELECT ENDSELECT RETURN 0 ENDSUB '------------------------------------------------------------------------ SUB Demo_Basic() '- This is the amount of space I allow between lines. It's arbitrary, but I ' pick it so there will be about 6 lines per inch. lh = .17 '- If the file name parameter is left blank, the engine will provide a temporary file. ' I pass it a null string to force this. '- Yup, there's a lot of parameters - you could wrap it in a function ' of your own to make it easier. But the parameters are needed to ' let the viewer know how to work the first page and give over-all document specs. hFile = dpStartDoc(0, "Basic Document", "", DDOC_INCH, DDOC_PAPER_A4, DDOC_PORTRAIT, DDOC_BIN_AUTO, DDOC_ZOOMFIT) IF hFile < 1 '- If dpStartDoc returns less than one, it means that ' an error occured during initialization. Refer to the error constants in this instance. MESSAGEBOX (0,STR$(hFile),"Initialise Document Error",64) ELSE '- First establish the font. fws1 = 18 dpFont(hFile,DDOC_FONTBOLD,fws1,vbBlack,"Verdana") '- Now print some text. Remember that all text printed after the dpFont call will be in that font specified, ' until either another dpFont is called or the page has ended. fws1 = 4.15 fws2 = 1.5 dpText(hFile, fws1, fws2, DDOC_CENTER, "Hello World from dDoc Print and Preview") '- Calling dpEndDoc indicates that you are done creating ' the document and the computer should either display ' it on the screen or print it out. Note that ' since we asked the computer to generate a file ' name for us (in the windows temp directory), it ' is only polite to tell the engine to delete it ' after the viewer closes. ' dpEndDoc(hFile, endCode) ENDIF ENDSUB '------------------------------------------------------------------------ SUB Demo_Fancy() lh = .17 zTemp = "" hFile = dpStartDoc(0, "Fancy Text Demo", zTemp, DDOC_INCH, DDOC_PAPER_A4, DDOC_PORTRAIT, DDOC_BIN_UPPER, DDOC_ZOOMFIT) IF hFile < 1 MESSAGEBOX (0,STR$(hFile),"Initialise Document Error",64) ELSE '- Bookmark the page - see the bookmark routine for details! dpBookmark(hFile, "Colour and Style") '- Fonts and Styles fws1 = 10 dpFont(hFile, DDOC_FONTNORMAL, fws1, vbBlack, "Times New Roman") fws1 = .5 fws2 = 1 dpText(hFile, fws1, fws2, DDOC_LEFT, "Just") fws1 = 14 dpFont(hFile, DDOC_FONTNORMAL, fws1, vbBlack, "Courier New") fws1 = .5 fws2 = 1.2 dpText(hFile, fws1, fws2, DDOC_LEFT, "about") fws1 = 8 dpFont(hFile, DDOC_FONTITALIC + DDOC_FONTUNDERLINE + DDOC_FONTBOLD, fws1, vbBlack, "Courier New") fws1 = .5 fws2 = 1.5 dpText(hFile, fws1, fws2, DDOC_LEFT, "any combination") fws1 = 18 dpFont(hFile, DDOC_FONTBOLD, fws1, vbBlack, "Arial") fws1 = .5 fws2 = 1.7 dpText(hFile, fws1, fws2, DDOC_LEFT, "of font") fws1 = 9 dpFont(hFile, DDOC_FONTITALIC, fws1, vbBlack, "Time New Roman") fws1 = .5 fws2 = 2.1 dpText(hFile, fws1, fws2, DDOC_LEFT, "and style") fws1 = 20 dpFont(hFile, DDOC_FONTSTRIKEOUT, fws1, vbBlack, "Arial") fws1 = .5 fws2 = 2.3 dpText(hFile, fws1, fws2, DDOC_LEFT, "is supported!") '- ALIGNMENT ' Oops, I'm sneaking in a line command for effect, even though this isn't the line demo! fws1 = 4.25 fws2 = 3.25 fws3 = 4.25 fws4 = 4.35 fws5 = 0 dpLine(hFile, fws1, fws2, fws3, fws4, fws5, vbBlack) fws1 = 10 dpFont(hFile, DDOC_FONTNORMAL, fws1, vbBlack, "Times New Roman") fws1 = 4.25 fws2 = 3.5 dpText(hFile, fws1, fws2, DDOC_RIGHT, "Text can be right justified!") fws1 = 4.25 fws2 = 3.75 dpText(hFile, fws1, fws2, DDOC_CENTER, "Text can be centred!") fws1 = 4.25 fws2 = 3.95 dpText(hFile, fws1, fws2, DDOC_LEFT, "Text can be left justified!") fws1 = 4.25 fws2 = 4.15 dpText(hFile, fws1, fws2, DDOC_DECIMAL, "Finally, decimal aligned $9.99") '- Colors fws1 = 24 dpFont(hFile, DDOC_FONTBOLD, fws1, vbMagenta, "Arial") fws1 = 4.5 fws2 = 7 dpText(hFile, fws1, fws2, DDOC_CENTER, "Colours") fws1 = 24 dpFont(hFile, DDOC_FONTBOLD, fws1, vbBlue, "Arial") fws1 = 4.25 fws2 = 7.4 dpText(hFile, fws1, fws2, DDOC_CENTER, "are") fws1 = 24 dpFont(hFile, DDOC_FONTBOLD, fws1, vbGreen, "Arial") fws1 = 4.25 fws2 = 7.8 dpText(hFile, fws1, fws2, DDOC_CENTER, "not") fws1 = 24 dpFont(hFile, DDOC_FONTBOLD, fws1, vbYellow, "Arial") fws1 = 4.25 fws2 = 8.2 dpText(hFile, fws1, fws2, DDOC_CENTER, "a") fws1 = 24 dpFont(hFile, DDOC_FONTBOLD, fws1, vbRed, "Arial") fws1 = 4.25 fws2 = 8.6 dpText(hFile, fws1, fws2, DDOC_CENTER, "problem") '- Various angled text output. dpNewPage(hFile, DDOC_PAPER_A4, DDOC_PORTRAIT, DDOC_BIN_UPPER) dpBookmark(hFile, "Angles") fws1 = 18 dpFont(hFile, DDOC_FONTNORMAL, fws1, vbBlack, "Calibri") fws1 = 6 fws2 = 1 angle=180 dpAngleText(hFile, fws1, fws2, angle, "Text can be printed upside down!") fws1 = 14 dpFont(hFile, DDOC_FONTBOLD, fws1, vbMagenta, "Times New Roman") fws1=5 fws2=5 FOR a = 0 TO 330 STEP 30 dpAngleText(hFile, fws1,fws2, a, "This text is at" + STR$(a) + " degrees") NEXT a fws1 = 18 dpFont(hFile, DDOC_FONTNORMAL, fws1, vbBlack, "Arial") fws1 = 1 fws2 = 5 angle=270 dpAngleText(hFile, fws1, fws2, angle, "Text can be printed") fws1 = 1 fws2 = 7.2 angle=330 dpAngleText(hFile, fws1, fws2, angle, "at any angle") dpEndDoc(hFile, endCode) ENDIF ENDSUB '------------------------------------------------------------------------ SUB Demo_Wrap() lh = .17 zTemp = "" hFile = dpStartDoc(0, "Wrapping Text", zTemp, DDOC_INCH, 0, DDOC_PORTRAIT, 0, DDOC_ZOOMFIT) IF hFile < 1 MESSAGEBOX (0,STR$(hFile),"Initialise Document Error",64) ELSE '- Wrapping text is a little complicated. If you take a minute ' to think about what you want the computer to do, it gets a little easier ... ' The object when wrapping text is to give the dDoc engine a bunch of text to print. You ' need to tell it the rectangle in which to fit the text. ' The engine will then go and print the text, fitting it in the rectange. At this ' point, you need to know two things ... ' 1. How much text is left to print ' 2. How may lines of text did it print. ' The dDoc engine will tell you both of these things. ' dpWrapText will return the number of characters actually printed. dpWrapCount will tell you ' how many lines of text were printed in the last call to dpWrapText. '- To show how to do this, I'll first need to build a long string of text... zText = "This is a test of a long string of text wrapped into " zText = zText + "a rectangle. It will wrap text in the rectangle " zText = zText + "until there is no more text to wrap or until " zText = zText + "the rectangle has been filled. Besides the text " zText = zText + "to print and the defining rectangle, you need " zText = zText + "to tell the engine how much leading to use. " zText = zText + "The leading (as I have defined it anyway :) " zText = zText + "is the amount of space from the top of one line " zText = zText + "of text to the top of the next line of text. " zText = zText + "Breaking at paragraphs is very easy, just put " zText = zText + "carriage returns (and optionally line feeds) " zText = zText + CHR$(13) + CHR$(13) + "If you look at the code, " zText = zText + "you will notice that I have inserted 2 carriage returns " zText = zText + "before this sentence. dDoc respects the carriage return " zText = zText + "and starts the text following it on the next line. " zText = zText + "It treats a carriage return followed by a line feed (" zText = zText + "ascii 13 followed by ascii 10) the same as a single " zText = zText + "carriage return." fws1 = 9 dpFont(hFile, DDOC_FONTBOLD, fws1, vbBlue, "Arial") fws1 = 2 fws2 = 8 dpText(hFile, fws1, fws2, DDOC_LEFT, "The text above is wrapped in a rectangle") fws1 = 2 fws2 = 8.2 dpText(hFile, fws1, fws2, DDOC_LEFT, "1 inch over and 1 inch down to 3 inches") fws1 = 2 fws2 = 8.4 dpText(hFile, fws1, fws2, DDOC_LEFT, "over and 3 inches down") fws1 = 10 dpFont(hFile, DDOC_FONTNORMAL, fws1, vbBlack, "Times New Roman") iLen = LEN(zText) DO fws1 = 1 fws2 = 1 fws3 = 3 fws4 = 3 iPrinted = dpWrapText(hFile, fws1, fws2, fws3, fws4, lh, zText) iLen = iLen - iPrinted IF iLen > 1 dpNewPage(hFile, DDOC_PAPER_A4, DDOC_PORTRAIT, DDOC_BIN_AUTO) fws5 = 9 dpFont(hFile, DDOC_FONTBOLD, fws5, vbBlue, "Arial") fws6 = 2 fws7 = 8 dpText(hFile, fws6, fws7, DDOC_LEFT, "The text above is wrapped in a rectangle") fws6 = 2 fws7 = 8.2 dpText(hFile, fws6, fws7, DDOC_LEFT, "1 inch over and 1 inch down to 3 inches") fws6 = 2 fws7 = 8.4 dpText(hFile, fws6, fws7, DDOC_LEFT, "over and 3 inches down.") fws8 = 10 dpFont(hFile, DDOC_FONTNORMAL, fws8, vbBlack, "Times New Roman") zText = MID$(zText, iPrinted) ENDIF UNTIL iLen < 1 '- Let's print some text on the line that follows the above wrapped text. iLinesPrinted = dpWrapCount(hFile) fws1 = 9 dpFont(hFile, DDOC_FONTNORMAL, fws1, vbMagenta, "Arial") zText = "This line follows the wrapped text and shows how to use dpWrapCount" fws1 = 1 fws2 = iLinesPrinted * lh + 1 dpText(hFile, fws1, fws2, DDOC_LEFT, zText) dpEndDoc(hFile, endCode) ENDIF ENDSUB '------------------------------------------------------------------------ SUB Demo_Graphic() lh = .17 zTemp = "" xFile = GETSTARTPATH+"dDoc.bmp" hFile = dpStartDoc(0, "Lines Rectangles, and Bitmap Demo", zTemp, DDOC_INCH, 0, DDOC_PORTRAIT, 0, DDOC_ZOOMFIT) IF hFile < 1 MESSAGEBOX (0,STR$(hFile),"Initialise Document Error",64) ELSE '- Graphic File IF(OPENFILE(myfile,xFile,"R") <> 0) MESSAGEBOX (0,"dDoc.bmp","Missing File Error",64) ELSE CLOSEFILE myfile fws1 = .5 fws2 = .5 fws3 = 2 fws4 = 1 dpGraphic(hFile, fws1, fws2, fws3, fws4, xFile) ENDIF '- Print header fws1 = 18 dpFont(hFile, DDOC_FONTBOLD, fws1, vbBlue, "Arial") fws1 = 8.2 fws2 = .5 dpText(hFile, fws1, fws2, DDOC_RIGHT, "INVOICE") '- Draw a light shaded box for the address to go in. ' Note that I put a Red "Hair Line" (0 as border width) around the box. fws1 = .4 fws2 = 2 fws3 = 3.6 fws4 = 3.25 fws5 = 0 dpRect(hFile, fws1, fws2, fws3, fws4, fws5, LIGHT_SHADE, vbMagenta) '- Print the address information fws1 = 9 fws2 = 0 dpFont(hFile, DDOC_FONTBOLD, fws1, fws2, "Arial") fws1 = .5 fws2 = 2.1 dpText(hFile, fws1, fws2, DDOC_LEFT, "Ship To:") fws1 = 9 fws2 = 0 dpFont(hFile, DDOC_FONTNORMAL, fws1, fws2, "Arial") fws1 = .75 fws2 = 2.55 dpText(hFile, fws1, fws2, DDOC_LEFT, "Don Dickinson") fws1 = .75 fws2 = 2.75 dpText(hFile, fws1, fws2, DDOC_LEFT, "5229 6th Street NE") fws1 = .75 fws2 = 2.95 dpText(hFile, fws1, fws2, DDOC_LEFT, "Columbia Hts, MN 55421") '- A light shaded box will also highlight the List of items. Note that the -1 passed in the ' border width parameter will tell the engine to not print a line bordering the rectangle. fws1 = .4 fws2 = 3.6 fws3 = 8.2 fws4 = 3.9 fws5 = -1 dpRect(hFile, fws1, fws2, fws3, fws4, fws5, LIGHT_SHADE, 0) fws1 = 9 fws2 = 0 dpFont(hFile, DDOC_FONTBOLD, fws1, fws2, "Arial") fws1 = .75 fws2 = 3.7 dpText(hFile, fws1, fws2, DDOC_RIGHT, "Qty") fws1 = .85 fws2 = 3.7 dpText(hFile, fws1, fws2, DDOC_LEFT, "Desc") fws1 = 6 fws2 = 3.7 dpText(hFile, fws1, fws2, DDOC_CENTER, "Price") fws1 = 7.5 fws2 = 3.7 dpText(hFile, fws1, fws2, DDOC_CENTER, "Total") '- Items. ' Note that the cy variable keeps track of our current Y position on the page. If I were reading the lines out of a database, ' I would check to see if cy got too close to the bottom of the page and start a new ' one. In this case, I'm just printing 2 lines, so no worry about a new page. cy = 4 fws1 = 9 fws2 = 0 dpFont(hFile, DDOC_FONTNORMAL, fws1, fws2, "Arial") fws1 = .75 xFmt = USING("##",5) dpText(hFile, fws1, cy, DDOC_RIGHT, xFmt) fws1 = .85 dpText(hFile, fws1, cy, DDOC_LEFT, "Part #1") fws1 = 6 xFmt = USING("#.##",3.5) dpText(hFile, fws1, cy, DDOC_DECIMAL, xFmt) fws1 = 7.5 xFmt = USING("##.##",17.5) dpText(hFile, fws1, cy, DDOC_DECIMAL, xFmt) cy = cy + lh fws1 = .75 xFmt = USING("#0",1) dpText(hFile, fws1, cy, DDOC_RIGHT, xFmt) fws1 = .85 dpText(hFile, fws1, cy, DDOC_LEFT, "Part #2") fws1 = 6 xFmt = USING("##.##",1.11) dpText(hFile, fws1, cy, DDOC_DECIMAL, xFmt) fws1 = 7.5 xFmt = USING("##.##",1.11) dpText(hFile, fws1, cy, DDOC_DECIMAL, xFmt) '- Some wrapped text, surrounded by a box. This call prints a rectangle with a 5 Point ' border and a white background. Print the rectangle before the text, or the rectangle ' will overwrite the text. fws1 = .65 fws2 = 6.9 fws3 = 4.35 fws4 = 9.5 fws5 = 5 dpRect(hFile, fws1, fws2, fws3, fws4, fws5, LIGHT_SHADE, 0) fws1 = 10 fws2 = 0 dpFont(hFile, DDOC_FONTNORMAL, fws1, fws2, "Times New Roman") zText = "Note:" + Chr$(13) + "This order comes with a 30 day, " zText = zText + "money-back guarantee. If for any reason, you are un-satisfied " zText = zText + "with the dDoc Print Preview system, you may return it to the " zText = zText + "author for a full refund. " + Chr$(13) + Chr$(10) + Chr$(13) zText = zText + Chr$(10) + "dDoc Print Preview is written entirely with Power " zText = zText + "Basic's PB/DLL compiler. It is a real, machine code, win32 " zText = zText + "application. Because it is written in native code, it is fast, " zText = zText + "lean, and has no run-time requirements. Just distribute dDoc.exe " zText = zText + "(< 70k) and either dDoc16.dll or dDoc32.dll (< 50k) with your " zText = zText + "application." fws1 = .75 fws2 = 7 fws3 = 4 fws4 = 9.5 iLeft = dpWrapText(hFile, fws1, fws2, fws3, fws4, lh, zText) '- Footer consists of lines and rectangles. fws1 = .4 fws2 = 10.25 fws3 = 8.2 fws4 = 10.25 fws5 = .5 dpLine(hFile, fws1, fws2, fws3, fws4, fws5, vbBlue) fws1 = .4 fws2 = 10.25 fws3 = 2 fws4 = 10.55 fws5 = 0 dpRect(hFile, fws1, fws2, fws3, fws4, fws5, vbBlue, vbBlue) fws1 = 10 dpFont(hFile, DDOC_FONTBOLD, fws1, vbWhite, "Arial") fws1 = .5 fws2 = 10.3 dpText(hFile, .5, 10.3, DDOC_LEFT, "dDoc Print Preview") fws1 = 9 fws2 = 0 dpFont(hFile, DDOC_FONTITALIC, fws1, fws2, "Arial") fws1 = 7.7 fws2 = 10.4 dpText(hFile, fws1, fws2, DDOC_RIGHT, "Page") fws1 = 7.8 fws2 = 10.4 dpPageNo(hFile, fws1, fws2, DDOC_LEFT, 0) fws1 = 7.95 fws2 = 10.4 dpText(hFile, fws1, fws2, DDOC_LEFT, "of") fws1 = 8.2 fws2 = 10.4 dpPageCount(hFile, fws1, fws2, DDOC_RIGHT, 0) dpEndDoc(hFile, endCode) ENDIF ENDSUB '------------------------------------------------------------------------ SUB Demo_Bookmark() lh = .17 zTemp = "" hFile = dpStartDoc(0, "Bookmark Demo", zTemp, DDOC_INCH, DDOC_PAPER_A4, DDOC_PORTRAIT, DDOC_BIN_AUTO, DDOC_ZOOMFIT) IF hFile < 1 MESSAGEBOX (0,STR$(hFile),"Initialise Document Error",64) ELSE '- A bookmark to a page can be added at any time during page creation. These bookmarks will ' be shown in a drop-down list at the top of the preview screen. Note that you ' may bookmark a single page multiple times. When a user selects a bookmark ' from the drop-down, the viewer will jump to the referenced page. dpBookmark(hFile, "Dickinson, Donald") fws1 = 18 dpFont(hFile, DDOC_FONTBOLD, fws1, vbBlue, "Arial") fws1 = 8.2 fws2 = .5 dpText(hFile, fws1, fws2, DDOC_RIGHT, "Don Dickinson") fws1 = 9 dpFont(hFile, DDOC_FONTBOLD, fws1, vbBlack, "Arial") fws1 = .5 fws2 = .75 dpText(hFile, fws1, fws2, DDOC_LEFT, "Address:") fws1 = 9 dpFont(hFile, DDOC_FONTNORMAL, fws1, vbBlack, "Arial") fws1 = .75 fws2 = .95 dpText(hFile, fws1, fws2, DDOC_LEFT, "Don Dickinson") fws2 = 1.15 dpText(hFile, fws1, fws2, DDOC_LEFT, "5229 6th Street NE") fws2 = 1.35 dpText(hFile, fws1, fws2, DDOC_LEFT, "Columbia Hts, MN 55421") fws2 = 1.55 dpText(hFile, fws1, fws2, DDOC_LEFT, "Email - ddickinson@usinternet.com") '- Before ending the page, let me add the page number and page count with the super special functions that I ' created for this purpose. Note that these functions, as other text functions, respect the current font setting. fws1 = 9 dpFont(hFile, DDOC_FONTITALIC, fws1, vbBlack, "Times New Roman") fws1 = 7.7 fws2 = 10.25 dpPageNo(hFile, fws1, fws2, DDOC_RIGHT, 0) fws1 = 7.8 fws2 = 10.25 dpText(hFile, fws1, fws2, DDOC_LEFT, "of") fws1 = 8 fws2 = 10.25 dpPageCount(hFile, fws1, fws2, DDOC_LEFT, 0) '- Now we'll do the next page. Note that this page will contain two bookmark entries. dpNewPage(hFile, DDOC_PAPER_A4, DDOC_LANDSCAPE, DDOC_BIN_AUTO) dpBookmark(hFile, "Spike") fws1 = 18 dpFont(hFile, DDOC_FONTBOLD, fws1, vbBlue, "Arial") fws1 = .75 fws2 = .75 dpText(hFile, fws1, fws2, DDOC_LEFT, "Spike") fws1 = 9 dpFont(hFile, DDOC_FONTBOLD, fws1, vbBlack, "Arial") fws1 = .75 fws2 = 1.25 dpText(hFile, fws1, fws2, DDOC_LEFT, "Type: Dog") fws1 = 9 dpFont(hFile, DDOC_FONTNORMAL, fws1, vbBlack, "Arial") fws1 = .775 fws2 = 1.45 dpText(hFile, fws1, fws2, DDOC_LEFT, "Note: Very Large, Eats everything") '- Entry #2 on the same page dpBookmark(hFile, "KC") fws1 = 18 dpFont(hFile, DDOC_FONTBOLD, fws1, vbBlue, "Arial") fws1 = 6.25 fws2 = .75 dpText(hFile, fws1, fws2, DDOC_LEFT, "KC") fws1 = 9 dpFont(hFile, DDOC_FONTBOLD, fws1, vbBlack, "Arial") fws1 = 6.25 fws2 = 1.25 dpText(hFile, fws1, fws2, DDOC_LEFT, "Type: Dog") fws1 = 9 dpFont(hFile, DDOC_FONTNORMAL, fws1, vbBlack, "Arial") fws1 = 6.25 fws2 = 1.45 dpText(hFile, fws1, fws2, DDOC_LEFT, "Note: Not quite as large, but equally hungry.") '- More text fws1 = 12 dpFont(hFile, DDOC_FONTBOLD, fws1, vbBlue, "Arial") fws1 = 5.5 fws2 = 7 dpText(hFile, fws1, fws2, DDOC_CENTER, "You are free to mix landscape and portrait within a document!") '- Page Number fws1 = 9 dpFont(hFile, DDOC_FONTITALIC, fws1, vbBlack, "Times New Roman") fws1 = 10.25 fws2 = 7.75 dpPageNo(hFile, fws1, fws2, DDOC_RIGHT, 0) fws1 = 10.3 fws2 = 7.75 dpText(hFile, fws1, fws2, DDOC_LEFT, "of") fws1 = 10.5 fws2 = 7.75 dpPageCount(hFile, fws1, fws2, DDOC_LEFT, 0) '- On to the final page dpNewPage(hFile, DDOC_PAPER_A4, DDOC_PORTRAIT, DDOC_BIN_AUTO) dpBookmark(hFile, "Dickinson, Tammy") fws1 = 18 dpFont(hFile, DDOC_FONTBOLD, fws1, vbBlue, "Arial") fws1 = 8.2 fws2 = .5 dpText(hFile, fws1, fws2, DDOC_RIGHT, "Tammy Dickinson") fws1 = 9 dpFont(hFile, DDOC_FONTBOLD, fws1, vbBlack, "Arial") fws1 = .75 fws2 = .75 dpText(hFile, fws1, fws2, DDOC_LEFT, "Type: Wife") fws1 = 9 dpFont(hFile, DDOC_FONTNORMAL, fws1, vbBlack, "Arial") fws1 = .75 fws2 = .95 dpText(hFile, fws1, fws2, DDOC_LEFT, "Note: Not as hungry as dogs, but not yet fully house-broken.") '-Final Page Number fws1 = 9 dpFont(hFile, DDOC_FONTITALIC, fws1, vbBlack, "Times New Roman") fws1 = 7.7 fws2 = 10.25 dpPageNo(hFile, fws1, fws2, DDOC_RIGHT, 0) fws1 = 7.8 fws2 = 10.25 dpText(hFile, fws1, fws2, DDOC_LEFT, "of") fws1 = 8 fws2 = 10.25 dpPageCount(hFile, fws1, fws2, DDOC_LEFT, 0) '- That's it, show the document. dpEndDoc(hFile, endCode) ENDIF ENDSUB '------------------------------------------------------------------------ SUB Demo_Labels() '- Make sure we can find the mailing labels before starting. xFile = GETSTARTPATH+"ddocml.ini" IF(OPENFILE(myfile,xFile,"R") <> 0) MESSAGEBOX (0,"ddocml.ini","Missing File Error",64) RETURN ELSE CLOSEFILE myfile ENDIF iHandle = dpStartDoc(0, "Mailing Label Demo", "", DDOC_INCH, DDOC_PAPER_A4, DDOC_PORTRAIT, DDOC_BIN_AUTO, DDOC_ZOOMFIT) IF iHandle > 0 el = dpMailInit(iHandle, xFile, "Avery5260", DDOC_CENTER) IF el <> 0 MESSAGEBOX (0,"Error: "+STR$(el),"Mail Labels Initialising",64) ELSE '- Note that the label engine respects the current font. I provide the dpPrintTemplate ' function to allow the programmer to display what the labels would look like if that particular label were used. fws1 = 8 dpFont(iHandle, DDOC_FONTITALIC, fws1, vbMagenta, "Courier New") dpBookmark(iHandle, "Left Aligned Template") dpPrintTemplate(iHandle, DDOC_LEFT) '- Print the template with a different font. dpNewPage(iHandle, DDOC_PAPER_A4, DDOC_PORTRAIT, DDOC_BIN_AUTO) fws1 = 12 dpFont(iHandle, DDOC_FONTNORMAL, fws1, 0xFF0000, "Times New Roman") dpBookmark(iHandle, "Centered Template") dpPrintTemplate(iHandle, DDOC_CENTER) '- Here's how to use the label engine. ' It's pretty easy. First, set the starting label (usually #1), then add text to the current label. ' If you exceed the number of lines on a label, the engine will ' call dpNextLabel for you. If you want to force the next label, use the dpNextLabel call. ' The current line on the label is incremented with each call to dpLabelText. dpNewPage(iHandle, DDOC_PAPER_A4, DDOC_PORTRAIT, DDOC_BIN_AUTO) fws1 = 9 fws2 = 0 dpFont(iHandle, DDOC_FONTNORMAL, fws1, fws2, "Times New Roman") dpBookmark(iHandle, "Usage Example") dpSetLabel(iHandle, 1) dpLabelText(iHandle, "Line 1") dpLabelText(iHandle, "Line 21") dpLabelText(iHandle, "Line 322") dpLabelText(iHandle, "Line 4333") dpNextLabel(iHandle) dpLabelText(iHandle, "Line 1") dpLabelText(iHandle, "Line 2") dpLabelText(iHandle, "Line 3") dpNextLabel(iHandle) dpLabelText(iHandle, "Line 1") dpLabelText(iHandle, "Line 2") dpNextLabel(iHandle) dpLabelText(iHandle, "Line 1") dpNextLabel(iHandle) '- Finally, you can obtain the location of any label on the page, including the current label (as done below). ' the dpLabelX and dpLabelY obtain the x and y positions of the current label line ' NOTE TO IBASIC USERS! ' The following three lines are commented out because for some reason they cause a Microsoft ' error. Perhaps someone could work on them and post the fix to other IBasic users ' dpLabelX(iHandle,x) ' dpLabelY(iHandle,y) ' dpText(iHandle, x, y, DDOC_LEFT,"This is where the next label would be") ENDIF dpEndDoc(iHandle,endCode) ELSE MESSAGEBOX (0,"iHandle "+STR$(iHandle),"StartDoc Initialising",64) ENDIF ENDSUB