Чтение и анализ расписания повторения
Область применения: Outlook 2013 | Outlook 2016
MAPI можно использовать для чтения и анализа шаблона повторения для встречи.
Сведения о том, как скачать, просмотреть и запустить код из проекта приложения MFCMAPI, указанного в этом разделе, см. в разделе Установка примеров, используемых в этом разделе.
Синтаксический анализ большого двоичного объекта повторения
Откройте элемент встречи. Сведения об открытии сообщения см. в разделе Открытие сообщения.
Получите именованное свойство dispidApptRecur (каноническое свойство PidLidAppointmentRecur). Сведения о получении именованных свойств см. в разделе Именованные свойства MAPI.
Следуйте указаниям в [MS-OXOCAL], чтобы прочитать структуру шаблона повторения встречи.
Эталонное приложение MFCMAPI демонстрирует последний шаг с BinToAppointmentRecurrencePatternStruct
функцией в InterpretProp2.cpp исходном файле проекта MFCMapi. Функция BinToAppointmentRecurrencePatternStruct
принимает указатель на буфер в памяти в качестве параметра. Приложение MFCMAPI получает этот буфер, сначала сопоставляя именованное свойство dispidApptRecur с тегом свойства, а затем запрашивая значение свойства с помощью метода IMAPIProp::GetProps . Если свойство слишком велико для извлечения с помощью метода GetProps , MFCMAPI открывает интерфейс потока для получения свойства с помощью метода IMAPIProp::OpenProperty . Затем приложение MFCMAPI считывает данные из потока для создания буфера.
Сведения о формате буфера см. в разделе Каноническое свойство PidLidAppointmentRecur. Основная часть данных в буфере состоит из полей с фиксированным числом байтов, которые должны считываться один за другим. Некоторые поля присутствуют только в том случае, если другие поля содержат определенные значения, а размер некоторых полей может зависеть от значения других полей. Анализ буфера для чтения различных полей требует большого объема бухгалтерского учета. MFCMAPI использует внутренний вспомогательный класс с именем CBinaryParser
для инкапсуляции этой бухгалтерии. Например, функция проверяет, CBinaryParser::GetDWORD
достаточно ли байтов в буфере для чтения DWORD, а затем считывает значение и обновляет указатели.
После анализа буфера в структуру приложение MFCMAPI использует AppointmentRecurrencePatternStructToString
функцию для преобразования структуры в строку для отображения пользователю. Это не та строка, которую будет отображать Outlook, но вместо этого является необработанным представлением данных, на которых Outlook строит свою логику.
Можно столкнуться с буфером, который содержит либо поврежденные данные, либо больше данных, чем требуется для кодирования шаблона повторения. Чтобы помочь определить эти сценарии, приложение MFCMAPI отслеживает, сколько данных успешно проанализировано и сколько осталось в буфере. Если данные остаются в буфере после завершения анализа, MFCMAPI включает эти "нежелательные данные" в структуру, чтобы их можно было проверить.
Ниже приведен полный BinToAppointmentRecurrencePatternStruct
список функции.
AppointmentRecurrencePatternStruct* BinToAppointmentRecurrencePatternStruct(ULONG cbBin, LPBYTE lpBin)
{
if (!lpBin) return NULL;
AppointmentRecurrencePatternStruct arpPattern = {0};
CBinaryParser Parser(cbBin,lpBin);
size_t cbBinRead = 0;
arpPattern.RecurrencePattern = BinToRecurrencePatternStruct(cbBin,lpBin,&cbBinRead);
Parser.Advance(cbBinRead);
Parser.GetDWORD(&arpPattern.ReaderVersion2);
Parser.GetDWORD(&arpPattern.WriterVersion2);
Parser.GetDWORD(&arpPattern.StartTimeOffset);
Parser.GetDWORD(&arpPattern.EndTimeOffset);
Parser.GetWORD(&arpPattern.ExceptionCount);
if (arpPattern.ExceptionCount &&
arpPattern.ExceptionCount == arpPattern.RecurrencePattern->ModifiedInstanceCount &&
arpPattern.ExceptionCount < _MaxExceptions)
{
arpPattern.ExceptionInfo = new ExceptionInfoStruct[arpPattern.ExceptionCount];
if (arpPattern.ExceptionInfo)
{
memset(arpPattern.ExceptionInfo,0,sizeof(ExceptionInfoStruct) * arpPattern.ExceptionCount);
WORD i = 0;
for (i = 0 ; i < arpPattern.ExceptionCount ; i++)
{
Parser.GetDWORD(&arpPattern.ExceptionInfo[i].StartDateTime);
Parser.GetDWORD(&arpPattern.ExceptionInfo[i].EndDateTime);
Parser.GetDWORD(&arpPattern.ExceptionInfo[i].OriginalStartDate);
Parser.GetWORD(&arpPattern.ExceptionInfo[i].OverrideFlags);
if (arpPattern.ExceptionInfo[i].OverrideFlags & ARO_SUBJECT)
{
Parser.GetWORD(&arpPattern.ExceptionInfo[i].SubjectLength);
Parser.GetWORD(&arpPattern.ExceptionInfo[i].SubjectLength2);
if (arpPattern.ExceptionInfo[i].SubjectLength2 && arpPattern.ExceptionInfo[i].SubjectLength2 + 1
== arpPattern.ExceptionInfo[i].SubjectLength)
{
Parser.GetStringA(arpPattern.ExceptionInfo[i].SubjectLength2,&arpPattern.ExceptionInfo[i].Subject);
}
}
if (arpPattern.ExceptionInfo[i].OverrideFlags & ARO_MEETINGTYPE)
{
Parser.GetDWORD(&arpPattern.ExceptionInfo[i].MeetingType);
}
if (arpPattern.ExceptionInfo[i].OverrideFlags & ARO_REMINDERDELTA)
{
Parser.GetDWORD(&arpPattern.ExceptionInfo[i].ReminderDelta);
}
if (arpPattern.ExceptionInfo[i].OverrideFlags & ARO_REMINDER)
{
Parser.GetDWORD(&arpPattern.ExceptionInfo[i].ReminderSet);
}
if (arpPattern.ExceptionInfo[i].OverrideFlags & ARO_LOCATION)
{
Parser.GetWORD(&arpPattern.ExceptionInfo[i].LocationLength);
Parser.GetWORD(&arpPattern.ExceptionInfo[i].LocationLength2);
if (arpPattern.ExceptionInfo[i].LocationLength2 && arpPattern.ExceptionInfo[i].LocationLength2
+ 1 == arpPattern.ExceptionInfo[i].LocationLength)
{
Parser.GetStringA(arpPattern.ExceptionInfo[i].LocationLength2,&arpPattern.ExceptionInfo[i].Location);
}
}
if (arpPattern.ExceptionInfo[i].OverrideFlags & ARO_BUSYSTATUS)
{
Parser.GetDWORD(&arpPattern.ExceptionInfo[i].BusyStatus);
}
if (arpPattern.ExceptionInfo[i].OverrideFlags & ARO_ATTACHMENT)
{
Parser.GetDWORD(&arpPattern.ExceptionInfo[i].Attachment);
}
if (arpPattern.ExceptionInfo[i].OverrideFlags & ARO_SUBTYPE)
{
Parser.GetDWORD(&arpPattern.ExceptionInfo[i].SubType);
}
if (arpPattern.ExceptionInfo[i].OverrideFlags & ARO_APPTCOLOR)
{
Parser.GetDWORD(&arpPattern.ExceptionInfo[i].AppointmentColor);
}
}
}
}
Parser.GetDWORD(&arpPattern.ReservedBlock1Size);
if (arpPattern.ReservedBlock1Size && arpPattern.ReservedBlock1Size < _MaxReservedBlock)
{
Parser.GetBYTES(arpPattern.ReservedBlock1Size,&arpPattern.ReservedBlock1);
}
if (arpPattern.ExceptionCount &&
arpPattern.ExceptionCount == arpPattern.RecurrencePattern->ModifiedInstanceCount &&
arpPattern.ExceptionCount < _MaxExceptions &&
arpPattern.ExceptionInfo)
{
arpPattern.ExtendedException = new ExtendedExceptionStruct[arpPattern.ExceptionCount];
if (arpPattern.ExtendedException)
{
memset(arpPattern.ExtendedException,0,sizeof(ExtendedExceptionStruct) * arpPattern.ExceptionCount);
WORD i = 0;
for (i = 0 ; i < arpPattern.ExceptionCount ; i++)
{
if (arpPattern.WriterVersion2 >= 0x0003009)
{
Parser.GetDWORD(&arpPattern.ExtendedException[i].ChangeHighlight.ChangeHighlightSize);
Parser.GetDWORD(&arpPattern.ExtendedException[i].ChangeHighlight.ChangeHighlightValue);
if (arpPattern.ExtendedException[i].ChangeHighlight.ChangeHighlightSize > sizeof(DWORD))
{
Parser.GetBYTES(arpPattern.ExtendedException[i].ChangeHighlight.ChangeHighlightSize
- sizeof(DWORD),&arpPattern.ExtendedException[i].ChangeHighlight.Reserved);
}
}
Parser.GetDWORD(&arpPattern.ExtendedException[i].ReservedBlockEE1Size);
if (arpPattern.ExtendedException[i].ReservedBlockEE1Size &&
arpPattern.ExtendedException[i].ReservedBlockEE1Size < _MaxReservedBlock)
{
Parser.GetBYTES(arpPattern.ExtendedException[i].ReservedBlockEE1Size,&arpPattern.ExtendedException[i].ReservedBlockEE1);
}
if (arpPattern.ExceptionInfo[i].OverrideFlags & ARO_SUBJECT ||
arpPattern.ExceptionInfo[i].OverrideFlags & ARO_LOCATION)
{
Parser.GetDWORD(&arpPattern.ExtendedException[i].StartDateTime);
Parser.GetDWORD(&arpPattern.ExtendedException[i].EndDateTime);
Parser.GetDWORD(&arpPattern.ExtendedException[i].OriginalStartDate);
}
if (arpPattern.ExceptionInfo[i].OverrideFlags & ARO_SUBJECT)
{
Parser.GetWORD(&arpPattern.ExtendedException[i].WideCharSubjectLength);
if (arpPattern.ExtendedException[i].WideCharSubjectLength)
{
Parser.GetStringW(arpPattern.ExtendedException[i].WideCharSubjectLength,&arpPattern.ExtendedException[i].WideCharSubject);
}
}
if (arpPattern.ExceptionInfo[i].OverrideFlags & ARO_LOCATION)
{
Parser.GetWORD(&arpPattern.ExtendedException[i].WideCharLocationLength);
if (arpPattern.ExtendedException[i].WideCharLocationLength)
{
Parser.GetStringW(arpPattern.ExtendedException[i].WideCharLocationLength,&arpPattern.ExtendedException[i].WideCharLocation);
}
}
if (arpPattern.ExceptionInfo[i].OverrideFlags & ARO_SUBJECT ||
arpPattern.ExceptionInfo[i].OverrideFlags & ARO_LOCATION)
{
Parser.GetDWORD(&arpPattern.ExtendedException[i].ReservedBlockEE2Size);
if (arpPattern.ExtendedException[i].ReservedBlockEE2Size && arpPattern.ExtendedException[i].ReservedBlockEE2Size < _MaxReservedBlock)
{
Parser.GetBYTES(arpPattern.ExtendedException[i].ReservedBlockEE2Size,&arpPattern.ExtendedException[i].ReservedBlockEE2);
}
}
}
}
}
Parser.GetDWORD(&arpPattern.ReservedBlock2Size);
if (arpPattern.ReservedBlock2Size && arpPattern.ReservedBlock2Size < _MaxReservedBlock)
{
Parser.GetBYTES(arpPattern.ReservedBlock2Size,&arpPattern.ReservedBlock2);
}
// Junk data remains.
if (Parser.RemainingBytes() > 0)
{
arpPattern.JunkDataSize = Parser.RemainingBytes();
Parser.GetBYTES(arpPattern.JunkDataSize,&arpPattern.JunkData);
}
AppointmentRecurrencePatternStruct* parpPattern = new AppointmentRecurrencePatternStruct;
if (parpPattern)
{
*parpPattern = arpPattern;
}
return parpPattern;
}