【问题标题】:VSTO Printer APIVSTO 打印机 API
【发布时间】:2018-02-13 13:31:19
【问题描述】:

尝试使用以下代码示例,该示例在 WinForm 应用程序中运行良好,但在 VSTO 中运行良好。是否有某种允许访问的权限?

可以设置默认打印机,但不能获取或设置打印机设置。

从插件中获取以下异常:

System.AccessViolationException: '试图读取或写入受保护的内存。这通常表明其他内存已损坏。 http://www.pinvoke.net/default.aspx/winspool.SetDefaultPrinter

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

visual studio 项目模板是一个 {Word/Outlook} 2013 和 2016 VSTO 插件

string name = @"\\{printer server name}\{printer name}";
PRNsettings p = new PRNsettings();

var v = p.ChangePrinterSetting(name, new PrinterData { colour = 1, copies = 1, duplex = 1, source = 7 });

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;
    }
}

【问题讨论】:

    标签: c# printing vsto office-interop


    【解决方案1】:

    如果您在为 AnyCPU 或 x64 构建时遇到此错误,您可能会发现我的回答很有帮助: WinSpool OpenPrinter Access Denied - building for AnyCPU\x64

    【讨论】:

      猜你喜欢
      • 2014-12-23
      • 2018-05-13
      • 1970-01-01
      • 1970-01-01
      • 2019-01-27
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多