I have figured out how to modify the printer settings ...
Procedure TfrmMain.btnPrint2Click
( Sender: TObject );
Var
Device,
Driver,
Port : Array[0..255] Of char;
DeviceMode : THandle;
DevMode : PDeviceMode;
Begin
{ Set the printer index to the one we choose }
Printer.PrinterIndex := lbxPrinters.ItemIndex;
With Printer Do Begin
GetPrinter (Device, Driver, Port, DeviceMode);
{ LOCK }
DevMode := GlobalLock (Devicemode);
With DevMode^ Do Begin
dmFields := dmFields Or DM_ORIENTATION;
dmOrientation := DMORIENT_LANDSCAPE;
dmPaperSize := DMPAPER_11X17;
End;
BeginDoc;
Try
Canvas.Font.Size := 20;
Canvas.Font.Name := 'Arial';
Canvas.TextOut (50, 50, 'This is landscape');
{ UNLOCK }
GlobalUnlock (DeviceMode);
Finally
EndDoc;
End; { Try..finally }
End; { With Printer Do Begin }
End; { btnPrint2Click Procedure }
The problem is, that I am uncertain how to actually print a PDF, other
than calling a shellexecute. We have Rave Reports Borland Edition
eXteneded 7.0.3. I was wondering if it was possible to load the PDF
file into RAVE, and send it to the printer from there? Maybe it can
be done within Delphi itself...i'm open to ideas.
Thank you for any help you are able to provide,
JJ
I created a solution for this task...it involves using the DDE.
Unit PDFDDEJJT;
Interface
Uses Windows,
ShellAPI,
SysUtils,
Messages,
DDeman,
Winspool,
Dialogs,
Printers;
Type TAdobePDF = Class (TObject)
Public
Procedure Start ( PrinterName :
String;
Orientation,
Duplex,
Copies,
Size :
Integer );
Procedure PrintPDF ( FileName :
String );
Procedure Stop ( ShutdownAdobe :
Boolean );
Private
OriginalSettings : PDeviceMode;
OriginalPrinter,
Driver,
Port : String;
Function SetPrinterProperties ( pPrinterName :
PChar;
pDevModeNew :
PDevMode ) : Boolean;
Function GetPrinterDevMode ( pDevice :
PChar ) : PDevMode;
Function GetExeName ( FileName,
FilePath,
PdfExeName,
Msg :
String;
RetCode :
Integer ) : Boolean;
Procedure HideAdobe;
Function
IsAdobeRunning :
Boolean;
End;
Implementation
Var
hWndAdobe : HWND;
{ ---------------------------------------------------------------------------- }
Function TAdobePDF.SetPrinterProperties
( pPrinterName : PChar;
pDevModeNew : PDevMode ) : Boolean;
Var
hPrinter : THandle;
dwNeeded : DWORD;
pi2 : PPrinterInfo2;
pDevModeVar,
pDevModeVar2 : PDevMode;
pd : PRINTER_DEFAULTS;
bFlag : Boolean;
lFlag : Integer;
Begin
{ Open printer handle }
ZeroMemory (@pd,SizeOf (pd));
pd.DesiredAccess := PRINTER_ACCESS_USE;
bFlag := OpenPrinter (pPrinterName, hPrinter, @pd);
If (bFlag = False) Or
(hPrinter = 0) Then Begin
Result := False;
Exit;
End;
{ The first GetPrinter tells you how big the buffer should be in
order to hold all of PRINTER_INFO_2. Note that this should fail
with
ERROR_INSUFFICIENT_BUFFER. If GetPrinter fails for any other
reason
or dwNeeded isn't set for some reason, then there is a
problem... }
SetLastError(0);
bFlag := GetPrinter(hPrinter, 2, Nil, 0, @dwNeeded);
If ( (bFlag) Or
(GetLastError () <> ERROR_INSUFFICIENT_BUFFER) Or
(dwNeeded = 0) ) Then Begin
ClosePrinter (hPrinter);
Result := False;
Exit;
End;
{ Allocate enough space for PRINTER_INFO_2 }
GetMem (pi2, dwNeeded);
If (pi2 = Nil) Then Begin
ClosePrinter (hPrinter);
Result := False;
Exit;
End;
{ The second GetPrinter fills in all the current settings, so all
you need to do is modify what you're interested in }
bFlag := GetPrinter(hPrinter, 2, pi2, dwNeeded, @dwNeeded);
If (bFlag = False) Then Begin
FreeMem (pi2);
ClosePrinter (hPrinter);
Result := False;
Exit;
End;
{ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- - - - }
{ If GetPrinter didn't fill in the DEVMODE, try to get it by calling
DocumentProperties }
If (pi2.pDevMode = Nil) Then Begin
dwNeeded := DocumentProperties (0,
hPrinter, { Handle to our
printer }
pPrinterName, { Name of the
printer }
pDevModevar^, { Asking for size,
so there are not used }
pDevModeVar2^,
0); { Zero returns
buffer size }
If (dwNeeded <= 0) Then Begin
FreeMem (pi2);
ClosePrinter (hPrinter);
Result := False;
End;
GetMem (pDevModeVar,dwneeded);
lFlag := DocumentProperties (0,
hPrinter,
pPrinterName,
pDevModeVar^,
pDevModeVar2^,
DM_OUT_BUFFER);
If (lFlag <> IDOK) Or
(pDevModeVar = Nil) Then Begin
FreeMem (pDevModeVar);
FreeMem (pi2);
ClosePrinter (hPrinter);
Result := False;
End;
pi2.pDevMode := pDevModeVar;
End; { If GetPrinter didn't fill in the DEVMODE }
{ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- - - - }
{ COPIES }
If ((pDevModeNew.dmFields And DM_COPIES) <> 0) And
(pi2.pDevMode.dmCopies <> pDevModeNew.dmCopies) Then Begin
pi2.pDevMode.dmFields := pi2.pDevMode.dmFields Or DM_COPIES;
pi2.pDevMode.dmCopies := pDevModeNew.dmCopies;
End;
{ ORIENTATION }
If ((pDevModeNew.dmFields And DM_ORIENTATION) <> 0) And
(pi2.pDevMode.dmOrientation <> pDevModeNew.dmOrientation) Then
Begin
pi2.pDevMode.dmFields := pi2.pDevMode.dmFields or
DM_ORIENTATION;
pi2.pDevMode.dmOrientation := pDevModeNew.dmOrientation;
End;
{ DUPLEX }
If ((pDevModeNew.dmFields And DM_DUPLEX) <> 0) And
(pi2.pDevMode.dmDuplex <> pDevModeNew.dmDuplex) Then Begin
pi2.pDevMode.dmFields := pi2.pDevMode.dmFields or DM_DUPLEX;
pi2.pDevMode.dmDuplex := pDevModeNew.dmDuplex;
End;
{ PAPER SIZE }
If ((pDevModeNew.dmFields And DM_PAPERSIZE) <> 0) And
(pi2.pDevMode.dmPaperSize <> pDevModeNew.dmPaperSize) Then Begin
pi2.pDevMode.dmFields := pi2.pDevMode.dmFields or
DM_PAPERSIZE;
pi2.pDevMode.dmPaperSize := pDevModeNew.dmPaperSize;
End;
{ SCALING }
If ((pDevModeNew.dmFields And DM_SCALE) <> 0) And
(pi2.pDevMode.dmScale <> pDevModeNew.dmScale) Then Begin
pi2.pDevMode.dmFields := pi2.pDevMode.dmFields or DM_SCALE;
pi2.pDevMode.dmDisplayFlags := 1;
pi2.pDevMode.dmScale := pDevModeNew.dmScale;
End;
{ Do not attempt to set security descriptor }
pi2.pSecurityDescriptor := Nil;
{ Make sure the driver-dependent part of devmode is updated }
lFlag := DocumentProperties (0,
hPrinter,
pPrinterName,
pi2.pDevMode^,
pi2.pDevMode^,
(DM_IN_BUFFER Or DM_OUT_BUFFER));
If (lFlag <> IDOK) Then Begin
FreeMem (pi2);
ClosePrinter (hPrinter);
Result := False;
Exit;
End;
{ Update printer information }
bFlag := WinSpool.SetPrinter (hPrinter, 2, pi2, 0);
{ Tell other apps that there was a change }
SendMessageTimeout (HWND_BROADCAST,
WM_DEVMODECHANGE,
0,
LPARAM (PChar (pPrinterName)),
SMTO_NORMAL,
1000,
PDWORD (nil)^);
{ Clean up }
If (pi2 <> Nil)
Then FreeMem (pi2);
If (hPrinter <> 0)
Then ClosePrinter (hPrinter);
Result := True;
End; { SetPrinterProperties Function }
{ ---------------------------------------------------------------------------- }
Function TAdobePDF.GetPrinterDevMode
( pDevice : PChar ) : PDevMode;
Var
hPrinter : THandle;
pDevModeVar,
pDevModeVar2 : PDEVMODE;
dwNeeded,
dwRet : DWORD;
Begin
{ Start by opening the printer }
If Not OpenPrinter (pDevice, hPrinter, Nil)
Then Result := Nil;
{ Step 1: Allocate a buffer of the correct size }
dwNeeded := DocumentProperties (0,
hPrinter, { Handle to our
printer }
pDevice, { Name of the
printer }
pDevModevar^, { Asking for size,
so these are not used }
pDevModeVar^,
0); { Zero returns
buffer size }
GetMem (pDevModeVar, dwNeeded);
{ Step 2: Get the default DevMode for the printer }
dwRet := DocumentProperties (0,
hPrinter,
pDevice,
pDevModeVar^, { The address of the
buffer to fill }
pDevModeVar2^, { Not using the
input buffer }
DM_OUT_BUFFER); { Have the output
buffer filled }
{ If failure, cleanup and return failure }
If (dwRet <> IDOK) Then Begin
FreeMem (pDevModeVar);
ClosePrinter (hPrinter);
Result := Nil;
End;
{ Finished with the printer }
ClosePrinter (hPrinter);
{ Return the DevMode structure }
Result := pDevModeVar;
End; { GetPrinterDevMode Function }
{ ---------------------------------------------------------------------------- }
Function TAdobePDF.GetExeName
( FileName,
FilePath,
PdfExeName,
Msg : String;
RetCode : Integer ) : Boolean;
Var
ResultArray : Array [0..MAX_PATH -1] Of Char;
Begin
RetCode := FindExecutable (PChar (FileName),PChar (FilePath),
ResultArray);
PdfExeName := ResultArray;
Result := False;
Case RetCode Of
SE_ERR_NOASSOC : Msg := 'File Association Not Found';
SE_ERR_FNF : Msg := 'File Not Found';
SE_ERR_PNF : Msg := 'Path not found ';
SE_ERR_ACCESSDENIED : Msg := 'Access denied';
SE_ERR_OOM : Msg := 'Out of memory ';
SE_ERR_DLLNOTFOUND : Msg := 'Dll not found';
SE_ERR_SHARE : Msg := 'Sharing error';
SE_ERR_ASSOCINCOMPLETE : Msg := 'Association incomplete';
SE_ERR_DDETIMEOUT : Msg := 'DDE Timeout';
SE_ERR_DDEFAIL : Msg := 'DDE Failure';
SE_ERR_DDEBUSY : Msg := 'DDE Busy';
Else Begin
{ I guess it worked }
Result := True;
Msg := 'Retcode ' + IntToStr (RetCode);
End; { Else }
End; {Case }
End; { HideAdobe Procedure }
{ ---------------------------------------------------------------------------- }
Procedure TAdobePDF.HideAdobe;
Begin
ShowWindow (hWndAdobe, SW_RESTORE);
MoveWindow (hWndAdobe, -100, -100, 0, 0, True);
ShowWindow (hWndAdobe, SW_RESTORE);
ShowWindow (hWndAdobe, SW_HIDE);
End; { HideAdobe Procedure }
{ ---------------------------------------------------------------------------- }
Function TAdobePDF.IsAdobeRunning : Boolean;
Begin
hWndAdobe := FindWindow('AdobeAcrobat', Nil);
Result := (hWndAdobe > 0);
If Not Result Then Begin
hWndAdobe := FindWindow ('AcrobatSDIWindow', Nil);
Result := (hWndAdobe > 0);
End; { Else Begin }
End; { IsAdobeRunning Function }
{ ---------------------------------------------------------------------------- }
Procedure TAdobePDF.Start
( PrinterName : String;
Orientation,
Duplex,
Copies,
Size : Integer );
Var
PrinterHandle : THandle;
dwNeeded : DWORD;
ppi2 : PPrinterInfo2;
RetCode : Integer;
ModifiedSettings : PDeviceMode;
Begin
{ Always set the original settings to nil }
If OriginalSettings <> Nil
Then OriginalSettings := Nil;
{ Copy the printer name }
OriginalPrinter := PrinterName;
{ If we can't open printer, then get the information and try again }
If Not OpenPrinter (PChar (PrinterName), PrinterHandle, Nil) Then
Begin
{ If not valid, log the problem & get default printer }
Printer.GetPrinter (PChar (PrinterName),
PChar (Driver),
PChar (Port),
PrinterHandle);
//DeviceMode);
{ If Printer won't open again, quit }
If Not OpenPrinter (PChar (PrinterName), PrinterHandle, Nil)
Then Exit;
End;
{ Find out how much space is needed for printer info }
GetPrinter (PrinterHandle,
2,
Nil,
0,
@dwNeeded);
{ We returned 0 bytes of space, so something isn't right; exit }
If (dwNeeded = 0) Then Begin
ClosePrinter (PrinterHandle);
Exit; { Bail out - result = false }
End;
{ Allocate enough space for PRINTER_INFO_2 }
GetMem (ppi2, dwNeeded);
{ The second GetPrinter() will fill in all the current information }
Try
If GetPrinter (PrinterHandle, 2, ppi2, dwNeeded, @dwNeeded) Then
Begin
Port := ppi2.pPortName;
Driver := ppi2.pDriverName;
End;
Finally
FreeMem (ppi2);
ClosePrinter (PrinterHandle);
End;
{ Get default printer settings }
OriginalSettings := GetPrinterDevMode (PChar
(PrinterName));
ModifiedSettings := GetPrinterDevMode (PChar
(PrinterName));
{ 2 Sided Printing (Duplex) }
ModifiedSettings.dmDuplex := Duplex;
ModifiedSettings.dmFields := ModifiedSettings.dmFields or
DM_DUPLEX;
OriginalSettings.dmFields := OriginalSettings.dmFields or
DM_DUPLEX;
{ Paper Size }
ModifiedSettings.dmPaperSize := Size;
ModifiedSettings.dmFields := ModifiedSettings.dmFields Or
DM_PAPERSIZE;
OriginalSettings.dmFields := OriginalSettings.dmFields Or
DM_PAPERSIZE;
{ Page Orientation }
ModifiedSettings.dmOrientation := Orientation;
ModifiedSettings.dmFields := ModifiedSettings.dmFields Or
DM_ORIENTATION;
OriginalSettings.dmFields := OriginalSettings.dmFields Or
DM_ORIENTATION;
{ Copies }
ModifiedSettings.dmCopies := Copies;
ModifiedSettings.dmFields := ModifiedSettings.dmFields Or
DM_COPIES;
OriginalSettings.dmFields := OriginalSettings.dmFields Or
DM_COPIES;
{ Change the printer settings to the ones defined above }
SetPrinterProperties (PChar (PrinterName), ModifiedSettings);
End; { PrintPdf Function }
{ ---------------------------------------------------------------------------- }
Procedure TAdobePDF.PrintPDF
( FileName : String );
Var
CommandStr,
Msg,
FileNameStr,
FilePathStr : String;
WasRunning : Boolean;
DdeConv : TDdeClientConv;
RetCode : Integer;
Begin
FileNameStr := ExtractFileName (FileName);
FilePathStr := ExtractFilePath (FileName);
{ Log errors here }
If Not GetExeName (Filename,
FilePathStr,
FileNameStr,
Msg,
RetCode)
Then Exit;
WasRunning := True;
{ Adobe isn't running, so start it up }
If Not IsAdobeRunning Then Begin
WasRunning := False;
{ Open Adobe }
ShellExecute (SizeOf (TShellExecuteInfo), 'open', 'acrobat', Nil,
Nil, SW_HIDE);
{ Give adobe time to open }
Sleep (3000);
{ If still not open, try to open reader and wait }
If Not IsAdobeRunning Then Begin
ShellExecute (SizeOf (TShellExecuteInfo), 'open', 'AcroRd32',
Nil, Nil, SW_HIDE);
Sleep (3000);
End;
{ Hide adobe }
HideAdobe();
End; { Not IsAdobeRunning }
DdeConv := TDdeClientConv.Create (Nil);
Try
DdeConv.SetLink ('acroview','control');
DdeConv.OpenLink;
CommandStr := '[FilePrintTo( "' + FileName +
'","' + OriginalPrinter +
'","' + Driver +
'","' + Port + '")]';
DdeConv.ExecuteMacro (PChar (CommandStr), False);
{ Log error here }
DdeConv.CloseLink;
Sleep (1000);
Finally
DdeConv.Free;
DdeConv := Nil;
End; { Try }
End; { PrintPDF Procedure }
{ ---------------------------------------------------------------------------- }
Procedure TAdobePDF.Stop
( ShutdownAdobe : Boolean );
Begin
Try
{ Set the printer settings to it's original state }
SetPrinterProperties (PChar (OriginalPrinter), OriginalSettings);
If IsAdobeRunning Then Begin
Sleep (1000);
{ Ask Acrobat Reader to close }
PostMessage (hWndAdobe, WM_CLOSE, 0, 0);
End; { If adobe is running }
Except
ShowMessage ('Could not set printer settings back for ' +
OriginalPrinter + '.');
End; { Try }
End; { Procedure Stop }
{ ---------------------------------------------------------------------------- }
End.