Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/.net/20.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 原始打印设置DevMode选项(方向、副本、边距、默认源等)_C#_.net_Windows_Winapi_Printing - Fatal编程技术网

C# 原始打印设置DevMode选项(方向、副本、边距、默认源等)

C# 原始打印设置DevMode选项(方向、副本、边距、默认源等),c#,.net,windows,winapi,printing,C#,.net,Windows,Winapi,Printing,希望这里有人能帮我,因为我正试图让这一切顺利进行。基本上,我需要使用winspool.Drv win32 API打印,以将原始文本/PCL命令发送到打印机。这很好,但是,您在“打印机”对话框/首选项中选择的打印机选项都不起作用 最终,我想从对话框PrinterSettings中获取DEVMODE,并将其用于原始打印,但我甚至无法手动设置它 在WritePrinter之前,或者在单独的打开/关闭打印机中,我尝试过更改DEVMODE,我尝试过仅使用DocumentProperties调用,并且使用带

希望这里有人能帮我,因为我正试图让这一切顺利进行。基本上,我需要使用winspool.Drv win32 API打印,以将原始文本/PCL命令发送到打印机。这很好,但是,您在“打印机”对话框/首选项中选择的打印机选项都不起作用

最终,我想从对话框PrinterSettings中获取DEVMODE,并将其用于原始打印,但我甚至无法手动设置它

在WritePrinter之前,或者在单独的打开/关闭打印机中,我尝试过更改DEVMODE,我尝试过仅使用DocumentProperties调用,并且使用带有printer_INFO_8结构的GetPrinter/SetPrinter,没有任何东西粘住。DEVMODE结构似乎填写正确,我对其进行了更改,而且似乎更改正确,但无论发生什么情况,打印机总是以相同的方式打印

以下是我一直使用的代码:

方法1:

public static bool SetPrinterSettings(PrinterSettings settings, IntPtr hPrinter)
{
    IntPtr hDevMode; // a handle to our current DEVMODE
    IntPtr pDevMode; // a pointer to our current DEVMODE
    String sPrinterName; // normalized printer name
    DEVMODE dm;

    // Setup
    sPrinterName = settings.PrinterName.Normalize();

    // Obtain the current DEVMODE from the PrinterSettings
    hDevMode = settings.GetHdevmode(settings.DefaultPageSettings);

    // Obtain a lock on the handle and get an actual pointer so Windows won't move
    // it around while we're futzing with it
    pDevMode = GlobalLock(hDevMode);

    // test
    dm = (DEVMODE)Marshal.PtrToStructure(pDevMode, typeof(DEVMODE));

    // Our DEVMODE is 188 bytes, but dmSize returns 220, does this matter?
    // This code doesnt seem to work
    //dm.dmSize = (short)Marshal.SizeOf(dm); // Set size to our implementation of DevMode
    //int isize = GlobalSize(pDevMode).ToInt32() - (int)dm.dmSize; // Set the print drivers extra size
    //dm.dmDriverExtra = Convert.ToInt16(isize);

    // Change things
    dm.dmFields = DM_FIELD_TYPE.DM_ORIENTATION;
    dm.dmOrientation = 2;

    // Load the structure back into the buffer
    Marshal.StructureToPtr(dm, pDevMode, true);

    //Tell the printer about the new property
    int ret = DocumentProperties(IntPtr.Zero, hPrinter, sPrinterName, pDevMode, pDevMode, (DM_IN_BUFFER | DM_OUT_BUFFER));

    if (ret <= 0)
    {
        return false;
    }



    // We're done futzing
    GlobalUnlock(hDevMode);

    // Tell our printer settings to use the one we just overwrote
    //settings.SetHdevmode(hDevMode);

    // It's copied to our printer settings, so we can free the OS-level one
    GlobalFree(hDevMode);

    //test
    dm = (DEVMODE)Marshal.PtrToStructure(pDevMode, typeof(DEVMODE));

    // ^^ this contains correct orientation

    return true;
}
测试打印的代码:

private void testPrint_Click(object sender, EventArgs e)
{
    IntPtr hPrinter;

    if (printDialog1.ShowDialog() == System.Windows.Forms.DialogResult.OK)
    {
        hPrinter = RawPrint.OpenRAWPrinter(printDialog1.PrinterSettings.PrinterName);

        if (hPrinter == IntPtr.Zero)
        {
            MessageBox.Show("Error opening printer");
            return;
        }

        if (!RawPrint.StartRAWDocument(hPrinter, "Test document"))
        {
            MessageBox.Show("Error starting raw document");
            RawPrint.CloseRAWPrinter(hPrinter);
            return;
        }

        // Start a page.
        if (RawPrint.StartRawPage(hPrinter))
        {
            // Set the printers settings
            //if (!RawPrint.SetPrinterSettings(printDialog1.PrinterSettings, hPrinter))
            if(!RawPrint.SetLandscapeMode(printDialog1.PrinterSettings, hPrinter))
            {
                MessageBox.Show("Error setting printer settings");
                RawPrint.CloseRAWPrinter(hPrinter);
                return;
            }

            String test = "This is \r\n test print data";
            byte[] buf = Encoding.Default.GetBytes(test);

            GCHandle gch = GCHandle.Alloc(buf, GCHandleType.Pinned);
            RawPrint.writeRAW(hPrinter, gch.AddrOfPinnedObject(), buf.Length);
            gch.Free();

            RawPrint.EndRawPage(hPrinter);
        }

        RawPrint.EndRAWDocument(hPrinter);
        RawPrint.CloseRAWPrinter(hPrinter);
    }
    else
    {
        MessageBox.Show("Error starting raw page");
    }
}
唯一奇怪的是Marshal.SizeOf(typeof(DEVMODE))或Marshal.SizeOf(dm)等于188,而返回到结构中的dmSize是220。我试着修改这个dmSize以匹配我们的结构,如注释掉的代码所示,但这似乎是错误的或不起作用,不确定这是否重要

此外,DevModes中返回的信息似乎都是正确的和有效的。我可以在“打印”对话框中设置选项,并在PrinterSettings devmode中查看它们的更改。在这些函数结束时,将pDevMode编组回结构会更改设置

然而,所有这些似乎都不会对印刷品产生任何影响。我有什么遗漏吗


编辑:测试函数中的RawPrint调用只是围绕后台处理程序api调用的包装。页面打印效果很好,只是始终以纵向模式打印,没有任何选项可用。

您应该正常启动打印作业,并使用ExtEscape()和escape注入PCL,而不是使用WritePrinter绕过打印机驱动程序。这将允许所有PrinterSettings值应用于作业。并非所有打印机驱动程序都支持PASSTHROUGH,但您可以使用调用ExtEscape()检查驱动程序支持。

您应该正常启动打印作业,并使用ExtEscape()和escape注入PCL,而不是使用WritePrinter绕过打印机驱动程序。这将允许所有PrinterSettings值应用于作业。并非所有的打印机驱动程序都支持PASSTHROUGH,但是您可以通过调用ExtEscape()来检查驱动程序支持。

您正在给自己挖一个很大的洞。DEVMODE是一个讨厌的结构,它是可变长度的,在打印机驱动程序存储自己配置的末尾填充了额外的字节。如果您确实在使用原始打印机输出、OpenPrinter等,那么更改DEVMODE将不会产生任何效果,您将绕过打印机驱动程序。然后完全由您来旋转输出。如果打印机本身不支持它,那将非常痛苦。绕过驱动程序是有意义的。是的,我意识到在DEVMODE的末尾有额外的驱动程序信息,但是代码可以处理,或者应该处理。尽管你说的很有道理,因为这是经过司机的。没有办法使用spool api(WritePrinter)并设置其中一些选项,例如横向模式或输出托盘(我知道是特定于驱动程序的)。是否需要在PCL代码中手动执行此操作,或者是否有更简单的方法在使用驱动程序时将PCL发送到打印机?是。生成正确PCL的一个非常简单的方法是不绕过驱动程序。@HansPassant所说的,如果你想要正确的PCL,就不要绕过驱动程序。如果您需要修改生成的PCL,您需要一个端口监视器或语言监视器。@HansPassant:hmm,是否有办法捕获所选对话框选项的PCL,并在我需要发送的常规PCL之前输出它?似乎应该有一个简单的解决方案:(.或以某种方式使用驱动程序,但仍然发送自定义命令。你正在给自己挖一个相当大的洞。DEVMODE是一个讨厌的结构,它是可变长度的,在打印机驱动程序存储自己配置的末尾填充了额外的字节。如果你真的使用原始打印机输出、OpenPrinter等,那么更改DEVMODE将不会有任何效果t、 你正在绕过打印机驱动程序。然后轮换输出完全取决于你。如果打印机本身不支持它,那将是相当痛苦的。绕过驱动程序是有意义的。是的,我意识到在DEVMODE末尾有额外的驱动程序信息,但代码可以处理,或者应该处理。尽管你所做的是有意义的因为这是通过传递驱动程序来实现的。是否无法使用spool api(WritePrinter)并设置其中一些选项,例如横向模式或输出托盘(我知道特定于驱动程序)。这是否需要在PCL代码中手动完成,或者在使用驱动程序时是否有更简单的方法将PCL发送到打印机?是的。生成正确PCL的一个非常简单的方法是不绕过驱动程序。如果需要正确的PCL,@HansPassant所说的不绕过驱动程序。如果需要修改生成的PCL,则需要端口监视器或者语言监视器。@HansPassant:hmm,有没有办法捕获所选对话框选项的PCL,并在我需要发送的常规PCL之前输出它?似乎应该有一个简单的解决方案:(.或以某种方式使用驱动程序,但仍发送自定义命令。谢谢,我会研究这些。当然,这对某些打印机有效,但并非所有打印机都有效,正如您所指出的。而且它不会阻止打印驱动程序生成其正常输出,所以您所能做的就是将其注入到中间。您不能使用
PASSTHROUGH .这是一种80年代的解决方案
private void testPrint_Click(object sender, EventArgs e)
{
    IntPtr hPrinter;

    if (printDialog1.ShowDialog() == System.Windows.Forms.DialogResult.OK)
    {
        hPrinter = RawPrint.OpenRAWPrinter(printDialog1.PrinterSettings.PrinterName);

        if (hPrinter == IntPtr.Zero)
        {
            MessageBox.Show("Error opening printer");
            return;
        }

        if (!RawPrint.StartRAWDocument(hPrinter, "Test document"))
        {
            MessageBox.Show("Error starting raw document");
            RawPrint.CloseRAWPrinter(hPrinter);
            return;
        }

        // Start a page.
        if (RawPrint.StartRawPage(hPrinter))
        {
            // Set the printers settings
            //if (!RawPrint.SetPrinterSettings(printDialog1.PrinterSettings, hPrinter))
            if(!RawPrint.SetLandscapeMode(printDialog1.PrinterSettings, hPrinter))
            {
                MessageBox.Show("Error setting printer settings");
                RawPrint.CloseRAWPrinter(hPrinter);
                return;
            }

            String test = "This is \r\n test print data";
            byte[] buf = Encoding.Default.GetBytes(test);

            GCHandle gch = GCHandle.Alloc(buf, GCHandleType.Pinned);
            RawPrint.writeRAW(hPrinter, gch.AddrOfPinnedObject(), buf.Length);
            gch.Free();

            RawPrint.EndRawPage(hPrinter);
        }

        RawPrint.EndRAWDocument(hPrinter);
        RawPrint.CloseRAWPrinter(hPrinter);
    }
    else
    {
        MessageBox.Show("Error starting raw page");
    }
}