在C#中控制或访问打印机的自定义打印机设置(旋转180度)

Mar*_*son 8 c# printing wpf winforms

我有多个打印机,其中包含"旋转180度"复选框,如下所示:

在此输入图像描述

这是另一个("倪"的意思是"不"):

在此输入图像描述

有没有办法以编程方式设置此值,并更改PrintTicket?如果没有,我怎样才能得到它的当前值?对于我的软件,我需要知道是否已设置,如果已设置,则需要更改,如果可能的话.对于我的软件来说,如果我不必打开printdialog就是最好的,它是一个软件,用户可以直接打印而无需点击任何按钮,因此设置或获取它是我正在寻找的.

我一直在寻找使用ManagementObjectSearcher和在正常的PrintDocument.DefaultPageSettings财产,但找不到任何东西!

如果未设置此选项,我会自动为用户临时设置它(否则它将使用我的特定打印机进行颠倒打印).我一直在努力为用户设置它,但我无法弄清楚如何让它工作.我一直在研究DEVMODE结构并尝试实现它,但它也没有"旋转180度选项"或任何类似的东西.

注意:我不打算设置风景模式.这很简单,也有所不同.

我尝试过以下操作: pdialog.PrintQueue.CurrentJobSettings.CurrentPrintTicket.PageOrientation = PageOrientation.ReversePortrait;

但是,这只会反转页面方向而不是内容(内容也需要旋转).

如果我旋转我正在打印的视觉效果,则边距不再正确,因此也不起作用!希望有人能提供帮助.

提前致谢.

编辑

我用Hans的方法找出要改变的值.请注意,他的方法适用于任何类型的打印机!该devmode变化的值PrintDialog.这花了我几个小时来解决,所以对于我可以帮助的人,这是我的代码,我很高兴分享或帮助!首先,我试图改变DefaultPrintTicket一个new PrintServer()不起作用,但UserPrintTicket似乎是正确的,你可以真正看到Windows Control Panel if you don't switch back to the original one. *However*, this only seemed to work on just my pc (which was necessary), on a virtual machine for example the魔术价值的价值变化已经不同了.这比实际使用更具实践性.

var pdialog = new PrintDialog();

pdialog.PrintQueue = new PrintQueue(new LocalPrintServer(), _printername, PrintSystemDesiredAccess.AdministratePrinter); // this will be your printer. any of these: new PrintServer().GetPrintQueues()

pdialog.PrintTicket.PageMediaSize = size;
pdialog.PrintTicket.CopyCount = _amount;

if (CheckPrinterDriverName(_printername))
{
    int magic = 361;
    var defaulttckt = pdialog.PrintQueue.UserPrintTicket;
    pdialog.PrintQueue.UserPrintTicket = PrinterModifier.ChangeDevMode(pdialog, magic, vis);
    pdialog.PrintQueue.Commit();
    pdialog.PrintVisual(vis, "Label");
    //Set back old settings so it's not permanently changed
    pdialog.PrintQueue.UserPrintTicket = defaulttckt;
    pdialog.PrintQueue.Commit();
}
Run Code Online (Sandbox Code Playgroud)

...

class PrinterModifier
{
    public static PrintTicket ChangeDevMode(PrintDialog pdialog, int prpty, DrawingVisual vis)
    {
        var queue = pdialog.PrintQueue;
        var cvt = new PrintTicketConverter(queue.Name, PrintTicketConverter.MaxPrintSchemaVersion);
        // Display dialog, don't make changes

        var devmode1 = cvt.ConvertPrintTicketToDevMode(pdialog.PrintTicket, BaseDevModeType.UserDefault);
        // Consistency check
        var dmSize = BitConverter.ToInt16(devmode1, 68);
        var dmDriverExtra = BitConverter.ToInt16(devmode1, 70);

        if (devmode1[361] == 0)
        {
            devmode1[361] = 1;
        }
        return cvt.ConvertDevModeToPrintTicket(devmode1, PrintTicketScope.PageScope);
    }
}
Run Code Online (Sandbox Code Playgroud)

printdialog中的值发生了变化,但仍然打印错误.这些更改不适用.欢迎任何帮助!

Han*_*ant 7

它可能有助于实现这个属性的异常程度.有趣的真实故事是关于Pete Conrad的介绍,Pete Conrad是由NASA为双子座太空计划招募的宇航员.由于没有真正了解长期太空飞行如何影响人类,医生们基本上将他们暴露在他们能想到的任何事物中.经常非常干扰和不舒服的测试.康拉德反叛并失败了一次心理测验.医生递给他一张空白卡片,问"你看到了什么?" 他立即将它推回去并评论说"这是颠倒的".

这台打印机很不寻常,总是值得担心.也许设计用于在包括某种自动纸张装订操作的生产线上操作.打印机驱动程序可以随意添加属性来自定义它们的行为,这就是一个这样的属性.您正在查看的属性表同样是非标准的,它来自打印机驱动程序.

要了解如何更改此设置,首先需要了解DEVMODE结构.关于winapi中使用的最丑陋的结构.它是一个可变大小的结构,您在MSDN页面中看到的声明仅涵盖标准属性.打印机驱动程序可以任意扩展它,该dmDriverExtra字段记录添加了多少额外字节.该dmSize字段报告结构的非变量部分的大小,在Windows版本6(Vista及更高版本)上为220.你需要检查的东西.

Winforms直接使用PrinterSettings.GetHdevmode()方法公开DEVMODE.WPF通过PrintTicket类抽象出来.您必须使用PrintTicketConverter类将PrintTicket转换为DEVMODE并返回.

您需要进行逆向工程的是存储此设置的专用驱动程序数据中的确切字段.只有打印机制造商知道这个细节,他们才会接听您的电话.一些示例代码可帮助您发现并验证该字段,只需在MainWindow构造函数中的无操作WPF应用程序中尝试:

using System.Printing;          // Add reference to System.Printing
using System.Printing.Interop;  // Add reference to ReachFramework
using System.Diagnostics;
....

    public MainWindow() {
        InitializeComponent();
        // Assume default printer
        var queue = new LocalPrintServer().DefaultPrintQueue;
        var cvt = new PrintTicketConverter(queue.Name, PrintTicketConverter.MaxPrintSchemaVersion);
        // Display dialog, don't make changes
        var dlg = new PrintDialog();
        dlg.ShowDialog();
        var devmode1 = cvt.ConvertPrintTicketToDevMode(dlg.PrintTicket, BaseDevModeType.UserDefault);
        // Consistency check
        var dmSize = BitConverter.ToInt16(devmode1, 68);
        var dmDriverExtra = BitConverter.ToInt16(devmode1, 70);
        Debug.Assert(dmSize == 220);
        Debug.Assert(dmDriverExtra > 0);
        Debug.Assert(dmSize + dmDriverExtra == devmode1.Length);
        // Display dialog again, do make the change
        dlg.ShowDialog();
        var devmode2 = cvt.ConvertPrintTicketToDevMode(dlg.PrintTicket, BaseDevModeType.UserDefault);
        var len = Math.Min(devmode1.Length, devmode2.Length);
        for (int ix = 0; ix < len; ++ix) {
            if (devmode1[ix] != devmode2[ix]) {
                Debug.Print("Change at {0} from {1} to {2}", ix, devmode1[ix], devmode2[ix]);
            }
        }
        // Tinker with the DEVMODE...
        var magic = dmSize + 0;   // Change this
        Debug.Assert(magic < dmSize + dmDriverExtra);
        devmode1[magic] = devmode2[magic];
        dlg.PrintTicket = cvt.ConvertDevModeToPrintTicket(devmode1);
        // Verify that the setting changed!
        dlg.ShowDialog();
    }
}
Run Code Online (Sandbox Code Playgroud)

请注意,您可能会看到许多字节更改.最有可能的猜测是你正在寻找一个从0变为1的调试.调试> Windows>内存>内存1窗口可用于过滤字符串产生的噪音,将"devmode2"放在地址字段中.

预期的结果是您现在知道如何自定义PrintTicket.请注意,它非常特定于该打印机,并且可以通过驱动程序更新进行更改.因此,您可以考虑以最合理的方式执行此操作,使用LayoutTransform属性旋转要打印的视觉效果.