C#winspool.drv调用WritePrinter不打印

时间:2015-04-03 02:14:50

标签: c# printing spool

我正在使用我在网上找到的一些代码来解决其他人的类似打印问题。代码似乎运行正常,甚至在我期望它时出错(例如,当我故意输入错误的打印机名称时)。我遇到的问题是对winspool.drv的WritePrinter方法的互操作似乎不会导致打印机打印任何内容,即使此方法返回" true"。任何想法为什么打印机实际上不打印???

public class PrintRaw
    {
        [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi)]
        public class DOC_INFO_1
        {
            [MarshalAs(UnmanagedType.LPStr)]
            public string pDocName;
            [MarshalAs(UnmanagedType.LPStr)]
            public string pOutputFile;
            [MarshalAs(UnmanagedType.LPStr)]
            public string pDataType;
        }

        [DllImport("winspool.Drv", EntryPoint = "OpenPrinterA", SetLastError = true, CharSet = CharSet.Ansi,
          ExactSpelling = true, CallingConvention = CallingConvention.StdCall)]
        public static extern bool OpenPrinter([MarshalAs(UnmanagedType.LPStr)] string szPrinter, out IntPtr hPrinter,
                                              IntPtr pd);

        [DllImport("winspool.Drv", EntryPoint = "ClosePrinter", SetLastError = true, ExactSpelling = true,
          CallingConvention = CallingConvention.StdCall)]
        public static extern bool ClosePrinter(IntPtr hPrinter);

        [DllImport("winspool.Drv", EntryPoint = "StartDocPrinterA", SetLastError = true, CharSet = CharSet.Ansi,
          ExactSpelling = true, CallingConvention = CallingConvention.StdCall)]
        public static extern bool StartDocPrinter(IntPtr hPrinter, Int32 level,
                                                  [In, MarshalAs(UnmanagedType.LPStruct)] DOC_INFO_1 di);

        [DllImport("winspool.Drv", EntryPoint = "EndDocPrinter", SetLastError = true, ExactSpelling = true,
          CallingConvention = CallingConvention.StdCall)]
        public static extern bool EndDocPrinter(IntPtr hPrinter);

        [DllImport("winspool.Drv", EntryPoint = "StartPagePrinter", SetLastError = true, ExactSpelling = true,
          CallingConvention = CallingConvention.StdCall)]
        public static extern bool StartPagePrinter(IntPtr hPrinter);

        [DllImport("winspool.Drv", EntryPoint = "EndPagePrinter", SetLastError = true, ExactSpelling = true,
          CallingConvention = CallingConvention.StdCall)]
        public static extern bool EndPagePrinter(IntPtr hPrinter);

        [DllImport("winspool.Drv", EntryPoint = "WritePrinter", SetLastError = true, ExactSpelling = true,
          CallingConvention = CallingConvention.StdCall)]
        public static extern bool WritePrinter(IntPtr hPrinter, IntPtr pBytes, Int32 dwCount, out Int32 dwWritten);

        public void Print(String printerName, String filename)
        {
            IntPtr lhPrinter;
            OpenPrinter(printerName, out lhPrinter, new IntPtr(0));

            if (lhPrinter.ToInt32() == 0)
                return; //Printer not found!!

            var rawPrinter = new DOC_INFO_1() { pDocName = "My Document", pDataType = "RAW" };

            StartDocPrinter(lhPrinter, 1, rawPrinter);

            using (var b = new BinaryReader(File.Open(filename, FileMode.Open)))
            {
                var length = (int)b.BaseStream.Length;
                const int bufferSize = 8192;

                var numLoops = length / bufferSize;
                var leftOver = length % bufferSize;


                for (int i = 0; i < numLoops; i++)
                {
                    var buffer = new byte[bufferSize];
                    int dwWritten;

                    b.Read(buffer, 0, bufferSize);
                    IntPtr unmanagedPointer = Marshal.AllocHGlobal(buffer.Length);
                    Marshal.Copy(buffer, 0, unmanagedPointer, buffer.Length);
                    WritePrinter(lhPrinter, unmanagedPointer, bufferSize, out dwWritten);
                    Marshal.FreeHGlobal(unmanagedPointer);
                }

                if (leftOver > 0)
                {
                    var buffer = new byte[leftOver];
                    int dwWritten;

                    b.Read(buffer, 0, leftOver);
                    IntPtr unmanagedPointer = Marshal.AllocHGlobal(buffer.Length);
                    Marshal.Copy(buffer, 0, unmanagedPointer, buffer.Length);
                    var result = WritePrinter(lhPrinter, unmanagedPointer, leftOver, out dwWritten);
                    Marshal.FreeHGlobal(unmanagedPointer);
                }
            }

            EndDocPrinter(lhPrinter);
            ClosePrinter(lhPrinter);
        }
    }

5 个答案:

答案 0 :(得分:1)

就我而言,我发现解决方案更改了 pDataType

对于Win7,使用 RAW

对于Win8 +,请使用 XPS_PASS

示例:

// SendBytesToPrinter()
// When the function is given a printer name and an unmanaged array
// of bytes, the function sends those bytes to the print queue.
// Returns true on success, false on failure.
private static bool SendBytesToPrinter(string szPrinterName, IntPtr pBytes, Int32 dwCount)
{
    bool bSuccess = false; // Assume failure unless you specifically succeed.
    try
    {
        Int32 dwError = 0, dwWritten = 0;
        IntPtr hPrinter = new IntPtr(0);
        DOCINFOA di = new DOCINFOA();

        di.pDocName = "RAW Document";
        // Win7
        //di.pDataType = "RAW";

        // Win8+
        di.pDataType = "XPS_PASS";

        // Open the printer.
        if (OpenPrinter(szPrinterName.Normalize(), out hPrinter, IntPtr.Zero))
        {
            // Start a document.
            if (StartDocPrinter(hPrinter, 1, di))
            {
                // Start a page.
                if (StartPagePrinter(hPrinter))
                {
                    // Write your bytes.
                    bSuccess = WritePrinter(hPrinter, pBytes, dwCount, out dwWritten);
                    EndPagePrinter(hPrinter);
                }
                EndDocPrinter(hPrinter);
            }
            ClosePrinter(hPrinter);
        }
        // If you did not succeed, GetLastError may give more information
        // about why not.
        if (!bSuccess)
        {
            dwError = Marshal.GetLastWin32Error();
        }
    }
    catch { }
    return bSuccess;
}

答案 1 :(得分:0)

更改您的代码:

 var rawPrinter = new DOC_INFO_1() { pDocName = "My Document", pDataType = "Text" };

答案 2 :(得分:0)

您需要在StartDocPrinter之后和WritePrinter

之前调用StartPagePrinter

答案 3 :(得分:0)

[DllImport("winspool.drv", EntryPoint = "FlushPrinter", SetLastError = true, CharSet = CharSet.Ansi, ExactSpelling = true, CallingConvention = CallingConvention.StdCall)]
public static extern bool FlushPrinter(IntPtr hPrinter, IntPtr pBuf, Int32 cbBuf, out Int32 pcWritten, Int32 cSleep);

WritePrinter(lhPrinter, unmanagedPointer, bufferSize, out dwWritten);

添加后:

FlushPrinter(hPrinter, pBytes, dwCount, out dwWritten,2);

答案 4 :(得分:0)

Zebra ZPL打印机

我在Window 10中遇到了同样的问题,并更新了以下设置以使其正常工作:

将突出显示的状态(请参见下图)从“未配置”更改为“禁用”

Image Local Group Policy Editor