Programming: Visual Basic


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



  Авторы: Алексей Малинин, Ольга Павлова


Совет 1. Настройка интерфейса VB/VBA

Совет 2. Добавьте команды управления комментариями к среде разработки

Совет 3. Как прочитать адреса отправленных писем

Совет 4. Использование пробелов в именах таблиц баз данных ADO

Совет 5. Как передать Null в API-функцию

Совет 6. Как вставить колонки в VB MSFlexGrid

Совет 7. Динамическое увеличение динамического массива

Совет 8. Как работать с адресной книгой MS Exchange

Совет 9. Как отключить ADO Recordset, созданный с помощью объекта Command

Совет 10. Как использовать символ @ в именах параметров SQL Server

Совет 11. Генерация строк соединения для OLE DB

Совет 12. Как создавать ISAM-файлы

Совет 13. Защита от макросов при использовании глобальных шаблонов

Совет 14. Управление подключением макросов в приложениях Office

Совет 15. Использование цифровой подписи в Office 2000/XP

   Замечание для Office 2000

Совет 16. Идентификация элементов управления

Совет 17. Предотвращение многократного запуска VB-программы на одном компьютере

Совет 18. Удостоверьтесь, что используете нужный провайдер при создании структурированных наборов данных ADO

Совет 19. Программная реализация копирования экрана

Совет 20. Как открыть ниспадающее меню программным образом

Совет 21. Формирование кода цвета для HTML

Совет 22. Модернизация объекта Err



Совет 1. Настройка интерфейса VB/VBA

Далеко не все VB/VBA-разработчики знают о возможности выполнять настройку интерфейса среды разработки с помощью окна Customize, которое открывается командой View|Toolbars|Customize (рис. 1).

Рис. 1

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

Советуем также открыть вкладку Customize|Commands (рис. 2). В списке Categories вы обнаружите перечень категорий команд, которые представлены в среде в виде меню. Но если внимательно посмотреть на состав команд отдельных категорий (список Commands), то можно заметить, что на самом деле их гораздо больше, чем видны в меню по умолчанию.

Рис. 2

К сожалению, справка окна Customize работает не самым лучшим образом, поэтому разобраться в смысле незнакомых команд непросто. Пользователи офисных приложений находятся в лучшем положении: в справке имеется раздел VB Use Interface Help с описаниями всех встроенных команд. Они также могут воспользоваться кнопкой Description для вывода подсказки (в VB эта кнопка почему-то не работает).



Совет 2. Добавьте команды управления комментариями к среде разработки

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

Командой View|Toolbars|Customize откройте окно Customize|Commands. Далее в списке Categories выделите строку Edit. Потом в списке Commands найдите команды Comment Block и Uncomment Block, а затем перетащите их мышью на панель управления Standard. Теперь, если вы выделите некоторый фрагмент кода, то одним щелчком мыши по соответствующей команде сможете устанавливать или убирать апострофы в первой позиции выделенных строк.

Кстати, среди таких малоизвестных команд имеются также Indent и Outdent, которые позволяют сдвигать фрагменты текста на один отступ вправо или влево.



Совет 3. Как прочитать адреса отправленных писем

Допустим, вам нужно получить список адресов, по которым вы отправили письма. Если они лежат в папке отправленных писем Outlook, то это можно сделать с помощью такого кода:

Dim myItems As Items  
 Dim mailmsg As MailItem  
 ' выборка писем из папки  
 Set myItems = _  
   Application.Session.GetDefaultFolder(olFolderOutbox).Items  
   
   If myItems.Count > 0 Then ' есть письма  
     For Each mailmsg In myItems  
       MsgBox "Куда отправлено - " & mailmsg.To  
     Next  
   Else  
     MsgBox "нет отправленных писем"  
   End If  

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

Set myItems = Application.GetNamespace("MAPI"). _  
    Folders.Item("Personal Folders").Folders.Item("Outbox").Items  


Совет 4. Использование пробелов в именах таблиц баз данных ADO

Наверняка вам известно, что в именах таблиц и полей баз данных ADO нельзя использовать ни пробелы, ни идентификаторы типа «Большая деревня». Но на самом деле подобные имена вполне допустимы, просто для их обозначения нужно применять квадратные скобки. Соответственно метод Open будет выглядеть примерно следующим образом:

rst.Open "[Большая деревня]", conn,,,adCmdTable  
   
А SQL-запрос может выглядеть так:  
   
rst.Open "SELECT [Малыш Дик] FROM [Большая деревня]"  


Совет 5. Как передать Null в API-функцию

Довольно часто бывает необходимо передать в API-функцию значение Null (0&) в качестве одного из аргументов. Но сделать это порой не так-то просто, поскольку вы можете столкнуться с ограничением объявления функции: VB выдаст в этом случае сообщение об ошибке. Например, рассмотрим такое объявление функции, которое получено копированием соответствующего кода из файла Win32api.txt с помощью API Viewer:

Public Declare Function ScrollWindowEx Lib _  
  "user32" (ByVal hwnd As Long, ByVal dx As Long, _  
  ByVal dy As Long, lprcScroll As RECT, _  
  lprcClip As RECT, ByVal hrgnUpdate As Long, _  
  lprcUpdate As RECT, ByVal fuScroll As Long) As Long  

Здесь видно, что эта функция использует несколько структур RECT, в которых задается область прокрутки Windows. Но если передать вместо адресов блоков данных нуль, то Windows самостоятельно будет определять эти области. С этих позиций следующее обращение к функции является вполне допустимым:

ScrollWindowEx m_hWnd, 0, 5, ByVal 0&, ByVal 0&, 0&, ByVal 0&, _  
  SW_SCROLLCHILDREN Or SW_INVALIDATE  

Однако в данном случае VB выдаст сообщение о том, что такое обращение (передача аргумента по значению) противоречит сделанному выше объявлению (передача по ссылке).

Чтобы решить указанную проблему, можно использовать два варианта. В первом нужно заменить в объявлении типы данных  RECT на Any:

Public Declare Function ScrollWindowEx Lib _  
  "user32" (ByVal hwnd As Long, ByVal dx As Long, _  
  ByVal dy As Long, lprcScroll As Any, _  
  lprcClip As Any, ByVal hrgnUpdate As Long, _  
  lprcUpdate As Any, ByVal fuScroll As Long) As Long  

С таким объявлением будет допустима передача как адреса структуры, так и числовой величины.

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

Public Declare Function ScrollWindowExLong Lib _  
  "user32" Alias ScrollWindowEx  
  (ByVal hwnd As Long, ByVal dx As Long, _  
  ByVal dy As Long, ByVal lprcScroll As Long, _  
  ByVal lprcClip As Long, ByVal hrgnUpdate As Long, _  
  ByVal lprcUpdate As Long, ByVal fuScroll As Long) As Long  

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

ScrollWindowExLong _  
  m_hWnd, 0, 5, ByVal 0&, ByVal 0&, 0&, ByVal 0&, _  
  SW_SCROLLCHILDREN Or SW_INVALIDATE  


Совет 6. Как вставить колонки в VB MSFlexGrid

Елемент управления MSFlexGrid предоставляет отличные возможности для визуализации данных в виде таблицы. Однако иногда необходимо, чтобы сам пользователь мог вставлять колонки в определенных точках таблицы, в то время как VB по умолчанию добавляет новые колонки в конец таблицы. Эта проблема легко решается с помощью обновленного свойства ColPosition, для чего достаточно написать такой код:

Private Sub Command1_Click()  
  With MSFlexGrid1  
    ' добавить новую колонку  
    .Cols = .Cols + 1  
    ' переместить в нужную позицию  
    .ColPosition(.Cols - 1) = .Col  
  End With  
  Call SetHeaders  ' переписать заголовки  
End Sub  
   
Private Sub SetHeaders()  
  ' формирование заголовков  
  Dim i As Integer  
  With MSFlexGrid1  
    For i = 0 To .Cols - 1  
      .Col = i  
      .Row = 0  
      .Text = "Колонка " & i  
    Next i  
  End With  
End Function  


Совет 7. Динамическое увеличение динамического массива

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

Dim upper As Long ...   
   
upper = UBound(myArray)   ' текущее значение верхней границы   
ReDim myArray(upper + 1)  'увеличение  

Но если к моменту обращения к функции Ubound массив не был еще инициализирован (то есть был определен в виде Dim myArray()), то приведенный выше код вызовет ошибку. Чтобы избежать этого, используйте такой код:

Dim myArray() As String  
   
Private Sub cmdAdd_Click()  
  Dim upper As Long  
   
  On Error Resume Next  ' включаем обработку ошибок  
  upper = UBound(myArray)  
  If Err.Number Then  
    upper = 0  
    ReDim myArray(0)  
  Else  
    upper = upper + 1  
    ReDim Preserve myArray(upper)  
  End If  
  On Error GoTo 0   ' отключаем обработку ошибок  
   myArray(upper) = CStr(txtName) ' ввод нового значения  
End Sub  


Совет 8. Как работать с адресной книгой MS Exchange

Наш читатель Виктор Крюков поделился своим опытом работы с адресной книгой MS Exchange. В организации, где он работает, почтой управляет MS Exchange 2000, поэтому результат обращения к свойству ContactItem.Email1Address выглядит примерно так:

"/o=UFG/ou=UFG/cn=Recipients/cn=VKryukov".  

Как же получить реальный адрес? Виктор предлагает такой рецепт. Объект, который хранит информацию о пользователе, — это AddressEntry, находящийся в коллекции AddressEntries, которая, в свою очередь, находится в объекте AddressList коллекции AddressLists данной сессии. У этого объекта есть семейство Fields, которое и хранит нужные свойства. Видимо, для доступа эти свойства проиндексированы какими-нибудь именованными константами типа PR_ADDRESS_EMAIL и т.п., но мы их не нашли.

Вот возможные варианты решения этой задачи:

  1. делать цикл по всем полям и искать значение, содержащее '@' в качестве подстроки;
  2. найти значение, которое является массивом, — оно всего одно, представляет собой массив строк и содержит строчки примерно такого вида (этот вариант кажется более надежным):
 SMTP:_servrice@ufg.com  
 MS:UFG/UFG/Service  
 CCMAIL: Service at UFG  
 X400:c=RU;a= ;p=UFG;o=UFG;s=?service;  

то есть это адреса в разных форматах. Из данного массива выбирается строчка, начинающаяся с 'SMTP', и обрезается начало, которое и является правильным ответом.

Вот код для примера (мы добавляем в коллекцию Result все имена и адреса), для выполнения которого требуется в References подключить Microsoft CDO 1.21 Library.

Private Sub Form_Load()  
  Dim oSession As MAPI.Session  
  Dim oAList As MAPI.AddressList  
  Dim oAEntry As MAPI.AddressEntry  
  Dim oValue As Variant  
  Dim i As Integer, v As Variant, j As Integer  
  Dim Result As New Collection  
   
  ' Logon to the MAPI session  
  Set oSession = New MAPI.Session  
  oSession.Logon  
   
  ' Get the Global Address List  
  Set oFolder = oSession.AddressLists("Global Address List")  
  For Each oEntry In oFolder.AddressEntries  
    For i = 1 To oEntry.Fields.Count  
      v = oEntry.Fields(i).Value  
      If IsArray(v) Then  
        For j = LBound(v) To UBound(v)  
         If Mid(v(j), 1, 5) = "SMTP:" Then  
           Result.Add Mid(v(j), 6) & " : " & oEntry.Name  
           GoTo continue  
         End If  
        Next j  
      End If  
    Next i  
continue:  
  Next oEntry  
   
  For i = 1 To Result.Count  
    MsgBox Result(i)  
  Next i  
End Sub   


Совет 9. Как отключить ADO Recordset, созданный с помощью объекта Command

Когда вы создаете распределенное приложение, крайне важно, чтобы ваш код занимал как можно меньше ресурсов сервера. В этом случае узким местом является поддержка соединения с сервером баз данных. Конечно, выполнить отключение набора данных из стандартного объекта Recordset очень просто. А вот сделать это с набором данных, который был сгенерирован с помощью объекта Command, не так легко, хотя и возможно.

В этих целях создайте объект Command и установите его свойства, как вы это обычно делаете, но вместо обращения к свойству Execute используйте метод Open объекта Recordset с аргументом Source. Тогда вы отключите соединение обычным образом и удалите объект Command. Все это можно проиллюстрировать с помощью такого кода:

 Dim cmd As ADODB.Command  
 Dim rst As ADODB.Recordset  
 Dim param As ADODB.Parameter  
   
Set cmd = CreateObject("ADODB.Command")  
  With cmd  
    .CommandText = "sp_myStoredProc"  
    .CommandType = adCmdStoredProc  
    .ActiveConnection = STR_CONN  'Какая-то строка соединения  
    Set param = .CreateParameter("Param1", _  
                adVarChar, adParamInput, 2, "foo")  
    .Parameters.Append param  
  End With  
  Set rst = CreateObject("ADODB.Recordset")  
  With rst  
    .CursorLocation = adUseClient  
    .Open cmd, CursorType:=adOpenStatic, _  
            Options:=adCmdStoredProc  
    Set .ActiveConnection = Nothing  
  End With  
  Set DataGrid1.DataSource = rst  
  Set cmd = Nothing  
End Sub  


Совет 10. Как использовать символ @ в именах параметров SQL Server

Как известно, ADO предлагает два варианта поддержки хранимых процедур со значениями параметров: в первом случае нужно сослаться на имя параметра напрямую и просто присвоить значение, а во втором следует построить объект Parameter и добавить его к коллекции Parameters объекта Command. Однако нужно иметь в виду, что, когда вы используете именованные параметры, следует применять символ @ перед именем каждого параметра SQL, например вот так:

cmd.Parameters("@someParam") = 250  

Если же вы создаете объект Parameter, этот символ не используется:

Set param = cmd.CreateParameter _  
  ("someParam", adBigInt, adParamInput, 2, 250)  
cmd.Parameters.Append param  


Совет 11. Генерация строк соединения для OLE DB



Создать строку соединения OLE DB без использования элемента управления DataEnvironment в VB-проекте не так-то просто: нужно в контекстном меню объекта Connection1 выделить команду Properies, а затем установить значение в диалоговом окне Data Link Properties, которое потом переписать в свойство ConnectionSource. Однако существует довольно легкое решение этой проблемы.

Создайте текстовый файл с расширением VBS (VBScript) с таким кодом:

Dim oDataLinks, sRetVal  
 Set oDataLinks = CreateObject("DataLinks")  
 On Error Resume Next  'отслеживание кнопки Cancel  
 sRetVal = oDataLinks.PromptNew  
 On Error Goto 0  ' отключение обработки ошибок  
 If Not IsEmpty (sRetVal) Then  ' не была нажата Cancel  
   InputBox "Строка соединения OLE DB = ", sRetVal  
 End If  
 Set oDataLinks = Nothing  

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

Если же вы работаете с VB, то можно добавить ссылку на Microsoft OLE DB Service Component 1.0 Type Library (OLEDB32.DLL) и использовать Object Browser для обращения к объекту DataLinks.



Совет 12. Как создавать ISAM-файлы

помощью библиотеки ADOX 2.1 (Microsoft ADO Extensions for DLL and Security) можно легко создать новый ISAM-файл в самых различных форматах (Excel, dBase, Paradox, HTML и Lotus) без обращения к соответствующим объектным моделям и даже при отсутствии приложений, для которых эти форматы являются родными.

Приведем пример того, как можно создать XLS-файл с двумя рабочими листами:

Public Sub Main()  
  Dim cn As Connection  
  Dim cat As Catalog  
  Dim tbl As Table  
  Dim fld As Column  
   
  Set cn = New Connection  
  With cn  ' установка соединения  
    .ConnectionString = _  
      "Provider=Microsoft.Jet.OLEDB.4.0;" & _  
      "Extended Properties=Excel 8.0;" & _  
      "Data Source=" & App.Path & "\newfile.xls"  
   
    .Open  
  End With  
   
   
  Set cat = New Catalog  
  With cat  ' формирование таблиц  
    .ActiveConnection = cn  
   
    ' первая таблица (рабочий лист)  
    Set tbl = New Table  
    tbl.Name = "NewSheet1"  
   
    Set fld = New Column  
    fld.Name = "MyCol1"  
    fld.Type = adWChar  
    fld.DefinedSize = 30  
    tbl.Columns.Append fld  
    ' вторая колонка  
    tbl.Columns.Append "Column2", adInteger  
   
    .Tables.Append tbl  ' добавляем первую таблицу  
   
    ' вторая таблица (рабочий лист)  
    Set tbl = New Table  
    tbl.Name = "NewSheet2"  
   
    ' вторая колонка  
    tbl.Columns.Append "МояКолонка1", adWChar, 20  
   
    .Tables.Append tbl  ' добавляем вторую таблицу  
   
    cat.Tables.Refresh  ' запись  
  End With  
  ' очистка  
  Set fld = Nothing  
  Set tbl = Nothing  
  Set cat = Nothing  
  cn.Close  
  Set cn = Nothing  
End Sub   

Запустите эту процедуры, а потом с помощью Excel убедитесь, что вы получили рабочую книгу с двумя листами, в которых заданы соответственно две и одна колонки. Вы можете создавать файлы и других типов, просто установив в Extended Properties нужное значение: dBase IV, Paradox 4.x и пр.


Совет 13. Защита от макросов при использовании глобальных шаблонов

нам поступил вопрос: «Почему при работе в Word 2000 при использовании глобальных шаблонов, а также при загрузке шаблонов в виде автономных документов или присоединенного файла из каталога «Шаблоны пользователя» не производится проверка на наличие макрокода, хотя такой режим контроля у меня установлен?»

Отвечаем на это следующим образом. Управление режимом контроля за наличием макрокода при загрузке документов производится в диалогом окне Security[Безопасность] (команда меню Tools|Macro|Securiry [Сервис/Макрос/Безопасность]). На его вкладке Trusted Sources [Надежные источники] имеется флажок Trust all installed Add-ins and templates [Доверять всем установленным надстройкам и шаблонам]. Под установленными здесь подразумеваются дополнения и шаблоны, помещенные в каталог «Шаблоны пользователя» (конкретное имя этого каталога указывается в поле User Templates [Шаблоны пользователя] во вкладке File Locations [Расположение] диалогового окна Tools|Options [Сервис|Параметры]).

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

В Word 97 специального режима для загрузки шаблонов не было. Но в начальной версии программы иногда имела место ошибка, когда шаблоны загружались без проверки на макрокод. Этот дефект уже давно устранен — заплатку, которая решает данную проблему, можно скачать по адресу .



Совет 14. Управление подключением макросов в приложениях Office

В одной из Web-дискуссий был задан такой вопрос: «При загрузке Outlook у меня постоянно выдается окно предупреждения о наличии макросов в загружаемом проекте. Как мне добиться того, чтобы загрузка выполнялась автоматически без требования подтверждения в диалоговом окне?»

В целом решение этого вопроса одинаково для всех приложений Office. Но в отношении Outlook (версии 2000 и 2002) стоит напомнить, что эта программа использует для хранения макросов только один фиксированный файл с именем VbaProject.OTM, который хранится в каталоге C:\Windows\Application Data\Microsoft\Outlook\. Сам программный проект может иметь еще и собственное произвольное имя (оно видно только в среде VBA).

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

Рассмотрим возможности управления безопасностью. Режим защиты устанавливается в диалоговом окне «Безопасность» (Security), которое открывается командой «Сервис|Макро|Безопасность», где видно описание трех возможных уровней безопасности.

рис. 3


  1. Высокий. Разрешается запуск только подписанных макросов из надежных источников. Неподписанные макросы удаляются автоматически. При наличии макросов с неизвестными подписями выдается окно предупреждения, однако такие макросы можно подключить, только признав подлинность подписи.
  2. Средний. Подписанные макросы загружаются автоматически. О наличии неподписанных макросов выдается предупреждение, и решение об их загрузке принимается пользователем.
  3. Низкий. Защита отсутствует, все макросы загружаются автоматически.

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

  1. Установите низкий уровень безопасности — и никаких предупреждений вообще не будет. Но мы не рекомендуем этот вариант, так как проверка на наличие макросов при загрузке неизвестных файлов (например, полученных из Интернета или по электронной почте) необходима. Но для Outlook такой вариант является вполне подходящим — ведь мы имеем дело только с фиксированным файлом локального компьютера, который создается исключительно его хозяином.
  2. Лучший способ (наиболее универсальный) — использовать цифровую подпись проекта (в том числе и для Outlook). Этот способ немного подробнее мы рассмотрим в совете 16.

Для тех, кто работает с Word и Excel, есть еще один вариант, который позволяет отменить проверку наличия макросов в глобальных шаблонах и Add-ins. Для подобных приложений во вкладке Trusted Sources [Надежные источники] окна Security [Безопасность] имеется флажок Trust all installed Add-ins and templates [Доверять всем установленным надстройкам и шаблонам].

Под «установленными» подразумеваются дополнения и шаблоны, помещенные в каталог «Шаблоны пользователя». (Конкретное имя этого каталога указывается в поле User Templates [Шаблоны пользователя] во вкладке File Locations [Расположение] диалогового окна Tools|Options [Сервис|Параметры].)

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

В Word 97 такого специального режима для загрузки шаблонов не было. Но в начальной версии программы иногда имела место ошибка, когда шаблоны загружались без проверки на макрокод. Этот дефект уже давно устранен — заплатку, которая решает данную проблему, можно скачать по адресу .



Совет 15. Использование цифровой подписи в Office 2000/XP

Здесь есть три элемента: создание и удаление сертификата, подключение цифровой подписи к документу, признание подписи в качестве «надежной». Рассмотрим их последовательно.

  1. Создание и удаление сертификата. Каждый пользователь может создать  один или несколько сертификатов. Это делается тремя способами: создать собственный сертификат, получить сертификат у администратора сети (если на предприятии разработаны собственные стандарты) и получить фирменный сертификат в специализированном центре (например, у той же компании Microsoft).

    Собственный сертификат создается утилитой SelfCert.exe, которая входит в состав пакета

    рис. 4

    В первом варианте русской версии MS Office 2000 в этой программе была ошибка (не раскрывалось диалоговое окно), но уже в первом сервисном наборе обновления дефект был исправлен.

  2. Удаление же сертификата выполняется довольно хитрым способом, с помощью (кто бы мог ожидать?) Internet Explorer. Для этого в IE нужно выбрать команду «Сервис|Свойства обозревателя», затем выделить вкладку «Содержание», нажать кнопку «Сертификатов...», открыть вкладку «Личные» в окне «Диспетчер Сертификатов» и уже там проводить операции с сертификатами

    рис. 5

  3. Подключение цифровой подписи. Электронная подпись подключается к VBA-проекту в среде VBA с помощью команды Tools|Digital Signature, которая выводит соответствующее окно «Цифровая подпись»

    рис. 6

    Для выбора нужного сертификата нужно нажать кнопку «Выбрать», после чего выдается окно Select Certificate со списком имеющихся сертификатов

    рис. 7

    Нажав кнопку, можно ознакомиться с более детальной информацией о сертификате в окне Certificate с тремя вкладками

    рис. 8

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

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

    В этом случае выдается окно предупреждения

    рис. 9

    В этот момент можно посмотреть более детальную информацию о данном сертификате (кнопка Details). Если вы считаете данный источник надежным, то нужно установить флажок Always trust macros from this source [Всегда доверять макросам этого источника] — и данный сертификат автоматически попадет в список надежных. Эти можно увидеть во вкладке Trusted Source окна Security

    рис. 10
    Здесь же можно удалить ненужные подписи.

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



Замечание для Office 2000

Следует обратить внимание еще на один важный момент, который имел место в приложениях Office 2000.

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

Причина такого поведения — наличие внутренних синтаксических ошибок в коде проекта. Поэтому при обнаружении подобного сообщения о невозможности сохранения документа с электронной подписью, прежде чем отменять подпись, рекомендуем вам проверить работоспособность вашего кода. Довольно часто ошибка связана с отсутствием описания переменной или ссылки на внешний объект. Чтобы лучше понять суть ситуации, сделайте следующий простой пример в Word: создайте новый документ, перейдите в среду VBA и там создайте макрокоманду Test1:

Sub Test1 ()  
    Avar = 1  
End If  

Разумеется, сначала должен быть задан режим Option Explicit (обязательное объявление переменных).

Теперь установите электронную подпись и попробуйте сохранить документ. Скорее всего, у вас появится сообщение о нехватке места на диске для записи файла. Запустите макрокоманду Test1 на выполнение — транслятор выдаст сообщение о синтаксической ошибке (не определена переменная Avar). Добавьте в процедуру описание:

Dim Avar As Integer  

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

Судя по всему, такое поведение Word 2000 является ошибкой (об этом говорит хотя бы выдача неверной диагностики). В Word 2002 эта ситуация исправлена — сохранение проекта с подписью выполняется независимо от ошибок кода.



Совет 16. Идентификация элементов управления

Порой бывает необходимо узнать внутри программного кода тип элемента управления, с которым выполняется в данный момент работа. Например, вы хотите изменить текст на всех командных кнопках формы или изменить какие-то свойства элементов управления определенного типа. Для подобной идентификации лучше всего подходит оператор TypeOf, который может использоваться в операторе If...Then:

If TypeOf ctl Is CommandButton Then
  ' Выполнить что-то  
End If  
Для идентификации типа произвольного элемента управления
можно использовать, например, такую процедуру:  
Private Sub Command1_Click()
  Dim ctl As Control
  Dim str As String
  For Each ctl In Me.Controls
    If TypeOf ctl Is CommandButton Then _
      str = "CommandButton"
    If TypeOf ctl Is TextBox Then str = "TextBox"
    If TypeOf ctl Is OptionButton Then str = _
      "OptionButton"
    If TypeOf ctl Is DriveListBox Then str = _
      "DriveListBox"
    If TypeOf ctl Is DataCombo Then str = _
      "DataCombo"
    MsgBox "Элемент управления типа " & str
  Next ctl
End Sub


Совет 17. Предотвращение многократного запуска VB-программы на одном компьютере

Возможно, вам необходимо предотвратить возможность повторного запуска вашего приложения (если оно уже запущено). Для этого можно воспользоваться свойством PrevInstance объекта App, например таким образом:

Private Sub Main()
  If App.PrevInstance Then   
    ' приложение уже запущено
    Exit Sub ' завершить процедуру (а значит и приложение)
  End If  
  ' продолжение работы программы
End Sub  


Совет 18. Удостоверьтесь, что используете нужный провайдер при создании структурированных наборов данных ADO

Как вы, возможно, знаете, технология ADO позволяет включать иерархические структуры данных в один объект Recordset. Однако при создании такого объекта нужно правильно указать опции провайдера. Например, типичный вариант формирования стандартного набора данных может использовать такую строку соединения:

"Provider=Microsoft.Jet.OLEDB.4.0;Data Source=C:\MyData\SomeDB.mdb"

Но для создания структурированного объекта Recordset вам нужно в качестве провайдера использовать SDataShape. К тому же вы должны указать, какой механизм OLEDB будет обеспечивать поддержку данных:

"Provider=MSDataShape;Data Provider=Microsoft.Jet.OLEDB.4.0;
Data Source=C:\MyData\SomeDB.mdb"

или в случае SQL Server users:

"Provider=MSDataShape;Data Provider=SQLOLEDB;
Data Source=MyServerName;Initial    Catalog=SomeSQLDB"

Кроме того, можно указать подобную строку в свойстве Provider объекта ADO Connection.



Совет 19. Программная реализация копирования экрана

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

Private Declare Function BitBlt Lib "gdi32" _  
   (ByVal hDestDC As Long, ByVal x As Long, _  
    ByVal y As Long, ByVal nWidth As Long, _  
    ByVal nHeight As Long, ByVal hSrcDC As Long, _  
    ByVal xSrc As Long, ByVal ySrc As Long, _  
    ByVal dwRop As Long) As Long  
Private Declare Function GetDesktopWindow _  
    Lib "user32" () As Long  
Private Declare Function GetDC _  
    Lib "user32" (ByVal hwnd As Long) As Long  
Private Declare Function ReleaseDC Lib "user32" _  
    (ByVal hwnd As Long, ByVal hdc As Long) As Long  
Private Const SRCCOPY = &HCC0020  
'-------------------------------------------------------------------------- 
Private Sub Command1_Click()  
 Dim hwndScreen As Long  
 Dim hScreenDC As Long  
 Dim Res As Long  
 hwndScreen = GetDesktopWindow()  
 hScreenDC = GetDC(hwndScreen)  
 Res = BitBlt(hdc, 0, 0, ScaleWidth, ScaleHeight, hScreenDC, 0, 0, SRCCOPY)  
 Res = ReleaseDC(hwndScreen, hScreenDC)  
 Form1.WindowState = vbMaximized 'распахиваем окно на полный экран  
End Sub  

Но только для формы нужно установить свойство AutoRedraw=True.



Совет 20. Как открыть ниспадающее меню программным образом

Как известно, VB 6 включает возможность задания Style=5 (tbrDropDown) для объекта Button элемента управления Toolbar. В этом случае можно добавить кнопке несколько объектов ButtonMenu. Но открыть меню можно только с помощью щелчка стрелки. То есть нельзя выполнить такую операцию из программного кода. Эта задача может быть решена с помощью следующего кода:

Private Type POINTAPI  
  x As Long  
  y As Long  
End Type  
Private Declare Function GetCursorPos Lib "user32" _  
  (lpPoint as POINTAPI) As Long  
Private Declare Function ClientToScreen Lib "user32" _  
  (ByVal hWnd As Long, _  
   lpPoint as POINTAPI) As Long  
Private Declare Function SetCursorPos Lib "user32" _  
  (ByVal x As Long, ByVal y As Long) As Long  
Private Declare Function ShowCursor Lib "user32" _  
  (ByVal bShow As Long) As Long  
Private Declare Sub mouse_event Lib "user32" _  
  (ByVal dwFlags As Long, ByVal dx As Long, _  
   ByVal dy As Long, ByVal cButtons As Long, _  
   ByVal dwExtraInfo As Long)  
Private Sub ShowPopUpMenu _  
  (TB As Toolbar, IndexOfButton%)  
  ' раскрываем меню  
  CONST MOUSEEVENTF_LEFTDOWN = &H2  
  Const MOUSEEVENTF_LEFTDOWN = &H2  
  Const MOUSEEVENTF_LEFTUP = &H4  
  Dim Pt As POINTAPI, oldPt As POINTAPI  
  With TB.Buttons(IndexOfButton)  
    If Not (.Style = tbrDropdown Then Exit Sub  
    ' режим разрешен  
    Call GetCursorPos(oldPt) ' запоминаем позицию курсора  
    Call ClientToScreen(TB.hWnd, Pt)  
    Call ShowCursor(False)  
    ' устанавливаем курсор на стрелку  
    Call SetCursorPos(Pt.x + ((.Left + .Width) / _  
       Screen.TwipsPerPixelX) - 1, _  
       Pt.y + ((.Top + .Height)\ 2 /_  
       Screen.TwipsPerPixelY))  
  End With  
  ' имитируем щелчок мышью  
  Call mouse_event(MOUSEEVENTF_LEFTDOWN, _  
     0, 0, 0, 0)        
  Call mouse_event(MOUSEEVENTF_LEFTUP, _  
     0, 0, 0, 0)        
  ' восстанавливаем позицию курсора мыши  
  Call SetCursor(oldPt.x, oldPt.y)  
  Call ShowCursor (True)  
End Sub  

Используя эту подпрограмму, можно, например, открыть меню, когда пользователь щелкнет саму кнопку:

Sub ToolBar1_ButtonClick _  
   (ByVal Button As MSComctllib.Button)  
  Call ShowPopUpMenu (Toolbar1.Button.Index)  
End Sub  


Совет 21. Формирование кода цвета для HTML

Эта функция преобразует числовое значение цвета в строковую переменную для использования в HTML:

Public Function HtmlHexColor _  
  (ByVal ColorValue As Long) As String  
  Dim r As Byte  
  Dim g As Byte  
  Dim b As Byte  
  ' преобразование цвета (если это нужно)  
  Call OleTranslateColor _  
    (ColorValue, 0&, ColorValue)  
  r = ColorValue Mod &H10  
  g = (ColorValue \ &h100) Mod &H100   
  b = (ColorValue \ &h10000) Mod &H100  
  HtmlHexColor = "#" & _  
    Right$("0" & Hex$(r),2) & _  
    Right$("0" & Hex$(g),2) & _  
    Right$("0" & Hex$(b),2)  
 End Function  


Совет 22. Модернизация объекта Err

Как это ни странно, но вы можете расширить функциональность встроенного объекта Err. Создайте класс с именем Cerror и включите в него такую процедуру свойства:

Public Property Get Number() As Long  
  Number = VBA.Err.Number  
End Property  
Далее создайте BAS-модуль со следующим кодом:  
Public Function Err() As Cerror  
  Static oErr As Cerror
   
  If oErr Is Nothing Then  
    Set oErr = New Cerror  
  End If  
  Set Err = oErr  
End Function  

Теперь вы можете обращаться к созданному объекту Cеrror для которого можно создать любой набор свойств и методов.







При перепечатке любого материала с сайта, видимая ссылка на источник www.warayg.narod.ru и все имена, ссылки авторов обязательны.

© 2005
 

Hosted by uCoz