Link to home
Start Free TrialLog in
Avatar of jlbryant
jlbryant

asked on

Page count

Hello, This has been bugging me for days, I have several computers on a network that many people use. I have fell into a problem where people are printing many pages with out really knowin how many pages they are fixing to print. SO I want to create a little app that when the press the print button, it will pop up with a msgbox or somthing and tell them how many pages they are about to print and give them an option to continue or not if they continue it will print if they don't it will not continue printing.
Avatar of nffvrxqgrcfqvvc
nffvrxqgrcfqvvc

'Make a CLASS MODULE  add the following code
'------------------------------------------------------
'Make SURE YOU NAME THE CLASS MODULE!

NAME CLASS MODULE:           clsPrintDialog

''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''

Option Explicit

' --- API CONSTANTS
'
Private Const CCHDEVICENAME = 32
Private Const CCHFORMNAME = 32
Private Const GMEM_FIXED = &H0
Private Const GMEM_MOVEABLE = &H2
Private Const GMEM_ZEROINIT = &H40
Private Const DM_DUPLEX = &H1000&
Private Const DM_ORIENTATION = &H1&
'
' --- API TYPES DEFINITION
'
Private Type PRINTDLG_TYPE
  lStructSize As Long
  hwndOwner As Long
  hDevMode As Long
  hDevNames As Long
  hdc As Long
  Flags As Long
  nFromPage As Integer
  nToPage As Integer
  nMinPage As Integer
  nMaxPage As Integer
  nCopies As Integer
  hInstance As Long
  lCustData As Long
  lpfnPrintHook As Long
  lpfnSetupHook As Long
  lpPrintTemplateName As String
  lpSetupTemplateName As String
  hPrintTemplate As Long
  hSetupTemplate As Long
End Type
Private Type DEVNAMES_TYPE
  wDriverOffset As Integer
  wDeviceOffset As Integer
  wOutputOffset As Integer
  wDefault As Integer
  extra As String * 100
End Type
Private Type DEVMODE_TYPE
  dmDeviceName As String * CCHDEVICENAME
  dmSpecVersion As Integer
  dmDriverVersion As Integer
  dmSize As Integer
  dmDriverExtra As Integer
  dmFields As Long
  dmOrientation As Integer
  dmPaperSize As Integer
  dmPaperLength As Integer
  dmPaperWidth As Integer
  dmScale As Integer
  dmCopies As Integer
  dmDefaultSource As Integer
  dmPrintQuality As Integer
  dmColor As Integer
  dmDuplex As Integer
  dmYResolution As Integer
  dmTTOption As Integer
  dmCollate As Integer
  dmFormName As String * CCHFORMNAME
  dmUnusedPadding As Integer
  dmBitsPerPel As Integer
  dmPelsWidth As Long
  dmPelsHeight As Long
  dmDisplayFlags As Long
  dmDisplayFrequency As Long
End Type
'
' --- API DECLARATIONS
'
Private Declare Function PrintDialog Lib "comdlg32.dll" Alias "PrintDlgA" _
                         (pPrintdlg As PRINTDLG_TYPE) As Long
Private Declare Sub CopyMemory Lib "kernel32" Alias "RtlMoveMemory" _
                    (hpvDest As Any, _
                     hpvSource As Any, _
                     ByVal cbCopy As Long)
Private Declare Function GlobalLock Lib "kernel32" (ByVal hMem As Long) As Long
Private Declare Function GlobalUnlock Lib "kernel32" _
                         (ByVal hMem As Long) As Long
Private Declare Function GlobalAlloc Lib "kernel32" _
                         (ByVal wFlags As Long, _
                          ByVal dwBytes As Long) As Long
Private Declare Function GlobalFree Lib "kernel32" (ByVal hMem As Long) As Long
'
' --- PUBLIC ENUM
'
Public Enum PrinterConstants
  cdlPDAllPages = &H0
  cdlPDCollate = &H10
  cdlPDDisablePrintToFile = &H80000
  cdlPDHelpButton = &H800
  cdlPDHidePrintToFile = &H100000
  cdlPDNoPageNums = &H8
  cdlPDNoSelection = &H4
  cdlPDNoWarning = &H80
  cdlPDPageNums = &H2
  cdlPDPrintSetup = &H40
  cdlPDPrintToFile = &H20
  cdlPDReturnDC = &H100
  cdlPDReturnDefault = &H400
  cdlPDReturnIC = &H200
  cdlPDSelection = &H1
  cdlPDUseDevModeCopies = &H40000
End Enum
Public Enum ErrorConstants
  cdlCancel = 32755
End Enum
'
' --- PRIVATE VARIABLES
'
Private intMinPage As Integer  ' Local copy of Min
Private intMaxPage As Integer  ' Local copy of Max
Private intFromPage As Integer ' Local copy of FromPage
Private intToPage As Integer   ' Local copy of ToPage
' N.B. 0 >= Min >= FromPage >= ToPage >= Max
'      If Max=0 then no limits.
'
' --- PUBLIC VARIABLES
'
Public Flags As PrinterConstants
Public CancelError As Boolean
'
' -- INITIALIZE
'
Private Sub Class_Initialize()
  intMinPage = 0
  intMaxPage = 0
  intFromPage = 0
  intToPage = 0
  CancelError = False
End Sub
'
' -- PUBLIC MEMBERS
'
Property Get Min() As Integer
  Min = intMinPage
End Property
Property Let Min(ByVal intNewValue As Integer)
  intNewValue = IIf(intNewValue > 0, intNewValue, 0)
  intMinPage = intNewValue
  If intNewValue > intFromPage Then _
    intFromPage = intNewValue
  If intNewValue > intToPage Then _
    intToPage = intNewValue
  If intNewValue > intMaxPage Then _
    intMaxPage = intNewValue
End Property
Property Get FromPage() As Integer
  FromPage = intFromPage
End Property
Property Let FromPage(ByVal intNewValue As Integer)
  intNewValue = IIf(intNewValue > 0, intNewValue, 0)
  intFromPage = intNewValue
  If intNewValue > intToPage Then _
    intToPage = intNewValue
  If intNewValue > intMaxPage Then _
    intMaxPage = intNewValue
  If intNewValue < intMinPage Then _
    intMinPage = intNewValue
End Property
Property Get ToPage() As Integer
  ToPage = intToPage
End Property
Property Let ToPage(ByVal intNewValue As Integer)
  intNewValue = IIf(intNewValue > 0, intNewValue, 0)
  intToPage = intNewValue
  If intNewValue > intMaxPage Then _
    intMaxPage = intNewValue
  If intNewValue < intFromPage Then _
    intFromPage = intNewValue
  If intNewValue < intMinPage Then _
    intMinPage = intNewValue
End Property
Property Get Max() As Integer
  Max = intMaxPage
End Property
Property Let Max(ByVal intNewValue As Integer)
  intNewValue = IIf(intNewValue > 0, intNewValue, 0)
  intMaxPage = intNewValue
  If intNewValue < intToPage Then _
    intToPage = intNewValue
  If intNewValue < intFromPage Then _
    intFromPage = intNewValue
  If intNewValue < intMinPage Then _
    intMinPage = intNewValue
End Property
Public Function ShowPrinter() As Boolean
Dim PrintDlg As PRINTDLG_TYPE
Dim DevMode As DEVMODE_TYPE
Dim DevName As DEVNAMES_TYPE
Dim lpDevMode As Long, lpDevName As Long
Dim intReturn As Integer
Dim objPrinter As Printer
Dim strNewPrinterName As String
Dim blnCancel   As Boolean
  blnCancel = False
  ' Use PrintDialog to get the handle to a memory
  ' block with a DevMode and DevName structures
  With PrintDlg
    .lStructSize = Len(PrintDlg)
    .hwndOwner = 0
    .Flags = Flags
    .nMinPage = intMinPage
    .nFromPage = intFromPage
    .nToPage = intToPage
    .nMaxPage = intMaxPage
  End With
  'Set the current orientation and duplex setting
  DevMode.dmDeviceName = Printer.DeviceName
  DevMode.dmSize = Len(DevMode)
  DevMode.dmFields = DM_ORIENTATION Or DM_DUPLEX
  DevMode.dmOrientation = Printer.Orientation
  On Error Resume Next
  DevMode.dmDuplex = Printer.Duplex
  On Error GoTo 0
  'Allocate memory for the initialization hDevMode structure
  'and copy the settings gathered above into this memory
  PrintDlg.hDevMode = GlobalAlloc(GMEM_MOVEABLE Or _
                                  GMEM_ZEROINIT, Len(DevMode))
  lpDevMode = GlobalLock(PrintDlg.hDevMode)
  If lpDevMode > 0 Then
    CopyMemory ByVal lpDevMode, DevMode, Len(DevMode)
    intReturn = GlobalUnlock(lpDevMode)
  End If
  'Set the current driver, device, and port name strings
  With DevName
    .wDriverOffset = 8
    .wDeviceOffset = .wDriverOffset + 1 + Len(Printer.DriverName)
    .wOutputOffset = .wDeviceOffset + 1 + Len(Printer.Port)
    .wDefault = 0
  End With
  With Printer
    DevName.extra = .DriverName & Chr(0) & _
                    .DeviceName & Chr(0) & .Port & Chr(0)
  End With
  'Allocate memory for the initial hDevName structure
  'and copy the settings gathered above into this memory
  PrintDlg.hDevNames = GlobalAlloc(GMEM_MOVEABLE Or _
                                   GMEM_ZEROINIT, Len(DevName))
  lpDevName = GlobalLock(PrintDlg.hDevNames)
  If lpDevName > 0 Then
    CopyMemory ByVal lpDevName, DevName, Len(DevName)
    intReturn = GlobalUnlock(lpDevName)
  End If
  'Call the print dialog up and let the user make changes
  If PrintDialog(PrintDlg) Then
    'First get the DevName structure.
    lpDevName = GlobalLock(PrintDlg.hDevNames)
    CopyMemory DevName, ByVal lpDevName, 45
    intReturn = GlobalUnlock(lpDevName)
    With PrintDlg
      Flags = .Flags
      intFromPage = .nFromPage
      intToPage = .nToPage
    End With
     GlobalFree PrintDlg.hDevNames
    'Next get the DevMode structure and set the printer
    'properties appropriately
    lpDevMode = GlobalLock(PrintDlg.hDevMode)
    CopyMemory DevMode, ByVal lpDevMode, Len(DevMode)
    intReturn = GlobalUnlock(PrintDlg.hDevMode)
    GlobalFree PrintDlg.hDevMode
    strNewPrinterName = UCase$(Left(DevMode.dmDeviceName, _
                        InStr(DevMode.dmDeviceName, Chr$(0)) - 1))
    If Printer.DeviceName <> strNewPrinterName Then
      For Each objPrinter In Printers
        If UCase$(objPrinter.DeviceName) = strNewPrinterName Then _
          Set Printer = objPrinter
      Next
    End If
    On Error Resume Next
    'Set printer object properties according to selections made
    'by user
    With Printer
      .Copies = DevMode.dmCopies
      .Duplex = DevMode.dmDuplex
      .Orientation = DevMode.dmOrientation
    End With
    On Error GoTo 0
  Else
    GlobalFree PrintDlg.hDevMode
    GlobalFree PrintDlg.hDevNames
    blnCancel = True
    If CancelError Then _
      Err.Raise cdlCancel, "LM PrintDialog", "Cancel."
  End If
  ShowPrinter = Not blnCancel
End Function

''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
'ADD THE FOLLOWING TO A FORM
''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''

Sub PrintPages()
Dim P As New clsPrintDialog
  P.Flags = cdlPDPageNums + cdlPDDisablePrintToFile + cdlPDNoSelection
  P.Min = 1
  P.FromPage = 3 'from page
  P.ToPage = 5 'to pages
  P.Max = 100
  P.ShowPrinter
  Debug.Print Printer.DeviceName
  Debug.Print Printer.Copies
  Debug.Print P.FromPage
  Debug.Print P.ToPage
 
End Sub



Call PrintPages
Avatar of aikimark
I think you will have to create an virtual or custom print queue server.  The only way to tell how many pages are in a print job is to let it finish spooling.  I assume you want this feature for all network attached print jobs.  I'm not sure this can be done with VB.
Avatar of jlbryant

ASKER

Well This is not what i want, If i am viewing a IE page and it contains 4 pages, and i goto the file then print button and whant to print, I need it to tell me it is 4 pages before i print it.
<<Well This is not what i want...>>
How do you propose to know how many pages are in a printed document from ANY application program before the document has finished?

Once the page is spooled, you can display a "Print Confirmation" form to the user that includes the number of pages in the queue.  The user may then choose to print/hold/cancel the actual printing of the document.  Your process would forward the queued document to the printer.  Of course, this confirmation might only be applied to documents larger than some number of pages.

Since I don't know the true purpose of your program, I can only address the technical issues.  You might be trying to address any one of the following concerns:
* users send big documents to a printer and prevent others from printing
* true cost of printing is not shared with users
* you want users to police themselves
* you want to restrict documents larger than some (corporate policy) limit from printing during normal business hours
* large documents should be send to optical media rather than being printed
* this is part of a page count chargeback scheme
* you want to discourage users from all printing
* you want to route large documents to a different printer
ASKER CERTIFIED SOLUTION
Avatar of nffvrxqgrcfqvvc
nffvrxqgrcfqvvc

Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial
In fact I just tested the project and it tells you how many pages are being printed in the printer spool!!!!

This is the answere you needed good luck!! :)
I just want to clarify that microsoft says in that article that pausing the printer might not work over the network printer, however I tested this on a network printer and it works regardless. :)
'Here are some additional references for printer usage.

http://www.merrioncomputing.com/Programming/WatchPrinter.htm

'to put a print job on hold / pause (from command line) cmd.exe or DOS command line

Net print \\computername\sharename /hold



I don't dispute what egl1044 has posted.  However, your question is one of counting print job pages before the printing begins and displaying the page count to the user.

Unless you buffer print jobs or replace the spooler, you can't count the pages.  The printer spooler options are generally:
* spool the print job vs print directly to the printer

* (If spooling): start printing after the first complete page spooled vs. start printing after ALL pages have been spooled.
Well all he needs to do is programmatically pause the print job, then get the page count from the textbox and display and use a message box to let the user either print all the pages or to cancel and delete the print job
egl1044,

My understanding of the problem is that this function needs to apply to every user printing to any network printer from any application.  How do you propose pausing every print job?

If a print job is paused while it is being spooled, does the spooling pause as well?

Also, direct printing will have to be prevented, since spooling is the only way of getting the accurate page count.