You need to enable JavaScript to run this app.
最新活动
大模型
产品
解决方案
定价
生态与合作
支持与服务
开发者
了解我们

.NET Framework 4.8中PrintPreviewControl无法正确显示灰度打印设置的问题求助

.NET Framework 4.8中PrintPreviewControl无法正确显示灰度打印设置的问题求助

大家好,我最近在做WinForms打印相关功能时遇到了个棘手的问题,想请各位帮忙分析下:

我跟着打印和打印预览的官方教程实现功能,但没有用默认的PrintPreviewDialog,而是换成了PrintPreviewControl。另外我还在自定义对话框里加了个打印机属性按钮,用来修改打印机的设置,比如无边距打印、灰度模式、纸张尺寸这些。

目前打印功能是正常的:根据设置,打印出来的内容可以是绿色或者灰度,纸张尺寸的修改也能正确生效。但PrintPreviewControl的预览效果始终不对——不管我怎么设置灰度,预览里的内容都是带正常边框的绿色,只有纸张尺寸的变化能在预览里正确反映。

有意思的是,如果我在打印机属性窗口里选择“打印预览”,然后点击打印,那个弹出的预览窗口是能正确显示灰度效果的。

下面是我的测试代码,有没有大佬能帮我看看为什么PrintPreviewControl没法正确显示灰度设置呢?我用的是Visual Studio,项目基于.NET Framework 4.8。

using System;
using System.Drawing;
using System.Drawing.Printing;
using System.Runtime.InteropServices;
using System.Windows.Forms;

namespace Penrose
{
    public partial class printCustom2 : Form
    {
        private string stringToPrint = "";
        readonly string docName = "testPage.txt";
        readonly string docPath = @"C:\Users\georg\My Drive\Personal\Godel Escher Bach\Maths\Penrose test";
        public PrinterSettings printerSettings { get; private set; }

        public printCustom2()
        {
            InitializeComponent();
            printerSettings = new PrinterSettings();
            printerSettings.PrinterName = "Canon TS8200 series"; // 换成你的打印机名称
            printDocument1.PrinterSettings = printerSettings;
        }

        private void ButtonPreview_Click(object sender, EventArgs e)
        {
            string fullPath = System.IO.Path.Combine(docPath, docName);
            printDocument1.DocumentName = docName;
            stringToPrint = System.IO.File.ReadAllText(fullPath);
            printPreviewControl1.Document = printDocument1;
            printPreviewControl1.StartPage = 0;
            printPreviewControl1.Invalidate();
            //printPreviewDialog1.Document = printDocument1; // 教程里的原始代码
            //printPreviewDialog1.ShowDialog();
        }

        private void ButtonUp_Click(object sender, EventArgs e)
        {
            if (printPreviewControl1.StartPage > 0)
            {
                printPreviewControl1.StartPage--;
                printPreviewControl1.Invalidate();
            }
        }

        private void ButtonDown_Click(object sender, EventArgs e)
        {
            printPreviewControl1.StartPage++;
            printPreviewControl1.Invalidate();
        }

        private void buttonPrint_Click(object sender, EventArgs e)
        {
            string fullPath = System.IO.Path.Combine(docPath, docName);
            printDocument1.DocumentName = docName;
            stringToPrint = System.IO.File.ReadAllText(fullPath);
            printDocument1.Print();
        }

        private void printDocument1_PrintPage(object sender, PrintPageEventArgs e)
        {
            Console.WriteLine("printDocument1_PrintPage");
            int charactersOnPage = 0;
            int linesPerPage = 0;

            e.Graphics.MeasureString(stringToPrint, this.Font, e.MarginBounds.Size, StringFormat.GenericTypographic, out charactersOnPage, out linesPerPage);
            e.Graphics.DrawString(stringToPrint, this.Font, Brushes.Green, e.MarginBounds, StringFormat.GenericTypographic);

            stringToPrint = stringToPrint.Substring(charactersOnPage);
            e.HasMorePages = (stringToPrint.Length > 0);
        }

        private void ButtonSettings_Click(object sender, EventArgs e)
        {
            string printerName = printerSettings.PrinterName;
            IntPtr hPrinter = IntPtr.Zero;
            if (!OpenPrinter(printerName, out hPrinter, IntPtr.Zero)) return;

            IntPtr pDevMode = IntPtr.Zero;
            IntPtr pDevModeOut = IntPtr.Zero;
            IntPtr settingsDevMode = printerSettings.GetHdevmode();
            IntPtr pDevModeSettings = IntPtr.Zero;

            try
            {
                int sizeNeeded = DocumentProperties(IntPtr.Zero, hPrinter, printerName, IntPtr.Zero, IntPtr.Zero, 0);
                if (sizeNeeded <= 0) return;

                pDevMode = Marshal.AllocHGlobal(sizeNeeded);
                pDevModeOut = Marshal.AllocHGlobal(sizeNeeded);
                int ret = IDOK;

                if (settingsDevMode != IntPtr.Zero)
                {
                    pDevModeSettings = GlobalLock(settingsDevMode);
                }

                if (pDevModeSettings != IntPtr.Zero)
                {
                    int hDevModeSize = GlobalSize(settingsDevMode);
                    int copySize = Math.Min(sizeNeeded, hDevModeSize);
                    NativeMethods.CopyMemory(pDevMode, pDevModeSettings, copySize);
                    Console.WriteLine($"pDevMode from PrinterSettings, copySize = {copySize}, pname = {printerName}");
                }
                else
                {
                    ret = DocumentProperties(IntPtr.Zero, hPrinter, printerName, pDevMode, IntPtr.Zero, DM_OUT_BUFFER);
                    if (ret != IDOK)
                    {
                        // 原代码此处截断,保留现有逻辑
                    }
                }

                // 原代码后续处理逻辑缺失,此处省略
            }
            finally
            {
                // 资源释放逻辑
                if (hPrinter != IntPtr.Zero) ClosePrinter(hPrinter);
                if (settingsDevMode != IntPtr.Zero) GlobalUnlock(settingsDevMode);
                if (pDevMode != IntPtr.Zero) Marshal.FreeHGlobal(pDevMode);
                if (pDevModeOut != IntPtr.Zero) Marshal.FreeHGlobal(pDevModeOut);
            }
        }

        // P/Invoke常量与方法定义
        private const int IDOK = 1;
        private const int DM_OUT_BUFFER = 2;

        [DllImport("winspool.drv", CharSet = CharSet.Auto, SetLastError = true)]
        private static extern bool OpenPrinter(string szPrinter, out IntPtr hPrinter, IntPtr pd);

        [DllImport("winspool.drv", CharSet = CharSet.Auto, SetLastError = true)]
        private static extern bool ClosePrinter(IntPtr hPrinter);

        [DllImport("winspool.drv", CharSet = CharSet.Auto, SetLastError = true)]
        private static extern int DocumentProperties(IntPtr hWnd, IntPtr hPrinter, string pDeviceName, IntPtr pDevModeOutput, IntPtr pDevModeInput, int fMode);

        [DllImport("kernel32.dll", SetLastError = true)]
        private static extern IntPtr GlobalLock(IntPtr hMem);

        [DllImport("kernel32.dll", SetLastError = true)]
        private static extern bool GlobalUnlock(IntPtr hMem);

        [DllImport("kernel32.dll", SetLastError = true)]
        private static extern int GlobalSize(IntPtr hMem);

        private static class NativeMethods
        {
            [DllImport("kernel32.dll", SetLastError = true)]
            public static extern void CopyMemory(IntPtr dest, IntPtr src, int count);
        }
    }
}

内容来源于stack exchange

火山引擎 最新活动