添加链接
link之家
链接快照平台
  • 输入网页链接,自动生成快照
  • 标签化管理网页链接
Collectives™ on Stack Overflow

Find centralized, trusted content and collaborate around the technologies you use most.

Learn more about Collectives

Teams

Q&A for work

Connect and share knowledge within a single location that is structured and easy to search.

Learn more about Teams

I'm using some code I found online which was a solution to someone else's similar printing problem. The code appears to run fine, and even errors out when I would expect it to (for example, when I purposefully enter in a bad printer name). The problem I'm having is that the interop call to winspool.drv's WritePrinter method does not seem to cause the printer to print anything, even though this method returns "true". Any ideas why the printer isn't actually printing???

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);
                The calls seem to be invoked, and it even returns a handle to the printer when I give it a real printer name, so I don't think that is the problem. As I mentioned in the question, it even fails when I give it a bad printer name. Plus the majority of that code is from MSDN itself
– spoof3r
                Apr 3, 2015 at 13:54
                In case anyone is wondering, code is taken from the link below I believe: vishalsbsinha.wordpress.com/2014/05/06/…
– slayernoah
                Apr 28, 2016 at 15:37
// 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.
        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;
                This worked for me in Windows 10! Thanks. But could you explain why we need to use XPS_PASS instead of RAW or how did you bumped on it?
– Noble
                Apr 21, 2021 at 21:38
                I don't really know much about it but this is what I found.  Use "XPS_PASS" when the data buffer should bypass the print filter pipeline of the XPSDrv printer driver. This datatype would be used to send the buffer directly to the printer, such as when sending print head alignment commands. Normally, a data buffer would be sent as the "RAW" datatype.
– Josue Barrios
                May 27, 2021 at 14:56
[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);

after add:

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

Zebra ZPL printer

I had the same issue with Window 10 and updated the following setting to make it work:

Changed highlighted State (Please see below images) from “Not configured” to “Disabled”

We ran into an issue with the WritePrinter pinvoke call succeeding but no physical print happening and also no print job making it into the windows print queue. This call was returning true for success and the number of bytes written was matching the number of bytes that needed to be written.

Solution:

Our problem turned out to be permissions related even though none of the pinvoke calls were failing. We had to grant read/write access for the user issuing the request to the following folder before this would work:
  • C:\Windows\System32\spool\PRINTERS
  • This request was being made by a windows service also for us.

    Thanks for contributing an answer to Stack Overflow!

    • Please be sure to answer the question. Provide details and share your research!

    But avoid

    • Asking for help, clarification, or responding to other answers.
    • Making statements based on opinion; back them up with references or personal experience.

    To learn more, see our tips on writing great answers.