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

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

 

Совет 155. Используйте VB API Viewer

Совет 156. Автоматическое выделение элементов списка

Совет 157. Применяйте повторно используемые процедуры

Совет 158. Как очистить все текстовые окна

Совет 159. Используйте клавиатуру для управления размерами и расположением элементов управления

Совет 160. Эмуляция события Click для правой кнопки мыши

Совет 161. Установка курсора мыши в нужное место на форме

Совет 162. Используйте массивы элементов управления

Совет 163. Код, расположенный после вызова события Unload Me, препятствует закрытию формы

Совет 164. Как прочитать имена стандартных каталогов

Совет 165. Определитесь — что такое текущий и временный каталоги?

Совет 166. Включение/выключение всех элементов управления в массиве

Совет 167. Сортировка пронумерованных элементов в окне списка

Совет 168. Убедитесь, что вы закрыли все объекты доступа к данным при выходе из программы

Совет 169. Проверка наличия файла из любого места программы

Совет 170. Простой способ генерации случайных чисел

 

Совет 155. Используйте VB API Viewer

При работе с внешними функциями DLL-библиотек их описание с помощью оператора Declare должно быть включено в состав каждого программного компонента проекта (форма, модуль и пр.), где они используются. Однако при этом нужно быть особенно внимательным — ошибка может повлечь неприятности в виде зависания программы.

Кроме того, многие такие функции используют в качестве параметров специальные структуры данных Type, а для управления режимами выполнения функций — определенные значения параметров. Здесь нужно обратить внимание на следующую особенность современного стиля документации и литературы по VB: если в описании говорится об использовании параметра или типа данных, имя которых обозначено заглавными буквами (например, LB_GETITEMHEIGHT), то имеются в виду некоторые стандартные значения констант или структур.

Для упрощения работы с наиболее часто используемыми внешними функциями — стандартным набором Windows — в состав VB 5.0 (и более ранних версий) входит два файла, содержащие описания процедур, а также константы и структуры данных: WIN32API.TXT (собственно набор Win32 API) и MAPI32.TXT (дополнительный набор Message API — почтовых функций). А для удобства работы с ними — утилита APILOAD.EXE и ее описание APILOAD.TXT. Все эти файлы находятся в подкаталоге \Winapi основного каталога Visual Basic. (Для установки файлов подкаталога \Winapi в программе Setup Visual Basic в разделе Online Help and Samples должен быть отмечен пункт Windows API Reference.)

Пользоваться информацией, содержащейся в файлах описаний, в принципе можно с помощью любого текстового редактора, копируя через буфер обмена необходимые данные в VB. Но удобнее для этого использовать стандартную программу APILOAD.EXE (VB API Viewer).

 

Предупреждение. Не следует загружать файл WIN32API.TXT в проект в виде программного модуля. Файл занимает слишком много места в памяти. Обычной практикой является копирование нужных описаний, констант и структур данных в соответствующие программные модули проекта.

 

Ее можно запускать из среды Windows, однако это лучше делать из среды VB 5.0, для чего нужно записать команду вызова APILOAD.EXE в меню Add-Ins. Для этого в среде VB меню Add-Ins выберите команду Add-In Manager, в появившемся диалоговом окне в списке Available Add-Ins установите флажок VB API Viewer (рис. 1) и нажмите ОК. Точно так же можно установить обращение и к другим дополнениям VB.

Примечание. Если в списке Available Add-Ins нет стандартного набора дополнений VB, то нужно запустить программу Setup VB и отметить раздел Wizards and Templates.

Далее все происходит достаточно просто — когда вам нужно получить описания, константы и типы данных для работы с API, выберите команду Add-Ins|API Viewer, после чего появится окно утилиты (рис. 2). Далее необходимо загрузить нужный файл описаний, например WIN32API.TXT, с помощью команды Load Text File из меню File. Потом, устанавливая в списке API Type нужный вид информации, можно просматривать содержимое файла в списке Available Items. Для быстрого поиска можно использовать кнопку Search.

Для более быстрой загрузки файла описания можно преобразовать текстовый файл в базу данных Jet (соответствующая команда находится в меню File). Но при работе с MDB-файлом почему-то пропадает кнопка Search.

Добавление описаний из исходного файла в проект VB выполняется следующим образом. В списке Available Items выделяется нужный элемент, а потом с помощью кнопки Add его содержимое переносится в окно Selected Items. Чтобы удалить информацию из окна Selected Items, надо установить на нее курсор и нажать кнопку Remove.

Скопировать содержимое окна Selected Items в проект VB можно двумя способами.

  1. Нажав кнопку Copy, скопировать данные в буфер обмена, а потом, перейдя в среду VB, вставить информацию в нужное место.
  2. Нажав кнопку Insert, сразу скопировать информацию в раздел Declarations активного в этот момент программного модуля VB. (Это самый удобный вариант — ведь обращение за описанием API-функции производится обычно как раз при активизации соответствующего модуля.)

ВНИМАНИЕ! ВСТРЕЧАЮТСЯ ОШИБКИ! К сожалению, в файле описаний встречаются ошибки. В частности, в WIN32API.TXT приведено такое описание функции GetCurrentDirectory (о ней рассказывается в совете 164):

Declare Function GetCurrentDirectory Lib “kernel32” _
Alias “GetCurrentDirectory”...

Здесь видно, что имя функции и ее альтернативное название совпадают. Соответственно при копировании этой строки в программный код редактор VB совершенно логично автоматически убирает команду Alias. При запуске программы на выполнение выдается сообщение об отсутствии функции в DLL-библиотеке. Ошибка очевидна — в конце названия функции после команды Alias пропала буква «A»: ... Alias “GetCurrentDirectoryA”... Имейте это в виду, если вам встретится аналогичная ошибка в других описаниях.

А зачем вообще нужна команда Alias? Об этом мы расскажем в одном из следующих выпусков «Советов».

 

В начало

В начало

Совет 156. Автоматическое выделение элементов списка

Хотите сделать так, чтобы ваше окно списка вело себя точно так же, как меню? А именно: чтобы когда пользователь перемещал курсор по списку, то выделенный элемент перемещался бы вместе с курсором? Это вполне возможно.

Ключевым моментом в решении данной задачи является то, что каждый элемент стандартного окна списка имеет одинаковую высоту. И если вы знаете эту высоту (значение для самого верхнего видимого элемента) и Y-координату курсора, то вычисление элемента, находящегося под курсором, не составит никакого труда.

Воспользуемся API-функцией SendMessage, чтобы получить высоту каждого элемента списка в пикселах (единица физического разрешения экрана). Для этого нужно обратиться к функции (мы писали о ней более подробно в совете 133 в КомпьютерПресс № 8’98, с. 146) с параметрами wMsg = LB_GETITEMHEIGHT (= &H1A1) и wParam = lParam = 0. Возвращаемая величина и будет высотой элемента списка.

Событие List1_MouseMove передает Y-координату курсора в твипах (единица длины — 1/1440 дюйма). Поэтому нужно преобразовать полученную ранее высоту элемента списка из пикселов в твипы с помощью метода ScaleY.

Теперь поделим передаваемое значение Y на преобразованную высоту элемента списка, затем добавим значение свойства TopIndex — и мы получим элемент, находящийся под курсором. И, наконец, последнее — проверьте, чтобы вычисленное значение свойства ListIndex не было равно или не превышало значения свойства ListCount, иначе могут возникнуть ошибки при установке нового значения.

Примечание. Высоту элемента списка в твипах ItemHeightTwips& можно вычислить один раз вне цикла, например при загрузке формы, а потом передавать ее в процедуру List1_MouseMove в качестве общего параметра формы.

Option Explicit
Private Declare Function SendMessage Lib "user32" _
   Alias "SendMessageA" (ByVal hWnd As Long, _
   ByVal wMsg As Long, ByVal wParam As Long, _
   lParam As Any) As Long
Const LB_GETITEMHEIGHT = &H1A1

Private Sub List1_MouseMove(Button As Integer, _
   Shift As Integer, X As Single, Y As Single)
   ' Выделение текущей позиции списка
   ' в соответствии с перемещением курсора мыши
   Dim ItemHeight&, NewIndex&
   With List1
       ' Высота элемента в пикселах
       ItemHeight& = SendMessage(.hWnd, LB_GETITEMHEIGHT, _
           0, 0)
       ' Высота элемента в твипах
       ItemHeight& = ScaleY(ItemHeightPixels&, vbPixels, _
           vbTwips)
       ' Вычисление индекса
       NewIndex& = .TopIndex + (Y \ ItemHeightTwips&)
       ' Проверка -- не вышли за пределы списка?
       If NewIndex& < .ListCount Then .ListIndex = NewIndex&
   End With
End Sub
В начало

В начало

Совет 157. Применяйте повторно используемые процедуры

Вернемся к предыдущему совету. А если такой режим работы со списком понадобится применить и для других списков? Писать такой код в каждой процедуре List_MouseMove?

Нет, нужно создать отдельный программный модуль, например ListMenu.Bas (или использовать уже имеющийся модуль, где вы храните свои повторно используемые вспомогательные процедуры), и сформировать в нем подпрограмму (ListMenuMouse) на основе программного кода подпрограммы List1_MouseMove. Текст такого модуля приведен в листинге 1. Обратите внимание на некоторые изменения в программе, в частности на то, что в качестве параметров в эту универсальную подпрограмму передается не только описание элемента управления, но и формы. Это необходимо, так как на самом деле метод ScaleY должен быть привязан к конкретной форме. В модуль ListMenu.Bas переместились также описания используемой API-функции и константы.

Теперь этот модуль можно подключить к какому-либо проекту, и, чтобы использовать режим отслеживания движения мыши в любом из его списков, нужно просто вставить следующую строку в событие ListN_MouseMove (заменив ListN на конкретное имя элемента управления):

Call ListMenuMouse(ListN, Me, Y)
В начало

В начало

Совет 158. Как очистить все текстовые окна

Чтобы очистить все текстовые окна на форме, используйте такой код:

Dim vControl
For Each vControl In Me.Controls
   'где Me -- текущая форма
   If TypeOf vControl Is TextBox Then
       vControl.Text = ""
   End If
Next
В начало

В начало

Совет 159. Используйте клавиатуру для управления размерами и расположением элементов управления

Иногда бывает гораздо удобнее использовать не мышь, а клавиатуру — стрелки Right, Left, Down и Up (Вправо, Влево, Вниз и Вверх) — для перемещения границ элементов управления. Для изменения размеров элементов управления (левый верхний угол остается на том же месте, перемещаются только правая и нижняя границы) надо использовать соответствующие клавиши стрелок при нажатой Shift. А для перемещения всего объекта, без изменения его размеров, следует нажать клавишу Ctrl.

Для того чтобы переместить левую (или верхнюю) границу элемента управления, например, вправо, нужно сначала сместить весь объект (Ctrl+Right), а потом вернуть на исходное место правую границу (Shift+Left).

Если вы выделите на форме сразу несколько элементов управления (для этого нужно сначала выделить первый из них с помощью мыши, а потом все остальные — щелкая их мышью при нажатой клавише Shift), то операции изменения размеров и их положения будут выполняться сразу для всех этих объектов.

 

В начало

В начало

Совет 160. Эмуляция события Click для правой кнопки мыши

Иногда бывает полезно использовать щелчок правой кнопкой мыши при работе с командной кнопкой. Например, для выполнения некоторых действий программы, отличных от обычного щелчка левой кнопкой. Для этого можно использовать события MouseDown и MouseUp, которые реагируют на действия с обеими кнопками мыши и позволяют определять, с какой из кнопок конкретно произошло событие. Однако здесь есть некоторые подводные камни, которые следует иметь в виду.

Обратите внимание на специфику реализации события Click для командной кнопки. Данное событие происходит в тот момент, когда вы отпускаете кнопку мыши, но при условии, если в моменты нажатия и отпускания левой кнопки мыши (а время между ними может быть достаточно большим) курсор мыши находится в пределах изображения командной кнопки. Понятно, что событие MouseDown сразу не подходит для эмуляции Click. Что же касается события MouseUp, то оно происходит, даже если в этот момент курсор мыши уже ушел за пределы кнопки — главное, чтобы он был в ее пределах в момент события MouseDown.

Решение задачи достаточно очевидно — нужно определить координаты мыши в событии MouseUp и проверить, попадают ли они в пределы изображения кнопки. Но при этом нужно иметь в виду, что координаты курсора мыши имеют значение относительно данного элемента управления, а не формы. Сделать это можно следующим образом:

Sub Command1_MouseUp (Button As Integer, Shift As Integer, _
   X As Integer, Y As Integer)
   '
   If Button = 2 Then  ' Правая кнопка мыши
       If X >= 0 And X <= Command1.Width And _
           Y >= 0 And Y <= Command1.Height Then
           ' Здесь нужно написать код, который
           ' обрабатывает данное событие
       End If
   End If
End Sub
В начало

В начало

Совет 161. Установка курсора мыши в нужное место на форме

Отличительной чертой коммерческих приложений является то, что курсор может «прыгать», то есть автоматически перемещаться на кнопку в диалоговом окне, которая предлагается по умолчанию. С помощью простой API-функции вы можете сделать то же самое и в своих приложениях:

#If Win32 Then
   Private Declare Function SetCursorPos Lib "user32" _
       (ByVal x As Long, ByVal y As Long) As Long
#Else
   Declare Sub SetCursorPos Lib "User" _
       (ByVal x As Integer, ByVal y As Integer)
#End If
 
Private Sub Form_Load()
   #If Win32 Then
       Dim x As Long, y As Long
   #Else
       Dim x As Integer, y As Integer
   #End If
   '
   Me.Show
   ' Вычисляет координаты командной кнопки
   x = (Me.Left + Command1.Left + Command1.Width / 2) _
       / Screen.TwipsPerPixelX
   y = (Me.Top + Command1.Top + Command1.Height / 2 _
       + Me.Height - Me.ScaleHeight) _
       / Screen.TwipsPerPixelY
   ' Помещает курсор на кнопку
   SetCursorPos x, y
End Sub

Событие Form_Load вычисляет экранные координаты центра командной кнопки в пикселах. Затем функция SetCursorPos перемещает курсор мыши в требуемое место аналогично функции «Snap-To», реализованной в продуктах Microsoft. Обратите внимание, что координаты и линейные размеры элементов управления задаются в твипах, а координаты курсора мыши при обращении к API-функции — в пикселах.

 

В начало

В начало

Совет 162. Используйте массивы элементов управления

Иногда бывает очень удобно объединить в массив группу элементов управления, выполняющих некоторые однотипные операции (мы будем это делать в последующих советах на примере командных кнопок). Тогда такой массив выступает в качестве одного комплексного объекта, а идентификация конкретного его элемента выполняется с помощью свойства Index (нумерация от нуля). За массивом закрепляется набор событийных процедур, состав которых аналогичен процедурам для отдельных элементов управления, но только в качестве первого параметра там будет передаваться номер индекса, по которому можно определить, с каким же конкретно элементом произошло событие.

Обращение к свойствам и методам отдельного элемента также выполняется с помощью индекса, например cmdAction(Index).Caption = “Кнопка”. Но у самого массива (без индекса) есть собственный набор свойств и методов.

Создается массив достаточно просто — в него включаются элементы с одинаковыми именами (свойство Name). При этом индекс формируется автоматически, но тут есть некоторые любопытные моменты. Например, вы последовательно сформировали четыре кнопки с именем cmdAction, у которых свойство Caption установили как А, Б, В и Г соответственно. Они сразу же получили индексы 0, 1, 2, 3.

Если теперь вы удалите кнопку Б, то индексы других кнопок не изменятся (не будет элемента с индексом 1). Теперь добавьте новую кнопку Д — она получит первый свободный индекс, равный 1. Далее мы хотим изменить индекс кнопки В. VB разрешит ввести только неиспользуемое значение индекса, например 4 или 10, то есть значение индекса конкретного элемента, присвоенного ему при создании, может быть изменено только самим программистом в явном виде — в отличие от свойства TabIndex (порядок обхода элементов управления на форме при нажатии клавиши Tab), где перенумерация выполняется автоматически.

 

В начало

В начало

Совет 163. Код, расположенный после вызова события Unload Me, препятствует закрытию формы

Вы можете столкнуться с такой проблемой при попытке выгрузки формы. Например, вы создали массив кнопок, с помощью которых хотите управлять представлением формы на экране, причем одна из них использует событие Unload Me для выгрузки формы. Для этого вы пишете следующий код:

Private Sub cmdAction_Click(Index As Integer)
   '
   ' *** эта подпрограмма не работает!
   '
   Select Case Index
       Case 0: Me.WindowState = vbMaximized
       Case 1: Me.WindowState = vbNormal
       Case 2: Me.WindowState = vbMinimized
       Case 3: Unload Me  ' не работает данная строка!
   End Select
   MsgBox "Текущее состояние: " & CStr(Me.WindowState)
End Sub

Однако приведенная выше подпрограмма не работает, поскольку за оператором Unload Me идет строка, содержащая исполняемый код. Таким образом, форма станет невидимой, но она не будет выгружена. Чтобы исправить эту ошибку, необходимо заменить вызов события Unload Me на установку переменной и выполнить это событие в самой последней строке подпрограммы:

Private Sub cmdAction_Click(Index As Integer)
   '
   ' *** эта подпрограмма работает!
   '
   Dim blnUnload As Boolean
   Select Case Index
       Case 0: Me.WindowState = vbMaximized
       Case 1: Me.WindowState = vbNormal
       Case 2: Me.WindowState = vbMinimized
       Case 3: blnUnload = True
   End Select
   MsgBox "Текущее состояние: " & CStr(Me.WindowState)
   If blnUnload = True Then Unload Me
End Sub
В начало

В начало

Совет 164. Как прочитать имена стандартных каталогов

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

Вариант подпрограммы StandardDirNameAPI$, которая выполняет эти операции, приведен в листинге 2 (модуль SDirName.BAS). По поводу этого программного кода можно сделать еще несколько замечаний. Во-первых, видно, что все четыре API-функции совершенно однотипны, но почему-то в двух из них параметры (имя строкового буфера и его длина) записаны в одном порядке, а в других — в обратном. Во-вторых, при обращении к GetTempPath имя каталога возвращается с символом “\” в конце, в остальных функциях — без него. Именно поэтому в процедуре StandardDirNameAPI$ было бы полезно использовать код, который приводил бы имя каталога в некоторый стандартный вид.

В результате мы формулируем еще один общий СОВЕТ: «Разработчики (в том числе и создатели Win API)! Общайтесь между собой и на рабочие темы!»

 

В начало

В начало

Совет 165. Определитесь — что такое текущий и временный каталоги?

Этот совет вытекает из предыдущего и является его продолжением. Для тестирования процедуры StandardDirNameAPI$ мы предлагаем создать небольшое приложение Tip164.vbp в виде формы, на которой расположен массив из четырех командных кнопок, двух меток и одного текстового поля (рис. 3) и подключенного модуля SDirName.BAS. Весь программный код формы состоит из одной событийной процедуры:

Private Sub cmdAction_Click(Index As Integer)
   ' Определение имени каталога
   Dim DirName$
   DirName$ = StandardDirNameAPI$(Index)
   If DirName$ = "" Then DirName$ = " Не смогли определить "
   Text1.Text = cmdAction(Index).Caption + " = " + DirName$
End Sub

Если нумерация кнопок (сверху вниз) правильно согласуется с их названиями, то после щелчка командной кнопки в текстовом поле будет появляться имя соответствующего каталога. Теперь начнем наше исследование.

Что такое каталоги Windows и System — в целом понятно. Их имена раз и навсегда жестко фиксируются в момент инициализации Windows. С текущим каталогом дела обстоят посложнее. Это каталог, где содержится запущенное на выполнение приложение. Соответственно, если вы запускаете Tip164.vbp в среде VB, текущим будет каталог, где находится VB. Если же вы создадите и запустите автономное приложение Tip164.exe, то текущим будет каталог, где размещается этот файл.

А что такое временный каталог? Вопрос довольно актуальный, лично нас всегда поражало какое-то не поддающееся простой логике хаотическое появление временных файлов в различных разделах диска.

В литературе по Windows 95 встречается такое определение: «Это каталог, описанный переменной окружения TMP. Если переменная TMP не задана — то переменной TEMP. Если TEMP также отсутствует, тогда это текущий каталог приложения». Однако наши эксперименты показали, что эта формулировка неверна.

Действительно, временным является каталог, описанный переменной окружения TMP (например, в AUTOEXEC.BAT). Но если TMP не задана, то временным является подкаталог \TEMP в каталоге операционной системы (Windows). Причем если его не было ранее, то он создается автоматически. Но это еще не все.

Предположим, у вас есть несколько логических дисков и вы в качестве временного почему-то решили определить корневой каталог диска D:. Если вы запишете SET TMP=D:\, то все будет OK. Но если вы забыли в конце строки “\”, то здесь нужно разбираться отдельно.

Так вот, в последнем случае определение временного каталога зависит от местонахождения проекта Tip164. Если он расположен вне диска D:, то временным каталогом будет D:\. Если же он находится на самом диске D:, то временным будет... каталог самого проекта (этот случай приведен на рис. 3). Причем независимо от того, запущен Tip164 из среды VB или как автономный файл.

Короче говоря, будет время — поэкспериментируйте. Вы обнаружите много любопытных вещей и еще раз подивитесь витиеватости замыслов разработчиков Microsoft Windows.

 

В начало

В начало

Совет 166. Включение/выключение всех элементов управления в массиве

Как известно, VB не позволяет передавать массив элементов управления в качестве аргумента в подпрограмму или функцию. И тем не менее вполне возможно придумать решение этой проблемы. Скажем, вы хотите включать/отключать любой набор элементов управления на форме. Это можно сделать с помощью следующей подпрограммы, помещенной в отдельный модуль:

Public Sub EnableControls(Form As Form, _
   ControlArray As Control, State As Boolean)
   '
   Dim ctl As Control
   For Each ctl In Form.Controls
       If ctl.Name = ControlArray.Name Then
           ' Данный элемент управления является
           ' элементом массива
           Ctl.Enabled = State
       End If
   Next
End Sub

Чтобы проверить ее работу, создайте форму и разместите на ней массив полей текста с именем txtSample и массив флажков chkSample. Добавьте две командные кнопки (cmdText и cmdCheck) и для каждой из них в событие Click введите соответственно два следующих кода:

Call EnableControls(Me, txtSample(0), _
   Not (txtSample(0).Enabled))

Call EnableControls(Me, chkSample(0), _
   Not (chkSample(0).Enabled))

Запустите на выполнение ваше приложение и по очереди щелкните кнопки, чтобы включить/отключить присоединенные группы элементов управления.

 

В начало

В начало

Совет 167. Сортировка пронумерованных элементов в окне списка

Предположим, что у вас есть пронумерованные элементы (в нашем случае — файлы):

FILE1.BMP FILE2.BMP FILE3.BMP FILE10.BMP

Если вы поместите их в элемент управления ListBox или ComboBox, то после сортировки они будут представлены в списке следующим образом:

FILE1.BMP
FILE10.BMP
FILE2.BMP
FILE3.BMP

А вы хотите, чтобы они выводились так:

FILE1.BMP
FILE2.BMP
FILE3.BMP
FILE10.BMP

Для этого можно использовать подпрограмму ReSort (листинг 3). После того как вы заполните окно списка, вызовите ReSort, передав исходный элемент управления ListBox или ComboBox в качестве единственного параметра, например Call ReSort(List1).

 

В начало

В начало

Совет 168. Убедитесь, что вы закрыли все объекты доступа к данным при выходе из программы

Если вы используете какие-либо объекты доступа к данным (DAO, RDO или ADO) в своей программе, следует перед выходом из нее закрыть все открытые наборы записей, базы данных и рабочие области. Конечно, когда вы выходите из программы, все указатели к этим объектам автоматически уничтожаются. Но если вы не закроете в явном виде все открытые элементы, то связи с базой данных освободятся не сразу, а память, используемая этими объектами, может так никогда и не перераспределиться операционной системой.

Ниже дается короткая подпрограмма, которую вы можете добавить к своему событию Form_Unload (или к любому другому модулю, завершающему выполнение программы) и которая закрывает все открытые рабочие области, базы данных и наборы записей для объекта доступа к данным (DAO) и освобождает память, резервируемую этими объектами. Приведенный здесь код будет всегда работать при выходе из формы независимо от того, сколько связей у вас будет открыто — одна, сто или даже ни одной.

Private Sub Form_Unload(Cancel As Integer)
   '
   ' Закрывает все объекты доступа к данным и
   ' освобождает всю память
   '
   On Error Resume Next
   Dim ws As Workspace
   Dim db As Database
   Dim rs As Recordset
   '
   For Each ws In Workspaces
       For Each db In ws.Databases
           For Each rs In db.Recordsets
               rs.Close
               Set rs = Nothing
           Next
           db.Close
           Set db = Nothing
       Next
       ws.Close
       Set ws = Nothing
   Next
End Sub
В начало

В начало

Совет 169. Проверка наличия файла из любого места программы

В приложениях довольно часто приходится делать проверку наличия определенных файлов. Здесь приводится простая подпрограмма, которая предназначена для выполнения этого:

Public Function VerifyFile(FileName$) As Boolean
   ' Проверка -- существует ли указанный файл
   On Error Resume Next
   ' Файл открывается как входной, последовательный
   Open FileName$ For Input As #1
   If Err Then ' Ошибка при открытии -- нет файла
       VerifyFile = False
   Else
       VerifyFile = True: Close #1
   End If
End Function

Для проверки работоспособности данной подпрограммы разместите на форме текстовое поле и командную кнопку, для которой напишите такой код в событии Click:

Private Sub Command1_Click()
   Dim FileName$, a$
   FileName$ = Text1.Text
   If VerifyFile(FileName$) Then a$ = "" Else a$ = " не"
   MsgBox ("Файл " & FileName$ & a$ & " найден")
End Sub

Щелкнув кнопку, вы получите сообщение о наличии файла, имя которого было набрано в текстовом поле.

 

В начало

В начало

Совет 170. Простой способ генерации случайных чисел

Если вашей программе часто требуются случайные числа, вам, вероятно, надоело каждый раз вставлять команду Randomize, инициализирующую датчик случайных чисел, а после нее — уравнение. Приведенная здесь простая подпрограмма будет выполнять обе эти операции. Вначале поместите следующую функцию в один из модулей своего проекта:

Public Function GenRndNumber(Lower%, Upper%)
   Randomize
   GenRndNumber = Int((Upper% - Lower% + 1) * Rnd + Lower%)
End Function

Чтобы получить случайное число в диапазоне от –99 до 99, просто введите:

RandomNumber = GenRndNumber(-99, 99)

Вы можете также получить случайную букву в диапазоне от A до M следующим образом:

RandomLetter = Chr$(GenRndNumber(Asc(“A”), Asc(“M”)))

Кроме того, можно удалить середину диапазона, поместив вызов к функции GenRndNumber внутри цикла Do...Loop. Так вы получите случайное число в диапазоне от 50 до 99 или от –50 до –99:

' Инициализирует число, которое будет сгенерировано
' внутри области, которую вы хотите исключить
RandomNumber = 0
Do Until Abs(RandomNumber) > 49
   RandomNumber = GenRndNumber (-99, 99)
Loop

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

 

КомпьютерПресс 1'1999