Page 1 of 1

[RichViewActions] How to access page setup properties

Posted: Sun Aug 28, 2005 11:26 am
by Sergey Tkachenko
1) Margins are stored in RVPrint, assigned to RVAControlPanel.RVPrint
2) Properties of header and footer are stored in global objects
RVAControlPanel.Header and RVAControlPanel.Footer (Text, Alignment, PrintOnFirstPage
properties)
3) Page size, orientation and source are stored in the global for the
application printer settings. They are accessible via global Printer object
(units Printers). Only orientation can be changed easily -
Printer.Orientation.
Other properties can be changed using WinAPI functions:

3.a) Changing paper source

Code: Select all

// make sure that WinSpool is defined after Windows in uses
uses Printers, WinSpool;

type
  TBinName = array [0..23] of Char;
  TBinNames = array [0..1000] of TBinName;
  PBinNames = ^TBinNames;
  TWordArray = array [0..1000] of Word;
  PWordArray = ^TWordArray;


 procedure GetAvailablePaperSources;
  var ADevice, ADriver, APort: array[0..79] of Char;
      ADeviceMode: THandle;
      DevMode: PDeviceMode;
      BinCount: Integer;
      BinNames: PBinNames;
      BinCodes: PWordArray;
  begin
    Printer.GetPrinter(ADevice,ADriver,APort,ADeviceMode);
    if ADeviceMode<>0 then begin
      DevMode := PDeviceMode(GlobalLock(ADeviceMode))
      end
    else
      raise Exception.Create('Error initializing printer');
    BinCount := DeviceCapabilities(ADevice, APort, DC_BINNAMES, nil, DevMode);
    GetMem(BinNames, sizeof(TBinName)*BinCount);
    GetMem(BinCodes, sizeof(Integer)*BinCount);
    try
       DeviceCapabilities(ADevice, APort, DC_BINNAMES, Pointer(BinNames), DevMode);
       DeviceCapabilities(ADevice, APort, DC_BINS, Pointer(BinCodes), DevMode);
       {
          At this point, BinNames[0..BinCount-1] contain names of paper sources,
          BinCodes[0..BinCount-1] contain their codes that can be used in SetPaperSource.
          Store them somewhere.
       }
    finally
      FreeMem(BinNames);
      FreeMem(BinCodes);
    end;
    GlobalUnlock(ADeviceMode);
 end;


 procedure SetPaperSource(PaperSource: Integer);
  var ADevice, ADriver, APort: array[0..79] of Char;
      ADeviceMode: THandle;
      DevMode: PDeviceMode;
  begin
    Printer.GetPrinter(ADevice,ADriver,APort,ADeviceMode);
    if ADeviceMode<>0 then begin
      DevMode := PDeviceMode(GlobalLock(ADeviceMode))
      end
    else
      raise Exception.Create('Error initializing printer');
    DevMode.dmFields := DevMode.dmFields or DM_DEFAULTSOURCE;
    DevMode.dmDefaultSource := PaperSource;
    GlobalUnlock(ADeviceMode);
    Printer.SetPrinter(ADevice,ADriver,APort,ADeviceMode);
  end;
3.b) Paper size

Code: Select all

uses Printers;

  procedure SetPaperSize(PaperSize: Integer);
  var ADevice, ADriver, APort: array[0..79] of Char;
      ADeviceMode: THandle;
      DevMode: PDeviceMode;
  begin
    Printer.GetPrinter(ADevice,ADriver,APort,ADeviceMode);
    if ADeviceMode<>0 then begin
      DevMode := PDeviceMode(GlobalLock(ADeviceMode))
      end
    else
      raise Exception.Create('Error initializing printer');
    DevMode.dmFields := DevMode.dmFields or DM_PAPERSIZE;
    DevMode.dmPaperSize := PaperSize;
    GlobalUnlock(ADeviceMode);
    Printer.SetPrinter(ADevice,ADriver,APort,ADeviceMode);
  end;
You can find a list of available paper sizes in Windows API Help (Delphi
menu: Help | Windows SDK).
Search DEVMODE in the help index, then search for DMPAPER_*** constants.

For example, SetPaperSize(DMPAPER_A4)

Do not forget to call RVPrint.FormatPages after any change in paper sizes.

You can get the current printer's paper size:

Code: Select all

function GetPaperSize: Integer;
var ADevice, ADriver, APort: array[0..79] of Char;
    ADeviceMode: THandle;
    DevMode: PDeviceMode;
begin
  Printer.GetPrinter(ADevice,ADriver,APort,ADeviceMode);
  if ADeviceMode<>0 then begin
    DevMode := PDeviceMode(GlobalLock(ADeviceMode))
    end
  else
    raise Exception.Create('Error initializing printer');
  Result := DevMode.dmPaperSize;
end;
You can see how to get a list of available paper sizes and their names in
the RichViewActions source code (in page setup form)

Note: in new version of Delphi, use String instead of array[0..79] of Char.

Posted: Sun Aug 13, 2006 12:53 pm
by marcpleysier
Perhaps someting simple and stupid, but...
When runing my editor made from RichViewAction demo, the Page setup menu is not enabled.
So I can't modify printer margins at runtime.
Who to enabled it?

Posted: Sun Aug 13, 2006 8:50 pm
by Sergey Tkachenko
Place TRVAControlPanel component to the form (if you do not have it already). Place TRVPrint component there. Assign RVAControlPanel1.RVPrint = RVPrint.

(as you can see from the explanations above, some of page setup properties are stored in TRVPrint component; what's why this action is not enabled if RVPrint is not specified)

Re: How to access page setup properties

Posted: Mon Dec 11, 2006 9:40 pm
by Byron Short
Hi Sergey,

I'm trying to use the example code you gave for getting the list of available bins from the Windows API. So far, I'm just trying to actually load the list of bins, using your "procedure GetAvailablePaperSources", as listed in your post from 27 Aug, 2005.

There were a few typos in the source code you gave which I think I correctly resolved as follows:

1. BinNames and BinCodes were never declared as vars; I declared them as:
BinNames:PBinNames;
BinCodes:PWordArray;

2. Your calls to DeviceCapabilities seem to be short one parameter--I inserted a parameter for ADriver as per the following example:
DeviceCapabilities(ADriver,ADevice,APort,DC_BINNAMES,nil,DevMode);

3. After using GetMem on BinNames and BinCodes, you use FreeMem on "PaperNames" and "PaperCodes", so I changed the FreeMem calls to refer back to BinNames and BinCodes again.

So with those three exceptions, I'm using your code as presented. It all compiles fine. But at start-up, I get an error before the program starts, that I think must be coming from the Windows API.

It comes up in a dialog titled "AFS.exe - Entry Point Not Found" (where AFS.exe is my executable name). The text of the message in the dialog is "The procedure entry point DeviceCapabilitiesA could not be located in the dynamic link library gdi32.dll."

What am I doing wrong? How could it not find a standard dll? Sorry, I must seem brain dead, but I thought I was following your code okay...

THANKS in advance!

--Byron

Posted: Tue Dec 12, 2006 12:57 am
by Byron Short
Sergey,

I think I found it...

The clue was that part where DeviceCapabilities asked for one more parameter...I was using the wrong "DeviceCapabilities". Found some documentation searching around the web. It appears that because I called only "DeviceCapabilities", and I had "Windows" in my Uses statement, I was calling "Windows.DeviceCapabilities" which sometime in Windows XP, no longer support DeviceCapabilities. What I needed to do was to put "WinSpool" in my Uses statement, so that I am actualling calling "WinSpool.DeviceCapabilities". To be sure, I explicitly called "WinSpool.DeviceCapabilities" in my code. And now everything works as it should.

I hope this is consistent for all XP? I'm on Professional, and documentation seems to suggest it will work for both, but I guess I'll find out. Any comments?

--Byron

Posted: Mon Dec 18, 2006 8:43 pm
by Sergey Tkachenko
I corrected errors in the function.
Yes, this function is from WinSpool.
Similar code is used in Delphi VCL itself. And no problems were reported.