The PrintManager
for .NET API allows printing of PDF files through any .NET application. The settings accessible to the PrintManager
are limited to those exposed through a standard API (such as Win32 or .NET). But a printer may have additional settings that are specific to that printer and are not readily available through a standard API. This means that there could be non-standard features or settings available that vary between printers that are not able to be exposed through the PrintManager
API. To remedy this, we have exposed a way to manually save and reuse a specific state of the native printer’s dialog box that when provided to the Printjob
will affect that job as if those options where manually selected by a user. A full example on how to accomplish this is outlined below.
We will start with the code to invoke printer’s native dialog box and save the settings to a file.
To invoke the printer's advanced setting dialog, we will be using a Win32
function called "AdvancedDocumentProperties
".
AdvancedDocumentProperties(IntPtr.Zero,IntPtr.Zero,e.PrintJob.Printer.Name,e.DevMode, e.DevMode);
In order to import the above function to a .NET application, use the following DllImport
.
[DllImport("winspool.Drv", EntryPoint = "AdvancedDocumentPropertiesW",
SetLastError = true, ExactSpelling = true, CallingConvention = CallingConvention.StdCall)]
static extern int AdvancedDocumentProperties(IntPtr hwnd, IntPtr hPrinter,
[MarshalAs(UnmanagedType.LPWStr)] string pDeviceName, IntPtr pDevModeOutput, IntPtr pDevModeInput);
Calling the Print()
method will fire the Printjob.Starting
event. In the event handler, call AdvancedDocumentProperties
to display the printer setting dialog box. Select the appropriate setting that you would like to save to file and click OK. The file can be generated with individual settings or with a group of settings.
PrintJob printJob = new PrintJob(Printer.Default, "DocumentA.pdf");
printJob.Starting += new PrintJobStartingEventHandler(this.onStartingPrint1);
printJob.Print();
PrintJobStartingEventArgs
contains the following properties that will be used to retrieve the printer settings from the dialog box.
Name | Type | Definition |
Devmode | Intptr | Pointer towards Devmode structure |
DevmodeSize | Int | Size of Devmode |
DevmodeDriverExtra | Int | Size of DmDriverExtra |
PrintJob | PrintJob | DynamicPDF Printmanager PrintJob object. Generic printer settings can be changed using this object. |
Here is the code for the event handler to retrieve and save the selected printer setting.
private void onStartingPrint1(object sender, PrintJobStartingEventArgs e)
{
int value = AdvancedDocumentProperties(IntPtr.Zero, IntPtr.Zero, e.PrintJob.Printer.Name, e.DevMode, e.DevMode);
byte[] bytearray = new byte[e.DevModeSize + e.DevModeDriverExtra];
Marshal.Copy(e.DevMode, bytearray, 0, e.DevModeSize + e.DevModeDriverExtra);
File.WriteAllBytes("SettingsFile.bin", bytearray);
}
Next, we will print a PDF using the saved settings by overwriting the Devmode
and DmDriverExtra
structures with the file contents. Due to this, all settings applied to the PrintJob
object before Printjob.Starting
event handler call will be lost. However, we can set the print settings after overwriting Devmode
and DmDriverExtra
in the event handler.
private void onStartingPrint2(object sender, PrintJobStartingEventArgs e)
{
byte[] bytearray = File.ReadAllBytes("SettingsFile.bin");
IntPtr pdevmode = Marshal.AllocHGlobal(bytearray.Length);
Marshal.Copy(bytearray, 0, e.DevMode, bytearray.Length);
int value = AdvancedDocumentProperties
(IntPtr.Zero, IntPtr.Zero, e.PrintJob.Printer.Name, e.DevMode, e.DevMode);
e.PrintJob.PrintOptions.Copies = 1;
}
The complete source code is available for download from the link at the top of this post.