0

Here is my main program:

class Program
{
    static void Main(string[] args)
    {
        Printer printer = new Printer();

        IntPtr printerHandle = printer.getPrinterHandle("TASKalfa 2551ci");

        UInt32 jobId = printer.getJobId();
        Console.WriteLine(printerHandle+","+jobId);
        printer.getJob(printerHandle, jobId);
        Console.ReadLine();
    }
}

I got the following error message from VS 2015 Community Edition, when I call printer.getJob Method, even I have catched the System.NullReferenceException.

System.NullReferenceException was unhandled
Message: An unhandled exception of type 'System.NullReferenceException' occurred in mscorlib.dll
Additional information: Object reference not set to an instance of an object.

I have checked that both variable printerHandle and jobId are not null, so I cannot figure out what is problem.

However the value of printerHandle is not a constant, is it correct?

Here is my printer object source code:

using System;
using System.Collections;
using System.Management;
using System.Runtime.InteropServices;
class Printer
{
    public Printer()
    {

    }
    public ArrayList getPrinterNameList()
    {
        ArrayList result = new ArrayList();
        var printerQuery = new ManagementObjectSearcher("SELECT * from Win32_Printer");
        foreach (var printer in printerQuery.Get())
        {
            result.Add(printer.GetPropertyValue("Name"));
        }
        return result;
    }
    public UInt32 getJobId()
    {
        UInt32 jobId=0;
        var printJobQuery = new ManagementObjectSearcher("select * from Win32_PrintJob");
        foreach (var printJob in printJobQuery.Get())
        {
            jobId= (UInt32)printJob.Properties["JobId"].Value;
        }
        return jobId;
    }
    public IntPtr getPrinterHandle(String printerName)
    {
        IntPtr result=new IntPtr(0);
        Console.WriteLine ("OpenPrinter="+OpenPrinter(printerName,out result, result));
        return result;
    }
    public void getJob(IntPtr printerHandle,UInt32 jobId)
    {
        int BUFFER_SIZE = 250;
        IntPtr pcbNeeed = new IntPtr(0);
        byte[] byteBuffer = new byte[BUFFER_SIZE];
        try
        { 
            Console.WriteLine("GetJob="+GetJob(printerHandle, (Int32)jobId, 1, out byteBuffer, BUFFER_SIZE, out pcbNeeed));
        }
        catch (System.NullReferenceException err)
        {
            Console.WriteLine(err.Message);
        }
    }
    [DllImport("winspool.drv", SetLastError = true)]
    static extern int OpenPrinter(string pPrinterName, out IntPtr phPrinter, IntPtr pDefault);

     [DllImport(
        "winspool.drv",
        EntryPoint = "GetJobW",
        SetLastError = true,
        CharSet = CharSet.Ansi,
        ExactSpelling = false,
        CallingConvention = CallingConvention.StdCall)]
            private static extern bool GetJob
        ([InAttribute()] IntPtr hPrinter,
        [InAttribute()] Int32 JobId,
        [InAttribute()] Int32 Level,
        [OutAttribute()] out byte[] pJob,
        [InAttribute()] Int32 cbBuf,
        [OutAttribute()] out IntPtr pcbNeeded);

}

enter image description here

Here is my WIN API version:

    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Diagnostics;
    using System.Runtime.InteropServices;

    namespace ConsoleApplication2
    {
        class Program
        {
            static void Main(string[] args)
            {
                string msg = null;
                var hPrinter = new IntPtr();
                bool open = NativeMethods.OpenPrinterW("TASKalfa 2551ci", ref hPrinter, IntPtr.Zero);
                Debug.Assert(open);

                /* Query for 99 jobs */
                const uint firstJob = 0u;
                const uint noJobs = 99u;
                const uint level = 1u;

                // Get byte size required for the function
                uint needed;
                uint returned;
                IntPtr tempptr = IntPtr.Zero;
                bool b1 = NativeMethods.EnumJobsW(
                    hPrinter, firstJob, noJobs, level, IntPtr.Zero, 0, out needed, out returned);
                uint lastError = NativeMethods.GetLastError();
                Console.WriteLine("b1="+b1);

                //Debug.Assert(lastError == NativeConstants.ERROR_INSUFFICIENT_BUFFER);
                NativeMethods.FormatMessage(0x1300, ref tempptr, lastError, 0, ref msg, 255, ref tempptr);
                Console.WriteLine("lastError=" + msg);


                // Populate the structs
                IntPtr pJob = Marshal.AllocHGlobal((int)needed);
                uint bytesCopied;
                uint structsCopied;
                bool b2 = NativeMethods.EnumJobsW(
                    hPrinter, firstJob, noJobs, level, pJob, needed, out bytesCopied, out structsCopied);
                lastError = NativeMethods.GetLastError();
                Console.WriteLine("b2="+b2);
                NativeMethods.FormatMessage(0x1300, ref tempptr, lastError, 0, ref msg, 255, ref tempptr);
                Console.WriteLine("lastError="+ msg);
                var jobInfos = new JOB_INFO_1W[structsCopied];
                int sizeOf = Marshal.SizeOf(typeof(JOB_INFO_1W));
                IntPtr pStruct = pJob;
                for (int i = 0; i < structsCopied; i++)
                {
                    var jobInfo_1W = (JOB_INFO_1W)Marshal.PtrToStructure(pStruct, typeof(JOB_INFO_1W));
                    jobInfos[i] = jobInfo_1W;
                    pStruct += sizeOf;
                }
                Marshal.FreeHGlobal(pJob);
                Console.WriteLine("structsCopied="+structsCopied);
                Console.ReadLine();
            }
            public class NativeConstants
            {
                public const int ERROR_INSUFFICIENT_BUFFER = 122;
            }
            public partial class NativeMethods
            {
                [DllImport("kernel32.dll", EntryPoint = "GetLastError")]
                public static extern uint GetLastError();

                [System.Runtime.InteropServices.DllImport("Kernel32.dll")]
                public extern static int FormatMessage(int flag, ref IntPtr source, uint msgid, int langid, ref string buf, int size, ref IntPtr args);
            }

            public partial class NativeMethods
            {
                [DllImport("Winspool.drv", EntryPoint = "OpenPrinterW")]
                [return: MarshalAs(UnmanagedType.Bool)]
                public static extern bool OpenPrinterW([In] [MarshalAs(UnmanagedType.LPWStr)] string pPrinterName,
                    ref IntPtr phPrinter, [In] IntPtr pDefault);

                [DllImport("Winspool.drv", EntryPoint = "EnumJobsW")]
                [return: MarshalAs(UnmanagedType.Bool)]
                public static extern bool EnumJobsW([In] IntPtr hPrinter, uint FirstJob, uint NoJobs, uint Level, IntPtr pJob,
                    uint cbBuf, [Out] out uint pcbNeeded, [Out] out uint pcReturned);
            }
            [StructLayout(LayoutKind.Sequential)]
            public struct JOB_INFO_1W
            {
                public uint JobId;
                [MarshalAs(UnmanagedType.LPWStr)]
                public string pPrinterName;
                [MarshalAs(UnmanagedType.LPWStr)]
                public string pMachineName;
                [MarshalAs(UnmanagedType.LPWStr)]
                public string pUserName;
                [MarshalAs(UnmanagedType.LPWStr)]
                public string pDocument;
                [MarshalAs(UnmanagedType.LPWStr)]
                public string pDatatype;
                [MarshalAs(UnmanagedType.LPWStr)]
                public string pStatus;
                public uint Status;
                public uint Priority;
                public uint Position;
                public uint TotalPages;
                public uint PagesPrinted;
                public SYSTEMTIME Submitted;
            }

            [StructLayout(LayoutKind.Sequential)]
            public struct SYSTEMTIME
            {
                public ushort wYear;
                public ushort wMonth;
                public ushort wDayOfWeek;
                public ushort wDay;
                public ushort wHour;
                public ushort wMinute;
                public ushort wSecond;
                public ushort wMilliseconds;
            }
        }
    }

I am using Windows 10.

The KNVB
  • 1,972
  • 1
  • 19
  • 28

1 Answers1

3

This is my solution:

using System;
using System.Text;
using System.Management;
using System.Runtime.InteropServices;
namespace WinApi
{
    class PrintJob
    {
        private const int ERROR_INSUFFICIENT_BUFFER = 122;
        public PrintJob()
        {
        string sql = "select * from Win32_PrintJob";
        var printJobQuery = new ManagementObjectSearcher(sql);
        foreach (ManagementObject printJob in printJobQuery.Get())
            {
                getJobDetail(printJob);
                Console.WriteLine("====================");
            }
        }

        private void getJobDetail(ManagementObject thePrintJob)
        {
            UInt32 jobId = 0, needed = 0;
            String printerName;
            bool result;
            IntPtr printerHandle = new IntPtr(0);
            jobId = (UInt32)thePrintJob.Properties["JobId"].Value;
            printerName = (String)thePrintJob.Properties["DriverName"].Value;
            Console.WriteLine("Job Id=" + jobId + ",Printer Name=" + printerName);
            result=OpenPrinter(printerName,out printerHandle, IntPtr.Zero);
            Console.Write("Open Printer " + printerName);
            if (result)
            {
                Console.WriteLine(" success.");
                result = GetJob(printerHandle, jobId, 2, IntPtr.Zero,0,out needed);
                if (Marshal.GetLastWin32Error() != ERROR_INSUFFICIENT_BUFFER)
                    Console.WriteLine("Get Job 1 failure, error code=" + Marshal.GetLastWin32Error());
                else
                {
                    Console.WriteLine("buffer size required=" + needed);
                    IntPtr buffer = Marshal.AllocHGlobal((int)needed);
                    result = GetJob(printerHandle, jobId, 2, buffer, needed, out needed);
                    JOB_INFO_2 jobInfo=(JOB_INFO_2)Marshal.PtrToStructure(buffer, typeof(JOB_INFO_2));
                    DEVMODE dMode = (DEVMODE)Marshal.PtrToStructure(jobInfo.pDevMode, typeof(DEVMODE));
                    Console.WriteLine("Job Id=" + jobInfo.JobId + ",Printer Name=" + Marshal.PtrToStringAnsi(jobInfo.pDriverName) + ",Copies=" + dMode.dmCopies);
                    Marshal.FreeHGlobal(buffer);
                }
                ClosePrinter(printerHandle);
                Console.WriteLine("Printer " + printerName+" is closed");
            }
            else
                Console.WriteLine(" failed.");
        }


        [DllImport("winspool.drv", SetLastError = true)]
        static extern bool OpenPrinter(string pPrinterName, out IntPtr phPrinter, IntPtr pDefault);
        [DllImport("winspool.drv", CharSet = CharSet.Auto)]
        static extern bool ClosePrinter(IntPtr hPrinter);
        [DllImport(
        "winspool.drv",
        EntryPoint = "GetJob",
        SetLastError = true,
        ExactSpelling = false,
        CallingConvention = CallingConvention.StdCall)]
        private static extern bool GetJob
        ([InAttribute()] IntPtr hPrinter,
        [InAttribute()] UInt32 JobId,
        [InAttribute()] UInt32 Level,
        [OutAttribute()] IntPtr pJob,
        [InAttribute()] UInt32 cbBuf,
        [OutAttribute()] out UInt32 pcbNeeded);

        [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)]
        private struct JOB_INFO_2
        {
            public UInt32 JobId;
            public IntPtr pPrinterName;
            public IntPtr pMachineName;
            public IntPtr pUserName;
            public IntPtr pDocument;
            public IntPtr pNotifyName;
            public IntPtr pDatatype;
            public IntPtr pPrintProcessor;
            public IntPtr pParameters;
            public IntPtr pDriverName;
            public IntPtr pDevMode;
            public IntPtr pStatus;
            public IntPtr pSecurityDescriptor;
            public UInt32 Status;
            public UInt32 Priority;
            public UInt32 Position;
            public UInt32 StartTime;
            public UInt32 UntilTime;
            public UInt32 TotalPages;
            public UInt32 Size;
            public SYSTEMTIME Submitted;
            public UInt32 Time;
            public UInt32 PagesPrinted;

        }

        [StructLayout(LayoutKind.Sequential)]
        public struct SYSTEMTIME
        {
            public short wYear;
            public short wMonth;
            public short wDayOfWeek;
            public short wDay;
            public short wHour;
            public short wMinute;
            public short wSecond;
            public short wMilliseconds;
        }
        [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)]
        public struct DEVMODE
        {
            [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 32)]
            public string dmDeviceName;
            public short dmSpecVersion;
            public short dmDriverVersion;
            public short dmSize;
            public short dmDriverExtra;
            public int dmFields;
            public short dmOrientation;
            public short dmPaperSize;
            public short dmPaperLength;
            public short dmPaperWidth;
            public short dmScale;
            public short dmCopies;
            public short dmDefaultSource;
            public short dmPrintQuality;
            public short dmColor;
            public short dmDuplex;
            public short dmYResolution;
            public short dmTTOption;
            public short dmCollate;
            [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 32)]
            public string dmFormName;
            public short dmLogPixels;
            public int dmBitsPerPel;
            public int dmPelsWidth;
            public int dmPelsHeight;
            public int dmDisplayFlags;
            public int dmDisplayFrequency;
        }
    }
}
The KNVB
  • 1,972
  • 1
  • 19
  • 28
  • Thank you! How should I use it? – jNewbie Oct 19 '17 at 19:57
  • What do you want to do? – The KNVB Oct 20 '17 at 01:20
  • I need to save the document that was send to the printer. Can I do that using the print job? – jNewbie Oct 20 '17 at 02:43
  • Do you mean the spool file? – The KNVB Oct 20 '17 at 03:36
  • Yes, it's possible? – jNewbie Oct 20 '17 at 03:41
  • Sorry, I am not sure. You may try GetSpoolFileHandle function. – The KNVB Oct 20 '17 at 04:07
  • I used your code and it works perfectly, but dmCopies only show the real number copies when I print a pdf file, from a Microsoft Word file, always shows "1", do you tested it in that scenary?? The others var works perfectly in any scenary. Thanks for you help! – karelp90 Oct 30 '17 at 13:17
  • Yes, I tested this scenery, but I cannot figure out the solution. It is because my boss does not want to spend too much resource on this project. – The KNVB Oct 30 '17 at 15:31
  • Take a look to this [https://stackoverflow.com/questions/38101174/printer-spooler-api-number-of-copies] There are two ways, I have not tried them yet, but if you do and works it, specially the one with the SPL file, let me know – karelp90 Oct 30 '17 at 19:08
  • Hi @karelp90 if you are trying to print from .doc extension then that is microsoft's known bug there is hotfix to update the some regedit please check this link https://support.microsoft.com/en-us/help/919736/the-dmcopies-member-always-returns-a-value-of-1-when-you-try-to-retrie – Trilok Chandra Feb 20 '19 at 05:40
  • I have used the this code. but i am enable to get the Page range. please let me know how should i get the page range entered by user – Trilok Chandra Feb 20 '19 at 05:41