home *** CD-ROM | disk | FTP | other *** search
-
-
-
-
-
-
-
- PRODUCT : Turbo Pascal NUMBER : 607
- VERSION : 1.0
- OS : Windows
- DATE : May 13, 1992 PAGE : 1/10
-
- TITLE : How to Print in Windows
-
-
-
-
- Printing in Windows is achieved with a device control associated
- with the printing device described in the WIN.INI. Before you
- start printing in your program, you will need to create a device
- control associated with your printer.
-
- To do this, you will call the function GetProfileString as
- follows.
-
- GetMem(Info, 80);
- GetProfileString('windows','device',',,', Info, 80);
-
- Where Info is defined to be of type PChar. The resulting ASCIIZ
- string will be placed in Info. Unfortunately, CreateDC requires
- three parameters, one for the driver, the printer type, and the
- port. If GetProfileString is successful, Info contains all the
- information required by CreateDC but contained in one string
- separated by semi-colons. These items must be parsed out of the
- string Info before CreateDC can be called. The following
- function is helpful in this task.
-
- function GetItem(var S:PChar): PChar;
- var
- P: PChar;
- I: Integer;
- begin
- i:=0;
- while (S[I]<>',') and (S[I]<>#0) do
- inc(I);
- S[I]:=#0;
- GetItem:=S;
-
- if S[0]<>#0 then S:= ;
- end;
-
- The function GetItem does not copy the strings but rather turns
- the larger string into a structure containing smaller component
- strings. Now separating the driver, printer type, and port
- information is fairly straight forward. Assuming that the PChar
- variables Driver, PrinterType, Port and TInfo have been
- predeclared, you would use the following assignments.
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- PRODUCT : Turbo Pascal NUMBER : 607
- VERSION : 1.0
- OS : Windows
- DATE : May 13, 1992 PAGE : 2/10
-
- TITLE : How to Print in Windows
-
-
-
-
- TInfo:=Info;
- PrinterType:=GetItem(Info);
- Driver:=GetItem(Info);
- Port:=GetItem(Info);
-
- The variable TInfo is necessary for a subsequent FreeMem call to
- free up the memory originally allocated for Info.
-
- At last, you may now call CreateDC with the appropriate
- parameters (assuming DC was previously declared to be of type
- HDC).
-
- DC:=CreateDC(Driver, PrinterType, Port, Nil);
-
- If for some reason CreateDC is not successful, it will return a
- value of zero.
-
- Now you are ready to start using the Escape function. Escape is
- a very special function as it allows access to device
- capabilities that are not supported by the Windows GDI. The
- second parameter to Escape represents the particular escape
- function to be used. Two fundamental escape functions always
- used when printing in Windows are STARTDOC and ENDDOC. These
- functions do any setup and shutdown required by the printer.
- Another important escape function is NEWFRAME. NEWFRAME forces a
- buffer flush and causes either a form feed operation or a page
- eject operation depending upon the type of printer used.
-
- To print some text, the following code illustrates the process
- involved.
-
- procedure Print;
- var
- TInfo, Info: PChar;
- Driver, PrinterType, Port: PChar;
- DC: HDC;
-
- begin
- GetMem(Info, 80);
- GetProfileString('windows', 'device', ',,', Info, 80);
-
- TInfo:=Info;
- Driver:=GetItem(Info);
-
-
-
-
-
-
-
-
-
-
-
-
-
- PRODUCT : Turbo Pascal NUMBER : 607
- VERSION : 1.0
- OS : Windows
- DATE : May 13, 1992 PAGE : 3/10
-
- TITLE : How to Print in Windows
-
-
-
-
- PrinterType:=GetItem(Info);
- Port:=GetItem(Info);
- DC:=CreateDC(PrinterType, Driver, Port, Nil);
- FreeMem(TInfo, 80);
-
- if Escape(DC, STARTDOC, 8,
- StrNew('Doc Name'), nil)<0then
- begin
- MessageBox(Window, 'Printing can not be started', nil,
- mb_Ok or mb_IconStop);
- exit;
- end;
-
- if Escape(DC, NEWFRAME, 0, nil, nil)<0 then
- begin
- MessageBox(Window, 'Paper can not be advanced', nil,
- mb_Ok or mb_IconStop);
- exit;
- end;
-
- TextOut(DC, 10, 10, 'This text is being printed', 26);
-
- if Escape(DC, NEWFRAME, 0, nil, nil)<0 then
- begin
- MessageBox(Window, 'Paper can not be advanced', nil,
- mb_Ok or mb_IconStop);
- exit;
- end;
-
- if Escape(DC, ENDDOC, 0, nil, nil)<0 then
- begin
- MessageBox(Window, 'Error Printing', nil,
- mb_Ok or mb_IconStop);
- exit;
- end;
- end;
-
- Notice that if Escape fails that it returns a value less than
- zero. The actual errors are governed by the spooler constants
- sp_Error, sp_OutOfDisk, sp_OutOfMemory, and sp_UserAbort. It is
- recommended that a NEWFRAME call precede and follow the intended
- output to ensure that the printer is working with a fresh piece
- of paper and flushes its buffer when printing ends.
-
-
-
-
-
-
-
-
-
-
-
-
-
- PRODUCT : Turbo Pascal NUMBER : 607
- VERSION : 1.0
- OS : Windows
- DATE : May 13, 1992 PAGE : 4/10
-
- TITLE : How to Print in Windows
-
-
-
-
- The coordinates used in TextOut are arbitrary. Exactly lines can
- be calculated from the values returned by GetTextMetrics as you
- would for normal output to the screen. See Chapter 4 of the
- Windows Reference Guide of TPW for a complete description of the
- TTextMetric type. The tmHeight, tmAveCharWidth, and
- tmMaxCharWidth fields will prove to be the most useful when
- determining line lengths and the number of characters per page.
- Use GetDeviceCaps to determine the maximum horizontal and
- vertical resolutions of your printer when calculating these
- values.
-
- Since device controls are used, printing graphics is a simple
- extension of what is done to display graphics on screen. Here's
- a procedure that copies a bitmap to the printer using the
- techniques that have been discussed so far.
-
- procedure HardCopy(HWindow: HWnd; BitMap: HBitMap);
- var
- DC, ScreenDC, MemDC: HDC;
- BM: TBitMap;
- OldBitMap: HBitMap;
- Info, TInfo: PChar;
- Driver, PrinterType, Port: PChar;
- begin
- GetMem(Info, 80);
- GetProfileString('windows', 'device', ',,', Info, 80);
- TInfo:=Info;
- Driver:=GetInfo(Info);
- PrinterType:=GetItem(Info);
- Port:=GetItem(Info);
-
- DC:=CreateDC(PrinterType, Driver, Port, Nil);
- Escape(DC, STARTDOC, 8, StrNew('HardCopy'), nil);
- Escape(DC, NEWFRAME, 0, nil, nil);
-
- ScreenDC:=GetDC(HWindow);
- MemDC:=CreateCompatibleDC(DC);
- ReleaseDC(HWindow, ScreenDC);
-
- OldBitMap:=SelectObject(MemDC, BitMap);
- GetObject(BitMap, sizeof(BM), @ BM);
- BitBlt(DC, 0,0, BM.bmWidth, BM.bmHeight,
- MemDC, 0, 0, SRCCOPY);
-
-
-
-
-
-
-
-
-
-
-
-
-
- PRODUCT : Turbo Pascal NUMBER : 607
- VERSION : 1.0
- OS : Windows
- DATE : May 13, 1992 PAGE : 5/10
-
- TITLE : How to Print in Windows
-
-
-
-
- Escape(DC, NEWFRAME, 0, nil, nil);
- Escape(DC, ENDDOC, 0, nil, nil);
-
- SelectObject(MemDC, OldBitMap);
- DeleteDC(MemDC);
- DeleteDC(DC);
- end;
-
- For clarity, this routine does not perform error checking in the
- manner of the previous example so use it with appropriate
- caution.
-
- As with BitBlt, you may use any of the other GDI functions with a
- DC associated with the printer. The only difficulty that you may
- run into in this regard is the capabilities of the printer
- itself. To determine if a printer can handle bitmaps, use the
- GetDeviceCaps function as follows.
-
- Value:=GetDeviceCaps(DC, RASTERCAPS);
- Value:=Value and rc_BitBlt;
-
- Assuming, DC to be associate with a printer device and Value to
- be declared as an integer, if the resulting contents of Value is
- not zero then the device has the ability to display bitmaps. See
- Device Capabilities under Chapter 1 of TPW's Windows Reference
- Guide for more on what GetDeviceCaps can do.
-
- Frequently, programs give user's the ability to change the
- setting of the printer. However, printers often have greatly
- different capabilities and it is impossible to determine what
- printers will be capable of in the future. Therefore, no one
- dialog is appropriate to change printer setting. Because of
- these facts, Windows requires the manufacturers of printers to
- supply drivers and incorporate into these drivers a dialog used
- to alter printer settings.
-
- There are two functions supported by the Windows API to call up
- this dialog DeviceMode and ExtDeviceMode. These functions do not
- exist in the API but rather are loaded from the driver directly.
- Before you can call on these functions you must obtain a driver
- handle. Here's how this would be done knowing what we know so
- far.
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- PRODUCT : Turbo Pascal NUMBER : 607
- VERSION : 1.0
- OS : Windows
- DATE : May 13, 1992 PAGE : 6/10
-
- TITLE : How to Print in Windows
-
-
-
-
- GetMem(FullDriver,13);
- GetProfileString('windows', 'device', ',,', Info, 80);
- TInfo:=Info;
- PrinterType:=GetItem(Info);
- Driver:=GetItem(Info);
- Port:=GetItem(Info);
- StrLCat(StrCopy(FullDriver,Driver),'.DRV',12);
- DriverHandle:=LoadLibrary(FullDriver);
-
- PrinterType, Driver, Port, Info, and TInfo you have seen above.
- FullDriver is declared to be PChar and DriverHandle is a THandle.
- FullDriver is necessary to provide the file extension to Driver
- as the function LoadLibrary requires a complete file name. All
- printer drivers have the file extension .DRV.
-
- ExtDeviceMode is a more advanced form of DeviceMode. It not only
- provides the dialog to allow user's change settings but also
- gives the means for the program to moniter and change the device
- settings. DeviceMode only provides the user dialog capability.
- However, ExtDeviceMode was introduced in version 3.0 of Windows
- and not all printer drivers provide a ExtDeviceMode function.
- But, all printer driver provide a DeviceMode function. So if
- ExtDeviceMode is not present, DeviceMode will be. The following
- code is appropriate for displaying the printer's dialog.
-
- P:=GetProcAddress(DriverHandle, 'ExtDeviceMode');
- if P<>nil then
- begin
- ExtDeviceMode:=TExtDeviceMode(P);
- Size:=ExtDeviceMode(Window, DriverHandle,
- OutModeRec^, PrinterType, Port,
- InModeRec^, nil, 0);
- GetMem(OutModeRec, Size);
- GetMem(InModeRec, Size);
- ExtDeviceMode(Window, DriverHandle,
- OutModeRec^, PrinterType, Port,
- InModeRec^, nil, dm_Prompt);
- FreeMem(OutModeRec, Size);
- FreeMem(InModeRec, Size);
- end
- else begin
- P:=GetProcAddress(DriverHandle, 'DeviceMode');
- DeviceMode:=TDeviceMode(P);
-
-
-
-
-
-
-
-
-
-
-
-
-
- PRODUCT : Turbo Pascal NUMBER : 607
- VERSION : 1.0
- OS : Windows
- DATE : May 13, 1992 PAGE : 7/10
-
- TITLE : How to Print in Windows
-
-
-
-
- DeviceMode(Window, DriverHandle, PrinterType, Port);
- end;
- FreeLibrary(DriverHandle);
-
- P is declared to be of type TFarProc; ExtDeviceMode is of type
- TExtDeviceMode which is supplied by the WinTypes unit (the same
- applies for DeviceMode and TDeviceMode). Both OutModeRec and
- InModeRec are declared to be of type PDevMode. These two pointers
- control the input and output to ExtDeviceMode where required.
-
- Notice that if the results of GetProcAddress(DriverHandle,
- 'ExtDeviceHandle'); are nil then ExtDeviceHandle cannot be
- provided by the printer. In this case, the code proceeds to the
- simple DeviceMode call.
-
- Before ExtDeviceMode can be called to prompt the user, it is a
- good idea to call ExtDeviceMode with its mode parameter (the 8th
- parameter) set to zero. The result will be the amount of space
- required for it input and output, TDevMode parameters. This is
- important as these records may not be the same size as the
- TDevMode type. After memory is allocated for these records, the
- data fields of the input record may then be initialized (see
- Chapter 4 of TPW's Windows Reference guide for more on TDevMode).
-
- Now ExtDeviceMode is called with the mode paramter set to
- dm_Prompt which displays and activates the printer's dialog.
- This constant can be combined with the other constants dm_Copy,
- dm_Modify, and dm_Update with Turbo's bitwise OR operator. (See
- Chapter 1 of TPW's Windows Reference Guide for information on
- these dm_ Device mode selections).
-
- Another important feature for printing is the Abort Dialog. An
- Abort Dialog is a dialog displayed when printing is taking place
- and gives the user of the program an opprotunity to halt printing
- before it is finished.
-
- The first thing to do, is create a dialog suitable for the task.
- Something like this .DLG file would serve (in a true DLG file all
- data for statement would appear on a single line). Though you
- may prefer to use a resource toolkit of some sort to build your
- dialog into a resource used by your program.
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- PRODUCT : Turbo Pascal NUMBER : 607
- VERSION : 1.0
- OS : Windows
- DATE : May 13, 1992 PAGE : 8/10
-
- TITLE : How to Print in Windows
-
-
-
-
- ABORTBOX DIALOG DISCARDABLE LOADONCALL PURE MOVEABLE 10, 37, 187,
- 67
- STYLE WS_POPUP | WS_VISIBLE | WS_CAPTION | 0x80L
- CAPTION "Printing in Progress"
- BEGIN
- CONTROL "Escape" 100, "BUTTON", WS_CHILD | WS_VISIBLE |
- WS_TABSTOP, 73, 37, 41, 16
- CONTROL "Press Escape to Stop Printing" 102, "STATIC", WS_CHILD
- | WS_VISIBLE, 44, 12, 99, 11
- END
-
- Next, using the Object Windows Library, you would define an
- object type to govern your Abort Dialog. Its actuall definition
- needs to be no more than something like the following.
-
- var
- Abort: Boolean;
- AbortWindow: HWindow;
- type
- PAbortDialog = ^TAbortDialog;
- TAbortDialog = object(TDlgWindow)
- procedure SetUpWindow; virtual;
- procedure WMCommand(var Msg: TMessage);
- virtual wm_First + wm_Command;
- end;
-
- procedure TAbortDialog.SetUpWindow;
- begin
- Abort:=false;
- SetFocus(HWindow);
- AbortWindow:=HWindow;
- end;
-
- procedure TAbortDialog.WMCommand(var Msg: TMessage);
- {Will be entered whenever a button, return key or escape key is
- pressed.}
- begin
- Abort:=true;
- end;
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- PRODUCT : Turbo Pascal NUMBER : 607
- VERSION : 1.0
- OS : Windows
- DATE : May 13, 1992 PAGE : 9/10
-
- TITLE : How to Print in Windows
-
-
-
-
- As any button press, return key press, or escape key press will
- abort printing only a WMCommand method is needed. InitDialog is
- necessary to set the focus to this dialog and to set the field
- Abort.
-
- Abort is used by the dialog to determine if printing has been
- aborted. To prevent interrupting printing while the dialog is
- displayed, a Call Back function is required to be installed.
- Most such functions call PeekMessage which checks the application
- queue for a message. If there are no messages, it returns and
- gives control to Windows. Here's a simple example of such a
- function.
-
- function AbortCallBack(DC: HDC; Code: Integer): Bool; export;
- var
- Msg: TMsg;
- begin
- While (not Abort) and PeekMessage(Msg, 0, 0, 0, pm_Remove) do
- if not IsDialogMessage(AbortWindow, Msg) then
- begin
- TranslateMessage(Msg);
- DispatchMessage(Msg);
- end;
- if Abort then AbortCallBack:=false else AbortCallBack:=true;
- end;
-
- PeekMessage yields control to Windows when a message is not
- available. If a message is received and it doesn't belong to the
- dialog, it is sent along using the customary TranslateMessage and
- DispatchMessage functions. After it checks to see if the user
- has aborted and if so, AbortCallBack returns false. Otherwise,
- it simply returns true which indicates printing may continue.
-
- Now you have all that you need to install you Abort Dialog.
- Before, your call to Escape for the STARTDOC, the following code
- should be executed (assuming that you have previously declared a
- variable AbortDialog of type PAbortDialog and a variable called
- AbortCallBackProc of type TFarProc to hold the address of the
- callback function).
-
- AbortDialog:=New(PAbortDialog,
- Init(Application^.MainWindow, 'ABORTBOX'));
- AbortDialog:=PAbortDialog(Application^.
-
-
-
-
-
-
-
-
-
-
-
-
-
- PRODUCT : Turbo Pascal NUMBER : 607
- VERSION : 1.0
- OS : Windows
- DATE : May 13, 1992 PAGE : 10/10
-
- TITLE : How to Print in Windows
-
-
-
-
- MakeWindow(AbortDialog));
- AbortCallBackProc:=MakeProcInstance(@ AbortCallBack,
- HInstance);
- Escape(DC, SETABORTPROC, 0, AbortCallBackProc, nil);
-
- Now you would call Escape with the appropriate STARTDOC,
- NEWFRAME, and ENDDOC parameters as illustrated before. However,
- it is vital to check for errors after a NEWFRAME escape call.
- For printing actually occurs during the NEWFRAME. If an error or
- user abort occurs Escape will return a value less than zero. If
- this happens do not allow the ENDDOC escape call take place; for
- the GDI automatically terminates the operation before returning
- the error value. Also, if an error other than a user abort
- occurs, use AbortDialog^.CloseWindow to remove the dialog from
- view. If the user cancles the print operation, Windows removes
- the dialog automatically.
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-