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

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

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

© 1996, Андрей Колесов, Ольга Павлова
Авторский вариант. Статья была опубликована c незначительной литературной правкой в журнале "КомпьютерПресс" N 7/96, с. 46-50.


Как мы и обещали в прошлый раз, все приведенные в этом выпуске советы предназначены для VB 4.0.

Совет 25. Используйте программный код для прекращения работы Windows 95 и даже для перезапуска Windows

В Windows 95 для этого существует функция ExitWindowsEx, входящая в состав Win 32 API. Данная функция позволяет перезапустить компьютер, прекратить работу, принудительно выйти из системы или осуществить выход, а затем вход другого пользователя.

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

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

Option Explicit
Private Declare Function ExitWindowsEx Lib "user32" (ByVal _
  uFlags As Long, _ ByVal dwReserved As Long ) As Long

Private Const EWX_FORCE=4 ' Принудительный выход
Private Const EWX_LOGOFF=0 ' Выход из системы
Private Const EWX_REBOOT=2 ' Перезапуск компьютера
Private Const EWX_SHUTDOWN=1 ' Прекращение работы

Sub Command1_Click ()
  Dim nRet As Long
  '- Перезапуск компьютера
  nRet=ExitWindowsEx (EWX_REBOOT, 0&)
  If nRet=False Then
    MsgBox "Невозможно выйти из Windows"
  End If
End Sub

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

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

Эта возможность VB 4.0 почти не отражена в документации. Чтобы передвинуть элемент управления, выделите его, а затем, удерживая клавишу Ctrl в нажатом состоянии, работайте с клавишами управления курсором. Аналогично, с помощью клавиши Shift можно изменить размеры элемента управления. Используя этот прием, нетрудно передвинуть или изменить размеры целой группы элементов управления. Если пометить параметр Align Controls to Grid в диалоговом окне Environment Options (это окно появляется, если в меню Tools выбрать команду Environment Options...), тогда каждое нажатие клавиши управления курсором будет приводить к увеличению позиции/размера на один шаг сетки. Если же этот параметр не помечен, элементы управления будут двигаться/менять свои размеры на один пиксел при каждом нажатии клавиши управления курсором.

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

Совет 27. Создавайте дополнительные средства (add-ins)

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

Чтобы Visual Basic знал о возможности использования созданного дополнительного средства, оно должно быть зарегистрировано в реестре, для чего в соответствующую секцию файла VB.INI нужно вставить идентификатор ProgID. ProgID состоит из имени проекта, точки и имени класса. Если проект носит имя Junk, а класс - Designer, то идентификатор ProgID будет Junk.Designer. Этот идентификатор следует добавить к секции [Add-Ins16] или [Add-Ins32] в файле VB.INI, в результате он будет выглядеть примерно так:

[Add-Ins16]
Microsoft.DesignSpec=0
Junk.Designer=0
Spacer.Connection=1

[Add-Ins32]
Junk.Designer=0
Spacer.Connection=1

С помощью значений 0 или 1 в строках INI-файла определяется, следует ли активизировать данное дополнительное средство при работе VB. В случае, если оно было создано при помощи самого VB, последний вызывает метод ConnectAddIn для данного класса и передает указатель объекту Application в этом методе. Это придает дополнительному средству статус базового, или корневого, объекта, необходимый для работы с объектами более низкого уровня.

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

Совет 28. Как определить, закончено ли выполнение 32-разрядной программы, запущенной из вашего приложения

Для этого теперь не нужно вызывать функцию API GetMOduleUsage. Более того, лучше использовать функцию CreateProcess() вместо функции Shell() для запуска программы. Функция CreateProcess() обеспечивает возможность управления запускаемой программой посредством одного из передаваемых параметров. Сразу после запуска процесса с помощью обращения к функции CreateProcess() передайте управление к функции WaitForSingleObject(). В результате ваше приложение будет приостановлено до тех пор, пока не прекратит работу запущенный им процесс.

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

Совет 29. Как работать с наборами элементов (collections)

Microsoft включила в версию 4.0 также несколько новых языковых конструкций для наборов элементов. С помощью нового оператора With ... End With можно укоротить ссылку к полному имени объекта для каждого свойства и метода. Следующий код использует полное имя объекта для каждого имени и свойства:

tipNew.ID="T: & Format$(iID+1)
tipNew.Text="Новое свойство может оказаться забавным!"
m_colTips.Add tipNew, tipNew.ID

Вы можете укоротить ссылки на объект и ускорить их выполнение с помощью оператора With:

With tipNew
  .ID="T: & Format$(iID+1)
  .Description="Новое свойство может оказаться забавным!"
  m_colTips.Add tipNew, .ID
End With

Другая новая языковая конструкция - это оператор For Each ... Next. Он аналогичен оператору For ... Next, но отличается тем, что особым образом выбирает каждый элемент, входящий в набор:

Private m_colTips as New Collection
Private m_Tip as CTip

For Each m_Tip in m_colTips
   m_Tip.Reserve
Next

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

Совет 30. Оптимизируйте процедуры установки значений свойств

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

Создание метода PropertyGet позволило бы приложению-клиенту осуществлять поиск текущих значений всех свойств конкретного OLE-сервера. Этот метод содержит список необязательных параметров, в который заносятся все значения свойств, выбранные OLE-сервером для того, чтобы сделать их доступными приложению-клиенту. Поскольку каждый запрос к удаленному OLE- серверу должен пройти по сети, данный метод увеличивает производительность, так как исключаются индивидуальные запросы значений каждого свойства, которые тормозят передачу данных в сети.

Для более полного решения проблемы следует также создать метод PropertySet, который позволил бы приложению-клиенту обновлять значения всех свойств OLE-сервера. Эти процедуры используют функцию IsMissing, чтобы определить, какой из параметров, переданных приложением-клиентом, получает или возвращает текущее значение свойства связанного объекта.

В качестве примера рассмотрим OrderMgr - объект OLE Automation, который может использоваться как часть приложения обработки очереди. Он обращается к объекту Order, который в свою очередь подвергает воздействию пять свойств OrderID, OrderDate, CustomerID, ShippedFlag и RemovedFlag. Объект Order будет работать с этими пятью отдельными свойствами, а также с методами PropertySet и PropertyGet, которые позволяют клиенту более эффективно работать со значениями свойств. Используя их, можно обновлять или осуществлять поиск всех пяти свойств объекта Order с помощью только одного вызова процедуры. Без этой процедуры потребовалось бы пять отдельных вызовов, чтобы получить всю необходимую информацию. Следующий листинг показывает, как в этом примере будут выполняться методы PropertySet и PropertyGet:

Public Sub PropertyGet(Optional OrderID As Variant, _
  Optional OrderDate As Variant, _
  Optional CustomerID As Variant, _
  Optional ShippedFlag As Variant, _
  Optional RemovedFlag As Variant)

  If IsMissing(OrderID) = False Then
     OrderID = prvOrderID
  End If
  If IsMissing(OrderDate) = False Then
     OrderDate = prvOrderDate
  End If
  If IsMissing(CustomerID) = False Then
     CustomerID = prvCustomerID
  End If
  If IsMissing(ShippedFlag) = False Then
     ShippedFlag = prvShippedFlag
  End If
  If IsMissing(RemovedFlag) = False Then
     RemovedFlag = prvRemovedFlag
  End If
End Sub

Public Sub PropertySet(Optional OrderDate As Variant, _
  Optional CustomerID As Variant, _
  Optional RemovedFlag As Variant)

  If IsMissing(OrderDate) = False Then
    prvOrderDate = OrderDate
  End If
  If IsMissing(CustomerID) = False Then
    prvCustomerID = CustomerID
  End If
  If IsMissing(RemovedFlag) = False Then
    prvRemovedFlag = RemovedFlag
  End If
End Sub

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

Совет 31. Следите за тем, что вы передаете в OLE-сервера

Не используйте в библиотеке объектов Visual Basic сами объекты в качестве параметров или возвращаемых значений для подвергаемых воздействию свойств или методов в классах типа Public. Эти объекты предназначены для применения только внутри единичного проекта. Иное их использование может привести к непредсказуемым результатам.

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

Совет 32. Снабжайте документами свои OLE-серверы

Снабдите документами интерфейс к своему OLE-серверу, используя кнопку Options в Object Browser. Чтобы документация была более полной, используйте для этого специальный файл справки. С помощью Object Browser подсоедините этот файл к OLE-серверу.

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

Совет 33. Что делать с ошибками OLE-сервера

Не выводите на экран сообщение об ошибках из самого OLE-сервера. Вместо этого передайте его в клиентское приложение. Для нумерации ошибок используйте значения больше чем vbObjectError + 512, и меньше чем vbObjectError + 5535. Значения, которые находятся в диапазоне от vbObjectError до vbObjectError + 512, могут вступить в противоречие со значениями ошибок OLE. Обязательно внесите номера ошибок в файл справки, который вы используете для своего OLE- сервера.

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

Совет 34. Как обрабатывать объекты OLE-сервера

Не возвращайте ссылки на объекты Form и Control из своего OLE-сервера. Лучше используйте упаковщики (wrappers) для свойств и методов, принадлежащих формам и элементам управления, которые должны обрабатываться вашим OLE-сервером. Например, вместо того чтобы возвращаться в текстовое окно, которое должно обрабатываться клиентским приложением, используйте методы упаковки в OLE-сервере для метода Move и свойства упаковки для Text.

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

Совет 35. Будьте осторожны, когда завершаете работу OLE-серверов

Не используйте никаких внешних методов для завершения работы вашего сервера. Пусть сервер сам автоматически прекратит работу, когда к нему не останется ссылок. Если вы используете позицию меню Exit в OLE-сервере, который выводит на экран пользовательский интерфейс, просто выгрузите формы, открытые пользователем, и освободите все созданные экземпляры объекта.

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

Совет 36. Установите все переменные объекта равными Nothing (Пусто)

Установите все переменные объекта равными Nothing (Пусто), прежде чем заканчивать приложение. При выполнении оператора End в клиентском приложении OLE OLE-сервер выключается, и события Terminate, относящиеся к тем объектам, которые еще не прекратили работу, не выполняются.

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

Совет 37. Используйте самый конкретный тип объектов из всех имеющихся

Вместо того чтобы объявлять тип объекта как Object (As Object), используйте конкретный тип объекта, такой, например, как Ctask. Это повышает производительность за счет минимизации требований к перекодировке в OLE.

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

Совет 38. Используйте подстановку объектов

Используйте подстановку объекта, чтобы заменить простое имя на расширенную ссылку на объект. Каждый знак ".", используемый в коде, представляет собой перекодировку OLE. Большая производительность достигается при минимизации числа выполнения перекодировки. Например:

For i = 1 to 10
   txt(i) = myApp.TimeSheet.Employee.Name
Next i

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

Dim emp As New Employee
' Создание переменной для подстановки объекта
Set emp = myApp.TimeSheet.Employee
For i =1 to 10
   txt(i) = emp.Name
Next i

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