/jcl/source/vcl/JclPrint.pas

https://github.com/the-Arioch/jcl · Pascal · 1632 lines · 1399 code · 118 blank · 115 comment · 78 complexity · 5da3cd05be4dfce70d81f91d9812de2f MD5 · raw file

  1. {**************************************************************************************************}
  2. { }
  3. { Project JEDI Code Library (JCL) }
  4. { }
  5. { The contents of this file are subject to the Mozilla Public License Version 1.1 (the "License"); }
  6. { you may not use this file except in compliance with the License. You may obtain a copy of the }
  7. { License at http://www.mozilla.org/MPL/ }
  8. { }
  9. { Software distributed under the License is distributed on an "AS IS" basis, WITHOUT WARRANTY OF }
  10. { ANY KIND, either express or implied. See the License for the specific language governing rights }
  11. { and limitations under the License. }
  12. { }
  13. { The Original Code is JclPrint.pas. }
  14. { }
  15. { The Initial Developers of the Original Code are unknown. }
  16. { Portions created by these individuals are Copyright (C) of these individuals. }
  17. { All rights reserved. }
  18. { }
  19. { The Initial Developer of the function DPSetDefaultPrinter is Microsoft. Portions created by }
  20. { Microsoft are Copyright (C) 2004 Microsoft Corporation. All Rights Reserved. }
  21. { }
  22. { Contributors: }
  23. { Marcel van Brakel }
  24. { Matthias Thoma (mthoma) }
  25. { Karl Ivar Hansen }
  26. { Martin Cakrt }
  27. { Jared Davison }
  28. { }
  29. {**************************************************************************************************}
  30. { }
  31. { This unit contains print-related classes and functions. }
  32. { }
  33. {**************************************************************************************************}
  34. { }
  35. { Last modified: $Date:: $ }
  36. { Revision: $Rev:: $ }
  37. { Author: $Author:: $ }
  38. { }
  39. {**************************************************************************************************}
  40. unit JclPrint;
  41. {$I jcl.inc}
  42. {$I windowsonly.inc}
  43. interface
  44. uses
  45. {$IFDEF UNITVERSIONING}
  46. JclUnitVersioning,
  47. {$ENDIF UNITVERSIONING}
  48. {$IFDEF HAS_UNITSCOPE}
  49. Winapi.Windows, System.Classes, Vcl.StdCtrls, System.SysUtils, System.IniFiles,
  50. {$ELSE ~HAS_UNITSCOPE}
  51. Windows, Classes, StdCtrls, SysUtils, IniFiles,
  52. {$ENDIF ~HAS_UNITSCOPE}
  53. JclBase;
  54. const
  55. CCHBinName = 24;
  56. CCHPaperName = 64;
  57. CBinMax = 256;
  58. CPaperNames = 256;
  59. type
  60. PWordArray = ^TWordArray;
  61. TWordArray = array [0..255] of Word;
  62. type
  63. EJclPrinterError = class(EJclError);
  64. TJclPrintSet = class(TObject)
  65. private
  66. FDevice: PChar; { TODO : change to string }
  67. FDriver: PChar;
  68. FPort: PChar;
  69. FHandle: THandle;
  70. FPrinter: Integer;
  71. FBinArray: PWordArray;
  72. FNumBins: DWord;
  73. FPaperArray: PWordArray;
  74. FNumPapers: DWord;
  75. FDpiX: Integer;
  76. FiDpiY: Integer;
  77. procedure CheckPrinter;
  78. procedure SetBinArray;
  79. procedure SetPaperArray;
  80. function DefaultPaperName(const PaperID: Word): string;
  81. function GetDevModePrinterDriverVersion: Word;
  82. function GetDevModePrinterDriver: string;
  83. function GetDevModePrinterDriverExtra: TDynByteArray;
  84. function LockDeviceMode: PDeviceMode;
  85. procedure SetDeviceMode(Creating: Boolean);
  86. procedure SetPrinterName(const Value: string);
  87. procedure UnlockDeviceMode;
  88. protected
  89. procedure SetOrientation(Orientation: Integer);
  90. function GetOrientation: Integer;
  91. procedure SetPaperSize(Size: Integer);
  92. function GetPaperSize: Integer;
  93. procedure SetPaperLength(Length: Integer);
  94. function GetPaperLength: Integer;
  95. procedure SetPaperWidth(Width: Integer);
  96. function GetPaperWidth: Integer;
  97. procedure SetScale(Scale: Integer);
  98. function GetScale: Integer;
  99. procedure SetCopies(Copies: Integer);
  100. function GetCopies: Integer;
  101. procedure SetBin(Bin: Integer);
  102. function GetBin: Integer;
  103. procedure SetPrintQuality(Quality: Integer);
  104. function GetPrintQuality: Integer;
  105. procedure SetColor(Color: Integer);
  106. function GetColor: Integer;
  107. procedure SetDuplex(Duplex: Integer);
  108. function GetDuplex: Integer;
  109. procedure SetYResolution(YRes: Integer);
  110. function GetYResolution: Integer;
  111. procedure SetTrueTypeOption(Option: Integer);
  112. function GetTrueTypeOption: Integer;
  113. function GetPrinterName: string;
  114. function GetPrinterPort: string;
  115. function GetPrinterDriver: string;
  116. procedure SetBinFromList(BinNum: Word);
  117. function GetBinIndex: Word;
  118. procedure SetPaperFromList(PaperNum: Word);
  119. function GetPaperIndex: Word;
  120. function ReadFromCustomIni(const PrIniFile: TCustomIniFile; const Section: string): Boolean;
  121. procedure SaveToCustomIni(const PrIniFile: TCustomIniFile; const Section: string);
  122. procedure SetPort(Port: string);
  123. procedure DevModePrinterDriverExtraReinstate(const ExtraData: TDynByteArray;
  124. const ExtraDataDriverName: string; const ExtraDataDriverVersion: Word);
  125. public
  126. constructor Create; virtual;
  127. destructor Destroy; override;
  128. // use the other implementations
  129. //function GetBinSourceList: TStringList; overload;
  130. //function GetPaperList: TStringList; overload;
  131. procedure GetBinSourceList(List: TStrings); overload;
  132. procedure GetPaperList(List: TStrings); overload;
  133. procedure UpdateDeviceMode(const ADeviceMode: PDeviceMode);
  134. procedure SaveToDefaults;
  135. procedure SavePrinterAsDefault;
  136. procedure ResetPrinterDialogs;
  137. function XInchToDot(const Inches: Double): Integer;
  138. function YInchToDot(const Inches: Double): Integer;
  139. function XCmToDot(const Cm: Double): Integer;
  140. function YCmToDot(const Cm: Double): Integer;
  141. function CpiToDot(const Cpi, Chars: Double): Integer;
  142. function LpiToDot(const Lpi, Lines: Double): Integer;
  143. procedure TextOutInch(const X, Y: Double; const Text: string);
  144. procedure TextOutCm(const X, Y: Double; const Text: string);
  145. procedure TextOutCpiLpi(const Cpi, Chars, Lpi, Lines: Double; const Text: string);
  146. procedure CustomPageSetup(const Width, Height: Double);
  147. procedure DevModePrinterDriverExtraClear;
  148. procedure SaveToIniFile(const IniFileName, Section: string); virtual;
  149. function ReadFromIniFile(const IniFileName, Section: string): Boolean; virtual;
  150. property Orientation: Integer read GetOrientation write SetOrientation;
  151. property PaperSize: Integer read GetPaperSize write SetPaperSize;
  152. property PaperLength: Integer read GetPaperLength write SetPaperLength;
  153. property PaperWidth: Integer read GetPaperWidth write SetPaperWidth;
  154. property Scale: Integer read GetScale write SetScale;
  155. property Copies: Integer read GetCopies write SetCopies;
  156. property DefaultSource: Integer read GetBin write SetBin;
  157. property PrintQuality: Integer read GetPrintQuality write SetPrintQuality;
  158. property Color: Integer read GetColor write SetColor;
  159. property Duplex: Integer read GetDuplex write SetDuplex;
  160. property YResolution: Integer read GetYResolution write SetYResolution;
  161. property TrueTypeOption: Integer read GetTrueTypeOption write SetTrueTypeOption;
  162. property PrinterName: string read GetPrinterName write SetPrinterName;
  163. property PrinterPort: string read GetPrinterPort write SetPort;
  164. property PrinterDriver: string read GetPrinterDriver;
  165. property BinIndex: Word read GetBinIndex write SetBinFromList;
  166. property DevModePrinterDriverVersion: Word read GetDevModePrinterDriverVersion;
  167. property DevModePrinterDriver: string read GetDevModePrinterDriver;
  168. property DevModePrinterDriverExtra: TDynByteArray read
  169. GetDevModePrinterDriverExtra;
  170. property PaperIndex: Word read GetPaperIndex write SetPaperFromList;
  171. property DpiX: Integer read FDpiX write FDpiX;
  172. property DpiY: Integer read FiDpiY write FiDpiY;
  173. end;
  174. TPrinterData = {$IFDEF SUPPORTS_UNICODE_STRING}RawByteString{$ELSE}AnsiString{$ENDIF};
  175. procedure DirectPrint(const Printer: string; const Data: TPrinterData;
  176. const DocumentName: string = '');
  177. procedure SetPrinterPixelsPerInch;
  178. function GetPrinterResolution: TPoint;
  179. function CharFitsWithinDots(const Text: string; const Dots: Integer): Integer;
  180. //procedure PrintTextRotation(X, Y: Integer; Rotation: Word; Text: string);
  181. procedure PrintMemo(const Memo: TMemo; const Rect: TRect);
  182. function GetDefaultPrinterName: string;
  183. function DPGetDefaultPrinter(out PrinterName: string): Boolean;
  184. function DPSetDefaultPrinter(const PrinterName: string): Boolean;
  185. {$IFDEF UNITVERSIONING}
  186. const
  187. UnitVersioning: TUnitVersionInfo = (
  188. RCSfile: '$URL$';
  189. Revision: '$Revision$';
  190. Date: '$Date$';
  191. LogPath: 'JCL\source\vcl';
  192. Extra: '';
  193. Data: nil
  194. );
  195. {$ENDIF UNITVERSIONING}
  196. implementation
  197. uses
  198. {$IFDEF HAS_UNITSCOPE}
  199. Vcl.Graphics, Winapi.Messages, Vcl.Printers, Winapi.WinSpool,
  200. {$ELSE ~HAS_UNITSCOPE}
  201. Graphics, Messages, Printers, WinSpool,
  202. {$ENDIF ~HAS_UNITSCOPE}
  203. JclSysInfo, JclVclResources;
  204. const
  205. PrintIniPrinterName = 'PrinterName';
  206. PrintIniPrinterPort = 'PrinterPort';
  207. PrintIniOrientation = 'Orientation';
  208. PrintIniPaperSize = 'PaperSize';
  209. PrintIniPaperLength = 'PaperLength';
  210. PrintIniPaperWidth = 'PaperWidth';
  211. PrintIniScale = 'Scale';
  212. PrintIniCopies = 'Copies';
  213. PrintIniDefaultSource = 'DefaultSource';
  214. PrintIniPrintQuality = 'PrintQuality';
  215. PrintIniColor = 'Color';
  216. PrintIniDuplex = 'Duplex';
  217. PrintIniYResolution = 'YResolution';
  218. PrintIniTTOption = 'TTOption';
  219. PrintDriverExtraSize = 'DriverExtraSize';
  220. PrintDriverExtraData = 'DriverExtraData';
  221. PrintDriverVersion = 'DriverVersion';
  222. PrintDriverName = 'DriverName';
  223. cWindows: PChar = 'windows';
  224. cDevice = 'device';
  225. cPrintSpool = 'winspool.drv';
  226. // Misc. functions
  227. procedure DirectPrint(const Printer: string; const Data: TPrinterData; const DocumentName: string);
  228. const
  229. cRaw = 'RAW';
  230. type
  231. TDoc_Info_1 = record
  232. DocName: PChar;
  233. OutputFile: PChar;
  234. Datatype: PChar;
  235. end;
  236. var
  237. PrinterHandle: THandle;
  238. DocInfo: TDoc_Info_1;
  239. BytesWritten: Cardinal;
  240. Count: Cardinal;
  241. Defaults: TPrinterDefaults;
  242. begin
  243. // Defaults added for network printers. Supposedly the last member is ignored
  244. // by Windows 9x but is necessary for Windows NT. Code was copied from a msg
  245. // by Alberto Toledo to the C++ Builder techlist and fwd by Theo Bebekis.
  246. Defaults.pDatatype := cRaw;
  247. Defaults.pDevMode := nil;
  248. Defaults.DesiredAccess := PRINTER_ACCESS_USE;
  249. Count := Length(Data);
  250. if not OpenPrinter(PChar(Printer), PrinterHandle, @Defaults) then
  251. raise EJclPrinterError.CreateRes(@RsInvalidPrinter);
  252. // Fill in the structure with info about this "document"
  253. if DocumentName = '' then
  254. DocInfo.DocName := PChar(LoadResString(@RsSpoolerDocName))
  255. else
  256. DocInfo.DocName := PChar(DocumentName);
  257. DocInfo.OutputFile := nil;
  258. DocInfo.Datatype := cRaw;
  259. try
  260. // Inform the spooler the document is beginning
  261. if StartDocPrinter(PrinterHandle, 1, @DocInfo) = 0 then
  262. EJclPrinterError.CreateRes(@RsNAStartDocument);
  263. try
  264. // Start a page
  265. if not StartPagePrinter(PrinterHandle) then
  266. EJclPrinterError.CreateRes(@RsNAStartPage);
  267. try
  268. // Send the data to the printer
  269. if not WritePrinter(PrinterHandle, PAnsiChar(Data), Count * SizeOf(AnsiChar), BytesWritten) then
  270. EJclPrinterError.CreateRes(@RsNASendData);
  271. finally
  272. // End the page
  273. if not EndPagePrinter(PrinterHandle) then
  274. EJclPrinterError.CreateRes(@RsNAEndPage);
  275. end;
  276. finally
  277. // Inform the spooler that the document is ending
  278. if not EndDocPrinter(PrinterHandle) then
  279. EJclPrinterError.CreateRes(@RsNAEndDocument);
  280. end;
  281. finally
  282. // Tidy up the printer handle
  283. ClosePrinter(PrinterHandle);
  284. end;
  285. // Check to see if correct number of bytes written
  286. if BytesWritten <> Count * SizeOf(AnsiChar) then
  287. EJclPrinterError.CreateRes(@RsNATransmission);
  288. end;
  289. procedure SetPrinterPixelsPerInch;
  290. var
  291. FontSize: Integer;
  292. begin
  293. FontSize := Printer.Canvas.Font.Size;
  294. Printer.Canvas.Font.PixelsPerInch := GetDeviceCaps(Printer.Handle, LogPixelsY);
  295. Printer.Canvas.Font.Size := FontSize;
  296. end;
  297. function GetPrinterResolution: TPoint;
  298. begin
  299. Result.X := GetDeviceCaps(Printer.Handle, LogPixelsX);
  300. Result.Y := GetDeviceCaps(Printer.Handle, LogPixelsY);
  301. end;
  302. function CharFitsWithinDots(const Text: string; const Dots: Integer): Integer;
  303. begin
  304. Result := Length(Text);
  305. while (Result > 0) and (Printer.Canvas.TextWidth(Copy(Text, 1, Result)) > Dots) do
  306. Dec(Result);
  307. end;
  308. //WIMDC: The function CanvasTextOutRotation contains a bug in DxGraphics so no need to
  309. // implement it right now here
  310. (*
  311. procedure PrintTextRotation(X, Y: Integer; Rotation: Word; Text: string);
  312. begin
  313. CanvasTextOutRotation(Printer.Canvas, X, Y, Rotation, Text);
  314. end;
  315. *)
  316. //WIMDC took the function from DXGraphics and replaced some lines to work with the TStrings class
  317. // of the memo.
  318. procedure CanvasMemoOut(Canvas: TCanvas; Memo: TMemo; Rect: TRect);
  319. var
  320. MemoText: PChar;
  321. begin
  322. MemoText := Memo.Lines.GetText;
  323. if MemoText <> nil then
  324. try
  325. DrawText(Canvas.Handle, MemoText, StrLen(MemoText), Rect,
  326. DT_LEFT or DT_EXPANDTABS or DT_WORDBREAK);
  327. finally
  328. StrDispose(MemoText);
  329. end;
  330. end;
  331. procedure PrintMemo(const Memo: TMemo; const Rect: TRect);
  332. begin
  333. CanvasMemoOut(Printer.Canvas, Memo, Rect);
  334. end;
  335. function GetDefaultPrinterName: string;
  336. begin
  337. DPGetDefaultPrinter(Result);
  338. end;
  339. { TODO -cHelp : DPGetDefaultPrinter, Author: Microsoft }
  340. // DPGetDefaultPrinter
  341. // Parameters:
  342. // PrinterName: Return the printer name.
  343. // Returns: True for success, False for failure.
  344. // Source of the original code: Microsoft Knowledge Base Article - 246772
  345. // http://support.microsoft.com/default.aspx?scid=kb;en-us;246772
  346. function DPGetDefaultPrinter(out PrinterName: string): Boolean;
  347. const
  348. BUFSIZE = 8192;
  349. type
  350. TGetDefaultPrinter = function(Buffer: PChar; var Size: DWORD): BOOL; stdcall;
  351. var
  352. Needed, Returned: DWORD;
  353. PI2: PPrinterInfo2;
  354. WinVer: TWindowsVersion;
  355. hWinSpool: HMODULE;
  356. GetDefPrint: TGetDefaultPrinter;
  357. Size: DWORD;
  358. begin
  359. Result := False;
  360. PrinterName := '';
  361. WinVer := GetWindowsVersion;
  362. // Windows 9x uses EnumPrinters
  363. if WinVer in [wvWin95, wvWin95OSR2, wvWin98, wvWin98SE, wvWinME] then
  364. begin
  365. SetLastError(0);
  366. Result := EnumPrinters(PRINTER_ENUM_DEFAULT, nil, 2, nil, 0, Needed, Returned);
  367. if not Result and ((GetLastError <> ERROR_INSUFFICIENT_BUFFER) or (Needed = 0)) then
  368. Exit;
  369. GetMem(PI2, Needed);
  370. try
  371. Result := EnumPrinters(PRINTER_ENUM_DEFAULT, nil, 2, PI2, Needed, Needed, Returned);
  372. if Result then
  373. PrinterName := PI2^.pPrinterName;
  374. finally
  375. FreeMem(PI2);
  376. end;
  377. end
  378. else
  379. // Win NT uses WIN.INI (registry)
  380. if WinVer in [wvWinNT31, wvWinNT35, wvWinNT351, wvWinNT4] then
  381. begin
  382. SetLength(PrinterName, BUFSIZE);
  383. Result := GetProfileString(cWindows, cDevice, ',,,', PChar(PrinterName), BUFSIZE) > 0;
  384. if Result then
  385. PrinterName := Copy(PrinterName, 1, Pos(',', PrinterName) - 1)
  386. else
  387. PrinterName := '';
  388. end
  389. else
  390. // >= Win 2000 uses GetDefaultPrinter
  391. begin
  392. hWinSpool := SafeLoadLibrary(cPrintSpool);
  393. if hWinSpool <> 0 then
  394. try
  395. {$IFDEF UNICODE}
  396. @GetDefPrint := GetProcAddress(hWinSpool, 'GetDefaultPrinterW');
  397. {$ELSE}
  398. @GetDefPrint := GetProcAddress(hWinSpool, 'GetDefaultPrinterA');
  399. {$ENDIF UNICODE}
  400. if not Assigned(GetDefPrint) then
  401. Exit;
  402. Size := BUFSIZE;
  403. SetLength(PrinterName, Size);
  404. Result := GetDefPrint(PChar(PrinterName), Size);
  405. if Result then
  406. SetLength(PrinterName, StrLen(PChar(PrinterName)))
  407. else
  408. PrinterName := '';
  409. finally
  410. FreeLibrary(hWinSpool);
  411. end;
  412. end;
  413. end;
  414. { TODO -cHelp : DPSetDefaultPrinter, Author: Microsoft }
  415. // DPSetDefaultPrinter
  416. // Parameters:
  417. // PrinterName: Valid name of existing printer to make default.
  418. // Returns: True for success, False for failure.
  419. // Source of the original code: Microsoft Knowledge Base Article - 246772
  420. // http://support.microsoft.com/default.aspx?scid=kb;en-us;246772
  421. function DPSetDefaultPrinter(const PrinterName: string): Boolean;
  422. type
  423. TSetDefaultPrinter = function(APrinterName: PChar): BOOL; stdcall;
  424. var
  425. Needed: DWORD;
  426. PI2: PPrinterInfo2;
  427. WinVer: TWindowsVersion;
  428. hPrinter: THandle;
  429. hWinSpool: HMODULE;
  430. SetDefPrint: TSetDefaultPrinter;
  431. PrinterStr: string;
  432. begin
  433. Result := False;
  434. if PrinterName = '' then
  435. Exit;
  436. WinVer := GetWindowsVersion;
  437. if WinVer in [wvWin95, wvWin95OSR2, wvWin98, wvWin98SE, wvWinME] then
  438. begin
  439. Result := OpenPrinter(PChar(PrinterName), hPrinter, nil);
  440. if Result and (hPrinter <> 0) then
  441. try
  442. SetLastError(0);
  443. Result := GetPrinter(hPrinter, 2, nil, 0, @Needed);
  444. if not Result and ((GetLastError <> ERROR_INSUFFICIENT_BUFFER) or (Needed = 0)) then
  445. Exit;
  446. GetMem(PI2, Needed);
  447. try
  448. Result := GetPrinter(hPrinter, 2, PI2, Needed, @Needed);
  449. if Result then
  450. begin
  451. PI2^.Attributes := PI2^.Attributes or PRINTER_ATTRIBUTE_DEFAULT;
  452. Result := SetPrinter(hPrinter, 2, PI2, 0);
  453. if Result then
  454. SendMessageTimeout(HWND_BROADCAST, WM_SETTINGCHANGE, 0,
  455. LPARAM(cWindows), SMTO_NORMAL, 1000, {$IFDEF RTL230_UP}@{$ENDIF}Needed);
  456. end;
  457. finally
  458. FreeMem(PI2);
  459. end;
  460. finally
  461. ClosePrinter(hPrinter);
  462. end;
  463. end
  464. else
  465. // Win NT uses WIN.INI (registry)
  466. if WinVer in [wvWinNT31, wvWinNT35, wvWinNT351, wvWinNT4] then
  467. begin
  468. Result := OpenPrinter(PChar(PrinterName), hPrinter, nil);
  469. if Result and (hPrinter <> 0) then
  470. try
  471. SetLastError(0);
  472. Result := GetPrinter(hPrinter, 2, nil, 0, @Needed);
  473. if not Result and ((GetLastError <> ERROR_INSUFFICIENT_BUFFER) or (Needed = 0)) then
  474. Exit;
  475. GetMem(PI2, Needed);
  476. try
  477. Result := GetPrinter(hPrinter, 2, PI2, Needed, @Needed);
  478. if Result and (PI2^.pDriverName <> nil) and (PI2^.pPortName <> nil) then
  479. begin
  480. PrinterStr := PrinterName + ',' + PI2^.pDriverName + ',' + PI2^.pPortName;
  481. Result := WriteProfileString(cWindows, cDevice, PChar(PrinterStr));
  482. if Result then
  483. SendMessageTimeout(HWND_BROADCAST, WM_SETTINGCHANGE, 0, 0,
  484. SMTO_NORMAL, 1000, {$IFDEF RTL230_UP}@{$ENDIF}Needed);
  485. end;
  486. finally
  487. FreeMem(PI2);
  488. end;
  489. finally
  490. ClosePrinter(hPrinter);
  491. end;
  492. end
  493. else
  494. // >= Win 2000 uses SetDefaultPrinter
  495. begin
  496. hWinSpool := SafeLoadLibrary(cPrintSpool);
  497. if hWinSpool <> 0 then
  498. try
  499. {$IFDEF UNICODE}
  500. @SetDefPrint := GetProcAddress(hWinSpool, 'SetDefaultPrinterW');
  501. {$ELSE}
  502. @SetDefPrint := GetProcAddress(hWinSpool, 'SetDefaultPrinterA');
  503. {$ENDIF UNICODE}
  504. if Assigned(SetDefPrint) then
  505. Result := SetDefPrint(PChar(PrinterName));
  506. finally
  507. FreeLibrary(hWinSpool);
  508. end;
  509. end;
  510. end;
  511. // TJclPrintSet
  512. constructor TJclPrintSet.Create;
  513. begin
  514. inherited Create;
  515. FBinArray := nil;
  516. FPaperArray := nil;
  517. FPrinter := -99; { TODO : why -99 }
  518. GetMem(FDevice, 255);
  519. GetMem(FDriver, 255);
  520. GetMem(FPort, 255);
  521. FHandle := 0;
  522. end;
  523. destructor TJclPrintSet.Destroy;
  524. begin
  525. if FBinArray <> nil then
  526. FreeMem(FBinArray, FNumBins * SizeOf(Word));
  527. if FPaperArray <> nil then
  528. FreeMem(FPaperArray, FNumPapers * SizeOf(Word));
  529. if FDevice <> nil then
  530. FreeMem(FDevice, 255);
  531. if FDriver <> nil then
  532. FreeMem(FDriver, 255);
  533. if FPort <> nil then
  534. FreeMem(FPort, 255);
  535. inherited Destroy;
  536. end;
  537. procedure TJclPrintSet.CheckPrinter;
  538. var
  539. NewHandle: THandle;
  540. PrinterChanged: Boolean;
  541. LastDevice, LastDriver, LastPort: string;
  542. begin
  543. LastDevice := FDevice;
  544. LastDriver := FDriver;
  545. LastPort := FPort;
  546. Printer.GetPrinter(FDevice, FDriver, FPort, NewHandle);
  547. PrinterChanged := (FHandle <> NewHandle) or (LastDevice <> FDevice)
  548. or (LastDriver <> FDriver) or (LastPort <> FPort) or (FPrinter <> Printer.PrinterIndex);
  549. FHandle := NewHandle;
  550. FPrinter := Printer.PrinterIndex;
  551. Printer.SetPrinter(FDevice, FDriver, FPort, FHandle);
  552. if PrinterChanged then
  553. SetDeviceMode(False);
  554. end;
  555. procedure TJclPrintSet.SetBinArray;
  556. var
  557. NumBinsRec: DWord;
  558. ADeviceMode: PDeviceMode;
  559. begin
  560. if FBinArray <> nil then
  561. FreeMem(FBinArray, FNumBins * SizeOf(Word));
  562. FBinArray := nil;
  563. ADeviceMode := LockDeviceMode;
  564. try
  565. FNumBins := DeviceCapabilities(FDevice, FPort, DC_Bins, nil, ADeviceMode);
  566. if FNumBins > 0 then
  567. begin
  568. GetMem(FBinArray, FNumBins * SizeOf(Word));
  569. NumBinsRec := DeviceCapabilities(FDevice, FPort, DC_Bins,
  570. PChar(FBinArray), ADeviceMode);
  571. if NumBinsRec <> FNumBins then
  572. raise EJclPrinterError.CreateRes(@RsRetrievingSource);
  573. end;
  574. finally
  575. UnlockDeviceMode;
  576. end;
  577. end;
  578. procedure TJclPrintSet.SetPaperArray;
  579. var
  580. NumPapersRec: DWord;
  581. ADeviceMode: PDeviceMode;
  582. begin
  583. if FPaperArray <> nil then
  584. FreeMem(FPaperArray, FNumPapers * SizeOf(Word));
  585. ADeviceMode := LockDeviceMode;
  586. try
  587. FNumPapers := DeviceCapabilities(FDevice, FPort, DC_Papers, nil, ADeviceMode);
  588. if FNumPapers > 0 then
  589. begin
  590. GetMem(FPaperArray, FNumPapers * SizeOf(Word));
  591. NumPapersRec := DeviceCapabilities(FDevice, FPort, DC_Papers,
  592. PChar(FPaperArray), ADeviceMode);
  593. if NumPapersRec <> FNumPapers then
  594. raise EJclPrinterError.CreateRes(@RsRetrievingPaperSource);
  595. end
  596. else
  597. FPaperArray := nil;
  598. finally
  599. UnlockDeviceMode;
  600. end;
  601. end;
  602. { TODO : complete this list }
  603. // Since Win32 the strings are stored in the printer driver, no chance to get
  604. // a list from Windows
  605. function TJclPrintSet.DefaultPaperName(const PaperID: Word): string;
  606. begin
  607. case PaperID of
  608. dmpaper_Letter:
  609. Result := LoadResString(@RsPSLetter);
  610. dmpaper_LetterSmall:
  611. Result := LoadResString(@RsPSLetter);
  612. dmpaper_Tabloid:
  613. Result := LoadResString(@RsPSTabloid);
  614. dmpaper_Ledger:
  615. Result := LoadResString(@RsPSLedger);
  616. dmpaper_Legal:
  617. Result := LoadResString(@RsPSLegal);
  618. dmpaper_Statement:
  619. Result := LoadResString(@RsPSStatement);
  620. dmpaper_Executive:
  621. Result := LoadResString(@RsPSExecutive);
  622. dmpaper_A3:
  623. Result := LoadResString(@RsPSA3);
  624. dmpaper_A4:
  625. Result := LoadResString(@RsPSA4);
  626. dmpaper_A4Small:
  627. Result := LoadResString(@RsPSA4);
  628. dmpaper_A5:
  629. Result := LoadResString(@RsPSA5);
  630. dmpaper_B4:
  631. Result := LoadResString(@RsPSB4);
  632. dmpaper_B5:
  633. Result := LoadResString(@RsPSB5);
  634. dmpaper_Folio:
  635. Result := LoadResString(@RsPSFolio);
  636. dmpaper_Quarto:
  637. Result := LoadResString(@RsPSQuarto);
  638. dmpaper_10X14:
  639. Result := LoadResString(@RsPS10x14);
  640. dmpaper_11X17:
  641. Result := LoadResString(@RsPS11x17);
  642. dmpaper_Note:
  643. Result := LoadResString(@RsPSNote);
  644. dmpaper_Env_9:
  645. Result := LoadResString(@RsPSEnv9);
  646. dmpaper_Env_10:
  647. Result := LoadResString(@RsPSEnv10);
  648. dmpaper_Env_11:
  649. Result := LoadResString(@RsPSEnv11);
  650. dmpaper_Env_12:
  651. Result := LoadResString(@RsPSEnv12);
  652. dmpaper_Env_14:
  653. Result := LoadResString(@RsPSEnv14);
  654. dmpaper_CSheet:
  655. Result := LoadResString(@RsPSCSheet);
  656. dmpaper_DSheet:
  657. Result := LoadResString(@RsPSDSheet);
  658. dmpaper_ESheet:
  659. Result := LoadResString(@RsPSESheet);
  660. dmpaper_User:
  661. Result := LoadResString(@RsPSUser);
  662. else
  663. Result := LoadResString(@RsPSUnknown);
  664. end;
  665. end;
  666. procedure TJclPrintSet.GetBinSourceList(List: TStrings);
  667. type
  668. TBinName = array [0..CCHBinName - 1] of Char;
  669. TBinArray = array [1..cBinMax] of TBinName;
  670. PBinArray = ^TBinArray;
  671. var
  672. NumBinsRec: DWord;
  673. BinArray: PBinArray;
  674. BinStr: string;
  675. Idx: Integer;
  676. ADeviceMode: PDeviceMode;
  677. begin
  678. CheckPrinter;
  679. BinArray := nil;
  680. if FNumBins = 0 then
  681. Exit;
  682. List.BeginUpdate;
  683. try
  684. GetMem(BinArray, FNumBins * SizeOf(TBinName));
  685. List.Clear;
  686. ADeviceMode := LockDeviceMode;
  687. try
  688. NumBinsRec := DeviceCapabilities(FDevice, FPort, DC_BinNames,
  689. PChar(BinArray), ADeviceMode);
  690. finally
  691. UnlockDeviceMode;
  692. end;
  693. if NumBinsRec <> FNumBins then
  694. raise EJclPrinterError.CreateRes(@RsRetrievingSource);
  695. for Idx := 1 to NumBinsRec do
  696. begin
  697. BinStr := StrPas(BinArray^[Idx]);
  698. List.Add(BinStr);
  699. end;
  700. finally
  701. List.EndUpdate;
  702. if BinArray <> nil then
  703. FreeMem(BinArray, FNumBins * SizeOf(TBinName));
  704. end;
  705. end;
  706. procedure TJclPrintSet.GetPaperList(List: TStrings);
  707. type
  708. TPaperName = array [0..CCHPaperName - 1] of Char;
  709. TPaperArray = array [1..cPaperNames] of TPaperName;
  710. PPaperArray = ^TPaperArray;
  711. var
  712. NumPaperRec: DWord;
  713. PaperArray: PPaperArray;
  714. PaperStr: string;
  715. Idx: Integer;
  716. ADeviceMode: PDeviceMode;
  717. begin
  718. CheckPrinter;
  719. PaperArray := nil;
  720. if FNumPapers = 0 then
  721. Exit;
  722. List.BeginUpdate;
  723. List.Clear;
  724. try
  725. GetMem(PaperArray, FNumPapers * SizeOf(TPaperName));
  726. ADeviceMode := LockDeviceMode;
  727. try
  728. NumPaperRec := DeviceCapabilities(FDevice, FPort, DC_PaperNames,
  729. PChar(PaperArray), ADeviceMode);
  730. finally
  731. UnlockDeviceMode;
  732. end;
  733. if NumPaperRec <> FNumPapers then
  734. begin
  735. for Idx := 1 to FNumPapers do
  736. begin
  737. PaperStr := DefaultPaperName(FPaperArray^[Idx - 1]);
  738. List.Add(PaperStr);
  739. end;
  740. end
  741. else
  742. begin
  743. for Idx := 1 to NumPaperRec do
  744. begin
  745. PaperStr := StrPas(PaperArray^[Idx]);
  746. List.Add(PaperStr);
  747. end;
  748. end;
  749. finally
  750. List.EndUpdate;
  751. if PaperArray <> nil then
  752. FreeMem(PaperArray, FNumPapers * SizeOf(TPaperName));
  753. end;
  754. end;
  755. procedure TJclPrintSet.SetDeviceMode(Creating: Boolean);
  756. var
  757. Res: TPoint;
  758. ADeviceMode: PDeviceMode;
  759. NewHandle: THandle;
  760. begin
  761. Printer.GetPrinter(FDevice, FDriver, FPort, NewHandle);
  762. if NewHandle = 0 then
  763. begin
  764. Printer.PrinterIndex := Printer.PrinterIndex;
  765. Printer.GetPrinter(FDevice, FDriver, FPort, NewHandle);
  766. end;
  767. FHandle := NewHandle;
  768. if FHandle <> 0 then
  769. begin
  770. ADeviceMode := GlobalLock(FHandle);
  771. FPrinter := Printer.PrinterIndex;
  772. UpdateDeviceMode(ADeviceMode);
  773. //FDeviceMode^.dmFields := 0;
  774. SetBinArray;
  775. SetPaperArray;
  776. end
  777. else
  778. begin
  779. if not Creating then
  780. raise EJclPrinterError.CreateRes(@RsDeviceMode);
  781. FPrinter := -99;
  782. end;
  783. Res := GetPrinterResolution;
  784. dpiX := Res.X;
  785. dpiY := Res.Y;
  786. if FHandle <> 0 then
  787. GlobalUnLock(FHandle);
  788. end;
  789. procedure TJclPrintSet.UpdateDeviceMode(const ADeviceMode: PDeviceMode);
  790. var
  791. DrvHandle: THandle;
  792. ExtDevCode: Integer;
  793. begin
  794. // ONLY CALL when ADeviceMode is locked by caller!!!
  795. //CheckPrinter;
  796. if OpenPrinter(FDevice, DrvHandle, nil) then
  797. try
  798. ADeviceMode^.dmFields := dm_Orientation or dm_PaperSize or
  799. dm_PaperLength or dm_PaperWidth or
  800. dm_Scale or dm_Copies or
  801. dm_DefaultSource or dm_PrintQuality or
  802. dm_Color or dm_Duplex or
  803. dm_YResolution or dm_TTOption;
  804. ExtDevCode := DocumentProperties(0, DrvHandle, FDevice,
  805. ADeviceMode^, ADeviceMode^,
  806. DM_IN_BUFFER or DM_OUT_BUFFER);
  807. if ExtDevCode <> IDOK then
  808. raise EJclPrinterError.CreateRes(@RsUpdatingPrinter);
  809. finally
  810. ClosePrinter(DrvHandle);
  811. end;
  812. end;
  813. procedure TJclPrintSet.SaveToDefaults;
  814. var
  815. DrvHandle: THandle;
  816. ExtDevCode: Integer;
  817. ADeviceMode: PDeviceMode;
  818. begin
  819. CheckPrinter;
  820. OpenPrinter(FDevice, DrvHandle, nil);
  821. ADeviceMode := LockDeviceMode;
  822. try
  823. ExtDevCode := DocumentProperties(0, DrvHandle, FDevice,
  824. ADeviceMode^, ADeviceMode^, DM_IN_BUFFER or DM_UPDATE);
  825. finally
  826. UnlockDeviceMode;
  827. end;
  828. if ExtDevCode <> IDOK then
  829. raise EJclPrinterError.CreateRes(@RsUpdatingPrinter)
  830. else
  831. SendMessage(HWND_BROADCAST, WM_SETTINGCHANGE, 0, 0);
  832. ClosePrinter(DrvHandle);
  833. end;
  834. procedure TJclPrintSet.SavePrinterAsDefault;
  835. begin
  836. CheckPrinter;
  837. DPSetDefaultPrinter(FDevice);
  838. end;
  839. procedure TJclPrintSet.ResetPrinterDialogs;
  840. begin
  841. Printer.GetPrinter(FDevice, FDriver, FPort, FHandle);
  842. Printer.SetPrinter(FDevice, FDriver, FPort, FHandle);
  843. SetDeviceMode(False);
  844. end;
  845. function TJclPrintSet.XInchToDot(const Inches: Double): Integer;
  846. begin
  847. Result := Trunc(DpiX * Inches);
  848. end;
  849. function TJclPrintSet.YInchToDot(const Inches: Double): Integer;
  850. begin
  851. Result := Trunc(DpiY * Inches);
  852. end;
  853. function TJclPrintSet.XCmToDot(const Cm: Double): Integer;
  854. begin
  855. Result := Trunc(DpiX * (Cm * 2.54));
  856. end;
  857. function TJclPrintSet.YCmToDot(const Cm: Double): Integer;
  858. begin
  859. Result := Trunc(DpiY * (Cm * 2.54));
  860. end;
  861. function TJclPrintSet.CpiToDot(const Cpi, Chars: Double): Integer;
  862. begin
  863. Result := Trunc((DpiX * Chars) / Cpi);
  864. end;
  865. function TJclPrintSet.LpiToDot(const Lpi, Lines: Double): Integer;
  866. begin
  867. Result := Trunc((DpiY * Lpi) / Lines);
  868. end;
  869. procedure TJclPrintSet.TextOutInch(const X, Y: Double; const Text: string);
  870. begin
  871. Printer.Canvas.TextOut(XInchToDot(X), YInchToDot(Y), Text);
  872. end;
  873. procedure TJclPrintSet.TextOutCm(const X, Y: Double; const Text: string);
  874. begin
  875. Printer.Canvas.TextOut(XCmToDot(X), YCmToDot(Y), Text);
  876. end;
  877. procedure TJclPrintSet.TextOutCpiLpi(const Cpi, Chars, Lpi, Lines: Double; const Text: string);
  878. begin
  879. Printer.Canvas.TextOut(CpiToDot(Cpi, Chars), LpiToDot(Lpi, Lines), Text);
  880. end;
  881. procedure TJclPrintSet.CustomPageSetup(const Width, Height: Double);
  882. begin
  883. PaperSize := dmPaper_User;
  884. PaperLength := Trunc(254 * Height);
  885. YResolution := Trunc(DpiY * Height);
  886. PaperWidth := Trunc(254 * Width);
  887. end;
  888. procedure TJclPrintSet.DevModePrinterDriverExtraClear;
  889. var
  890. ADeviceMode: PDeviceMode;
  891. begin
  892. CheckPrinter;
  893. ADeviceMode := LockDeviceMode;
  894. try
  895. ADeviceMode^.dmDriverExtra := 0;
  896. finally
  897. UnlockDeviceMode;
  898. end;
  899. end;
  900. procedure TJclPrintSet.DevModePrinterDriverExtraReinstate(const ExtraData: TDynByteArray;
  901. const ExtraDataDriverName: string; const ExtraDataDriverVersion: Word);
  902. var
  903. Src, Dest: PDeviceMode;
  904. ADeviceModeDriverExtra: PByte;
  905. NewHandle: THandle;
  906. begin
  907. CheckPrinter;
  908. { http://support.microsoft.com/kb/167345
  909. Using a DEVMODE structure to modify printer settings is more difficult than just changing the fields of the structure. Specifically, a valid DEVMODE structure for a device contains private data that can only be modified by the DocumentProperties() function.
  910. This article explains how to modify the contents of a DEVMODE structure with the DocumentProperties() function.}
  911. if FHandle <> 0 then
  912. begin
  913. Src := GlobalLock(FHandle);
  914. try
  915. if not ((Src^.dmDeviceName = ExtraDataDriverName) and (Src^.dmDriverVersion = ExtraDataDriverVersion)) then
  916. exit;
  917. //raise Exception.Create('TJclPrintSet.DevModePrinterDriverExtraReinstate - Driver Private data does not match selected printer');
  918. NewHandle := GlobalAlloc(GHND, sizeof(DEVMODE) + Length(ExtraData));
  919. if NewHandle <> 0 then
  920. try
  921. Dest := GlobalLock(NewHandle);
  922. if (Src <> nil) and (Dest <> nil) then
  923. begin
  924. Move(Src^, Dest^, Src^.dmSize);
  925. Dest^.dmDriverExtra := 0;
  926. Dest^.dmDriverExtra := Length(ExtraData);
  927. ADeviceModeDriverExtra := PByte(Dest);
  928. Inc(ADeviceModeDriverExtra, Dest^.dmSize);
  929. Move(ExtraData[0], ADeviceModeDriverExtra^, dest^.dmDriverExtra);
  930. end
  931. else
  932. raise Exception.Create('TJclPrintSet.DevModePrinterDriverExtraReinstate - GlobalLock failed');
  933. finally
  934. GlobalUnlock(NewHandle);
  935. end;
  936. Printer.SetPrinter(FDevice, FDriver, FPort, NewHandle);
  937. FHandle := NewHandle;
  938. SetDeviceMode(False);
  939. finally
  940. GlobalUnlock(FHandle);
  941. end;
  942. end
  943. else
  944. raise Exception.Create('TJclPrintSet.DevModePrinterDriverExtraReinstate invalid handle');
  945. end;
  946. procedure TJclPrintSet.SaveToIniFile(const IniFileName, Section: string);
  947. var
  948. PrIniFile: TMemIniFile;
  949. begin
  950. PrIniFile := TMemIniFile.Create(IniFileName); // use TMemIniFile as TIniFile truncats longs values
  951. try
  952. SaveToCustomIni(PrIniFile, Section);
  953. PrIniFile.UpdateFile;
  954. finally
  955. PrIniFile.Free;
  956. end;
  957. end;
  958. function TJclPrintSet.ReadFromIniFile(const IniFileName, Section: string): Boolean;
  959. var
  960. PrIniFile: TMemIniFile;
  961. begin
  962. PrIniFile := TMemIniFile.Create(IniFileName); // use TMemIniFile as TIniFile truncats longs values
  963. try
  964. Result := ReadFromCustomIni(PrIniFile, Section);
  965. finally
  966. PrIniFile.Free;
  967. end;
  968. end;
  969. procedure TJclPrintSet.SetOrientation(Orientation: Integer);
  970. var
  971. ADeviceMode: PDeviceMode;
  972. begin
  973. CheckPrinter;
  974. ADeviceMode := LockDeviceMode;
  975. try
  976. ADeviceMode^.dmOrientation := Orientation;
  977. Printer.Orientation := TPrinterOrientation(Orientation - 1);
  978. ADeviceMode^.dmFields := ADeviceMode^.dmFields or DM_ORIENTATION;
  979. finally
  980. UnlockDeviceMode;
  981. end;
  982. end;
  983. function TJclPrintSet.GetOrientation: Integer;
  984. var
  985. ADeviceMode: PDeviceMode;
  986. begin
  987. CheckPrinter;
  988. ADeviceMode := LockDeviceMode;
  989. try
  990. Result := ADeviceMode^.dmOrientation;
  991. finally
  992. UnlockDeviceMode;
  993. end;
  994. end;
  995. procedure TJclPrintSet.SetPaperSize(Size: Integer);
  996. var
  997. ADeviceMode: PDeviceMode;
  998. begin
  999. CheckPrinter;
  1000. ADeviceMode := LockDeviceMode;
  1001. try
  1002. ADeviceMode^.dmPaperSize := Size;
  1003. ADeviceMode^.dmFields := ADeviceMode^.dmFields or DM_PAPERSIZE;
  1004. finally
  1005. UnlockDeviceMode;
  1006. end;
  1007. end;
  1008. function TJclPrintSet.GetPaperSize: Integer;
  1009. var
  1010. ADeviceMode: PDeviceMode;
  1011. begin
  1012. CheckPrinter;
  1013. ADeviceMode := LockDeviceMode;
  1014. try
  1015. Result := ADeviceMode^.dmPaperSize;
  1016. finally
  1017. UnlockDeviceMode;
  1018. end;
  1019. end;
  1020. procedure TJclPrintSet.SetPaperLength(Length: Integer);
  1021. var
  1022. ADeviceMode: PDeviceMode;
  1023. begin
  1024. CheckPrinter;
  1025. ADeviceMode := LockDeviceMode;
  1026. try
  1027. ADeviceMode^.dmPaperLength := Length;
  1028. ADeviceMode^.dmFields := ADeviceMode^.dmFields or DM_PAPERLENGTH;
  1029. finally
  1030. UnlockDeviceMode;
  1031. end;
  1032. end;
  1033. function TJclPrintSet.GetPaperLength: Integer;
  1034. var
  1035. ADeviceMode: PDeviceMode;
  1036. begin
  1037. CheckPrinter;
  1038. ADeviceMode := LockDeviceMode;
  1039. try
  1040. Result := ADeviceMode^.dmPaperLength;
  1041. finally
  1042. UnlockDeviceMode;
  1043. end;
  1044. end;
  1045. procedure TJclPrintSet.SetPaperWidth(Width: Integer);
  1046. var
  1047. ADeviceMode: PDeviceMode;
  1048. begin
  1049. CheckPrinter;
  1050. ADeviceMode := LockDeviceMode;
  1051. try
  1052. ADeviceMode^.dmPaperWidth := Width;
  1053. ADeviceMode^.dmFields := ADeviceMode^.dmFields or DM_PAPERWIDTH;
  1054. finally
  1055. UnlockDeviceMode;
  1056. end;
  1057. end;
  1058. function TJclPrintSet.GetPaperWidth: Integer;
  1059. var
  1060. ADeviceMode: PDeviceMode;
  1061. begin
  1062. CheckPrinter;
  1063. ADeviceMode := LockDeviceMode;
  1064. try
  1065. Result := ADeviceMode^.dmPaperWidth;
  1066. finally
  1067. UnlockDeviceMode;
  1068. end;
  1069. end;
  1070. procedure TJclPrintSet.SetScale(Scale: Integer);
  1071. var
  1072. ADeviceMode: PDeviceMode;
  1073. begin
  1074. CheckPrinter;
  1075. ADeviceMode := LockDeviceMode;
  1076. try
  1077. ADeviceMode^.dmScale := Scale;
  1078. ADeviceMode^.dmFields := ADeviceMode^.dmFields or DM_SCALE;
  1079. finally
  1080. UnlockDeviceMode;
  1081. end;
  1082. end;
  1083. function TJclPrintSet.GetScale: Integer;
  1084. var
  1085. ADeviceMode: PDeviceMode;
  1086. begin
  1087. CheckPrinter;
  1088. ADeviceMode := LockDeviceMode;
  1089. try
  1090. Result := ADeviceMode^.dmScale;
  1091. finally
  1092. UnlockDeviceMode;
  1093. end;
  1094. end;
  1095. procedure TJclPrintSet.SetCopies(Copies: Integer);
  1096. var
  1097. ADeviceMode: PDeviceMode;
  1098. begin
  1099. CheckPrinter;
  1100. ADeviceMode := LockDeviceMode;
  1101. try
  1102. ADeviceMode^.dmCopies := Copies;
  1103. ADeviceMode^.dmFields := ADeviceMode^.dmFields or DM_COPIES;
  1104. finally
  1105. UnlockDeviceMode;
  1106. end;
  1107. end;
  1108. function TJclPrintSet.GetCopies: Integer;
  1109. var
  1110. ADeviceMode: PDeviceMode;
  1111. begin
  1112. CheckPrinter;
  1113. ADeviceMode := LockDeviceMode;
  1114. try
  1115. Result := ADeviceMode^.dmCopies;
  1116. finally
  1117. UnlockDeviceMode;
  1118. end;
  1119. end;
  1120. procedure TJclPrintSet.SetBin(Bin: Integer);
  1121. var
  1122. ADeviceMode: PDeviceMode;
  1123. begin
  1124. CheckPrinter;
  1125. ADeviceMode := LockDeviceMode;
  1126. try
  1127. ADeviceMode^.dmDefaultSource := Bin;
  1128. ADeviceMode^.dmFields := ADeviceMode^.dmFields or DM_DEFAULTSOURCE;
  1129. finally
  1130. UnlockDeviceMode;
  1131. end;
  1132. end;
  1133. function TJclPrintSet.GetBin: Integer;
  1134. var
  1135. ADeviceMode: PDeviceMode;
  1136. begin
  1137. CheckPrinter;
  1138. ADeviceMode := LockDeviceMode;
  1139. try
  1140. Result := ADeviceMode^.dmDefaultSource;
  1141. finally
  1142. UnlockDeviceMode;
  1143. end;
  1144. end;
  1145. procedure TJclPrintSet.SetPrintQuality(Quality: Integer);
  1146. var
  1147. ADeviceMode: PDeviceMode;
  1148. begin
  1149. CheckPrinter;
  1150. ADeviceMode := LockDeviceMode;
  1151. try
  1152. ADeviceMode^.dmPrintQuality := Quality;
  1153. ADeviceMode^.dmFields := ADeviceMode^.dmFields or DM_PRINTQUALITY;
  1154. finally
  1155. UnlockDeviceMode;
  1156. end;
  1157. end;
  1158. function TJclPrintSet.GetPrintQuality: Integer;
  1159. var
  1160. ADeviceMode: PDeviceMode;
  1161. begin
  1162. CheckPrinter;
  1163. ADeviceMode := LockDeviceMode;
  1164. try
  1165. Result := ADeviceMode^.dmPrintQuality;
  1166. finally
  1167. UnlockDeviceMode;
  1168. end;
  1169. end;
  1170. procedure TJclPrintSet.SetColor(Color: Integer);
  1171. var
  1172. ADeviceMode: PDeviceMode;
  1173. begin
  1174. CheckPrinter;
  1175. ADeviceMode := LockDeviceMode;
  1176. try
  1177. ADeviceMode^.dmColor := Color;
  1178. ADeviceMode^.dmFields := ADeviceMode^.dmFields or DM_COLOR;
  1179. finally
  1180. UnlockDeviceMode;
  1181. end;
  1182. end;
  1183. function TJclPrintSet.GetColor: Integer;
  1184. var
  1185. ADeviceMode: PDeviceMode;
  1186. begin
  1187. CheckPrinter;
  1188. ADeviceMode := LockDeviceMode;
  1189. try
  1190. Result := ADeviceMode^.dmColor;
  1191. finally
  1192. UnlockDeviceMode;
  1193. end;
  1194. end;
  1195. procedure TJclPrintSet.SetDuplex(Duplex: Integer);
  1196. var
  1197. ADeviceMode: PDeviceMode;
  1198. begin
  1199. CheckPrinter;
  1200. ADeviceMode := LockDeviceMode;
  1201. try
  1202. ADeviceMode^.dmDuplex := Duplex;
  1203. ADeviceMode^.dmFields := ADeviceMode^.dmFields or DM_DUPLEX;
  1204. finally
  1205. UnlockDeviceMode;
  1206. end;
  1207. end;
  1208. function TJclPrintSet.GetDuplex: Integer;
  1209. var
  1210. ADeviceMode: PDeviceMode;
  1211. begin
  1212. CheckPrinter;
  1213. ADeviceMode := LockDeviceMode;
  1214. try
  1215. Result := ADeviceMode^.dmDuplex;
  1216. finally
  1217. UnlockDeviceMode;
  1218. end;
  1219. end;
  1220. procedure TJclPrintSet.SetYResolution(YRes: Integer);
  1221. var
  1222. PrintDevMode: PDeviceModeA;
  1223. ADeviceMode: PDeviceMode;
  1224. begin
  1225. CheckPrinter;
  1226. ADeviceMode := LockDeviceMode;
  1227. try
  1228. PrintDevMode := @ADeviceMode^;
  1229. PrintDevMode^.dmYResolution := YRes;
  1230. ADeviceMode^.dmFields := ADeviceMode^.dmFields or DM_YRESOLUTION;
  1231. finally
  1232. UnlockDeviceMode;
  1233. end;
  1234. end;
  1235. function TJclPrintSet.GetYResolution: Integer;
  1236. var
  1237. PrintDevMode: PDeviceModeA;
  1238. ADeviceMode: PDeviceMode;
  1239. begin
  1240. CheckPrinter;
  1241. ADeviceMode := LockDeviceMode;
  1242. try
  1243. PrintDevMode := @ADeviceMode^;
  1244. Result := PrintDevMode^.dmYResolution;
  1245. finally
  1246. UnlockDeviceMode;
  1247. end;
  1248. end;
  1249. procedure TJclPrintSet.SetTrueTypeOption(Option: Integer);
  1250. var
  1251. PrintDevMode: PDeviceModeA;
  1252. ADeviceMode: PDeviceMode;
  1253. begin
  1254. CheckPrinter;
  1255. ADeviceMode := LockDeviceMode;
  1256. try
  1257. PrintDevMode := @ADeviceMode^;
  1258. PrintDevMode^.dmTTOption := Option;
  1259. ADeviceMode^.dmFields := ADeviceMode^.dmFields or DM_TTOPTION;
  1260. finally
  1261. UnlockDeviceMode;
  1262. end;
  1263. end;
  1264. function TJclPrintSet.GetTrueTypeOption: Integer;
  1265. var
  1266. PrintDevMode: PDeviceModeA;
  1267. ADeviceMode: PDeviceMode;
  1268. begin
  1269. CheckPrinter;
  1270. ADeviceMode := LockDeviceMode;
  1271. try
  1272. PrintDevMode := @ADeviceMode^;
  1273. Result := PrintDevMode^.dmTTOption;
  1274. finally
  1275. UnlockDeviceMode;
  1276. end;
  1277. end;
  1278. function TJclPrintSet.GetPrinterName: string;
  1279. begin
  1280. CheckPrinter;
  1281. Result := StrPas(FDevice);
  1282. end;
  1283. function TJclPrintSet.GetPrinterPort: string;
  1284. begin
  1285. CheckPrinter;
  1286. Result := StrPas(FPort);
  1287. end;
  1288. function TJclPrintSet.GetPrinterDriver: string;
  1289. begin
  1290. CheckPrinter;
  1291. Result := StrPas(FDriver);
  1292. end;
  1293. procedure TJclPrintSet.SetBinFromList(BinNum: Word);
  1294. begin
  1295. CheckPrinter;
  1296. if FNumBins = 0 then
  1297. Exit;
  1298. if BinNum > FNumBins then
  1299. raise EJclPrinterError.CreateRes(@RsIndexOutOfRange)
  1300. else
  1301. DefaultSource := FBinArray^[BinNum];
  1302. end;
  1303. function TJclPrintSet.GetBinIndex: Word;
  1304. var
  1305. Idx: Word;
  1306. ADeviceMode: PDeviceMode;
  1307. begin
  1308. Result := 0;
  1309. ADeviceMode := LockDeviceMode;
  1310. try
  1311. for Idx := 0 to FNumBins do
  1312. begin
  1313. if FBinArray^[Idx] = Word(ADeviceMode^.dmDefaultSource) then
  1314. begin
  1315. Result := Idx;
  1316. Break;
  1317. end;
  1318. end;
  1319. finally
  1320. UnlockDeviceMode;
  1321. end;
  1322. end;
  1323. function TJclPrintSet.GetDevModePrinterDriverVersion: Word;
  1324. var
  1325. ADeviceMode: PDeviceMode;
  1326. begin
  1327. CheckPrinter;
  1328. ADeviceMode := LockDeviceMode;
  1329. try
  1330. Result := ADeviceMode^.dmDriverVersion;
  1331. finally
  1332. UnlockDeviceMode;
  1333. end;
  1334. end;
  1335. function TJclPrintSet.GetDevModePrinterDriver: string;
  1336. var
  1337. ADeviceMode: PDeviceMode;
  1338. begin
  1339. CheckPrinter;
  1340. ADeviceMode := LockDeviceMode;
  1341. try
  1342. Result := ADeviceMode^.dmDeviceName;
  1343. finally
  1344. UnlockDeviceMode;
  1345. end;
  1346. end;
  1347. function TJclPrintSet.GetDevModePrinterDriverExtra: TDynByteArray;
  1348. var
  1349. ADeviceMode: PDeviceMode;
  1350. ADeviceModeDriverExtra: PByte;
  1351. begin
  1352. CheckPrinter;
  1353. ADeviceMode := LockDeviceMode;
  1354. try
  1355. ADeviceModeDriverExtra := PByte(ADeviceMode);
  1356. Inc(ADeviceModeDriverExtra, ADeviceMode^.dmSize);
  1357. SetLength(Result, ADeviceMode^.dmDriverExtra);
  1358. Move(ADeviceModeDriverExtra^, Result[0], ADeviceMode^.dmDriverExtra);
  1359. finally
  1360. UnlockDeviceMode;
  1361. end;
  1362. end;
  1363. procedure TJclPrintSet.SetPaperFromList(PaperNum: Word);
  1364. begin
  1365. CheckPrinter;
  1366. if FNumPapers = 0 then
  1367. Exit;
  1368. if PaperNum > FNumPapers then
  1369. raise EJclPrinterError.CreateRes(@RsIndexOutOfRangePaper)
  1370. else
  1371. PaperSize := FPaperArray^[PaperNum];
  1372. end;
  1373. procedure TJclPrintSet.SetPort(Port: string);
  1374. begin
  1375. CheckPrinter;
  1376. Port := Port + #0;
  1377. Move(Port[1], FPort^, Length(Port));
  1378. Printer.SetPrinter(FDevice, FDriver, FPort, FHandle);
  1379. end;
  1380. function TJclPrintSet.GetPaperIndex: Word;
  1381. var
  1382. Idx: Word;
  1383. ADeviceMode: PDeviceMode;
  1384. begin
  1385. Result := 0;
  1386. ADeviceMode := LockDeviceMode;
  1387. try
  1388. for Idx := 0 to FNumPapers do
  1389. begin
  1390. if FPaperArray^[Idx] = Word(ADeviceMode^.dmPaperSize) then
  1391. begin
  1392. Result := Idx;
  1393. Break;
  1394. end;
  1395. end;
  1396. finally
  1397. UnlockDeviceMode;
  1398. end;
  1399. end;
  1400. function TJclPrintSet.LockDeviceMode: PDeviceMode;
  1401. begin
  1402. if FHandle <> 0 then
  1403. begin
  1404. Result := GlobalLock(FHandle);
  1405. if not assigned(Result) then
  1406. RaiseLastOSError;
  1407. end
  1408. else
  1409. raise Exception.Create('TJclPrintSet.LockDeviceMode invalid FHandle');
  1410. end;
  1411. function TJclPrintSet.ReadFromCustomIni(const PrIniFile: TCustomIniFile; const Section: string): Boolean;
  1412. var
  1413. privData: TMemoryStream;
  1414. privDataExtra: TDynByteArray;
  1415. privDataExtraSize: Integer;
  1416. DevModeDriverName: string;
  1417. DevModeDriverVersion: Word;
  1418. begin
  1419. PrinterName := PrIniFile.ReadString(Section, PrintIniPrinterName, PrinterName);
  1420. PrinterPort := PrIniFile.ReadString(Section, PrintIniPrinterPort, PrinterPort);
  1421. Orientation := PrIniFile.ReadInteger(Section, PrintIniOrientation, Orientation);
  1422. PaperSize := PrIniFile.ReadInteger(Section, PrintIniPaperSize, PaperSize);
  1423. PaperLength := PrIniFile.ReadInteger(Section, PrintIniPaperLength, PaperLength);
  1424. PaperWidth := PrIniFile.ReadInteger(Section, PrintIniPaperWidth, PaperWidth);
  1425. Scale := PrIniFile.ReadInteger(Section, PrintIniScale, Scale);
  1426. Copies := PrIniFile.ReadInteger(Section, PrintIniCopies, Copies);
  1427. DefaultSource := PrIniFile.ReadInteger(Section, PrintIniDefaultSource, DefaultSource);
  1428. PrintQuality := PrIniFile.ReadInteger(Section, PrintIniPrintQuality, PrintQuality);
  1429. Color := PrIniFile.ReadInteger(Section, PrintIniColor, Color);
  1430. Duplex := PrIniFile.ReadInteger(Section, PrintIniDuplex, Duplex);
  1431. YResolution := PrIniFile.ReadInteger(Section, PrintIniYResolution, YResolution);
  1432. TrueTypeOption := PrIniFile.ReadInteger(Section, PrintIniTTOption, TrueTypeOption);
  1433. DevModeDriverName := PrIniFile.ReadString(Section, PrintDriverName, '');
  1434. DevModeDriverVersion := Word(PrIniFile.ReadInteger(Section, PrintDriverVersion, 0));
  1435. if (DevModePrinterDriver = DevModeDriverName) and
  1436. (DevModePrinterDriverVersion = DevModeDriverVersion) then
  1437. begin
  1438. privData := TMemoryStream.Create;
  1439. try
  1440. PrIniFile.ReadBinaryStream(Section, PrintDriverExtraData, privData);
  1441. privDataExtraSize := PrIniFile.ReadInteger(Section, PrintDriverExtraSize, 0);
  1442. if (privData.Size = privDataExtraSize) then
  1443. begin
  1444. SetLength(privDataExtra, privDataExtraSize);
  1445. privdata.Read(privDataExtra[0], privDataExtraSize);
  1446. DevModePrinterDriverExtraReinstate(privDataExtra, DevModeDriverName, DevModeDriverVersion);
  1447. end;
  1448. finally
  1449. privData.Free;
  1450. end;
  1451. end;
  1452. Result := True;
  1453. end;
  1454. procedure TJclPrintSet.SaveToCustomIni(const PrIniFile: TCustomIniFile; const Section: string);
  1455. var
  1456. CurrentName: string;
  1457. privData: TMemoryStream;
  1458. privDataExtra: TDynByteArray;
  1459. begin
  1460. PrIniFile.EraseSection(Section);
  1461. CurrentName := Printer.Printers[Printer.PrinterIndex];
  1462. PrIniFile.WriteString(Section, PrintIniPrinterName, CurrentName);
  1463. PrIniFile.WriteString(Section, PrintIniPrinterPort, PrinterPort);
  1464. PrIniFile.WriteInteger(Section, PrintIniOrientation, Orientation);
  1465. PrIniFile.WriteInteger(Section, PrintIniPaperSize, PaperSize);
  1466. PrIniFile.WriteInteger(Section, PrintIniPaperLength, PaperLength);
  1467. PrIniFile.WriteInteger(Section, PrintIniPaperWidth, PaperWidth);
  1468. PrIniFile.WriteInteger(Section, PrintIniScale, Scale);
  1469. PrIniFile.WriteInteger(Section, PrintIniCopies, Copies);
  1470. PrIniFile.WriteInteger(Section, PrintIniDefaultSource, DefaultSource);
  1471. PrIniFile.WriteInteger(Section, PrintIniPrintQuality, PrintQuality);
  1472. PrIniFile.WriteInteger(Section, PrintIniColor, Color);
  1473. PrIniFile.WriteInteger(Section, PrintIniDuplex, Duplex);
  1474. PrIniFile.WriteInteger(Section, PrintIniYResolution, YResolution);
  1475. PrIniFile.WriteInteger(Section, PrintIniTTOption, TrueTypeOption);
  1476. PrIniFile.WriteString(Section, PrintDriverName, DevModePrinterDriver);
  1477. PrIniFile.WriteInteger(Section, PrintDriverVersion, DevModePrinterDriverVersion);
  1478. PrIniFile.WriteInteger(Section, PrintDriverExtraSize, Length(DevModePrinterDriverExtra));
  1479. privDataExtra := DevModePrinterDriverExtra;
  1480. privData := TMemoryStream.Create;
  1481. try
  1482. privdata.Write(privDataExtra[0], Length(privDataExtra));
  1483. privData.Position := 0;
  1484. PrIniFile.WriteBinaryStream(Section, PrintDriverExtraData, privData);
  1485. finally
  1486. privData.Free;
  1487. end;
  1488. end;
  1489. procedure TJclPrintSet.SetPrinterName(const Value: string);
  1490. var
  1491. NewIndex: Integer;
  1492. begin
  1493. if PrinterName <> Value then
  1494. begin
  1495. NewIndex := Printer.Printers.IndexOf(Value);
  1496. if NewIndex <> -1 then
  1497. begin
  1498. Printer.PrinterIndex := NewIndex;
  1499. end;
  1500. end;
  1501. CheckPrinter;
  1502. end;
  1503. procedure TJclPrintSet.UnlockDeviceMode;
  1504. begin
  1505. if FHandle <> 0 then
  1506. GlobalUnLock(FHandle);
  1507. end;
  1508. {$IFDEF UNITVERSIONING}
  1509. initialization
  1510. RegisterUnitVersion(HInstance, UnitVersioning);
  1511. finalization
  1512. UnregisterUnitVersion(HInstance);
  1513. {$ENDIF UNITVERSIONING}
  1514. end.