DocumentProperties не обновляет задание печати с новой структурой DEVMODE

Я пытаюсь обновить задание печати с новым набором свойств для структуры принтера DEVMODE в моем приложении Win Forms на С#. В частности, лоток для печати.

            [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, 0, 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, 2, 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, IntPtr.Zero, IntPtr.Zero, (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, hPrinter, szPrinterName.Normalize(), pDevMode, IntPtr.Zero, (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, hPrinter, szPrinterName.Normalize(), printerInfo.pDevMode, printerInfo.pDevMode, (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 каждый раз, когда я читаю или пишу в структуру, и она возвращает ok. Я пытался установить структуру DEVMODE как до, так и после настройки задания. Он просто не обновляет настройки, когда я просматриваю свойства заданий на печать.

Может ли кто-нибудь сказать мне, что мне здесь не хватает? К вашему сведению, он отлично печатает любые документы, но в лоток принтера по умолчанию.


person Maddy    schedule 21.12.2020    source источник
comment
Вы должны показать все определения взаимодействия.   -  person Simon Mourier    schedule 21.12.2020
comment
@SimonMourier добавил   -  person Maddy    schedule 21.12.2020
comment
DOCINFOA явно неверен для начала. Также я настоятельно рекомендую везде использовать версии Unicode (W). Все A версии для Ansi (много воды утекло со времен Windows 95)   -  person Simon Mourier    schedule 21.12.2020
comment
@SimonMourier при использовании версий Unicode выдает ошибку OpenPrinter с кодом 1801, говорящим о недопустимом имени принтера. Раньше это работало при использовании ANSI.   -  person Maddy    schedule 21.12.2020
comment
Ну, это, вероятно, еще одна проблема в ваших определениях, но Unicode API работает.   -  person Simon Mourier    schedule 21.12.2020
comment
Существует множество примеров взаимодействия для изучения: stackoverflow.com/q/46586214/313445   -  person Nick Westgate    schedule 22.12.2020