VB打印(二)类CPrinterInfo.cls

' *************************************************************************
'  Copyright ?001 Karl E. Peterson
'  All Rights Reserved, http://www.mvps.org/vb
' *************************************************************************
'  You are free to use this code within your own applications, but you
'  are expressly forbidden from selling or otherwise distributing this
'  source code, non-compiled, without prior written consent.
' *************************************************************************
Option Explicit

' Win32 API declares
Private Declare Function OpenPrinter Lib "winspool.drv" Alias "OpenPrinterA" (ByVal pPrinterName As String, phPrn As Long, pDefault As Any) As Long
Private Declare Function ClosePrinter Lib "winspool.drv" (ByVal hPrn As Long) As Long
Private Declare Function GetPrinter Lib "winspool.drv" Alias "GetPrinterA" (ByVal hPrinter As Long, ByVal Level As Long, pPrinter As Any, ByVal cbBuf As Long, pcbNeeded As Long) As Long
Private Declare Function SetPrinter Lib "winspool.drv" Alias "SetPrinterA" (ByVal hPrinter As Long, ByVal Level As Long, pPrinter As Any, ByVal Command As Long) As Long
Private Declare Function EnumPrinters Lib "winspool.drv" Alias "EnumPrintersA" (ByVal Flags As Long, ByVal name As String, ByVal Level As Long, pPrinterEnum As Any, ByVal cdBuf As Long, pcbNeeded As Long, pcReturned As Long) As Long
Private Declare Function PrinterProperties Lib "winspool.drv" (ByVal hWnd As Long, ByVal hPrinter As Long) As Long

Private Declare Function GetDefaultPrinter Lib "winspool.drv" Alias "GetDefaultPrinterA" (ByVal pszBuffer As String, pcchBuffer As Long) As Long
Private Declare Function SetDefaultPrinter Lib "winspool.drv" Alias "SetDefaultPrinterA" (ByVal pszPrinter As String) As Long
Private Declare Function GetProfileString Lib "kernel32" Alias "GetProfileStringA" (ByVal lpAppName As String, ByVal lpKeyName As Any, ByVal lpDefault As String, ByVal lpReturnedString As String, ByVal nSize As Long) As Long
Private Declare Function WriteProfileString Lib "kernel32" Alias "WriteProfileStringA" (ByVal lpszSection As String, ByVal lpszKeyName As String, ByVal lpszString As String) As Long
Private Declare Function SendMessageTimeout Lib "user32" Alias "SendMessageTimeoutA" (ByVal hWnd As Long, ByVal msg As Long, ByVal wParam As Long, ByVal lParam As Long, ByVal fuFlags As Long, ByVal uTimeout As Long, lpdwResult As Long) As Long

Private Declare Sub CopyMemory Lib "kernel32" Alias "RtlMoveMemory" (Destination As Any, Source As Any, ByVal Length As Long)
Private Declare Function lstrlenA Lib "kernel32" (ByVal lpString As Long) As Long
Private Declare Function FormatMessage Lib "kernel32" Alias "FormatMessageA" (ByVal dwFlags As Long, lpSource As Any, ByVal dwMessageId As Long, ByVal dwLanguageId As Long, ByVal lpBuffer As String, ByVal nSize As Long, Arguments As Long) As Long
Private Declare Function GetVersion Lib "kernel32" Alias "GetVersionA" (lpVersionInformation As Any) As Long
Private Declare Function GetVersionEx Lib "kernel32" Alias "GetVersionExA" (lpVersionInformation As Any) As Long

' Some calls need to know OS
Private Type OSVERSIONINFO
   dwOSVersionInfoSize As Long
   dwMajorVersion As Long
   dwMinorVersion As Long
   dwBuildNumber As Long
   dwPlatformId As Long
   szCSDVersion As String * 128
End Type

' Platform ID constants
Private Const VER_PLATFORM_WIN32s As Long = &H0
Private Const VER_PLATFORM_WIN32_WINDOWS As Long = &H1
Private Const VER_PLATFORM_WIN32_NT As Long = &H2

'  SendMessageTimeout values
Private Const SMTO_NORMAL = &H0
Private Const SMTO_BLOCK = &H1
Private Const SMTO_ABORTIFHUNG = &H2

' Used with SendMessageTimeout to tell all apps of changes
Private Const HWND_BROADCAST = &HFFFF&
Private Const WM_SETTINGCHANGE = &H1A

' Need defaults to OpenPrinter in some cases
Private Type PRINTER_DEFAULTS
   pDatatype As String
   pDevMode As Long
   pDesiredAccess As Long
End Type

Private Const STANDARD_RIGHTS_REQUIRED = &HF0000
Private Const PRINTER_ACCESS_ADMINISTER = &H4
Private Const PRINTER_ACCESS_USE = &H8
Private Const PRINTER_ALL_ACCESS = (STANDARD_RIGHTS_REQUIRED Or PRINTER_ACCESS_ADMINISTER Or PRINTER_ACCESS_USE)

' Used to retrieve last API error text.
Private Const FORMAT_MESSAGE_FROM_SYSTEM As Long = &H1000

' The data area passed to a system call is too small.
Private Const ERROR_INSUFFICIENT_BUFFER As Long = 122

' Used to indicate what to enumerate
Private Const PRINTER_ENUM_DEFAULT         As Long = &H1
Private Const PRINTER_ENUM_LOCAL           As Long = &H2
Private Const PRINTER_ENUM_CONNECTIONS     As Long = &H4
Private Const PRINTER_ENUM_FAVORITE        As Long = &H4
Private Const PRINTER_ENUM_NAME            As Long = &H8
Private Const PRINTER_ENUM_REMOTE          As Long = &H10
Private Const PRINTER_ENUM_SHARED          As Long = &H20
Private Const PRINTER_ENUM_NETWORK         As Long = &H40

' Printer control codes
Private Const PRINTER_CONTROL_PAUSE        As Long = 1
Private Const PRINTER_CONTROL_RESUME       As Long = 2
Private Const PRINTER_CONTROL_PURGE        As Long = 3
Private Const PRINTER_CONTROL_SET_STATUS   As Long = 4

Private Enum PrinterControlCodes
   pcPause = PRINTER_CONTROL_PAUSE
   pcResume = PRINTER_CONTROL_RESUME
   pcPurge = PRINTER_CONTROL_PURGE
End Enum

' Printer status flags used with PRINTER_INFORMATION_2
Private Const PRINTER_STATUS_READY              As Long = &H0
Private Const PRINTER_STATUS_PAUSED             As Long = &H1
Private Const PRINTER_STATUS_ERROR              As Long = &H2
Private Const PRINTER_STATUS_PENDING_DELETION   As Long = &H4
Private Const PRINTER_STATUS_PAPER_JAM          As Long = &H8
Private Const PRINTER_STATUS_PAPER_OUT          As Long = &H10
Private Const PRINTER_STATUS_MANUAL_FEED        As Long = &H20
Private Const PRINTER_STATUS_PAPER_PROBLEM      As Long = &H40
Private Const PRINTER_STATUS_OFFLINE            As Long = &H80
Private Const PRINTER_STATUS_IO_ACTIVE          As Long = &H100
Private Const PRINTER_STATUS_BUSY               As Long = &H200
Private Const PRINTER_STATUS_PRINTING           As Long = &H400
Private Const PRINTER_STATUS_OUTPUT_BIN_FULL    As Long = &H800
Private Const PRINTER_STATUS_NOT_AVAILABLE      As Long = &H1000
Private Const PRINTER_STATUS_WAITING            As Long = &H2000
Private Const PRINTER_STATUS_PROCESSING         As Long = &H4000
Private Const PRINTER_STATUS_INITIALIZING       As Long = &H8000
Private Const PRINTER_STATUS_WARMING_UP         As Long = &H10000
Private Const PRINTER_STATUS_TONER_LOW          As Long = &H20000
Private Const PRINTER_STATUS_NO_TONER           As Long = &H40000
Private Const PRINTER_STATUS_PAGE_PUNT          As Long = &H80000
Private Const PRINTER_STATUS_USER_INTERVENTION  As Long = &H100000
Private Const PRINTER_STATUS_OUT_OF_MEMORY      As Long = &H200000
Private Const PRINTER_STATUS_DOOR_OPEN          As Long = &H400000
Private Const PRINTER_STATUS_SERVER_UNKNOWN     As Long = &H800000
Private Const PRINTER_STATUS_POWER_SAVE         As Long = &H1000000

Public Enum PrinterStatusCodes
   psReady = PRINTER_STATUS_READY
   psPaused = PRINTER_STATUS_PAUSED
   psError = PRINTER_STATUS_ERROR
   psPendingDeletion = PRINTER_STATUS_PENDING_DELETION
   psPaperJam = PRINTER_STATUS_PAPER_JAM
   psPaperOut = PRINTER_STATUS_PAPER_OUT
   psManualFeed = PRINTER_STATUS_MANUAL_FEED
   psPaperProblem = PRINTER_STATUS_PAPER_PROBLEM
   psOffline = PRINTER_STATUS_OFFLINE
   psIoActive = PRINTER_STATUS_IO_ACTIVE
   psBusy = PRINTER_STATUS_BUSY
   psPrinting = PRINTER_STATUS_PRINTING
   psOutputBinFull = PRINTER_STATUS_OUTPUT_BIN_FULL
   psNotAvailable = PRINTER_STATUS_NOT_AVAILABLE
   psWaiting = PRINTER_STATUS_WAITING
   psProcessing = PRINTER_STATUS_PROCESSING
   psInitializing = PRINTER_STATUS_INITIALIZING
   psWarmingUp = PRINTER_STATUS_WARMING_UP
   psTonerLow = PRINTER_STATUS_TONER_LOW
   psNoToner = PRINTER_STATUS_NO_TONER
   psPagePrint = PRINTER_STATUS_PAGE_PUNT
   psUserIntervention = PRINTER_STATUS_USER_INTERVENTION
   psOutOfMemory = PRINTER_STATUS_OUT_OF_MEMORY
   psDoorOpen = PRINTER_STATUS_DOOR_OPEN
   psServerUnknown = PRINTER_STATUS_SERVER_UNKNOWN
End Enum
  
' Printer attribute flags used with PRINTER_INFORMATION_2
Private Const PRINTER_ATTRIBUTE_QUEUED            As Long = &H1
Private Const PRINTER_ATTRIBUTE_DIRECT            As Long = &H2
Private Const PRINTER_ATTRIBUTE_DEFAULT           As Long = &H4
Private Const PRINTER_ATTRIBUTE_SHARED            As Long = &H8
Private Const PRINTER_ATTRIBUTE_NETWORK           As Long = &H10
Private Const PRINTER_ATTRIBUTE_HIDDEN            As Long = &H20
Private Const PRINTER_ATTRIBUTE_LOCAL             As Long = &H40
Private Const PRINTER_ATTRIBUTE_ENABLE_DEVQ       As Long = &H80
Private Const PRINTER_ATTRIBUTE_KEEPPRINTEDJOBS   As Long = &H100
Private Const PRINTER_ATTRIBUTE_DO_COMPLETE_FIRST As Long = &H200
Private Const PRINTER_ATTRIBUTE_WORK_OFFLINE      As Long = &H400
Private Const PRINTER_ATTRIBUTE_ENABLE_BIDI       As Long = &H800
Private Const PRINTER_ATTRIBUTE_RAW_ONLY          As Long = &H1000
Private Const PRINTER_ATTRIBUTE_PUBLISHED         As Long = &H2000

Public Enum PrinterAttributeCodes
   paQueued = PRINTER_ATTRIBUTE_QUEUED
   paDirect = PRINTER_ATTRIBUTE_DIRECT
   paDefault = PRINTER_ATTRIBUTE_DEFAULT
   paShared = PRINTER_ATTRIBUTE_SHARED
   paNetwork = PRINTER_ATTRIBUTE_NETWORK
   paHidden = PRINTER_ATTRIBUTE_HIDDEN
   paLocal = PRINTER_ATTRIBUTE_LOCAL
   paEnableDevQ
End Enum

' VB5-friendly structure used to cache the values in this class.
Private Type PrinterInfo2
   pServerName As String
   pPrinterName As String
   pShareName As String
   pPortName As String
   pDriverName As String
   pComment As String
   pLocation As String
   pDevMode As Long 'DEVMODE
   pSepFile As String
   pPrintProcessor As String
   pDatatype As String
   pParameters As String
   pSecurityDescriptor As Long 'SECURITY_DESCRIPTOR
   Attributes As Long
   Priority As Long
   DefaultPriority As Long
   StartTime As Long
   UntilTime As Long
   Status As Long
   cJobs As Long
   AveragePPM As Long
End Type

' Structure used to obtain the data from Windows.
Private Type PRINTER_INFO_2
   pServerName As Long
   pPrinterName As Long
   pShareName As Long
   pPortName As Long
   pDriverName As Long
   pComment As Long
   pLocation As Long
   pDevMode As Long 'DEVMODE
   pSepFile As Long
   pPrintProcessor As Long
   pDatatype As Long
   pParameters As Long
   pSecurityDescriptor As Long 'SECURITY_DESCRIPTOR
   Attributes As Long
   Priority As Long
   DefaultPriority As Long
   StartTime As Long
   UntilTime As Long
   Status As Long
   cJobs As Long
   AveragePPM As Long
End Type

' Member variables
Private m_pi2 As PrinterInfo2
Private m_pi2Null As PrinterInfo2
Private m_dm As CDevMode
Private m_jobs As CPrinterJobs
Private m_DevName As String
Private m_DispName As String
Private m_GetPrinterError As Long

' *********************************************
'  Initialize/Terminate
' *********************************************
Private Sub Class_Initialize()
   ' Initialize member objects
   Set m_dm = New CDevMode
   Set m_jobs = New CPrinterJobs
End Sub

Private Sub Class_Terminate()
   ' Release member objects
   Set m_dm = Nothing
   Set m_jobs = Nothing
End Sub

' *********************************************
'  Public Properties (Read/Write)
' *********************************************
Public Property Get DeviceName() As String
   ' This is the name returned by a VB Printer
   ' object's .DeviceName property
   DeviceName = m_DevName
End Property

Public Property Let DeviceName(ByVal NewVal As String)
   m_DevName = NewVal
   Call Refresh
   'm_jobs.DeviceName = m_DevName
   'm_jobs.Refresh
End Property

Public Property Get IsDefault() As Boolean
   Dim DefPrn As String
   ' PRINTER_ATTRIBUTE_DEFAULT only works to *set* default.
   DefPrn = DefaultPrinterName
   IsDefault = (UCase$(DefPrn) = UCase$(m_DevName))
End Property

Public Property Let IsDefault(ByVal NewVal As Boolean)
   ' Really makes no sense to react to a new value
   ' of False, as something must be default.
   If NewVal = True Then
      Call DefaultPrinterSet
   End If
End Property

' *********************************************
'  Public Properties (Derived, Read-Only)
' *********************************************
Public Property Get CanAdminister() As Boolean
   Dim hPrn As Long
   Dim pd As PRINTER_DEFAULTS
   ' Try to open handle to printer, requesting
   ' administrative priviledges.
   pd.pDesiredAccess = PRINTER_ACCESS_ADMINISTER
   Call OpenPrinter(m_DevName, hPrn, pd)
   CanAdminister = (hPrn <> 0)
   Call ClosePrinter(hPrn)
End Property

Public Property Get DisplayName() As String
   DisplayName = m_DispName
End Property

Public Property Get GetPrinterError() As Long
   ' If the call to GetPrinter doesn't succeed,
   ' client needs to know LastDllError.
   GetPrinterError = m_GetPrinterError
End Property

Public Property Get IsPaused() As Boolean
   ' Is this printer paused?
   IsPaused = CBool(m_pi2.Status And PRINTER_STATUS_PAUSED)
End Property

Public Property Get IsShared() As Boolean
   ' Is this printer shared?
   IsShared = CBool(m_pi2.Attributes And PRINTER_ATTRIBUTE_SHARED)
End Property

Public Property Get IsToFile() As Boolean
   If InStr(m_pi2.pPortName, "FILE:") Then
      IsToFile = True
   End If
End Property

Public Property Get IsLocal() As Boolean
   ' Is this a local printer?
   IsLocal = CBool(m_pi2.Attributes And PRINTER_ATTRIBUTE_LOCAL)
End Property

Public Property Get IsNetwork() As Boolean
   ' Is this a network printer?
   IsNetwork = CBool(m_pi2.Attributes And PRINTER_ATTRIBUTE_NETWORK)
End Property

Public Property Get StatusText() As String
   If m_GetPrinterError Then
      StatusText = ApiErrorText(m_GetPrinterError)
   Else
      Select Case m_pi2.Status
         Case PRINTER_STATUS_READY
            StatusText = "Ready"
         Case PRINTER_STATUS_PAUSED
            StatusText = "Paused"
         Case PRINTER_STATUS_ERROR
            StatusText = "Error"
         Case PRINTER_STATUS_PENDING_DELETION
            StatusText = "Deleting..."
         Case PRINTER_STATUS_PAPER_JAM
            StatusText = "Paper Jam"
         Case PRINTER_STATUS_PAPER_OUT
            StatusText = "Paper Out"
         Case PRINTER_STATUS_MANUAL_FEED
            StatusText = "Manual Feed Required"
         Case PRINTER_STATUS_PAPER_PROBLEM
            StatusText = "Paper Problem"
         Case PRINTER_STATUS_OFFLINE
            StatusText = "Offline"
         Case PRINTER_STATUS_IO_ACTIVE
            StatusText = "Downloading Job"
         Case PRINTER_STATUS_BUSY
            StatusText = "Busy"
         Case PRINTER_STATUS_PRINTING
            StatusText = "Printing"
         Case PRINTER_STATUS_OUTPUT_BIN_FULL
            StatusText = "Output Bill Full"
         Case PRINTER_STATUS_NOT_AVAILABLE
            StatusText = "Not Available"
         Case PRINTER_STATUS_WAITING
            StatusText = "Waiting"
         Case PRINTER_STATUS_PROCESSING
            StatusText = "Processing Job"
         Case PRINTER_STATUS_INITIALIZING
            StatusText = "Initializing"
         Case PRINTER_STATUS_WARMING_UP
            StatusText = "Warming Up"
         Case PRINTER_STATUS_TONER_LOW
            StatusText = "Toner Low"
         Case PRINTER_STATUS_NO_TONER
            StatusText = "Toner Out"
         Case PRINTER_STATUS_PAGE_PUNT
            StatusText = "Page too Complex"
         Case PRINTER_STATUS_USER_INTERVENTION
            StatusText = "User Intervention Required"
         Case PRINTER_STATUS_OUT_OF_MEMORY
            StatusText = "Out of Memory"
         Case PRINTER_STATUS_DOOR_OPEN
            StatusText = "Door Open"
         Case PRINTER_STATUS_SERVER_UNKNOWN
            StatusText = "Unable to connect"
         Case PRINTER_STATUS_POWER_SAVE
            StatusText = "Power Save Mode"
         Case Else
            StatusText = Hex$(m_pi2.Status)
      End Select
   End If
End Property

' *********************************************
'  Public Properties (Read-Only)
' *********************************************
Public Property Get Attributes() As Long
   ' Specifies the printer attributes. This member can be any
   ' reasonable combination of the PRINTER_ATTRIBUTE_* values.
   Attributes = m_pi2.Attributes
End Property

Public Property Get AveragePPM() As Long
   ' Specifies the average number of pages per minute
   ' that have been printed on the printer.
   AveragePPM = m_pi2.AveragePPM
End Property

Public Property Get Comment() As String
   ' A string that provides a brief description of
   ' the printer.
   Comment = m_pi2.pComment
End Property

Public Property Get Datatype() As String
   ' A string that specifies the data type used to record
   ' the print job. You can use the EnumPrintProcessorDatatypes
   ' function to obtain a list of data types supported by a
   ' specific print processor.
   Datatype = m_pi2.pDatatype
End Property

Public Property Get DefaultPriority() As Long
   ' Specifies the default priority value
   ' assigned to each print job.
   DefaultPriority = m_pi2.DefaultPriority
End Property

Public Property Get DevMode() As CDevMode
   ' Pointer to a DEVMODE structure that defines default printer
   ' data such as the paper orientation and the resolution.
   Set DevMode = m_dm
End Property

Public Property Get DriverName() As String
   ' A string that specifies the name of the printer driver.
   DriverName = m_pi2.pDriverName
End Property

Public Property Get Jobs() As CPrinterJobs
   ' Return collection of printer jobs
   Set Jobs = m_jobs
End Property

Public Property Get Location() As String
   ' A string that specifies the physical location of
   ' the printer (for example, "Bldg. 38, Room 1164").
   Location = m_pi2.pLocation
End Property

Public Property Get Parameters() As String
   ' A string that specifies the default print-processor
   ' parameters.
   Parameters = m_pi2.pParameters
End Property

Public Property Get PortName() As String
   ' A string that identifies the port(s) used to transmit data
   ' to the printer. If a printer is connected to more than one
   ' port, the names of each port must be separated by commas
   ' (for example, "LPT1:,LPT2:,LPT3:").
   ' Windows 95: This member can specify only one port because
   ' multiple ports per printer are not supported.
   PortName = m_pi2.pPortName
End Property

Public Property Get PrinterName() As String
   ' A string that specifies the name of the printer.
   PrinterName = m_pi2.pPrinterName
End Property

Public Property Get PrintProcessor() As String
   ' A string that specifies the name of the print processor
   ' used by the printer. You can use the EnumPrintProcessors
   ' function to obtain a list of print processors installed
   ' on a server.
   PrintProcessor = m_pi2.pPrintProcessor
End Property

Public Property Get Priority() As Long
   ' Specifies a priority value that the spooler
   ' uses to route print jobs.
   Priority = m_pi2.Priority
End Property

Public Property Get SeparatorPageFile() As String
   ' A string that specifies the name of the file used to create
   ' the separator page. This page is used to separate print jobs
   ' sent to the printer.
   SeparatorPageFile = m_pi2.pSepFile
End Property

Public Property Get ServerName() As String
   ' A string identifying the server that controls the printer.
   ' If this string is NULL, the printer is controlled locally.
   ServerName = m_pi2.pServerName
End Property

Public Property Get ShareName() As String
   ' A string that identifies the sharepoint for the printer.
   ' (This string is used only if the PRINTER_ATTRIBUTE_SHARED
   ' constant was set for the Attributes member.)
   ShareName = m_pi2.pShareName
End Property

Public Property Get StartTime() As Long
   ' Specifies the earliest time at which the printer
   ' will print a job. This value is expressed as
   ' minutes elapsed since 12:00 AM GMT.
   StartTime = m_pi2.StartTime
End Property

Public Property Get Status() As Long
   ' Specifies the printer status. This member can be any
   ' reasonable combination of the PRINTER_STATUS_* values.
   Status = m_pi2.Status
End Property

Public Property Get UntilTime() As Long
   ' Specifies the latest time at which the printer
   ' will print a job. This value is expressed as
   ' minutes elapsed since 12:00 AM GMT.
   UntilTime = m_pi2.UntilTime
End Property

' *********************************************
'  Public Methods
' *********************************************
Public Function ControlPause() As Boolean
   ' Attempt to pause printing
   ControlPause = SendControl(pcPause)
End Function

Public Function ControlPurge() As Boolean
   ' Attempt to purge all print jobs
   ControlPurge = SendControl(pcPurge)
End Function

Public Function ControlResume() As Boolean
   ' Attempt to resume printing
   ControlResume = SendControl(pcResume)
End Function

Public Sub Refresh()
   Dim pi2 As PRINTER_INFO_2
   Dim hPrn As Long
   Dim Buffer() As Byte
   Dim BytesNeeded As Long
   Dim BytesUsed As Long
   Dim slash As Long
  
   ' Zero out cached values
   m_pi2 = m_pi2Null
   Set m_dm = New CDevMode
  
   ' Get handle to printer.
   Call OpenPrinter(m_DevName, hPrn, ByVal 0&)
   If hPrn Then
      ' Call once to get proper buffer size.
      Call GetPrinter(hPrn, 2, ByVal 0&, 0, BytesNeeded)
      If Err.LastDllError = ERROR_INSUFFICIENT_BUFFER Then
         ' Size buffer and get printer data.
         ReDim Buffer(0 To BytesNeeded - 1) As Byte
         If GetPrinter(hPrn, 2, Buffer(0), BytesNeeded, BytesUsed) Then
            ' Fill local structure with data/pointers.
            Call CopyMemory(pi2, Buffer(0), Len(pi2))
            ' Transfer string data to cached structure.
            m_pi2.pServerName = PointerToStringA(pi2.pServerName)
            m_pi2.pPrinterName = PointerToStringA(pi2.pPrinterName)
            m_pi2.pShareName = PointerToStringA(pi2.pShareName)
            m_pi2.pPortName = PointerToStringA(pi2.pPortName)
            m_pi2.pDriverName = PointerToStringA(pi2.pDriverName)
            m_pi2.pComment = PointerToStringA(pi2.pComment)
            m_pi2.pLocation = PointerToStringA(pi2.pLocation)
            m_pi2.pSepFile = PointerToStringA(pi2.pSepFile)
            m_pi2.pPrintProcessor = PointerToStringA(pi2.pPrintProcessor)
            m_pi2.pDatatype = PointerToStringA(pi2.pDatatype)
            m_pi2.pParameters = PointerToStringA(pi2.pParameters)
            ' Copy two sub-structure pointers.
            m_pi2.pDevMode = pi2.pDevMode
            m_pi2.pSecurityDescriptor = pi2.pSecurityDescriptor
            ' Fill DEVMODE substructure
            m_dm.Initialize m_pi2.pDevMode
            ' Sling remaining dword data to cached structure.
            ' Attributes begins at byte 52 in structure, so
            ' just copy last 32 bytes of structure directly.
            Call CopyMemory(m_pi2.Attributes, Buffer(52), 32)
         End If
         m_GetPrinterError = 0  'clear error value
      Else
         m_GetPrinterError = Err.LastDllError
      End If
      Call ClosePrinter(hPrn)
   End If
  
   ' Build display name, based on whether this
   ' is a network printer, defaulting to devname.
   m_DispName = m_DevName
   If CBool(m_pi2.Attributes And PRINTER_ATTRIBUTE_NETWORK) Then
      If Len(m_pi2.pServerName) > 2 Then
         If InStr(m_pi2.pServerName, "//") = 1 Then
            ' Find 3rd backslash.
            slash = InStr(3, m_pi2.pPrinterName, "/")
            If slash Then
               m_DispName = Mid$(m_pi2.pPrinterName, slash + 1) & _
                            " on " & Mid$(m_pi2.pServerName, 3)
            End If
         End If
      End If
   End If
  
   ' Update jobs collection
   If m_jobs.DeviceName <> m_DevName Then
      m_jobs.DeviceName = m_DevName
   Else
      m_jobs.Refresh
   End If
End Sub

Public Sub ShowPropertiesDialog(Optional ByVal hWndParent As Long = 0)
   Dim hPrn As Long
   Dim pd As PRINTER_DEFAULTS
   ' HOWTO: Open the Printer Properties Dialog
   ' http://support.microsoft.com/support/kb/articles/Q198/8/60.asp
   pd.pDatatype = vbNullString
   ' Try admin access first
   pd.pDesiredAccess = PRINTER_ALL_ACCESS
   If OpenPrinter(m_DevName, hPrn, pd) = 0 Then
      ' Not an admin, try reduced privileges
      pd.pDesiredAccess = STANDARD_RIGHTS_REQUIRED Or PRINTER_ACCESS_USE
      Call OpenPrinter(m_DevName, hPrn, pd)
   End If
   ' Show dialog, if we have a handle to printer
   If hPrn Then
      Call PrinterProperties(hWndParent, hPrn)
      Call ClosePrinter(hPrn)
   End If
End Sub

' *********************************************
'  Private Methods
' *********************************************
Private Function ApiErrorText(ByVal ErrNum As Long) As String
   Dim msg As String
   Dim nRet As Long

   msg = Space$(1024)
   nRet = FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM, ByVal 0&, ErrNum, 0&, msg, Len(msg), ByVal 0&)
   If nRet Then
      ApiErrorText = Left$(msg, nRet - 2) ' account for Cr/Lf
   Else
      ApiErrorText = "Error (" & ErrNum & ") not defined."
   End If
End Function

Private Function DefaultPrinterSet() As Boolean
   Dim os As OSVERSIONINFO

   ' Fork based on what OS we're running on...
   os.dwOSVersionInfoSize = Len(os)
   Call GetVersionEx(os)
   Select Case os.dwPlatformId
      Case VER_PLATFORM_WIN32_WINDOWS '95/98/ME
         Call DefaultPrinterSet9x
      Case VER_PLATFORM_WIN32_NT
         Call DefaultPrinterSetNT(os.dwMajorVersion)
   End Select
  
   ' Return results based on test in IsDefault.
   Me.Refresh
   DefaultPrinterSet = Me.IsDefault
End Function

Private Sub DefaultPrinterSet9x()
   ' HOWTO: Retrieve and Set the Default Printer in Windows
   ' http://support.microsoft.com/support/kb/articles/q246/7/72.asp
   Dim hPrn As Long
   Dim BytesNeeded As Long
   Dim Buffer() As Byte
   Dim BytesUsed As Long
   Dim Attributes As Long
  
   ' Get handle to printer.
   Call OpenPrinter(m_DevName, hPrn, ByVal 0&)
   If hPrn Then
      ' Call once to get proper buffer size.
      Call GetPrinter(hPrn, 2, ByVal 0&, 0, BytesNeeded)
      If Err.LastDllError = ERROR_INSUFFICIENT_BUFFER Then
         ' Size buffer and get printer data.
         ReDim Buffer(0 To BytesNeeded - 1) As Byte
         If GetPrinter(hPrn, 2, Buffer(0), BytesNeeded, BytesUsed) Then
            ' Set default printer attribute for this printer...
            ' Attributes is the 14th element in structure
            Const AttribOffset As Long = 13 * 4&
            Call CopyMemory(Attributes, Buffer(AttribOffset), 4&)
            Attributes = Attributes Or PRINTER_ATTRIBUTE_DEFAULT
            Call CopyMemory(Buffer(AttribOffset), Attributes, 4&)
            ' Send back updated structure.
            If SetPrinter(hPrn, 2, Buffer(0), 0) Then
               ' Alert all other running applications,
               ' giving each 1/2 second to react.
               Call SettingChangeAlert(500)
            End If
         End If
      End If
      Call ClosePrinter(hPrn)
   End If
End Sub

Private Sub DefaultPrinterSetNT(ByVal MajorVersion As Long)
   ' HOWTO: Retrieve and Set the Default Printer in Windows
   ' http://support.microsoft.com/support/kb/articles/q246/7/72.asp
   Dim os As OSVERSIONINFO
   Dim BufSize As Long
   Dim pPrinterName As Long
   Dim Result As String
   Dim comma As Long

   ' Use either SetDefaultPrinter (2k+) or WIN.INI (NT4).
   If MajorVersion >= 5 Then
      ' Almost so easy as to be boring. <g>
      Call SetDefaultPrinter(m_DevName)

   Else ' (NT4 or less)
      ' Create satisfactory buffer.
      BufSize = 1024
      Result = Space$(BufSize)
      ' In NT, the old WIN.INI [PrinterPorts] section is mapped to
      ' HKCU/Software/Microsoft/Windows NT/CurrentVersion/PrinterPorts
      ' and we can just use GetProfileString to extract! :-)
      ' Returns: "driver name,port,timeout1,timeout2"
      If GetProfileString("PrinterPorts", ByVal m_DevName, "", Result, BufSize) Then
         ' Find 2nd comma and truncate
         comma = InStr(Result, ",")
         comma = InStr(comma + 1, Result, ",")
         If comma Then
            Result = Left$(Result, comma - 1)
            ' Prepend devname and write to registry.
            Result = m_DevName & "," & Result
            Call WriteProfileString("Windows", "device", Result)
            ' Alert all other running applications,
            ' giving each 1/2 second to react.
            Call SettingChangeAlert(500)
         End If
      End If
   End If
End Sub

Private Function DefaultPrinterName() As String
   ' HOWTO: Retrieve and Set the Default Printer in Windows
   ' http://support.microsoft.com/support/kb/articles/q246/7/72.asp
   ' HOWTO: Get and Set the Default Printer in Windows
   ' http://support.microsoft.com/support/kb/articles/q135/3/87.asp
   Dim os As OSVERSIONINFO
   Dim Buffer() As Byte
   Dim BufSize As Long
   Dim pPrinterName As Long
   Dim Returned As Long
   Dim Result As String
  
   ' Get OS version info, so we know which way to fork.
   os.dwOSVersionInfoSize = Len(os)
   Call GetVersionEx(os)
  
   If os.dwPlatformId = VER_PLATFORM_WIN32_WINDOWS Then  '95/98/ME
      ' Determine how big the buffer needs to be
      Call EnumPrinters(PRINTER_ENUM_DEFAULT, vbNullString, 2, ByVal 0&, 0, BufSize, Returned)
      If BufSize > 0 Then
         ' Size buffer accordingly
         ReDim Buffer(0 To BufSize - 1) As Byte
         ' Call again to retrieve needed info
         Call EnumPrinters(PRINTER_ENUM_DEFAULT, vbNullString, 2, Buffer(0), BufSize, BufSize, Returned)
         ' A pointer to the default printer name is
         ' returned at the 5th byte in the buffer.
         Call CopyMemory(pPrinterName, Buffer(4), 4)
         Result = PointerToStringA(pPrinterName)
      End If
      
   ElseIf os.dwPlatformId = VER_PLATFORM_WIN32_NT Then
      ' Create satisfactory buffer.
      BufSize = 1024
      Result = Space$(BufSize)
     
      ' Use either GetDefaultPrinter (2k+) or WIN.INI (NT4).
      If os.dwMajorVersion >= 5 Then
         If GetDefaultPrinter(Result, BufSize) Then
            ' Truncate at first NULL
            Result = Left$(Result, InStr(Result, vbNullChar) - 1)
         End If
      Else 'NT4 or less
         ' The old WIN.INI [Windows] section is mapped to
         ' HKCU/Software/Microsoft/Windows NT/CurrentVersion/Windows
         ' and we can just use GetProfileString to extract! :-)
         ' Returns: "printer name,driver name,port"
         If GetProfileString("Windows", ByVal "device", "", Result, BufSize) Then
            ' Truncate buffer at end of name.
            Result = Left$(Result, InStr(Result, ",") - 1)
         End If
      End If
   End If
     
   ' Return default printer name.
   DefaultPrinterName = Result
End Function

Private Function PointerToStringA(ByVal lpStringA As Long) As String
   Dim Buffer() As Byte
   Dim nLen As Long
  
   If lpStringA Then
      nLen = lstrlenA(ByVal lpStringA)
      If nLen Then
         ReDim Buffer(0 To (nLen - 1)) As Byte
         CopyMemory Buffer(0), ByVal lpStringA, nLen
         PointerToStringA = StrConv(Buffer, vbUnicode)
      End If
   End If
End Function

Private Function PointerToDWord(ByVal lpDWord As Long) As Long
   Dim nRet As Long
   If lpDWord Then
      CopyMemory nRet, ByVal lpDWord, 4
      PointerToDWord = nRet
   End If
End Function

Private Function SendControl(ByVal ControlCode As PrinterControlCodes) As Boolean
   Dim hPrn As Long
   Dim pd As PRINTER_DEFAULTS
  
   ' Get handle to printer.
   pd.pDesiredAccess = PRINTER_ACCESS_ADMINISTER
   Call OpenPrinter(m_DevName, hPrn, pd)
   If hPrn Then
      ' Attempt to send control code
      SendControl = CBool(SetPrinter(hPrn, 0, ByVal 0&, ControlCode))
      Call ClosePrinter(hPrn)
      Call Me.Refresh
   End If
End Function

Private Sub SettingChangeAlert(Optional ByVal Delay As Long = 500)
   ' Send out alert to notify all other running applications
   ' that a system setting has been updated.
   Call SendMessageTimeout(HWND_BROADCAST, WM_SETTINGCHANGE, _
                           0, 0, SMTO_NORMAL, Delay, ByVal 0&)
End Sub

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值