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

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

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

© 1997, Андрей Колесов, Ольга Павлова
Авторский вариант. Статья была опубликована c незначительной литературной правкой в журнале "КомпьютерПресс" N 3/97, с.116-120.


Совет 88. Будьте внимательны при установке VB 5.0.

У вас могут появиться некоторые проблемы при установке VB 5.0 (в том числе и свободно распространяемой редакции VB5/CCE), если на компьютере уже стоит VB 4.0. На это особенно стоит обратить внимание тем, кто рискует работать с бета- версиями, уже вовсю распространяющимися на "китайских" CD.

Дело в том, что VB 5.0 и VB 4.0 используют ряд одних и тех же элементов управления OCX. Соответственно, при установке VB 5.0 он автоматически заменяет эти модули на свои. С чисто юридической точки зрения может возникнуть проблема с дистрибьюцией приложений, написанных для VB 4.0, в которые могут попасть компоненты VB 5.0. Об этом были специально предупреждены бета-тестеры. Но могут возникнуть трудности и чисто технического характера. Поясним это на собственном примере.

Мы установили на свой ПК, где уже был VB 4.0, сначала VB5/CCE (бета-версия 1), а потом VB5/Pro (официальная бета-версия 2). Неожиданно при запуске утилиты API Text Viewer (VB 4.0) появилось сообщение об ошибке: "Модуль COMDLG32.OCX отсутствует или неверно лицензирован". Потом обнаружилось, что и другая утилита не хочет работать с COMCTL32.OCX. Однако сам VB 4.0 работал с этими модулями нормально. После небольшого анализа прояснилась следующая ситуация.

Оказалось, что на CD находилось по две версии этих модулей: для VB5/CCE с датой 25.10.96 и для VB5/Pro с датой 01.10.96. Соответственно при их установке автоматически остались модули с более поздней датой (VB5/CCE). Мы подумали, не возникли ли проблемы из-за каких-то наших ошибок при установке (мы проводили установку в несколько приемов, что-то добавляя, что-то удаляя и пр.), и решили заново провести полную инсталляцию. Однако после удаления VB5/Pro с компьютера исчезли все его OCX: он посчитал их своими собственными компонентами! Остались лишь файлы COMDLG32.OCX и COMCTL32.OCX, которые он, по-видимому, определил как чужие из-за их даты. Короче говоря, VB 4.0 оказался без расширенного набора элементов управления.

Повторив установку VB5/Pro, мы обнаружили те же самые ошибки. Тогда, заподозрив дефект именно в модулях от 25.10.96, мы опять удалили VB5/Pro (для чистоты эксперимента), переименовали на жестком диске файлы COMDLG32.OCX и COMCTL32.OCX от 25.10.96 и повторили установку. С версиями модулей от 01.10.96 все вроде бы стало работать нормально.

Хотелось бы подчеркнуть, что речь здесь шла не о конечных версиях продукта, а об их бета-версиях. Однако описанная ситуация является довольно типичной для проблемы обновления версий вообще. В связи с этим нужно сказать, что идея компонентной организации вычислительных систем (когда разные приложения используют одни и те же компоненты — OCX, DLL и пр.) является безусловной прогрессивной и заманчивой, но в процессе ее практической реализации возникают многие вопросы, в том числе касающиеся обновления версий компонентов, контроля их принадлежности (например, когда при удалении приложения оно заодно удаляет и общие модули) и т.п. К тому же, несмотря на все желания разработчика, не всегда удается добиться полной совместимости "снизу вверх". Или у вас вдруг могут возникнуть проблемы с оперативной памятью из-за увеличения размеров новых версий компонентов. Так что будьте внимательны.

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

Совет 88a. Индексирование русскоязычных баз данных

Наш читатель обратился к нам с такой проблемой:

При создании базы данных в VB 4.0 с помощью Data Manager для русскоязычных строковых переменных не создается индекс и не работают методы поиска и сортировки. Однако если создать БД с помощью русскоязычного ACCESS в русскоязычной версии Windows, то потом с ней можно работать в VB без всяких проблем. Создавать БД в среде VB без Data Manager я не пробовал, может быть, там этих проблем и нет.

Ответ

При работе в VB правила сортировки и поиска в базах данных в самой программе устанавливаются с помощью параметра locale при создании и преобразовании БД (методы CreateDatabase и CompactDatabase). После создания базы данных значение параметра фиксируется (для объектов DataBase и Field) в виде свойства CollatingOrder, которое можно прочитать (но не изменить!) в ходе работы программы:

object.CollatingOrder

Этот параметр можно использовать в программе для настройки операции сравнения и поиска строковых переменных, создания новых объектов (например, баз данных) и пр.

Значения наиболее актуальных вариантов параметра locale для VB 4.0 (в нем предусмотрено 20 значений для разных языков) таковы:

dbSortGeneral = 1033 = &409     ' English
dbSortCyrillic = 1049 = &419    ' Russian - в VB 3.0 его нет
dbSortNeutral = 1024 = &400     ' без сортировки

(Для VB 3.0 состав кодов меньше, русского языка там нет, символьные названия констант и их значения — другие).

Эти параметры также можно задавать и при работе в Data Manager. Создавая и открывая базу данных, выделите в списке нужную таблицу и нажмите кнопку Design. В списке описателей полей Вы увидите параметр CollatingOrder, который задается в цифровом виде (конечно, было бы удобнее иметь дело со списком типа General, Cyrillic...). Затем выберите нужное поле, нажмите Edit и т.д.

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

Совет 89. Управляйте режимами преобразования, сортировки и сравнения символьных переменных.

Учитывая предыдущий вопрос читателя, имеет смысл подробнее рассмотреть некоторые аспекты работы с символьными переменными, в том числе с русскими буквами. Вообще говоря, переменная String представляет собой простую последовательность байтов. Соответственно операции сравнения (на них были основаны также алгоритмы поиска и сортировки) сводятся к последовательному сравнению значений байтов строки (кодов символов). Однако в частном (но наиболее часто встречающемся) случае строка является осмысленным набором символов, которые записаны в виде ASCII кода. А для них операции побайтового сравнения кодов не всегда подходят.

Например, для варианта русской кодовой таблицы ASCII последовательность сортировки (в порядке возрастания кодов) выглядит так:

ABCD...abcd...АБВГ...абвг

Для алфавитной же сортировки требуется другая последовательность (именно она реализуется при работе с базами данных):

aAbBcCdD...аАбБвВгГ

А для операций поиска необходимо часто вообще игнорировать регистр букв (прописные/строчные) (ignore case). В старых версиях Basic операторы Ucase/Lcase (преобразование всей строки в прописные или строчные буквы) являются фактически единственными командами, позволяющими производить какие-либо специфические операции над символьными переменными. Но они работали только с английскими буквами!

Впервые алгоритмы алфавитной сортировки и поиска были реализованы в базах данных ISAM, включенных в MS Basic PDS 7.1. В них была предусмотрена поддержка нескольких национальных языков, но русского среди них не было. В VB 3.0 в дополнение к работе с БД (а, может быть, и раньше: с VB 2.0 мы не работали) появились аналогичные возможности на языковом уровне — операторы InStr и StrComp. В VB 4.0 была реализована также поддержка для русского языка.

Преобразование символьных данных

В VB 4.0 операторы Lcase/Ucase выполняют соответствующие преобразования не только над латинскими буквами (как в VB3), но и со всеми буквами установленной кодовой таблицы Windows 95. (У нас установлена 32-разрядная версия VB4. Может быть, это работает и для Windows 3.x? Поделитесь опытом.) Таким образом, для cp251 результатом функции Ucase$("Вася") будет: ВАСЯ. В VB 4.0 появилась также новая функция StrConv, которая выполняет дополнительные варианты преобразования кодов (в том числе аналог операций Ucase/Lcase в Unicode и обратно).

Операции сравнения

В VB есть два оператора: поиска — InStr (расширенный вариант оператора INSTR, используемого в Basic/DOS) и сравнения — StrComp. В них имеется возможность использования дополнительного (необязательного) параметра Compare:

В случае отсутствия параметра Compare в операторе используется его значение по умолчанию — 0 (двоичная обработка). Однако этот параметр по умолчанию можно изменить для всех процедур конкретного модуля с помощью оператора Option Compare Binary/Text: Binary указывает на режим двоичного сравнения (он установлен по умолчанию), Text — на алфавитный режим для текущей кодовой таблицы Windows.

Примеры (VB4, cp1251):

Print StrConv ("Петя петухов", 3)  ' = Петя Петухов
Print InStr ("Петя петухов", "п", 0)   ' = 6
Print InStr ("Петя петухов", "п", 1)   ' = 1
Print StrComp ("Петя", "петЯ", 1)  ' = -1
Print StrComp ("Петя", "петЯ", 0)  ' = 0

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

Совет 90. Простой алгоритм преобразования прописных букв в строчные и наоборот

ASCII-таблица латинских символов организована таким образом, что коды строчных букв (a-z = &H61-&H7A) отличаются от кодов соответствующих прописных (A-Z = &H41-&H5A) только наличием 1 в третьем разряде байта (&H20). Более того, данный принцип реализован для Windows-кодировки (cp1251) русских букв: а-я = &HE0-&HFF, А-Я = &HC0-&HDF.

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

Word$ = "aBcDeF"
For i% = 1 to Len(Word$)
  Mid$(Word$,i%) = Chr$(Asc(Mid$(Word$,i%)) Xor &H20)
Next
Print Word$   'напечатано - AbCdEf 

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

Совет 91. Установка специальных шрифтов приложения

Бывают ситуации, когда в состав вашего приложения входят какие-то специальные шрифты, которые распространяются вместе с ним. Соответственно эти шрифты должны входить в состав дистрибутива и устанавливаться на жесткий диск в процессе инсталляции, то есть их надо уметь аккуратно добавлять к системе. Для этого можно использовать API-функцию LoadFontResource. Однако вначале следует самостоятельно скопировать файл в то место, где хранятся остальные шрифты. В Windows файл шрифта копируется в системный каталог, а в Windows 95 — в каталог \Windows\Fonts.

После вызова функции LoadFontResource нужно известить все открытые окна о том, что таблица шрифтов была изменена. Для этого отправьте в HWND_BROADCAST сообщение WM_FONTCHANGE, которое даст указание Windows послать данное сообщение во все открытые окна.

Процедура AddFont копирует файл шрифтов, регистрирует данный шрифт, а затем уведомляет об этом все открытые окна. Она представлена в варианте для VB 4.0. Для VB 3.0 в этом тексте нужно убрать фрагмент, относящийся к 32-разрядной версии, и объявление Private в операторах Declare:

Option Explicit
 #If Win32 Then
    Private Declare Function AddFontResource Lib _
            "gdi32" Alias "AddFontResourceA" (ByVal _
             lpFileName As String) As Long
    Private Declare Function SendMessage Lib _
             "user32" Alias "SendMessageA" (ByVal hWnd _
             As Long, ByVal wMsg As Long, ByVal wParam _
             As Long, lParam As Long) As Long
     Private Declare Function GetWindowsDirectory _
             Lib "kernel32" Alias "GetWindowsDirectoryA" _
             (ByVal lpBuffer As String, ByVal nSize As _
             Long) As Long
 #Else
     Private Declare Function AddFontResource Lib _
             "GDI" (ByVal lpFilename As Any) As Integer
     Private Declare Function SendMessage Lib "User" _
             (ByVal hWnd As Integer, ByVal wMsg As Integer, _
             ByVal wParam As Integer, lParam As Any) As Long
     Private Declare Function GetWindowsDirectory _
             Lib "Kernel" (ByVal lpBuffer As String, ByVal _
             nSize As Integer) As Integer
 #End If

Const WM_FONTCHANGE = &H1D
Const HWND_BROADCAST = &HFFFF&

Function AddFont3 (FileName As String) As Integer
  Dim WindowsDir As String
  Dim Lbuf As Long
  ' - Получение каталога Windows
  Lbuf = GetWindowsDirectory (WindowsDir, Len (Buffer))
  If Lbuf Then
    WindowsDir = Left$(windowsDir, Lbuf)
    ' - Копирование файла
    FileCopy FileName, WindowsDir & "\Fonts\" & FileName
    ' - Добавление шрифта
    If AddFontResource (FileName) Then
      SendMessage HWND_BROADCAST, WM_FONTCHANGE, 0, 0
      AddFont3 = True
    End If
  End If
End Function

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

Совет 92. Автоматическая установка кавычек в строковых переменных

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

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

SQLx = "INSERT UserTable VALUES ("
SQLx = SQLx & Index & ","
SQLx = SQLx & q(txtUserName.text) & ","
SQLx = SQLx & q(txtPassword.text) & ")"

Function q(strng As String) As String
  '
  ' Данная функция возвращает передаваемую
  ' ей символьную переменную, заключенную
  ' в кавычки. Если символьная переменная
  ' содержит двойные кавычки, данная функция
  ' заключает эту переменную в одиночные
  ' кавычки.
  '
  If InSTR(1, strng, Chr(34)) Then
    q = Chr(39) & strng & Chr(39)
  Else
    q = Chr(34) & strng &Chr(34)
  End If
End Function

Эта функция экономит время и снижает возможность ошибок при написании длинных SQL-операторов. Единственный случай, когда она не работает, — наличие в одной и той же символьной переменной как одиночных, так и двойных кавычек. Однако это бывает крайне редко.

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