home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Shareware BBS: 10 Tools / 10-Tools.zip / sibdemo3.zip / SOURCE.DAT / SOURCE / SPCC / PRINTERS.PAS < prev    next >
Pascal/Delphi Source File  |  1997-12-03  |  22KB  |  834 lines

  1.  
  2. {╔══════════════════════════════════════════════════════════════════════════╗
  3.  ║                                                                          ║
  4.  ║     Sibyl Portable Component Classes                                     ║
  5.  ║                                                                          ║
  6.  ║     Copyright (C) 1995,97 SpeedSoft Germany,   All rights reserved.      ║
  7.  ║                                                                          ║
  8.  ╚══════════════════════════════════════════════════════════════════════════╝}
  9.  
  10. {************************************************}
  11. {                                                }
  12. { Speed-Pascal 2.0 Printer support Unit          }
  13. {                                                }
  14. { Copyright (C) 1996-1997 Joerg Pleumann         }
  15. {                                                }
  16. { Please mail All bugs And suggestions To:       }
  17. {                                                }
  18. { Internet: pleumann @ uni-duisburg.de           }
  19. { FidoNet:  Joerg Pleumann @ 2:2448/136.6        }
  20. {                                                }
  21. {************************************************}
  22.  
  23. Unit Printers;
  24.  
  25. Interface
  26.  
  27. {$IFDEF OS2}
  28. Uses
  29.   Os2Def, PmSpl;
  30. {$ENDIF}
  31.  
  32. Uses SysUtils, Classes, Forms, Graphics;
  33.  
  34. Type
  35.   EPrinter = Class(Exception);
  36.     { raised In Case Of Printer errors. }
  37.  
  38.   TPrinterOrientation = (poPortrait, poLandscape);
  39.     { used For Orientation Property. }
  40.  
  41.   TPrinterState = (psNoHandle, psHandleIC, psHandleDC);
  42.     { internal. }
  43.  
  44.   {$IFDEF OS2}
  45.   TQueueInfo = Array[0..1023] Of PRQINFO3;
  46.   PQueueInfo = ^TQueueInfo;
  47.     { internal. }
  48.  
  49.   TDeviceInfo = Array[0..1023] Of PRDINFO3;
  50.   PDeviceInfo = ^TDeviceInfo;
  51.     { internal. }
  52.   {$ENDIF}
  53.  
  54.   TPrinter = Class
  55.   Private
  56.   Public // temporary only
  57.     {$IFDEF OS2}
  58.     FQueues: PQueueInfo;       // Pointer To Queue Info Buffer
  59.     {$ENDIF}
  60.     FQueueCount: LongInt;      // Number Of queues available
  61.     FQueueIndex: LongInt;      // Currently Selected Queue
  62.     FQueueSize:  LongInt;      // Size Of Queue Info Buffer
  63.  
  64.     {$IFDEF OS2}
  65.     FDevices: PDeviceInfo;     // Pointer To Device Info Buffer
  66.     {$ENDIF}
  67.     FDeviceCount: LongInt;     // Number Of Devices available
  68.     FDeviceIndex: LongInt;     // Currently Selected Device
  69.     FDeviceSize:  LongInt;     // Size Of Device Info Buffer
  70.  
  71.     FDeviceName: cstring[32];  // Name Of Currently Selected Device
  72.     {$IFDEF OS2}
  73.     FDeviceData: DEVOPENSTRUC; // Data Needed To Open Device contect
  74.     {$ENDIF}
  75.  
  76.     FPrintToFile: Boolean;     // Print To File instead Of printer?
  77.     FFileName: AnsiString;     // Name Of Output File
  78.  
  79.     FPrinters: TStrings;       // Printer Names Visible To End user
  80.  
  81.     FHandle: HDC;              // Printer Device context
  82.     FCanvas: TCanvas;          // Printer Canvas
  83.  
  84.     FState: TPrinterState;     // Current State Of Printer Object
  85.  
  86.     FTitle: AnsiString;        // Document Title
  87.     FCopies: LongInt;          // Number Of copies To be printed
  88.     FAborted: Boolean;         // True when Last job was aborted
  89.     FPageNumber: LongInt;      // Number Of Current page
  90.  
  91.     Procedure Error(Id: Word);
  92.     Procedure FmtError(Id: Word; Args: Array Of Const);
  93.     Function GetOrientation: TPrinterOrientation;
  94.     Function GetPageHeight: LongInt;
  95.     Function GetPageWidth: LongInt;
  96.     Procedure GetPrinterInfo;
  97.     Function GetPrinting: Boolean;
  98.     Procedure SetFileName(Value: AnsiString);
  99.     Procedure SetPrinterIndex(Value: LongInt);
  100.     Procedure SetPrinterState(Value: TPrinterState);
  101.     Procedure SetPrintToFile(Value: Boolean);
  102.  
  103.   Public
  104.     Constructor Create;
  105.       { Create Printer Object. one Printer Object
  106.         Is automatically created And stored In the
  107.         Printer variable. no need To Create more
  108.         Printer Objects. }
  109.     Destructor Destroy; Override;
  110.       { Destroy Printer Object. the Instance stored
  111.         In the Printer variable Is automatically
  112.         destroyed In the unit's Finalization Code. }
  113.  
  114.     Procedure Abort;
  115.       { Abort Current Document. only available inside
  116.         Document. }
  117.     Procedure BeginDoc;
  118.       { Begin New Document. only available when Last
  119.         job has either been completed Or aborted. }
  120.     Procedure EndDoc;
  121.       { End Document. only available inside Document. }
  122.     Procedure NewPage;
  123.       { Start A New, blank page. only available inside
  124.         Document. }
  125.     Procedure OptionsDlg;
  126.       { display job properties Dialog For Currently
  127.         Selected Printer. allow the user To Change
  128.         job properties. only available While Not In
  129.         Document. }
  130.     procedure PrintBitmap(Bitmap: TBitmap; SrcRec, DstRec: TRect);
  131.       { Prints a bitmap. SrcRec and DstRec specify
  132.         the source and destination rectangles.
  133.  
  134.         You should always use this method to display
  135.         bitmaps on the printer. Never use the blitting
  136.         operations provided by the canvas or graphics
  137.         objects, since they can't cooperate with a
  138.         printer canvas. }
  139.     procedure PrintForm(Form: TForm; DstRec: TRect);
  140.       { Prints the contents of a form. DstRec
  141.         specifies the destination rectangle on
  142.         the page.
  143.  
  144.         Please note the following differences from
  145.         form printing under Borland Delphi:
  146.  
  147.         (a) A print job must already be initiated.
  148.         (b) Only the currently visible part of the
  149.             the form can be printed. This is due to
  150.             an OS/2 limitation. }
  151.     Property Aborted: Boolean Read FAborted;
  152.       { True If Last job has been aborted. }
  153.     Property Canvas: TCanvas Read FCanvas;
  154.       { Printer Canvas. only available inside
  155.         Document. }
  156.     Property Copies: LongInt Read FCopies Write FCopies;
  157.       { Number Of copies To be printed Of Next
  158.         Document. MUST be Set before BeginDoc,
  159.         Otherwise ignored. }
  160.     Property FileName: AnsiString Read FFileName Write SetFileName;
  161.       { destination when printing To A File. }
  162.     Property Handle: HDC Read FHandle;
  163.       { Printer Device context. }
  164.     Property Orientation: TPrinterOrientation Read GetOrientation;
  165.       { page Orientation. }
  166.     Property PageHeight: LongInt Read GetPageHeight;
  167.       { page Height In Pixels. }
  168.     Property PageNumber: LongInt Read FPageNumber;
  169.       { Current page Number. }
  170.     Property PageWidth: LongInt Read GetPageWidth;
  171.       { page Width In Pixels. }
  172.     Property PrinterIndex: LongInt Read FQueueIndex Write SetPrinterIndex;
  173.       { Currently Selected Printer. Change only While Not
  174.         In Document. Set PrinterIndex To -1 For System
  175.         Default Printer. }
  176.     Property Printers: TStrings Read FPrinters;
  177.       { Names Of Printers (aka queues) available. If
  178.         Printers.Count Is 0, the System doesn't have
  179.         any Printers installed. }
  180.     Property Printing: Boolean Read GetPrinting;
  181.       { True when inside Document. }
  182.     Property PrintToFile: Boolean Read FPrintToFile Write SetPrintToFile;
  183.       { when True, Output Is sent To File specified
  184.         In the FileName Property. }
  185.     Property Title: AnsiString Read FTitle Write FTitle;
  186.       { Title Of Next Document. MUST be Set before
  187.         BeginDoc, Otherwise ignored. }
  188.   End;
  189.  
  190. Var
  191.   Printer: TPrinter;
  192.  
  193. Implementation
  194.  
  195. {$IFDEF OS2}
  196. Uses
  197.   PmWin, PmDev, PMSHL, PmGpi;
  198. {$ENDIF}
  199.  
  200. {$IFDEF WIN32}
  201. Uses WinDef,WinNT,WinBase,WinUser,WinGDI;
  202. {$ENDIF}
  203.  
  204. { --- For debugging purposes only --- }
  205.  
  206. Procedure DisplayPrinterInfo;
  207. Var
  208.   C: cstring;
  209.   I: LongInt;
  210. Begin
  211.   {$IFDEF OS2}
  212.   PrfQueryProfileString(HINI_PROFILE,
  213.                         'PM_SPOOLER',
  214.                         'QUEUE',
  215.                         Nil,
  216.                         C,
  217.                         SizeOf(C));
  218.  
  219.   I := 0;
  220.   While (C[I] <> #0) And (C[I] <> ';') Do Inc(I);
  221.   C[I] := #0;
  222.  
  223.   WriteLn(Printer.FQueueCount, ' queues, ',
  224.           Printer.FDeviceCount, ' devices, ',
  225.           'default queue is ', C);
  226.  
  227.   For I := 0 To Printer.FQueueCount - 1 Do
  228.   Begin
  229.     WriteLn('--- Queue #', I, ': ---');
  230.     With Printer.FQueues^[I] Do
  231.     Begin
  232.       WriteLn('pszName:        ', pszName);
  233.       WriteLn('pszPrinters:    ', pszPrinters);
  234.       WriteLn('pszDriverName:  ', pszDriverName);
  235.     End;
  236.   End;
  237.  
  238.   For I := 0 To Printer.FDeviceCount - 1 Do
  239.   Begin
  240.     WriteLn('--- Device #', I, ': ---');
  241.     With Printer.FDevices^[I] Do
  242.     Begin
  243.       WriteLn('pszPrinterName: ', pszPrinterName);
  244.       WriteLn('pszLogAddr      ', pszLogAddr);
  245.       WriteLn('pszDrivers:     ', pszDrivers);
  246.     End;
  247.   End;
  248.   {$ENDIF}
  249. End;
  250.  
  251. { --- TPrinter --- }
  252.  
  253. Constructor TPrinter.Create;
  254. Begin
  255.   Inherited Create;
  256.   FPrinters := TStringList.Create;
  257.   FCanvas := TCanvas.Create(Nil);
  258.   FCanvas.NonDisplayDevice:=True;
  259.   Try
  260.     GetPrinterInfo;
  261.     If Printers.Count <> 0 Then SetPrinterIndex(-1);
  262.   Except
  263.     ON E: EPrinter Do
  264.       ErrorBox2(LoadNLSStr(SPrinterInit1)
  265.               + #13#13
  266.               + E.Message
  267.               + #13#13
  268.               + LoadNLSStr(SPrinterInit2));
  269.   End;
  270. End;
  271.  
  272. Destructor TPrinter.Destroy;
  273. Begin
  274.   SetPrinterState(psNoHandle);
  275.   {$IFDEF OS2}
  276.   If FQueueSize <> 0 Then FreeMem(FQueues, FQueueSize);
  277.   If FDeviceSize <> 0 Then FreeMem(FDevices, FDeviceSize);
  278.   {$ENDIF}
  279.  
  280.   FPrinters.Free;
  281.   FCanvas.Free;
  282.   Inherited Destroy;
  283. End;
  284.  
  285. Procedure TPrinter.Abort;
  286. Begin
  287.   If Not printing Then FmtError(SPrinterIdle, ['Abort']);
  288.  
  289.   {$IFDEF OS2}
  290.   DevEscape(FHandle,
  291.             DEVESC_ABORTDOC,
  292.             0,
  293.             Nil,
  294.             Nil,
  295.             Nil);
  296.   {$ENDIF}
  297.   {$IFDEF WIN32}
  298.   WinGDI.AbortDocAPI(FHandle);
  299.   {$ENDIF}
  300.  
  301.   SetPrinterState(psNoHandle);
  302.   FAborted := True;
  303. End;
  304.  
  305. Procedure TPrinter.BeginDoc;
  306. {$IFDEF WIN32}
  307. Var DI:DOCINFO;
  308. {$ENDIF}
  309. var
  310.   DefFnt: TFont;
  311. Begin
  312.   If printing Then FmtError(SPrinterBusy, ['BeginDoc']);
  313.  
  314.   SetPrinterState(psHandleDC);
  315.  
  316.   {$IFDEF OS2}
  317.   DevEscape(FHandle,
  318.             DEVESC_STARTDOC,
  319.             Length(FTitle) + 1,
  320.             PChar(FTitle)^,
  321.             Nil,
  322.             Nil);
  323.   {$ENDIF}
  324.   {$IFDEF WIN32}
  325.   DI.cbSize:=SizeOf(DOCINFO);
  326.   DI.lpszDocName:=PChar(FTitle);
  327.   DI.lpszOutput:=Nil;
  328.   DI.lpszDatatype:=Nil;
  329.   DI.fwType:=0;
  330.   StartDocAPI(FHandle,DI);
  331.   {$ENDIF}
  332.  
  333.   with FCanvas do
  334.   begin
  335.     {$IFDEF OS2}
  336.     GpiCreateLogColorTable(Handle, LCOL_RESET, LCOLF_RGB, 0, 0, nil);
  337.     {$ENDIF}
  338.  
  339.     with Pen do
  340.     begin
  341.       Color := clBlack;
  342.       Mode  := pmCopy;
  343.       Style := psSolid;
  344.     end;
  345.  
  346.     with Brush do
  347.     begin
  348.       Color := clWhite;
  349.       Mode  := bmOpaque;
  350.       Style := bsSolid;
  351.     end;
  352.  
  353.     DefFnt := Screen.GetFontFromPointSize('Courier New', 10);
  354.  
  355.     if DefFnt = nil then
  356.       DefFnt := Screen.GetFontFromPointSize('Courier', 10);
  357.  
  358.     Font := DefFnt;
  359.   end;
  360.  
  361.   FAborted := False;
  362.   FPageNumber := 1;
  363. End;
  364.  
  365. Procedure TPrinter.EndDoc;
  366. Begin
  367.   If Not printing Then FmtError(SPrinterIdle, ['EndDoc']);
  368.  
  369.   NewPage;
  370.  
  371.   {$IFDEF OS2}
  372.   DevEscape(FHandle,
  373.             DEVESC_ENDDOC,
  374.             0,
  375.             Nil,
  376.             Nil,
  377.             Nil);
  378.   {$ENDIF}
  379.   {$IFDEF WIN32}
  380.   WinGDI.EndDocAPI(FHandle);
  381.   {$ENDIF}
  382.  
  383.   SetPrinterState(psHandleIC);
  384. End;
  385.  
  386. Procedure TPrinter.Error;
  387. Begin
  388.   Raise EPrinter.Create(LoadNLSStr(Id));
  389. End;
  390.  
  391. Procedure TPrinter.FmtError;
  392. Begin
  393.   Raise EPrinter.Create(FmtLoadNLSStr(Id, Args));
  394. End;
  395.  
  396. Function TPrinter.GetOrientation;
  397. Begin
  398.   If PageHeight >= PageWidth Then Result := poPortrait
  399.   Else Result := poLandscape;
  400. End;
  401.  
  402. Function TPrinter.GetPageHeight;
  403. Begin
  404.   {$IFDEF OS2}
  405.   DevQueryCaps(FHandle, CAPS_HEIGHT, 1, Result);
  406.   {$ENDIF}
  407.   {$IFDEF WIN32}
  408.   Result := GetDeviceCaps(FHandle, VertRes);
  409.   {$ENDIF}
  410. End;
  411.  
  412. Function TPrinter.GetPageWidth;
  413. Begin
  414.   {$IFDEF OS2}
  415.   DevQueryCaps(FHandle, CAPS_WIDTH, 1, Result);
  416.   {$ENDIF}
  417.   {$IFDEF WIN32}
  418.   Result := GetDeviceCaps(FHandle, HorzRes);
  419.   {$ENDIF}
  420. End;
  421.  
  422. Procedure TPrinter.GetPrinterInfo;
  423. {$IFDEF OS2}
  424. Var
  425.   dummy, I, J, QueueTotal, DeviceTotal: LongInt;
  426.   S: String;
  427. {$ENDIF}
  428. Begin
  429.   {$IFDEF OS2}
  430.   SplEnumQueue('',
  431.                3,
  432.                dummy,
  433.                0,
  434.                LongWord(FQueueCount),
  435.                LongWord(QueueTotal),
  436.                LongWord(FQueueSize),
  437.                Nil);
  438.  
  439.   GetMem(FQueues, FQueueSize);
  440.  
  441.   SplEnumQueue('',
  442.                3,
  443.                FQueues^,
  444.                FQueueSize,
  445.                LongWord(FQueueCount),
  446.                LongWord(QueueTotal),
  447.                LongWord(FQueueSize),
  448.                Nil);
  449.  
  450.   SplEnumDevice('',
  451.                 3,
  452.                 dummy,
  453.                 0,
  454.                 LongWord(FDeviceCount),
  455.                 LongWord(DeviceTotal),
  456.                 LongWord(FDeviceSize),
  457.                 Nil);
  458.  
  459.   GetMem(FDevices, FDeviceSize);
  460.  
  461.   SplEnumDevice('',
  462.                 3,
  463.                 FDevices^,
  464.                 FDeviceSize,
  465.                 LongWord(FDeviceCount),
  466.                 LongWord(DeviceTotal),
  467.                 LongWord(FDeviceSize),
  468.                 Nil);
  469.  
  470.   For I := 0 To FQueueCount - 1 Do
  471.   Begin
  472.     S := FQueues^[I].pszComment^;
  473.     J := 1;
  474.     While J <= Length(S) Do
  475.     Begin
  476.       Case S[J] Of
  477.         #10: Delete(S, J, 1);
  478.         #13: S[J] := ' ';
  479.       End;
  480.       Inc(J);
  481.     End;
  482.     FPrinters.Add(S);
  483.   End;
  484.   {$ENDIF}
  485. End;
  486.  
  487. Function TPrinter.GetPrinting;
  488. Begin
  489.   Result := (FState = psHandleDC);
  490. End;
  491.  
  492. Procedure TPrinter.NewPage;
  493. Begin
  494.   If Not printing Then FmtError(SPrinterIdle, ['NewPage']);
  495.  
  496.   {$IFDEF OS2}
  497.   DevEscape(FHandle,
  498.             DEVESC_NEWFRAME,
  499.             0,
  500.             Nil,
  501.             Nil,
  502.             Nil);
  503.   {$ENDIF}
  504.   {$IFDEF WIN32}
  505.   StartPage(FHandle);
  506.   {$ENDIF}
  507.  
  508.   Inc(FPageNumber);
  509. End;
  510.  
  511. Procedure TPrinter.OptionsDlg;
  512. Var
  513.   I: LongInt;
  514. Begin
  515.   If printing Then FmtError(SPrinterBusy, ['OptionsDlg']);
  516.  
  517.   {$IFDEF OS2}
  518.   With FDeviceData Do
  519.   Begin
  520.     I := DevPostDeviceModes(AppHandle,
  521.                             Nil,
  522.                             pszDriverName^,
  523.                             pDriv^.szDeviceName,
  524.                             Nil,
  525.                             DPDM_POSTJOBPROP);
  526.  
  527.     If I > pDriv^.cb Then FmtError(SJobProperties, [I, pDriv^.cb]);
  528.  
  529.     DevPostDeviceModes(AppHandle,
  530.                        pDriv^,
  531.                        pszDriverName^,
  532.                        pDriv^.szDeviceName,
  533.                        Nil,
  534.                        DPDM_POSTJOBPROP);
  535.   End;
  536.   {$ENDIF}
  537.   SetPrinterState(FState);
  538. End;
  539.  
  540. procedure TPrinter.PrintBitmap;
  541. {$IFDEF OS2}
  542. var
  543.   DC: HDC;
  544.   PS: HPS;
  545.   BM: HBITMAP;
  546.   Size: SIZEL;
  547.   Points: array[0..1] of TRect;
  548. {$ENDIF}
  549. begin
  550.   {$IFDEF OS2}
  551.   If not Printing Then FmtError(SPrinterIdle, ['PrintBitmap']);
  552.  
  553.   if Bitmap = nil then Exit;
  554.  
  555.   DC := 0;
  556.   PS := 0;
  557.  
  558.   try
  559.     DC := DevOpenDC(AppHandle, OD_MEMORY, '*', 0,
  560.                     nil, Handle);
  561.  
  562.     Size.CX := 0;
  563.     Size.CY := 0;
  564.  
  565.     PS := GpiCreatePS(AppHandle, DC, Size,
  566.                       PU_PELS or GPIT_MICRO or GPIA_ASSOC);
  567.  
  568.     BM := Bitmap.Handle;
  569.     try
  570.       GpiSetBitmap(Bitmap.Canvas.Handle, 0);
  571.       GpiSetBitmap(PS, BM);
  572.  
  573.       Points[0] := DstRec;
  574.       Points[1] := SrcRec;
  575.  
  576.       GpiBitBlt(Canvas.Handle,
  577.                 PS,
  578.                 4,
  579.                 Points[0].LeftBottom,
  580.                 ROP_SRCCOPY,
  581.                 BBO_IGNORE);
  582.  
  583.     finally
  584.       GpiSetBitmap(PS, 0);
  585.       GpiSetBitmap(Bitmap.Canvas.Handle, BM);
  586.     end;
  587.  
  588.   finally
  589.     if PS <> 0 then GpiDestroyPS(PS);
  590.     if DC <> 0 then DevCloseDC(DC);
  591.   end;
  592.   {$ENDIF}
  593. end;
  594.  
  595. procedure TPrinter.PrintForm;
  596. var
  597.   Image: TBitmap;
  598. begin
  599.   If not Printing Then FmtError(SPrinterIdle, ['PrintForm']);
  600.  
  601.   Image := TBitmap(Form.GetFormImage);
  602.   try
  603.     PrintBitmap(Image,
  604.                 Forms.Rect(0, 0, Image.Width, Image.Height),
  605.                 DstRec);
  606.   finally
  607.     Image.Free;
  608.   end;
  609. end;
  610.  
  611. Procedure TPrinter.SetPrinterIndex;
  612. {$IFDEF OS2}
  613. Var
  614.   C: cstring;
  615.   P: PChar;
  616.   I: LongInt;
  617. {$ENDIF}
  618. Begin
  619.   If printing Then FmtError(SPrinterBusy, ['SetPrinterIndex']);
  620.  
  621.   {$IFDEF OS2}
  622.   If Value = -1 Then
  623.   Begin
  624.     // Query Default Queue Name
  625.     PrfQueryProfileString(HINI_PROFILE,
  626.                           'PM_SPOOLER',
  627.                           'QUEUE',
  628.                           Nil,
  629.                           C,
  630.                           SizeOf(C));
  631.  
  632.     // Remove useless semicolon At End
  633.     I := 0;
  634.     While (C[I] <> #0) And (C[I] <> ';') Do
  635.       Inc(I);
  636.     C[I] := #0;
  637.  
  638.     // Find Index Of Default Queue
  639.     I := 0;
  640.     While (I < FQueueCount) And (C <> FQueues^[I].pszName^) Do
  641.       Inc(I);
  642.  
  643.     If I < FQueueCount Then Value := I Else Value := 0;
  644.   End;
  645.  
  646.   // Change Current Queue If Value Is legal
  647.   If (Value < 0) Or (Value >= FQueueCount) Then FmtError(SInvalidIndex, [Value, Printers.Count]);
  648.   FQueueIndex := Value;
  649.  
  650.   // Get Printer Name Of Selected Queue, Find matching Device
  651.   P := FQueues^[FQueueIndex].pszPrinters;
  652.  
  653.   I := 0;
  654.   While (I < FDeviceCount) And (P^ <> FDevices^[I].pszPrinterName^) Do
  655.     Inc(I);
  656.  
  657.   If I = FDeviceCount Then FmtError(SDeviceNotFound, [P]);
  658.  
  659.   FDeviceIndex := I;
  660.  
  661.   // Set Device Name
  662.   C := FQueues^[FQueueIndex].pszDriverName^;
  663.   I := 0;
  664.   While (C[I] <> #0) And (C[I] <> '.') Do Inc(I);
  665.   C[I] := #0;
  666.   FDeviceName := C;
  667.  
  668.   // Fill Device Open structure
  669.   With FDeviceData Do
  670.   Begin
  671.     If FPrintToFile Then pszLogAddress := PChar(FileName)
  672.     Else pszLogAddress := FDevices^[FDeviceIndex].pszLogAddr;
  673.  
  674.     pszDriverName := @FDeviceName;
  675.     pszDataType := 'PM_Q_STD';
  676.     pDriv := FQueues^[FQueueIndex].pDriverData;
  677.   End;
  678.   {$ENDIF}
  679.  
  680.   // Get Info context
  681.   SetPrinterState(psHandleIC);
  682. End;
  683.  
  684. Procedure TPrinter.SetPrinterState;
  685. {$IFDEF OS2}
  686. Var
  687.   C: cstring[16];
  688.   S: SIZEL;
  689.   D, E: LongInt;
  690. {$ENDIF}
  691. Begin
  692.   {$IFDEF OS2}
  693.   If FCanvas.Handle <> 0 Then
  694.   Begin
  695.     GpiDestroyPS(FCanvas.Handle);
  696.     FCanvas.Handle := 0;
  697.   End;
  698.  
  699.   If FHandle <> 0 Then
  700.   Begin
  701.     DevCloseDC(FHandle);
  702.     FHandle := 0;
  703.   End;
  704.  
  705.   If FCopies > 1 Then
  706.   Begin
  707.     C := 'COP=' + tostr(FCopies);
  708.     FDeviceData.pszQueueProcParams := @C;
  709.   End;
  710.  
  711.   Case Value Of
  712.     psHandleIC:
  713.     Begin
  714.       FHandle := DevOpenDC(AppHandle,
  715.                            OD_INFO,
  716.                            '*',
  717.                            4,
  718.                            FDeviceData,
  719.                            0);
  720.  
  721.       If FHandle = 0 Then
  722.       Begin
  723.         E := WinGetLastError(AppHandle);
  724.         FmtError(SNoHandleIC, [E]);
  725.       End;
  726.     End;
  727.  
  728.     psHandleDC:
  729.     Begin
  730.       If FPrintToFile Then D := OD_DIRECT Else D := OD_QUEUED;
  731.  
  732.       FHandle := DevOpenDC(AppHandle,
  733.                            D,
  734.                            '*',
  735.                            9,
  736.                            FDeviceData,
  737.                            0);
  738.  
  739.       If FHandle = 0 Then
  740.       Begin
  741.         E := WinGetLastError(AppHandle);
  742.         FmtError(SNoHandleDC, [E]);
  743.       End;
  744.  
  745.       S.CX := 0;
  746.       S.CY := 0;
  747.  
  748.       FCanvas.Handle := GpiCreatePS(AppHandle,
  749.                                     FHandle,
  750.                                     S,
  751.                                     //PU_ARBITRARY Or GPIF_DEFAULT Or GPIT_MICRO Or GPIA_ASSOC
  752.                                     PU_PELS or GPIT_MICRO or GPIA_ASSOC
  753.                                    );
  754.  
  755.       If FCanvas.Handle = 0 Then
  756.       Begin
  757.         E := WinGetLastError(AppHandle);
  758.         DevCloseDC(FHandle);
  759.         FHandle := 0;
  760.         FmtError(SNoHandlePS, [E]);
  761.       End;
  762.     End;
  763.   End;
  764.   {$ENDIF}
  765.  
  766.   FState := Value;
  767. End;
  768.  
  769. Procedure TPrinter.SetPrintToFile;
  770. Begin
  771.   FPrintToFile := Value;
  772.   {$IFDEF OS2}
  773.   With FDeviceData Do
  774.   Begin
  775.     If FPrintToFile Then pszLogAddress := PChar(FileName)
  776.     Else pszLogAddress := FDevices^[FDeviceIndex].pszLogAddr;
  777.   End;
  778.   {$ENDIF}
  779. End;
  780.  
  781. Procedure TPrinter.SetFileName;
  782. Begin
  783.   FFileName := Value;
  784.   SetPrintToFile(FPrintToFile);
  785. End;
  786.  
  787. Initialization
  788.   Try //just To Make sure <G>
  789.     Printer := TPrinter.Create; { cannot Fail anymore }
  790.   Except
  791.     Printer:=Nil;
  792.   End;
  793.  
  794. Finalization
  795.   Printer.Free;
  796.  
  797. End.
  798.  
  799. { -- date -- - changes ------------------------------------------
  800.  
  801.   22-Dec-97   Initial Release.
  802.   28-Jan-97   printing To File didn't work when FileName was
  803.               specified With PrintToFile already being True.
  804.   08-Feb-97   Device Name now 32 characters. Problems With
  805.               systems where several Printer Objects Use the same
  806.               Device. results In 'No queue for device'. don't
  807.               know how To fix This.
  808.   27-Feb-97   removed Some debugging stuff.
  809.   05-Mar-97   FIXED bug that resulted In 'No queue for device'.
  810.               moved Error Messages To Resource Id 65300.
  811.   13-Mar-97   Some changes by Rene Nürnberger
  812.   04-Apr-97   GetPrinterInfo now replaces #13#10 by A space
  813.               If the Printer Name Is Multi-Line.
  814.   15-Apr-97   additional diagnostic information when DevOpenDC
  815.               Or GpiCreatePS Fail. New Error Handling For
  816.               startup sequence. Existence Of Printer Instance
  817.               guaranteed.
  818.   16-Apr-97   Rene: Saved Initialization part With Try..Except.
  819.               This Is only For safety If For Instance A GPF
  820.               occurs within the Constructor.
  821.   05-Aug-97   Jörg: Fixed bug reported by Alex Vermeulen.
  822.               Printer had no palette, which resulted in
  823.               empty pages when trying to use RGB colors.
  824.               Some other initialization also done on
  825.               every BeginDoc: Pen, Brush and Font set to
  826.               default values.
  827.   06-Aug-97   Jörg: Default printer font is now either
  828.               "Courier New" or "Courier", depending on
  829.               which one is available. Changes to BeginDoc
  830.               and SetPrinterState.
  831.   16-Aug-97   Jörg: Added methods PrintBitmap and PrintForm.
  832.  
  833.   --------------------------------------------------------------- }
  834.