VBA - get active printer status

kelly mort

Well-known Member
Code:
Private Declare Function GetPrinterApi Lib "winspool.drv" Alias _
       "GetPrinterA" (ByVal hPrinter As Long, _
         ByVal Level As Long, _
         buffer As Long, _
         ByVal pbSize As Long, _
         pbSizeNeeded As Long) As Long
  
Private Type PRINTER_DEFAULTS
  pDatatype As String
  pDevMode As DEVMODE
  DesiredAccess As Long
End Type


Private Declare Function OpenPrinter Lib "winspool.drv" _
    Alias "OpenPrinterA" (ByVal pPrinterName As String, _
    phPrinter As Long, pDefault As PRINTER_DEFAULTS) As Long


Private Declare Function ClosePrinter Lib "winspool.drv" _
    (ByVal hPrinter As Long) As Long
 
Dim lret As Long
Dim pDef As PRINTER_DEFAULTS


lret = OpenPrinter(Printer.DeviceName, mhPrinter, pDef)


Public Enum Printer_Status
   PRINTER_STATUS_READY = &H0
   PRINTER_STATUS_PAUSED = &H1
   PRINTER_STATUS_ERROR = &H2
   PRINTER_STATUS_PENDING_DELETION = &H4
   PRINTER_STATUS_PAPER_JAM = &H8
   PRINTER_STATUS_PAPER_OUT = &H10
   PRINTER_STATUS_MANUAL_FEED = &H20
   PRINTER_STATUS_PAPER_PROBLEM = &H40
   PRINTER_STATUS_OFFLINE = &H80
   PRINTER_STATUS_IO_ACTIVE = &H100
   PRINTER_STATUS_BUSY = &H200
   PRINTER_STATUS_PRINTING = &H400
   PRINTER_STATUS_OUTPUT_BIN_FULL = &H800
   PRINTER_STATUS_NOT_AVAILABLE = &H1000
   PRINTER_STATUS_WAITING = &H2000
   PRINTER_STATUS_PROCESSING = &H4000
   PRINTER_STATUS_INITIALIZING = &H8000
   PRINTER_STATUS_WARMING_UP = &H10000
   PRINTER_STATUS_TONER_LOW = &H20000
   PRINTER_STATUS_NO_TONER = &H40000
   PRINTER_STATUS_PAGE_PUNT = &H80000
   PRINTER_STATUS_USER_INTERVENTION = &H100000
   PRINTER_STATUS_OUT_OF_MEMORY = &H200000
   PRINTER_STATUS_DOOR_OPEN = &H400000
   PRINTER_STATUS_SERVER_UNKNOWN = &H800000
   PRINTER_STATUS_POWER_SAVE = &H1000000
End Enum


Private Type PRINTER_INFO_2
   pServerName As String
   pPrinterName As String
   pShareName As String
   pPortName As String
   pDriverName As String
   pComment As String
   pLocation As String
   pDevMode As Long
   pSepFile As String
   pPrintProcessor As String
   pDatatype As String
   pParameters As String
   pSecurityDescriptor As Long
   Attributes As Long
   Priority As Long
   DefaultPriority As Long
   StartTime As Long
   UntilTime As Long
   Status As Long
   JobsCount As Long
   AveragePPM As Long
End Type
  
  Dim lret As Long
  Dim SizeNeeded As Long


  Dim buffer() As Long


  ReDim Preserve buffer(0 To 1) As Long
  lret = GetPrinterApi(mhPrinter, Index, buffer(0), UBound(buffer), SizeNeeded)
  ReDim Preserve buffer(0 To (SizeNeeded / 4) + 3) As Long
  lret = GetPrinterApi(mhPrinter, Index, buffer(0), UBound(buffer) * 4, SizeNeeded)
  
'\\ Memory manipulation routines
Private Declare Sub CopyMemory Lib "kernel32" Alias "RtlMoveMemory" (Destination As Any, Source As Any, ByVal Length As Long)
'\\ Pointer validation in StringFromPointer
Private Declare Function IsBadStringPtrByLong Lib "kernel32" Alias "IsBadStringPtrA" (ByVal lpsz As Long, ByVal ucchMax As Long) As Long


Public Function StringFromPointer(lpString As Long, lMaxLength As Long) As String


  Dim sRet As String
  Dim lret As Long


  If lpString = 0 Then
    StringFromPointer = ""
    Exit Function
  End If


  If IsBadStringPtrByLong(lpString, lMaxLength) Then
    '\\ An error has occured - do not attempt to use this pointer
      StringFromPointer = ""
    Exit Function
  End If


  '\\ Pre-initialise the return string...
  sRet = Space$(lMaxLength)
  CopyMemory ByVal sRet, ByVal lpString, ByVal Len(sRet)
  If Err.LastDllError = 0 Then
    If InStr(sRet, Chr$(0)) > 0 Then
      sRet = Left$(sRet, InStr(sRet, Chr$(0)) - 1)
    End If
  End If


  StringFromPointer = sRet


End Function


With mPRINTER_INFO_2 '\\ This variable is of type PRINTER_INFO_2
   .pServerName = StringFromPointer(buffer(0), 1024)
   .pPrinterName = StringFromPointer(buffer(1), 1024)
   .pShareName = StringFromPointer(buffer(2), 1024)
   .pPortName = StringFromPointer(buffer(3), 1024)
   .pDriverName = StringFromPointer(buffer(4), 1024)
   .pComment = StringFromPointer(buffer(5), 1024)
   .pLocation = StringFromPointer(buffer(6), 1024)
   .pDevMode = buffer(7)
   .pSepFile = StringFromPointer(buffer(8), 1024)
   .pPrintProcessor = StringFromPointer(buffer(9), 1024)
   .pDatatype = StringFromPointer(buffer(10), 1024)
   .pParameters = StringFromPointer(buffer(11), 1024)
   .pSecurityDescriptor = buffer(12)
   .Attributes = buffer(13)
   .Priority = buffer(14)
   .DefaultPriority = buffer(15)
   .StartTime = buffer(16)
   .UntilTime = buffer(17)
   .Status = buffer(18)
   .JobsCount = buffer(19)
   .AveragePPM = buffer(20)
End With

So I came across this script while I was trying to get the status of the active printer. Whether it is online or offline.


Can someone point to me how to use this? And looking at it , looks like it was written for 32-bits. How do I optimize it for both 32-bits and 64-bits?

This is the link:
http://www.merrioncomputing.com/Programming/PrintStatus.htm
 

kelly mort

Well-known Member

So this is how I uses the code:
Code:
Sub GetStatus()
strComputer = "."
Set objWMIService = GetObject("winmgmts:" _
& "{impersonationLevel=impersonate}!\\" & strComputer & "\root\cimv2")
Set colInstalledPrinters = objWMIService.ExecQuery _
("Select * from Win32_Printer")
For Each objPrinter in colInstalledPrinters
[B]Wscript.Echo "Name: " & objPrinter.Name[/B]
Wscript.Echo "Location: " & objPrinter.Location
Select Case objPrinter.PrinterStatus
Case 1
strPrinterStatus = "Other"
Case 2
strPrinterStatus = "Unknown"
Case 3
strPrinterStatus = "Idle"
Case 4
strPrinterStatus = "Printing"
Case 5
strPrinterStatus = "Warmup"
Case 6
strPrinterStatus = "Stopped printing"
Case 7
strPrinterStatus = "Offline"
End Select
Wscript.Echo "Printer Status: " & strPrinterStatus
Wscript.Echo "Server Name: " & objPrinter.ServerName
Wscript.Echo "Share Name: " & objPrinter.ShareName
Wscript.Echo
Next
End Sub
Then the bold line says object required
 

kelly mort

Well-known Member

John_w

MrExcel MVP
That code is VBScript - change every Wscript.Echo to Debug.Print for VBA. You'll also need to declare the variables if you're using Option Explicit.
 

kelly mort

Well-known Member
That code is VBScript - change every Wscript.Echo to Debug.Print for VBA. You'll also need to declare the variables if you're using Option Explicit.
Okay, cool it's working great.

So how do I declare the various variables?

Which data type ?


Then lastly, I want to show for only the active printer. What's the fix?

Also, I can't differentiate the idle state from the offline state. Because my printer is offline but it says idle
 
Last edited:

Some videos you may like

This Week's Hot Topics

  • Importing multiple excel files into one spreadsheet
    Hi, I'm trying to import multiple excel files (with the same format into a single spreadsheet) so that each day's file is listed underneath the...
  • find many based on a certain criteria
    good evening, I hope someone can help me? I have a workbook sheet 2 contains lots of data.... I would like to be able to find anything on sheet...
  • How to copy multiple rows using If
    Hi all, I'm very new to VBA and have written this simple code to copy certain cells if a certain cell within that row contains any data. I need...
  • VBA If statement
    Dear All, I have two dates, where I'd like a message box to pop, if the dates are between this criteria. [CODE] sDate1 = #10/1/2019#...
  • Text Format
    I have a sheet for user to keyin the data. The format of the data can be 451 / 1903, 0012 / 9908 or 00287 / 0099. The number after the "/" is...
  • Syntax errors
    Good Morning, Trying to compile a workbook, I keep getting a few errors. Here are the first two: [code=rich]Syntax Error: Function...
Top