Советы тем, кто программирует на VB & VBA

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

Совет 234. Используйте свойство ItemData элемента управления ListBox для хранения идентификаторов

Совет 235. Как правильно сгенерировать значения ADO RecordCount в VB

Совет 236. Пусть VB сам определяет, есть в дисководе CD-ROM компакт-диск или нет

Совет 237. Как добавить новый элемент к системному меню формы

Совет 238. Как быстро осуществить проверку на наличие определенного элемента в списке

Совет 239. Используйте для объектов ADO родные драйверы OLEDB вместо драйверов ODBC

Совет 240. Как модифицировать элемент управления DataGrid при помощи изменения набора записей

Совет 241. Как запустить на выполнение VB-приложение в процессе инициализации Windows

Совет 242. Как восстановить короткое имя файла в VB без помощи API-функций

Совет 243. Создавайте временные VB-файлы с помощью API-функции

Совет 244. Как преобразовать число в строку с фиксированным количеством цифр

Совет 245. Используйте режим Option Explicit

Совет 246. Как сделать временную задержку

Совет 247. Как сделать заставку при старте VB-программы или VBA-документа

Совет 248. Как изучать программирование в среде VBA

Совет 249. Как обрабатывать строки на VBA и каковы преимущества для этого в MS Office 2000

Совет 250. Как перекодировать почтовые сообщения

Совет 234. Используйте свойство ItemData элемента управления ListBox для хранения идентификаторов

Часто при заполнении элемента управления ListBox информацией из базы данных бывает необходимо, чтобы этот компонент не только выводил описания элементов базы данных, но и хранил некоторые ключевые значения. Например, если окно списка содержит имена сотрудников, наверное, будет полезно хранить здесь также их персональные идентификаторы. В том случае, если вы используете числовые идентификаторы, VB предоставляет возможность осуществить это с помощью свойства ItemData компонента ListBox, которое позволяет хранить дополнительное число для каждого элемента списка. Проиллюстрируем это на таком примере. Поместите окно списка на стандартную форму и введите следующий код:

Private Sub Form_Load()
       ' Заполнение списка и массива ItemData
       ' соответствующими элементами
       With List1
       .AddItem "Владимир Николаев"
       .ItemData(List1.NewIndex) = 42310
       .AddItem "Максим Сергеев"
       .ItemData(List1.NewIndex) = 52855
       .AddItem "Михаил Смирнов"
       .ItemData(List1.NewIndex) = 64932
       .AddItem "Анна Васильева"
       .ItemData(List1.NewIndex) = 39227
       End With
       End Sub
       
       Private Sub List1_Click()
       Dim Msg As String
       ' Вывод окна сообщения, содержащего
       ' идентификатор и имя сотрудника
       With List1
       Msg = .ItemData(.ListIndex) & " " & .List(.ListIndex)
       MsgBox Msg
       End With
       End Sub
       

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

В начало В начало

Совет 235. Как правильно сгенерировать значения ADO RecordCount в VB

Как известно, свойство ADO RecordCount возвращает количество записей в наборе записей ADO. Однако в некоторых случаях данное свойство возвращает значение, равное –1. Почему так происходит? Дело в том, что значение, возвращаемое свойством RecordCount, зависит от типа курсора в наборе записей: –1 для курсора, перемещаемого только вперед; реальное количество записей — для статического курсора или курсора, управляемого клавишами на клавиатуре; –1 или реальное количество записей — для динамического курсора, в зависимости от источника данных.

Однако вам будет также интересно узнать, что значение RecordCount равно –1 для наборов записей, созданных с помощью метода Execute для объекта Connection или Command. Это происходит потому, что данный метод генерирует набор записей, перемещаться по которому можно только вперед и который возвращает, как мы уже упоминали выше, –1. В качестве примера создайте следующую подпрограмму внутри стандартного VB-проекта. (Не забудьте установить ссылку на Microsoft ActiveX Data Objects 2.1 Library и изменить путь к базе данных Biblio.mdb в соответствии с тем, где она хранится на вашем компьютере.) Запустите проект на выполнение, и вы увидите окно сообщения, содержащее такие значения: –1 для набора записей на базе myConRst и 6246 — для myKeyRst.

Sub TestRecordCount()
       Dim myConn As ADODB.Connection
       Dim myComm As String
       Dim myConRst As ADODB.Recordset
       Dim myKeyRst As ADODB.Recordset
       Dim sConnection As String
       sConnection = "Provider=Microsoft.Jet.OLEDB.4.0;" & _
       "Data Source=D:\Microsoft Visual Studio\VB98\Biblio.mdb"

       Set myConn = New ADODB.Connection
       Set myKeyRst = New ADODB.Recordset

       myConn.Open sConnection
       myComm = "Select * From Authors"
       Set myConRst = myConn.Execute(myComm, , adCmdText)

       myKeyRst.Open myComm, myConn, adOpenKeyset
       MsgBox "RecCount from Connection: " & myConRst.RecordCount & _
       vbCr & "From Recordset: " & myKeyRst.RecordCount

       Set myKeyRst = Nothing
       Set myConRst = Nothing
       Set myConn = Nothing

       End Sub
В начало В начало

Совет 236. Пусть VB сам определяет, есть в дисководе CD-ROM компакт-диск или нет

Для того чтобы быстро определить, не забыл ли пользователь вставить компакт-диск в дисковод CD-ROM, используйте свойство IsReady для объекта Drive. Данное свойство возвращает значение True (Истина) только в том случае, если компакт-диск находится в устройстве CD-ROM. Рассмотрим следующий пример. Установите ссылку к библиотеке Microsoft Scripting Runtime (scrrun.dll), а затем создайте переменную Drive для дисковода CD-ROM. Протестируйте свойство IsReady, как показано ниже:

Dim FSO As FileSystemObject
       Dim CDDrive As Drive

       Set FSO = New FileSystemObject
       Set CDDrive = FSO.GetDrive("E:")
       If CDDrive.IsReady Then
       MsgBox CDDrive.VolumeName
       Else
       MsgBox "Вставьте, пожалуйста, компакт-диск"
       End If

       Set CDDrive = Nothing
       Set FSO = Nothing
В начало В начало

Совет 237. Как добавить новый элемент к системному меню формы

В некоторых случаях вам может понадобиться добавить дополнительный элемент к системному меню формы. (Кнопка системного меню находится в верхнем левом углу формы.) Для этого воспользуйтесь тремя API-функциями — GetSystemMenu, AppendItemMenu и DrawMenuBar:

Option Explicit
       Private Declare Function DrawMenuBar Lib "user32" _
       (ByVal hWnd As Long) As Long

       Private Declare Function GetSystemMenu        Lib "user32" _
       (ByVal hWnd As Long, ByVal bRevert As Long) As Long

       Private Declare Function AppendMenu Lib        "user32" Alias _
       "AppendMenuA" (ByVal hMenu As Long, ByVal wFlags _
       As Long, ByVal wIDNewItem As Long, ByVal lpNewItem _
       As Any) As Long

       Const MF_STRING = &H0&

       Private Sub Form_Load()
       Dim SysMenu As Long
       SysMenu = GetSystemMenu(Me.hWnd, False)
       If SysMenu Then
       AppendMenu SysMenu, MF_STRING, 0, "Свой элемент меню"
       DrawMenuBar Me.hWnd
       End If
       End Sub

Как видно из приведенного выше кода, подпрограмма находит указатель к копии системного меню текущей формы. Затем она добавляет строку «Свой элемент меню» к списку команд системного меню, и наконец перерисовывает меню, добавляя новый текст в конец списка. Команду DrawMenuBar следует всегда использовать при изменении системного меню, даже если в данный момент оно является невидимым.

То, что вы просто добавили новую команду к системному меню, совершенно не означает, что она будет выполнять какую-либо операцию: для этого необходимо написать соответствующий код. Функция AppendMenu предлагает несколько различных параметров, описывающих элемент, который вы хотите добавить к системному меню. Полный список этих параметров приводится в файле Справки.

Следует помнить также, что для функции AppendMenu имеется более мощный аналог — новая API-функция InsertMenuItem, которая, хотя и предлагает более широкие возможности управления, намного более сложна в использовании. Поэтому если вы просто хотите поместить дополнительный элемент в конец списка команд системного меню, для этого лучше всего подойдет функция AppendMenu.

В начало В начало

Совет 238. Как быстро осуществить проверку на наличие определенного элемента в списке

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

For X = 0 To List1.ListCount - 1
       strItemList = strItemList & "[" & List1.List(X) & "]"
       Next X

После этого с помощью функции Instr() определите, содержит ли новая строка искомый элемент:

If InStr(strItemList, "[" & strTestItem & "]") Then
       MsgBox "Уже есть в списке"
       Else
       MsgBox "Добавьте в список..."
       End If
В начало В начало

Совет 239. Используйте для объектов ADO родные драйверы OLEDB вместо драйверов ODBC

При создании строки соединения (connection string) для объектов ADO имеется возможность задать драйвер источника данных либо как Driver, например, так:

Driver={SQL Server};DBQ=database_file

либо как Provider, наподобие следующего:

Provider=Microsoft.Jet.OLEDB.4.0;Data 
      Source=database_name

Однако в первом случае объект ADO использует более старые драйверы ODBC для связи с источником данных, в то время как во втором применяется OLEDB, являющийся “родным” для ADO интерфейсом доступа к данным. Поэтому всегда, когда это возможно, пользуйтесь вариантом Provider. Напоминаем, что “родные” драйверы OLEDB существуют для SQL Server, Index Server, Site Server Search и Oracle.

В начало В начало

Совет 240. Как модифицировать элемент управления DataGrid при помощи изменения набора записей

Элемент управления DataGrid, входящий в состав VB 6.0, является хорошим средством для представления данных в табличном виде. Однако в нем имеется несколько ошибок. Часть из них была исправлена в Service Patch 3, но некоторые из них все же остались. Например, если вы свяжете элементы управления DataGrid и DataEnvironment, затем измените набор данных, используемый в DataEnvironment, и обновите DataGrid с помощью метода Refresh, этот компонент останется неизменным. К сожалению, метод Refresh не работает, когда свойство DataSource элемента управления DataGrid установлено как DataEnvironment. Поэтому, чтобы отразить изменения, которые были сделаны в наборе данных элемента управления DataEnvironment, следует сначала обновить эти данные, а затем повторно связать DataGrid с DataEnvironment. Поэтому если у вас есть кнопка Refresh, событие Click для нее может выглядеть так:

DataEnvironment1.rsCommand1.Requery
       Set DataGrid1.DataSource = DataEnvironment1

Теперь, когда вы щелкнете мышью кнопку Refresh, приведенный выше код повторно свяжет элементы управления DataEnvironment и DataGrid, а затем заново заполнит последний из них обновленными данными.

В начало В начало

Совет 241. Как запустить на выполнение VB-приложение в процессе инициализации Windows

В зависимости от версии Windows, в которой вы работаете, существуют два различных способа выполнить VB-приложение в процессе загрузки системы. Для Windows 9x поместите команду Shell в раздел [Boot] файла System.ini, например так:

Shell=Myprog.exe

Для Windows NT/2000 используйте ту же самую команду Shell в Системном Реестре (Registry) в разделе

HKEY_CURRENT_USER\Software\Microsoft\WindowsNT\CurrentVersion\Winlogon

Будьте, однако, осторожны, выполняя подобные модификации, поскольку это может привести к некорректной работе Windows.

В начало В начало

Совет 242. Как восстановить короткое имя файла в VB без помощи API-функций

Во многих случаях может возникнуть необходимость сделать ссылку на файл в соответствии с соглашением об именах файлов 8.3. Вы, несомненно, неоднократно встречали такие имена в MS-DOS. Например, используя данное соглашение, папка Program Files превращается в Progra~1. Поэтому вам приятно будет узнать о том, что в VB 6.0 появилась возможность восстанавливать короткие имена файлов, не обращаясь к API-функции GetShortPathName. В качестве альтернативы новая библиотека Scripting Runtime предлагает свойство ShortPath для объектов File и Folder. Чтобы получить короткое имя файла, просто добавьте ссылку к Microsoft Scripting Runtime, а затем введите следующий код:

Private Sub Form_Load()
       Dim fsoFile As File, fso As FileSystemObject
       Set fso = New FileSystemObject
       Set fsoFile = fso.GetFile("C:\MyReallyLongName.txt")
       MsgBox fsoFile.ShortPath
       Set fsoFile = Nothing
       Set fso = Nothing
       End Sub
В начало В начало

Совет 243. Создавайте временные VB-файлы с помощью API-функции

Если вы когда-либо работали с Word или другим приложением Office, вы, вероятно, обратили внимание, что каждый раз при открытии файла Office создает временный файл, в котором будут храниться все изменения. И тогда у вас мог возникнуть вопрос, как создавать произвольные временные файлы в своем собственном VB-приложении. Для этого воспользуйтесь API-функцией GetTempFileName:

Public Declare Function GetTempFileName        Lib "kernel32" _
       Alias "GetTempFileNameA" (ByVal lpszPath As String, _
       ByVal lpPrefixString As String, ByVal wUnique As Long, _
       ByVal lpTempFileName As String) As Long

Аргумент lpszPath передает полное имя файла (включая путь к нему), lpPrefixString позволяет добавить префикс из трех букв слева от имени файла, а wUnique дает команду Windows либо создать файл с произвольным именем (wUnique равен 0), либо использовать заданный номер. Параметр lpTempFileName, конечно же, содержит имя нового временного файла. В качестве примера поместите приведенное выше объявление API-функции в стандартный модуль, а затем напишите следующую функцию:

Private Function GenTempName(sPath As        String)
       Dim sPrefix As String
       Dim lUnique As Long
       Dim sTempFileName As String
       
       If IsEmpty(sPath) Then sPath = "D:\Articles\IVB"
       sPrefix = "fVB"
       lUnique = 0
        
       sTempFileName = Space$(100)
       GetTempFileName sPath, sPrefix, lUnique, sTempFileName
       sTempFileName = Mid$(sTempFileName, 1, _
       InStr(sTempFileName, Chr$(0)) - 1)
       GenTempName = sTempFileName
       End Function

После этого откройте новую форму и введите следующий код в ее событие Click. (Замените D:\Articles\IVB на любой допустимый путь.)

MsgBox GenTempName("D:\Articles\IVB")

Запустите проект на выполнение. Заданный вами каталог теперь содержит временный файл, имя которого было выведено в окне сообщения.

Обратите внимание: для того чтобы приведенная выше функция работала надлежащим образом, вы должны задать только допустимый путь. В противном случае функция GetTempFileName вернет 0 и нулевой параметр в качестве имени файла в Windows NT. В Windows 9x неправильно указанный путь также вернет 0, а параметр lpTempFileName не будет содержать имя временного файла.

В начало В начало

Совет 244. Как преобразовать число в строку с фиксированным количеством цифр

Порой бывает нужно вывести числа с фиксированным количеством цифр, когда впереди добавляются нули: например, если требуется представить число 12345 в виде 0012345. Это легко осуществимо с помощью такой функции:

Public Function FixNumber$(SourceNumber, Lend%)
       '
       ' Преобразование числа в строку с фиксированным
       ' количеством цифр (добавляем нули спереди)
       ' =======================================
       ' SourceNumber — исходное число
       ' Lend — количество цифр
       '
       Dim MaxNumber
       MaxNumber = 10 ^ Lend
       If SourceNumber >= MaxNumber Then ' превышен предел
       ' тут могут быть разные варианты
       FixNumber$ = SourceNumber ' вывод числа полностью
       ' или
       ' FixNumber$ = String$(Lend, "?") ' замена на знаки вопроса
       Else ' укладывается в рамки
       FixNumber$ = Right$(MaxNumber + SourceNumber,        Lend)
       End If
       End Function
В начало В начало

Совет 245. Используйте режим Option Explicit

Именно так назвался один из первых советов, опубликованных в самом начале цикла «Советы для тех, кто программирует на VB» четыре года назад (КомпьютерПресс 5/96). С тех пор мы неоднократно показывали на разных примерах пользу обязательного объявления переменных: затраченное на написание нескольких операторов Dim время многократно окупается ускорением отладки. И тем не менее вновь вернуться к этому вопросу нас заставило письмо читателя Игоря, который обратился к нам с «неразрешимой» проблемой.

Игорь хотел подключить DLL-процедуру, написанную на Фортране, к VB. Вопрос корректной передачи параметров в DLL не совсем тривиален, поэтому мы посоветовали ему начать с отладки какого-нибудь простого случая, например с передачи имени файла, который нужно прочитать в DLL, в виде строковой переменной.

С внешней стороны тестовый пример выглядел правильно:

Обращение к DLL из VB:
         
       Private Declare Sub OpenFileFortran _
       Lib "FortLib" (ByVal ss As String)
       '
       Dim cc As String
       сc = "sams.txt"
       Call OpenFileFortran(cc)
       End Sub
        
       Процедура на Фортране:
        
       Subroutine OpenFileFortran (pfn)
       character*(*) pfn
       open(0,file=pfn)
       close(0)
       End
        

Прислав этот пример, Игорь сообщил, что он уже два дня безуспешно сражается с ним, причем обычно происходит аварийное завершение программы с «мгновенным исчезновением среды VB». Он испробовал разные варианты передачи имени файла, в том числе с использованием байтовых массивов и структур данных, но с тем же неудачным результатом. Распечатка переменной pfn упорно показывала отсутствие нужного имени файла. А может быть, тут проблема в путанице ANSI/Unicode? Или «глючит» Windows 98 Second Edition?

Однако «ларчик просто открывался». На самом деле в VB-программе Игоря используются две разные переменные: в первой и третьей строках указана переменная «cc» (обе буквы латинские), а во второй — «сc» (первая буква русская).

Определить это на взгляд просто невозможно. Но мы всегда применяем режим Option Explicit, поэтому компилятор сразу же сообщил, что во второй строке используется неопределенная переменная. Мы, конечно, сначала не поверили своим глазам, но потом вспомнили случай из времен DOS. Тогда у нас был установлен какой-то русификатор клавиатуры, у которого переключение клавиш на русский язык порой срабатывало только после нажатия первой клавиши. В результате при вводе такого текста
Andy спит
оказывалось, что в слове «спит» первая буква — английская. Заметить разницу было невозможно («с» и «с» находятся на одной клавише). В этой связи еще один совет: старайтесь использовать шрифты, которые используют различные начертания внешне похожих русских и латинских букв.

После исправления идентификатора пример стал нормально работать. Таким образом, для того чтобы не терять несколько дней на отладку, нужно было всего-навсего установить режим Option Explicit (который автоматически определяется командой Tools|Options|Editor|Required Variable Declaration).

В начало В начало

Совет 246. Как сделать временную задержку

В версиях MS Basic для DOS имелся полезный оператор временной задержки
SLEEP Seconds
который приостанавливал выполнение программы на указанное число секунд. Такого оператора в VB не существует, но его нетрудно реализовать самостоятельно в виде следующей простой подпрограммы:

Sub SleepVB (Seconds)
       ' ожидание Seconds секунд
       Dim Start
       Start = Timer ' текущее время в секундах
       Do While Timer < Start + Seconds
       ' обеспечивает параллельное выполнение других процессов
       DoEvents
       Loop
       End Sub
        

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

Старый оператор SLEEP осуществлял задержку выполнения на заданное число секунд или до нажатия любой клавиши клавиатуры. (В Basic/DOS с ним были свои проблемы, так как код нажатой клавиши оставался в буфере клавиатуры и автоматически использовался в последующих операциях ввода. Для предотвращения подобной ситуации после оператора SLEEP нужно было очищать буфер.)

При желании такой режим можно реализовать и в нашей функции SleepVB. Один из ее вариантов, а также необходимость применения функции DoEvents мы покажем в следующем примере.

В начало В начало

Совет 247. Как сделать заставку при старте VB-программы или VBA-документа

Как сделать, чтобы при запуске VB-программы появлялась некая заставка-форма, которая бы автоматически исчезала после завершения загрузки программы? Для этого лучше всего использовать вариант старта приложения с подпрограммы Main (устанавливается командой Project Properties|General|Strartup Object), которая может выглядеть примерно следующим образом:

       Sub Main()
       '
       frmSplash.Show ' открываем форму-заставку
       '
       Call AllStartOperations ' этой процедурой
       ' мы обозначаем все необходимые подготовительные
       ' операции для запуска приложения, например,
       ' открываем базы данных, очищаем какие-то файлы и пр.
       '
       Load frmMain ' загружаем основную форму приложения,
       ' с которой начнется его реальное выполнение
       Unload frmSplash ' выгружаем форму-заставку
       'показываем основную форму и начинаем работать с ней
       frmMain.Show
       End Sub

Обратите внимание, что форма-заставка появляется здесь только на очень короткое время (в данном случае — на время загрузки frmMain) и тут же исчезает. Как сделать временную задержку, мы покажем ниже.

А как создать заставку, которая бы появлялась при открытии офисного документа, например для Word 97/2000?

Откроем Word, создадим новый документ под названием Splash.doc и перейдем в среду VBA (Alt+F11). Затем создадим форму (Insert|UserForm), для которой установим свойства Name=frmSplash и Caption="Заставка нашей программы". На заставке можно показать разнообразную информацию о нашем приложении (название, логотип, имя автора и пр.). Мы же сейчас ограничимся только размещением небольшой GIF-картинки с помощью установки свойства Picture (рис. 1).

Теперь в окне Project откроем узел Microsoft Word Objects и дважды щелкнем появившийся в нем стандартный элемент ThisDocument (в Excel это соответственно Microsoft Excel Objects|ThisWorkbook). В открывшемся окне кода в списке предопределенных событийных процедур (в правом верхнем углу) найдем подпрограмму Open. Именно ей передается управление в момент открытия документа, и сюда можно поместить любой код для выполнения необходимых стартовых операций. Поместим в нее следующий программный код (рис. 2):

   Private Sub Document_Open()
   ' эта процедура срабатывает при открытии документа
   '
   frmSplash.Show ' открываем форму-заставку
   Unload frmSplash ' выгружаем форму-заставку
   Msgbox "Hello!" ' фиксируем начало реальной работы
   End Sub

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

Совет. Чтобы избежать постоянного закрытия-открытия документа для проведения отладки, измените в описателе Sub Document_Open ключевое слово Private на Public. В этом случае данная процедура автоматически попадет в список макрокоманд документа, и вы сможете обращаться к ней любой момент без перезагрузки документа.

Однако, запустив процедуру Document_Open, мы обнаружим, что характер ее работы отличается от того, как она функционирует в обычном Visual Basic: здесь форма-заставка не исчезает до тех пор, пока пользователь сам не закроет ее.

Причина такого поведения заключается в том, что форма может открываться в двух разных режимах: модальном и немодальном. В первом случае управление полностью передается форме (остальные элементы интерфейса становятся недоступными пользователю) и возвращается обратно в вызывающую программу только после закрытия этой формы. В немодальном режиме форма открывается, и управление сразу возвращается в программу (форма начинает работать как бы в автономном режиме, параллельно со всеми остальными элементами программы). Различие в поведении формы-заставки в VB и VBA заключается в том, что благодаря используемому по умолчанию параметру метода Show в первом случае форма открывается в немодальном режиме, а во втором — в модальном.

Более того, в Office 97 был реализован только модальный режим работы форм. Поэтому для автоматического удаления формы-заставки нужно придумывать какой-нибудь программный трюк внутри ее модуля, который бы, например, отслеживал некую временную задержку и сам закрывал форму. В Office 2000 появилась возможность использования немодальных форм, но для этого нужно указать параметр Show в явном виде:

frmSplash.Show 0 ' открывает форму в 
      немодальном режиме

Как нам сделать, чтобы форма-заставка не мелькала на экране, а оставалась открытой некоторое минимальное время, например пять секунд? Для этого можно воспользоваться подпрограммой временной задержки SleepVB, приведенной в Совете 246, и тогда код открытия документа будет выглядеть следующим образом:

frmSplash.Show 0 ' открываем форму-заставку
       ' Call AllStartOperations необходимые дополнительные операции
       Call SleepVB (5) ' задержка на 5 секунд
       Unload frmSplash ' выгружаем форму-заставку
       Msgbox "Hello!" ' фиксируем начало реальной работы

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

frmSplash.Show 0 ' открываем форму-заставку
       '
       PauseTime = 10 ' задержка в 10 секунд
       Start = Timer
       ' Call AllStartOperations ' необходимые дополнительные операции
       Do While Timer < Start + PauseTime
       ' обеспечивает параллельное выполнение других процессов
       DoEvents
       Loop
       '
       Unload frmSplash ' выгружаем форму-заставку
       Msgbox "Hello!" ' фиксируем начало реальной работы

Обратите внимание, что здесь мы вставили обращение к процедуре AllStartOperations после получения начального времени таймера. Таким образом, время появления заставки на экране будет оптимизировано с учетом длительности выполнения дополнительных операций, то есть первый недочет начального варианта мы устранили. Для понимания смысла функции DoEvents (см. Совет 246) временно заблокируйте обращение к ней, поставив знак комментария. Запустите процедуру на выполнение и вы увидите, что форма-заставка появится без рисунка! Объясняется это тем, что управление возвращается в вызывающую программу до полного завершения прорисовки формы, но этот процесс не может завершиться из-за выполнения цикла Do... Loop. Функция же DoEvents обеспечивает возможность выполнения других параллельных процессов, в том числе и завершения прорисовки заставки.

Как нам теперь дать возможность пользователю сократить время задержки, например, закрыв форму-заставку щелчком мыши? Тут могут быть два варианта реализации цикла ожидания.

1. Анализ числа открытых форм:

Do
       OpenForms = DoEvents ' число открытых форм в приложении
       Loop While Timer < Start + PauseTime And OpenForms > 0

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

2. Анализ состояния формы-заставки:

Do
       DoEvents
       Loop While Timer < Start + PauseTime And frmSplash.Visible

Вот, собственно, и все по поводу создания стартовых заставок. Обратите внимание, что реализация этих программных конструкций в VB и VBA практически одинакова.

В начало В начало

Совет 248. Как изучать программирование в среде VBA

Парадокс заключается в том, что освоение программирования в среде MS Office представляет определенные трудности как для начинающих программистов, так и для опытных разработчиков. Первым нужно изучить незнакомый мир программирования, а вторым — овладеть функциональными возможностями офисных пакетов. И как выясняется на практике, для этого нужно читать не только книги по «программированию в Office», но и литературу (уже давно опубликованную) по собственно программированию и работе с офисными пакетами.

Не менее половины вопросов о «MS Office как средство разработки», поступающих в российский центр технической поддержки, относится к теме «Как научиться программировать»: как перекодировать данные, как работать со строковыми переменными, как использовать базы данных и пр.

Ответ на подобные вопросы довольно прост: изучайте материалы по программированию в среде обычного VB. Что касается самого программирования, MS Office и VB пересекаются на 70-80 процентов. И не нужно удивляться тому, что в книгах по «Office/VBA» вопросы технологии написания кода зачастую освещаются довольно скупо. Просто эти темы более подробно рассматриваются в других книгах.

Информацию об информационных ресурсах по VB можно найти по адресу www.visual.2000.ru/develop/

В начало В начало

Совет 249. Как обрабатывать строки на VBA и каковы преимущества для этого в MS Office 2000

Данный вопрос как раз относится к категории «Как изучать программирование». Строки в VBA обрабатываются точно так же, как и в обычном VB. «Обработка строк» рассматривается во многих книгах, но, как правило, это делается довольно бегло, в рамках отдельной главы.

Современные авторы не уделяют особого внимания этому вопросу, считая, что данная тема была досконально описана еще во времена Basic/DOS. Поэтому советуем заглянуть в архив, находящийся по адресу www.visual.2000.ru/develop/basicdos. Из современных публикаций рекомендуем прочитать соответствующую главу в книге «Использование Visual Basic 6.0» (www.visual.2000.ru/develop/vb/books-vb/), а также статью «Особенности работы со строковыми переменными в Visual Basic», опубликованную в журнале КомпьютерПресс 10/99 и 01/2000.

В начало В начало

Совет 250. Как перекодировать почтовые сообщения

Проблемы с двойной перекодировкой почтовых сообщений встречаются не часто, но они все же существуют.

В библиотеке Office Extensions (www.microsoft.ru/offext/) имеется довольно большая группа решений этой проблемы. Дело в том, что включить макрос в Outlook 97/98 было не очень просто (там использовался механизм VBScript, а не VBA). Поэтому большинство решений основывалось на варианте, когда исходный текст копируется в среду Word, где и производится перекодирование. К счастью, Outlook 2000 содержит уже полнофункциональный VBA.

Если вы хотите написать собственный макрос перекодирования текста, то советуем посмотреть решение RusTextC в библиотеке Office Extensions, которое представлено в виде «открытого кода». А о том, как интегрировать макрос в среду Word, можно прочитать в статье «Разработка приложений в среде Office 97».

КомпьютерПресс 2'2000