Contributor: BRAD STOWERS { NOTE DCR AND DEMO located at the END of this unit } {-----------------------------------------------------------------------------} { A component to wrap the Win95 PageSetupDlg common dialog API function. } { Borland seems to have forgotten this new common dialog in Delphi 2.0. } { Copyright 1996, Brad Stowers. All Rights Reserved. } { This component can be freely used and distributed in commercial and private } { environments, provided this notice is not modified in any way and there is } { no charge for it other than nominal handling fees. Contact me directly for } { modifications to this agreement. } {-----------------------------------------------------------------------------} { Feel free to contact me if you have any questions, comments or suggestions } { at bstowers@pobox.com or 72733,3374 on CompuServe. } { The lateset version will always be available on the web at: } { http://www.pobox.com/~bstowers/delphi/ } {-----------------------------------------------------------------------------} { Date last modified: 08/27/96 } {-----------------------------------------------------------------------------} { ----------------------------------------------------------------------------} { TPageSetupDialog v1.00 } { ----------------------------------------------------------------------------} { Description: } { A component to wrap the PageSetupDlg API function that Borland forgot. } { It is a common dialog available on the Win95 platform, so it can not be } { used with Delphi 1.0. } { ----------------------------------------------------------------------------} { Revision History: } { 1.00: + Initial release. } { ----------------------------------------------------------------------------} unit PgSetup; interface {$IFNDEF WIN32} ERROR! This unit only available for Delphi 2.0!!! {$ENDIF} uses Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs, CommDlg, DsgnIntf; type TPageSetupOption = ( poDefaultMinMargins, poDisableMargins, poDisableOrientation, poDisablePagePainting, poDisablePaper, poDisablePrinter, poNoWarning, poShowHelp ); TPageSetupOptions = set of TPageSetupOption; TPSPaperType = (ptPaper, ptEnvelope); TPSPaperOrientation = (poPortrait, poLandscape); TPSPrinterType = (ptDotMatrix, ptHPPCL); TPSPaintWhat = (pwFullPage, pwMinimumMargins, pwMargins, pwGreekText, pwEnvStamp, pwYAFullPage); TPSMeasurements = (pmMillimeters, pmInches); TPSPrinterEvent = procedure(Sender: TObject; Wnd: HWND) of object; { PPSDlgData is simply redeclared as PPageSetupDlg (COMMDLG.PAS) to prevent compile } { errors in units that have this event. They won't compile unless you add CommDlg } { to their units. This circumvents the problem. } PPSDlgData = ^TPSDlgData; TPSDlgData = TPageSetupDlg; { PaperSize: See DEVMODE help topic, dmPaperSize member. DMPAPER_* constants. } TPSInitPaintPageEvent = function(Sender: TObject; PaperSize: short; PaperType: TPSPaperType; PaperOrientation: TPSPaperOrientation; PrinterType: TPSPrinterType; pSetupData: PPSDlgData): boolean of object; TPSPaintPageEvent = function(Sender: TObject; PaintWhat: TPSPaintWhat; Canvas: TCanvas; Rect: TRect): boolean of object; TPageSetupDialog = class(TCommonDialog) private FOptions: TPageSetupOptions; FCustomData: LPARAM; FPaperSize: TPoint; FMinimumMargins: TRect; FMargins: TRect; FMeasurements: TPSMeasurements; FOnPrinter: TPSPrinterEvent; FOnInitPaintPage: TPSInitPaintPageEvent; FOnPaintPage: TPSPaintPageEvent; function DoPrinter(Wnd: HWND): boolean; function DoExecute(Func: pointer): boolean; protected function Printer(Wnd: HWND): boolean; virtual; public constructor Create(AOwner: TComponent); override; destructor Destroy; override; function Execute: boolean; virtual; { It is the user's responsibility to clean up this pointer if necessary. } property CustomData: LPARAM read FCustomData write FCustomData; { These should be published, but need Property Editors for TPoint and TRect. As } { best I can tell, there is no way to do that, since they need RTTI, and that is } { not available for record types. Bummer. } { Also, all of these rects return sizes that need to be divided by 1000. For } { example, PaperSize.X would be 8500 for 8.5 inch paper. Maybe I should make a } { TSingleRect and TSinglePoint and return the actual single value, but the API } { returns them to me that way, and I'm lazy by default. :) } property PaperSize: TPoint read FPaperSize write FPaperSize; property MinimumMargins: TRect read FMinimumMargins write FMinimumMargins; property Margins: TRect read FMargins write FMargins; published property Options: TPageSetupOptions read FOptions write FOptions default [poDefaultMinMargins, poShowHelp]; property Measurements: TPSMeasurements read FMeasurements write FMeasurements default pmInches; { Events } property OnPrinter: TPSPrinterEvent read FOnPrinter write FOnPrinter; property OnInitPaintPage: TPSInitPaintPageEvent read FOnInitPaintPage write FOnInitPaintPage; property OnPaintPage: TPSPaintPageEvent read FOnPaintPage write FOnPaintPage; end; procedure Register; implementation uses Printers; const IDPRINTERBTN = $0402; { Private globals } var HelpMsg: Integer; HookCtl3D: boolean; { Center the given window on the screen } procedure CenterWindow(Wnd: HWnd); var Rect: TRect; begin GetWindowRect(Wnd, Rect); SetWindowPos(Wnd, 0, (GetSystemMetrics(SM_CXSCREEN) - Rect.Right + Rect.Left) div 2, (GetSystemMetrics(SM_CYSCREEN) - Rect.Bottom + Rect.Top) div 3, 0, 0, SWP_NOACTIVATE or SWP_NOSIZE or SWP_NOZORDER); end; { Generic dialog hook. Centers the dialog on the screen in response to the WM_INITDIALOG message } function DialogHook(Wnd: HWnd; Msg: UINT; WParam: WPARAM; LParam: LPARAM): UINT; stdcall; begin Result := 0; case Msg of WM_INITDIALOG: begin if HookCtl3D then begin Subclass3DDlg(Wnd, CTL3D_ALL); SetAutoSubClass(True); end; CenterWindow(Wnd); Result := 1; end; WM_DESTROY: if HookCtl3D then SetAutoSubClass(False); end; end; var PageSetupDialog: TPageSetupDialog; function PageSetupDialogHook(Wnd: HWnd; Msg: UINT; WParam: WPARAM; LParam: LPARAM): UINT; stdcall; const PagePaintWhat: array[WM_PSD_FULLPAGERECT.. WM_PSD_YAFULLPAGERECT] of TPSPaintWhat = ( pwFullPage, pwMinimumMargins, pwMargins, pwGreekText, pwEnvStamp, pwYAFullPage ); PRINTER_MASK = $00000002; ORIENT_MASK = $00000004; PAPER_MASK = $00000008; var PaperData: word; Paper: TPSPaperType; Orient: TPSPaperOrientation; Printer: TPSPrinterType; PaintRect: TRect; PaintCanvas: TCanvas; begin if (Msg = WM_COMMAND) and (LongRec(WParam).Lo = IDPRINTERBTN) and (LongRec(WParam).Hi = BN_CLICKED) then begin // if hander is assigned, use it. If not, let system do it. Result := ord(PageSetupDialog.DoPrinter(Wnd)); end else begin if assigned(PageSetupDialog.FOnInitPaintPage) and assigned(PageSetupDialog.FOnPaintPage) then begin case Msg of WM_PSD_PAGESETUPDLG: begin PaperData := HiWord(WParam); if (PaperData AND PAPER_MASK > 0) then Paper := ptEnvelope else Paper := ptPaper; if (PaperData AND ORIENT_MASK > 0) then Orient := poPortrait else Orient := poLandscape; if (PaperData AND PAPER_MASK > 0) then Printer := ptHPPCL else Printer := ptDotMatrix; Result := Ord(PageSetupDialog.FOnInitPaintPage(PageSetupDialog, LoWord(WParam), Paper, Orient, Printer, PPSDlgData(LParam))); end; WM_PSD_FULLPAGERECT, WM_PSD_MINMARGINRECT, WM_PSD_MARGINRECT, WM_PSD_GREEKTEXTRECT, WM_PSD_ENVSTAMPRECT, WM_PSD_YAFULLPAGERECT: begin if LParam <> 0 then PaintRect := PRect(LParam)^ else PaintRect := Rect(0,0,0,0); PaintCanvas := TCanvas.Create; PaintCanvas.Handle := HDC(WParam); try Result := Ord(PageSetupDialog.FOnPaintPage(PageSetupDialog, PagePaintWhat[Msg], PaintCanvas, PaintRect)); finally PaintCanvas.Free; { This better not be deleting the DC! } end; end; else Result := DialogHook(Wnd, Msg, wParam, lParam); end; end else Result := DialogHook(Wnd, Msg, wParam, lParam); end; end; constructor TPageSetupDialog.Create(AOwner: TComponent); begin inherited Create(AOwner); FOptions := [poDefaultMinMargins, poShowHelp]; FOnPrinter := NIL; FOnInitPaintPage := NIL; FOnPaintPage := NIL; FCustomData := 0; FPaperSize := Point(0,0); FMinimumMargins := Rect(0,0,0,0); FMargins := Rect(1000,1000,1000,1000); FMeasurements := pmInches; end; destructor TPageSetupDialog.Destroy; begin inherited Destroy; end; procedure GetPrinter(var DeviceMode, DeviceNames: THandle); var Device, Driver, Port: array[0..79] of char; DevNames: PDevNames; Offset: PChar; begin Printer.GetPrinter(Device, Driver, Port, DeviceMode); if DeviceMode <> 0 then begin DeviceNames := GlobalAlloc(GHND, SizeOf(TDevNames) + StrLen(Device) + StrLen(Driver) + StrLen(Port) + 3); DevNames := PDevNames(GlobalLock(DeviceNames)); try Offset := PChar(DevNames) + SizeOf(TDevnames); with DevNames^ do begin wDriverOffset := Longint(Offset) - Longint(DevNames); Offset := StrECopy(Offset, Driver) + 1; wDeviceOffset := Longint(Offset) - Longint(DevNames); Offset := StrECopy(Offset, Device) + 1; wOutputOffset := Longint(Offset) - Longint(DevNames);; StrCopy(Offset, Port); end; finally GlobalUnlock(DeviceNames); end; end; end; procedure SetPrinter(DeviceMode, DeviceNames: THandle); var DevNames: PDevNames; begin DevNames := PDevNames(GlobalLock(DeviceNames)); try with DevNames^ do Printer.SetPrinter(PChar(DevNames) + wDeviceOffset, PChar(DevNames) + wDriverOffset, PChar(DevNames) + wOutputOffset, DeviceMode); finally GlobalUnlock(DeviceNames); GlobalFree(DeviceNames); end; end; function CopyData(Handle: THandle): THandle; var Src, Dest: PChar; Size: Integer; begin if Handle <> 0 then begin Size := GlobalSize(Handle); Result := GlobalAlloc(GHND, Size); if Result <> 0 then try Src := GlobalLock(Handle); Dest := GlobalLock(Result); if (Src <> nil) and (Dest <> nil) then Move(Src^, Dest^, Size); finally GlobalUnlock(Handle); GlobalUnlock(Result); end end else Result := 0; end; function TPageSetupDialog.DoExecute(Func: pointer): boolean; const PageSetupOptions: array [TPageSetupOption] of DWORD = ( PSD_DEFAULTMINMARGINS, PSD_DISABLEMARGINS, PSD_DISABLEORIENTATION, PSD_DISABLEPAGEPAINTING, PSD_DISABLEPAPER, PSD_DISABLEPRINTER, PSD_NOWARNING, PSD_SHOWHELP ); PageSetupMeasurements: array [TPSMeasurements] of DWORD = ( PSD_INHUNDREDTHSOFMILLIMETERS, PSD_INTHOUSANDTHSOFINCHES ); var Option: TPageSetupOption; PageSetup: TPageSetupDlg; SavePageSetupDialog: TPageSetupDialog; DevHandle: THandle; begin FillChar(PageSetup, SizeOf(PageSetup), 0); with PageSetup do try lStructSize := SizeOf(TPageSetupDlg); hInstance := System.HInstance; Flags := PSD_MARGINS; if assigned(FOnPrinter) or assigned(FOnInitPaintPage) or assigned(FOnPaintPage) then begin Flags := Flags or PSD_ENABLEPAGESETUPHOOK; lpfnPageSetupHook := PageSetupDialogHook; end; for Option := Low(Option) to High(Option) do if Option in FOptions then Flags := Flags OR PageSetupOptions[Option]; Flags := Flags OR PageSetupMeasurements[FMeasurements]; { if not assigned(FOnPrinter) then Flags := Flags OR PSD_DISABLEPRINTER;} if assigned(FOnInitPaintPage) and assigned(FOnPaintPage) then begin Flags := Flags OR PSD_ENABLEPAGEPAINTHOOK; lpfnPagePaintHook := PageSetupDialogHook; end; hWndOwner := Application.Handle; GetPrinter(DevHandle, hDevNames); hDevMode := CopyData(DevHandle); HookCtl3D := Ctl3D; lCustData := FCustomData; ptPaperSize := FPaperSize; rtMinMargin := FMinimumMargins; rtMargin := FMargins; SavePageSetupDialog := PageSetupDialog; PageSetupDialog := Self; Result := TaskModalDialog(Func, PageSetup); PageSetupDialog := SavePageSetupDialog; if Result then begin FPaperSize := ptPaperSize; FMinimumMargins := rtMinMargin; FMargins := rtMargin; SetPrinter(hDevMode, hDevNames); end else begin if hDevMode <> 0 then GlobalFree(hDevMode); if hDevNames <> 0 then GlobalFree(hDevNames); end; finally { Nothing yet } end; end; function TPageSetupDialog.Execute: boolean; begin Result := DoExecute(@PageSetupDlg); end; function TPageSetupDialog.Printer(Wnd: HWND): boolean; begin Result := assigned(FOnPrinter); if Result then FOnPrinter(Self, Wnd); end; function TPageSetupDialog.DoPrinter(Wnd: HWND): boolean; begin try Result := Printer(Wnd); except Result := FALSE; Application.HandleException(Self); end; end; procedure Register; begin { You may prefer it on the Dialogs page, I like it on Win95 because it is } { only available on Win95. } RegisterComponents('Win95', [TPageSetupDialog]); end; { Initialization and cleanup } procedure InitGlobals; begin HelpMsg := RegisterWindowMessage(HelpMsgString); end; initialization InitGlobals; finalization { Nothing } end. { the following contains additional files that should be included with this file. To extract, you need XX3402 available with the SWAG distribution. 1. Cut the text below out, and save to a file .. filename.xx 2. Use XX3402 : xx3402 d filename.xx 3. The decoded file should be created in the same directory. 4. If the file is a archive file, use the proper archive program to extract the members. { ------------------ CUT ----------------------} *XX3402-000488-130396--72--85-52265-----PGSETUP.DCR--1-OF--1 +++++0++++1zzk++zzw+++++++++++++++++++++++06+E++E++++Dzz+U-I+3++EE-5+2I+ Ik-3+3E+JE-E+2E+GE--+2k+Hk-5++++++++++++2-+7-+++++++++++8++++-U++++M++++ +E+2+++++++U+E+++++++++++++++++++++++++++++++6+++6++++0+U+0+++++U+0++60+ ++1+kA++U60+++++zk++zk+++Dzz+Dw+++1z+Dw+zzw++Dzzzk+nAnAnAnAnAnAnAnAnAnAn AnAnAnAnAnAnA++++++++++++nAnADzzzzzzzzzz+nAnADzzzzzzzzzz+nAnADzzzzzzzzzz +nAnADzzzzzzzzzz+nAnADzzzzzk++zz+nAnADzzzzxivi1z+nAnADU+++1a++Xz+nAnAD-i PivUyDzz+nAnADU+++1a++Xz+nAnADzzzzVivi1z+nAnADzzzzy+++Xz+nAnADzzzzzzzzzz +nAnADzzzzzzzzzz+nAnADzzzzzzw++++nAnADzzzzzzwDTr+nAnADzzzzzzw5xkAnAnADzz zzzzwDQ1AnAnADzzzzzzw5+nAnAnA+++++++++AnAnAnAnAnAnAnAnAnAnAnAnAnAnAnAnAn AnA+ ***** END OF BLOCK 1 ***** *XX3402-002427-270896--72--85-39530--------DEMO.ZIP--1-OF--1 I2g1--E++++6+5lq4m28GpP-V++++9c++++6++++N4JhPmtYQ56f8AdD9ofAJIV7nQqrtiLW tGchHWratJ7EQAgjmWrK+P30wn791-ImwlHIkGmxUgFWRMJeY9lV9JV9hIeEUdNSY4hk9MWL Z7eSaETGtpVEY7CNb3WGaNybtkbIaNaMYpaJOcoitJmIaZWG0X7C6kFge+vMPYBB17J-dLZ+ gRGw31qEDE-EGkA23+++++U+UrMP6HdGJDQt+U++rkE+++Y+++-JPaZoAGtYNaq3YwyCon+E lhpY2uRBmpM06F+QQZdl+PIfEBexhJqeLR4GW2Gel+arxPMKWFotvZ7s4cuw1Gz+UGAGNwvU C5yOde0xK7fAn4wyTz5wOM3Uv9uRxY4jyyo6UA+PxwlUn5XIBxFtBA5LEjzJo+AKusyona+V m+oSAGcs0m2QPcFUh4wD4JxWvchD6MPKD9YU84EfC28l66mOxnmokXsKanV9C-QsMipFG1+J ZtWgpY8zqv0nS2OKMeqzOvH4QgOn2EgNVyp3C0BomHs4S0hgZQXOhBxB3Pp-2HMvIxzl2IoQ 5rBmbTIfFHOkD7OEJ+ew2nBzkH4a6nY9wst5hXVADAmju48hjKyZ2r7q-tX--AplO8cngo9f dYtcZsPGePooWy9mgfO5MgkRbrn4tq+TQJd-u1z-zlZhZuRSc1GcEttLROlnFb16u2s77R2a QeO6fkVBudkLJH3T0n3D1Y3K3H12Bl8UnhkEc6HYzT953M+nMl0G3MI40aK-sOyZ9P+xHsNA DdZcEWUi-HKJNOZX4H9SwpUj7NIBRgKTGgjCorzoh8ETyIqeIr65xSyUO5Ze1HO0dKcgOmPT xMmXi3ZWs04XRCxq0+mmXGYK7uDoZ77ifjppkLWsSpAbuEMtOcKg+ArRRBgo+3oeZqPl+PNn b6cCdaHDHjw-PVhXj1fN2f2Po8UDCAo5R6DOFVzLseN9DIvG1MDrOubwyv39fmUF5d7FKU2T pyfqgfPYZNIDugEWYxrnGrND0k1k3p-9+kEI++++0+-pRVgVfDRcut+3++1x2U++0E+++3Ji OLEl9b-VQxpMrKwPBklz1t1zURU554ySaqHPEqDocL5G9ZW04949h+Xu6BzlP0ouuG1dsbV3 zzSFiUyTnwuGTakMNVExWG6dwYS8Z77fuS2BzLQkqBrNrN5Ocop2V1n75PfR5M-feKCnQ1qs ECT214YoLfcrLWcO1NJkXYajfQXaAa8GoRsOLblZP2eT2maIaPYS8ljvSCUh9tvSyr7oUHeb nqUqFdxbB91-1VRAWclqbWJN4Qb+0yXosmHh17UskLhT2TqxvkEFjwkk97uwifWoYvQHKhsX eyvEycZVDQ56MgcOiV1YG66L1sUxMfTqkfH90k+XwXnMJrVn-7AKNJ1k5STS4rp+uwJcXLnM 7dy98Gda1cAawL+PwNRhl3xPl4Cw8rG4kO+mDoAvZbxWWzbGGhFSS4ZoOyJ0uUhVNp8vxg7K OaNBV53igL7pe4FoinR45OAZrgjd5lXtvUDQ-rz9bSEuMUjPEHWXl-o7GVOahsJ9qHLLluZE WjU5-L30WQ8-5BSnRO3pQ2eq-b3EdSd8oKdSewc8WsILFn+OXIzIXATR6nUqFe5EXnXt3+S7 srciT4ZYCFj+ICUvkM2e-UCs6X4OwaRXzpJ6qUMIDapg1xQuDc6nKdiV9I8JKLYbD-M8Dn+u D6IMuHnN+7a1Xs2lbp9+SIF8ky4v2vMutNmvsJjId1FHa3OEAyL1RpTkEtwCxwSeHA3sfgUe 8YlnJCfZu0l6viugT0cIxVz9nGZGOfAREqIQVv+mvk3B1yRhfIYaPI1vdzQMtMG9buC4af4F eTqVm26i59o6W+WzpvaKgNxHOTfydwDyMT6BgTy4QXPr8p8bJqI2zqvOiuuojsJbQ90zjxzP g4n3wuvYSRwhOmD+Ed6-PEYe2n9Bov6cE4ke4pPpMtgrttXsdXBL9JSyDTXtluMr1zsu2tAp 3FoPWYju20UDz4vqUXq3lxoSv-Lap5DScs8grC07u4n0wYxXwXI+iKb+oMAa42z1shYnOjFt YZ040kyFGSa67dMs8SAVmeqZswn3Uih86Q4bd7Xr4kKKfAvAm3Vj-RpHy9VIhXSMaZ-q8iNC kMX8sKAWto959e92vuneILLguu7QbjdDPY0Tr5myIiBtEhCd0kx3uuJGY347Hd2jLVElqYVe W2a4efS9f7l8DEjVmxWKTWZrFPhM1RvaJAoAS8eyUGYCw-HVLm+g-AIvBffXWm4llUO2LY7g lM6oxo1qgJ980WtpXGjEBMNY3d7oOyCdM272G47A0a7MaflMAZchMMMS-2mJo9RP1Io27EFj HkfAMaoL6esoClAIFo650o5ucCU8LOtwC9AjnwSbHoyIlt9YGlhs5QhB0s4wQ9XO+olG5x67 6IrMGhgA8mLDsZKi37hvJ-qSQcBJuGUguVzPrArvEuCAtIoXxEsNqQ48ARF3BfVF--g8S2Lc aQ7EUYBt8GhCJJuuhP68vBdugXjVd0KTJfZNyP1SaReShAkMcKtuwRcWug3zn3i2BDU0hh7G izctDZtVjCYVwsnxIW5nNCv2y0SUQ1qL5jwp24fjMH35mU+by6N6hMTSUR83wuffFCN+rj6P vzyDnRUH2+2RG4Vrd+SiAVau4chHTFRsDUq8MtLXZq-FQorRq0Wt-RQBnBPFzye6hNjwlhry Qlx+BNvZLoecuytp7bB8mXap8cKqO1gix-PeByMCfNIl7n9JtPb6AhGCfrbEjiRp3jlIs-75 nlp9JmTYjvc2EaYRHAC1d+xkZf1yvKecur693H2pnxccnVN7O92qhrESou8XSb49qxLk0fIJ 4kcjWwPGNIcgenh0NJA+QPi8+ZcGReUGgXf+FDw036mDFE7fKRkLbXzzTfiKgitvaK8zosDI byYYr8Od3TTU7dpSzjuy-zjRFfHdqmxSVrw-I2g-+VE93+++++U+T5MP6Ed9Jg42++++iU++ ++U++++++++++E+U+9O-+++++4FZPKwiN5-mI2g-+VE93+++++U+UrMP6HdGJDQt+U++rkE+ ++Y++++++++++E+U+9O-eU+++3JiOLEl9aFaPJ-9+E6I0lE++++6+5Jq4m4gxqXfY+I++DoG +++7++++++++++2+6+0qUEc1++-JPaZoAGtkMLBEGkI4++++++A++k0Y++++kEU+++++ ***** END OF BLOCK 1 *****