.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




