Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
308 views
in Technique[技术] by (71.8m points)

.net - Printing with advanced options (tray selection, duplex, staple)

We have a project of managing printing documents. At first I wonder why printing options couldn't be set up in single place. For example printer tray selection for first page and for other pages can be done using MS Word automation:

var doc = _applicationObject.Documents.OpenNoRepairDialog(FileName: ref sourceFile, ReadOnly: ref readOnly,
                                                                 AddToRecentFiles: ref addToRecentFiles,
                                                                 Visible: ref visible);
doc.PageSetup.FirstPageTray = (WdPaperTray) firstPageTrayCode;
doc.PageSetup.OtherPagesTray = (WdPaperTray) otherPagesTrayCode;
_applicationObject.ActivePrinter = printerPath;
doc.Activate();
_applicationObject.PrintOut(Background: ref backgroundPrint, FileName: sourceFile);
doc.Close(ref saveChanges, ref _missing, ref _missing);

In the code above printer tray is specified as integer because some printers have not standart values for trays (we had this issue with HP - it's tray codes described here). So we first retrieve what trays printer have, using code:

var setting = new PrinterSettings();
setting.PrinterName = myPrinterName;
foreach (PaperSource tray in setting.PaperSources)
{
    Console.WriteLine("{0}: #{1}", tray.SourceName, tray.RawKind);
}

And this code works with no problems.

But there is no way to specify duplex and staple options here. Duplex can be done, using driver functions OpenPrinter and SetPrinter, like described here and recommended by Microsoft as well in this forum thread. Staple is completely unclear and if somebody knows by the way how to implement this, please let me know. Using Stapling enum, like in this MSDN article is useless as it requires custom rendering of the document to print.

I described the situation and how parts were implemented. That works fine on our environment: Windows Server 2008 R2, MS Office 2010 x32, Printers HP LaserJet P2055 and Ricoh Nashuatec DSm635. Tested with native and universal PCL6/PCL5e drivers: duplex and tray selection works as expected.

But after deployment the application to client, printers (HP LaserJet 4250 and Ricoh Aficio MP C7501) do printing always from default tray and without duplex. Tried few different drivers with exactly the same result.

In both environments printers are network printers. So to make them apply duplex setting, using printer driver, we needed to install local driver on server and make a local printer, as recommended my Microsoft on this support forum thread.

Though environments and printers used looks very similar, one works while other do not. Any help will be highly appreciated.

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

In case someone else needs it, I came up with a workaround, based on storing printer settings memory block in a binary file and then restoring it. The idea was described in this blog post, but it didn't work for me when simply copy-pasted (it worked only for some drivers and for some settings while other printing options were ignored).

So I remade it a bit so that now it can support all settings I've tried on any printer (with compatible driver) I've tested. Of course if you use driver of another printer for example it won't work.

The disadvantage of thi approach is of course that you should first set default printer preferences (in Control Panel) to what you need. That isn't always possible of course, but at least in some cases it can help.

So the full source code of a test util which is capable to store printer settings into a file, load this file again into printer and print a document using the specified settings file:

using System;
using System.Collections.Generic;
using System.Drawing.Printing;
using System.IO;
using System.Linq;
using System.Runtime.InteropServices;
using System.Text;
using Microsoft.Office.Interop.Word;

namespace PrintAdvancedTest
{
    [StructLayout(LayoutKind.Sequential)]
    public struct PRINTER_DEFAULTS
    {
        public int pDatatype;
        public int pDevMode;
        public int DesiredAccess;
    }

    [StructLayout(LayoutKind.Sequential)]
    public struct PRINTER_INFO_2
    {
        [MarshalAs(UnmanagedType.LPStr)]
        public readonly string pServerName;
        [MarshalAs(UnmanagedType.LPStr)]
        public readonly string pPrinterName;
        [MarshalAs(UnmanagedType.LPStr)]
        public readonly string pShareName;
        [MarshalAs(UnmanagedType.LPStr)]
        public readonly string pPortName;
        [MarshalAs(UnmanagedType.LPStr)]
        public readonly string pDriverName;
        [MarshalAs(UnmanagedType.LPStr)]
        public readonly string pComment;
        [MarshalAs(UnmanagedType.LPStr)]
        public readonly string pLocation;
        public IntPtr pDevMode;
        [MarshalAs(UnmanagedType.LPStr)]
        public readonly string pSepFile;
        [MarshalAs(UnmanagedType.LPStr)]
        public readonly string pPrintProcessor;
        [MarshalAs(UnmanagedType.LPStr)]
        public readonly string pDatatype;
        [MarshalAs(UnmanagedType.LPStr)]
        public readonly string pParameters;
        public IntPtr pSecurityDescriptor;
        public readonly Int32 Attributes;
        public readonly Int32 Priority;
        public readonly Int32 DefaultPriority;
        public readonly Int32 StartTime;
        public readonly Int32 UntilTime;
        public readonly Int32 Status;
        public readonly Int32 cJobs;
        public readonly Int32 AveragePPM;
    }

    public class PrintSettings
    {
        private const short CCDEVICENAME = 32;
        private const short CCFORMNAME = 32;

        //Constants for DEVMODE
        // Constants for DocumentProperties
        private const int DM_MODIFY = 8;
        private const int DM_COPY = 2;
        private const int DM_IN_BUFFER = DM_MODIFY;
        private const int DM_OUT_BUFFER = DM_COPY;
        // const intants for dmOrientation
        private const int DMORIENT_PORTRAIT = 1;
        private const int DMORIENT_LANDSCAPE = 2;
        // const intants for dmPrintQuality
        private const int DMRES_DRAFT = (-1);
        private const int DMRES_HIGH = (-4);
        private const int DMRES_LOW = (-2);
        private const int DMRES_MEDIUM = (-3);
        // const intants for dmTTOption
        private const int DMTT_BITMAP = 1;
        private const int DMTT_DOWNLOAD = 2;
        private const int DMTT_DOWNLOAD_OUTLINE = 4;
        private const int DMTT_SUBDEV = 3;
        // const intants for dmColor
        private const int DMCOLOR_COLOR = 2;
        private const int DMCOLOR_MONOCHROME = 1;
        // const intants for dmCollate
        private const int DMCOLLATE_FALSE = 0;
        private const int DMCOLLATE_TRUE = 1;
        // const intants for dmDuplex
        private const int DMDUP_HORIZONTAL = 3;
        private const int DMDUP_SIMPLEX = 1;
        private const int DMDUP_VERTICAL = 2;

        //const for security access
        private const int PRINTER_ACCESS_ADMINISTER = 0x4;
        private const int PRINTER_ACCESS_USE = 0x8;
        private const int STANDARD_RIGHTS_REQUIRED = 0xF0000;

        private const int PRINTER_ALL_ACCESS =
            (STANDARD_RIGHTS_REQUIRED | PRINTER_ACCESS_ADMINISTER
             | PRINTER_ACCESS_USE);


        /* field selection bits */
        private const int DM_ORIENTATION = 0x00000001;
        private const int DM_PAPERSIZE = 0x00000002;
        private const int DM_PAPERLENGTH = 0x00000004;
        private const int DM_PAPERWIDTH = 0x00000008;
        private const int DM_SCALE = 0x00000010;
        private const int DM_POSITION = 0x00000020;
        private const int DM_NUP = 0x00000040;
        private const int DM_DISPLAYORIENTATION = 0x00000080;
        private const int DM_COPIES = 0x00000100;
        private const int DM_DEFAULTSOURCE = 0x00000200;
        private const int DM_PRINTQUALITY = 0x00000400;
        private const int DM_COLOR = 0x00000800;
        private const int DM_DUPLEX = 0x00001000;
        private const int DM_YRESOLUTION = 0x00002000;
        private const int DM_TTOPTION = 0x00004000;
        private const int DM_COLLATE = 0x00008000;
        private const int DM_FORMNAME = 0x00010000;
        private const int DM_LOGPIXELS = 0x00020000;
        private const int DM_BITSPERPEL = 0x00040000;
        private const int DM_PELSWIDTH = 0x00080000;
        private const int DM_PELSHEIGHT = 0x00100000;
        private const int DM_DISPLAYFLAGS = 0x00200000;
        private const int DM_DISPLAYFREQUENCY = 0x00400000;
        private const int DM_ICMMETHOD = 0x00800000;
        private const int DM_ICMINTENT = 0x01000000;
        private const int DM_MEDIATYPE = 0x02000000;
        private const int DM_DITHERTYPE = 0x04000000;
        private const int DM_PANNINGWIDTH = 0x08000000;
        private const int DM_PANNINGHEIGHT = 0x10000000;
        private const int DM_DISPLAYFIXEDOUTPUT = 0x20000000;


        [StructLayout(LayoutKind.Sequential)]
        public struct DEVMODE
        {
            [MarshalAs(UnmanagedType.ByValTStr, SizeConst = CCDEVICENAME)]
            public string dmDeviceName;
            public short dmSpecVersion;
            public short dmDriverVersion;
            public short dmSize;
            public short dmDriverExtra;
            public int dmFields;
            public short dmOrientation;
            public short dmPaperSize;
            public short dmPaperLength;
            public short dmPaperWidth;
            public short dmScale;
            public short dmCopies;
            public short dmDefaultSource;
            public short dmPrintQuality;
            public short dmColor;
            public short dmDuplex;
            public short dmYResolution;
            public short dmTTOption;
            public short dmCollate;
            [MarshalAs(UnmanagedType.ByValTStr, SizeConst = CCFORMNAME)]
            public string dmFormName;
            public short dmUnusedPadding;
            public short dmBitsPerPel;
            public int dmPelsWidth;
            public int dmPelsHeight;
            public int dmDisplayFlags;
            public int dmDisplayFrequency;
        }

        static void Main(string[] args)
        {
            Dictionary<string, Action> commands = new Dictionary<string, Action>
                                                      {
                                                          {"save", PrinterPreferencesSave},
                                                          {"print", PrinterPreferencesPrint},
                                                          {"set", PrinterPreferencesSet},
                                                          {"info", PrinterInfo}
                                                      };

            while (true)
            {
                Console.Write("Command ({0}): ", string.Join(", ", commands.Keys));
                string command = Console.ReadLine();
                Action action;
                if (!commands.TryGetValue(command, out action))
                {
                    Console.WriteLine("Invalid command");
                }
                else
                {
                    action();
                }
            }
        }

        static void PrinterPreferencesSave()
        {
            Console.Write("Printer name: ");
            string printerName = Console.ReadLine();
            Console.Write("Settings file path format: ");
            string SettingsFileNameFormat = Console.ReadLine();
            string testName;

            while (true)
            {
                Console.Write("SAVE: Settings set name: ");
                testName = Console.ReadLine();
                if (testName == "end")
                {
                    break;
                }
                getDevMode(printerName, string.Format(SettingsFileNameFormat, testName));
            }
        }

        static void PrinterPreferencesPrint()
        {
            Console.Write("Printer name: ");
            string printerName = Console.ReadLine();
            Console.Write("Settings file path format: ");
            string SettingsFileNameFormat = Console.ReadLine();
            Console.Write("Document to print: ");
            string docToPrintPath = Console.ReadLine();

            string testName;
            while (true)
            {
                Console.Write("PRINT: Settings set name: ");
                testName = Console.ReadLine();
                if (testName == "end")
                {
                    break;
                }
                string filePath = string.Format(SettingsFileNameFormat, testName);
                if (!File.Exists(filePath))
                {
                    Console.WriteLine("File {0} not exists", filePath);
                    return;
                }
                var success = setDevMode(printerName, filePath);
                if (success)
                {
                    PrintWordDocument(docToPrintPath, printerName);
                }
            }
        }

        static void PrinterPreferencesSet()
        {
            Console.Write("Printer name: ");
            string printerName = Console.ReadLine();
            Console.Write("Settings file path format: ");
            string SettingsFileNameFormat = Console.ReadLine();

            string testName;
            while (true)
            {
                Console.Write("SET: Settings set name: ");
                testName = Console.ReadLine();
                if (testName == "end")
                {
                    break;
                }
                string filePath = string.Format(SettingsFileNameFormat, testName);
                if (!File.Exists(filePath))
                {
                    Console.WriteLine("File {0} not exists", filePath);
                    return;
                }
                var success = setDevMode(printerName, filePath);
                if(!success)
                {
                    Console.WriteLine("Failed");
                }
            }
        }

        private static void PrinterInfo()
        {
            Console.Write("Printer name: ");
            string printerName = Console.ReadLine

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...