div.main {margin-left: 20pt; margin-right: 20pt}
Получаем состояние выбранного принтера.
Одна из проблематичных частей разработки профессиональнальных
приложений в 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) '\ Проверка указателя в 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 '\ Ошибка - данный указатель нельзя
использовать 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 '\ Эта переменная типа
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
|