none
VSTO Printer API RRS feed

  • Question

  • Trying to use the following code example which works fine in winform application but not in VSTO is there some sort of permissions that allow access ?

    Can set the default printer but can't get or set printer settings.

    Get the following exception from within addin:

    System.AccessViolationException: 'Attempted to read or write protected memory. This is often an indication that other memory is corrupt.'

    http://www.pinvoke.net/default.aspx/winspool.SetDefaultPrinter

    http://www.pinvoke.net/default.aspx/winspool/OpenPrinter.html

        public class PrinterData
        {
            public PrinterData()
            {
                copies = -1;
                colour = -1;
                duplex = -1;
                source = -1;
            }

            public int copies { get; set; }
            public int colour { get; set; }
            public int duplex { get; set; }
            public int source { get; set; }
        }

        public class PRNsettings
        {
            private IntPtr hPrinter = new System.IntPtr();
            private PRINTER_DEFAULTS PrinterValues = new PRINTER_DEFAULTS();
            private PRINTER_INFO_2 pinfo = new PRINTER_INFO_2();
            private DEVMODE dm;
            private IntPtr ptrDM;
            private IntPtr ptrPrinterInfo;
            private int sizeOfDevMode = 0;
            private int lastError;
            private int nBytesNeeded;
            private long nRet;
            private int intError;
            private System.Int32 nJunk;
            private IntPtr yDevModeData;

            [DllImport("kernel32.dll", EntryPoint = "GetLastError", SetLastError = false, ExactSpelling = true, CallingConvention = CallingConvention.StdCall)]
            private static extern Int32 GetLastError();

            [DllImport("winspool.Drv", EntryPoint = "ClosePrinter", SetLastError = true, ExactSpelling = true, CallingConvention = CallingConvention.StdCall)]
            private static extern bool ClosePrinter(IntPtr hPrinter);

            [DllImport("winspool.Drv", EntryPoint = "DocumentPropertiesA", SetLastError = true, ExactSpelling = true, CallingConvention = CallingConvention.StdCall)]
            private static extern int DocumentProperties(IntPtr hwnd, IntPtr hPrinter,

            [MarshalAs(UnmanagedType.LPStr)] string pDeviceNameg, IntPtr pDevModeOutput, ref IntPtr pDevModeInput, int fMode);
            [DllImport("winspool.Drv", EntryPoint = "GetPrinterA", SetLastError = true, CharSet = CharSet.Ansi, ExactSpelling = true, CallingConvention = CallingConvention.StdCall)]
            private static extern bool GetPrinter(IntPtr hPrinter, Int32 dwLevel, IntPtr pPrinter, Int32 dwBuf, out Int32 dwNeeded);

            [DllImport("winspool.drv", CharSet = CharSet.Unicode, SetLastError = true)]
            [return: MarshalAs(UnmanagedType.Bool)]
            private static extern bool OpenPrinter(string pPrinterName, out IntPtr phPrinter, PRINTER_DEFAULTS pDefault);

            [DllImport("winspool.drv", CharSet = CharSet.Ansi, SetLastError = true)]
            private static extern bool SetPrinter(IntPtr hPrinter, int Level, IntPtr pPrinter, int Command);

            [DllImport("winspool.drv", CharSet = CharSet.Auto, SetLastError = true)]
            public static extern bool SetDefaultPrinter(string Name);

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

            [StructLayout(LayoutKind.Sequential)]
            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 Int32 Attributes;
                public Int32 Priority;
                public Int32 DefaultPriority;
                public Int32 StartTime;
                public Int32 UntilTime;
                public Int32 Status;
                public Int32 cJobs;
                public Int32 AveragePPM;
            }

            private const short CCDEVICENAME = 32;
            private const short CCFORMNAME = 32;

            [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;
                public uint dmMediaType;
            }

            private const int DM_DUPLEX = 0x1000;
            private const int DM_IN_BUFFER = 8;
            private const int DM_OUT_BUFFER = 2;
            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);

            public int returnSource;
            public int returnDuplex;
            public int returnColor;
            public int returnCopies;

            public bool SetDefault(string name)
            {
                try
                {
                    return SetDefaultPrinter(name);
                }
                catch (Exception) { return false; }
            }

            public bool ChangePrinterSetting(string PrinterName, PrinterData PS)
            {
                try
                {
                    dm = this.GetPrinterSettings(PrinterName);

                    // Sent back to allow reset of the settings back to original.
                    returnSource = dm.dmDefaultSource;
                    returnDuplex = dm.dmDuplex;
                    returnColor = dm.dmColor;
                    returnCopies = dm.dmCopies;

                    if (PS.source > -1)
                        dm.dmDefaultSource = (short)PS.source;

                    if (PS.duplex > -1)
                        dm.dmDuplex = (short)PS.duplex;

                    if (PS.colour > -1)
                        dm.dmColor = (short)PS.colour;

                    if (PS.copies > -1)
                        dm.dmCopies = (short)PS.copies;

                    Marshal.StructureToPtr(dm, yDevModeData, true);
                    pinfo.pDevMode = yDevModeData;
                    pinfo.pSecurityDescriptor = IntPtr.Zero;

                    Marshal.StructureToPtr(pinfo, ptrPrinterInfo, false);
                    lastError = Marshal.GetLastWin32Error();
                    nRet = Convert.ToInt16(SetPrinter(hPrinter, 2, ptrPrinterInfo, 0));

                    // Error
                    if (nRet == 0)
                        return false;

                    if (hPrinter != IntPtr.Zero)
                        ClosePrinter(hPrinter);

                    return Convert.ToBoolean(nRet);
                }
                catch (Exception) { return false; }
            }

            public DEVMODE GetPrinterSettings(string PrinterName)
            {
                PrinterData PData = new PrinterData();
                DEVMODE dm;

                const int PRINTER_ACCESS_ADMINISTER = 0x4;
                const int PRINTER_ACCESS_USE = 0x8;
                const int PRINTER_ALL_ACCESS = (STANDARD_RIGHTS_REQUIRED |
                           PRINTER_ACCESS_ADMINISTER | PRINTER_ACCESS_USE);

                PrinterValues.pDatatype = 0;
                PrinterValues.pDevMode = 0;
                PrinterValues.DesiredAccess = PRINTER_ALL_ACCESS;
                nRet = Convert.ToInt32(OpenPrinter(PrinterName,
                               out hPrinter, PrinterValues));

                GetPrinter(hPrinter, 2, IntPtr.Zero, 0, out nBytesNeeded);

                Marshal.AllocCoTaskMem(nBytesNeeded);
                ptrPrinterInfo = Marshal.AllocHGlobal(nBytesNeeded);
                nRet = Convert.ToInt32(GetPrinter(hPrinter, 2, ptrPrinterInfo, nBytesNeeded, out nJunk));
                pinfo = (PRINTER_INFO_2)Marshal.PtrToStructure(ptrPrinterInfo, typeof(PRINTER_INFO_2));

                IntPtr Temp = new IntPtr();

                if (pinfo.pDevMode == IntPtr.Zero)
                {
                    IntPtr ptrZero = IntPtr.Zero;
                    sizeOfDevMode = DocumentProperties(IntPtr.Zero, hPrinter, PrinterName, ptrZero, ref ptrZero, 0);
                    ptrDM = Marshal.AllocCoTaskMem(sizeOfDevMode);

                    int i = DocumentProperties(IntPtr.Zero, hPrinter, PrinterName, ptrDM, ref ptrZero, DM_OUT_BUFFER);
                    pinfo.pDevMode = ptrDM;
                }

                intError = DocumentProperties(IntPtr.Zero, hPrinter, PrinterName, IntPtr.Zero, ref Temp, 0);

                yDevModeData = Marshal.AllocHGlobal(intError);
                intError = DocumentProperties(IntPtr.Zero, hPrinter, PrinterName, yDevModeData, ref Temp, 2);
                dm = (DEVMODE)Marshal.PtrToStructure(yDevModeData, typeof(DEVMODE));

                return dm;
            }
        }


    Friday, February 2, 2018 12:05 PM

All replies

  • Hell JohnA-83,

    Which type is your add-in? A word add-in? Excel add-in? How do you set the print setting? Could you tell us the detail repro steps so we could try to reproduce your issue?

    Besides, many developers report that unchecking option "Suppress JIT optimization on module load" could resolve this issue. I would suggest you go to Tools->Option->Debugging->General and then uncheck the option for testing.

    Best Regards,

    Terry


    MSDN Community Support
    Please remember to click "Mark as Answer" the responses that resolved your issue, and to click "Unmark as Answer" if not. This can be beneficial to other community members reading this thread. If you have any compliments or complaints to MSDN Support, feel free to contact MSDNFSF@microsoft.com.

    Monday, February 5, 2018 8:32 AM
  • Hi Terry,

    Just check the "Suppress JIT optimization on module load" and it's already unchecked. Using it in Word and Outlook. visual studio project template is a {Word/Outlook} 2013 and 2016 VSTO Add-in

    string name = @"\\{printer server name}\{printer name}";
    PRNsettings p = new PRNsettings();
    
    //button1.Text = p.SetDefault(name); works
    
    var v = p.ChangePrinterSetting(name, new PrinterData { colour = 1, copies = 1, duplex = 1, source = 7 });
    
    

    Thanks,

    John

    Monday, February 5, 2018 11:16 AM
  • Hi Terry,
    Did you manage to get this working?

    Thanks,

    John

    Monday, February 12, 2018 10:17 AM