Создание сложного элемента повторяющейся встречи
Область применения: Outlook 2013 | Outlook 2016
MAPI можно использовать для создания повторяющихся элементов встреч.
Сведения о том, как скачать, просмотреть и запустить код из приложения MFCMAPI и проекта CreateOutlookItemsAddin, упоминаемого в этом разделе, см. в разделе Установка примеров, используемых в этом разделе.
Создание элемента встречи
Откройте хранилище сообщений. Сведения об открытии хранилища сообщений см. в разделе Открытие хранилища сообщений.
Откройте папку Календарь в хранилище сообщений. См . PR_IPM_APPOINTMENT_ENTRYID (PidTagIpmAppointmentEntryId).
Вызовите метод IMAPIFolder::CreateMessage в папке Calendar, чтобы создать новый элемент встречи.
Задайте свойство dispidApptRecur (PidLidAppointmentRecur) и другие свойства, необходимые для создания повторяющейся встречи.
Сохраните новый элемент встречи.
Эти AddAppointment
шаги демонстрирует функция в исходном файле Appointments.cpp проекта CreateOutlookItemsAddin. Функция AddAppointment
принимает параметры из диалогового окна Добавление встречи , которое отображается при нажатии кнопки Добавить встречу в меню Addins в примере приложения MFCMAPI. Функция DisplayAddAppointmentDialog
в Appointments.cpp отображает диалоговое окно и передает значения из диалогового окна в функцию AddAppointment
. Функция DisplayAddAppointmentDialog
не связана напрямую с созданием элемента встречи с помощью MAPI, поэтому она не указана здесь.
Важно!
Код в приложении MFCMAPI не гарантирует, что папка Calendar выбрана при нажатии команды Добавить встречу в меню Addins . Создание элемента встречи в папке, отличной от папки Календарь , может привести к неопределенному поведению. Убедитесь, что вы выбрали папку Календарь , прежде чем использовать команду Добавить встречу в приложении MFCMAPI.
Метод AddAppointment
приведен ниже. Обратите внимание, что параметр lpFolder , передаваемый AddAppointment
в метод, является указателем на интерфейс IMAPIFolder , представляющий папку, в которой создается повторяющаяся встреча. Учитывая параметр lpFolder , представляющий интерфейс IMAPIFolder , код вызывает метод IMAPIFolder::CreateMessage . Метод CreateMessage возвращает код успешного выполнения и указатель на указатель на интерфейс IMessage . Большая часть AddAppointment
кода функции обрабатывает работу по указанию свойств при подготовке к вызову метода IMAPIProp::SetProps . Если вызов метода SetProps выполнен успешно, вызывается метод IMAPIProp::SaveChanges для фиксации изменений в хранилище и создания нового элемента календаря.
Функция AddAppointment
задает ряд именованных свойств. Сведения об именованных свойствах и способах их создания см. в статье Использование MAPI для создания элементов Outlook 2007. Так как именованные свойства, используемые для элементов встреч, занимают несколько наборов свойств, при создании параметров необходимо соблюдать осторожность для передачи в метод IMAPIProp::GetIDsFromNames .
Функция AddAppointment
использует несколько вспомогательных функций для создания структуры для различных свойств, связанных с встречами. Вспомогательные BuildTimeZoneStruct
функции и BuildTimeZoneDefinition
используются для создания структуры, указывающей свойства, связанные с часовыми поясами. Свойства, связанные с часовыми поясами: dispidTimeZoneStruct (PidLidTimeZoneStruct), dispidTimeZoneDesc (PidLidTimeZoneDescription), dispidApptTZDefRecur (PidLidAppointmentTimeZoneDefinitionRecur).dispidApptTZDefStartDisplay (PidLidAppointmentTimeZoneDefinitionStartDisplay) и dispidApptTZDefEndDisplay (PidLidAppointmentTimeZoneDefinitionEndDisplay), и они обсуждаются в соответствующие разделы [MS-OXOCAL].
Функция BuildGlobalObjectID
используется для создания структуры, указывающей свойства LID_GLOBAL_OBJID (PidLidGlobalObjectId) и dispidCleanGlobalObjId (PidLidCleanGlobalObjectId), которые рассматриваются в соответствующих разделах [MS-OXOCAL]. Структура, указывающая свойство dispidApptRecur , строится с помощью BuildWeeklyAppointmentRecurrencePattern
функции .
Сведения о структуре, созданной функцией, см. в BuildWeeklyAppointmentRecurrencePattern
разделе Каноническое свойство PidLidAppointmentRecur. Обратите внимание, что хотя существует множество шаблонов повторения встреч, BuildWeeklyAppointmentRecurrencePattern
функция создает только еженедельный шаблон повторения встреч. Он также использует несколько жестко закодированных значений, таких как тип календаря (григорианский), первый день недели (воскресенье) и количество измененных или удаленных экземпляров (нет). Функция создания шаблона повторения встреч общего назначения должна принимать такие переменные в качестве параметров.
Ниже приведен полный AddAppointment
список функции.
HRESULT AddAppointment(LPMAPIFOLDER lpFolder,
SYSTEMTIME* lpstStartDateLocal, // PidLidAppointmentRecur
SYSTEMTIME* lpstEndDateLocal, // PidLidAppointmentRecur
SYSTEMTIME* lpstStartFirstUST, // PidLidAppointmentStartWhole, PidLidCommonStart, PR_START_DATE
SYSTEMTIME* lpstEndFirstUST, // PidLidAppointmentEndWhole, PidLidCommonEnd, PR_END_DATE
SYSTEMTIME* lpszClipStartUST, // PidLidClipStart
SYSTEMTIME* lpstClipEndUST, // PidLidClipEnd
SYSTEMTIME* lpstFirstDOW, // PidLidAppointmentRecur
DWORD dwStartOffsetLocal, // PidLidAppointmentRecur
DWORD dwEndOffsetLocal, // PidLidAppointmentRecur
DWORD dwPeriod, // PidLidAppointmentRecur
DWORD dwOccurrenceCount, // PidLidAppointmentRecur
DWORD dwPatternTypeSpecific, // PidLidAppointmentRecur
ULONG ulDuration, // PidLidAppointmentDuration
LPWSTR szSubject, // PR_SUBJECT_W
LPWSTR szLocation, // PidLidLocation
LPWSTR szPattern) // PidLidRecurrencePattern
{
if (!lpFolder) return MAPI_E_INVALID_PARAMETER;
HRESULT hRes = S_OK;
LPMESSAGE lpMessage = 0;
// create a message and set its properties
hRes = lpFolder->CreateMessage(0,
0,
&lpMessage);
if (SUCCEEDED(hRes))
{
MAPINAMEID rgnmid[ulAppointmentProps];
LPMAPINAMEID rgpnmid[ulAppointmentProps];
LPSPropTagArray lpNamedPropTags = NULL;
ULONG i = 0;
for (i = 0 ; i < ulAppointmentProps ; i++)
{
if (i < ulFirstMeetingProp)
rgnmid[i].lpguid = (LPGUID)&PSETID_Appointment;
else if (i < ulFirstCommonProp)
rgnmid[i].lpguid = (LPGUID)&PSETID_Meeting;
else
rgnmid[i].lpguid = (LPGUID)&PSETID_Common;
rgnmid[i].ulKind = MNID_ID;
rgnmid[i].Kind.lID = aulAppointmentProps[i];
rgpnmid[i] = &rgnmid[i];
}
hRes = lpFolder->GetIDsFromNames(
ulAppointmentProps,
(LPMAPINAMEID*) &rgpnmid,
NULL,
&lpNamedPropTags);
if (SUCCEEDED(hRes) && lpNamedPropTags)
{
// Because the properties to be set are known in advance,
// most of the structures involved can be statically declared
// to minimize expensive MAPIAllocateBuffer calls.
SPropValue spvProps[NUM_PROPS] = {0};
spvProps[p_PidLidAppointmentSequence].ulPropTag
= CHANGE_PROP_TYPE(lpNamedPropTags->aulPropTag[p_PidLidAppointmentSequence],PT_LONG);
spvProps[p_PidLidBusyStatus].ulPropTag
= CHANGE_PROP_TYPE(lpNamedPropTags->aulPropTag[p_PidLidBusyStatus],PT_LONG);
spvProps[p_PidLidLocation].ulPropTag
= CHANGE_PROP_TYPE(lpNamedPropTags->aulPropTag[p_PidLidLocation],PT_UNICODE);
spvProps[p_PidLidAppointmentStartWhole].ulPropTag
= CHANGE_PROP_TYPE(lpNamedPropTags->aulPropTag[p_PidLidAppointmentStartWhole],PT_SYSTIME);
spvProps[p_PidLidAppointmentEndWhole].ulPropTag
= CHANGE_PROP_TYPE(lpNamedPropTags->aulPropTag[p_PidLidAppointmentEndWhole],PT_SYSTIME);
spvProps[p_PidLidAppointmentDuration].ulPropTag
= CHANGE_PROP_TYPE(lpNamedPropTags->aulPropTag[p_PidLidAppointmentDuration],PT_LONG);
spvProps[p_PidLidAppointmentColor].ulPropTag
= CHANGE_PROP_TYPE(lpNamedPropTags->aulPropTag[p_PidLidAppointmentColor],PT_LONG);
spvProps[p_PidLidResponseStatus].ulPropTag
= CHANGE_PROP_TYPE(lpNamedPropTags->aulPropTag[p_PidLidResponseStatus],PT_LONG);
spvProps[p_PidLidRecurring].ulPropTag
= CHANGE_PROP_TYPE(lpNamedPropTags->aulPropTag[p_PidLidRecurring],PT_BOOLEAN);
spvProps[p_PidLidClipStart].ulPropTag
= CHANGE_PROP_TYPE(lpNamedPropTags->aulPropTag[p_PidLidClipStart],PT_SYSTIME);
spvProps[p_PidLidClipEnd].ulPropTag
= CHANGE_PROP_TYPE(lpNamedPropTags->aulPropTag[p_PidLidClipEnd],PT_SYSTIME);
spvProps[p_PidLidTimeZoneStruct].ulPropTag
= CHANGE_PROP_TYPE(lpNamedPropTags->aulPropTag[p_PidLidTimeZoneStruct],PT_BINARY);
spvProps[p_PidLidTimeZoneDescription].ulPropTag
= CHANGE_PROP_TYPE(lpNamedPropTags->aulPropTag[p_PidLidTimeZoneDescription],PT_UNICODE);
spvProps[p_PidLidAppointmentTimeZoneDefinitionRecur].ulPropTag
= CHANGE_PROP_TYPE(lpNamedPropTags->aulPropTag[p_PidLidAppointmentTimeZoneDefinitionRecur],
PT_BINARY);
spvProps[p_PidLidAppointmentTimeZoneDefinitionStartDisplay].ulPropTag
= CHANGE_PROP_TYPE(lpNamedPropTags->aulPropTag[p_PidLidAppointmentTimeZoneDefinitionStartDisplay],
PT_BINARY);
spvProps[p_PidLidAppointmentTimeZoneDefinitionEndDisplay].ulPropTag
= CHANGE_PROP_TYPE(lpNamedPropTags->aulPropTag[p_PidLidAppointmentTimeZoneDefinitionEndDisplay],
PT_BINARY);
spvProps[p_PidLidAppointmentRecur].ulPropTag
= CHANGE_PROP_TYPE(lpNamedPropTags->aulPropTag[p_PidLidAppointmentRecur],PT_BINARY);
spvProps[p_PidLidRecurrenceType].ulPropTag
= CHANGE_PROP_TYPE(lpNamedPropTags->aulPropTag[p_PidLidRecurrenceType],PT_LONG);
spvProps[p_PidLidRecurrencePattern].ulPropTag
= CHANGE_PROP_TYPE(lpNamedPropTags->aulPropTag[p_PidLidRecurrencePattern],PT_UNICODE);
spvProps[p_PidLidIsRecurring].ulPropTag
= CHANGE_PROP_TYPE(lpNamedPropTags->aulPropTag[p_PidLidIsRecurring],PT_BOOLEAN);
spvProps[p_PidLidGlobalObjectId].ulPropTag
= CHANGE_PROP_TYPE(lpNamedPropTags->aulPropTag[p_PidLidGlobalObjectId],PT_BINARY);
spvProps[p_PidLidCleanGlobalObjectId].ulPropTag
= CHANGE_PROP_TYPE(lpNamedPropTags->aulPropTag[p_PidLidCleanGlobalObjectId],PT_BINARY);
spvProps[p_PidLidCommonStart].ulPropTag
= CHANGE_PROP_TYPE(lpNamedPropTags->aulPropTag[p_PidLidCommonStart],PT_SYSTIME);
spvProps[p_PidLidCommonEnd].ulPropTag
= CHANGE_PROP_TYPE(lpNamedPropTags->aulPropTag[p_PidLidCommonEnd],PT_SYSTIME);
spvProps[p_PidLidSideEffects].ulPropTag
= CHANGE_PROP_TYPE(lpNamedPropTags->aulPropTag[p_PidLidSideEffects],PT_LONG);
spvProps[p_PR_SUBJECT_W].ulPropTag = PR_SUBJECT_W;
spvProps[p_PR_START_DATE].ulPropTag = PR_START_DATE;
spvProps[p_PR_END_DATE].ulPropTag = PR_END_DATE;
spvProps[p_PR_MESSAGE_CLASS_W].ulPropTag = PR_MESSAGE_CLASS_W;
spvProps[p_PR_ICON_INDEX].ulPropTag = PR_ICON_INDEX;
spvProps[p_PR_CONVERSATION_INDEX].ulPropTag = PR_CONVERSATION_INDEX;
spvProps[p_PR_MESSAGE_FLAGS].ulPropTag = PR_MESSAGE_FLAGS;
spvProps[p_PidLidAppointmentSequence].Value.l = 0;
spvProps[p_PidLidBusyStatus].Value.l = olBusy;
spvProps[p_PidLidLocation].Value.lpszW = szLocation;
SystemTimeToFileTime(lpstStartFirstUST,&spvProps[p_PidLidAppointmentStartWhole].Value.ft);
SystemTimeToFileTime(lpstEndFirstUST,&spvProps[p_PidLidAppointmentEndWhole].Value.ft);
spvProps[p_PidLidAppointmentDuration].Value.l = ulDuration;
spvProps[p_PidLidAppointmentColor].Value.l = 0; // No color
spvProps[p_PidLidResponseStatus].Value.l = respNone;
spvProps[p_PidLidRecurring].Value.b = true;
SystemTimeToFileTime(lpszClipStartUST,&spvProps[p_PidLidClipStart].Value.ft);
SystemTimeToFileTime(lpstClipEndUST,&spvProps[p_PidLidClipEnd].Value.ft);
SYSTEMTIME stStandard = {0};
stStandard.wMonth = 0xB;
stStandard.wDay = 0x1;
stStandard.wHour = 0x2;
SYSTEMTIME stDaylight = {0};
stDaylight.wMonth = 0x3;
stDaylight.wDay = 0x2;
stDaylight.wHour = 0x2;
hRes = BuildTimeZoneStruct(
300,
0,
(DWORD)-60,
&stStandard,
&stDaylight,
&spvProps[p_PidLidTimeZoneStruct].Value.bin.cb,
&spvProps[p_PidLidTimeZoneStruct].Value.bin.lpb);
spvProps[p_PidLidTimeZoneDescription].Value.lpszW = L"(GMT-05:00) Eastern Time (US & Canada)";
SYSTEMTIME stRule1Standard = {0};
stRule1Standard.wMonth = 0xA;
stRule1Standard.wDay = 0x5;
stRule1Standard.wHour = 0x2;
SYSTEMTIME stRule1Daylight = {0};
stRule1Daylight.wMonth = 0x4;
stRule1Daylight.wDay = 0x1;
stRule1Daylight.wHour = 0x2;
if (SUCCEEDED(hRes)) hRes = BuildTimeZoneDefinition(
L"Eastern Standard Time",
0, // TZRule Flags
2006, // wYear
300, // lbias
0, // lStandardBias,
(DWORD)-60, // lDaylightBias,
&stRule1Standard, // stStandardDate
&stRule1Daylight, // stDaylightDate
TZRULE_FLAG_EFFECTIVE_TZREG, // TZRule Flags
2007, // wYear
300, // lbias
0, // lStandardBias,
(DWORD)-60, // lDaylightBias,
&stStandard, // stStandardDate
&stDaylight, // stDaylightDate
&spvProps[p_PidLidAppointmentTimeZoneDefinitionRecur].Value.bin.cb,
&spvProps[p_PidLidAppointmentTimeZoneDefinitionRecur].Value.bin.lpb);
spvProps[p_PidLidAppointmentTimeZoneDefinitionStartDisplay].Value.bin.cb
= spvProps[p_PidLidAppointmentTimeZoneDefinitionRecur].Value.bin.cb;
spvProps[p_PidLidAppointmentTimeZoneDefinitionStartDisplay].Value.bin.lpb
= spvProps[p_PidLidAppointmentTimeZoneDefinitionRecur].Value.bin.lpb;
spvProps[p_PidLidAppointmentTimeZoneDefinitionEndDisplay].Value.bin.cb
= spvProps[p_PidLidAppointmentTimeZoneDefinitionRecur].Value.bin.cb;
spvProps[p_PidLidAppointmentTimeZoneDefinitionEndDisplay].Value.bin.lpb
= spvProps[p_PidLidAppointmentTimeZoneDefinitionRecur].Value.bin.lpb;
if (SUCCEEDED(hRes)) hRes = BuildWeeklyAppointmentRecurrencePattern(
lpstStartDateLocal,
lpstEndDateLocal,
lpstFirstDOW,
dwStartOffsetLocal,
dwEndOffsetLocal,
dwPeriod,
dwOccurrenceCount,
dwPatternTypeSpecific,
&spvProps[p_PidLidAppointmentRecur].Value.bin.cb,
&spvProps[p_PidLidAppointmentRecur].Value.bin.lpb);
spvProps[p_PidLidRecurrenceType].Value.l = rectypeWeekly;
spvProps[p_PidLidRecurrencePattern].Value.lpszW = szPattern;
spvProps[p_PidLidIsRecurring].Value.b = true;
if (SUCCEEDED(hRes)) hRes = BuildGlobalObjectId(
&spvProps[p_PidLidGlobalObjectId].Value.bin.cb,
&spvProps[p_PidLidGlobalObjectId].Value.bin.lpb);
spvProps[p_PidLidCleanGlobalObjectId].Value.bin.cb = spvProps[p_PidLidGlobalObjectId].Value.bin.cb;
spvProps[p_PidLidCleanGlobalObjectId].Value.bin.lpb = spvProps[p_PidLidGlobalObjectId].Value.bin.lpb;
SystemTimeToFileTime(lpstStartFirstUST,&spvProps[p_PidLidCommonStart].Value.ft);
SystemTimeToFileTime(lpstEndFirstUST,&spvProps[p_PidLidCommonEnd].Value.ft);
spvProps[p_PidLidSideEffects].Value.l
= seOpenToDelete | seOpenToCopy | seOpenToMove | seCoerceToInbox | seOpenForCtxMenu;
spvProps[p_PR_SUBJECT_W].Value.lpszW = szSubject;
SystemTimeToFileTime(lpstStartFirstUST,&spvProps[p_PR_START_DATE].Value.ft);
SystemTimeToFileTime(lpstEndFirstUST,&spvProps[p_PR_END_DATE].Value.ft);
spvProps[p_PR_MESSAGE_CLASS_W].Value.lpszW = L"IPM.Appointment";
spvProps[p_PR_ICON_INDEX].Value.l = 0x00000401; // Recurring Appointment
if (SUCCEEDED(hRes)) hRes = BuildConversationIndex(
&spvProps[p_PR_CONVERSATION_INDEX].Value.bin.cb,
&spvProps[p_PR_CONVERSATION_INDEX].Value.bin.lpb);
spvProps[p_PR_MESSAGE_FLAGS].Value.l = MSGFLAG_READ;
if (SUCCEEDED(hRes)) hRes = lpMessage->SetProps(NUM_PROPS, spvProps, NULL);
if (SUCCEEDED(hRes))
{
hRes = lpMessage->SaveChanges(FORCE_SAVE);
}
if (spvProps[p_PidLidTimeZoneStruct].Value.bin.lpb)
delete[] spvProps[p_PidLidTimeZoneStruct].Value.bin.lpb;
if (spvProps[p_PidLidAppointmentTimeZoneDefinitionRecur].Value.bin.lpb)
delete[] spvProps[p_PidLidAppointmentTimeZoneDefinitionRecur].Value.bin.lpb;
// Do not delete p_PidLidAppointmentTimeZoneDefinitionStartDisplay,
// it was borrowed from p_PidLidAppointmentTimeZoneDefinitionStartDisplay
// Do not delete p_PidLidAppointmentTimeZoneDefinitionEndDisplay,
// it was borrowed from p_PidLidAppointmentTimeZoneDefinitionStartDisplay
if (spvProps[p_PidLidAppointmentRecur].Value.bin.lpb)
delete[] spvProps[p_PidLidAppointmentRecur].Value.bin.lpb;
if (spvProps[p_PidLidGlobalObjectId].Value.bin.lpb)
delete[] spvProps[p_PidLidGlobalObjectId].Value.bin.lpb;
// Do not delete p_PidLidCleanGlobalObjectId, it was borrowed from p_PidLidGlobalObjectId
if (spvProps[p_PR_CONVERSATION_INDEX].Value.bin.lpb)
delete[] spvProps[p_PR_CONVERSATION_INDEX].Value.bin.lpb;
}
MAPIFreeBuffer(lpNamedPropTags);
}
if (lpMessage) lpMessage->Release();
return hRes;
}