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

时间:2016-12-08 11:26:57

标签: c# wpf winforms printing

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

enter image description here

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

enter image description here

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

我一直在使用ManagementObjectSearcher并在普通的PrintDocument.DefaultPageSettings属性中搜索但找不到任何内容!

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

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

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

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

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

提前致谢。

修改

我使用Hans的方法来确定要改变的值。请注意,他的方法适用于任何类型的打印机! devmode更改了PrintDialog的值。这花了我几个小时来解决,所以对于我可以帮助的人,这是我的代码,我很高兴分享或帮助!首先,我尝试从DefaultPrintTicket更改new PrintServer(),但UserPrintTicket似乎是正确的,您可以在其中实际看到Windows {{1}中的值更改魔术价值已经不同了。这比实际使用更具实践性。

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

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

3 个答案:

答案 0 :(得分:7)

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

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

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

Winforms直接使用PrinterSettings.GetHdevmode()方法公开DEVMODE。 WPF通过PrintTicket类抽象出来。您必须使用PrintTicketConverter class从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();
    }
}

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

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

答案 1 :(得分:1)

试试这个。 “LandscapeAngle”将返回打印对话框控件中设置的方向。

PrintDialog.PrinterSettings.LandscapeAngle

价: https://msdn.microsoft.com/en-us/library/system.drawing.printing.printersettings(v=vs.110).aspx

答案 2 :(得分:-1)

您是否尝试过Print Spooler API?

https://msdn.microsoft.com/en-us/library/windows/desktop/dd162863(v=vs.85).aspx

Pinvoke.net显示了在C#中使用dll调用的C#语法。

在C#中打开对话框的示例:

http://hintdesk.com/c-invoke-printer-properties-dialog/