2

I want to send raw data to print, avoiding printer selection (fast print).

I am trying to use this helper provided by Microsoft: https://support.microsoft.com/en-us/kb/322091#top

However, when I call to the method:

RawPrinterHelper.SendStringToPrinter(pd.PrinterSettings.PrinterName, s);

My printer starts to works (makes some noise) but It never takes the white paper and starts to print.

I have tried it with my two printers and the behavior is the same in both printers. Also I discard the possibility that the printers are broken because I can print other documents.

What can be wrong?

Brian Tompsett - 汤莱恩
  • 5,753
  • 72
  • 57
  • 129
Fran_gg7
  • 717
  • 3
  • 13
  • 30
  • 1
    What type of document are you trying to print? – Tjaart van der Walt Apr 10 '15 at 14:22
  • I have edited your title. Please see, "[Should questions include “tags” in their titles?](http://meta.stackexchange.com/questions/19190/)", where the consensus is "no, they should not". – John Saunders Apr 10 '15 at 14:24
  • Are you using the same code in the MS article you referenced? – IndieTech Solutions Apr 10 '15 at 14:29
  • What are you trying to accomplish, and what are you sending? Modern printers aren't devices that just start outputting things you send them, they speak certain languages. If you don't speak the language, they certainly won't output anything. – Sami Kuhmonen Apr 10 '15 at 14:49

5 Answers5

5

Try this:

using System;
using System.Drawing;
using System.Drawing.Printing;
using System.IO;
using System.Runtime.InteropServices;
using System.Windows.Forms;

public class RawPrinterHelper
{
  // Structure and API declarions:
  [StructLayout(LayoutKind.Sequential, CharSet=CharSet.Ansi)]
  public class DOCINFOA
  {
    [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)] DOCINFOA 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 );

  // 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.
  public static bool SendBytesToPrinter( string szPrinterName, IntPtr pBytes, Int32 dwCount)
  {
    Int32    dwError = 0, dwWritten = 0;
    IntPtr    hPrinter = new IntPtr(0);
    DOCINFOA    di = new DOCINFOA();
    bool    bSuccess = false; // Assume failure unless you specifically succeed.
    di.pDocName = "My C#.NET RAW Document";
    di.pDataType = "RAW";

    // 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 == false )
    {
      dwError = Marshal.GetLastWin32Error();
    }
    return bSuccess;
  }

  public static bool SendFileToPrinter( string szPrinterName, string szFileName )
  {
    // Open the file.
    FileStream fs = new FileStream(szFileName, FileMode.Open);
    // Create a BinaryReader on the file.
    BinaryReader br = new BinaryReader(fs);
    // Dim an array of bytes big enough to hold the file's contents.
    Byte []bytes = new Byte[fs.Length];
    bool bSuccess = false;
    // Your unmanaged pointer.
    IntPtr pUnmanagedBytes = new IntPtr(0);
    int nLength;

    nLength = Convert.ToInt32(fs.Length);
    // Read the contents of the file into the array.
    bytes = br.ReadBytes( nLength );
    // Allocate some unmanaged memory for those bytes.
    pUnmanagedBytes = Marshal.AllocCoTaskMem(nLength);
    // Copy the managed byte array into the unmanaged array.
    Marshal.Copy(bytes, 0, pUnmanagedBytes, nLength);
    // Send the unmanaged bytes to the printer.
    bSuccess = SendBytesToPrinter(szPrinterName, pUnmanagedBytes, nLength);
    // Free the unmanaged memory that you allocated earlier.
    Marshal.FreeCoTaskMem(pUnmanagedBytes);
    return bSuccess;
  }

  public static bool SendStringToPrinter( string szPrinterName, string szString )
  {
    IntPtr pBytes;
    Int32 dwCount;

    // How many characters are in the string?
    // Fix from Nicholas Piasecki:
    // dwCount = szString.Length;
    dwCount = (szString.Length + 1) * Marshal.SystemMaxDBCSCharSize;

    // Assume that the printer is expecting ANSI text, and then convert
    // the string to ANSI text.
    pBytes = Marshal.StringToCoTaskMemAnsi(szString);
    // Send the converted ANSI string to the printer.
    SendBytesToPrinter(szPrinterName, pBytes, dwCount);
    Marshal.FreeCoTaskMem(pBytes);
    return true;
  }
}
IndieTech Solutions
  • 2,527
  • 1
  • 21
  • 36
3

Fran_gg7, I had the same issue recently. Firstly, turn on the persistence of documents on the printer. This will allow you to see if the printer successfully received the print request.

enter image description here

You will see items in the printer queue and they will remain there.

In my scenario the print request was correctly being sent to the printer, however I was testing it on a laser printer that ultimately was unable to interpret the raw string data I was passing to it.

I tested the same output on a label printer that could understand the ZPL (zebra programming language) I was passing it and boom it worked fine.

Have a look at this for a detailed explanation

Hope this helps.

Community
  • 1
  • 1
DotNetHitMan
  • 931
  • 8
  • 20
  • Thank you for your reply DotNetHitMan, and my printers are laser printers too. However, I'm not sure about the type of printer the final customer will use. So...what can I do? – Fran_gg7 Apr 13 '15 at 07:39
  • @Fran_gg7, what sort of data are you trying to print? Generally the only reason you want to send 'RAW' data directly to a printer will be because that printer's driver can interpret the RAW data. For example a label printer with its own native language. – DotNetHitMan Apr 13 '15 at 15:20
  • 2
    Finally it works changing this line: di.pDataType = "TEXT"; Changing "RAW" per "TEXT" it works!! For easy understanding about how does the brokered components work I really recommend to read this article http://blogs.u2u.be/diederik/post/2014/04/25/Building-Enterprise-apps-using-Brokered-Windows-Runtime-Components.aspx – Fran_gg7 Apr 14 '15 at 10:21
  • Thanks a million @Fran_gg7 that did it for me, working with an Oki Microline 280 Elite. – epalm Apr 18 '18 at 10:01
  • 1
    @DotNetHitMan your are master blamaster – Dgan Oct 12 '18 at 07:32
1

In cases where you are using the MSDN example from here https://support.microsoft.com/en-us/kb/322091#top but are trying to use an array of bytes instead of a string or file... This may help

public static void SendBytesToLocalPrinter(byte[] data, string printerName)
{
   var size = Marshal.SizeOf(data[0]) * data.Length;
   var pBytes = Marshal.AllocHGlobal(size);
   try
   {
      SendBytesToPrinter(printerName, pBytes, size);
   }
   finally
   {
      Marshal.FreeCoTaskMem(pBytes);
   }
}

This does not change with the byte array encoding. This is useful if you are trying to send some utf8 encoded byte sequences with some binary (ie. image) data mixed in as was the case for our team.

Mike1234
  • 139
  • 1
  • 4
0

If printing plain text to Dot Matrix using "RawPrinterHelper" Method, it would only work properly for me when I manually added a printer, selected Generic / Text Only, and selected the USB001 port that was assigned to my USB connected printer (okidata in my test). Then RawPrinterHelper.SendStringToPrinter would behave very much like an 'lpd to lpt1:'

waitman
  • 33
  • 6
0

Had exactly the same issue with my ZEBRA ZD420 printer. Sending ZPL string to printer only the data light flashing shortly without printing.

I changed only

Marshal.StringToCoTaskMemAnsi(szString);
to 
Marshal.StringToCoTaskMemUTF8(szString);

and it works !

Kevin V
  • 129
  • 2
  • 9