home *** CD-ROM | disk | FTP | other *** search
-
- {*******************************************************}
- { }
- { Turbo Pascal Runtime Library }
- { Windows Simplified Printer Interface Unit }
- { }
- { Copyright (c) 1991,92 Borland International }
- { }
- {*******************************************************}
-
- unit WinPrn;
-
- {$S-}
-
- interface
-
- uses WinTypes;
-
- { AbortPrn will cause all unprinted portions of the writes to the }
- { file to be thrown away. Note: the file still must be closed. }
-
- procedure AbortPrn(var F: Text);
-
- { AssignPrn assigns a file to a printer. The Device, Driver, and }
- { Port can be retrieved from the WIN.INI file's [device] section }
- { or from the [windows] sections 'device' string. If Device is nil }
- { the default printer is used. }
-
- procedure AssignPrn(var F: Text; Device, Driver, Port: PChar);
-
- { AssignDefPrn calls AssignPrn with Device equal to nil. }
-
- procedure AssignDefPrn(var F: Text);
-
- { SetPrnFont will cause the file to begin printing using the given }
- { font. The old font is returned. }
-
- function SetPrnFont(var F: Text; Font: HFont): HFont;
-
- { TitlePrn will give a title to the file being printed which is }
- { displayed by Window's Print Manager. For this routine to have }
- { effect it needs to be called before ReWrite. }
-
- procedure TitlePrn(var F: Text; Title: PChar);
-
- { ProcessPrnMessage is called whenever a message is received by }
- { WinPrn's abort procedure. If the function returns false, the }
- { message is translated and dispatched, otherwise it is ignored. }
- { Use this variable if you wish modeless dialogs to continue to }
- { operate while printing. (Note: Since ObjectWindow automatically }
- { initializes this variable for KBHandler's, no special action is }
- { necessary when using ObjectWindows). }
-
- var
- ProcessPrnMessage: function (var Msg: TMsg): Boolean;
-
- implementation
-
- uses
- WinProcs, WinDos, Strings;
-
- { ---------------------------------------------------------------- }
- { Internal helper routines --------------------------------------- }
- { ---------------------------------------------------------------- }
-
- const
- wpInvalidDevice = 230;
- wpTooManyAborted = 231;
- wpPrintingError = 232;
-
- { Printer abort manager ------------------------------------------ }
-
- var
- AbortList: array[1..8] of HDC; { List of aborted printings }
- const
- AbortListLen: Byte = 0;
-
- { Abort ---------------------------------------------------------- }
- { Add the given DC to the abort list }
-
- procedure Abort(DC: HDC);
- begin
- if AbortListLen < SizeOf(AbortList) then
- begin
- Inc(AbortListLen);
- AbortList[AbortListLen] := DC;
- end
- else
- InOutRes := wpTooManyAborted;
- end;
-
- { UnAbort -------------------------------------------------------- }
- { Remove a DC value from the abort list. If not in the list }
- { ignore it. }
-
- procedure UnAbort(DC: HDC);
- var
- I: Byte;
- begin
- for I := 1 to AbortListLen do
- if DC = AbortList[I] then
- begin
- if AbortListLen <> I then
- Move(AbortList[I], AbortList[I + 1], AbortListLen - I - 1);
- Dec(AbortListLen);
- Exit;
- end;
- end;
-
- { IsAbort -------------------------------------------------------- }
- { Is the given DC in the abort list? }
-
- function IsAborted(DC: HDC): Bool;
- var
- I: Byte;
- begin
- for I := 1 to AbortListLen do
- if DC = AbortList[I] then
- begin
- IsAborted := True;
- Exit;
- end;
- IsAborted := False;
- end;
-
- { PrnRec --------------------------------------------------------- }
- { Printer data record }
-
- type
- PrnRec = record
- DC: HDC; { Printer device context }
- case Integer of
- 0: (
- Title: PChar); { Title of the printout }
- 1: (
- Cur: TPoint; { Next position to write text }
- Finish: TPoint; { End of the pritable area }
- Height: Word; { Height of the current line }
- Status: Word); { Error status of the printer }
- 2: (
- Tmp: array[1..14] of Char);
- end;
-
- { NewPage -------------------------------------------------------- }
- { Start a new page. }
-
- procedure NewPage(var Prn: PrnRec);
- begin
- with Prn do
- begin
- LongInt(Cur) := 0;
- if not IsAborted(DC) and
- (Escape(DC, NewFrame, 0, nil, nil) <= 0) then
- Status := wpPrintingError;
- end;
- end;
-
- { NewLine -------------------------------------------------------- }
- { Start a new line on the current page, if no more lines left }
- { start a new page. }
-
- procedure NewLine(var Prn: PrnRec);
-
- function CharHeight: Word;
- var
- Metrics: TTextMetric;
- begin
- GetTextMetrics(Prn.DC, Metrics);
- CharHeight := Metrics.tmHeight;
- end;
-
- begin
- with Prn do
- begin
- Cur.X := 0;
-
- if Height = 0 then
- { two new lines in a row, use the current character height }
- Inc(Cur.Y, CharHeight)
- else
- { Advance the height of the tallest font }
- Inc(Cur.Y, Height);
- if Cur.Y > (Finish.Y - (Height * 2)) then NewPage(Prn);
- Height := 0;
- end;
- end;
-
- { PrnOutStr ------------------------------------------------------ }
- { Print a string to the printer without regard to special }
- { characters. These should handled by the caller. }
-
- procedure PrnOutStr(var Prn: PrnRec; Text: PChar; Len: Integer);
- var
- Extent: TPoint; { Size of the current text }
- L: Integer; { Temporary used for printing }
- begin
- with Prn do
- begin
- while Len > 0 do
- begin
- L := Len;
- LongInt(Extent) := GetTextExtent(DC, Text, L);
-
- { Wrap the text to the line }
- while (L > 0) and (Extent.X + Cur.X > Finish.X) do
- begin
- Dec(L);
- LongInt(Extent) := GetTextExtent(DC, Text, L);
- end;
-
- { Adjust the current line height }
- if Extent.Y > Height then Height := Extent.Y;
-
- if not IsAborted(DC) then
- TextOut(DC, Cur.X, Cur.Y, Text, L);
-
- Dec(Len, L);
- Inc(Text, L);
- if Len > 0 then NewLine(Prn)
- else Cur.X := Extent.X;
- end;
- end;
- end;
-
- { PrnString ------------------------------------------------------ }
- { Print a string to the printer handling special characters. }
-
- procedure PrnString(var Prn: PrnRec; Text: PChar; Len: Integer);
- var
- L: Integer; { Temporary used for printing }
- TabWidth: Word; { Width (in pixels) of a tab }
-
- { Flush to the printer the non-specal characters found so far }
- procedure Flush;
- begin
- if L <> 0 then
- PrnOutStr(Prn, Text, L);
- Inc(Text, L + 1);
- Dec(Len, L + 1);
- L := 0;
- end;
-
- { Calculate the average character width }
- function AvgCharWidth: Word;
- var
- Metrics: TTextMetric;
- begin
- GetTextMetrics(Prn.DC, Metrics);
- AvgCharWidth := Metrics.tmAveCharWidth;
- end;
-
- begin
- L := 0;
- with Prn do
- begin
- while L < Len do
- begin
- case Text[L] of
- #9:
- begin
- Flush;
- TabWidth := AvgCharWidth * 8;
- Inc(Cur.X, TabWidth - ((Cur.X + TabWidth + 1)
- mod TabWidth) + 1);
- if Cur.X > Finish.X then NewLine(Prn);
- end;
- #13: Flush;
- #10:
- begin
- Flush;
- NewLine(Prn);
- end;
- ^L:
- begin
- Flush;
- NewPage(Prn);
- end;
- else
- Inc(L);
- end;
- end;
- end;
- Flush;
- end;
-
- { PrnInput ------------------------------------------------------- }
- { Called when a Read or Readln is applied to a printer file. }
- { Since reading is illegal this routine tells the I/O system that }
- { no characters where read, which generates a runtime error. }
-
- function PrnInput(var F: TTextRec): Integer; far;
- begin
- with F do
- begin
- BufPos := 0;
- BufEnd := 0;
- end;
- PrnInput := 0;
- end;
-
- { PrnOutput ------------------------------------------------------ }
- { Called when a Write or Writeln is applied to a printer file. }
- { The calls PrnString to write the text in the buffer to the }
- { printer. }
-
- function PrnOutput(var F: TTextRec): Integer; far;
- begin
- with F do
- begin
- PrnString(PrnRec(UserData), PChar(BufPtr), BufPos);
- BufPos := 0;
- PrnOutput := PrnRec(UserData).Status;
- end;
- end;
-
- { PrnIgnore ------------------------------------------------------ }
- { Will ignore certain requests by the I/O system such as flush }
- { while doing an input. }
-
- function PrnIgnore(var F: TTextRec): Integer; far;
- begin
- PrnIgnore := 0;
- end;
-
- { AbortProc ------------------------------------------------------ }
- { Abort procedure used for printing. }
-
- var
- AbortProcInst: TFarProc; { Instance of the abort proc }
-
- function AbortProc(Prn: HDC; Code: Integer): Bool; export;
- var
- Msg: TMsg;
- UserAbort: Boolean;
- begin
- UserAbort := IsAborted(Prn);
- while not UserAbort and PeekMessage(Msg, 0, 0, 0, pm_Remove) do
- if not ProcessPrnMessage(Msg) then
- begin
- TranslateMessage(Msg);
- DispatchMessage(Msg);
- end;
- AbortProc := not UserAbort;
- end;
-
- { PrnClose ------------------------------------------------------- }
- { Deallocates the resources allocated to the printer file. }
-
- function PrnClose(var F: TTextRec): Integer; far;
- begin
- with PrnRec(F.UserData) do
- begin
- if DC <> 0 then
- begin
- if not IsAborted(DC) then
- begin
- NewPage(PrnRec(F.UserData));
- if Escape(DC, EndDoc, 0, nil, nil) <= 0 then
- Status := wpPrintingError;
- end;
- DeleteDC(DC);
- UnAbort(DC);
- end;
- PrnClose := Status;
- end;
- end;
-
- { PrnOpen -------------------------------------------------------- }
- { Called to open I/O on a printer file. Sets up the TTextFile to }
- { point to printer I/O functions. }
-
- function PrnOpen(var F: TTextRec): Integer; far;
- const
- Blank: array[0..0] of Char = '';
- begin
- with F, PrnRec(UserData) do
- begin
- if Mode = fmInput then
- begin
- InOutFunc := @PrnInput;
- FlushFunc := @PrnIgnore;
- CloseFunc := @PrnIgnore;
- end
- else
- begin
- Mode := fmOutput;
- InOutFunc := @PrnOutput;
- FlushFunc := @PrnOutput;
- CloseFunc := @PrnClose;
-
- { Setup the DC for printing }
- Status := Escape(DC, SetAbortProc, 0, PChar(AbortProcInst), nil);
- if Status > 0 then
- if Title <> nil then
- begin
- Status := Escape(DC, StartDoc, StrLen(Title), Title, nil);
- StrDispose(Title);
- end
- else
- Status := Escape(DC, StartDoc, 0, @Blank, nil);
-
- if Status <= 0 then
- Status := wpPrintingError
- else
- Status := 0;
-
- { Initialize the printer record }
- LongInt(Cur) := 0;
- Finish.X := GetDeviceCaps(DC, HorzRes);
- Finish.Y := GetDeviceCaps(DC, VertRes);
- Height := 0;
- end;
- PrnOpen := Status;
- end;
- end;
-
- { FetchStr ------------------------------------------------------- }
- { Returns a pointer to the first comma delimited field pointed }
- { to by Str. It replaces the comma with a #0 and moves the Str }
- { to the beginning of the next string (skipping white space). }
- { Str will point to a #0 character if no more strings are left. }
- { This routine is used to fetch strings out of text retrieved }
- { from WIN.INI. }
-
- function FetchStr(var Str: PChar): PChar;
- begin
- FetchStr := Str;
- if Str = nil then Exit;
- while (Str^ <> #0) and (Str^ <> ',') do
- Str := AnsiNext(Str);
- if Str^ = #0 then Exit;
- Str^ := #0;
- Inc(Str);
- while Str^ = ' ' do
- Str := AnsiNext(Str);
- end;
-
- { ---------------------------------------------------------------- }
- { External interface routines ------------------------------------ }
- { ---------------------------------------------------------------- }
-
- { AbortPrn ------------------------------------------------------- }
-
- procedure AbortPrn(var F: Text);
- begin
- Abort(PrnRec(TTextRec(F).UserData).DC);
- end;
-
- { AssignPrn ------------------------------------------------------ }
-
- procedure AssignPrn(var F: Text; Device, Driver, Port: PChar);
- var
- DeviceStr: array[0..80] of Char;
- P: PChar;
- begin
- if Device = nil then
- begin
- { Get the default printer device }
- GetProfileString('windows', 'device', '', DeviceStr,
- SizeOf(DeviceStr) - 1);
- P := DeviceStr;
- Device := FetchStr(P);
- Driver := FetchStr(P);
- Port := FetchStr(P);
- end;
- with TTextRec(F), PrnRec(UserData) do
- begin
- Mode := fmClosed;
- BufSize := SizeOf(Buffer);
- BufPtr := @Buffer;
- OpenFunc := @PrnOpen;
- Name[0] := #0;
- DC := CreateDC(Driver, Device, Port, nil);
- if DC = 0 then
- begin
- InOutRes := wpInvalidDevice;
- Exit;
- end;
- Title := nil;
- end;
- end;
-
- { AssignDefPrn --------------------------------------------------- }
-
- procedure AssignDefPrn(var F: Text);
- begin
- AssignPrn(F, nil, nil, nil);
- end;
-
- { SetPrnFont ----------------------------------------------------- }
-
- function SetPrnFont(var F: Text; Font: HFont): HFont;
- begin
- SetPrnFont := SelectObject(PrnRec(TTextRec(F).UserData).DC, Font);
- end;
-
- { TitlePrn ------------------------------------------------------- }
-
- procedure TitlePrn(var F: Text; Title: PChar);
- var
- S: array[0..31] of Char;
- begin
- { Limit title size to 31 characters plus 0 }
- StrLCopy(S, Title, SizeOf(S));
- PrnRec(TTextRec(F).UserData).Title := StrNew(S);
- end;
-
- { ---------------------------------------------------------------- }
-
- function DummyMsg(var Msg: TMsg): Boolean; far;
- begin
- DummyMsg := False;
- end;
-
- var
- SaveExit: Pointer; { Saves the old ExitProc }
-
- procedure ExitWinPrn; far;
- begin
- FreeProcInstance(AbortProcInst);
- ExitProc := SaveExit;
- end;
-
- begin
- ProcessPrnMessage := DummyMsg;
-
- AbortProcInst := MakeProcInstance(@AbortProc, hInstance);
-
- SaveExit := ExitProc;
- ExitProc := @ExitWinPrn;
- end.
-