oldi

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

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

Новость: создан Web-архив повторно используемого кода

Нам пишут, мы отвечаем

Глобальный cовет: работайте с лицензионными копиями программ

Совет 271. Избегайте использования переменных типа Variant

Совет 272. Вывод анимационных GIF-файлов в VB

Совет 273. Как прочитать значения Системного Реестра в VB без помощи функций API

Совет 274. Реализация проверки правописания в RTF-документах в VB

Совет 275. Как реализовать ссылки к набору записей объекта Command, содержащегося в конструкторе Data Environment

Совет 276. Сжимайте длинные имена файлов с помощью библиотеки SHLWAPI

Совет 277. Еще один способ чтения нескольких элементов списка

Совет 278. Как можно просто связать элементы двух списков

Совет 279. Как реализовать работу с несколькими дисководами CD-ROM с помощью MCI-интерфейса

Совет 280. Как обрабатывать события, связанные с изменением свойств шрифта

Совет 281. Как определить, какой именно объект не может быть создан

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

Совет 283. Используйте библиотеку ADOX, чтобы установить существование внутренних объектов баз данных

Совет 284. Используйте оператор SendKeys

 

Программные примеры, которые использовались в приведенных здесь советах, можно найти по адресу: www.visual.2000.ru/develop/vb/source/.

Новость: создан Web-архив повторно используемого кода

В составе MS Office 2000 версии Developer была впервые включена полезная утилита VBA Code Librarian, обеспечивающая работу с иерархическими библиотеками исходных кодов программ (см. КомпьютерПресс 12’99, с. 169-175). В составе этого продукта поставляется довольно большая база данных CodeLib.mdb, которую разработчик может дополнять собственными фрагментами программного кода. Отметим, что содержимое этой базы данных представляет интерес также для VB-программистов, а сама утилита может применяться для поддержки наборов кода пользователями других инструментальных средств.

С конца марта нынешнего года программисты получили возможность доступа к новому Web-сервису Code Librarian Update, с помощью которого они могут пополнять свой локальный архив повторно используемого кода.

Первое ежемесячное обновление, содержащее более 100 функций, было подготовлено Visio, подразделением Microsoft (ранее независимая компания Visio, известный разработчик ПО для проектирования и графического изображения данных, была приобретена корпорацией Microsoft в сентябре прошлого года). Этот набор программ можно загрузить с Web-страницы http://msdn.microsoft.com/officedev/downloads/codelibrarian.asp

Выпуски Code Librarian Update будут выходить ежемесячно. Они будут содержать код, предоставленный различными сторонними компаниями (WRQ, Lawson, Elsinore Technologies и другими), которые разрабатывают продукты с поддержкой VBA. В другие продукты Microsoft, например в Microsoft MapPoint 2001 (новый продукт обработки картографических данных), также будет включен код, повышающий эффективность труда разработчиков.

Российское отделение Microsoft также довольно активно пополняет свои информационные ресурсы по VB и Office/VBA. Загляните на Web-серверы по адресам: www.microsoft.ru/msdn/library и www.microsoft.ru/offext/officedev/.

В начало

В начало

Нам пишут, мы отвечаем

Нам пришло такое письмо:

Просматривая CD-ROM ко второму номеру КП за 2000 год, в разделе «Советы тем, кто программирует на VB&VBA» с удивлением прочитал Совет 244 «Как преобразовать число в строку с фиксированным количеством цифр». Неужели редакция не знает о чудодейственной функции Format? С ее помощью тот же пример занимает всего одну строку кода и без всяких дополнительных художеств: Format (12345, «0000000»).

Альберт

Мы написали ответ, который считаем нужным опубликовать:

Уважаемый Альберт!

Спасибо, что читаете наши статьи, вдвойне — что читаете внимательно, втройне — что реагируете на наши недочеты. Был бы благодарен еще больше, если бы Вы (и все читатели) не только критиковали, но и делились собственным опытом работы.

Если говорить об ошибках в статьях в общем случае, то их, к сожалению, полностью избежать нельзя. Мы сами их порой обнаруживаем уже в опубликованном варианте. Иногда они появляются на этапе верстки, чаще — из-за наших собственных ошибок в исходном тексте. Мы стараемся «минимизировать» ущерб для наших читателей, сообщая о принципиальных ошибках на нашем сервере (www.visual.2000.ru/develop/vb/) и на страницах журнала. Но, честно говоря, больше всего беспокоит довольно вялая реакция читателей на эти ошибки. В результате у авторов появляются сомнения: а читает ли вообще кто-нибудь твои статьи? Использует ли кто-либо сведения, приведенные в них? Так что наша благодарность за Ваше замечание — вполне искренняя.

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

  1. Давайте уточним — редакция тут вообще ни при чем. Редакция непосредственно не занимается изучением тонкостей программирования на VB, во-вторых, она доверяет «опытным, авторитетным экспертам». Так что все упреки адресуйте не редакции вообще, а конкретно автору — Андрею Колесову, то есть мне.
  2. Честно скажу — я не знал (до Вашего письма) о такой возможности применения функции Format. Казалось бы, на этом можно было бы поставить точку (мол, виноват, исправлюсь), но на самом деле мне здесь видится важная методическая проблема.

    А кто вообще может похвастаться, что знает VB на все 100%? И если ответ — «никто», то является ли это недостатком пользователей или самого VB? Мне кажется, что средний пользователь представляет себе возможности системы процентов на 10, не более. И поэтому порой решает свои задачи довольно сложным образом, не подозревая, что оптимальное решение лежит рядом. Собственно, само решение освещать совершенно безграничную тему «Советов для тех...» определяется именно этим положением вещей.

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

    Это общая проблема современного мира информации: почти у любой проблемы есть готовое решение, но часто легче решить ее «с нуля», чем найти готовый ответ.

    Вопрос к Вам: откуда Вы узнали, что функцию можно применять таким образом? Представьте себе, что я — начинающий программист. Как я могу узнать о «чудодейственной функции Format»? Я просмотрел справочную информацию по всем версиям VB, начиная с 3.0 и кончая 6.0. И только в одной версии я нашел достаточно подробное описание данной функции и возможностей применения второго аргумента для числа.

    Думаю, что Вы отгадаете с первого раза, о какой версии идет речь. Конечно же, во VB3! Вопрос: откуда о возможностях функции Format сможет узнать пользователь версии 6.0?

  3. Однако даже если бы я знал обо всех возможностях этой функции, думаю, что публикация подобного совета (в котором вместо применения готовой функции использовала несколько более сложная конструкция) все равно имела бы смысл. Вообще говоря, я считаю, что VB (и современные средства программирования вообще) явно перенасыщены дублирующими функциями. Например, зачем создавать специальную функцию проверки существования файла, если ее можно выполнить уже имеющейся функцией Dir?

Давайте вернемся к упомянутому Совету 244. На самом деле приведенный Вами пример — a$ = Format (12345, «0000000») — можно реализовать еще проще: a$=”0012345". Ведь в нашем совете речь шла о создании функции, которая преобразовывала произвольное число SourceNumber в строку с заданным числом цифр Lend. С использованием функции Format это будет выглядеть так:

a$ = Format(SourceNumber, String$(Lend, “0”))

В нашем варианте это выглядит немного более замысловато:

If 10^Lend > SourceNumber Then
    a$ = Right$(10^Lend + SourceNumber, Lend)
Else
    a$ = Str$(SourceNumber)
End If

Основная сложность нашей конструкции — проверка на допустимость параметров функции. Но обратите внимание на преимущество последнего варианта: это может сделать каждый программист, на любой версии Basic. (Даже на QBasic — поверьте, что пользователей этой системы еще довольно много.)

Нам кажется, что демонстрация того, что многие функции могут быть решены неким тривиальным набором операций, очень важна, так как она стимулирует разработчика к поиску собственного решения (чтобы не ждать, когда Microsoft решит осчастливить человечество своим встроенным оператором).

4. И все же основная цель нашей рубрики — поделиться собственным опытом, своими находками. Действительно, порой имеет место «изобретение велосипеда». Но чем больше людей (разработчиков) будут участвовать в этом обсуждении, тем меньше будет таких «велосипедов».

Короче говоря: спасибо за письмо. Оставайтесь с нами.

Присылайте свои советы, замечания, вопросы.

Андрей Колесов,

один из ведущих рубрики «Советы для тех...»

В начало

В начало

Глобальный cовет: работайте с лицензионными копиями программ

Наш многолетний опыт общения с пользователями VB позволяет нам сделать уверенный вывод: пиратские копии программ, продаваемые в Митино, на Горбушке и пр., отличаются от оригиналов. Мы не являемся службой поддержки Microsoft (не несем каких-то обязательств перед корпорацией), но мы придерживаемся такого подхода при анализе проблем, с которыми к нам обращаются читатели. Если при воспроизведении некоего примера мы получаем различные результаты (у нас работает, а у спрашивающего — нет), то сразу задаем вопрос: какая копия VB у вас стоит? Дело в том, что проблемы довольно часто возникают именно из-за применения программ неизвестного происхождения.

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

В начале весны к нам в офис приехал за консультацией человек, которому мы помогали в разработке его программы лет шесть назад, во времена Basic/DOS. У него не работала программа, которую он скачал из Интернета, а она была ему очень интересна.

Проблема решалась тривиально — ошибка была в «левой» копии VB 6, установленной на ноутбуке клиента (не работало подключение OCX-компонентов). Но самое поразительное было в другом — у него стояла программа с полностью русифицированным интерфейсом (Microsoft выпускает локализованные версии VB только с русской справкой). Но наш пользователь при этом был полностью уверен, что его инструмент — точная копия оригинала.

Мы часто ищем истоки российского пиратства в низкой покупательной способности населения. Но вот что интересно — наш программист приехал к нам на иномарке с довольно приличным ноутбуком. Неужели он не понимает, что время, которое он тратит на борьбу с ошибками пиратских копий, — это деньги, которые он теряет?

В начало

В начало

Совет 271. Избегайте использования переменных типа Variant

Наш Совет 259 (об использовании операторов Print # и Write #) был основан на замечании, которое прислал наш читатель Константин Абакумов по поводу конструкций, использованных нами в коде утилиты Summa.vbp (сумма прописью, Совет 228). Кроме того, он обнаружил еще одну «дырочку» в этой программе: оказалось, что следующая конструкция у него давала неверный результат:

Dim InVal
...
Input #1, InVal                  ‘ здесь у Константина не срабатывала
If InVal = True Then Call ...    ‘ проверка при вводе значения True
...

Константин предложил заменить последнюю строку на такой работоспособный вариант:

If InVal Then Call ...    ‘ при вводе значения True

Совершенно очевидно, что оба варианта в принципе тождественны. Не говоря уже о том, что у нас исходный вариант надежно работал. В чем же дело?

Проблема заключалась в том, что мы работали в среде VB5 (мы сознательно используем эту версию, если нет нужды в применении новшеств VB6), а наш читатель — в VB6. Судя по всему, в VB6 имеется ошибка, в результате чего внешне правильная конструкция оказалась неработоспособной.

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

Мы считаем, что VB (как и многие другие современные системы программирования) обладает серьезным технологическим недостатком, который заключается в широком использовании неявного преобразования типов данных. С точки зрения классических принципов программирования конструкция типа:

SrtVal$ = IntVal%

является просто недопустимой — преобразование типов должно выполняться только с помощью специальных функций в явном виде, например так:

SrtVal$ = Str$(IntVal%)

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

Строго говоря, неявное преобразование данных недопустимо даже в арифметических операциях (из целых в вещественные и наоборот). Например, результат такого выражения:

sVal! = 1/3*6

в зависимости от желания разработчика компилятора может быть равным и 0 и 2. И в обоих случаях разработчик будет прав, так как нет жестких правил порядка преобразования данных.

Что же касается конструкции (вполне допустимой в VB) типа

strTrue$ = “True”
If strTrue$=True Then ...,

то она вообще представляется кошмарной.

Логическим выводом из вышесказанного является то, что появление некоторого универсального типа данных, которым в VB является Variant, является грубым нарушением классических принципов программирования. Желание помочь программистам («вам не нужно думать о форме представления данных») на самом деле усложнило разработку программ.

Пример тому — приведенная выше ситуация, когда VB сам запутался в том, как нужно интерпретировать переменную InVar. Кто-то отнесет это к невнимательности разработчиков Microsoft, но на самом деле появление этой ошибки было предопределено стратегией на смешение типов данных.

Каемся: мы были не правы, что использовали в утилите Summa общую переменную InVar (по умолчанию — Variart) для обработки ввода нескольких параметров разных типов данных. Мы исправили код, который теперь выглядит так:

Dim InBool As Boolean, InText$, InVal%
        Input #1, InBool: If InBool Then Call LabelSet(1)
        Input #1, InText: txtW1.Text = InText

ИЗБЕГАЙТЕ использования переменных типа Variant! Применяйте фиксированные типы переменных и функции явного преобразования типов данных. Если у вас есть доводы против этого тезиса — присылайте нам (akolesov@glasnet.ru) свои соображения.

В начало

В начало

Совет 272. Вывод анимационных GIF-файлов в VB

Хотя элемент управления Picture позволяет отображать на экране графические изображения, он выводит только первый рисунок из анимационного GIF-файла. Чтобы полностью показать такой файл, не создавая заново всю последовательность изображений, можно воспользоваться элементом управления WebBrowser (который, правда, недоступен на компьютерах, где отсутствует Internet Explorer 3.0 или выше). Для этого установите компонент Microsoft Internet Controls (команда Project|Components), и тогда на панели инструментов Visual Basic появится элемент управления WebBrowser. Поместите его на форму, а затем в событии Form_Load() введите следующий код:

WebBrowser1.Navigate “filespec”

где filespec — полное имя GIF-файла (включая путь к нему) или URL-адрес. Запустите программу на выполнение, и Visual Basic выведет указанный файл.

К сожалению, WebBrowser одновременно выведет вертикальную линейку прокрутки на правой стороне формы, что не вполне сочетается с графическим изображением. Чтобы отключить ее, как ни удивительно, можно применить тот же самый метод, что обычно реализуется в HTML-коде:

WebBrowser1.Navigate “about:<html> _
    <body scroll=’no’><img src=’filespec’> _
    </img></body></html>”

Теперь, когда вы запустите программу, Visual Basic выведет графическое изображение без линейки прокрутки.

В начало

В начало

Совет 273. Как прочитать значения Системного Реестра в VB без помощи функций API

В некоторых случаях бывает необходимо управлять Реестром Windows в VB, не прибегая к использованию функций API. Для этого существует библиотека Registry Access Functions (RegObj.dll), позволяющая создавать объект Registry, при помощи которого можно управлять конкретными ключами. Это может пригодиться, например, в следующем случае.

В предыдущем Совете мы продемонстрировали использование элемента управления WebBrowser. Однако, как мы уже отмечали, WebBrowser доступен только в том случае, если на машине-приемнике также установлен Internet Explorer. Поэтому, прежде чем приступить к выводу анимации, было бы целесообразно определить, имеется там IE или нет. Для этого вначале установите в своем проекте ссылку к библиотеке

Registry Access Functions (команда Project|References) и введите код, аналогичный тому, что приводится здесь:

Dim myReg As New Registry, KeyFound As Boolean
Dim HasIE As Boolean, sValue As String
    sValue = “”
    HasIE = False
    KeyFound = myReg.GetKeyValue(HKEY_LOCAL_MACHINE, _
        “Software\Microsoft\Windows\CurrentVersion\” & _
        “App Paths\IEXPLORE.EXE”, “Path”, sValue)
    If KeyFound Then HasIE = (sValue <> “”)
    ‘ выводит полное название каталога,
    ‘ где установлен IE
    If HasIE Then MsgBox sValue
    Set myReg = Nothing
В начало

В начало

Совет 274. Реализация проверки правописания в RTF-документах в VB

Для проверки правописания в RTF-документах можно было бы прибегнуть к следующему способу: внедрить Word в свое приложение (этот вариант приведен ниже, в Совете 282). Однако мы рекомендуем воспользоваться элементом управления WebBrowser, о котором шла речь в двух предыдущих Советах и с помощью которого можно организовать такую проверку. Для этого вам понадобится метод ExecWB() с флагом OLECMDID_SPELL. В качестве иллюстрации поместите WebBrowser на форму и введите такой код в событие Form_Load():

WebBrowser1.Navigate “filespec”

Замените filespec любой строкой, которая указывает путь к RTF-файлу. Затем добавьте к форме командную кнопку, для которой в событии Click напишите следующий код:

WebBrowser1.ExecWB OLECMDID_SPELL, OLECMDEXECOPT_DODEFAULT

Запустите проект на выполнение. Элемент управления WebBrowser выведет указанный RTF-документ, и, когда вы щелкнете командную кнопку, VB активизирует установленную на вашем компьютере программу проверки правописания.

В начало

В начало

Совет 275. Как реализовать ссылки к набору записей объекта Command, содержащегося в конструкторе Data Environment

Каждый объект Command в новом конструкторе Data Environment в VB 6.0 имеет соответствующий ему набор записей. Для того чтобы в коде программы сослаться на этот объект, необходимо добавить к его имени префикс rs. Так, если конструктор Data Environment содержит объект Command с именем cmdSomeQuery, то для ссылки к набору записей этого объекта напишите примерно такую строку кода:

Set rst = DataEnvironment1.rscmdSomeQuery
В начало

В начало

Совет 276. Сжимайте длинные имена файлов с помощью библиотеки SHLWAPI

Использование функции PathCompactPath из библиотеки SHLWAPI — один из способов сжатия длинных имен файлов, благодаря которому часть имени слева заменяется на многоточие (...). Для работы с данной API-функцией требуется описать ее следующим образом:

Private Declare Function _
PathCompactPath Lib “shlwapi”_
    Alias “PathCompactPathA” _
    (ByVal hDC As Long, ByVal _
    lpszPath As String, _
    ByVal dx As Long) As Long

Как видно из этого описания, функция PathCompactPath содержит три аргумента: первый из них задает дескриптор контекста устройства (device context handle), второй — имя файла, которое будет сжиматься, и, наконец, последний — ширину в пикселах того компонента на форме, куда мы хотим поместить это имя. Так, чтобы вывести компактное имя файла в метке с именем lblEllipsis, напишем следующий код для события Click() командной кнопки:

Private Sub Command1_Click()
Dim lhDC As Long, lCtlWidth As Long
Dim FileSpec As String
    FileSpec = “C:\MyFolder\VisualBasic\” &
        MyReallyWayTooLongFolderName\ButWhoCares\IhaveTheAPI.doc”
    Me.ScaleMode = vbPixels
    lCtlWidth = lblEllipsis.Width - Me.DrawWidth
    lhDC = Me.hDC
    PathCompactPath lhDC, FileSpec, lCtlWidth
    lblEllipsis.Caption = FileSpec
End Sub
В начало

В начало

Совет 277. Еще один способ чтения нескольких элементов списка

Обычное правило чтения выделенных элементов окна списка, поддерживающего выбор нескольких позиций (иными словами, того, у которого свойство MultiSelect отлично от 0), гласит, что необходимо организовать в цикле просмотр всех элементов и проверить у них значение свойства Selected. Однако такой подход (как и при работе с любыми циклами) может значительно снизить быстродействие создаваемого вами приложения, особенно на менее скоростных процессорах. В качестве более быстрой и элегантной альтернативыпредлагаем вам воспользоваться API-функцией SendMessage().

Как известно, с помощью данной функции можно отправить сообщение в одно или несколько окон. Ее описание выглядит следующим образом:

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

Поскольку мы хотим прочитать все выделенные элементы списка, необходимо отправить константу LB_GETSELITEMS в качестве аргумента wMsg и описать ее так:

Private Const LB_GETSELITEMS = &H191

По существу сообщение LB_GETSELITEMS заполняет массив значениями индексов всех выделенных элементов. В результате вместе с функцией SendMessage() необходимо передать два дополнительных аргумента. Первый из них должен содержать максимальное количество выделенных элементов, получить которое можно с помощью свойства SelCount элемента управления ListBox. Второй же аргумент должен хранить переменную массива, которую мы хотим заполнить значениями индексов.

Следующий пример демонстрирует, как можно использовать функцию SendMessage(). Поместите на форму элемент управления ListBox1, установите его свойство MultiSelect как 1-Simple и заполните список. Затем добавьте командную кнопку Command1 и напишите следующий код для ее события Click:

Dim ItemIndexes() As Long, x As Integer, iNumItems As Integer
NumItems = ListBox1.SelCount
If iNumItems Then
    ReDim ItemIndexes(iNumItems - 1)
    SendMessage ListBox1.hwnd, LB_GETSELITEMS, iNumItems, _
    ItemIndexes(0)
End If
For x = 0 To iNumItems - 1
    MsgBox ListBox1.List(ItemIndexes(x))
Next x

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

В начало

В начало

Совет 278. Как можно просто связать элементы двух списков

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

Array(3, “Конфеты”, “Мишка на Севере”, “Белочка”, “Красная Шапочка”)

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

Чтобы протестировать приведенный ниже код, создайте проект Standard EXE, а потом поместите на форму два окна списка, оставив без изменения их имена List1 и List2:

Option Explicit
Private varArray As Variant
Private varSubArray As Variant
Private Sub Form_Initialize()
    varArray = Array(Array(4, “Фрукты”, “Яблоки”, _
    “Апельсины”, “Персики”, “Груши”), Array(5, _
    “Овощи”, “Горох”, “Бобы”, “Кукуруза”, “Свекла”, _
    “Лук”), Array(3, “Ежедневные продукты”, _
    “Молоко”, “Сметана”, “Масло”))
End Sub
Private Sub Form_Load()
    Dim intIndex1 As Integer
    With List1
        For intIndex1 = 0 To UBound(varArray)
            varSubArray = varArray(intIndex1)
            .AddItem varSubArray(1)
        Next intIndex1
        .ListIndex = 0
    End With
End Sub
Private Sub List1_Click()
    Dim intIndex2 As Integer
    With List2
        varSubArray = varArray(List1.ListIndex)
        .Clear
        For intIndex2 = 0 To varSubArray(0) - 1
            .AddItem varSubArray(intIndex2 + 2)
        Next intIndex2
        .ListIndex = 0
        .Refresh
    End With
End Sub
В начало

В начало

Совет 279. Как реализовать работу с несколькими дисководами CD-ROM с помощью MCI-интерфейса

Интерфейс MCI (Media Control Interface — Интерфейс управления средой) позволяет поддерживать несколько устройств для чтения аудиокомпакт-дисков. Для этого следует просто указать имя дисковода в команде MCI Open. Вначале поместите окно списка List1 на форму, а затем, чтобы определить, какие дисководы предназначены для чтения компакт-дисков, напишите в разделе General Declarations формы такой код:

Option Explicit
Private Declare Function GetDriveType Lib _
    “kernel32” Alias “GetDriveTypeA” (ByVal _
    nDrive As String) As Long
Private Declare Function mciSendString Lib _
    “winmm.dll” Alias “mciSendStringA” (ByVal _
    lpstrCommand As String, ByVal lpstrReturnString _
    As String, ByVal uReturnLength As Long, ByVal _
    hWndCallback As Long) As Long
Private Const DRIVE_CDROM = 5

Подпрограмма Form_Load заполняет окно списка обнаруженными на компьютере именами дисководов CD-ROM:

Sub Form_Load()
    Dim k As Long
    For k = Asc(“A”) To Asc(“Z”)
        If GetDriveType(Chr$(k) & “:”) = DRIVE_CDROM Then
            List1.AddItem Chr$(k) & “:”
        End If
    Next
End Sub

А чтобы действительно открыть дверцу дисковода, куда можно будет вставить компакт-диск, введите такой код в событие List1_dblClick:

Private Sub List1_DblClick()
    mciSendString “open” & _
        List1.List(List1.ListIndex) & _
        “type cdaudio alias cdaudio”, _
        vbNullString, 0, 0
    mciSendString “set cdaudio door open”, _
        vbNullString, 0, 0
    mciSendString “close cdaudio”, _
        vbNullString, 0, 0
End Sub
В начало

В начало

Совет 280. Как обрабатывать события, связанные с изменением свойств шрифта

Предположим, вы хотите выполнить какое-нибудь действие при изменении любых свойств шрифта конкретного элемента управления или формы. Для этого вам понадобится ключевое слово WithEvents. (Не забудьте установить ссылку OLE Automation в диалоговом окне References с помощью команды Project|References):

Private WithEvents fntAny As StdFont

Затем напишите подпрограмму, которая будет реагировать на изменения свойств шрифта:

Private Sub fntAny_FontChanged(ByVal _
    PropertyName As String)
    Select Case PropertyName
        Case “Name”
            ‘ Какое-либо действие
        Case “Size”
            ‘ Какое-либо действие
        Case “Italic”
            ‘ Какое-либо действие
        Case “Bold”
            ‘ Какое-либо действие
        Case “Underline”
            ‘ Какое-либо действие
        ‘...
        ‘ Подобным образом можно расширить
        ‘ функциональные возможности для
        ‘ каждого свойства шрифта
    End Select
End Sub

Теперь осталось только установить свойство Font формы или элемента управления как fntAny. Так, если вы хотите отслеживать изменения свойств шрифта формы, напишите следующий код в событии Form_Load:

Set fntAny = Me.Font
‘ Если вы имеете дело с элементом управления,
‘ тогда Control.Font
В начало

В начало

Совет 281. Как определить, какой именно объект не может быть создан

При разработке крупного VB-приложения, использующего сотни COM-объектов, вы можете в какой-то момент получить сообщение об ошибке такого вида: «429 can’t create object». К сожалению, эта информация не очень-то поможет вам определить, какой именно объект не может быть создан. Чтобы преодолеть подобное ограничение, можно написать функцию на базе функции CreateObject из библиотеки Visual Basic runtime objects and procedures:

Public Function CreateObject(sProgID As String) As Object
    ‘
    On Error GoTo CreateErr
    ‘ Вызов функции CreateObject из библиотеки
    ‘ VB runtime objects and procedures
    Set CreateObject = VBA.CreateObject(sProgID)
    Exit Function
        ‘
CreateErr:
    ‘ возвращает сообщение об ошибке вместе
    ‘ с именем объекта, который не может
    ‘ быть создан
    Err.Raise Err.Number, “CreateObject Wrapper”, _
    Err.Description & “: ‘“ & sProgID & “‘“
End Function
В начало

В начало

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

VB позволяет осуществить интеграцию возможностей проверки правописания, имеющихся в Microsoft Word 97/2000, в VB-приложения, сохраняя при этом параметры форматирования внутри элемента управления RichTextBox. Продемонстрируем это на таком примере:

  1. Создайте проект Standard EXE в VB.
  2. Добавьте к панели инструментов элемент управления RichTextBox (команда Project|Components).
  3. Добавьте ссылку к библиотеке Microsoft Word 8.0 Object Library (для Word 2000 — Microsoft Word 9.0 Object Library).
  4. Разместите на форме элементы управления RichTextBox и CommandButton.
  5. Переименуйте компонент RichTextBox в rtfText.
  6. Установите свойство Caption командной кнопки как «Правописание».
  7. Введите в событие Click командной кнопки следующий код:
Private Sub Command1_Click()
        On Error GoTo SpellCheckErr
        Dim oWord As Object
        ‘
        Set oWord = CreateObject(“Word.Application”)
        ‘
        ‘ сохраняет содержимое компонента RichTextBox
        ‘ во временном файле
        rtfText.SaveFile “c:\Vb-db\Test.RTF”
        ‘
        ‘ открывает сохраненный файл и проводит
        ‘ в нем проверку правописания
        oWord.Documents.Open (“c:\Vb-db\Test.RTF”)
        oWord.ActiveDocument.SpellingChecked = False
        oWord.Options.IgnoreUppercase = False
        oWord.ActiveDocument.CheckSpelling
        ‘
        ‘ сохраняет изменения в RTF-файле
        ‘ и закрывает его
        oWord.ActiveDocument.Save
        oWord.ActiveDocument.Close
        oWord.Quit
        ‘
        ‘ загружает изменения в элемент
        ‘ управления RichTextBox
        rtfText.LoadFile “c:\Vb-db\Test.RTF”
        
        Set oWord = Nothing
        Screen.MousePointer = vbDefault
        MsgBox “Проверка правописания закончена”, _
                vbInformation, “Правописание”
        Exit Sub
        ‘
SpellCheckErr:
        MsgBox Err.Description, vbCritical, “Правописание”
        Set oWord = Nothing
End Sub
  1. Сохраните проект и запустите его на выполнение.
  2. Введите какой-нибудь текст в элемент управления RichTextBox и затем щелкните кнопку «Правописание». Вы попадете в среду Word, где и осуществите проверку правописания.
В начало

В начало

Совет 283. Используйте библиотеку ADOX, чтобы установить существование внутренних объектов баз данных

Вскоре после выпуска библиотеки ADO компания Microsoft создала для нее расширение, называемое ActiveX Data Objects Extensions, или просто ADOX, и включающее большую часть функций DAO, которые не вошли в состав стандартной версии ADO. С помощью библиотеки ADOX можно легко определить, входит ли конкретная таблица, разрез данных или запрос в базу данных.

Для этого установите ссылку к библиотеке Microsoft ADO Ext. for DDL and Security. В упрощенном виде ADOX состоит из объекта Catalog, который включает коллекции объектов, описывающих базу данных и содержащиеся в ней таблицы и разрезы данных. Чтобы проверить наличие конкретной таблицы в коллекции Tables, можно пройти шаг за шагом по всей коллекции и сравнить имя каждого элемента с заданной строкой либо воспользоваться предлагаемым ниже способом:

Private Sub Command1_Click()
    Dim con As New ADODB.Connection
    Dim cat As New ADOX.Catalog
    Dim tbl As ADOX.Table
    Dim tblName As String
    con.Open “Provider=Microsoft.Jet.OLEDB.4.0;” & _
        “Data Source=c:\Vb-db\Biblio.mdb;”
    Set cat.ActiveConnection = con
    On Error Resume Next
    tblName = “Titles”
    Set tbl = cat.Tables(tblName)
    If tbl Is Nothing Then
        MsgBox “Таблица “ & tblName & “ не существует”
    Else
        MsgBox “Таблица “ & tblName & “ существует”
        Set tbl = Nothing
    End If
    Set cat = Nothing
    Set con = Nothing
End Sub
В начало

В начало

Совет 284. Используйте оператор SendKeys

В нашем Совете 264 мы рассказывали о том, как программным образом имитировать нажатие клавиши с помощью обращения к соответствующей API-функции. Оказывается, что в VB6 можно использовать для этих целей встроенный оператор SendKeys (любопытно, что его не было в VB5, он присутствовал в VBA 5 — Office 97). Например, посылка кода Enter выглядит следующим образом:

SendKeys “{Enter}”

Такая программная имитация нажатия клавиши может быть полезна при создании макрокоманд в MS Office. Ведь некоторые команды в ходе их выполнения выдают диагностические сообщения с требованием подтвердить выполнение операции или выбрать нужный вариант ее реализации. Использование SendKeys позволяет автоматически выполнить подобные «нажатия» кнопок.

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