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

qpgpyjmq  于 2022-12-14  发布在  C#
关注(0)|答案(4)|浏览(267)

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

下面是另一个例子(“Nee”的意思是“不”):

有没有方法可以通过编程设置这个值,并更改PrintTicket?如果没有,我怎么才能得到它的当前值?对于我的软件,我需要知道它是否被设置,如果它被设置,它需要被更改,如果可能的话。对于我的软件,如果我不需要打开printdialog,这将是最好的。这是一个软件,用户可以直接打印,而不需要点击任何按钮,所以设置或获得它的编程是我所寻找的。
我一直在使用ManagementObjectSearcher和在正常的PrintDocument.DefaultPageSettings属性中搜索,但什么都找不到!
如果没有设置这个选项,我会自动为用户临时设置它(否则它会在我的特定打印机上打印颠倒)。我一直在为用户设置它,但我不知道如何让它工作。我一直在研究DEVMODE结构体,并试图实现它,但它也没有“旋转180度选项”或类似的东西。

**注意:我并不想设置景观模式。**这很简单,而且有些不同。

我尝试执行以下操作:pdialog.PrintQueue.CurrentJobSettings.CurrentPrintTicket.PageOrientation = PageOrientation.ReversePortrait;
但是,这只会反转页面方向,而不会反转内容(内容也需要旋转)。
如果我旋转我正在打印的视觉效果,边距不再正确,所以也不起作用!希望有人能帮助。
先谢谢你。

编辑

我用Hans的方法找出要更改的值。请注意,他的方法适用于任何类型的打印机!devmode更改PrintDialog的值。这花了我很多时间来解决,所以我可以帮助任何人,这是我的代码,我很高兴与大家分享或提供帮助!首先,我试图将new PrintServer()更改为DefaultPrintTicket,但没有成功,但是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();
}

...

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

打印对话框中的值改变了,但是打印仍然错误。改变不适用。欢迎任何帮助!

33qvvth1

33qvvth11#

这可能有助于认识到这种性质是多么不寻常。有趣的真实故事作为介绍皮特康拉德,宇航员招募的美国宇航局为双子座太空计划。没有真正的想法如何长期太空飞行影响人类,医生让他们接触基本上他们能想到的任何东西。通常是非常侵入性和不舒服的测试。康拉德反抗,一次心理测试失败。医生递给他一张空白卡片,问“你看到了什么?”他立即把卡片推回去,说“它是颠倒的”。
这台打印机很不寻常,总是要担心的。可能是设计在包含某种自动纸张装订作业的生产线上操作。打印机驱动程序可以任意添加属性来自定义它们的行为,这就是一个这样的属性。您正在查看的属性表同样是非标准的,它来自打印机驱动程序。
要了解如何更改此设置,首先需要了解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的变化。Debug〉Windows〉Memory〉Memory1窗口可以用来过滤字符串产生的噪音,将“devmode2”放入Address字段。
预期的结果是您现在知道如何自定义PrintTicket。请注意,它是高度特定于该打印机的,并且可以随驱动程序更新而更改。因此,您可以考虑以最合理的方式来完成此操作,即旋转要用LayoutTransform property打印的视觉对象。

vsnjm48y

vsnjm48y2#

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

PrintDialog.PrinterSettings.LandscapeAngle

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

vhipe2zx

vhipe2zx3#

打印任何方向。这解决了我的问题
私有void打印页面(对象发送方,打印页面事件参数ev){

Metafile pageImage = new
           Metafile(m_streams[m_currentPageIndex]);            
             pageImage.Save("Test.emf");                
        var img = System.Drawing.Image.FromFile("Test.emf");
        img.RotateFlip(RotateFlipType.Rotate90FlipNone);          
        ev.Graphics.DrawImage(img, ev.PageBounds);                
        m_currentPageIndex++;
        ev.HasMorePages = (m_currentPageIndex < m_streams.Count);
    }
xxe27gdn

xxe27gdn4#

您是否尝试过后台打印程序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/

相关问题