Click here to Skip to main content
15,886,825 members
Please Sign up or sign in to vote.
3.75/5 (4 votes)
See more:
Hi,

I want to get toner and pages information from printer. I am using ReadPrinter because connected is a local printer but i dont know why i am not getting any response from printer. Its lexmark E332n. Printer is PostScript enabled and is connected via USB with 2003 server.

All other methods are working ( OpenPrinter, ClosePrinter, StartDocPrinter, EndDocPrinter, StartPagePrinter, EndPagePrinter and WritePrinter ) but ReadPrinter always return zero. The GetLastWin32Error method in this code not returning any error message. This code is avaiable on MSDN but i made few changes in it. original code does not have ReadPrinter method coded in it.

Kindly, see if someone can find error in this code and most probably the parameter provided to the ReadPrinter method were not used correcly.

This program has three buttons on a form "Send File", "Send Query" and "Read From Printer". "Send File" button send PostScript file to printer, "Send Query" sends PostScript PJL commands in a string. The third button "Read From Printer" is what want to work for me and get result of my PostScript Query or File.

what i do, i click on "Send Query" button and printer prints one page with "Hello World" on it. Here at this stage i am assuming that the printer will be holding some information for me because my Send Query method was successful. And all i need is to click on the "Read From printer button" that gives call to ReadPrinter method and the method will fetch the results of the PJL commands that were sent when i clicked on Send Query button. So i am asking the printer to give me the information you are holding.
Here is the string.
"%!PS-Adobe-2.0"; +
"\x1b%-12345X@PJL INQUIRE LANG \f " +
"\x1b%-12345X@PJL INQUIRE LOWTONER \f " +
"gsave " +
"1 0.5 scale " +
"70 100  48  0 360 arc " +
"fill " +
"grestore " +
"/Helvetica-Bold 14 selectfont " +
"1.0 setgray " +
"29 45 moveto " +
"(Hello, world!) show " +
"showpage ";


But the Read Button does not return any thing but 0 that is what mSDN tell "If the function fails, the return value is zero". It is clear that function fails but for what reason i dont know. Please help me out of this problem because it taking to much out of my time. Here is the code.
The wrapping messed up the shape of code but anyway when you will copy it in the editor it will allign itself.

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.Drawing.Printing;
using System.Runtime.InteropServices;
using System.IO;
using System.Management;
namespace RawDataToPrinter
{
    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();
        }


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


Here is the ReadPrinter import.

[DllImport("winspool.drv", EntryPoint = "ReadPrinter", SetLastError = true, ExactSpelling = true, CallingConvention = CallingConvention.StdCall)]
public static extern int ReadPrinter(IntPtr hPrinter, out IntPtr pBytes, Int32 dwCount, out Int32 dwNoBytesRead);
//public static extern bool ReadPrinter(IntPtr hPrinter, [MarshalAs(UnmanagedType.LPStr)] StringBuilder pBytes, Int32 dwCount, ref Int32 dwNReadBytes);



// 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.
    using (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?
    dwCount = szString.Length;
    // 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;
}

Here is the ReadPrinter method call. ReadFromPrinter is called from the button "Read From Printer"
public static bool ReadFromPrinter(string szPrinterName, IntPtr pBytes, Int32 dwCount)
{
    // Read the data from the printer.
    Int32 dwError = 0;
    IntPtr hPrinter = new IntPtr(0);
    Int32 dwBytesRead = 0;
    DOCINFOA di = new DOCINFOA();
    int bSuccess = -1;

    // 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))
            {
                // read your bytes.
                bSuccess = ReadPrinter(hPrinter, out pBytes, dwCount, out dwBytesRead);
                EndPagePrinter(hPrinter);
            }
            EndDocPrinter(hPrinter);
        }
        ClosePrinter(hPrinter);
    }

I commented the condition on purpose to check the GetLastWin32Error
        // If you did not succeed, GetLastError may give more information
        // about why not.
        //if (bSuccess != 0)
        //{
        dwError = Marshal.GetLastWin32Error();
        //   return false;
        // }
        return true;
    }
}

Its "Send File".
private void button1_Click(object sender, EventArgs e)
{
    // Allow the user to select a file.
    OpenFileDialog ofd = new OpenFileDialog();
    if (DialogResult.OK == ofd.ShowDialog(this))
    {
        // Allow the user to select a printer.
        PrintDialog pd = new PrintDialog();
        pd.PrinterSettings = new PrinterSettings();
        if (DialogResult.OK == pd.ShowDialog(this))
        {
            // Print the file to the printer.
            RawPrinterHelper.SendFileToPrinter(pd.PrinterSettings.PrinterName, ofd.FileName);
        }
    }
}

It is "Read From Printer" button.
private void button2_Click(object sender, EventArgs e)
        {
            Int32 dwCount = 256;
            IntPtr pBytes = new IntPtr(dwCount);
            string gotit = "";
            byte[] returnbytes = new byte[dwCount];
            pBytes = Marshal.AllocCoTaskMem(dwCount);
            RawPrinterHelper.ReadFromPrinter("PS3", pBytes, dwCount);
            Marshal.Copy(returnbytes, 0, pBytes, dwCount);
            gotit = Convert.ToString(pBytes);
            gotit = gotit;

            // Read the data from the printer.
        }


It is "Send Query" button.
   private void button3_Click(object sender, EventArgs e)
        {
            string shoot =
                "%!PS-Adobe-2.0" +
                "\x1b%-12345X@PJL INQUIRE LANG \f" +
                "\x1b%-12345X@PJL INQUIRE LOWTONER \f" +
                "gsave " +
                "1 0.5 scale " +
                "70 100  48  0 360 arc " +
                "fill " +
                "grestore " +
                "/Helvetica-Bold 14 selectfont " +
                "1.0 setgray " +
                "29 45 moveto " +
                "(Hello, world!) show " +
                "showpage ";
                //"\x1b%-12345X\f";
            RawPrinterHelper.SendStringToPrinter("PS3", shoot);
        }
     }
}


Please see why ReadPrinter is not working. There must be something missing. My idea of reading information this way may not be correct. So please make correction. All the above code was collected from different sites. All the code is in working condition except that ReadPrinter method. I could not find one complete solution no where so lets do it now.


Yasir



Updated 1:

I changed ReadPrinter method and this time i am getting error code 6. Error code 6 is (the handle is Invalid). It also create job but problem is still there (ReadPrinter method does not work).

public static bool ReadFromPrinter(string szPrinterName, IntPtr pBytes, Int32 dwCount)
{
	// Read the data from the printer.
	Win32Exception ex = new Win32Exception();
	string errMsg = "";
	Int32 dwError = 0;
	IntPtr hPrinter = new IntPtr(0);
	IntPtr hPrinterJob = new IntPtr(0);
	Int32 dwBytesRead = 0;
	DOCINFOA di = new DOCINFOA();
	int bSuccess = -1;
	// Open the printer.
	if (OpenPrinter(szPrinterName.Normalize(), out hPrinter, IntPtr.Zero))
	{
		dwError = Marshal.GetLastWin32Error();
		ex = new Win32Exception();
		errMsg = ex.Message;
		MessageBox.Show(errMsg, "Open Printer");
		
		ZeroMemory(hPrinterJob, 0);
		di.pDataType = "RAW";
		di.pDocName = "Dummy job";
		
		// Start a document.
		if (StartDocPrinter(hPrinter, 1, di))
		{
			dwError = Marshal.GetLastWin32Error();
			ex = new Win32Exception();
			errMsg = ex.Message;
			MessageBox.Show(errMsg, "Start Doc Printer");
			// Start a page.
			if (StartPagePrinter(hPrinter))
			{
				dwError = Marshal.GetLastWin32Error();
				ex = new Win32Exception();
				errMsg = ex.Message;
				MessageBox.Show(errMsg, "Start Page Printer");
				// Read your bytes.
				bSuccess = ReadPrinter(hPrinter, out pBytes, dwCount, out dwBytesRead);
				dwError = Marshal.GetLastWin32Error();
				ex = new Win32Exception();
				errMsg = ex.Message;
				MessageBox.Show(errMsg, "Read Printer");
				EndPagePrinter(hPrinter);
			}
			EndDocPrinter(hPrinter);
		}
		ClosePrinter(hPrinter);
	}
	// If you did not succeed, GetLastError may give more information
	// about why not.
	//if (bSuccess != 0)
	//{
	dwError = Marshal.GetLastWin32Error();
	//   return false;
	//}
	return true;
}



Someone is telling us to read ports instead of reading printer. Also GetPrinter method can be used. I am not sure if that is the right answer. Pease read details on this link.
http://www.eggheadcafe.com/software/aspnet/32623898/retrieving-data-from-printer-using-readprinter-api.aspx
There may be some other ways to solve this problem but the requirements are that the printer is local USB, I dont want to use Windows WDF and GetPrinter method is also not required. If ReadPrinter can be used to set/get printer settings then it should be working. I think there may be mistake in parameter passing to readPrinter. Lets help others with a complete solution.
:-) Yasir
Posted
Updated 11-Apr-11 6:47am
v3
Comments
El_Codero 31-May-12 17:02pm    
Unfortunately no solution yet. Problem still exists?
guy messika 21-Jul-13 13:41pm    
problem still exist

 
Share this answer
 
To expound upon Avi's solution, the problem is that the call to OpenPrinter must specify the job identifier, in addition to the printer name.

From MSDN:

hPrinter [in]
A handle to the printer object for which to retrieve data. Use the OpenPrinter function to retrieve a printer object handle. Use the format: Printername, Job xxxx.
 
Share this answer
 

This content, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)



CodeProject, 20 Bay Street, 11th Floor Toronto, Ontario, Canada M5J 2N8 +1 (416) 849-8900