Справочник функций

Ваш аккаунт

Войти через: 
Забыли пароль?
Регистрация
Информацию о новых материалах можно получать и без регистрации:

Последние темы форума

Показать новые сообщения »

Почтовая рассылка

Подписчиков: 11656
Последний выпуск: 19.06.2015

Получаем состояние выбранного принтера.

Одна из проблематичных частей разработки профессиональнальных приложений в 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 

www.исходники.ru

Оставить комментарий

Комментарий:
можно использовать BB-коды
Максимальная длина комментария - 4000 символов.
 
Реклама на сайте | Обмен ссылками | Ссылки | Экспорт (RSS) | Контакты
Добавить статью | Добавить исходник | Добавить хостинг-провайдера | Добавить сайт в каталог