Visual2000 · Архив статей А.Колесова & О.Павловой

Советы тем, кто программирует на Visual Basic

Андрей Колесов, Ольга Павлова

© 1998, Андрей Колесов, Ольга Павлова
Авторский вариант. Статья была опубликована c незначительной литературной правкой в журнале "КомпьютерПресс" N 7/98, с.194-196.


Совет 127. Выводите осмысленные сообщения об ошибках при вызовах функций Win32 API

Большинство функций Win32 API выводит на экран сообщение об ошибках, возникающих при их некорректном использовании. Чтобы сделать эту информацию более содержательной, следует воспользоваться функциями GetLastError и FormatMessage.

Для этого введите в BAS-модуль VB-проекта следующие описания и функцию:

Option Explicit

Public Declare Function GetLastError Lib "kernel32" () As Long
Public 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

Public Const FORMAT_MESSAGE_FROM_SYSTEM = &H1000

Public Function LastSystemError() As String
    '
    ' системная ошибка
    Dim sError As String * 500
    Dim lErrNum As Long
    Dim lErrMsg As Long
    '
    lErrNum = GetLastError
    lErrMsg = FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM, _
      ByVal 0&, lErrNum, 0, sError, Len(sError), 0)
    LastSystemError = Trim(sError)
    '
End Function

Затем поместите командную кнопку на стандартную VB-форму и вызовите функцию LastSystemError:

Private Sub Command1_Click()
    '
    MsgBox LastSystemError
    '
End Sub

Если не было зарегистрировано никакой ошибки, вы увидите сообщение со словами "The operation completed successfully".

При использовании данной функции следует помнить следующее:

  1. Большинство вызовов функций API при успешном выполнении операции сбрасывает значение GetLastError в первоначальное состояние, поэтому функцию LastSystemError следует вызывать сразу же после того вызова функции API, который создает ошибочную ситуацию.

  2. Значение последней ошибки хранится отдельно для каждого процесса, поэтому функцию LastSystemError необходимо вызывать из того же процесса, откуда осуществлялся вызов функции API, приводящий к ошибке.

В начало статьи

Совет 128. Увеличение и уменьшение даты с помощью клавиш [+] и [-]

В некоторых программах работа с датой реализована довольно интересным образом. Нажатие клавиши [+] увеличивает дату на один день, клавиши [-] — уменьшает на один день, клавиша [PgDn] прибавляет один месяц, а клавиша [PgDn] убавляет на один месяц. Попробуем реализовать это с помощью VB.

Вначале поместите на форму элемент управления TextBox (txtDate). Установите его свойство Text равным "", а свойство Locked — True. После этого введите следующий код в событие KeyDown:

Private Sub txtDate_KeyDown(KeyCode As Integer, Shift As Integer)
    '
    ' KeyCode — специальный код клавиши (а не ASCII-код!)
    ' 107 = "+" KeyPad (цифровая клавиатура)
    ' 109 = "-" KeyPad
    ' 187 = "+" (в действительности это клавиша "=")
    ' 189 = "-"
    ' 33 = PageUp
    ' 34 = PageDown
    '
    Dim strYear As String
    Dim strMonth As String
    Dim strDay As String
    '
    If txtDate.Text = "" Then
        txtDate.Text = Format(Now, "d/m/yyyy")
        Exit Sub
    End If
    '
    strYear = Format(txtDate.Text, "yyyy")
    strMonth = Format(txtDate.Text, "mm")
    strDay = Format(txtDate.Text, "dd")
    '
    Select Case KeyCode
        Case 107, 187 ' добавляет один день
            txtDate.Text = Format(DateSerial(strYear, strMonth, strDay) + _
                           1, "d/m/yyyy")
        Case 109, 189 ' убавляет на один день
            txtDate.Text = Format(DateSerial(strYear, strMonth, strDay) - _
                           1, "d/m/yyyy")
        Case 33 ' увеличивает на один месяц
            txtDate.Text = Format(DateSerial(strYear, strMonth + 1, _
                           strDay), "d/m/yyyy")
        Case 34 ' уменьшает на один месяц
            txtDate.Text = Format(DateSerial(strYear, strMonth - 1, _
                          strDay), "d/m/yyyy")
    End Select
    '
End Sub

Этот способ коррекции даты очень полезен, так как гарантирует правильный формат даты в окне. Именно для того, чтобы избежать возможных ошибок при вводе, мы, установив свойство Locked равным True, заблокировали возможность редактировать в текстовом окне дату в явном виде.

В начало статьи

Совет 129. Различайте термины KeyCode и KeyAscii

Обратите внимание, что при вводе данных в событие KeyPress передается код символа ASCII (KeyAscii), а для событий KeyDown/KeyUp — код клавиши (KeyCode).

В первом случае мы получаем значимые символы в однобайтовой кодировке ANSI (событие KeyPress не реагирует на нажатие функциональных клавиш, клавиш редактирования, перемещения и пр., которые часто кодируются в двухбайтовой ANSI-кодировке). Нажатию одной и той же клавиши может соответствовать до четырех разных символов и их значений ASCII, например — "S s Ы ы". Код передается в виде ссылки (By Reference). Так что если вы измените его в этой процедуре, то объект (элемент управления) будет иметь дело с вашим значением. Например, такой код:

Sub Text1_KeyPress (KeyAscii As Interger)
   If KeyAscii = Asc("1") Then KeyAscii = Asc("2")
End If

будет вводить в текстовое окно двойку вместо единицы.

Во втором случае в процедуру передается код, закрепленный за данной клавишей (без учета текущей раскладки клавиатуры и регистра). При этом события KeyDown/KeyUp реагируют на нажатие (или освобождение) ЛЮБОЙ клавиши клавиатуры. Но нужно иметь в виду, что коды клавиш малой цифровой клавиатуры идентичны кодам соответствующих клавиш редактирования и перемещения. Не очень понятно, почему, но эти коды клавиш отличаются от значений SCAN-кодов клавиатуры.

В программе можно применять код клавиш в цифровом виде (как мы делали в предыдущем примере) или использовать встроенные константы VB. Например, клавиша PageDown описывается константой vbKeyPageDown=34. Список этих констант и их значений можно найти либо в справочной системе (для поиска нужного раздела введите во вкладке Index слово "KeyCode" для десятичного варианта значения или "Key Code" для шестнадцатеричного) либо через Object Browser:

Однако в списке этих констант почему-то отсутствуют некоторые клавиши — ('-=;',./). Впрочем, код любой клавиши вы можете легко определить с помощью такой простой программки:

Sub Text1_KeyDown (KeyCode As Interger, Shift As Integer)
    Debug.Print KeyCode
End If

Как видно из этого примера, в процедуры KeyDown/KeyUp передается также параметр Shift, значение которого отражает состояние клавиш Shift, Ctrl и Alt: при их нажатии устанавливается единица соответственно в 0-й, 1-й и 2-й разряд переменной. Например, комбинация клавиш Shift+Ctrl будет иметь значение 3 (двоичное 011).

В начало статьи

Совет 130. Если хотите, то создавайте окна произвольной формы

В состав Win32 API входит одна очень занимательная функция, используя которую вы обнаружите, что в 32-разрядной версии Windows окно может иметь не только прямоугольную форму. На самом деле оно может быть любой конфигурации. Следующий пример демонстрирует работу с одной из так называемых функций региона (region functions) — SetWindowRgn.

Вначале введите такой код в раздел General Declarations:

Private Declare Function CreateEllipticRgn Lib "gdi32" _
  (ByVal X1 As Long, ByVal Y1 As Long, ByVal X2 As Long, _
  ByVal Y2 As Long) As Long

Private Declare Function SetWindowRgn Lib "user32" _
 (ByVal hWnd As Long, ByVal hRgn As Long, _
 ByVal bRedraw As Boolean) As Long

А затем напишите следующее для события Load:

Private Sub Form_Load()
   Show ' Вывод формы
   SetWindowRgn hWnd, CreateEllipticRgn(0, 0, 300, 200), True
End Sub

Вот и все. Запустите данный пример на выполнение, и VB выведет на экран форму в виде эллипса.

В начало статьи

Совет 131. Управление размещением на экране элементов среды в VB5

После установки VB вы можете обнаружить, что инструментальные окна среды как бы "подключены" к основному окну и вы лишены возможности свободно управлять их размерами и размещением на экране. (В VB5 используется 9 таких окон: Immediate Window, Locals Window, Watches Window, Project Explorer, Properties Window, Object Browser, Form Layout, Toolbox и Color Palette.) Это означает, что для них установлен режим Dockable, снять который можно во вкладке Docking диалогового окна Options (меню Tools команда Options). Причем установка/снятие режима Dockable осуществляется отдельно для каждого окна (их список приведен во вкладке Docking).

В начало статьи

Совет 132. Не используйте звуковой сигнал при нажатии клавиши Enter

Введя какую-либо информацию в текстовое окно, а затем нажав клавишу Enter, вы услышите звуковой сигнал. Чтобы избежать этого, запишите в событие KeyPress следующий код:

If KeyAscii = Asc(vbCr) Then KeyAscii = 0

В начало статьи