Доброго времени суток всем!
Мне пришлось столкнуться с этой задачей на работе во время написания плагина к Outlook 2003
В процессе выяснилось, что все E-Mail адреса по имени из Глобального списка адресов (GAL) MS Exchange вытащить не так то просто.
Поковыряв интернет, смог найти только получение одного адреса SMPT по умолчанию, написанное на C#. Вооружившись энтузиазмом и интересом я немного переделал этот код под свои нужды (чтобы он выдавал все адреса).
Итак, для начала нам понадобится импотрировать MAPIшные функции:
После всех приготовлений, напишем функцию, которая будет принимать на вход MAPI объект из AddressEntry
(этот интерфейс есть в пространстве имен Microsoft.Office.Interop.Outlook и как его вытащить GAL можно найти в инете, либо это будет отдельная статья)
Заметьте, что при компилировании данного кода надо поставить галочку Allow Unsafe Code в настройках компилятора.
Сама функция:
Это моя первая в жизни статья, так что сильно не бейте :)
Спасибо за внимание.
Мне пришлось столкнуться с этой задачей на работе во время написания плагина к Outlook 2003
В процессе выяснилось, что все E-Mail адреса по имени из Глобального списка адресов (GAL) MS Exchange вытащить не так то просто.
Поковыряв интернет, смог найти только получение одного адреса SMPT по умолчанию, написанное на C#. Вооружившись энтузиазмом и интересом я немного переделал этот код под свои нужды (чтобы он выдавал все адреса).
Итак, для начала нам понадобится импотрировать MAPIшные функции:
- [DllImport("MAPI32.DLL", CharSet = CharSet.Ansi, EntryPoint = "HrGetOneProp@12")]
- private static extern void HrGetOneProp(IntPtr pmp, uint ulPropTag, out IntPtr ppProp);
- /* Это нам не пригодится, но на всякий напишу */
- [DllImport("MAPI32.DLL", CharSet = CharSet.Ansi, EntryPoint = "HrSetOneProp@8")]
- private static extern void HrSetOneProp(IntPtr pmp, IntPtr pprop);
-
- [DllImport("MAPI32.DLL", CharSet = CharSet.Ansi, EntryPoint = "MAPIFreeBuffer@4")]
- private static extern void MAPIFreeBuffer(IntPtr lpBuffer);
-
- [DllImport("MAPI32.DLL", CharSet = CharSet.Ansi)]
- private static extern int MAPIInitialize(IntPtr lpMapiInit);
-
- [DllImport("MAPI32.DLL", CharSet = CharSet.Ansi)]
- private static extern void MAPIUninitialize();
-
- private const uint PR_EMS_AB_PROXY_ADDRESSES = 0x800F101F; //код свойства, которое нам надо вытащить
-
- private const long mask = 0x00000000FFFFFFFF;
- //нужна для того, чтобы отделить потом количество строк в массиве результата от указателя на начало массива
-
- //Структура, указатель на которую нам вернет функция HrGetOneProp()
- private struct SPropValue
- {
- public uint ulPropTag;
- public uint dwAlignPad;
- public long Value;
- }
После всех приготовлений, напишем функцию, которая будет принимать на вход MAPI объект из AddressEntry
(этот интерфейс есть в пространстве имен Microsoft.Office.Interop.Outlook и как его вытащить GAL можно найти в инете, либо это будет отдельная статья)
Заметьте, что при компилировании данного кода надо поставить галочку Allow Unsafe Code в настройках компилятора.
Сама функция:
- private static unsafe string[] GetMapiProperty(AddressEntry olAddress)
- {
- if (olAddress == null) return null;
- //вытаскиваем из переданного интерфейса МАПИ объект
- var oMapiObject = olAddress.MAPIOBJECT;
- string[] retval = null;
- IntPtr pPropValue = IntPtr.Zero; //указатель на структуру SPropValue
- IntPtr pIUnknown = IntPtr.Zero; //Указатель на IUnknown интерфейс
- IntPtr imapiProperty = IntPtr.Zero; //Указатель на свойство интерфейса
-
- try
- {
- //инициализируем МАПИ
- MAPIInitialize(IntPtr.Zero);
- //Запрашиваем интерфейс для нашего объекта
- pIUnknown = Marshal.GetIUnknownForObject(oMapiObject);
- //Просим указатель на свойство
- var guidMapiProp = new Guid(0x00020303, 0, 0, 0xC0, 0, 0, 0, 0, 0, 0, 0x46);
- if (Marshal.QueryInterface(pIUnknown, ref guidMapiProp, out imapiProperty) != 0) return null;
-
- try
- {
- // и если все ок, то вытаскиваем указатель на значения свойства
- HrGetOneProp(imapiProperty, PR_EMS_AB_PROXY_ADDRESSES, out pPropValue);
-
- if (pPropValue == IntPtr.Zero) return null;
- //берем из памяти структуру по указателю
- var propValue =
- (SPropValue) Marshal.PtrToStructure(pPropValue, typeof (SPropValue));
- //propValue.Value содержит 64-битное целое, первая половина которого
- //указатель, а вторая число E-mail'ов в массиве
- // поэтому надо отделить одно от другого
- var adrcnt = propValue.Value & mask;
- var adrptr = new IntPtr((propValue.Value | mask) >> 32);
- retval = new string[adrcnt];
- //пробегаем по всем строкам и суем их в результирующий массив
- for (int i = 0; i < adrcnt; i++)
- {
- //читаем указатель на строку. i * sizeof(IntPtr) - смещение
- var strptr = Marshal.ReadIntPtr(adrptr, i*sizeof (IntPtr));
- //Вытаскиваем строку по адресу (из МСДН узнал, что они юникодные)
- var email = Marshal.PtrToStringUni(strptr);
-
- if (email != null) retval[i] = email;
- }
- }
- catch (Exception ex)
- {
- throw ex; //тут можно поставить обработчик по вкусу...
- }
- }
- finally
- {
- //после всех манипуляций чистим за собой
- if (pPropValue != IntPtr.Zero)
- {
- MAPIFreeBuffer(pPropValue);
- }
-
- if (imapiProperty != IntPtr.Zero)
- {
- Marshal.Release(imapiProperty);
- }
-
- if (pIUnknown != IntPtr.Zero)
- {
- Marshal.Release(pIUnknown);
- }
- MAPIUninitialize();
- }
-
- return retval;
- }
Это моя первая в жизни статья, так что сильно не бейте :)
Спасибо за внимание.