How to Retrieve Printer Information in Delphi: Using DeviceCapabilities, LOGPIXELSX, and Related Techniques
When controlling printers in Delphi, you often need to retrieve detailed information such as paper size, resolution, and printable area. To do this, you use Windows API functions like DeviceCapabilities and GetDeviceCaps.
This page explains how to obtain values such as LOGPIXELSX, LOGPIXELSY, PHYSICALWIDTH, and PHYSICALOFFSETX, with practical code examples.
It also covers useful techniques for improving printing accuracy, including pixel conversion for A3 paper size and how to specify DMPAPER constants.
For information on printing with TPrinter in Delphi, see: Printing in Delphi.
To work with printers, add the following units to uses:
uses Vcl.Printers, WinApi.WinSpool;
Retrieving Printer Lists and Selecting a Printer
Use the following properties and methods to retrieve the list of printers and select the printer to use.
| Value to Retrieve | How to Retrieve |
|---|---|
| Number of installed printers | Printer.Printers.Count |
| List of printer names |
Printer.Printers[ index ] Index ranges from 0 to Printer.Printers.Count - 1 |
| Selecting the active printer |
Printer.PrinterIndex := index; Index ranges from 0 to Printer.Printers.Count - 1 |
Paper Size List and Paper Size Settings
Use the following methods to retrieve the list of available paper sizes for the current printer and to set the desired paper size.
| Value to Retrieve | How to Retrieve |
|---|---|
| Paper Size List |
With the following source code: The dynamic array PaperNo[0 ~ PaperCount‑1] will contain the paper size numbers, and the dynamic array PaperName[0 ~ PaperCount‑1] will contain the paper size names (such as A4, A3). The displayed names may differ depending on the currently selected printer—some drivers return English names, others Japanese. This behavior likely depends on each printer driver. type TPaperName = array[0..63] of Char; // Static array (stack memory) var Device, Driver, Port: array[0..255] of Char; // Static arrays (stack memory) DeviceModeHandle: THandle; PMode: PDevMode; PaperCount, i: Integer; PaperNo: Array of WORD; // Dynamic array (heap memory) PaperName: Array of TPaperName; // Dynamic array (heap memory) begin // Get the DeviceMode handle of the current printer Printer.GetPrinter(Device, Driver, Port, DeviceModeHandle); if DeviceModeHandle = 0 then Exit; // Get a pointer to the DevMode structure from the DeviceMode handle PMode := GlobalLock(DeviceModeHandle); try // When the 4th argument is nil, the number of paper sizes is returned PaperCount := DeviceCapabilities(Device, Port, DC_PAPERS, nil, PMode); if PaperCount > 0 then begin SetLength(PaperNo, PaperCount); SetLength(PaperName, PaperCount); // Retrieve paper size numbers DeviceCapabilities(Device, Port, DC_PAPERS, PChar(@PaperNo[0]), PMode); // Retrieve paper size names DeviceCapabilities(Device, Port, DC_PAPERNAMES, PChar(@PaperName[0]), PMode); end; finally GlobalUnlock(DeviceModeHandle); end; end; |
| Retrieving the Paper Size Number |
var Device, Driver, Port: array[0..255] of Char; DeviceModeHandle: THandle; PMode: PDevMode; begin // Get the DeviceMode handle of the current printer Printer.GetPrinter(Device, Driver, Port, DeviceModeHandle); if DeviceModeHandle = 0 then Exit; // Get a pointer to the DevMode structure from the DeviceMode handle PMode := GlobalLock(DeviceModeHandle); try ShowMessage('Paper size number: ' + IntToStr(PMode.dmPaperSize)); finally GlobalUnlock(DeviceModeHandle); end; end; |
| Setting the Paper Size |
With the following source code: you can set the paper size by assigning, for example: pMode.dmPaperSize := DMPAPER_B4;Paper size numbers are defined as constants. For example, DMPAPER_B4 = 13 (paper size number 13), DMPAPER_A4 = 9 (paper size number 9).
var Device, Driver, Port: array[0..255] of Char; // Static arrays (stack memory) DeviceModeHandle: THandle; PMode: PDevMode; begin // Get the DeviceMode handle of the current printer Printer.GetPrinter(Device, Driver, Port, DeviceModeHandle); if DeviceModeHandle = 0 then Exit; // Get a pointer to the DevMode structure from the DeviceMode handle PMode := GlobalLock(DeviceModeHandle); try // Enable the paper size change flag PMode.dmFields := PMode.dmFields or DM_PAPERSIZE; // Change the paper size PMode.dmPaperSize := DMPAPER_A3; finally GlobalUnlock(DeviceModeHandle); end; // Apply the paper size setting to the printer Printer.SetPrinter(Device, Driver, Port, DeviceModeHandle); end; |
Retrieving Current Paper Information from the Active Printer
You can obtain the current paper settings of the active printer using the following values.
| Value to Retrieve | How to Retrieve |
|---|---|
| Physical paper width (px) | GetDeviceCaps(Printer.Handle, PHYSICALWIDTH) |
| Physical paper height (px) | GetDeviceCaps(Printer.Handle, PHYSICALHEIGHT) |
| Non-printable left margin X (px) | GetDeviceCaps(Printer.Handle, PHYSICALOFFSETX) |
| Non-printable top margin Y (px) | GetDeviceCaps(Printer.Handle, PHYSICALOFFSETY) |
| Resolution X (dpi) | GetDeviceCaps(Printer.Handle, LOGPIXELSX) |
| Resolution Y (dpi) | GetDeviceCaps(Printer.Handle, LOGPIXELSY) |
| Printable width (px) |
GetDeviceCaps(Printer.Handle, HORZRES) or Printer.PageWidth |
| Printable height (px) |
GetDeviceCaps(Printer.Handle, VERTRES) or Printer.PageHeight |
| Paper orientation |
Printer.Orientation One of the following values:
Printer.Orientation := TPrinterOrientation.poLandscape; |
The relationship between the values above and the actual paper layout is illustrated below.
Physical Paper Width (px)
Printable Height (px)
All units are in pixels (px).
For example, when converting the following values to millimeters (mm):
- Physical paper width = 4960 px
- Physical paper height = 7014 px
- Non‑printable upper‑left X = 120 px
- Non‑printable upper‑left Y = 120 px
- Printable width = 4720 px
- Printable height = 6774 px
- Non‑printable lower‑right X = 4960 − 120 − 4720 = 120 px
- Non‑printable lower‑right Y = 7014 − 120 − 6774 = 120 px
- Resolution X = 600 dpi
- Resolution Y = 600 dpi
Since 1 inch = 25.4 mm and dpi means “dots (pixels) per inch,”
you can convert pixels to millimeters using:
pixels ÷ resolution × 25.4
- Physical paper width = 4960 px ÷ 600 dpi × 25.4 = 209.97 mm
- Physical paper height = 7014 px ÷ 600 dpi × 25.4 = 296.93 mm
- Non‑printable upper‑left X = 120 px ÷ 600 dpi × 25.4 = 5.08 mm
- Non‑printable upper‑left Y = 120 px ÷ 600 dpi × 25.4 = 5.08 mm
- Printable width = 4720 px ÷ 600 dpi × 25.4 = 199.81 mm
- Printable height = 6774 px ÷ 600 dpi × 25.4 = 286.77 mm
- Non‑printable lower‑right X = 120 px ÷ 600 dpi × 25.4 = 5.08 mm
- Non‑printable lower‑right Y = 120 px ÷ 600 dpi × 25.4 = 5.08 mm
To convert a position measured from the upper‑left corner of the paper—e.g., (x = 20 mm, y = 40 mm)—into pixels while accounting for the non‑printable area:
(20 mm ÷ 25.4 × 600 dpi − 120 px, 40 mm ÷ 25.4 × 600 dpi − 120 px) = (352 px, 825 px)
Creating an Application to Retrieve and Configure Printer and Paper Information
Creating the Project and Designing the UI
Launch Delphi and select “File” → “New” → “Windows VCL Application – Delphi (W)” to create a new project.
Drag and drop the following components onto the form:
TListBox × 2, TRadioGroup × 1, TMemo × 1.
Writing the Source Code and Setting Properties
Press F12 to switch to Code mode, then copy and paste the source code shown below.
Press F12 again to return to Design mode, then open the Object Inspector and switch to the Events tab.
Assign the following event handlers:
• Form1.OnCreate → FormCreate
• ListBox1.OnClick → ListBox1Click
• ListBox2.OnClick → ListBox2Click
• RadioGroup1.OnClick → RadioGroup1Click
unit Unit1;
interface
uses
Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants, System.Classes,
Vcl.Graphics, Vcl.Controls, Vcl.Forms, Vcl.Dialogs, Vcl.StdCtrls, Vcl.ExtCtrls;
type
TForm1 = class(TForm)
ListBox1: TListBox;
ListBox2: TListBox;
RadioGroup1: TRadioGroup;
Memo1: TMemo;
procedure FormCreate(Sender: TObject);
procedure ListBox1Click(Sender: TObject);
procedure ListBox2Click(Sender: TObject);
procedure RadioGroup1Click(Sender: TObject);
private
{ Private 宣言 }
//Retrieve current paper information from the active printer
procedure GetPaperInfo();
//Retrieve the list of available paper sizes for the active printer
procedure GetPapersList();
public
{ Public 宣言 }
end;
var
Form1: TForm1;
implementation
{$R *.dfm}
uses Vcl.Printers, WinApi.WinSpool;
// Form initialization
procedure TForm1.FormCreate(Sender: TObject);
var i:Integer;
begin
//Retrieve the list of installed printers
for i := 0 to Printer.Printers.Count-1 do
ListBox1.AddItem(Printer.Printers[i],nil);
ListBox1.ItemIndex:=Printer.PrinterIndex;
//Paper orientation
RadioGroup1.Caption:='Paper orientation';
RadioGroup1.Items.Add('Portrait');
RadioGroup1.Items.Add('Landscape');
RadioGroup1.ItemIndex:=0;
//Retrieve paper size list for the current printer
GetPapersList();
//Retrieve current paper information
GetPaperInfo();
end;
//Retrieve current paper information from the active printer
procedure TForm1.GetPaperInfo;
var Device, Driver, Port: array[0..255] of char;
DeviceModeHandle: THandle;
PMode : PDevMode;
begin
Memo1.Clear;
Memo1.Lines.Add('Physical Width:' + IntToStr(GetDeviceCaps(Printer.Handle, PHYSICALWIDTH))+'px');
Memo1.Lines.Add('Physical Height:' + IntToStr(GetDeviceCaps(Printer.Handle, PHYSICALHEIGHT))+'px');
Memo1.Lines.Add('Non-printable X:' + IntToStr(GetDeviceCaps(Printer.Handle, PHYSICALOFFSETX))+'px');
Memo1.Lines.Add('Non-printable Y:' + IntToStr(GetDeviceCaps(Printer.Handle, PHYSICALOFFSETY))+'px');
Memo1.Lines.Add('Resolution X:' + IntToStr(GetDeviceCaps(Printer.Handle, LOGPIXELSX))+'dpi');
Memo1.Lines.Add('Resolution Y:' + IntToStr(GetDeviceCaps(Printer.Handle, LOGPIXELSY))+'dpi');
Memo1.Lines.Add('Printable Width:' + IntToStr(GetDeviceCaps(Printer.Handle, HORZRES))+'px');
Memo1.Lines.Add('Printable Height:' + IntToStr(GetDeviceCaps(Printer.Handle, VERTRES))+'px');
Memo1.Lines.Add('Printable Width:' + IntToStr(Printer.PageWidth) +'px');
Memo1.Lines.Add('Printable Height:' + IntToStr(Printer.PageHeight)+'px');
if Printer.Orientation=TPrinterOrientation.poPortrait then
Memo1.Lines.Add('Orientation: Portrait')
else
Memo1.Lines.Add('Orientation: Landscape');
//Retrieve DeviceMode handle
Printer.GetPrinter(Device, Driver, Port, DeviceModeHandle);
if DeviceModeHandle = 0 then exit;
//Retrieve pointer to DevMode structure
PMode := GlobalLock(DeviceModeHandle);
try
Memo1.Lines.Add('Paper Size Number:'+IntToStr(PMode.dmPaperSize));
finally
GlobalUnlock(DeviceModeHandle);
end;
end;
//Retrieve the list of available paper sizes for the active printer
procedure TForm1.GetPapersList;
type
TPaperName = array[0..63] of Char; //static array (stack memory)
var Device, Driver, Port: array[0..255] of char;//static array (stack memory)
DeviceModeHandle: THandle;
PMode : PDevMode;
PaperCount, i:Integer;
PaperNo:Array of WORD; //dynamic array (heap memory)
PaperName:Array of TPaperName; //dynamic array (heap memory)
begin
ListBox2.Clear;
//Retrieve DeviceMode handle
Printer.GetPrinter(Device, Driver, Port, DeviceModeHandle);
if DeviceModeHandle = 0 then exit;
//Retrieve pointer to DevMode structure
PMode := GlobalLock(DeviceModeHandle);
try
//If 4th argument is nil, returns number of paper sizes
PaperCount := DeviceCapabilities(Device, Port, DC_PAPERS, nil, PMode);
if PaperCount>0 then
begin
SetLength(PaperNo,PaperCount);
SetLength(PaperName,PaperCount);
//Retrieve paper size numbers
DeviceCapabilities(Device, Port, DC_PAPERS, PChar(@PaperNo[0]), PMode);
//Retrieve paper size names
DeviceCapabilities(Device, Port, DC_PAPERNAMES, PChar(@PaperName[0]), PMode);
for i := 0 to PaperCount-1 do
ListBox2.AddItem(IntToStr(PaperNo[i])+'='+ PaperName[i], nil);
end;
finally
GlobalUnlock(DeviceModeHandle);
end;
if ListBox2.Items.Count>0 then
begin
ListBox2.ItemIndex:=
ListBox2.Items.IndexOfName( IntToStr(PMode.dmPaperSize) );
end;
end;
//When ListBox1 (printers) is clicked
procedure TForm1.ListBox1Click(Sender: TObject);
begin
Printer.PrinterIndex:=ListBox1.ItemIndex;
//Refresh paper size list
GetPapersList;
//Refresh current paper info
GetPaperInfo();
end;
//When ListBox2 (paper sizes) is clicked
procedure TForm1.ListBox2Click(Sender: TObject);
var Device, Driver, Port: array[0..255] of char;
DeviceModeHandle: THandle;
PMode : PDevMode;
begin
//Retrieve DeviceMode handle
Printer.GetPrinter(Device, Driver, Port, DeviceModeHandle);
if DeviceModeHandle = 0 then exit;
//DeviceModeハンドルからDevMode構造体のポインタを取得
PMode := GlobalLock(DeviceModeHandle);
try
//Enable paper size change flag
pMode.dmFields := pMode.dmFields or DM_PAPERSIZE;
//Change paper size
pMode.dmPaperSize :=
StrToInt( ListBox2.Items.Names[ListBox2.ItemIndex] );
finally
GlobalUnlock(DeviceModeHandle);
end;
//Apply paper size to printer
Printer.SetPrinter(Device,Driver,Port,DeviceModeHandle);
//Refresh current paper info
GetPaperInfo();
end;
//When RadioGroup1 (orientation) is clicked
procedure TForm1.RadioGroup1Click(Sender: TObject);
begin
if RadioGroup1.ItemIndex=0 then
Printer.Orientation:=TPrinterOrientation.poPortrait
else
Printer.Orientation:=TPrinterOrientation.poLandscape;
//Refresh current paper info
GetPaperInfo();
end;
end.
Running the Application
Select "Run" -> "Run" from the menu to compile and execute the application.
The list of installed printers will appear in ListBox1, with the current printer automatically selected.
ListBox2 will display the list of available paper sizes for the selected printer, and the currently active paper size will be highlighted.
Memo1 will show detailed information about the current printer’s active paper settings.
