创建复杂定期约会项
适用于:Outlook 2013 | Outlook 2016
MAPI 可用于创建定期约会项目。
有关如何从本主题中引用的 MFCMAPI 应用程序和 CreateOutlookItemsAddin 项目下载、查看和运行代码的信息,请参阅 安装本节中使用的示例。
创建约会项目
打开消息存储。 有关如何打开消息存储的信息,请参阅 打开消息存储。
在邮件存储中打开日历文件夹。 请参阅 PR_IPM_APPOINTMENT_ENTRYID (PidTagIpmAppointmentEntryId) 。
调用 Calendar 文件夹上的 IMAPIFolder::CreateMessage 方法以创建新的约会项目。
设置 dispidApptRecur (PidLidAppointmentRecur) 属性和创建定期约会所需的其他属性。
保存新的约会项目。
AddAppointment
CreateOutlookItemsAddin 项目的 Appointments.cpp 源文件中的 函数演示了这些步骤。 该AddAppointment
函数从“添加约会”对话框中获取参数,在 MFCMAPI 示例应用程序中的“添加约会”菜单上单击“添加约会”时显示该对话框。
DisplayAddAppointmentDialog
Appointments.cpp 中的函数显示对话框,并将值从对话框传递到AddAppointment
函数。 函数 DisplayAddAppointmentDialog
与使用 MAPI 创建约会项目不直接相关,因此此处未列出。
重要
单击“添加约会”菜单上的“添加约会”命令时,MFCMAPI 应用程序中的代码不确保选择了“日历”文件夹。 在 日历 文件夹以外的文件夹中创建约会项目可能会导致未定义的行为。 在 MFCMAPI 应用程序中使用“添加约会”命令之前,请确保选择了“日历”文件夹。
下面 AddAppointment
列出了 方法。 请注意,传递给 方法的 AddAppointment
lpFolder 参数是指向 IMAPIFolder 接口的指针,该接口表示创建定期约会的文件夹。 给定表示 IMAPIFolder 接口的 lpFolder 参数,代码将调用 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;
}