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

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

Совет 351. Пишите замечания, присылайте советы, задавайте вопросы

Совет 352. Как решить проблему с VisData

Совет 353. Внимание при работе с булевыми типами данных

Совет 354. Как обеспечить совместимость между VBA- и VB-проектами

Совет 355. Используйте свойство Buttonдля элемента управления DataGrid

Совет 356. Как сделать Help для своего приложения

Совет 357. Преобразование текстового файла в набор данных ADO

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

Совет 359. Работа с реестром и INI-файлами с помощью System.PrivateProfileString

Совет 360. Вместо DoEvents отслеживайте реальные события

Совет 361. Избегайте неявного преобразования типов данных

Совет 362. Как узнать список папок Outlook

Совет 363. Как добавить новый контакт в папку Outlook

Совет 364. Как обрабатывать входящие письма

Совет 365. Как вставить текст в создаваемое письмо

Совет 351. Пишите замечания, присылайте советы, задавайте вопросы

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

Промашки у нас, конечно, бывают. Например, Евгений Иванов справедливо заметил, что в Совете 307 (КомпьютерПресс № 6’2000) мы, рассказывая об удалении каталога с помощью Windows API, совсем забыли сказать, что в большинстве случаев с этой задачей отлично справляется давно знакомая встроенная Basic-функция rmDir.

Приятно отметить, что журнал КомпьютерПресс и наши Советы читают не только в нашей стране, но и в дальнем зарубежье (кстати, хотя русскоязычных программистов в Европе и США гораздо меньше, чем в России, их активность на электронных форумах и в переписке заметно выше). Михаил Эскин, например,  живет в Мюнхене и, как оказалось, является давним читателем наших публикаций. При этом он отмечает: «Ваши статьи стали постоянным моим спутником, несмотря на появление специальной литературы на прилавках». Спасибо!

В Германию российские журналы приходят с задержкой, поэтому Михаил только в ноябре прислал некоторые замечания по поводу статьи «Календарь наших дел», опубликованной в КомпьютерПресс № 5’2000. (Кстати, Михаил — автор серии статей о создании элементов управления в среде VB, опубликованных на сервере http://www.vbrussian.com/.) Об этих замечаниях мы поговорим в последующих Советах.

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

Совет 352. Как решить проблему с VisData

Мы уже несколько раз отмечали, что у утилиты VisData (создание баз данных) существуют проблемы с вводом и просмотром русских текстов. Михаил Эскин отмечает, что это, скорее, проблема конфигурации конкретного компьютера, которая решается следующим образом: в разделе [FontSubstitutes] файла WIN.INI нужно добавить сверху строку Tahoma,0=Tahoma,204 и затем перезагрузить компьютер.

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

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

Совет 353. Внимание при работе с булевыми типами данных

Михаил отметил также, что приведенный в нашей статье код для чтения/записи свойства DeleteMe (для пользовательского элемента управления Memos) при его привязке к значению флажка chkDeleteMe

Public Property Get DeleteMe() As Boolean 
  If chkDeleteMe.Value = 0 Then  
    DeleteMe = False  
  Else  
    DeleteMe = True  
  End If  
End Property  
   
Public Property Let DeleteMe(ByVal newDelete As Boolean)  
  If newDelete Then  
    chkDeleteMe.Value = 1  
  Else  
    chkDeleteMe.Value = 0  
  End If  
End Property  

Можно упростить, записав содержимое каждой из этих процедур в одну строку:

DeleteMe = -1 * chkDeleteMe.Value  
   
chkDeleteMe.Value = -1 * newDelete  

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

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

  1. Мы считаем принципиально неверным неявное преобразование данных, в данном случае из Integer в Boolean и наоборот. К сожалению, VB позволяет делать это, хотя вполне вероятно, что в VB.NET (7.0) такие вещи будут запрещены.
  2. Конечно, программисту полезно знать, в каком конкретном двоичном виде хранятся те или иные типы данных, но пользоваться такими знаниями нужно лишь в случае крайней необходимости.
  3. Серьезной проблемой VB является отсутствие беззнаковых целых типов данных. При этом путаница часто возникает именно из-за того, что переменные типа Integer и Long на самом деле выступают в роли то чисел со знаками (в арифметических операциях и при использовании десятичных литералов), то беззнаковыми (в логических операциях и в шестадцатеричных и восьмеричных литералах).
  4. Вообще говоря, практически в любой программе можно легко обойтись без использования типа Boolean, так как она является всего лишь частным случаем Integer (те же два байта для хранения информации). Более того, можно даже добиться экономии памяти — если использовать переменную типа Byte со значениями 0 или 1. Это легко можно сделать в «Календаре», где основная коррекция заключалась бы в замене в SQL-запроса:
    вместо "Where DeleteMe = True"  
       
    написать -- "Where DeleteMe = 1"  

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

  5. Но главное достоинство конструкции IF...Then...Else...EndIf –— очевидность логики ее работы. Попробуйте мгновенно ответить, каково будет значение DeleteMe при chkValue = 0 в этом выражении:
    DeleteMe = -1 * chkValue  
  6. В одну более короткую строку (но все же с увеличением машинных команд) можно было бы предложить вариант без неявного преобразования данных:
    DeleteMe = (chkDeleteMe.Value = 1)  
       
    chkDeleteMe.Value = IIf (1, 0, DeleteMe)  

    Но с точки зрения «очевидности» результата такой код также не безупречен.

  7. Несмотря на большое число строк в нашей конструкции IF...Then...Else...EndIf, очевидно, что этот код является самым компактным и быстрым (он занимает всего несколько машинных коротких команд). Более компактно его можно записать в таком виде:
    If chkDeleteMe.Value = 0 Then DeleteMe = False _ 
      Else DeleteMe = True 

Мы советуем использовать именно такой вариант.

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

Совет 354. Как обеспечить совместимость между VBA- и VB-проектами

Мы уже несколько раз отмечали, что, несмотря на всю схожесть VB и Office/VBA, у этих систем есть ряд серьезных различий, которые препятствуют прямому перенесению кода из одного вида проекта в другой и наоборот. Поэтому при написании кода, который предполагается для использования в разных системах, нужно специально тестировать возможность их использования в обоих вариантах. К сожалению, только изучая документацию, проверить это трудно.

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

Это, в частности, касается и создания модулей формы. Мы уже писали (Совет 301), что Office/VBA использует для создания форм ActiveX-конструктор Microsoft Form 2.0, который доступен также в VB. То есть VB может создавать два типа форм — собственные VB-формы (Ruby Forms) и UserForms (VBA Forms). Однако проблема заключается в том, что, даже используя одинаковый конструктор, VB и VBA сохраняют модули формы в разных форматах. При этом VB может читать оба формата, а VBA — только свой собственный.

Соответственно, если вы намерены создавать модули формы двойного применения, это следует делать не просто с помощью MS Forms 2.0 , а обязательно с этой целью использовать Office/VBA.

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

Перенос модулей формы в случае их несовместимости можно сделать следующим образом (например, из VB в VBA). Создайте в VBA визуальную форму со всеми компонентами. Задайте имена компонентов такие же, как в VB. Далее скопируйте содержимое кода из VB в VBA через буфер обмена.

Однако этот способ будет работать только при использовании Forms 2.0. При переносе VB-форм придется вручную корректировать имена некоторых событий и свойств. Например, в VBA события формы Initialize и Terminate соответствуют событиям Load и Unload в VB. В общем, с Microsoft не соскучишься.

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

Совет 355. Используйте свойство Buttonдля элемента управления DataGrid

Элемент управления DataGrid позволяет установить для ячеек одной или нескольких колонок таблицы свойство Button, которое обеспечивает их работу в режиме «кнопок». Например, установите

DataGrid1.Columns.Item(1).Button = True

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

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

Совет 356. Как сделать Help для своего приложения

Программ создания HELP-файлов довольно много, ряд из них — свободно распространяемые или условно-бесплатные. Для VB и VBA, возможно, лучшим способом является использование утилиты Microsoft HTML Help Workshop, которая поставляется в составе ряда программных продуктов, в том числе MS Office 2000 Developer Edition. При желании ее можно скачать из Интернета по адресу: http://www.microsoft.com/workshop/author/htmlhelp/. Описания работы этой утилиты имеются в целом ряде книг по VB.

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

Совет 357. Преобразование текстового файла в набор данных ADO

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

connCSV.Open "Provider=Microsoft.Jet.OLEDB.4.0;" & _  
  "Data Source=" & FileName$ & _  
  ";Extended Properties='text;FMT=Delimited'"  

В данном случае строка с параметрами соединения (Connection String) содержит раздел Extended Properties, который указывает, что используется текстовый файл с полями. Однако следует иметь в виду, что приведенный вариант обращения подразумевает наличие в первой строке текстового файла заголовков полей. Если же заголовков нет, следует указать в явном виде аргумент HDR:

connCSV.Open "Provider=Microsoft.Jet.OLEDB.4.0;" & _  
  "Data Source=" & FileName$ & _  
  ";Extended Properties='text;HDR=NO;FMT=Delimited'"  
В начало В начало

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

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

Load object(index)  

где object — имя массива, а index — номер нового элемента управления, который вы хотите добавить. Но при этом в исходном состоянии в массиве уже должен иметься хотя бы один элемент управления (нумерация индекса начинается с нуля). В более общем случае создание новой кнопки может выглядеть так, как описано ниже.

Создайте новый проект и добавьте к форме командную кнопку. Затем в окне Properties введите 0 для свойства Index — VB сразу преобразует одиночную кнопку в массив. Далее введите такой код для формы:

Private Sub cmdBtn_Click(Index As Integer)  
  ' создание новой кнопки для массива элементов управления  
  Dim btn As CommandButton  
  Dim iIndex As Integer  
  iIndex = cmdBtn.Count  'текущее числе элементов массива  
  If iIndex <= 32767 Then '  можно добавлять  
    Load cmdBtn(iIndex)  
    Set btn = cmdBtn(iIndex)  
    With btn  ' установка свойств  
      .Top = cmdBtn(iIndex - 1).Top + 620  
      .Caption = "Command" & iIndex + 1  
      .Visible = True  
    End With  
    Set btn = Nothing  
  End If  
End Sub  
В начало В начало

Совет 359. Работа с реестром и INI-файлами с помощью System.PrivateProfileString

Работа с реестром Windows может выполняться не только с помощью функций Windows API или объекта Registry (см. Совет 273), но и с применением свойства PrivateProfileString объекта System, который входит в состав библиотеки Microsoft Word 8.0/9.0 Object Library. Она автоматически подключается при работе с MS Word 97/2000 и может использоваться в любых инструментах, которые поддерживают работу с ActiveX-объектами. В частности, к среде VB или MS Office/VBA она подключается с помощью команды Project|Reference или Tools|Reference соответственно.

Вот как будет выглядеть чтение полного имени каталога, где находится Internet Explorer:

RegFile$ = ""   ' пустое имя означает Системный Реестр  
SectionName$ = "HKEY_CURRENT_USER\Software\Microsoft\" _  
    & "Windows\CurrentVersion\App Paths\IEXPLORER.EXE") ' имя раздела  
KeyName$ = "Path"  ' имя ключа  
IEPath$ = System.PrivateProfileString(RegFile$, SectionName$, KeyName$)  
If IEPath$ <> "" Then   ' есть имя каталога  
  MsgBox "Имя каталога с IE = " & IEPath$  
End If  

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

System.PrivateProfileString(RegFile$, SectionName$, KeyName$)= IEPath$  

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

Например, при закрытии текущего документа Word можно автоматически фиксировать имя последнего использовавшегося документа:

System.PrivateProfileString("C:\MyWordSetting.ini", "MacroSettings", _  
    "LastFile") = ActiveDocument.FullName  

А при загрузке Word можно автоматически открыть данный файл:

LastFile$ = System.PrivateProfileString("C:\Settings.Txt", _  
    "MacroSettings", "LastFile")  
If LastFile$ <> "" Then Documents.Open FileName:=LastFile$  

Необходимо обратить внимание на следующие особенности применения свойства PrivateProfileString:

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

Например, если файл D:\MyFile.INI не существует, то после выполнения кода:

System.PrivateProfileString("d:\ MyFile.INI", "test1", "key1") = "andy"  

будет сформирован файл следующего содержания:

[test1]  
key1=andy  
В начало В начало

Совет 360. Вместо DoEvents отслеживайте реальные события

Оператор DoEvents позволяет выполнять параллельные процессы, поэтому достаточно часто используется для синхронизации двух различных вычислительных процессов. Типичным случаем является такой пример. Имеются две формы: главная (frmMain) выполняет некоторые вычисления и выводит результаты, а вторая (frmEntry) — вводит исходные данные для этих вычислений. При этом логика взаимодействия данных форм такова: главная форма запускает frmEntry и ожидает, когда там будут введены нужные данные, например, в виде нажатия пользователем кнопки Submit (Подтверждение).

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

Private Sub Command1_Click()  
  ' процедура в форме frmMain  
  Dim Myform As frmEntry  
  ' создание второй формы для ввода данных  
  Set Myform = New frmEntry  
  With Myform  
    .Show  
    .Ready = False  ' начальная установка глобальной переменной  
    Do  ' ожидание  
      DoEvents  ' передача управления операционной системе  
                ' для обработки других событий  
    Loop Until .Ready  
    'Выполнение каких-то вычислений на основе введенных данных  
    txtResults.Text = .txtNum1 * .txtNum2  
  End With  
  Unload Myform  
  Set Myform = Nothing  ' освободить объект  
End Sub  
'  
'============  
' код формы frmEntry1  
Public Ready As Boolean  
Private Sub cmdSubmit_Click()  
  Ready = True  ' подтверждение ввода  
End Sub   

Данная конструкция базируется на отслеживании состояния глобальной переменной Ready в форме frmEntry1. Однако недостатком этой конструкции является как раз использование оператора DoEvents, который требует достаточно много времени, то есть «съедает» значительную часть ресурсов.

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

' описание события в секции Declaration  
Public Event NumbersSubmitted(Num1 As Integer, Num2 As Integer)  
   
' выполнение операций   
Private Sub cmdSubmit2_Click()  
  Dim Num1%, Num2%  
  Num1 = CInt(txtNum1.Text)  
  Num2 = CInt(txtNum2.Text)  
  Unload Me  
  ' запуск внешнего события с передачей параметров  
  RaiseEvent NumbersSubmitted(Num1, Num2)  
End Sub  

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

Private WithEvents frmNumEntry As frmEntry 
   
Private Sub Command2_Click()  
  ' запуск второй формы  
  Set frmNumEntry = New frmEntry  
  frmNumEntry.Show  
End Sub  
   
Private Sub frmNumEntry_NumbersSubmitted(Num1%, Num2%)  
  ' обработка события, инициализированного из формы frmEntry  
  txtResults.Text = Num1 * Num2  
  Set frmNumEntry = Nothing  
End Sub  
В начало В начало

Совет 361. Избегайте неявного преобразования типов данных

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

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

Выполните такой код:

Dim strSource As String, strR1 As String, strR2 As String  
Dim sngResult As Single  
strSource = "2.34"  
' преобразование строки в вещественное число  
sngResult = Val(strSource)  
Print sngResult   ' будет напечатано 2,34  
'  
strR1 = Str(sngResult)  
strR2 = sngResult  
Print strR1, strR2    ' будет напечатано 2.34  2,34  

Если вы попробуете выполнить код:

strSource = "2.34" 
sngResult = strSource  

то получите на втором операторе сообщение об ошибке — неверный тип данных.

Далее выполните еще один код:

strSource = "2,34" 
sngResult = Val(strSource)  
Print sngResult   ' будет напечатано 2 ! Ошибка  
   
sngResult = Val(strSource)  
strR1 = Str(sngResult)  
strR2 = sngResult  
Print strR1, strR2    ' будет напечатано 2.34  2,34  

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

  1. Функции явного и неявного преобразования данных работают по-разному! Val и Str выполняют операции преобразования по правилам американских региональных установок, независимо от установок пользователя на его компьютере. Неявное преобразование выполняется с учетом установленных на компьютере параметров.
  2. Казалось бы, оба варианта имеют свои недостатки. Более того, на «русской» системе лучше использовать неявное преобразование. Но здесь стоит обратить внимание на следующий момент: функции Val и Str будут одинаково работать на любом ПК, тогда как операции неявного преобразования могут выдавать разные результаты в зависимости от региональных установок.
В начало В начало

Совет 362. Как узнать список папок Outlook

Допустим, вы хотите собрать список папок в некий список. Казалось бы, узнать имена папок можно следующим образом:

Dim AllFolders As Folders  
Set AllFolders = Application.GetNamespace("MAPI").Folders  
MsgBox AllFolders.Count  
For i = 1 To AllFolders.Count  
  MsgBox AllFolder.Item(i).Name  
Next  

Однако выясняется, что у вас имеется всего две папки с именами Personal Folders. Здесь полезно вспомнить, что папки OutLook имеют иерархическую структуру, такую же, как знакомая файловая система. В частности, она может иметь вид, представленный на рис. 1.Приведенная выше конструкция выдала нам имена стандартных папок самого верхнего уровня.

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

Dim allFolders As Folders  
Dim i%, j%  
Set allFolders = Application.GetNamespace("MAPI").Folders  
MsgBox "Число папок верхнего уровня = " & allFolders.Count  
' обзор папок верхнего уровня  
For i = 1 To allFolders.Count  
  MsgBox "Имя папки = " & _  
    allFolders.Item(i).Name & vbCrLf & _  
     "  число вложенных папок = " & _  
      allFolders.Item(i).Folders.Count  
  ' обзор папок второго уровня  
  For j = 1 To allFolders.Item(i).Folders.Count  
     MsgBox "Имена вложенной папки = " & _  
       allFolders.Item(i).Folders.Item(j).Name & vbCrLf & _  
        " число вложенных в нее папок = " & _  
        allFolders.Item(i).Folders.Item(j).Folders.Count  
  Next  
Next  

Однако понятно, что наращивание числа вложенных циклов для обзора иерархических структур является совершенно бесперспективным занятием. (В нашем примере одна из папок второго уровня — Contacts — имеет также вложенную папку.) Здесь требуется переходить к рекурсивным конструкциям, которые могут выглядеть примерно так:

Dim allFolders As Folders  
Dim intLevel%  ' номер уровня  
intLevel = 0  
Set allFolders = Application.GetNamespace("MAPI").Folders  
Call FoldersViewRecurse(allFolders, intLevel, "MAPI")  
   
Sub FoldersViewRecurse(allFolders As Folders, intLevel%, strName$)  
  Dim i%, FolderName$  
  Dim newFolders As Folders  
  ' Вывод информации о папках данного узла иерархической структуры  
  Debug.Print "Уровень = "; intLevel; " Узел = "; _  
    strName$; Tab(45); " Вложенных папок = "; allFolders.Count  
  If allFolders.Count > 0 Then ' есть вложенные папки  
    For i = 1 To allFolders.Count  ' обзор вложенных папок  
      FolderName$ = allFolders.Item(i).Name  
      Set newFolders = allFolders.Item(i).Folders  
      ' рекурсивное обращение к самой себе:  
      Call FoldersViewRecurse(newFolders, intLevel + 1, FolderName$)  
    Next  
  End If  
End Sub  

В правильности работы данной конструкции легко убедиться, взглянув на полученную распечатку результатов (рис. 2).

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

Совет 363. Как добавить новый контакт в папку Outlook

Это производится приблизительно следующим образом:

Dim myNewContact As ContactItem
' создание объекта "Контакт"  
Set myNewContact = Application.CreateItem(olContactItem)  
' далее заполняются нужные поля формы  
myNewContact.FirstName = "Андрей"  
myNewContact.LastName = "Колесов"  
myNewContact.Email1Address = "akolesov@online.ru"  
myNewContact.Close olSave    ' сохранить  

Можно также выдать диалоговое окно «Контакты» для заполнения пользователем:

myNewContact.Display 

Однако данная конструкция записывает новый контакт в стандартную папку «Контакты». Если вам нужно работать с какой-то индивидуальной папкой, вы должны написать такой код (здесь мы вдобавок создаем новую папку):

Dim myNewContact As ContactItem 
Dim myNewFolder As MAPIFolder  
' Создание папки типа "Контакты"  
Set myNewFolder = Application.GetNamespace("MAPI"). _  
     GetDefaultFolder(olFolderContacts).Folders.Add("Личная")  
' создание объекта "Контакт" для данной папки  
Set myNewContact = myNewFolder.Items.Add(olContactItem)  
myNewContact.FirstName = "Андрей"  
...  
В начало В начало

Совет 364. Как обрабатывать входящие письма

Вам бы хотелось автоматически обрабатывать входящие письма? Это довольно просто сделать с помощью такого кода:

Private Sub Application_NewMail() 
   ' При поступлении нового письма  
   ' производится его обработка  
    Dim mailItems As Items  
    Dim mailmsg As MailItem  
   
    ' Набор писем из папки "Входящие"  
    Set mailItems = Application.Session._  
        GetDefaultFolder(olFolderInbox).Items  
    Set mailmsg = mailItems.GetLast ' выбираем последнее  
    ' далее выполняется анализ письма  
    ' (его реквизитов, содержимого и пр.  
    ' ...  
    ' по результатам анализа можно:  
    mailmsg.UnRead = False  ' установить признак "Прочтенное"  
    mailmsg.Delete   ' удалить  
    mailmsg.Move(myFolder)   ' переместить в другую папку  
End Sub  
В начало В начало

Совет 365. Как вставить текст в создаваемое письмо

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

Sub NewMailToKolesov() 
  ' создание нового письма  
  Dim myMail As MailItem  
  Set myMail = CreateItem(olMailItem)  
  ' заполнение его полей  
  myMail.To = "akolesov@online.ru"  
  myMail.Subject = "Привет!"  
  myMail.body = "Андрей!" & vbCrLf & _  
    "Я тут придумал такую классную штуку."  
  myMail.Display  ' выводим окно и дополняем текст  
End Sub  

Но возможен и другой вариант — вы уже создали новое письмо и хотите в процессе его ввода сделать вставку какого-то текста. В этом случае вам пригодится макрокоманда такого вида:

Sub InsertText() 
    'Вставить текст в текущее окно  
    Dim myMail As MailItem  
    ' выбирает текущее окно (т.е. нового письма)  
    Set myMail = Application.ActiveInspector.CurrentItem  
    myMail.body = myMail.body + " Привет семье!"  
End Sub  

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