Merge with default sync
authorThomas
Mon, 25 Mar 2019 13:27:16 +0100
branchsync
changeset 2610 09fde2338362
parent 2594 b4351ec5c330 (current diff)
parent 2607 8a9eddf5347a (diff)
child 2613 9b7775c64b39
Merge with default
ThisAddIn.cs
--- a/Extensions/MailItemExtensions.cs	Tue Mar 05 14:45:53 2019 +0100
+++ b/Extensions/MailItemExtensions.cs	Mon Mar 25 13:27:16 2019 +0100
@@ -367,214 +367,228 @@
             Outlook.MailItem mirror = null;
             Outlook.Folder folder = omi.GetMirrorFolder();
 
-            /* If S/MIME is enabled by default, the mirror creation by new mail item fails during the
-             * Save() method. 
-             */
-            if ((Globals.ThisAddIn.OutlookOptions.IsSMIMEEnabled == false) &&
-                (omi.GetIsSMIMEEnabled() == false))
+            try
             {
+                Log.Verbose("CreateMirrorOMI: Creating by new mail item.");
+
+                // Try to create the new mail item directly in the pEp store
+                Outlook.Application application = null;
+                try
+                {
+                    mirror = (Outlook.MailItem)folder.Items.Add(Outlook.OlItemType.olMailItem);
+                }
+                catch (Exception ex)
+                {
+                    // If this fails, log the error and try to create the item with backup method
+                    Log.Warning("CreateMirrorOMI: Error creating mirror via Items.ItemAdd. " + ex.ToString());
+
+                    // If backup fails, let error get thrown out to outer catch
+                    application = Globals.ThisAddIn.Application;
+                    mirror = application.CreateItem(Outlook.OlItemType.olMailItem);
+                    Log.Verbose("CreateMirrorOMI: mail item successfully created via backup method 1.");
+                }
+                finally
+                {
+                    application = null;
+                }
+
+                // Set the mirror as read
+                mirror.UnRead = false;
+
+                try
+                {
+                    MapiHelper.SetProperty(mirror, MapiProperty.PidTagMessageDeliveryTime, omi.ReceivedTime.ToUniversalTime());
+                    MapiHelper.SetProperty(mirror, MapiProperty.PidTagClientSubmitTime, omi.SentOn.ToUniversalTime());
+                }
+                catch (Exception ex)
+                {
+                    Log.Verbose("CreateMirrorOMI: Failed to set received and sent time. " + ex.ToString());
+                    throw;
+                }
+
+                // Attempt to set sender information
+                try
+                {
+                    mirror.Sender = omi.Sender;
+                }
+                catch (Exception ex)
+                {
+                    Log.Verbose("CreateMirrorOMI: Failed to set sender directly. " + ex.ToString());
+                }
+
+                try
+                {
+                    MapiHelper.SetProperty(mirror, MapiProperty.PidTagSenderName, omi.SenderName);
+                    MapiHelper.SetProperty(mirror, MapiProperty.PidTagSenderEmailAddress, omi.SenderEmailAddress);
+
+                    // Entry ID is needed to resolve the sender so a reply is possible without having to re-enter address, this is last in case it fails
+                    MapiHelper.SetProperty(mirror, MapiProperty.PidTagSenderEntryId, MapiHelper.GetProperty(omi, MapiProperty.PidTagSenderEntryId));
+                }
+                catch (Exception ex)
+                {
+                    Log.Verbose("CreateMirrorOMI: Failed to set sender through MAPI properties. " + ex.ToString());
+                    throw;
+                }
+
+                try
+                {
+                    mirror.SendUsingAccount = omi.SendUsingAccount;
+                }
+                catch (Exception ex)
+                {
+                    Log.Verbose("CreateMirrorOMI: Failed to set SendUsingAccount. " + ex.ToString());
+                }
+
+                // Set flags
+                messageFlags = (System.Int32)MapiHelper.GetProperty(mirror, MapiProperty.PidTagMessageFlags);
+                messageFlags &= ~((System.Int32)MapiPropertyValue.EnumPidTagMessageFlags.mfUnsent);  // Clear UNSENT flag -- must be done before save
+                messageFlags |= ((System.Int32)MapiPropertyValue.EnumPidTagMessageFlags.mfRead);     // Mark as read
                 try
                 {
-                    Log.Verbose("CreateMirrorOMI: Creating by new mail item.");
-
-                    mirror = (Outlook.MailItem)folder.Items.Add(Outlook.OlItemType.olMailItem);
-                    mirror.UnRead = false;
-
-                    // Set received and sent time
-                    try
-                    {
-                        MapiHelper.SetProperty(mirror, MapiProperty.PidTagMessageDeliveryTime, omi.ReceivedTime.ToUniversalTime());
-                        MapiHelper.SetProperty(mirror, MapiProperty.PidTagClientSubmitTime, omi.SentOn.ToUniversalTime());
-                    }
-                    catch (Exception ex)
-                    {
-                        Log.Verbose("CreateMirrorOMI: Failed to set received and sent time. " + ex.ToString());
-                        throw;
-                    }
-
-                    // Attempt to set sender information
-                    try
-                    {
-                        mirror.Sender = omi.Sender;
-                    }
-                    catch (Exception ex)
-                    {
-                        Log.Verbose("CreateMirrorOMI: Failed to set sender directly. " + ex.ToString());
-                    }
-
-                    try
-                    {
-                        MapiHelper.SetProperty(mirror, MapiProperty.PidTagSenderName, omi.SenderName);
-                        MapiHelper.SetProperty(mirror, MapiProperty.PidTagSenderEmailAddress, omi.SenderEmailAddress);
-
-                        // Entry ID is needed to resolve the sender so a reply is possible without having to re-enter address, this is last in case it fails
-                        MapiHelper.SetProperty(mirror, MapiProperty.PidTagSenderEntryId, MapiHelper.GetProperty(omi, MapiProperty.PidTagSenderEntryId));
-                    }
-                    catch (Exception ex)
+                    MapiHelper.SetProperty(mirror, MapiProperty.PidTagMessageFlags, messageFlags);
+                }
+                catch (Exception ex)
+                {
+                    Log.Verbose("CreateMirrorOMI: Failed to set message flags. " + ex.ToString());
+                }
+
+                // Conversation information
+                try
+                {
+                    /* Note: PidTagConversationId cannot be set even through the MAPI accessor.
+                     * This is by design since this property is computed automatically from other properties.
+                     * See: https://msdn.microsoft.com/en-us/library/ee204279.aspx
+                     */
+
+                    str = omi.ConversationIndex;
+                    bytes = MapiHelper.StringToPtypBinary(str);
+                    if (bytes?.Length > 0)
                     {
-                        Log.Verbose("CreateMirrorOMI: Failed to set sender through MAPI properties. " + ex.ToString());
-                        throw;
-                    }
-
-                    try
-                    {
-                        mirror.SendUsingAccount = omi.SendUsingAccount;
+                        MapiHelper.SetProperty(mirror, MapiProperty.PidTagConversationIndex, bytes);
                     }
-                    catch (Exception ex)
-                    {
-                        Log.Verbose("CreateMirrorOMI: Failed to set SendUsingAccount. " + ex.ToString());
-                    }
-
-                    // Set flags
-                    messageFlags = (System.Int32)MapiHelper.GetProperty(mirror, MapiProperty.PidTagMessageFlags);
-                    messageFlags &= ~((System.Int32)MapiPropertyValue.EnumPidTagMessageFlags.mfUnsent);  // Clear UNSENT flag -- must be done before save
-                    messageFlags |= ((System.Int32)MapiPropertyValue.EnumPidTagMessageFlags.mfRead);     // Mark as read
-                    try
+
+                    MapiHelper.SetProperty(mirror, MapiProperty.PidTagConversationIndexTracking, true);
+                    MapiHelper.SetProperty(mirror, MapiProperty.PidTagConversationTopic, omi.ConversationTopic);
+                }
+                catch (Exception ex)
+                {
+                    Log.Verbose("CreateMirrorOMI: Failed to set conversation information. " + ex.ToString());
+                }
+
+                // Remove S/MIME flags if necessary
+                mirror.RemoveSMIMEFlags();
+
+                mirror.To = omi.To;
+                mirror.CC = omi.CC;
+                mirror.BCC = omi.BCC;
+                mirror.Subject = omi.Subject;
+                mirror.Body = string.Empty;
+                mirror.Save();
+
+                /* Set all received-by information
+                 * 
+                 * This must be stored as a user-property because settings MAPI properties such as "PR_RECEIVED_BY_EMAIL_ADDRESS"
+                 * is not supported by Outlook. The user-properties are named the same as the MAPI property for simplicity.
+                 * 
+                 * In most situations the received-by information will not be needed.
+                 * Decryption for example uses the recipients/identities in the original mail item itself.
+                 * However, the GetMyIdentity(omi) method requires this information in some cases:
+                 *  • The true 'myself' identity of a mail item is not an account registerd in Outlook. This can happen
+                 *    using aliases or when forwarding emails from another account.
+                 *  • This is primarily needed when displaying mirrors themselves then opening the handshake dialog.
+                 */
+                try
+                {
+                    /* Get the "received by" email address. In case this returns an internal X500 Exchange address ("/O=DOMAIN/OU=EXCHANGE ADMINISTRATIVE GROUP..."),
+                     * compare it with the recipients' addresses and take the primary SMTP address.
+                     */
+                    string email = MapiHelper.GetProperty(omi, MapiProperty.PidTagReceivedByEmailAddress) as string;
+                    if (email.StartsWith("/O"))
                     {
-                        MapiHelper.SetProperty(mirror, MapiProperty.PidTagMessageFlags, messageFlags);
-                    }
-                    catch (Exception ex)
-                    {
-                        Log.Verbose("CreateMirrorOMI: Failed to set message flags. " + ex.ToString());
-                    }
-
-                    // Conversation information
-                    try
-                    {
-                        /* Note: PidTagConversationId cannot be set even through the MAPI accessor.
-                         * This is by design since this property is computed automatically from other properties.
-                         * See: https://msdn.microsoft.com/en-us/library/ee204279.aspx
-                         */
-
-                        str = omi.ConversationIndex;
-                        bytes = MapiHelper.StringToPtypBinary(str);
-                        if (bytes?.Length > 0)
+                        Outlook.Recipients recipients = null;
+                        Outlook.Recipient recipient = null;
+                        Outlook.AddressEntry addressEntry = null;
+                        Outlook.ExchangeUser exchangeUser = null;
+
+                        try
                         {
-                            MapiHelper.SetProperty(mirror, MapiProperty.PidTagConversationIndex, bytes);
-                        }
-
-                        MapiHelper.SetProperty(mirror, MapiProperty.PidTagConversationIndexTracking, true);
-                        MapiHelper.SetProperty(mirror, MapiProperty.PidTagConversationTopic, omi.ConversationTopic);
-                    }
-                    catch (Exception ex)
-                    {
-                        Log.Verbose("CreateMirrorOMI: Failed to set conversation information. " + ex.ToString());
-                    }
-
-                    // Remove S/MIME flags if necessary
-                    mirror.RemoveSMIMEFlags();
-
-                    mirror.To = omi.To;
-                    mirror.CC = omi.CC;
-                    mirror.BCC = omi.BCC;
-                    mirror.Subject = omi.Subject;
-                    mirror.Body = string.Empty;
-                    mirror.Save();
-
-                    /* Set all received-by information
-                     * 
-                     * This must be stored as a user-property because settings MAPI properties such as "PR_RECEIVED_BY_EMAIL_ADDRESS"
-                     * is not supported by Outlook. The user-properties are named the same as the MAPI property for simplicity.
-                     * 
-                     * In most situations the received-by information will not be needed.
-                     * Decryption for example uses the recipients/identities in the original mail item itself.
-                     * However, the GetMyIdentity(omi) method requires this information in some cases:
-                     *  • The true 'myself' identity of a mail item is not an account registerd in Outlook. This can happen
-                     *    using aliases or when forwarding emails from another account.
-                     *  • This is primarily needed when displaying mirrors themselves then opening the handshake dialog.
-                     */
-                    try
-                    {
-                        /* Get the "received by" email address. In case this returns an internal X500 Exchange address ("/O=DOMAIN/OU=EXCHANGE ADMINISTRATIVE GROUP..."),
-                         * compare it with the recipients' addresses and take the primary SMTP address.
-                         */
-                        string email = MapiHelper.GetProperty(omi, MapiProperty.PidTagReceivedByEmailAddress) as string;
-                        if (email.StartsWith("/O"))
-                        {
-                            Outlook.Recipients recipients = null;
-                            Outlook.Recipient recipient = null;
-                            Outlook.AddressEntry addressEntry = null;
-                            Outlook.ExchangeUser exchangeUser = null;
-
-                            try
+                            recipients = omi.Recipients;
+
+                            for (int i = 1; i <= recipients.Count; i++)
                             {
-                                recipients = omi.Recipients;
-
-                                for (int i = 1; i <= recipients.Count; i++)
+                                recipient = recipients[i];
+                                addressEntry = recipient?.AddressEntry;
+                                exchangeUser = addressEntry?.GetExchangeUser();
+
+                                if (email.ToUpperInvariant().Equals(exchangeUser?.Address?.ToUpperInvariant()))
                                 {
-                                    recipient = recipients[i];
-                                    addressEntry = recipient?.AddressEntry;
-                                    exchangeUser = addressEntry?.GetExchangeUser();
-
-                                    if (email.ToUpperInvariant().Equals(exchangeUser?.Address?.ToUpperInvariant()))
-                                    {
-                                        email = exchangeUser?.PrimarySmtpAddress;
-                                        break;
-                                    }
-
-                                    recipient = null;
-                                    addressEntry = null;
-                                    exchangeUser = null;
+                                    email = exchangeUser?.PrimarySmtpAddress;
+                                    break;
                                 }
-                            }
-                            catch (Exception ex)
-                            {
-                                Log.Error("CreateMirrorOMI: Error getting ReceivedByEmailAddress. " + ex.ToString());
-                            }
-                            finally
-                            {
-                                recipients = null;
+
                                 recipient = null;
                                 addressEntry = null;
                                 exchangeUser = null;
                             }
                         }
-                        mirror.SetUserProperty(MapiProperty.PidTagReceivedByEmailAddress.DaslName, email,
-                                            Outlook.OlUserPropertyType.olText);
-                        mirror.SetUserProperty(MapiProperty.PidTagReceivedByName.DaslName,
-                                            MapiHelper.GetProperty(omi, MapiProperty.PidTagReceivedByName),
-                                            Outlook.OlUserPropertyType.olText);
-                    }
-                    catch (Exception ex)
-                    {
-                        Log.Verbose("CreateMirrorOMI: Failed to set received-by information. " + ex.ToString());
+                        catch (Exception ex)
+                        {
+                            Log.Error("CreateMirrorOMI: Error getting ReceivedByEmailAddress. " + ex.ToString());
+                        }
+                        finally
+                        {
+                            recipients = null;
+                            recipient = null;
+                            addressEntry = null;
+                            exchangeUser = null;
+                        }
                     }
-
-                    // Mark the mail item as a mirror
-                    mirror.SetUserProperty(MailItemExtensions.USER_PROPERTY_KEY_IS_MIRROR, true, Outlook.OlUserPropertyType.olYesNo);
-
-                    /* Set the incoming status of the new mail item.
-                     * This is necessary because manually setting the PR_RECEIVED_BY_ENTRYID fails if called by user code.
-                     * PR_RECEIVED_BY_ENTRYID is only set when copying the original mail item.
-                     */
-                    if (omi.GetIsIncoming())
-                    {
-                        mirror.SetUserProperty(MailItemExtensions.USER_PROPERTY_KEY_IS_INCOMING, true, Outlook.OlUserPropertyType.olYesNo);
-                    }
-                    else
-                    {
-                        mirror.SetUserProperty(MailItemExtensions.USER_PROPERTY_KEY_IS_INCOMING, false, Outlook.OlUserPropertyType.olYesNo);
-                    }
-
-                    // Add the original EntryID or the messageId if the latter has been passed
-                    mirror.SetUserProperty(MailItemExtensions.USER_PROPERTY_KEY_ORIG_ENTRY_ID, messageId ?? omi.EntryID);
-                    mirror.Save();
-
-                    // Move the mirror copy to the correct folder
-                    // This is needed as some account-types/office versions will still create a mail item in the default folder
-                    // even if folder.Items.Add is used to specify a location.
-                    // WARNING: this creates a new mail item that will no longer be referenced here!!
-                    mirror.Move(folder);
-                    created = true;
+                    mirror.SetUserProperty(MapiProperty.PidTagReceivedByEmailAddress.DaslName, email,
+                                        Outlook.OlUserPropertyType.olText);
+                    mirror.SetUserProperty(MapiProperty.PidTagReceivedByName.DaslName,
+                                        MapiHelper.GetProperty(omi, MapiProperty.PidTagReceivedByName),
+                                        Outlook.OlUserPropertyType.olText);
                 }
                 catch (Exception ex)
                 {
-                    Log.Verbose("CreateMirrorOMI: Creating new mail item failed. " + ex.ToString());
-                    mirror.PermanentlyDelete();
-                    mirror = null;
+                    Log.Verbose("CreateMirrorOMI: Failed to set received-by information. " + ex.ToString());
+                }
+
+                // Mark the mail item as a mirror
+                mirror.SetUserProperty(MailItemExtensions.USER_PROPERTY_KEY_IS_MIRROR, true, Outlook.OlUserPropertyType.olYesNo);
+
+                /* Set the incoming status of the new mail item.
+                 * This is necessary because manually setting the PR_RECEIVED_BY_ENTRYID fails if called by user code.
+                 * PR_RECEIVED_BY_ENTRYID is only set when copying the original mail item.
+                 */
+                if (omi.GetIsIncoming())
+                {
+                    mirror.SetUserProperty(MailItemExtensions.USER_PROPERTY_KEY_IS_INCOMING, true, Outlook.OlUserPropertyType.olYesNo);
+                }
+                else
+                {
+                    mirror.SetUserProperty(MailItemExtensions.USER_PROPERTY_KEY_IS_INCOMING, false, Outlook.OlUserPropertyType.olYesNo);
                 }
+
+                // Add the original EntryID or the messageId if the latter has been passed
+                mirror.SetUserProperty(MailItemExtensions.USER_PROPERTY_KEY_ORIG_ENTRY_ID, messageId ?? omi.EntryID);
+                mirror.Save();
+
+                // Move the mirror copy to the correct folder
+                // This is needed as some account-types/office versions will still create a mail item in the default folder
+                // even if folder.Items.Add is used to specify a location.
+                // WARNING: this creates a new mail item that will no longer be referenced here!!
+                mirror.Move(folder);
+                created = true;
             }
-
+            catch (Exception ex)
+            {
+                Log.Verbose("CreateMirrorOMI: Creating new mail item failed. " + ex.ToString());
+                mirror.PermanentlyDelete();
+                mirror = null;
+            }
+
+            // Backup method
             if (created == false)
             {
                 try
--- a/Mapi.cs	Tue Mar 05 14:45:53 2019 +0100
+++ b/Mapi.cs	Mon Mar 25 13:27:16 2019 +0100
@@ -135,7 +135,35 @@
         #region Interfaces
 
         /// <summary>
-        /// Performs operations on the messages and subfolders in a folder..
+        /// Manages high-level operations on container objects such as address books, distribution lists, and folders.
+        /// </summary>
+        [
+            ComImport,
+            ComVisible(false),
+            InterfaceType(ComInterfaceType.InterfaceIsIUnknown),
+            Guid(Mapi.MAPIInterfaceIds.IMAPIContainer)
+        ]
+        internal interface IMAPIContainer : IMAPIProp
+        {
+            [return: MarshalAs(UnmanagedType.I4)]
+            [PreserveSig]
+            int GetContentsTable();
+            [return: MarshalAs(UnmanagedType.I4)]
+            [PreserveSig]
+            int GetHierarchyTable();
+            [return: MarshalAs(UnmanagedType.I4)]
+            [PreserveSig]
+            int OpenEntry(uint cbEntryId, IntPtr entryId, ref Guid iid, uint flags, out IntPtr type, out IntPtr iUnk);
+            [return: MarshalAs(UnmanagedType.I4)]
+            [PreserveSig]
+            int SetSearchCriteria();
+            [return: MarshalAs(UnmanagedType.I4)]
+            [PreserveSig]
+            int GetSearchCriteria();
+        }
+
+        /// <summary>
+        /// Performs operations on the messages and subfolders in a folder.
         /// </summary>
         [
             ComImport,
@@ -143,7 +171,7 @@
             InterfaceType(ComInterfaceType.InterfaceIsIUnknown),
             Guid(Mapi.MAPIInterfaceIds.IMAPIFolder)
         ]
-        internal interface IMAPIFolder
+        internal interface IMAPIFolder : IMAPIContainer
         {
             /// <summary>
             /// Creates a new message.
@@ -158,7 +186,7 @@
             /// <returns>The status of this method.</returns>
             [return: MarshalAs(UnmanagedType.I4)]
             [PreserveSig]
-            int CreateMessage(IntPtr _interface, uint flags, [MarshalAs(UnmanagedType.Interface)] ref IMessage message);
+            int CreateMessage(ref Guid lpiid, uint flags, [MarshalAs(UnmanagedType.Interface)] out IMessage message);
 
             /// <summary>
             /// Copies or moves one or more messages. 
@@ -469,7 +497,7 @@
         /// The IMessage interface defines methods and properties used to manage messages.
         /// </summary>
         [ComImport()]
-        [Guid("00020307-0000-0000-C000-000000000046")]
+        [Guid(Mapi.MAPIInterfaceIds.IMessage)]        
         [InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
         public interface IMessage
         {
@@ -487,7 +515,7 @@
             int GetNamesFromIDs(out IntPtr lppPropTags, ref Guid lpPropSetGuid, uint ulFlags, out uint lpcPropNames, out IntPtr lpppPropNames);
             int GetIDsFromNames(uint cPropNames, ref IntPtr lppPropNames, uint ulFlags, out IntPtr lppPropTags);
             int GetAttachmentTable(uint ulFlags, out IMAPITable lppTable);
-            //int OpenAttach(uint ulAttachmentNum, ref Guid lpInterface, uint ulFlags, out IAttach lppAttach);
+            int OpenAttach(uint ulAttachmentNum, ref Guid lpInterface, uint ulFlags, out IAttach lppAttach);
             int CreateAttach();
             int DeleteAttach();
             int GetRecipientTable(uint ulFlags, out IMAPITable lppTable);
@@ -496,6 +524,12 @@
             int SetReadFlag(uint ulFlags);
         }
 
+        [ComImport()]
+        [Guid(Mapi.MAPIInterfaceIds.IAttachment)]
+        [InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
+        public interface IAttach : IMAPIProp
+        { }
+
         #endregion
 
         #region Structures
@@ -692,6 +726,95 @@
         }
 
         /// <summary>
+        /// Gets an attachment's properties.
+        /// </summary>
+        /// <param name="omi">The Outlook mail item that contains the attachment.</param>
+        /// <param name="index">The attachment's index. 0-based.</param>
+        /// <param name="mapiProperties">The MAPI properties to get its values for.</param>
+        /// <param name="propertyValues">The property values that have been returned.</param>
+        /// <returns>The status (Mapi.HResult) of this method.</returns>
+        public static int GetAttachmentProperties(Outlook.MailItem omi,
+                                                  int index,
+                                                  List<MapiProperty.MapiProp> mapiProperties,
+                                                  out MAPIProperties propertyValues)
+        {
+            int result = (int)Mapi.HResult.S_FALSE;
+            propertyValues = null;
+
+            try
+            {
+                // Get the IMessage interface
+                IMessage iMessage = (IMessage)omi?.MAPIOBJECT;
+                if (iMessage == null)
+                {
+                    throw new Exception("Could not get IMessage interface.");
+                }
+
+                // Open the attachment
+                Guid guid = (typeof(Mapi.IAttach)).GUID;
+                result = iMessage.OpenAttach((uint)index, ref guid, 0, out IAttach attachment);
+
+                // If we can't open the attachment, throw error
+                if (result != 0)
+                {
+                    throw new Exception("Error opening attachment. " + Mapi.GetHResultError(result));
+                }
+
+                // Create the SPropValue structure
+                Mapi.SPropValue sPropValue = new Mapi.SPropValue();
+                int propValueSize = Marshal.SizeOf(sPropValue);
+
+                // Allocate memory for the array of SPropValues to set
+                int propertiesCount = mapiProperties.Count;
+                IntPtr propTagArray = Marshal.AllocHGlobal(propValueSize * propertiesCount);
+
+                // Create the property values array
+                uint[] propertyTags = new uint[propertiesCount + 1];
+                propertyTags[0] = (uint)propertiesCount;
+                for (int i = 0; i < propertiesCount; i++)
+                {
+                    propertyTags[i + 1] = (uint)mapiProperties[i].Tag;
+                }
+
+                // Get properties
+                result = attachment.GetProps(propertyTags, Mapi.MAPI_UNICODE, out uint valuesCount, out IntPtr propArray);
+
+                // If an error occured, just log at this point.
+                if (result != 0)
+                {
+                    Log.Error("OpenAttachment: Error getting attachment properties. " + Mapi.GetHResultError(result));
+                }
+
+                // Convert the retrieved values
+                object[] values = new object[valuesCount];
+                for (int i = 0; i < valuesCount; i++)
+                {
+                    sPropValue = (SPropValue)Marshal.PtrToStructure((propArray + (i * propValueSize)), typeof(SPropValue));
+                    values[i] = Mapi.ConvertSPropValueToObject(mapiProperties[i], sPropValue);
+                }
+
+                // Check if returned values match properties count
+                if (propertiesCount != valuesCount)
+                {
+                    throw new Exception("Properties count doesn't match values count.");
+                }
+
+                // Create return dictionary
+                propertyValues = new MAPIProperties();
+                for (int i = 0; i < valuesCount; i++)
+                {
+                    propertyValues.Add(mapiProperties[i], values[i]);
+                }
+            }
+            catch (Exception ex)
+            {
+                Log.Error("OpenAttachment: Error getting attachment.  " + ex.ToString());
+            }
+
+            return result;
+        }
+
+        /// <summary>
         /// Gets the attachment table of an Outlook mail item.
         /// </summary>
         /// <param name="omi">The Outlook mail item to get its attachment table for.</param>
--- a/Properties/AssemblyInfo.cs	Tue Mar 05 14:45:53 2019 +0100
+++ b/Properties/AssemblyInfo.cs	Mon Mar 25 13:27:16 2019 +0100
@@ -46,5 +46,5 @@
 // You can specify all the values or you can default the Build and Revision Numbers 
 // by using the '*' as shown below:
 // [assembly: AssemblyVersion("1.0.*")]
-[assembly: AssemblyVersion("1.0.209.0")]
-[assembly: AssemblyFileVersion("1.0.209.0")]
+[assembly: AssemblyVersion("1.0.210.0")]
+[assembly: AssemblyFileVersion("1.0.210.0")]
--- a/ThisAddIn.cs	Tue Mar 05 14:45:53 2019 +0100
+++ b/ThisAddIn.cs	Mon Mar 25 13:27:16 2019 +0100
@@ -1547,7 +1547,6 @@
         /// </summary>
         private void OpenPEPStoreRootFolder()
         {
-            string path;
             Outlook.Store pEpStore = null;
             Outlook.Store store = null;
             Outlook.Stores stores = null;
@@ -1555,9 +1554,18 @@
 
             try
             {
+                // The path to store the pEp store to
+                string path = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData), "pEp", (Globals.PEP_DATA_FILE_NAME + ".pst"));
+                
+                /* For Outlook installations from the Windows Trusted Store the AddStoreEx function to add a store seems to
+                 * convert "%LOCALAPPDATA%" to "%LOCALAPPDATA\Packages\Microsoft.Office.Desktop_8wekyb3d8bbwe\LocalCache\Local\".
+                 * This is also confirmed on several sites/blogs. No official documentation has been found so far, though.
+                 * In any case, we also use the above mentioned path to search for the pEp store.
+                 */
+                string winStorePath = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData), "Packages", "Microsoft.Office.Desktop_8wekyb3d8bbwe", "LocalCache", "Local", "pEp", (Globals.PEP_DATA_FILE_NAME + ".pst"));
+
                 ns = this.Application.Session;
                 stores = ns.Stores;
-                path = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData), "pEp", (Globals.PEP_DATA_FILE_NAME + ".pst"));
 
                 // Try to find an existing store based on file name
                 for (int i = 1; i <= stores.Count; i++)
@@ -1576,7 +1584,8 @@
                         Log.Warning("OpenPEPStoreRootFolder: Failed to get store, " + ex.ToString());
                     }
 
-                    if (store?.FilePath == path)
+                    if ((store?.FilePath?.Equals(path) == true) ||
+                        (store?.FilePath?.Equals(winStorePath) == true))
                     {
                         pEpStore = store;
                         break;
@@ -1588,7 +1597,7 @@
                 // If no store was found, create new 
                 if (pEpStore == null)
                 {
-                    /* Will create the file and add it as a store, otherwise it will use the existing one.
+                    /* Create the file and add it as a store, otherwise use the existing one.
                      * This can throw an error if a user either modified the list of Outlook data stores
                      * or the pEp.pst file itself.
                      */
@@ -1616,12 +1625,15 @@
                             Log.Warning("OpenPEPStoreRootFolder: Failed to get store, " + ex.ToString());
                         }
 
-                        if (store?.FilePath == path)
+                        if ((store?.FilePath?.Equals(path) == true) ||
+                            (store?.FilePath?.Equals(winStorePath) == true))
                         {
                             pEpStore = store;
                             pEpStore.GetRootFolder().Name = Globals.PEP_DATA_FILE_NAME;
                             break; // Break before releasing
                         }
+
+                        store = null;
                     }
                 }
 
@@ -1632,14 +1644,14 @@
                 else
                 {
                     // Try again using fallback solution for file paths with prefixes
-                    Log.Warning("OpenPEPStoreRootFolder: No pEp store found. Trying fallback. \npEp path is " + path);
+                    Log.Warning("OpenPEPStoreRootFolder: No pEp store found. Trying fallback. pEp path is " + path);
 
                     for (int i = 1; i <= stores.Count; i++)
                     {
                         try
                         {
                             store = stores[i];
-                            Log.Warning("OpenPEPStoreRootFolder: file path of store " + i + ": " + store?.FilePath ?? "<null>");
+                            Log.Info("OpenPEPStoreRootFolder: file path of store " + i + " (" + (store?.DisplayName ?? "<null>") + "): " + store?.FilePath ?? "<null>");
                         }
                         catch (Exception ex)
                         {
@@ -1647,18 +1659,21 @@
                         }
 
                         // Custom comparison of file paths independently of their (known) prefixes
-                        if (Comparisons.FilePathsAreEqual(store?.FilePath, path))
+                        if (Comparisons.FilePathsAreEqual(store?.FilePath, path) ||
+                            Comparisons.FilePathsAreEqual(store?.FilePath, winStorePath))
                         {
                             pEpStore = store;
                             pEpStore.GetRootFolder().Name = Globals.PEP_DATA_FILE_NAME;
                             break;
                         }
+
+                        store = null;
                     }
 
                     // If pEp store was found, use it. Else throw error.
                     if (pEpStore != null)
                     {
-                        this._PEPStoreRootFolder = (Outlook.Folder)pEpStore.GetRootFolder();
+                        this._PEPStoreRootFolder = pEpStore.GetRootFolder() as Outlook.Folder;
                     }
                     else
                     {
--- a/UI/FormRegionPreviewUnencrypted.cs	Tue Mar 05 14:45:53 2019 +0100
+++ b/UI/FormRegionPreviewUnencrypted.cs	Mon Mar 25 13:27:16 2019 +0100
@@ -21,44 +21,41 @@
             // Use e.OutlookItem to get a reference to the current Outlook item.
             private void FormRegionPreviewUnencryptedFactory_FormRegionInitializing(object sender, Microsoft.Office.Tools.Outlook.FormRegionInitializingEventArgs e)
             {
-                Outlook.MailItem omi;
-
-                try
+                if (e?.OutlookItem is Outlook.MailItem omi)
                 {
-                    omi = (Outlook.MailItem)e.OutlookItem;
+                    // Do not load if the mail item itself is not stored encrypted or pEp is disabled
+                    if ((omi.GetIsSecurelyStored() == false) ||
+                        (omi.GetIsPEPEnabled() == false) && (omi.GetIsDecryptAlwaysEnabled() == false))
+                    {
+                        e.Cancel = true;
+                    }
+                    else if (string.IsNullOrEmpty(CryptableMailItem.PreviewAttachedMailId) == false)
+                    {
+                        HeaderList headers = omi.GetParsedTransportMessageHeaders();
+                        string messageId = null;
+
+                        try
+                        {
+                            messageId = headers[HeaderId.MessageId];
+                        }
+                        catch (Exception ex)
+                        {
+                            Log.Verbose("FormRegionPreviewUnencryptedFactory_FormRegionInitializing: Error getting MessageId from item. " + ex.ToString());
+                        }
+
+                        e.Cancel = (messageId?.Equals(CryptableMailItem.PreviewAttachedMailId) != true);
+                    }
+                    else
+                    {
+                        e.Cancel = false;
+                    }
+
+                    omi = null;
                 }
-                catch
+                else
                 {
                     // Never load if it's not a MailItem
                     e.Cancel = true;
-                    return;
-                }
-
-                // Do not load if the mail item itself is not stored encrypted or pEp is disabled
-                if ((omi.GetIsSecurelyStored() == false) ||
-                    (omi.GetIsPEPEnabled() == false) && (omi.GetIsDecryptAlwaysEnabled() == false))
-                {
-                    e.Cancel = true;
-                }
-                else if (string.IsNullOrEmpty(CryptableMailItem.PreviewAttachedMailId) == false)
-                {
-                    HeaderList headers = omi.GetParsedTransportMessageHeaders();
-                    string messageId = null;
-
-                    try
-                    {
-                        messageId = headers[HeaderId.MessageId];
-                    }
-                    catch (Exception ex)
-                    {
-                        Log.Verbose("FormRegionPreviewUnencryptedFactory_FormRegionInitializing: Error getting MessageId from item. " + ex.ToString());
-                    }
-
-                    e.Cancel = (messageId?.Equals(CryptableMailItem.PreviewAttachedMailId) != true);
-                }
-                else
-                {
-                    e.Cancel = false;
                 }
 
                 Log.Verbose("FormRegionPreviewUnencryptedFactory_FormRegionInitializing: e.Cancel = " + e.Cancel.ToString());
--- a/pEpForOutlook.csproj	Tue Mar 05 14:45:53 2019 +0100
+++ b/pEpForOutlook.csproj	Mon Mar 25 13:27:16 2019 +0100
@@ -44,7 +44,7 @@
     <PublishUrl>publish\</PublishUrl>
     <InstallUrl>https://pep-project.org/</InstallUrl>
     <TargetCulture>en</TargetCulture>
-    <ApplicationVersion>1.0.209.0</ApplicationVersion>
+    <ApplicationVersion>1.0.210.0</ApplicationVersion>
     <AutoIncrementApplicationRevision>true</AutoIncrementApplicationRevision>
     <UpdateEnabled>true</UpdateEnabled>
     <UpdateInterval>0</UpdateInterval>