Вариации на тему Digital Dashboard. Часть 2

Виталий Сизов

Web-страница Digital Dashboard

Прямая и обратная связь с VBA

Взаимодействие с Word, Excel и Access

Взаимодействие с Outlook

Вызов приложений

 

В настоящей статье продолжается начатый в предыдущем номере журнала разговор о Digital Dashboard — одной из наиболее интересных технологий Microsoft.

Web-страница Digital Dashboard

Настало время перейти к проектированию самой Web-страницы Digital Dashboard (DD). Конечно, она может быть выполнена совершенно произвольно, в соответствии со вкусами и предпочтениями дизайнера. Однако с учетом того, что эта страница не предназначена для широкого круга пользователей в Internet, можно ограничиться требованиями функциональности и простоты модификации. Что касается функциональности, требования к ней уже определены. Классическая DD состоит из совокупности динамических окон, которые раскрываются, не перекрывая друг друга. В каждом из этих окон отображается информация из какого-либо источника. Чтобы совместить как можно больше информации на одной странице, окна располагаются в нескольких столбцах, в зависимости от разрешения монитора дисплея (обычно их два).

Чтобы минимизировать затраты по модификации DD при изменении совокупности источников информации, нужно отделить описание структуры страницы от конкретного содержания окон. Для этого поступим следующим образом. Спроектируем DD в виде таблицы размером 16 строк по 2 столбца в каждой. Это позволит иметь до 32 различных окон с Web Parts. Такое количество окон в свернутом виде займет практически весь экран среднего монитора. Сверху или снизу таблицы можно поместить классический объект, специально разработанный для DD. Это элемент управления Microsoft Investor Ticker, представляющий полезную информацию в виде бегущих строк. HTML-код такой страницы выглядит следующим образом:

<html>
 
<head>
<meta http-equiv=”Content-Type” content=”text/html;
charset=windows-1251">
<link rel=”StyleSheet” href=”dd.css” type=”text/css”>
<title>Digital Dashboard</title>
</head>
 
<body onload=”init()”>
 
<table width=”100%” border=”0">
<tr>
<td>
<object type=”application/x-oleobject”
classid=”clsid:62360003-D8A7-418b-
9DC6-2B9DE95273A0"
width=”100%” height=”34">
<param name=”NumLines” value=”2">
<param name=”ServerRoot”
value=”http://moneycentral.msn.com”>
<param name=”Keywords”
value=”ticker.txt”>
<param name=”SpecialsServerURL”
value=”specials.txt”>
<param name=”BigTarget” value=”_top”>
<param name=”NewsTarget” value=”_new”>
<param name=”StockTarget” value=”_top”>
<param name=”ShowBrand” value=”1">
<param name=”BackgroundColor”
value=”0x00FFFFFF”>
<param name=”DefaultCategories”
value=”News,Commerce,Investor Headlines”>
</object>
</td>
</tr>
</table>
 
<table width=”100%” border=”0">
<tr>
<td width=”50%” valign=”top”>
<table cellpadding=”0"
border=”0" cellspacing=”0"
class=”nuggetHeader” id=”nHeader1">
<tr>
<td nowrap width=”100%” class=”nuggetTitle”
valign=”center” id=”nTitle1"></td>
<td nowrap class=”nuggetButtonWrapper”>
<img id=”nToggle1" src=”images/blank.gif”
title=”Click to maximize / minimize”
onClick=”document.all.nContent1.style.display=
document.all.nContent1.style.display==
‘none’?’’:’none’;
if(document.images)this.src=
document.all.nContent1.style.display==
‘none’?imgMax.src:imgMin.src;”
WIDTH=”17" HEIGHT=”17"></td>
</tr>
</table>
<div valign=”top” id=”nContent1">
<table width=”100%” border=”0" cellpadding=”5"
cellspacing=”0" class=”nuggetBodyOdd”>
<tr>
<td id=”nBody1"></td>
</tr>
</table>
</div>
 
. . .
 
<table cellpadding=”0"
border=”0" cellspacing=”0"
class=”nuggetHeader” id=”nHeader32">
<tr>
<td nowrap width=”100%” class=”nuggetTitle”
valign=”center” id=”nTitle32"></td>
<td nowrap class=”nuggetButtonWrapper”>
<img id=”nToggle32" src=”images/blank.gif”
title=”Click to maximize / minimize”
onClick=”document.all.nContent32.style.display=
document.all.nContent32.style.display==
‘none’?’’:’none’;
if(document.images)this.src=
document.all.nContent32.style.display==
‘none’?imgMax.src:imgMin.src;”
WIDTH=”17" HEIGHT=”17"></td>
</tr>
</table>
<div valign=”top” id=”nContent32">
<table width=”100%” border=”0" cellpadding=”5"
cellspacing=”0" class=”nuggetBodyEven”>
<tr>
<td id=”nBody32"></td>
</tr>
</table>
</div></td>
</tr>
</table>
</body>
</html>

Если присмотреться к приведенному выше коду, можно заметить, что все 32 окна (они называются Nuggets) совершенно одинаковы и состоят из двух частей: заголовка и тела. Заголовок nugget — это таблица, состоящая из одной строки и двух ячеек. Первая ячейка — nTitleNN (где NN — порядковый номер от 1 до 32) предназначена для хранения имени Web Part. Вторая ячейка содержит графическое изображение кнопки maximize/minimize с именем nToggleNN. События, связанные с этой кнопкой, полностью определены и выполняют два действия: меняют SRC кнопки и отображают или скрывают тело nugget с именем nContentNN.

Само тело заключено в Generic Block Level-контейнер <DIV></DIV> с именем nContentNN, внутри которого расположена таблица с единственной пустой, но именованной ячейкой nBodyNN. Как видите, все элементы Web-страницы, за исключением кнопок, лишены содержания, которое может отражаться на экране. Зато все эти пустые элементы имеют уникальные имена.

Остается вспомнить, что данная страница предназначена для отображения исключительно в обозревателе Internet Explorer, и написать JavaScript-функцию init(), присваивающую значения свойствам innerHTML всех именованных объектов семейства document.all.

Поскольку содержание nuggets желательно совсем отделить от страницы, предусмотрим создание коллекции объектов и ее динамическую загрузку:

var MAX_NUGGETS = 32
 
function MakeArray(n)
{
for (var i = 1; i <= n; i++) {
this[i] = 0
}
this.maxlen = n
this.len = 0
return this
}
 
var nuggets = MakeArray(MAX_NUGGETS)
 
function NuggetItem(title, home, body)
{
this.title = title
this.home = home
this.body = body
}
 
function NuggetAdd(title, home, body)
{
nuggets.len++
if (nuggets.len <= nuggets.maxlen) {
nuggets[nuggets.len] =
new NuggetItem(title, home, body)
} else {
alert(“Better increase MAX_NUGGETS: “ +
nuggets.len + “ > “ + nuggets.maxlen)
}
}

С помощью приведенных выше функций JavaScript создается коллекция объектов nuggets со свойствами .len и .maxlen и методом NuggetAdd, позволяющим добавлять элементы в коллекцию. Каждый элемент имеет три свойства: title (заголовок), home (адрес домашней страницы) и body (произвольный HTML-код для тела).

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

NuggetAdd(“Заголовок”, “Домашняя страница”,
“Коды тела”)
Непосредственная загрузка коллекции осуществляется с помощью кода:
 
<script TYPE=”text/javascript” LANGUAGE=”JavaScript”
src=”nlist.js”></script>
Здесь nlist.js — имя текстового файла с командами NuggetAdd.
После того как все необходимое для отображения окон готово, можно написать и    саму функцию init(), завершающую формирование DD:
 
n = (document.layers) ? 1 : 0
ie = (document.all) ? 1 : 0
 
function init()
{
if (ie) {
for (i = 1; i <= nuggets.len; i++) {
if (nuggets[i].home == “”) {
strTitle = “<span class=\”nuggetTitleText\”>” +
nuggets[i].title + “</span>”
} else {
strTitle = “<a href=\”” + nuggets[i].home + “\”
class=\”nuggetTitleText\”
title=\”Nugget Title\”>” +
nuggets[i].title + “</a>”
}
document.all[“nTitle” + i].innerHTML =
strTitle
if (nuggets[i].body != “”) {
document.all[“nBody” + i].innerHTML =
nuggets[i].body
}
document.all[“nContent” + i].style.display =
“none”
if (document.images) {
document.images[“nToggle” + i].src =
imgMax.src
}
}
for (i = nuggets.len + 1 ;
i <= nuggets.maxlen; i++) {
document.all[“nContent” + i].style.display =
“none”
document.all[“nHeader” + i].style.display =
“none”
}
}
if (n) {
document.close()
document.writeln(“<h1>This page is the Digital
Dashboard</h1>”)
document.writeln(“<h2>Special software is
required</h2>”)
document.writeln(“<h3><a HREF=
\”javascript:history.go(-1)\”>Click Here</a>
to go back to the page you were on.</h3>”)
document.close()
}
}

В этой функции нет ничего сложного. Выполняется цикл от 1 до nuggets.len (количество загруженных элементов). Если свойство home (адрес домашней страницы) пусто, то в заголовок c именем nTitleNN записывается простой текст. В противном случае формируется гиперссылка — элемент <A>. Тело, а это может быть произвольный HTML-код, просто копируется из элемента коллекции в свойство .innerHTML соответствующего окна.

Если в коллекции меньше элементов, чем 32, все оставшиеся пустыми окна скрываются вместе с заголовками.

И наконец, если обнаруживается Netscape Navigator, вместо DD формируется страница с предупреждающим сообщением.

На рис. 1 показана такая страница со всеми загруженными окнами.

Существует еще одно очень важное обстоятельство, обусловленное применением обозревателя единственного типа. Internet Explorer поддерживает элементы <IFRAME>. А это означает, что тело любого из 36 окон может быть представлено отдельной полноценной HTML-страницей. В этом случае в файле загрузки nlist.js в поле кода тела можно использовать следующую конструкцию:

“<IFRAME SRC=\”yourpage.html\” TITLE=\”Page Title\”
frameborder=\”0\” width=\”100%\” height=\”220\”
scrolling=no></IFRAME>”

Здесь yourpage.html — адрес отдельной страницы того или иного источника информации, включенного в DD.

Использование <IFRAME>, кроме простоты включения, дает еще одно замечательное преимущество. Окно, содержащее <IFRAME>, может перезагружаться (refresh) независимо от основной страницы. Это существенно повышает динамические характеристики системы в целом, позволяя организовать асинхронные режимы обновления информации.

В начало В начало

Прямая и обратная связь с VBA

Все решения, описанные выше, носят пока еще вспомогательный характер. Вызов Internet Explorer в том или ином виде из приложений Office — не такое уж большое достижение. Действия на уровне приложений не обеспечивают обмен информацией между Web-страницами и объектами Microsoft Office. Реальная польза от DD появится только тогда, когда удастся установить связь между произвольными документами и их содержимым.

Определенные предпосылки для этого созданы. Если вернуться к библиотеке SHDocVw и внимательно проанализировать доступные свойства объектов WebBrowser и InternetExplorer, то можно обнаружить свойство .Document, содержащее ссылку на некий объект. Интуиция подсказывает, что это именно то, что нужно.

Для работы с объектами класса Document потребуется еще одна библиотека — Microsoft HTML Object Library (MSHTML), обычно находящаяся по адресу C:\WINDOWS\ SYSTEM\MSHTML.tlb. Данная библиотека содержит объектную модель HTML-документов, открытых в Internet Explorer. Именно с этой объектной моделью взаимодействуют функции JavaScript, JScript и VBScript, используемые в Web-страницах. В проекте VBA необходимо подключить ссылку на эту библиотеку с помощью команды «Сервис|Ссылки…».

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

 Dim objHTML As HTMLDocument

Затем с помощью инструкции Set объектной переменной присваивается ссылка на существующий объект:

 Set objHTML = WebBrowser1.Document

или:

Set objHTML = gobjIE.IE.Document

Здесь первая команда относится к варианту с внедренным WebBrowser, а вторая — к варианту с классом InternetExplorerWithEvents.

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

objHTML.BGColor = “red”

Для того чтобы динамически помещать на страницу какую-либо содержательную информацию, полезными окажутся свойства innerHTML, outerHTML, innerText или outerText.

Применение объектной модели HTML в VBA позволяет программисту использовать интеллектуальную поддержку редактора VBE. Программирование для гипертекстового документа становится таким же простым и приятным, как и при работе в специализированной инструментальной системе Visual InterDev.

Таким образом, связь со стороны Microsoft Office в направлении DD практически идеальна, чего нельзя сказать о связи в обратном направлении. Web-страница DD — это активный документ, предназначенный для организации интерактивной работы с пользователем. Источником событий является Web-страница, тогда как VBA-проект должен обеспечивать только ответную реакцию на эти события. Для обработки событий в VBA можно было бы создать классы — упаковки WithEvents, как это уже было сделано для объекта InternetExplorer. Однако в объектной модели HTML классов с событиями великое множество, и проектировать для каждого из них контейнер нерационально.

Для того чтобы обеспечить связь DD в направлении VBA, воспользуемся переменной типа Variant — хорошо известным URL, универсальным локатором ресурса. В самом деле, по отношению к Web-странице проект VBA является таким же ресурсом, как ASP, процедуры Perl в каталогах /cgi-bin/, да и просто функции JavaScript, вызываемые с помощью параметра href. Для обращения к процедурам и функциям VBA можно было бы использовать синтаксис, похожий на вызов функций JavaScript, например:

 vba:command([param1[,param2[,…]]])

где command — имя функции VBA-проекта, paramN — параметры, а vba — префикс, указывающий, что осуществляется обращение к ресурсу родительского приложения Office.

Получить URL из Web-страницы не составляет труда. Для этого достаточно предусмотреть обработку события BeforeNavigate2. Для внедренного WebBrowser — это следующая процедура:

Private Sub WebBrowser1_BeforeNavigate2( _
ByVal pDisp As Object, _
URL As Variant, _
Flags As Variant, _
TargetFrameName As Variant, _
PostData As Variant, _
Headers As Variant, _
Cancel As Boolean)
 
. . .
 
End Sub

Для класса InternetExplorerWithEvents эта же процедура выглядит так:

Private Sub IE_BeforeNavigate2( _
ByVal pDisp As Object, _
URL As Variant, _
Flags As Variant, _
TargetFrameName As Variant, _
PostData As Variant, _
Headers As Variant, _
Cancel As Boolean)
 
. . .
 
End Sub

Событие BeforeNavigate2 возникает всякий раз перед тем, как обозреватель получает задание обратиться к внешнему ресурсу или выполнить функцию JavaScript, записанную в параметре href. Это происходит в том случае, если пользователь щелкнет мышью по элементу <A>, нажмет на кнопку Submit в форме либо в результате программной установки значения свойства document.location.

Задача процедуры обработки события BeforeNavigate2 заключается в том, чтобы проанализировать значение URL. Если обнаружится префикс vba, то следует не только выполнить команду, но и предотвратить дальнейший вызов метода Navigate. Для этого достаточно присвоить параметру Cancel значение True.

Перед тем как заняться обработкой события, следует уяснить некоторые правила формирования URL самим обозревателем. Прежде всего URL представляет собой полный адрес ресурса, который начинается с указания протокола. Стандартные протоколы имеют следующие имена: javascript, about, http, file, ftp, mailto, news и gopher. После имени протокола обязательно следует двоеточие. Изобретенный нами префикс vba с двоеточием — не что иное, как название нового нестандартного протокола. Если бы двоеточия не было, обозреватель попытался бы спереди дополнить строку указанием протокола по умолчанию (http) и текущим адресом host. А это нам совсем не требуется. Кроме того, нужно иметь в виду, что в URL не может быть пробелов и символов управления: возврата каретки и перевода строки. Все пробелы автоматически преобразуются в комбинацию символов %20 (20 — это шестнадцатеричный код пробела). Поэтому, если необходимо передать в VBA параметры с такими символами, следует использовать символы-заменители. Например, чтобы указать Chr(10), можно написать %10, а для Chr(13) — использовать %13. Конечно, это некорректно, поскольку мы используем знак шестнадцатеричного числа для десятичного кода, но варианты %0A и %0С потребовали бы дополнительно применять функции UCase() или LCase().

Теперь можно сочинить и тело процедуры-перехватчика:

Dim strVBA As String ‘ URL как строка
Dim strMsg As String ‘ сообщение об ошибке
 
‘— проверка тэга URL
If UCase(Left(URL, 4)) = “VBA:” Then
Cancel = True
strVBA = URL
 
‘— вызов процедуры VBA
On Error Resume Next
DoIt ParseCmd(strVBA)
 
‘— сообщение об ошибке
If Err <> 0 Then
‘— коррекция символов
strMsg = ReplaceString(Error$, “\”, “\\”)
strMsg = ReplaceString(strMsg, vbCr, “\r”)
strMsg = ReplaceString(strMsg, vbLf, “\n”)
 
‘— фокус на Internet Explorer
IE.Visible = True
IE.Document.Location = _
“javascript:alert(“”” & strMsg & “””)”
End If
End If

Непосредственно обработку команды, полученной из DD, выполняет процедура DoIt, которую не следует помещать в модуль класса или модуль листа с внедренным WebBrowser. Очевидно, что по мере развития проекта будут появляться все новые команды. А вот функцию разбора строки ParseCmd() необходимо тщательно продумать и поместить в модуле класса:

Private Function ParseCmd(strIn As String) As Variant
‘— Анализ командной строки
Dim strCmd As String ‘ команда целиком
Dim strParmSet As String ‘ строка параметров
Dim strParmItem As String ‘ один параметр
Dim varParmArray() As Variant
‘ массив параметров
Dim intL As Integer ‘ позиция левой скобки
Dim intR As Integer ‘ позиция правой скобки
Dim intComa As Integer ‘ позиция запятой
Dim intCount As Integer ‘ счетчик параметров
 
‘— восстановление управляющих символов
strIn = ReplaceString(strIn, “%20”, “ “)
strIn = ReplaceString(strIn, “%10”, vbLf)
strIn = ReplaceString(strIn, “%13”, vbCr)
 
‘— поиск скобок
intL = InStr(1, strIn, “(“)
intR = InStr(1, strIn, “)”)
 
‘— коррекция скобок
If intL = 0 Or intR = 0 Or intL >= intR Then
intL = Len(strIn) + 1
intR = Len(strIn) + 2
strCmd = strIn & “()”
Else
strCmd = strIn
End If
 
‘— первый элемент — код операции
ReDim varParmArray(1)
varParmArray(0) = UCase(Trim(Mid(strCmd, 5,
intL - 5)))
strParmSet = Mid(strCmd, intL + 1, intR - intL
- 1)
 
‘— выделение параметров в скобках
strParmItem = “”
intCount = 0
Do While Len(strParmSet) > 0
 
‘— выделение текста до запятой
intComa = InStr(1, strParmSet, “,”)
If intComa > 0 Then
strParmItem = Left(strParmSet, intComa - 1)
strParmSet = Mid(strParmSet, intComa + 1)
Else
strParmItem = strParmSet
strParmSet = “”
End If
 
‘— добавление параметра в массив
ReDim Preserve
varParmArray(UBound(varParmArray) + 1)
intCount = intCount + 1
varParmArray(intCount) = Trim(strParmItem)
strParmItem = “”
Loop
 
‘— возвращается массив
ParseCmd = varParmArray
End Function

Функция ParseCmd преобразует полученный URL в массив типа Variant. Первый элемент массива — код команды. Даже если для какой-либо команды не требуется параметров, массив всегда будет иметь ненулевую размерность. Это исключает возникновение ошибок в случае выполнения функции UBound при дальнейшей обработке в процедуре DoIt.

Возвращаясь к тексту обработчика событий, следует обратить внимание на то, что происходит при возникновении ошибок. При использовании варианта с внедренным WebBrowser сообщение об ошибке можно выводить с помощью обычного MsgBox. В варианте с классом InternetExplorerWithEvents (а именно его обработчик событий показан выше) этого делать не следует. Обращение к VBA происходит из отдельного окна Internet Explorer; следовательно, и сообщение об ошибке, возникшей при таком обращении, необходимо выводить в этом же окне. Для этого используется функция alert(), хорошо знакомая программистам на JavaScript. Правда, текст сообщения, сформированный VBA, приходится слегка подправить. Все управляющие символы необходимо заменить соглашениями, принятыми в системе UNIX (возврат каретки заменить «\r» и т.д.).

Что касается самой процедуры DoIt, то это простой переключатель, основанный на операторе Select Case:

Public Sub DoIt(varArray As Variant)
‘— Диспетчер команд VBA, вызываемых из DD
Dim i As Integer ‘ индекс массива
Dim strCmd As String ‘ имя функции
Dim strMsg As String ‘ сообщение об ошибке
 
On Error Resume Next
strCmd = varArray(0)
Select Case strCmd
 
‘— вызов обработчика известной команды
Case “Имя допустимой команды”
 
. . .
 
‘— незнакомая команда
Case Else
strMsg = “Unknown Command: “ & strCmd & “(“
For i = 1 To UBound(varArray) - 1
If i > 1 Then
strMsg = strMsg & “, “
End If
strMsg = strMsg & varArray(i)
Next i
strMsg = strMsg & “)”
 
‘— сообщение об ошибке в Internet Explorer
gobjIE.IE.Document.Location = _
“javascript:alert(“”” & strMsg & “””)”
End Select
End Sub

Здесь, как и в обработчике событий, формируется сообщение об ошибке, которое выводится в окне Internet Explorer с помощью функции alert(). Только в приведенном примере ошибка не связана с объектом Err. Просто из DD была получена незнакомая команда, для которой не предусмотрено определенное значение в операторе Case. Такая команда отвергается.

Все, что остается делать в дальнейшем, так это придумывать все новые и новые команды, разрабатывать процедуры для их обработки и добавлять в процедуру DoIt соответствующие операторы Case «Имя команды».

В начало В начало

Взаимодействие с Word, Excel и Access

Первое, что приходит в голову, — научить DD создавать новые и открывать существующие документы Microsoft Office в классических приложениях. Например, для взаимодействия с Word полезными будут команды OpenWordDoc и NewWordDoc. В процедуре DoIt создадим пару переключателей:

‘— OpenWordDoc(Path[,ReadOnly])
Case “OPENWORDDOC”
strParam = varArray(1)
If UBound(varArray) >= 3 Then
blnFlag = True
Else
blnFlag = False
End If
 
WordProc strParam, False, blnFlag
 
‘— NewWordDoc([PathTemplate])
Case “NEWWORDDOC”
If UBound(varArray) >= 2 Then
strParam = varArray(1)
Else
strParam = “”
End If
 
WordProc strParam, True, False

Здесь предполагается, что непосредственно открытие документов будет осуществляться в процедуре WordProc, требующей трех параметров. Первый из них — путь (Path) к документу или шаблону. Второй параметр показывает, что нужно сделать: создать новый или открыть существующий документ. Третий параметр, флаг «только чтение», введен для разграничения прав доступа к тем или иным документам, часть из которых может быть расположена на сервере и открываться с помощью протокола FTP.

Прежде чем разрабатывать процедуру WordProc, необходимо твердо уяснить следующее. В варианте с классом InternetExplorerWithEvents вызов DD может осуществляться из любого приложения. Чтобы не пришлось изготавливать несколько вариантов процедур, при программировании нужно забыть, в каком из приложений производится первоначальная разработка и отладка. К проекту, где бы он ни находился, следует подключить ссылки на все офисные библиотеки, содержащие объектные модели всех приложений. А при обращении к объектам необходимо явно указывать имя приложения. Так, даже если мы программируем в проекте Word, процедура WordProc должна выглядеть следующим образом:

Private Sub WordProc(strPath As String, _
blnNew As Boolean, _
blnReadOnly As Boolean)
‘— Процедуры Word
Dim objWord As Word.Application
Dim objWordDoc As Word.Document
 
‘— проверка, выполняется ли Microsoft Word
On Error Resume Next
‘ отложенный перехват ошибок.
‘— функция GetObject, вызванная без указания
‘— первого аргумента,
‘— возвращает ссылку на экземпляр приложения.
‘— Если это приложение
‘— не запущено, возвращается ошибка.
Set objWord = GetObject(, “Word.Application”)
 
If (Err.Number <> 0) Then
Err.Clear
‘ Очищаем объект Err на случай ошибки.
Set objWord = New Word.Application
End If
 
With objWord
.Visible = True
.WindowState = wdWindowStateMaximize
If blnNew Then
‘— новый документ
If strPath <> “” Then
‘— шаблон
Set objWordDoc = .Documents.Add(strPath)
Else
Set objWordDoc = .Documents.Add
End If
Else
‘— существующий документ
Set objWordDoc = .Documents.Open(strPath, , _
blnReadOnly)
End If
objWordDoc.Application.Activate
End With
End Sub

Для открытия документов Excel команды DD будут практически аналогичными:

‘— OpenWorkBook(Path[,ReadOnly])
Case “OPENWORKBOOK”
strParam = varArray(1)
If UBound(varArray) >= 3 Then
blnFlag = True
Else
blnFlag = False
End If
 
ExcelProc strParam, False, blnFlag
 
‘— NewWorkBook([PathTemplate])
Case “NEWWORKBOOK”
If UBound(varArray) >= 2 Then
strParam = varArray(1)
Else
strParam = “”
End If
 
ExcelProc strParam, True, False

Кроме того, сама процедура ExcelProc, выполняющая создание новых и открытие существующих рабочих книг Excel, тоже мало отличается от WordProc:

Private Sub ExcelProc(strPath As String, _
blnNew As Boolean, _
blnReadOnly As Boolean)
‘— Процедуры Excel
Dim objExcel As Excel.Application
Dim objExcelBook As Excel.Workbook
 
‘— проверка, выполняется ли Microsoft Excel.
On Error Resume Next
‘ отложенный перехват ошибок.
‘— функция GetObject, вызванная без указания
‘— первого аргумента,
‘— возвращает ссылку на экземпляр приложения.
‘— Если это приложение
‘— не запущено, возвращается ошибка.
Set objExcel = GetObject(, “Excel.Application”)
 
If (Err.Number <> 0) Then
Err.Clear
‘ Очищаем объект Err на случай ошибки.
Set objExcel = New Excel.Application
End If
 
With objExcel
.Visible = True
.WindowState = xlMaximized
If blnNew Then
‘— новая книга
If strPath <> “” Then
‘— шаблон
Set objExcelBook = .Workbooks.Add(strPath)
Else
Set objExcelBook = .Workbooks.Add
End If
Else
‘— существующая книга
Set objExcelBook = .Workbooks.Open(strPath, , _
blnReadOnly)
End If
End With
End Sub

Здесь есть только одно почти незаметное отличие от WordProc. Объект Excel.Application не имеет метода Activate. Для передачи фокуса на открываемую книгу используется установка свойства .Visible = True. Любопытно, что устанавливать значение этого свойства необходимо перед тем, как открыть рабочую книгу. В противном случае при закрытии единственного документа может наблюдаться аварийное завершение Excel, если, конечно, сам вызов производится, например, из Word.

Что касается Microsoft Access, то вряд ли целесообразно придумывать команду DD для создания новой базы данных. Проектирование базы данных — процесс долгий и кропотливый, а для руководителей предприятий — совсем уж неуместный. Да и открытие базы данных как офисного документа — возможность достаточно сомнительная. Другое дело — предусмотреть в DD работу с готовыми формами базы данных. Синтаксис команды и оператор Case в этом случае может быть такой:

‘— OpenAccessDb(Path,Form)
Case “OPENACCESSDB”
If UBound(varArray) >= 3 Then
AccessProc varArray(1), varArray(2)
End If
Процедура взаимодействия с Access в этом случае может быть следующей:
Private Sub AccessProc(varPath As Variant, _
varForm As Variant)
‘— Процедуры Access
Dim objAccess As Access.Application
Dim objDatabase As Database
Dim objForm As form
Dim strPath As String
Dim strForm As String
 
strPath = varPath
strForm = varForm
‘— проверка, выполняется ли Microsoft Access
On Error Resume Next
‘ отложенный перехват ошибок.
‘— функция GetObject, вызванная без указания
‘— первого аргумента,
‘— возвращает ссылку на экземпляр приложения.
‘— Если это приложение
‘— не запущено, возвращается ошибка.
Set objAccess = GetObject(, “Access.Application”)
 
If (Err.Number <> 0) Then
Err.Clear
‘ Очищаем объект Err на случай ошибки.
Set objAccess = New Access.Application
End If
 
With objAccess
.Visible = True
.OpenCurrentDatabase strPath
Set objDatabase = .CurrentDb
.DoCmd.OpenForm strForm
Set objForm = .forms(strForm)
objForm.SetFocus
End With
End Sub

Приведенная процедура примечательна тем, что, как только работа с базой данных заканчивается, приложение Microsoft Access закрывается автоматически, освобождая изрядный пул оперативной памяти. Для этой процедуры, кроме библиотеки объектов Access, необходима открытая ссылка на Microsoft DAO Object Library.

В начало В начало

Взаимодействие с Outlook

В стандартных DD, открытых в Microsoft Outlook, специальных средств для обращения к папкам Outlook не требуется. Другое дело, если DD вызывается из классических приложений Office. Выше уже отмечалось, что при использовании почтового агента, отличного от Outlook, необходимость в части папок-приложений отпадает. Поэтому открывать Outlook как единое целое нецелесообразно. Гораздо интереснее вызывать отдельное приложение в форме специализированного обозревателя — объекта Explorer, настроенного на работу с конкретным типом документов: контактами, задачами или календарем.

Синтаксис команды вызова отдельных приложений Outlook и соответствующий оператор Case может быть таким:

‘— Outlook(Folder)
Case “OUTLOOK”
strParam = varArray(1)
SelectOutlookExplorer strParam

Для открытия конкретного приложения Outlook потребуется отдельная процедура, построенная в виде переключателя:

Private Sub SelectOutlookExplorer(strFolder)
‘— Выбор папки Outlook
Dim lngFolder As Long
Dim lngMode As Long
 
Select Case UCase(strFolder)
Case “CALENDAR”
lngFolder = olFolderCalendar
Case “CONTACTS”
lngFolder = olFolderContacts
Case “DELETEDITEMS”
lngFolder = olFolderDeletedItems
Case “INBOX”
lngFolder = olFolderInbox
Case “JOURNAL”
lngFolder = olFolderJournal
Case “NOTES”
lngFolder = olFolderNotes
Case “OUTBOX”
lngFolder = olFolderOutbox
Case “SENTMAIL”
lngFolder = olFolderSentMail
Case “TASKS”
lngFolder = olFolderTasks
Case Else
Exit Sub
End Select
 
lngMode = olFolderDisplayNoNavigation
 
OutlookExplorer lngFolder, lngMode
End Sub

На рис. 2 показано, как может выглядеть окно для открытия любых папок Outlook в DD.

Ниже приведен фрагмент кода HTML-страницы, открытой в этом окне:

<table border=”0" width=”100%”>
<tr>
<td><img src=”images/ol_inbox.gif” alt=”Inbox”
WIDTH=”16" HEIGHT=”16" onClick=
“parent.document.location=’vba:Outlook(Inbox)’”>
</td>
<td><a href=”vba:Outlook(Inbox)”>Входящие</a>
</td>
</tr>
<tr>
<td><img src=”images/ol_diary.gif” alt=”Journal”
WIDTH=”16" HEIGHT=”16" onClick=
“parent.document.location=’vba:Outlook(Journal)’”>
</td>
<td><a href=”vba:Outlook(Journal)”>Дневник</a>
</td>
</tr>
 
. . .
 
</table>

Обратите внимание на два варианта вызова команд VBA: с помощью события onClick для графического изображения и с помощью параметра href для обычного элемента <A>.

В начало В начало

Вызов приложений

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

Для запуска исполняемых программ в VBA предусмотрена функция Shell. Реализовать команду DD для вызова через VBA функции Shell совсем просто. Единственное, что следует учитывать, так это то, что перед вызовом некоторых программ требуется сделать активным каталог приложения. Следовательно, в вызове желательно предусмотреть те же параметры, что присутствуют в ярлыке приложения на рабочем столе. Очевидно, что все необходимые действия можно выполнить непосредственно в операторе Case процедуры DoIt:

‘— ShellApplication(Path,[StartDir])
Case “SHELLAPPLICATION”
If UBound(varArray) >= 3 Then
strParam = varArray(2)
ChDir strParam
End If
strParam = varArray(1)
RetVal = Shell(strParam, 1)

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

 

Окончание следует

КомпьютерПресс 5'2001

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
Популярные статьи
КомпьютерПресс использует