Получаем состояние выбранного
принтера.
Одна из проблематичных частей разработки
профессиональнальных приложений в Visual Basic, это
добавление в программу возможности печати. С
появлением Visual Basic 4 у разработчиков появилась
возможность пользоваться новым объектом Printer.
Однако, у этого объекта есть серьёзнае
недостатки, а именно, невозможно узнать готов
принтер к печати или занят, вставлена в него
бумага или нет и т.д. Поэтому для получения такой
информации можно воспользоваться API функцией GetPrinter.
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
Используя дескриптор принтера hPrinter она
заполняет буфер информацией из драйвера
принтера. Чтобы получить дескриптор из объекта
Printer, нам необходимо воспользоваться API функцией OpenPrinter.
Как только мы закончим использовать этот
дескриптор, его необходимо освободить при помощи
API функции ClosePrinter.
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)
2. Различные
состояния принтера
Драйвер принтера может вернуть различные
стандартные состояния принтера.
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
3.
Структура данных
Существуют несколько разных структур
данных, которые возвращает драйвер принтера (в
Windows 2000, например, их девять штук), однако только
две первые являются наиболее универсальными и
подходят для всех версий Windows. Из них вторая
является наиболее интересной для нас (PRINTER_INFO_2)
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
Однако, не достаточно просто передать эту
структуру в API функцию GetPrinter, так как принтер
может вернуть больше информации, чем размер
структуры. Поэтому, если не зарезервировать
достаточного буфера для неё, программа может
"выполнить недопустимую оперцию".
К счастью, сама функция GetPrinter позволяет
узнать необходимый объём буфера для структуры.
Для этого достаточно передать ноль в параметре pbSize,
тогда функция вернёт размер требуемого буфера в pbSizeNeeded.
Таким образом, получение информации из
драйвера принтера состоит из двух этапов:
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)
Однако, мы выделили буфер значений Long, а
некоторые значения в структуре PRINTER_INFO_2 имеют тип
данных String. Поэтому, необходимо получить эти
строковые данные из соответствущих адресов
буфера.
Для получения строки по указанному адресу,
используется API функция CopyMemory. Текже
существует API функция IsBadStringPtr, которая
используется для проверки того, что по
указанному адресу содержится допустимая строка.
Private Declare Sub CopyMemory Lib
"kernel32" Alias "RtlMoveMemory"
(Destination As Any, Source As Any,
ByVal Length As Long)
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
StringFromPointer = ""
Exit Function
End If
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
А теперь используем эту функцию, чтобы
заполнить нашу переменную PRINTER_INFO_2:
With mPRINTER_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
|