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

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

Совет 322. Получение даты последней коррекции файла

Совет 323. Преобразование кода цвета из DOS в Windows

Совет 324. Как отличить обычные элементы управления от компонентов массива

Совет 325. Преобразование числа в двоичное представление и наоборот

    Листинг 1. Функции sBin$ и iBin% — представление числа в двоичной записи и наоборот

Совет 326. Функции с двухсторонним обращением

Совет 327. Преобразование величины размера памяти

Совет 328. Переключение вида заголовков элемента управления ListView

Совет 329. Генерация динамических HTML-страниц

    Листинг 2. Процедура ShowRecordSetASP выводит содержимое заданного набора данных в виде таблицы

Совет 330. Как отлаживать ASP-скрипты

Совет 331. Как улучшить читаемость кода

Совет 332. Проверка на недействительные символы

Совет 333. Проверка дубликатности элементов списка

Совет 334. Как организовать выбор каталога

Совет 322. Получение даты последней коррекции файла

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

Dim MyDateTime As Date
MyDateTime = FileDateTime("D:\Calc.bas)

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

 MyDateTime = FileDateTime("D:\TMP\")       ' имя каталога задано неверно
   MyDateTime = FileDateTime("D:\TMP")      '    имя каталога задано правильно

Но получить дату создания корневого каталога (то есть диска) с использование FileDateTime нельзя.

В начало

В начало

Совет 323. Преобразование кода цвета из DOS в Windows

Как известно, в стандартном варианте DOS использовалось 16 цветов, а сейчас в Windows их 16 777 216 (16M). Точнее говоря, такая палитра определяется не операционной системой, а техническими характеристиками мониторов.

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

В любом случае, возникает задача преобразования кодов цветов из DOS в Windows, которая, казалось бы, легко решается с помощью встроенной функции QBColor:

WindowsColor = QBColor(DosColor)

Однако небольшое исследование показывает, что такой вариант представляет собой весьма приблизительное решение.

С помощью следующей конструкции:

For i = 0 To 16
      Debug.Print i; QBColor(i)
   Next

можно получить таблицу соответствия кодов DOS и Windows.

 

DOS (QuickBasic)

Windows (Visual Basic)

Код: десятичный (двоичный)

Название

(точный перевод с английского)

Код шестнадцатеричный

Название

(перевод Microsoft)

0 (0000)

Черный

000000

Черный

1 (0001)

Синий

800000

Темно-синий

2 (0010)

Зеленый

008000

Темно-зеленый

3 (0011)

Циан (Cyan)

808000

Бирюзовый

4 (0100)

Красный

000080

Малиновый

5 (0101)

Сиреневый

800080

Сиреневый

6 (0110)

Коричневый

008080

Оливковый

7 (0111)

Белый

C0C0C0

Светло-серый

8 (1000)

Серый

808080

Темно-серый

9 (1001)

Светло-синий

FF0000

Синий

10 (1010)

Светло-зеленый

00FF00

Зеленый

11 (1011)

Светлый циан

FFFF00

Голубой

12 (1100)

Светло-красный

0000FF

Красный

13 (1101)

Светло-сиреневый

FF00FF

Розовый

14 (1110)

Желтый

00FFFF

Желтый

15 (1111)

Ярко-белый

FFFFFF

Белый

Здесь хорошо видны принципы кодирования цветов в DOS и Windows. В обоих случаях цвет задается комбинацией красного, зеленого и синего (Red, Green, Blue). Но в первом варианте используется лишь один разряд (то есть две градации цвета — есть или нет данной составляющей), а во втором — целый байт (256 градаций). В DOS увеличение цветовой гаммы в два раза достигается наличием четвертого разряда, который задает нормальную или повышенную яркость (но не для каждого компонента, а для всей комбинации).

Казалось бы, на этом можно поставить точку, но из таблицы видно некоторое несоответствие в логике преобразования кода. Почти для всех цветов замена кода выполняется по такому правилу: для нормальной яркости двоичный разряд со значением 1 заменяется на &h80, для повышенной яркости — на &hFF. Но имеется также исключение из этого правила для цветов 7 и 8. Следует обратить внимание и на разные названия, например одинаковых цветов, которые используются в английском и русском вариантах Help. Оказывается, это не неточность перевода, а отражение реального несоответствия цветов в DOS и в Windows после преобразования кодов с помощью QBColor.

Визуальное сравнение изображений палитры из 16 цветов, полученных в среде QB и VB, показало заметное расхождение в красках, поэтому мы выполнили следующий эксперимент:

импортировали графический файл с палитрой QB в VB и прочитали RGB-код каждого цвета. По результатам замеров мы сделали свою функцию преобразования кодов цветов из DOS в Windows:

 Public Function QBColorMy(DosColor%) As Long
      ' Преобразование    кода из QB (16 цветов) в VB (RGB - 16М)
      ' Значения RGB-кодов получены на основе исследования
      ' 16-цветной палитры, полученной в QB/DOS
      Select Case DosColor
         Case 0: QBColorMy = &H0            '    Black
         Case 1: QBColorMy = &HAA0000       ' Blue
         Case 2: QBColorMy = &HAA00&      '    Green
         Case 3: QBColorMy = &HAAAA00       ' Cyan
         Case 4: QBColorMy = &HAA             ' Red
         Case 5: QBColorMy = &HAA00AA       ' Magenta
         Case 6: QBColorMy = &H55AA&      '    Brown (! нарушение    алгоритма)
         Case 7: QBColorMy = &HAAAAAAA   '    White
         Case 8: QBColorMy = &H555555       ' Gray
         Case 9: QBColorMy = &HFF5555       ' Light Blue
         Case 10: QBColorMy = &H55FF55   '    Light Green
         Case 11: QBColorMy = &HFFFF55   '    Light Cyan
         Case 12: QBColorMy = &H5555FF   '    Light Red
         Case 13: QBColorMy = &HFF55FF   '    Light Magenta
         Case 14: QBColorMy = &H55FFFF   '    Yellow
         Case 15: QBColorMy = &HFFFFFF   '    Bright White
      End Select
   End Function
Здесь следует обратить внимание на следующие моменты.
  1. Для нормальной яркости двоичный разряд со значением 1 меняется на &hAA, а для повышенной яркости — на &hFF. Но в последнем случае нулевой двоичный разряд меняется на шестнадцатиричное 55 (в двоичном варианте это выглядит как 01010101).
  2. Как ни странно, код 6 опять отличается от ожидаемой величины (было бы логично увидеть &hAAAA). При этом нужно отметить, что этот код действительно Brown (коричневый) — именно так он называется в QB. В документации VB он именуется как Yellow, что явно не соответствует действительности.
В начало

В начало

Совет 324. Как отличить обычные элементы управления от компонентов массива

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

 Dim ctl As Control
For Each ctl In Controls
   If TypeName(ctl) = "TextBox" Then
      MsgBox ctl.Name & " - это элемент управления   TextBox."
   End If
Next ctl

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

TypeName(Controls(ctl.Name)) 

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

 Dim ctl As Control
   For Each ctl In Controls
   ' MsgBox TypeName(ctl)
   If TypeName(ctl) = "TextBox" Then
       If TypeName(Controls(ctl.Name)) = "TextBox" Then
          MsgBox ctl.Name & " - обычный    TextBox"
       Else
          MsgBox "Элемент    массива"    & ctl.Name & _
             "/ Индекс    = " & ctl.Index
       End If
   End If
   Next ctl  
В начало

В начало

Совет 325. Преобразование числа в двоичное представление и наоборот

В VB (и QB) имеются функции для представления целого числа в символьном виде в восьмеричной (Oct) и шестнадцатеричной (Hex) системах счисления:

 Print Hex(59)    ' будет    напечатано   3B
   Print Oct(59)    ' будет напечатано   73  

Соответственно можно также использовать специальный вид констант для задания чисел в восьмеричном или шестнадцатеричном виде:

 iValue = &H3B   ' = 59 (приставка    &h)
   iValue = &O73   ' = 59 (приставка &o — второй символ    буква "O")  

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

Правило формирования константы &H таково: если в ней указано поле приставки менее пяти символов, то формируется переменная Integer, в противном случае — Long. Если необходимо сразу получить тип Long, то константа должна иметь в конце суффикс &.

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

 Const MyConst As Long = &hFFFF
   Print Hex$(MyConst)      ' будет    напечатано    FFFFFFFF  

Это объясняется тем, что &hFFFF соответствует значению — 1 (Integer). При переводе этого числа в тип Long получается код &hFFFFFFFF. Если же требуется сформировать число типа Long, в котором два старшие байта были нулевыми, то следует указать суффикс &:

 Const MyConst As Long = &hFFFF&
   Print Hex$(MyConst)      ' будет    напечатано FFFF  

Если число задано в виде символьной записи, то его можно преобразовать следующим образом:

MyStr$ = "3B"
   MyValue& = Val ("&h" & MyStr$)

Однако довольно часто бывает полезно представлять числа в двоичной системе счисления. Хотя шестнадцатеричный и восьмеричный вид чисел хорошо показывать двоичную структуру числа, все же такое преобразование требует внимания и не гарантирует от ошибок. Даже опытному программисту может понадобиться некоторое время, чтобы записать число, в котором 7-й, 8-й и 10-й разряды (считая справа! — 1011000000) были бы равны единице, а остальные — нулю.

Для решения этой задачи можно использовать функции iBin% и sBin$, приведенные на листинге 1:

 Print Hex(iBin%("1011000000")   '    будет напечатано 2C0
   Print sBin$(34)                   'будет напечатано   100010  

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

  1. Именно такой диапазон чисел чаще всего используется для представления в двоичный формат (16 разрядов — это довольно много для визуального восприятия).
  2. Для Long необходимо написать такие функции, чтобы они же по умолчанию работали и для Integer. Все это — из-за автоматического преобразования типов данных при обращении к процедурам и проблем такого преобразования, описанных выше. В этой связи приведем такой пример: строка "1000000000000000" (15 нулей справа) в терминах Integer равна –32768, а Long –32768. Таким образом, для двух типов данных необходимы разные процедуры. (В VB 7 обещано появление Overloading — возможности использования одного и того же идентификатора для обозначения разных процедур. Выбор нужной процедуры зависит от типа аргумента.)
В начало

В начало

Листинг 1. Функции sBin$ и iBin% — представление числа в двоичной записи и наоборот

Public Function sBin$(Source%)
      ' Преобразование целого числа в
      ' символьное представление в двоичной системе счисления
      Dim StrBin$, lValue&
      ' эта конструкция нужна для учета знакового разряда
      If Source < 0 Then          'знаковый разряд равен единице
         lValue = (Source And &H7FFF) Or &H8000&
      Else: lValue = Source
      End If
      Do While lValue > 0
         StrBin = Chr((lValue Mod 2) + 48) + StrBin
         lValue = lValue \ 2 ' деление нацело
      Loop
      If StrBin = "" Then sBin = "0" Else sBin    = StrBin
   End Function
   
   Public Function iBin%(Source$)
      ' Преобразование символьной строки
      ' (числа в двоичной системе счисления) в целое число
      Dim lValue&, i%
      For i = 1 To Len(Source)
         If Mid(Source, i, 1) <> "0"    Then
            lValue = lValue + 2 ^    (Len(Source) - i)
         End If
      Next
      ' эта конструкция нужна для учета знакового разряда
      If (lValue And &H8000) > 0 Then
         iBin = (lValue And &H7FFF) Or &H8000
      Else: iBin = lValue
      End If
   End Function
В начало

В начало

Совет 326. Функции с двухсторонним обращением

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

   y = MyFunc(x)
   MyFunc(y) = x

Примером такого решения является популярная функция Mid:

 Sym$ = Mid$(MyStr$, i, k)   ' выбирает    из строки фрагмент
   Mid$(MyStr$, i, k) = Sym$   ' вставляет    фрагмент строку  

Обратите внимание, что в первом случае конструкция называется функцией, а во втором — оператором (Statement). Если бы мы писали второй вариант сами, то данная процедура имела бы тип Sub, а ее запись выглядела бы так:

 Call MyMid(MyStr$, i, k, Sym$)   

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

 Public Property Get LowByte(LongVar As Long) As Byte
      ' прочитать младший    байт переменной LongVar
      LowByte = LongVar And &HFF
   End Property
   
   Public Property Let LowByte(LongVar As Long, ByVal NewByte As Byte)
      ' Записать в    младший байт переменной LongVar новое значение NewByte
      LongVar = (LongVar And &HFFFFFF00)    Or NewByte
   End Property

Обращение к ним будет выглядеть следующим образом:

 Dim LongVar$, ByteVar As Byte
      LongVar = &h12345678
      ByteVar = LowByte(LongVar)
      Print Hex(ByteVar)   ' напечатано    78
   
      ByteVar = &hF1
      LowByte(LongVar) = ByteVar
      Print Hex(LongVar)   ' напечатано    123456F1

На самом деле такие связанные функции представляют собой созданные выше iBin% и sBin$ (см. Совет 325). Их можно легко преобразовать в пару процедур Property:

 Public Property Get MyBin(Source%) As String
      ' Число Source%    в символьную запись двоичного кода
      MyBin = sBin$(Source%)
   End Property
   
   Public Property Let MyBin(Source%, ByVal NewStr As String)
      ' Символьную    запись двоичного кода NewStr$ в число Source%
      Source% = iBin%(NewStr)
   End Property

В этом случае обращение к ним будет выглядеть следующим образом:

MyBin(intBin) = "1011000"
   Print Hex(intBin)   ' напечатано 58
      
   StrBin$ = MyBin(intBin)
   MsgBox (StrBin)      ' напечатано 101100
В начало

В начало

Совет 327. Преобразование величины размера памяти

В составе Internet Explorer имеется библиотека SHLWAPI.DLL (Shell Windowing API), в которую включена функция, преобразующая число байтов в символьную строку типа "1,41 KB" или "1,32 MB". Обращение к этой функции выглядит следующим образом:

Private Declare Function StrFormatByteSize _
      Lib "shlwapi" Alias "StrFormatByteSizeA"    _
      (ByVal dw As Long, ByVal pszBuf As String, _
      ByVal cchbuf As Long) As Long
   
   Public Function FormatKB(ByVal Amount As Long) As String
      Dim Buffer As String, i%
      Buffer = Space$(255) ' резервируем буфер
      Call StrFormatByteSize(Amount, Buffer, Len(Buffer))
      i = InStr(Buffer, vbNullChar)
      If i > 1 Then FormatKB = Left$(Buffer, i - 1)
   End Function
В начало

В начало

Совет 328. Переключение вида заголовков элемента управления ListView

С помощью приведенного ниже кода можно переключать представление заголовков элемента управления ListView из плоского вида в объемное и наоборот:

Private Declare Function GetWindowLong _
      Lib "user32" Alias "GetWindowLongA" _
      (ByVal hwnd As Long, ByVal nIndex As Long) As Long
   Private Declare Function SetWindowLong _
      Lib "user32" Alias "SetWindowLongA" _
      (ByVal hwnd As Long, ByVal nIndex As Long, _
       ByVal dwNewLong As Long) As Long
   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
   
   Private Const GWL_STYLE = -16
   Private Const LVM_FIRST = &H1000
   Private Const LVM_GETHEADER = LVM_FIRST + 31
   Private Const HDS_BUTTONS = &H2
   
   Private Sub Command1_Click()
      Call ToggleHeader(ListView1.hwnd)
   End Sub
   
   Public Sub ToggleHeader(lsvhWnd As Long)
      Dim hHeader As Long, lStyle As Long
      hHeader = SendMessage(lsvhWnd, LVM_GETHEADER, 0, ByVal 0&)
      lStyle = GetWindowLong(hHeader, GWL_STYLE)
      SetWindowLong hHeader, GWL_STYLE, lStyle Xor HDS_BUTTONS
   End Sub
В начало

В начало

Совет 329. Генерация динамических HTML-страниц

Полтора года назад мы опубликовали (КомпьютерПресс 5’99) две статьи, посвященные созданию Web- и DHTML-приложений. Нам удалось создать вполне работоспособные примеры, однако технология разработки показалась нам весьма запутанной. Возможно, создавать динамические HTML-страницы проще с помощью знакомой ASP-технологии? С помощью VB это делается достаточно просто. Ниже приведены содержание ASP-страницы, которое можно сделать с помощью самого простого текстового редактора, и код процедуры, которая используется для генерации HTML-кода.

Тестовая Active Server Page:

 <html>
   <head></head>
   <body>
   <h2>Далее будет приведена некоторая информация 
пользователя </h2> 
 <%
   Dim objRSServer
   Set objRSServer = Server.CreateObject("TestASP.Htmlcrt")
   objRSServer.WriteSomeThing Response, "Привет    всем!"
   %>
   </body>
   </html>

Программный код (проект TestASP.DLL, модуль класса Htmlcrt):

Public Sub WriteSomeThing _
      (ASPResponse As ASPTypeLibrary.Response, SomeText$)
      With ASPResponse
         .Write "<font size=4 color='#cc3366'>"
         .Write SomeText$
         .Write "</font>"
      End With
   End Sub

В данном случае все выглядит достаточно понятным. Сначала мы создали ActiveX DLL с именем TestASP, в модуле класса Htmlcrt которой написали процедуру WhiteSomeThing (она превратилась, таким образом, в метод объекта TestASP.Htmlcrl). При этом для нашей DLL мы сделали ссылку на библиотеку Microsoft Active Server Page Object Library, чтобы получить доступ к объекту Response. Далее мы написали ASP-страницу с тривиальным скриптом — сначала создается объект TestASP.Htmlcrt. Затем — следует обращение к его методу WhiteSomeThing с передачей объекта Response и некоторого набора параметров. В данном случае передается текстовая строка, которая выводится в HTML-страницу.

Напомним, что обращение к ASP-странице должно выполняться через Internet Infomation Server (NT) или Personal Web Server (Windows 9x). В последнем случае ASP-файл должен быть помещен в одну из папок сервера, обращение к которому из браузера выполняется по адресу http://localhost/MyDir/Test.ASP.

Понятно, что никакого практического применения подпрограмма WhiteSomeThing не имеет, поэтому предлагаем вашему вниманию процедуру ShowRecordSetASP (листинг 2), которая выводит на HTML-страницу содержимое заданного набора данных. Теперь, сделав в ASP обращение к методу ShowRecordSetASP:

 objRSServer. ShowRecordSet(Response,   _
         "Provider=Microsoft.Jet.OLEDB.3.51;"    & _
         "Persist Security Info=False;"    & _
         "Data Source=C:\vb-db\nwind.mdb",    _
         "Select FirstName +' ' + LastName as    Имя_Фамилия,"    & _
         "Title as Должность,    " & _
         "BirthDate as ДатаРождения,    HomePhone as ДомашнийТелефон"    & _
         " from Employees Order by LastName,    FirstName", _
         "Список    сотрудников"

с помощью браузера можно будет посмотреть полезную информацию, хранимую на Web-сервере (рис. 1).

В начало

В начало

Листинг 2. Процедура ShowRecordSetASP выводит содержимое заданного набора данных в виде таблицы

Public Sub ShowRecordSetASP _
                      (ASPResponse As ASPTypeLibrary.Response, _
                      strConnectString$, strSQL$, strHeading$)
      ' Данная процедура:
      ' 1. Устанавливает соединение с источником данных ADO
      '      (нужна ссылка на MS ActiveX    Data Objects 2.x Library
      ' 2. Формирует набор данных
      ' 3. Выводит содержимое набора данных в виде таблицы
      '      в HTML-коде, который    записывается в ASP-страницу
      '      с помощью объекта Response
      ' Необходима ссылка на библиотеку MS Active Server Pages Object
      ' Должна быть записана в ActiveX DLL
      '-----------------------------------
      Dim cnn As ADODB.Connection
      Dim rs As ADODB.Recordset
      Dim fldField As ADODB.Field
      Dim iCount%, RowBGColor$
      Set cnn = New ADODB.Connection
      Set rs = New ADODB.Recordset
      cnn.Open strConnectString$
      Set rs = cnn.Execute(strSQL)
      '
      ' формирование таблицы
      With ASPResponse
         .Write "<table cellpadding=3 border=0><tr>"
         .Write "<tr><td width=100%    height=18" & _
                     "    colspan = " & rs.Fields.Count & _
                     "    bgcolor='#666699'>" & _
                         "<p align=Center><font size=4 color='#ffffff'>" &    _
                     strHeading    & "</font></tr>"
                     'вывод    заголовков колонок -- название полей
         .Write "<tr>"
         For Each fldField In rs.Fields
            .Write "<td bgcolor='#8f9fe9'>"    & fldField.Name & "</td>"
         Next
         .Write "</tr>"
         ' вывод записей в виде строк таблицы
         iCount = 1
         Do While Not rs.EOF
            .Write "<tr>"
            ' чередование цветов строк
            If iCount > 0 Then
               RowBGColor    = "'#c9c9c9'"
            Else: RowBGColor = "'#f5f5f5'"
            End If
            For Each fldField In rs.Fields
               .Write    "<td bgcolor=" & RowBGColor & ">" & _
                                  fldField.Value & "</td>"
            Next
            .Write "</tr>"
            rs.MoveNext
            iCount = iCount Xor 1
         Loop
         .Write "</table>"
      End With
      rs.Close
      cnn.Close
      Set rs = Nothing
      Set cnn = Nothing
      Close #1
   End Sub
В начало

В начало

Совет 330. Как отлаживать ASP-скрипты

Отладить процедуры для создания ASP-страниц непросто: необходимо писать код, потом создавать DLL, затем обращаться из браузера к ASP. Увидев ошибки, найти их причину, исправить в VB программу, создать DLL...

С этой проблемой мы столкнулись при разработке довольно простой процедуры ShowRecordSetASP (см. совет 329), решив ее следующим образом.

Мы сделали стандартный VB-проект, в котором создали процедуру ShowRecordSet такого вида:

 Public Sub ShowRecordSet(strConnectString$, strSQL$, strHeading$)
...
Nf=FreeFile
Open "d:\file.htm" For Output As #Nf
   Print #Nf, "<html><head></head><body>"
   ' формирование таблицы
      Print #Nf, "<table cellpadding=3 border=0><tr>"
 ...' мы опустили код, который приведен в ShowRecordSet

   Print #Nf, "</body></html>"
   Close #Nf
End Sub

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

Open "d:\file.htm" For Output As #Nf
Print #Nf, "<html><head></head><body>"
...
Print #Nf, "</body></html>"
Close #Nf

и в режиме Replace заменили «Print #1,» на «.Write», а потом давили логические скобки:

With ASPResponse
   ...
   End With

Существует еще один вариант разработки кода для ASP-страниц. Делаем такую процедуру, которая формирует автономный HTM-файл:

 Public Sub MyShowRecordSet(strConnectString$, strSQL$, strHeading$)

Nf=FreeFile
Open "с:\file.htm" For Output As #Nf
Print #Nf, "<html><head></head><body>"
 Call MyShowRecordSetMain(strConnectString$, strSQL$, strHeading$)
Print #Nf, "</body></html>"
Close #Nf

Подпрограмма MyShowRecordSetMain записывает нужный код в HTM-файл.

Для ASP пишем еще пару подпрограмм:

 Public Sub MyShowRecordSetASP _
   (ASPResponse As ASPTypeLibrary.Response, _
    strConnectString$, strSQL$, strHeading$)

   Nf=FreeFile
   FileName$ = "с:\TempFile.htm"
   ' формируем промежуточный текстовый файл
   Open FileName$ For Output As #Nf
   Call MyShowRecordSetMain(strConnectString$, strSQL$, strHeading$)
   Close #Nf
   ' переписываем его в ASP
   Call CopyFromFileToASP(FileName$, ASPResponse)
   Kill FileName$    ' удалить временный файл
End Sub
Public Sub CopyFromFileToASP(FileName$, _        ASPResponse As ASPTypeLibrary.Response)    ' переписываем содержимое текстового файла в ASP    Dim a$    nf= FreeFile    Open FileName$ For Input As #Nf    Do while not eof(Nf) ' переписываем       Line Input #Nf, a$       ASPResponse.Write a$    Loop    Сlose #Nf End Sub
В начало

В начало

Совет 331. Как улучшить читаемость кода

Качество оформления программного кода — один из важных факторов, влияющих на эффективность разработки приложений. Прежде, когда программист имел дело с бумажными распечатками кода, считалось, что одна процедура не должна превышать 60-90 строк кода (1-1,5 страницы). Такой объем текста человек может охватить одним взглядом и, таким образом, легко воспринять логику работы данного фрагмента. С внедрением персональных компьютеров необходимость в бумажных листингах отпала, наступило время интерактивной работы с кодом с помощью экрана монитора.

В текстовом режиме экрана (когда мы работали с QuickBasic) мы придерживались правила, что объем процедуры не должен превышать 40-50 строк, то есть занимать не более двух экранных страниц, которые можно легко перелистывать «туда-сюда». Теперь, при работе в графическом режиме программист может гибко управлять размером шрифта и окна с кодом. Но чаще всего приведенные выше пределы числа строк можно рекомендовать и в этом случае.

С размером текста процедур непосредственно связан вопрос навигации между отдельными компонентами VB-проекта. Следует открыто признать, что навигация в VB оставляет желать лучшего. К сожалению, сегодня многие VB-программисты даже не представляют себе, что этот процесс можно сделать более удобным. Довольно удачным примером этого может служить окно выбора нужной процедуры, которое было реализовано в VB 3.0 (рис. 2). Оно гораздо удобнее существующего сегодня Object Browser хотя бы потому, что для модуля формы показываются все реально сформированные процедуры.

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

  1. Возможность написания нескольких операторов в одной строке. Для этого используется разделитель операторов в виде двоеточия. Согласитесь, что такой код:
    A = 1: C$ = "Строковая переменная":   D = #09/30/2000#

    или:

    Select Case MyVar
       Case 0: OtherVar = 1
       Case 1: OtherVar = 45
    End Select

    который читается достаточно хорошо, но при этом занимает меньше строк.

  2. Оператор If ... Then ... Else может писать в одну строку, причем в последнем случае не нужно использовать закрывающую скобку End If. Вот несколько примеров использования этой возможности:

    Вместо

    If k = 0 Then 
       A =1
    End If

    можно написать

    If k = 0 then A = 1 

    Вместо:

    If k = 0 Then
       A = 1
       B = 2
    Else 
       A = 2
       B = 1
    End If
    

    можно написать:

    If k = 0 Then A = 1: B = 2 Else A = 2: B = 1
    

    или:

    If k = 0 Then A = 1: B = 2 _
        Else A = 2: B = 1
    
В начало

В начало

Совет 332. Проверка на недействительные символы

С этой задачей приходится сталкиваться довольно часто. Самый простой пример — ввод строки, которая должна содержать число. Ранее мы уже приводили простые процедуры собственной разработки, но сейчас хотим показать возможности библиотеки SHLWAPI.DLL, которая входит в состав Internet Explorer:

 Declare Function StrSpn Lib "SHLWAPI" Alias _
   "StrSpnW" (ByVal psz As Long, ByVal pszSet As Long) As Long

Public Function IsDecimal (ByVal sString As String) As Boolean
   Const DECIMAL_NUM As String = "0123456789"
   Dim iPos
   
   iPos = StrSpn (StrPtr(sString), StrPtr(DECIMAL_NUM)
   ' если возвращается значение, не равное длине исходной строки,
   ' то значит найдены символы, не являющиеся цифрами
   IsDecimal = (iPos = Len(sString))
End Function
В начало

В начало

Совет 333. Проверка дубликатности элементов списка

При добавлении нового элемента списка полезно проверить, не содержит ли он уже такие строки. Это можно сделать с помощью следующего кода:

Declare Function SendMessageByString _
      Lib "User32" Alias "SendMessageA _
      (ByVal hWnd As Long,   _
       ByVal wMsg As Long, _
       ByVal wParam As Long, _
       ByVal lParam As String) As Long
   
   ...
      NewListItem$ = "Новый элемент списка"
      If SendMessageByString _
            (List1.hWnd, &H1A2,    -1, NewListItem$) = - 1 then
         List1. AddItem          ' добавить новый элемент
      Else
         MsgBox NewListItem$ & "- такой    элемент уже есть в списке"
      End If   
В начало

В начало

Совет 334. Как организовать выбор каталога

Мы уже приводили пример решения этой задачи с помощью обращения к DLL-функциям (см. совет 205). Наш читатель Сергей Мичковский предложил более компактный вариант решения этой задачи:

 Sub Main()
   Dim oShell As New Shell32.Shell
   Dim oFolder As Shell32.FolderSet
   oFolder = oShell.BrowseForFolder _
    (UserControl.hWnd, "Выберите компьютер и нажмите кнопку OK", _
      &H1000, &H12)
   MsgBox oFolder.Title
End Sub

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


Наш канал на Youtube

1999 1 2 3 4 5 6 7 8 9 10 11 12
2000 1 2 3 4 5 6 7 8 9 10 11 12
2001 1 2 3 4 5 6 7 8 9 10 11 12
2002 1 2 3 4 5 6 7 8 9 10 11 12
2003 1 2 3 4 5 6 7 8 9 10 11 12
2004 1 2 3 4 5 6 7 8 9 10 11 12
2005 1 2 3 4 5 6 7 8 9 10 11 12
2006 1 2 3 4 5 6 7 8 9 10 11 12
2007 1 2 3 4 5 6 7 8 9 10 11 12
2008 1 2 3 4 5 6 7 8 9 10 11 12
2009 1 2 3 4 5 6 7 8 9 10 11 12
2010 1 2 3 4 5 6 7 8 9 10 11 12
2011 1 2 3 4 5 6 7 8 9 10 11 12
2012 1 2 3 4 5 6 7 8 9 10 11 12
2013 1 2 3 4 5 6 7 8 9 10 11 12
Популярные статьи
КомпьютерПресс использует