DocumentProperties 不使用新的 DEVMODE 结构更新打印作业

问题描述

我正在尝试使用设置为我的 C# win 表单应用程序中打印机 DEVMODE 结构的新属性来更新打印作业。特别是要打印到的托盘。

            [StructLayout(LayoutKind.Sequential,CharSet = CharSet.Ansi)]
            public class DOCINFOA
            {                    
                [MarshalAs(UnmanagedType.LPStr)]
                public string lpszDocName;

                [MarshalAs(UnmanagedType.LPStr)]
                public string lpszOutput;

                [MarshalAs(UnmanagedType.LPStr)]
                public string lpszDatatype;          
            }

            [StructLayout(LayoutKind.Sequential,CharSet = CharSet.Auto)]
            private struct PRINTER_INFO_2
            {
                [MarshalAs(UnmanagedType.LPStr)]
                public string pServerName;

                [MarshalAs(UnmanagedType.LPStr)]
                public string pprinterName;

                [MarshalAs(UnmanagedType.LPStr)]
                public string pShareName;

                [MarshalAs(UnmanagedType.LPStr)]
                public string pPortName;

                [MarshalAs(UnmanagedType.LPStr)]
                public string pDriverName;

                [MarshalAs(UnmanagedType.LPStr)]
                public string pComment;

                [MarshalAs(UnmanagedType.LPStr)]
                public string pLocation;

                public IntPtr pDevMode;

                [MarshalAs(UnmanagedType.LPStr)]
                public string pSepFile;

                [MarshalAs(UnmanagedType.LPStr)]
                public string pprintProcessor;

                [MarshalAs(UnmanagedType.LPStr)]
                public string pDatatype;

                [MarshalAs(UnmanagedType.LPStr)]
                public string pParameters;

                public IntPtr pSecurityDescriptor;

                public int Attributes;
                public int Priority;
                public int DefaultPriority;
                public int StartTime;
                public int UntilTime;
                public int Status;
                public int cJobs;
                public int AveragePPM;
            }

            [StructLayout(LayoutKind.Sequential,CharSet = CharSet.Ansi)]
            public class DEVMODE
            {
                private const int CCHDEVICENAME = 32;
                private const int CCHFORMNAME = 32;

                [MarshalAs(UnmanagedType.ByValTStr,SizeConst = CCHDEVICENAME)]
                public string dmDeviceName;
                public ushort dmSpecVersion;
                public ushort dmDriverVersion;
                public ushort dmSize;
                public ushort dmDriverExtra;
                public uint dmFields;

                // values to set based on dmFields bits
                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 int dmPositionX;
                public int dmPositionY;
                public uint dmdisplayOrientation;
                public uint dmdisplayFixedOutput;

                public short dmColor;
                public short dmDuplex;
                public short dmYResolution;
                public short dmTTOption;
                public short dmCollate;

                [MarshalAs(UnmanagedType.ByValTStr,SizeConst = CCHFORMNAME)]
                public string dmFormName;
                public ushort dmLogPixels;
                public uint dmBitsPerPel;
                public uint dmPelsWidth;
                public uint dmPelsHeight;
                public uint dmdisplayFlags;
                public uint dmdisplayFrequency;
                public uint dmICMMethod;
                public uint dmICMIntent;
                public uint dmMediaType;
                public uint dmDitherType;
                public uint dmReserved1;
                public uint dmReserved2;
                public uint dmPanningWidth;
                public uint dmPanningHeight;
            }
            
            [StructLayout(LayoutKind.Sequential,CharSet = CharSet.Ansi)]
            public class PRINTER_DEFAULTS
            {
                public IntPtr pDatatype;
                public IntPtr pDevMode;
                public int DesiredAccess;
            }

            [Flags]
            public enum FModes
            {
                DM_SIZEOF = 0,DM_UPDATE = 1,DM_copY = 2,DM_PROMPT = 4,DM_MODIFY = 8,DM_OUT_DEFAULT = DM_UPDATE,DM_OUT_BUFFER = DM_copY,DM_IN_PROMPT = DM_PROMPT,DM_IN_BUFFER = DM_MODIFY,}

            [Flags]
            public enum DevModeFields : uint
            { 
                DM_ICMMETHOD = 0x10000,DM_FORMNAME = 0x00010000,DM_ICMINTENT = 0x04000000,DM_MEDIATYPE = 0x08000000,DM_DITHERTYPE = 0x10000000,DM_copIES = 0x00000100,DM_DEFAULTSOURCE = 0x00000200,DM_PRINT_QUALITY = 0x00000400,DM_COLOR = 0x00000800,DM_DUPLEX = 0x00001000,DM_YRESOLUTION = 0x00002000,DM_TTOPTION = 0x00004000,DM_COLLATE = 0x00008000,DM_ORIENTATION = 0x00000001,DM_PAPERSIZE = 0x00000002,DM_PAPERLENGTH = 0x00000004,DM_PAPERWIDTH = 0x00000008,DM_SCALE = 0x00000010
            }

            // DesiredAccess properties
            const int PRINTER_ACCESS_ADMINISTER = 0x4;
            const int PRINTER_ACCESS_USE = 0x8;
            const int STANDARD_RIGHTS_required = 0xF0000;
            const int PRINTER_ALL_ACCESS = (STANDARD_RIGHTS_required | PRINTER_ACCESS_ADMINISTER | PRINTER_ACCESS_USE);


            public enum PaperSource
            {
                DMRES_HIGH = -4,DMRES_MEDIUM = -3,DMRES_LOW = -2,DMRES_DRAFT = -1,DMBIN_UPPER = 1,DMBIN_LOWER = 2,DMBIN_MIDDLE = 3,DMBIN_MANUAL = 4,DMBIN_ENVELOPE = 5,DMBIN_ENVMANUAL = 6,DMBIN_AUTO = 7,DMBIN_TRACTOR = 8,DMBIN_SMALLFMT = 9,DMBIN_LARGEFMT = 10,DMBIN_LARGECAPACITY = 11,DMBIN_CASSETTE = 14,DMBIN_FORMSOURCE = 15
            }

            PRINTER_DEFAULTS settings = new PRINTER_DEFAULTS
            {
                pDatatype = IntPtr.Zero,pDevMode = IntPtr.Zero,DesiredAccess = PRINTER_ACCESS_USE
            };

            int bytesNeeded = 0;

            // get the printer handle
            if (OpenPrinter(szPrinterName.normalize(),out IntPtr hPrinter,settings))
            {
                // find out size needed for buffer first
                GetPrinter(hPrinter,2,IntPtr.Zero,out bytesNeeded);
                if (bytesNeeded > 0)
                {
                    // allocate memory for the printer info
                    IntPtr pprinterInfo = Marshal.AllocHGlobal(bytesNeeded);

                    // fetch pointer to printer info at level 2 (gives us DEVMODE data)
                    if (GetPrinter(hPrinter,pprinterInfo,bytesNeeded,out _))
                    {
                        // convert the pointer to the readable data
                        PRINTER_INFO_2 printerInfo = (PRINTER_INFO_2)Marshal.PtrToStructure(pprinterInfo,typeof(PRINTER_INFO_2));

                        // for some reason it didnt fetch the DEVMODE data we need,try getting it elsewhere
                        if (true)
                        {
                            // find out size needed for buffer first
                            bytesNeeded = DocumentProperties(IntPtr.Zero,hPrinter,printerInfo.pprinterName,(int)FModes.DM_SIZEOF);
                            if (bytesNeeded > 0)
                            {
                                // allocate memory for the DEVMODE info
                                IntPtr pDevMode = Marshal.AllocHGlobal(bytesNeeded);

                                // fetch pointer to DEVMODE info
                                int result = DocumentProperties(IntPtr.Zero,szPrinterName.normalize(),pDevMode,(int)FModes.DM_OUT_BUFFER);
                                if (result > 0)
                                {
                                    printerInfo.pDevMode = pDevMode;
                                }
                            }
                        }

                        // create the print job
                        DOCINFOA di = new DOCINFOA
                        {
                            lpszDocName = "My C#.NET RAW Document",lpszDatatype = "RAW"
                        };

                        if (StartDocPrinter(hPrinter,1,di))
                        {
                            if (StartPagePrinter(hPrinter))
                            {
                                // convert the pointer to readable data
                                DEVMODE dm = (DEVMODE)Marshal.PtrToStructure(printerInfo.pDevMode,typeof(DEVMODE));

                                // set new properties for printer
                                dm.dmFields |= (uint)DevModeFields.DM_DEFAULTSOURCE;
                                dm.dmDefaultSource = (short)PaperSource.DMBIN_UPPER;

                                Marshal.StructuretoPtr(dm,printerInfo.pDevMode,false);

                                //overwrite the printers settings
                                int res = DocumentProperties(IntPtr.Zero,(int)FModes.DM_IN_BUFFER | (int)FModes.DM_OUT_BUFFER);
                                if (res > 0)
                                {
                                    WritePrinter(hPrinter,pBytes,dwCount,out _);
                                    EndPagePrinter(hPrinter);
                                }

                                EndDocPrinter(hPrinter);
                            }

                            ClosePrinter(hPrinter);
                        }
                    }
                }

我遇到的问题是对 DocumentProperties 的最终调用没有更新打印机作业设置。我通过在每次读取或写入结构时插入 IsDevmodeValid 调用来检查结构是否有效,并且返回正常。我已经尝试在设置作业之前和之后设置 DEVMODE 结构。当我查看打印作业属性时,它只是不更新​​设置。

谁能告诉我我在这里遗漏了什么?仅供参考,它可以正常打印任何文档,但打印到打印机的认托盘。

解决方法

暂无找到可以解决该程序问题的有效方法,小编努力寻找整理中!

如果你已经找到好的解决方法,欢迎将解决方案带上本链接一起发送给小编。

小编邮箱:dio#foxmail.com (将#修改为@)