3

I would like to make a program that provides me with the print counter of a selected printer. I want to know at any given time how many prints/copies the device has done.

Is there an easy way to achieve this? I have searched but can't seem to find a solutions.

Thank you in advance.

Edit (added code: this is code that i found on the internet that will serve as a starting point to list all installed printers + properties source: Wade Brooks)

Imports System.Drawing.Printing             'Printer Settings
Imports System.Runtime.InteropServices      'Printer Information
Imports System.text                         'String Builder

Public Class frmPrinterInfoExample

#Region "Imports for Printer Information"
    <DllImport("winspool.drv", EntryPoint:="OpenPrinterW", CharSet:=CharSet.Auto, SetLastError:=True, ExactSpelling:=True, CallingConvention:=CallingConvention.StdCall)> _
    Private Shared Function OpenPrinter(ByVal pPrinterName As String, ByRef hPrinter As IntPtr, ByVal pDefault As IntPtr) As Boolean
    End Function

    <DllImport("winspool.drv", CharSet:=CharSet.Auto, SetLastError:=True, ExactSpelling:=True, CallingConvention:=CallingConvention.StdCall)> _
    Private Shared Function ClosePrinter(ByVal hPrinter As IntPtr) As Boolean
    End Function


    <DllImport("winspool.drv", EntryPoint:="GetPrinterW", CharSet:=CharSet.Auto, SetLastError:=True, ExactSpelling:=True, CallingConvention:=CallingConvention.StdCall)> _
    Private Shared Function GetPrinter(ByVal hPrinter As IntPtr, ByVal dwLevel As Integer, ByVal pPrinter As IntPtr, ByVal cbBuf As Integer, ByRef pcbNeeded As Integer) As Boolean
    End Function
#End Region

#Region "Variables"
    Dim mstrInfo As StringBuilder 'Info for User

    'Printer Info structure
    <StructLayout(LayoutKind.Sequential, CharSet:=CharSet.Auto)> Public Structure PRINTER_INFO_2
        Dim pServerName As String
        Dim pPrinterName As String
        Dim pShareName As String
        Dim pPortName As String
        Dim pDriverName As String
        Dim pComment As String
        Dim pLocation As String
        Dim pDevMode As Integer
        Dim pSepFile As String
        Dim pPrintProcessor As String
        Dim pDatatype As String
        Dim pParameters As String
        Dim pSecurityDescriptor As Integer
        Dim Attributes As Integer
        Dim Priority As Integer
        Dim DefaultPriority As Integer
        Dim StartTime As Integer
        Dim UntilTime As Integer
        Dim Status As Integer
        Dim cJobs As Integer
        Dim AveragePPM As Integer
    End Structure

#End Region

#Region "Private Methods"

    ''' <summary>
    ''' Populate printer list
    ''' </summary>
    Private Sub btnPrinterList_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btnPrinterList.Click
        Try
            PopulateInstalledPrintersCombo()
        Catch ex As Exception
            MessageBox.Show(ex.Message, "Error", MessageBoxButtons.OK)
        End Try
    End Sub

    ''' <summary>
    ''' List of installed printers
    ''' </summary>
    Private Sub PopulateInstalledPrintersCombo()

        Try
            cboInstalledPrinters.Items.Clear()

            ' Add list of installed printers found to the combo box.
            For Each strPrinter As String In PrinterSettings.InstalledPrinters
                cboInstalledPrinters.Items.Add(strPrinter)
            Next

            If cboInstalledPrinters.Items.Count > 0 Then
                cboInstalledPrinters.SelectedIndex = 0
            End If
        Catch ex As Exception
            MessageBox.Show(ex.Message, "Error", MessageBoxButtons.OK)
        End Try
    End Sub

    ''' <summary>
    ''' Show other printer info to user
    ''' </summary>
    Private Sub OtherPrinterInfo()
        Dim prtPrinter As PrinterSettings = Nothing
        Try
            prtPrinter = New PrinterSettings
            prtPrinter.PrinterName = cboInstalledPrinters.Text

            'Assumes textbox1 cleared in calling function
            mstrInfo.Append(String.Format("SupportsColor: {0}{1}", prtPrinter.SupportsColor, vbCrLf))

            mstrInfo.Append(String.Format("IsDefaultPrinter: {0}{1}", prtPrinter.IsDefaultPrinter, vbCrLf))

            mstrInfo.Append(String.Format("CanDuplex: {0}{1}", prtPrinter.CanDuplex, vbCrLf))

            mstrInfo.Append(String.Format("IsPlotter: {0}{1}", prtPrinter.IsPlotter, vbCrLf))

            mstrInfo.Append(String.Format("MaximumCopies: {0}{1}", prtPrinter.MaximumCopies, vbCrLf))

        Catch ex As Exception
            MessageBox.Show(ex.Message, "Error", MessageBoxButtons.OK)
        End Try

    End Sub

    ''' <summary>
    ''' Printer Information
    ''' </summary>
    Private Function GetPrinterInfo(ByVal sName As String) As PRINTER_INFO_2

        Dim hPrinter As IntPtr = IntPtr.Zero
        Dim pPrinterInfo As IntPtr = IntPtr.Zero
        Dim iNeed As Integer = -1
        Dim SizeOf As Integer = -1
        Try

            'Open printer object
            If (Not OpenPrinter(sName, hPrinter, IntPtr.Zero)) Then
                Marshal.ThrowExceptionForHR(System.Runtime.InteropServices.Marshal.GetHRForLastWin32Error())
            End If

            Try
                ' Get the number of bytes needed. 
                GetPrinter(hPrinter, 2, IntPtr.Zero, 0, iNeed)

                ' Allocate enough memory. 
                pPrinterInfo = Marshal.AllocHGlobal(iNeed)
                SizeOf = iNeed
                If (Not GetPrinter(hPrinter, 2, pPrinterInfo, SizeOf, iNeed)) Then
                    Marshal.ThrowExceptionForHR(System.Runtime.InteropServices.Marshal.GetHRForLastWin32Error())
                End If

                ' Now marshal the structure manually. 
                Dim PrinterInfo As PRINTER_INFO_2 = CType(Marshal.PtrToStructure(pPrinterInfo, GetType(PRINTER_INFO_2)), PRINTER_INFO_2)

                Return PrinterInfo
            Catch ex As Exception
                MessageBox.Show(ex.Message, "Error", MessageBoxButtons.OK)
            Finally
                ' Close the printer object. 
                ClosePrinter(hPrinter)
                ' Deallocate the memory. 
                Marshal.FreeHGlobal(pPrinterInfo)
            End Try
        Catch ex As Exception
            MessageBox.Show(ex.Message, "Error", MessageBoxButtons.OK)
        End Try
        Return New PRINTER_INFO_2()
    End Function

    ''' <summary>
    ''' Handles printer info button click
    ''' </summary>
    Private Sub btnPrinterInfo_Click_1(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btnPrinterInfo.Click

        Try
            Cursor = Cursors.WaitCursor
            If mstrInfo IsNot Nothing Then
                mstrInfo = Nothing
            End If
            mstrInfo = New StringBuilder

            Dim PrinterInformation As PRINTER_INFO_2 = GetPrinterInfo(cboInstalledPrinters.Text)
            txtPrinterInfo.Clear()

            'Show info in Text box
            If PrinterInformation.pPrinterName IsNot Nothing Then
                mstrInfo.Append(String.Format("PrinterName: {0}{1}", PrinterInformation.pPrinterName, vbCrLf))
            End If

            If PrinterInformation.pPortName IsNot Nothing Then
                mstrInfo.Append(String.Format("PortName: {0}{1}", PrinterInformation.pPortName, vbCrLf))
            End If

            If PrinterInformation.pComment IsNot Nothing Then
                mstrInfo.Append(String.Format("Comment: {0}{1}", PrinterInformation.pComment, vbCrLf))
            End If

            If PrinterInformation.pDatatype IsNot Nothing Then
                mstrInfo.Append(String.Format("Datatype: {0}{1}", PrinterInformation.pDatatype, vbCrLf))
            End If

            If PrinterInformation.pDriverName IsNot Nothing Then
                mstrInfo.Append(String.Format("DriverName: {0}{1}", PrinterInformation.pDriverName, vbCrLf))
            End If

            If PrinterInformation.pLocation IsNot Nothing Then
                mstrInfo.Append(String.Format("Location: {0}{1}", PrinterInformation.pLocation, vbCrLf))
            End If

            If PrinterInformation.pParameters IsNot Nothing Then
                mstrInfo.Append(String.Format("Parameters: {0}{1}", PrinterInformation.pParameters, vbCrLf))
            End If

            If PrinterInformation.pPrintProcessor IsNot Nothing Then
                mstrInfo.Append(String.Format("PrintProcessor: {0}{1}", PrinterInformation.pPrintProcessor, vbCrLf))
            End If

            If PrinterInformation.pServerName IsNot Nothing Then
                mstrInfo.Append(String.Format("ServerName: {0}{1}", PrinterInformation.pServerName, vbCrLf))
            End If

            If PrinterInformation.pShareName IsNot Nothing Then
                mstrInfo.Append(String.Format("ShareName: {0}{1}", PrinterInformation.pShareName, vbCrLf))
            End If



            'Get other info
            OtherPrinterInfo()

            'Add info to textbox
            txtPrinterInfo.Text = mstrInfo.ToString

        Catch ex As Exception
            MessageBox.Show(ex.Message, "Error", MessageBoxButtons.OK)
        Finally
            'Clean up
            If (mstrInfo IsNot Nothing) Then
                mstrInfo = Nothing
            End If
            Cursor = Cursors.Default

        End Try

    End Sub

    ''' <summary>
    ''' Close Form
    ''' </summary>
    Private Sub cmdClose_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles cmdClose.Click
        Try
            Close()
        Catch ex As Exception
            MessageBox.Show(ex.Message, "Error", MessageBoxButtons.OK)
        End Try

    End Sub

#End Region

EDIT 2 I have found this function that does give me the print counter of some printers but not all. The general HP printers and all are no problem but a multifunctional printer (Kyocera/ Konica Minolta) allways returns an error and a value of 0.

Public Function GetPageCount(ByVal PrinterIP As String) As Integer
        Dim tcpClient As TcpClient
        Dim connector As New cliConnector

        Try
            tcpClient = connector.Connect(PrinterIP, 9100, 1000)
            tcpClient.SendTimeout = 1000
            tcpClient.ReceiveTimeout = 1000
            Dim networkStream As NetworkStream = tcpClient.GetStream()
            If networkStream.CanWrite And networkStream.CanRead Then
                ' Do a simple write.
                Dim txt As String
                txt = Chr(27) & "%-12345X@PJL" & vbLf & "@PJL INFO PAGECOUNT" & vbLf & Chr(27) & "%-12345X" & vbLf
                Dim sendBytes As [Byte]() = Encoding.ASCII.GetBytes(txt)
                networkStream.Write(sendBytes, 0, sendBytes.Length)
                ' Read the NetworkStream into a byte buffer.
                Dim bytes(tcpClient.ReceiveBufferSize) As Byte
                networkStream.Read(bytes, 0, CInt(tcpClient.ReceiveBufferSize))
                ' Output the data received from the host to the console.
                Dim returndata As String = Encoding.ASCII.GetString(bytes)
                tcpClient.Close()

                Return returndata.Substring(returndata.IndexOf(vbNewLine) + 1, returndata.Substring(returndata.IndexOf(vbNewLine) + 1).IndexOf(vbNewLine))
            Else
                If Not networkStream.CanRead Then
                    tcpClient.Close()
                    Return False

                Else
                    If Not networkStream.CanWrite Then
                        tcpClient.Close()
                        Return False

                    End If
                End If
            End If
            tcpClient.Close()
        Catch ex As Exception
            MessageBox.Show(ex.Message)
            Return False
        End Try

    End Function
Jo Broeckx
  • 73
  • 5
  • 1
    You should provide some insight into what you have tried already. This is largely expected on this site. Please refer here: http://stackoverflow.com/help/how-to-ask – Jens Jul 30 '14 at 07:13
  • Thnx for your reply Jens but I haven't really got much to start from. I have found some help with listing the installed printers on a device and some of their properties. But I haven't got a clue how I can find the print counter. – Jo Broeckx Jul 30 '14 at 07:23
  • Just add some of these information and it is fine. It doesn't need to be working code. It shows research effort which is appreciated and it helps people provide answers. – Jens Jul 30 '14 at 07:26
  • This is the code I'm using at the moment that i included in the original post. But this is code that I found on the internet. (source:Wade Brooks) – Jo Broeckx Jul 30 '14 at 07:33
  • 1
    This is not generally possible. It is up to the printer driver to decide how multiple copies of a document get generated. If it knows that the print job fits in the memory of the printer then it will send the job just once and tell the printer how often to print it. If not then it has to spool it multiple times. And of course, print jobs can be submitted from multiple machines, the printer itself tends to have a page counter but there's no standard way to obtain the value. The printer manufacturer usually has some kind of utility to query it. – Hans Passant Jul 30 '14 at 08:12
  • Thnx for the reply Hans. The idea first began when an external company (printerdealer) to install software that would do just this. Give me an overview of printer usage for all printers within our company. I've seen their software but not their code. Does this mean that for each manufacurer they are using different code? – Jo Broeckx Jul 30 '14 at 08:18

1 Answers1

0

SNMP is going to be your best bet here, I would image almost all newer printers aimed at office/business use will support this.

There's a fantastic post here by Cristian explaining a bit more about this. SNMP for Local printer?

You can get example VB.net code for connecting to SNMP capable devices here: http://www.snmpsharpnet.com/?page_id=105

There's also an open source .Net library - https://sharpsnmplib.codeplex.com/ - I've never used this but it appears well documented.

Sliding away from coding help here but - it would be much easier using something like Spiceworks which is free and does exactly what you need and more. http://www.spiceworks.com

You can get a printer report add on for Spiceworks from here (http://community.spiceworks.com/reports/1237).

Community
  • 1
  • 1
GJKH
  • 1,635
  • 12
  • 29