Report Sent to Printer? (2 Viewers)

Have you considered always sending the report to PDF and presenting the PDF as the preview. Any attempts to reprint the report would reopen the saved PDF or creating a revision PDF to preview.
 
Maybe it's possible to track completion if the spooler is bypassed and the print job is sent directly using the printer's IP address. IIRC, a batch script with a //NET USE LPTn: command was used to accomplish that.
Actually, I don't understand how this suggestion could work.
How would I sent an Access Report to a printer directly?
Maybe the printer could be configured to bypass the print queue with the "Print directly to printer" option as shown in your screenshot. But this would mean to reconfigure all potentially used printers to use this option, which might have side effects for all the other documents printed there.

And, even if the basic setup could be achieved, the core questions remains: How would I be able to detect when the report is printed?
(I don't want to track completion of the print job, just knowing if the report was sent to the printer is relevant to me.)
 
Have you considered always sending the report to PDF and presenting the PDF as the preview.
I haven't.
Your suggestion would probably solve the problem, but at what cost?
Printing to PDF and displaying the PDF as preview will be much, much slower than just opening the report in preview, even if I use a webbrowser control to display the PDF instead of an external PDF viewer.
Users will be very confused: Why is this report preview looking and working so differently from all the other report previews in the application? - To make the confusion worse: Almost all reports are exclusively printed to PDF, except the one this thread is about, which is printed on paper.
 
Actually, I don't understand how this suggestion could work.
How would I sent an Access Report to a printer directly?
Maybe the printer could be configured to bypass the print queue with the "Print directly to printer" option as shown in your screenshot. But this would mean to reconfigure all potentially used printers to use this option, which might have side effects for all the other documents printed there.

And, even if the basic setup could be achieved, the core questions remains: How would I be able to detect when the report is printed?
(I don't want to track completion of the print job, just knowing if the report was sent to the printer is relevant to me.)
Disregard bypassing spooler since you only want to know the job was received by the spooler.
 
This is always going to come back to this question: "What - and where - is the measurable property?" If you cannot get feedback from the printer such as notification for advanced printers, there is no way to answer this question.
 
the core questions remains: How would I be able to detect when the report is printed?
(I don't want to track completion of the print job, just knowing if the report was sent to the printer is relevant to me.)
Your question and desire contradict each other. Anyway, send print jobs to the spooler. Your Access app can call WinAPI's to get a status from the printer server as to whether the job is queued for printing, currently printing, or cancelled. Once a print job has successfully completed printing, it will no longer appear in the queue.

PrintJobStatus.png
 
Would this be of any use?
Indeed it would. It includes the comparatively easy part of fetching print job info from the print queue. I added something similar as a fallback because the print spooler events API function behave somewhat unpredictably in regards to the data the can be retrieved with their events.

This is always going to come back to this question: "What - and where - is the measurable property?" If you cannot get feedback from the printer such as notification for advanced printers, there is no way to answer this question.
The tangible information is in the print queue (print spooler). Luckily it's not really the printer itself that needs to be interrogated for that information. It is in the windows print spooler already. This is very fortunate, because there is no need for "advanced printers". Basically every printer that has a Windows driver should be good enough. However, some printer drivers (e.g., "Microsoft Print to PDF") don't support the notifications from the spooler.

Meanwhile I built a proof of concept using mainly the Printer Change Notification Functions. These are a bunch of unwieldy beasts, but I finally managed to tame them. Currently I only got a couple of somewhat isolated code fragments implementing parts of the solution. I haven't integrated and tested them with an actual Access report yet. I also haven't had the opportunity to test with a print server on the network yet.
Nonetheless, it looks very promising. - I will report back, once I got a complete, integrated solution.
 
OK, I'm impressed. My only question is, given some remote installations, can you see the printer queues from the remote place that is printing (or vice versa, the remote printer queues from the local place that is printing)?
 
OK, I'm impressed. My only question is, given some remote installations, can you see the printer queues from the remote place that is printing (or vice versa, the remote printer queues from the local place that is printing)?
The screenshot in my last post is proof that you can see queues of remote printers. It shows the remote printer's intranet IP address.
 
Your question and desire contradict each other.
Sorry. That was a foreign language issue. I only noticed now that "is printed" is likely being read as "completed printing" while a literal translation to my language would be "is in the process of being printed".

Anyway, send print jobs to the spooler. Your Access app can call WinAPI's to get a status from the printer server as to whether the job is queued for printing, currently printing, or cancelled.
In theory you are right. The problem is that I need to know *when* to get the status from the print queue. Too frequent polling would waste resources and block the Access UI, while too infrequent polling might miss the report being in the queue.
To solve this problem, I'm utilizing the Change Notification functions.
 
I need to know *when* to get the status from the print queue. Too frequent polling would waste resources and block the Access UI, while too infrequent polling might miss the report being in the queue.
Use a timer to poll the status every 500 ticks (half second).You can set a limit of 10 seconds, (20 polls) using a loop. Play with the polling frequency and total time until you feel it's right.
 
I only noticed now that "is printed" is likely being read as "completed printing" while a literal translation to my language would be "is in the process of being printed".
The problem is that I need to know *when* to get the status from the print queue.
The answer to the modified question is, start asking immediately after you open the report object. Check for it in the appropriate print queue on a one-second timer loop until you see the job or you reach a time-out point when the report object has been closed for at least 10-15 seconds. Your comments about using CTRL/P to trigger printing from the Preview screen means you might not have a clear-cut event for when it gets sent out for printing. Therefore, you have to have that loop running during the time it COULD be requested by command or keyboard shortcut.

I don't care how many pages are in the job. Once it is in the queue, it will take at least a second or two to stage the job and feed the first page, so a one-second timer loop should be adequate. If the job is IN the print queue in ANY state except Error or Suspended or something like that, you made it to the point where it is committed to being printed. Unless you even want to catch cases where it gets canceled before it actually starts.
 
Try the code below that uses Windows Management Instrumentation through the GetObject function to detect the status of remote print jobs.

NOTE: If (lQueueStatus And &H80) = &H80 Then sStatus = sStatus & "Printing, "

Code:
Function GetRemotePrinterQueueStatus(strPrinterName As String, strRemoteComputer As String) As String
    Dim objWMIService As Object
    Dim colPrinters As Object
    Dim objPrinter As Object
    Dim strStatus As String
 
    On Error GoTo ErrorHandler
 
    ' Connect to WMI on the remote computer
    Set objWMIService = GetObject("winmgmts:\\" & strRemoteComputer & "\root\cimv2")
 
    ' Query for the specific printer
    Set colPrinters = objWMIService.ExecQuery("SELECT * FROM Win32_Printer WHERE Name = '" & strPrinterName & "'")
 
    If colPrinters.Count > 0 Then
        For Each objPrinter In colPrinters
            ' Get the QueueStatus property
            ' You can bitwise AND this with specific PrintQueueStatus values
            ' to check for conditions like PaperProblem, NoToner, Error, etc.
            ' For simplicity, we'll just return the raw status for now.
            strStatus = GetPrinterQueueStatusDescription(objPrinter.QueueStatus)
            Exit For ' Assuming unique printer names
        Next
    Else
        strStatus = "Printer not found on remote computer."
    End If
 
    GetRemotePrinterQueueStatus = strStatus
 
ExitFunction:
    Set objPrinter = Nothing
    Set colPrinters = Nothing
    Set objWMIService = Nothing
    Exit Function

ErrorHandler:
    GetRemotePrinterQueueStatus = "Error: " & Err.Description
    Resume ExitFunction
End Function

Private Function GetPrinterQueueStatusDescription(ByVal lQueueStatus As Long) As String
    Dim sStatus As String
    sStatus = ""

    If (lQueueStatus And &H1) = &H1 Then sStatus = sStatus & "Paused, "
    If (lQueueStatus And &H2) = &H2 Then sStatus = sStatus & "Error, "
    If (lQueueStatus And &H4) = &H4 Then sStatus = sStatus & "Pending Deletion, "
    If (lQueueStatus And &H8) = &H8 Then sStatus = sStatus & "Paper Problem, "
    If (lQueueStatus And &H10) = &H10 Then sStatus = sStatus & "Offline, "
    If (lQueueStatus And &H20) = &H20 Then sStatus = sStatus & "I/O Active, "
    If (lQueueStatus And &H40) = &H40 Then sStatus = sStatus & "Busy, "
    If (lQueueStatus And &H80) = &H80 Then sStatus = sStatus & "Printing, "
    If (lQueueStatus And &H100) = &H100 Then sStatus = sStatus & "Output Bin Full, "
    If (lQueueStatus And &H200) = &H200 Then sStatus = sStatus & "Not Available, "
    If (lQueueStatus And &H400) = &H400 Then sStatus = sStatus & "Waiting, "
    If (lQueueStatus And &H800) = &H800 Then sStatus = sStatus & "Processing, "
    If (lQueueStatus And &H1000) = &H1000 Then sStatus = sStatus & "Initializing, "
    If (lQueueStatus And &H2000) = &H2000 Then sStatus = sStatus & "Warming Up, "
    If (lQueueStatus And &H4000) = &H4000 Then sStatus = sStatus & "Toner Low, "
    If (lQueueStatus And &H8000) = &H8000 Then sStatus = sStatus & "No Toner, "
    If (lQueueStatus And &H10000) = &H10000 Then sStatus = sStatus & "Page Punt, "
    If (lQueueStatus And &H20000) = &H20000 Then sStatus = sStatus & "User Intervention Required, "
    If (lQueueStatus And &H40000) = &H40000 Then sStatus = sStatus & "Out of Memory, "
    If (lQueueStatus And &H80000) = &H80000 Then sStatus = sStatus & "Door Open, "
    If (lQueueStatus And &H100000) = &H100000 Then sStatus = sStatus & "Server Unknown, "
    If (lQueueStatus And &H200000) = &H200000 Then sStatus = sStatus & "Power Off, "
    If (lQueueStatus And &H400000) = &H400000 Then sStatus = sStatus & "Client Error, "
    If (lQueueStatus And &H800000) = &H800000 Then sStatus = sStatus & "Spooling, "

    If Len(sStatus) > 0 Then
        GetPrinterQueueStatusDescription = Left(sStatus, Len(sStatus) - 2) ' Remove trailing ", "
    Else
        GetPrinterQueueStatusDescription = "Ready" ' Default if no specific flags are set
    End If
End Function

'----------------------------------
'Usage Example:

Sub TestPrinterStatus()
    Dim sPrinterStatus As String
 
    ' Replace "YourPrinterName" with the actual name of your network printer
    ' Replace "RemoteComputerNameOrIP" with the name or IP of the computer hosting the printer queue
    sPrinterStatus = GetRemotePrinterQueueStatus("YourPrinterName", "RemoteComputerNameOrIP")
 
    MsgBox "Printer Queue Status: " & sPrinterStatus
End Sub

Considerations:

Permissions:

The user running the Access database must have appropriate permissions on the remote computer to query WMI information.

Firewall:
The firewall on the remote computer must allow WMI traffic.

Printer Name:
The strPrinterName argument must exactly match the printer name as configured on the remote machine.

Error Handling:
The above code includes basic error handling, but you may want to expand upon it for more robust error management.

IP Printer:
While you provide the remote computer's name or IP, the printer itself could be an IP-based printer connected to that remote computer. The above code queries the status of the printer queue on the remote computer, which reflects the overall status of that printer.
 
Last edited:

Users who are viewing this thread

  • Back
    Top Bottom