From 06c691cf898919ef48630dedc564344c72729b14 Mon Sep 17 00:00:00 2001 From: RKrom Date: Thu, 8 Nov 2012 11:29:43 +0000 Subject: [PATCH] Cleanup, before branching: Moved interop assemblies from the GreenshotInterop to this project git-svn-id: http://svn.code.sf.net/p/greenshot/code/trunk@2249 7dccd23d-a4a3-4e1f-8c07-b4c1b4018ab4 --- .../GreenshotOfficePlugin.csproj | 48 +- .../OfficeExport/ExcelExporter.cs | 88 ++ .../OfficeExport/OneNoteExporter.cs | 100 ++ .../OfficeExport/OutlookEmailExporter.cs | 520 +++++++++++ .../OfficeExport/PowerpointExporter.cs | 185 ++++ .../OfficeExport/WordExporter.cs | 148 +++ .../OfficeInterop/ExcelInterop.cs | 64 ++ .../OfficeInterop/OfficeCommunicator.cs | 71 ++ .../OfficeInterop/OfficeInterop.cs | 31 + .../OfficeInterop/OneNoteInterop.cs | 59 ++ .../OfficeInterop/OutlookInterop.cs | 465 ++++++++++ .../OfficeInterop/OutlookUtils.cs | 853 ++++++++++++++++++ .../OfficeInterop/PowerpointInterop.cs | 149 +++ .../OfficeInterop/WordInterop.cs | 84 ++ 14 files changed, 2829 insertions(+), 36 deletions(-) create mode 100644 GreenshotOfficePlugin/OfficeExport/ExcelExporter.cs create mode 100644 GreenshotOfficePlugin/OfficeExport/OneNoteExporter.cs create mode 100644 GreenshotOfficePlugin/OfficeExport/OutlookEmailExporter.cs create mode 100644 GreenshotOfficePlugin/OfficeExport/PowerpointExporter.cs create mode 100644 GreenshotOfficePlugin/OfficeExport/WordExporter.cs create mode 100644 GreenshotOfficePlugin/OfficeInterop/ExcelInterop.cs create mode 100644 GreenshotOfficePlugin/OfficeInterop/OfficeCommunicator.cs create mode 100644 GreenshotOfficePlugin/OfficeInterop/OfficeInterop.cs create mode 100644 GreenshotOfficePlugin/OfficeInterop/OneNoteInterop.cs create mode 100644 GreenshotOfficePlugin/OfficeInterop/OutlookInterop.cs create mode 100644 GreenshotOfficePlugin/OfficeInterop/OutlookUtils.cs create mode 100644 GreenshotOfficePlugin/OfficeInterop/PowerpointInterop.cs create mode 100644 GreenshotOfficePlugin/OfficeInterop/WordInterop.cs diff --git a/GreenshotOfficePlugin/GreenshotOfficePlugin.csproj b/GreenshotOfficePlugin/GreenshotOfficePlugin.csproj index fa23955ce..bc7dfc6fa 100644 --- a/GreenshotOfficePlugin/GreenshotOfficePlugin.csproj +++ b/GreenshotOfficePlugin/GreenshotOfficePlugin.csproj @@ -57,42 +57,18 @@ - - Interop\ExcelExporter.cs - - - Interop\OneNoteExporter.cs - - - Interop\OutlookEmailExporter.cs - - - Interop\PowerpointExporter.cs - - - Interop\WordExporter.cs - - - Interop\ExcelInterop.cs - - - Interop\OfficeInterop.cs - - - Interop\OneNoteInterop.cs - - - Interop\OutlookInterop.cs - - - Interop\OutlookUtils.cs - - - Interop\PowerpointInterop.cs - - - Interop\WordInterop.cs - + + + + + + + + + + + + diff --git a/GreenshotOfficePlugin/OfficeExport/ExcelExporter.cs b/GreenshotOfficePlugin/OfficeExport/ExcelExporter.cs new file mode 100644 index 000000000..d9e077df0 --- /dev/null +++ b/GreenshotOfficePlugin/OfficeExport/ExcelExporter.cs @@ -0,0 +1,88 @@ +/* + * Greenshot - a free and open source screenshot tool + * Copyright (C) 2007-2012 Thomas Braun, Jens Klingen, Robin Krom + * + * For more information see: http://getgreenshot.org/ + * The Greenshot project is hosted on Sourceforge: http://sourceforge.net/projects/greenshot/ + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 1 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +using System; +using System.Collections.Generic; +using System.Text; +using System.Reflection; + +using Greenshot.Interop; + +namespace Greenshot.Interop.Office { + public class ExcelExporter { + private static readonly log4net.ILog LOG = log4net.LogManager.GetLogger(typeof(ExcelExporter)); + + public static List GetWorkbooks() { + List currentWorkbooks = new List(); + using (IExcelApplication excelApplication = COMWrapper.GetInstance()) { + if (excelApplication != null) { + for (int i = 1; i <= excelApplication.Workbooks.Count; i++) { + IWorkbook workbook = excelApplication.Workbooks[i]; + if (workbook != null) { + currentWorkbooks.Add(workbook.Name); + } + } + } + } + return currentWorkbooks; + } + + /// + /// Insert image from supplied tmp file into the give excel workbook + /// + /// + /// + public static void InsertIntoExistingWorkbook(string workbookName, string tmpFile) { + using (IExcelApplication excelApplication = COMWrapper.GetInstance()) { + if (excelApplication != null) { + for (int i = 1; i <= excelApplication.Workbooks.Count; i++) { + IWorkbook workbook = excelApplication.Workbooks[i]; + if (workbook != null && workbook.Name.StartsWith(workbookName)) { + InsertIntoExistingWorkbook(workbook, tmpFile); + } + } + } + } + } + + private static void InsertIntoExistingWorkbook(IWorkbook workbook, string tmpFile) { + IWorksheet sheet = workbook.ActiveSheet; + if (sheet != null) { + if (sheet.Pictures != null) { + sheet.Pictures.Insert(tmpFile); + } + } else { + LOG.Error("No pictures found"); + } + } + + public static void InsertIntoNewWorkbook(string tmpFile) { + using (IExcelApplication excelApplication = COMWrapper.GetOrCreateInstance()) { + if (excelApplication != null) { + excelApplication.Visible = true; + object template = Missing.Value; + IWorkbook workbook = excelApplication.Workbooks.Add(template); + InsertIntoExistingWorkbook(workbook, tmpFile); + } + } + } + } + +} diff --git a/GreenshotOfficePlugin/OfficeExport/OneNoteExporter.cs b/GreenshotOfficePlugin/OfficeExport/OneNoteExporter.cs new file mode 100644 index 000000000..6a6f14e0e --- /dev/null +++ b/GreenshotOfficePlugin/OfficeExport/OneNoteExporter.cs @@ -0,0 +1,100 @@ +/* + * Greenshot - a free and open source screenshot tool + * Copyright (C) 2007-2012 Thomas Braun, Jens Klingen, Robin Krom + * + * For more information see: http://getgreenshot.org/ + * The Greenshot project is hosted on Sourceforge: http://sourceforge.net/projects/greenshot/ + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 1 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +using System; +using System.Collections.Generic; +using System.Text; + +using Greenshot.Interop; +using System.Reflection; +using System.Xml; +using System.IO; +using System.Drawing; +using System.Drawing.Imaging; +using Greenshot.Plugin; +using GreenshotPlugin.Core; + +namespace Greenshot.Interop.Office { + public class OneNotePage { + public string PageName { get; set; } + public string PageID { get; set; } + } + public class OneNoteExporter { + private static readonly log4net.ILog LOG = log4net.LogManager.GetLogger(typeof(OneNoteExporter)); + private const string XML_IMAGE_CONTENT = "{0}"; + private const string XML_OUTLINE = "{0}"; + private const string ONENOTE_NAMESPACE_2007 = "http://schemas.microsoft.com/office/onenote/2007/onenote"; + private const string ONENOTE_NAMESPACE_2010 = "http://schemas.microsoft.com/office/onenote/2010/onenote"; + + public static void ExportToPage(Bitmap imageToExport, OneNotePage page) { + using (MemoryStream pngStream = new MemoryStream()) { + OutputSettings pngOutputSettings = new OutputSettings(OutputFormat.png, 100, false); + ImageOutput.SaveToStream(imageToExport, pngStream, pngOutputSettings); + string base64String = Convert.ToBase64String(pngStream.GetBuffer()); + string imageXmlStr = string.Format(XML_IMAGE_CONTENT, base64String, imageToExport.Width, imageToExport.Height); + string pageChangesXml = string.Format(XML_OUTLINE, new object[] { imageXmlStr, page.PageID, ONENOTE_NAMESPACE_2010, page.PageName }); + using (IOneNoteApplication oneNoteApplication = COMWrapper.GetOrCreateInstance()) { + LOG.InfoFormat("Sending XML: {0}", pageChangesXml); + oneNoteApplication.UpdatePageContent(pageChangesXml, DateTime.MinValue, XMLSchema.xs2010, false); + } + } + } + + /// + /// Get the captions of all the open word documents + /// + /// + public static List GetPages() { + List pages = new List(); + try { + using (IOneNoteApplication oneNoteApplication = COMWrapper.GetOrCreateInstance()) { + if (oneNoteApplication != null) { + string notebookXml = ""; + oneNoteApplication.GetHierarchy("", HierarchyScope.hsPages, out notebookXml, XMLSchema.xs2010); + if (!string.IsNullOrEmpty(notebookXml)) { + LOG.Debug(notebookXml); + using (StringReader reader = new StringReader(notebookXml)) { + using (XmlTextReader xmlReader = new XmlTextReader(reader)) { + while (xmlReader.Read()) { + if ("one:Page".Equals(xmlReader.Name)) { + if ("true".Equals(xmlReader.GetAttribute("isCurrentlyViewed"))) { + OneNotePage page = new OneNotePage(); + page.PageName = xmlReader.GetAttribute("name"); + page.PageID = xmlReader.GetAttribute("ID"); + pages.Add(page); + // For debugging + //string pageXml = ""; + //oneNoteApplication.GetPageContent(page.PageID, out pageXml, PageInfo.piAll, XMLSchema.xs2010); + //LOG.DebugFormat("Page XML: {0}", pageXml); + } + } + } + } + } + } + } + } + } catch (Exception ex) { + LOG.Warn("Problem retrieving onenote destinations, ignoring: ", ex); + } + return pages; + } + } +} diff --git a/GreenshotOfficePlugin/OfficeExport/OutlookEmailExporter.cs b/GreenshotOfficePlugin/OfficeExport/OutlookEmailExporter.cs new file mode 100644 index 000000000..1004ea439 --- /dev/null +++ b/GreenshotOfficePlugin/OfficeExport/OutlookEmailExporter.cs @@ -0,0 +1,520 @@ +/* + * Greenshot - a free and open source screenshot tool + * Copyright (C) 2007-2012 Thomas Braun, Jens Klingen, Robin Krom + * + * For more information see: http://getgreenshot.org/ + * The Greenshot project is hosted on Sourceforge: http://sourceforge.net/projects/greenshot/ + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 1 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +using System; +using System.Collections.Generic; +using System.Text; +using System.IO; + +using Microsoft.Win32; + +using Greenshot.Interop; +using Greenshot.Interop.IE; +using System.Threading; + +namespace Greenshot.Interop.Office { + /// + /// Outlook exporter has all the functionality to export to outlook + /// + public class OutlookEmailExporter { + private static readonly log4net.ILog LOG = log4net.LogManager.GetLogger(typeof(OutlookEmailExporter)); + private static readonly string SIGNATURE_PATH = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData), @"Microsoft\Signatures"); + private static Version outlookVersion = null; + private static string currentUser = null; + private const int OUTLOOK_2003 = 11; + private const int OUTLOOK_2007 = 12; + private const int OUTLOOK_2010 = 14; + + // The signature key can be found at: + // HKEY_CURRENT_USER\Software\Microsoft\Windows NT\CurrentVersion\Windows Messaging Subsystem\Profiles\\9375CFF0413111d3B88A00104B2A6676\ [New Signature] + private const string PROFILES_KEY = @"Software\Microsoft\Windows NT\CurrentVersion\Windows Messaging Subsystem\Profiles\"; + private const string ACCOUNT_KEY = "9375CFF0413111d3B88A00104B2A6676"; + private const string NEW_SIGNATURE_VALUE = "New Signature"; + private const string DEFAULT_PROFILE_VALUE = "DefaultProfile"; + + /// + /// A method to retrieve all inspectors which can act as an export target + /// + /// bool true if also exporting to meetings + /// List with inspector captions (window title) + public static Dictionary RetrievePossibleTargets(bool allowMeetingAsTarget) { + Dictionary inspectorCaptions = new Dictionary(); + try { + using (IOutlookApplication outlookApplication = GetOutlookApplication()) { + if (outlookApplication == null) { + return null; + } + + using (Inspectors inspectors = outlookApplication.Inspectors) { + if (inspectors != null && inspectors.Count > 0) { + for (int i = 1; i <= inspectors.Count; i++) { + using (Inspector inspector = outlookApplication.Inspectors[i]) { + string inspectorCaption = inspector.Caption; + using (Item currentItem = inspector.CurrentItem) { + if (canExportToInspector(currentItem, allowMeetingAsTarget)) { + OlObjectClass currentItemClass = currentItem.Class; + inspectorCaptions.Add(inspector.Caption, currentItemClass); + } + } + } + } + } + } + } + } catch (Exception ex) { + LOG.Warn("Problem retrieving word destinations, ignoring: ", ex); + } + return inspectorCaptions; + } + + /// + /// Return true if we can export to the supplied inspector + /// + /// the Item to check + /// bool true if also exporting to meetings + /// + private static bool canExportToInspector(Item currentItem, bool allowMeetingAsTarget) { + try { + if (currentItem != null) { + OlObjectClass currentItemClass = currentItem.Class; + if (OlObjectClass.olMail.Equals(currentItemClass)) { + MailItem mailItem = (MailItem)currentItem; + //MailItem mailItem = COMWrapper.Cast(currentItem); + LOG.DebugFormat("Mail sent: {0}", mailItem.Sent); + if (!mailItem.Sent) { + return true; + } + } else if (outlookVersion.Major >= OUTLOOK_2010 && allowMeetingAsTarget && OlObjectClass.olAppointment.Equals(currentItemClass)) { + //AppointmentItem appointmentItem = COMWrapper.Cast(currentItem); + AppointmentItem appointmentItem = (AppointmentItem)currentItem; + if (string.IsNullOrEmpty(appointmentItem.Organizer) || (currentUser != null && currentUser.Equals(appointmentItem.Organizer))) { + return true; + } else { + LOG.DebugFormat("Not exporting, as organizer is {1} and currentuser {2}", appointmentItem.Organizer, currentUser); + } + } + } + } catch (Exception ex) { + LOG.WarnFormat("Couldn't process item due to: {0}", ex.Message); + } + return false; + } + + + /// + /// Export the image stored in tmpFile to the Inspector with the caption + /// + /// Caption of the inspector + /// Path to image file + /// name of the attachment (used as the tooltip of the image) + /// true if it worked + public static bool ExportToInspector(string inspectorCaption, string tmpFile, string attachmentName) { + // Assume true, although this might cause issues. + bool allowMeetingAsTarget = true; + using (IOutlookApplication outlookApplication = GetOrCreateOutlookApplication()) { + if (outlookApplication != null) { + Inspectors inspectors = outlookApplication.Inspectors; + if (inspectors != null && inspectors.Count > 0) { + LOG.DebugFormat("Got {0} inspectors to check", inspectors.Count); + for (int i = 1; i <= inspectors.Count; i++) { + using (Inspector inspector = outlookApplication.Inspectors[i]) { + string currentCaption = inspector.Caption; + if (currentCaption.StartsWith(inspectorCaption)) { + using (Item currentItem = inspector.CurrentItem) { + if (canExportToInspector(currentItem, allowMeetingAsTarget)) { + try { + return ExportToInspector(inspector, currentItem, tmpFile, attachmentName); + } catch (Exception exExport) { + LOG.Error("Export to " + currentCaption + " failed.", exExport); + } + } + } + } + } + } + } + } + } + return false; + } + + /// + /// Export the file to the supplied inspector + /// + /// Inspector + /// Item + /// + /// + /// + private static bool ExportToInspector(Inspector inspector, Item currentItem, string tmpFile, string attachmentName) { + if (currentItem == null) { + LOG.Warn("No current item."); + return false; + } + OlObjectClass itemClass = currentItem.Class; + bool isMail = OlObjectClass.olMail.Equals(itemClass); + bool isAppointment = OlObjectClass.olAppointment.Equals(itemClass); + if (!isMail && !isAppointment) { + LOG.Warn("Item is no mail or appointment."); + return false; + } + MailItem mailItem = null; + try { + if (isMail) { + //mailItem = COMWrapper.Cast(currentItem); + mailItem = (MailItem)currentItem; + if (mailItem.Sent) { + LOG.WarnFormat("Item already sent, can't export to {0}", currentItem.Subject); + return false; + } + } + + // Make sure the inspector is activated, only this way the word editor is active! + // This also ensures that the window is visible! + inspector.Activate(); + bool isTextFormat = OlBodyFormat.olFormatPlain.Equals(mailItem.BodyFormat); + if (isAppointment || !isTextFormat) { + // Check for wordmail, if so use the wordexporter + // http://msdn.microsoft.com/en-us/library/dd492012%28v=office.12%29.aspx + // Earlier versions of Outlook also supported an Inspector.HTMLEditor object property, but since Internet Explorer is no longer the rendering engine for HTML messages and posts, HTMLEditor is no longer supported. + if (inspector.IsWordMail() && inspector.WordEditor != null) { + try { + if (WordExporter.InsertIntoExistingDocument(inspector.WordEditor.Application, inspector.WordEditor, tmpFile)) { + LOG.Info("Inserted into Wordmail"); + + // check the format afterwards, otherwise we lose the selection + //if (!OlBodyFormat.olFormatHTML.Equals(currentMail.BodyFormat)) { + // LOG.Info("Changing format to HTML."); + // currentMail.BodyFormat = OlBodyFormat.olFormatHTML; + //} + return true; + } + } catch (Exception exportException) { + LOG.Error("Error exporting to the word editor, trying to do it via another method", exportException); + } + } else if (isAppointment) { + LOG.Info("Can't export to an appointment if no word editor is used"); + return false; + } else { + LOG.Info("Trying export for outlook < 2007."); + } + } + // Only use mailitem as it should be filled!! + LOG.InfoFormat("Item '{0}' has format: {1}", mailItem.Subject, mailItem.BodyFormat); + + string contentID; + if (outlookVersion.Major >= OUTLOOK_2007) { + contentID = Guid.NewGuid().ToString(); + } else { + LOG.Info("Older Outlook (<2007) found, using filename as contentid."); + contentID = Path.GetFileName(tmpFile); + } + + // Use this to change the format, it will probably lose the current selection. + //if (!OlBodyFormat.olFormatHTML.Equals(currentMail.BodyFormat)) { + // LOG.Info("Changing format to HTML."); + // currentMail.BodyFormat = OlBodyFormat.olFormatHTML; + //} + + bool inlinePossible = false; + if (OlBodyFormat.olFormatHTML.Equals(mailItem.BodyFormat)) { + // if html we can try to inline it + // The following might cause a security popup... can't ignore it. + try { + IHTMLDocument2 document2 = inspector.HTMLEditor as IHTMLDocument2; + if (document2 != null) { + IHTMLSelectionObject selection = document2.selection; + if (selection != null) { + IHTMLTxtRange range = selection.createRange(); + if (range != null) { + // First paste, than attach (otherwise the range is wrong!) + range.pasteHTML("
\""
"); + inlinePossible = true; + } else { + LOG.DebugFormat("No range for '{0}'", inspector.Caption); + } + } else { + LOG.DebugFormat("No selection for '{0}'", inspector.Caption); + } + } else { + LOG.DebugFormat("No HTML editor for '{0}'", inspector.Caption); + } + } catch (Exception e) { + // Continue with non inline image + LOG.Warn("Error pasting HTML, most likely due to an ACCESS_DENIED as the user clicked no.", e); + } + } + + // Create the attachment (if inlined the attachment isn't visible as attachment!) + using (Attachment attachment = mailItem.Attachments.Add(tmpFile, OlAttachmentType.olByValue, inlinePossible ? 0 : 1, attachmentName)) { + if (outlookVersion.Major >= OUTLOOK_2007) { + // Add the content id to the attachment, this only works for Outlook >= 2007 + try { + PropertyAccessor propertyAccessor = attachment.PropertyAccessor; + propertyAccessor.SetProperty(PropTag.ATTACHMENT_CONTENT_ID, contentID); + } catch { + } + } + } + } catch (Exception ex) { + LOG.WarnFormat("Problem while trying to add attachment to Item '{0}' : {1}", inspector.Caption, ex); + return false; + } + LOG.Debug("Finished!"); + return true; + } + /// + /// Export image to a new email + /// + /// + /// + /// + private static void ExportToNewEmail(IOutlookApplication outlookApplication, EmailFormat format, string tmpFile, string subject, string attachmentName, string to, string CC, string BCC) { + Item newItem = outlookApplication.CreateItem(OlItemType.olMailItem); + if (newItem == null) { + return; + } + //MailItem newMail = COMWrapper.Cast(newItem); + MailItem newMail = (MailItem)newItem; + newMail.Subject = subject; + if (!string.IsNullOrEmpty(to)) { + newMail.To = to; + } + if (!string.IsNullOrEmpty(CC)) { + newMail.CC = CC; + } + if (!string.IsNullOrEmpty(BCC)) { + newMail.BCC = BCC; + } + newMail.BodyFormat = OlBodyFormat.olFormatHTML; + string bodyString = null; + // Read the default signature, if nothing found use empty email + try { + bodyString = GetOutlookSignature(format); + } catch (Exception e) { + LOG.Error("Problem reading signature!", e); + } + switch (format) { + case EmailFormat.Text: + newMail.Attachments.Add(tmpFile, OlAttachmentType.olByValue, 1, attachmentName); + newMail.BodyFormat = OlBodyFormat.olFormatPlain; + if (bodyString == null) { + bodyString = ""; + } + newMail.Body = bodyString; + break; + case EmailFormat.HTML: + default: + string contentID = Path.GetFileName(tmpFile); + // Create the attachment + using (Attachment attachment = newMail.Attachments.Add(tmpFile, OlAttachmentType.olByValue, 0, attachmentName)) { + // add content ID to the attachment + if (outlookVersion.Major >= OUTLOOK_2007) { + try { + contentID = Guid.NewGuid().ToString(); + PropertyAccessor propertyAccessor = attachment.PropertyAccessor; + propertyAccessor.SetProperty(PropTag.ATTACHMENT_CONTENT_ID, contentID); + } catch { + LOG.Info("Error working with the PropertyAccessor, using filename as contentid"); + contentID = Path.GetFileName(tmpFile); + } + } + } + + newMail.BodyFormat = OlBodyFormat.olFormatHTML; + string htmlImgEmbedded = "
\""
"; + string fallbackBody = "" + htmlImgEmbedded + ""; + if (bodyString == null) { + bodyString = fallbackBody; + } else { + int bodyIndex = bodyString.IndexOf("= 0) { + bodyIndex = bodyString.IndexOf(">", bodyIndex) + 1; + if (bodyIndex >= 0) { + bodyString = bodyString.Insert(bodyIndex, htmlImgEmbedded); + } else { + bodyString = fallbackBody; + } + } else { + bodyString = fallbackBody; + } + } + newMail.HTMLBody = bodyString; + break; + } + // So not save, otherwise the email is always stored in Draft folder.. (newMail.Save();) + try { + newMail.Display(false); + newMail.GetInspector().Activate(); + } catch (Exception ex) { + LOG.Warn("Problem displaying the new email, retrying to display it. Problem:", ex); + Thread retryDisplayEmail = new Thread(delegate() { + int retries = 10; + int retryInXSeconds = 5; + while (retries-- > 0) { + Thread.Sleep(retryInXSeconds * 1000); + try { + newMail.Display(false); + newMail.GetInspector().Activate(); + LOG.InfoFormat("Managed to display the message."); + return; + } catch (Exception displayEx) { + LOG.WarnFormat("Error displaying message: {0}, retrying to show email in {1} seconds... Retries left: {2}", displayEx, retryInXSeconds, retries); + } + } + LOG.WarnFormat("Retry failed, saving message to draft."); + try { + newMail.Save(); + } catch (Exception saveEx) { + LOG.WarnFormat("Saving message to draft failed: {0}", saveEx); + } + }); + retryDisplayEmail.Name = "Retry to display email"; + retryDisplayEmail.IsBackground = true; + retryDisplayEmail.Start(); + } + if (newItem != null) { + newItem.Dispose(); + } + } + + /// + /// Helper method to create an outlook mail item with attachment + /// + /// The file to send, do not delete the file right away! + /// true if it worked, false if not + public static bool ExportToOutlook(EmailFormat format, string tmpFile, string subject, string attachmentName, string to, string CC, string BCC) { + bool exported = false; + try { + using (IOutlookApplication outlookApplication = GetOrCreateOutlookApplication()) { + if (outlookApplication != null) { + ExportToNewEmail(outlookApplication, format, tmpFile, subject, attachmentName, to, CC, BCC); + exported = true; + } + } + return exported; + } catch (Exception e) { + LOG.Error("Error while creating an outlook mail item: ", e); + } + return exported; + } + + /// + /// Helper method to get the Outlook signature + /// + /// + private static string GetOutlookSignature(EmailFormat format) { + using (RegistryKey profilesKey = Registry.CurrentUser.OpenSubKey(PROFILES_KEY, false)) { + if (profilesKey == null) { + return null; + } + string defaultProfile = (string)profilesKey.GetValue(DEFAULT_PROFILE_VALUE); + LOG.DebugFormat("defaultProfile={0}", defaultProfile); + using (RegistryKey profileKey = profilesKey.OpenSubKey(defaultProfile + @"\" + ACCOUNT_KEY, false)) { + if (profilesKey == null) { + return null; + } + string[] numbers = profileKey.GetSubKeyNames(); + foreach (string number in numbers) { + LOG.DebugFormat("Found subkey {0}", number); + using (RegistryKey numberKey = profileKey.OpenSubKey(number, false)) { + byte[] val = (byte[])numberKey.GetValue(NEW_SIGNATURE_VALUE); + if (val == null) { + continue; + } + string signatureName = ""; + foreach (byte b in val) { + if (b != 0) { + signatureName += (char)b; + } + } + LOG.DebugFormat("Found email signature: {0}", signatureName); + string extension; + switch (format) { + case EmailFormat.Text: + extension = ".txt"; + break; + case EmailFormat.HTML: + default: + extension = ".htm"; + break; + } + string signatureFile = Path.Combine(SIGNATURE_PATH, signatureName + extension); + if (File.Exists(signatureFile)) { + LOG.DebugFormat("Found email signature file: {0}", signatureFile); + return File.ReadAllText(signatureFile, Encoding.Default); + } + } + } + } + } + return null; + } + + /// + /// Initialize static outlook variables like version and currentuser + /// + /// + private static void InitializeVariables(IOutlookApplication outlookApplication) { + if (outlookApplication == null || outlookVersion != null) { + return; + } + try { + outlookVersion = new Version(outlookApplication.Version); + LOG.InfoFormat("Using Outlook {0}", outlookVersion); + } catch (Exception exVersion) { + LOG.Error(exVersion); + LOG.Warn("Assuming outlook version 1."); + outlookVersion = new Version(1, 1, 1, 1); + } + // Preventing retrieval of currentUser if Outlook is older than 2007 + if (outlookVersion.Major >= OUTLOOK_2007) { + try { + INameSpace mapiNamespace = outlookApplication.GetNameSpace("MAPI"); + currentUser = mapiNamespace.CurrentUser.Name; + LOG.InfoFormat("Current user: {0}", currentUser); + } catch (Exception exNS) { + LOG.Error(exNS); + } + } + } + + /// + /// Call this to get the running outlook application, returns null if there isn't any. + /// + /// IOutlookApplication or null + private static IOutlookApplication GetOutlookApplication() { + IOutlookApplication outlookApplication = COMWrapper.GetInstance(); + InitializeVariables(outlookApplication); + return outlookApplication; + } + + /// + /// Call this to get the running outlook application, or create a new instance + /// + /// IOutlookApplication + private static IOutlookApplication GetOrCreateOutlookApplication() { + IOutlookApplication outlookApplication = COMWrapper.GetOrCreateInstance(); + InitializeVariables(outlookApplication); + return outlookApplication; + } + } + +} diff --git a/GreenshotOfficePlugin/OfficeExport/PowerpointExporter.cs b/GreenshotOfficePlugin/OfficeExport/PowerpointExporter.cs new file mode 100644 index 000000000..f99a2a012 --- /dev/null +++ b/GreenshotOfficePlugin/OfficeExport/PowerpointExporter.cs @@ -0,0 +1,185 @@ +/* + * Greenshot - a free and open source screenshot tool + * Copyright (C) 2007-2012 Thomas Braun, Jens Klingen, Robin Krom + * + * For more information see: http://getgreenshot.org/ + * The Greenshot project is hosted on Sourceforge: http://sourceforge.net/projects/greenshot/ + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 1 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +using System; +using System.Collections.Generic; +using System.Drawing; +using System.Text; + +using Greenshot.Interop; + +namespace Greenshot.Interop.Office { + public class PowerpointExporter { + private static readonly log4net.ILog LOG = log4net.LogManager.GetLogger(typeof(PowerpointExporter)); + private static string version = null; + + public static bool isAfter2003() { + if (version != null) { + return !version.StartsWith("11"); + } + return false; + } + /// + /// Get the captions of all the open powerpoint presentations + /// + /// + public static System.Collections.Generic.List GetPowerpointPresentations() { + System.Collections.Generic.List presentations = new System.Collections.Generic.List(); + try { + using (IPowerpointApplication powerpointApplication = COMWrapper.GetInstance()) { + if (powerpointApplication != null) { + if (version == null) { + version = powerpointApplication.Version; + } + LOG.DebugFormat("Open Presentations: {0}", powerpointApplication.Presentations.Count); + for (int i = 1; i <= powerpointApplication.Presentations.Count; i++) { + IPresentation presentation = powerpointApplication.Presentations.item(i); + if (presentation != null && presentation.ReadOnly != MsoTriState.msoTrue) { + if (isAfter2003()) { + if (presentation.Final) { + continue; + } + } + presentations.Add(presentation.Name); + } + } + } + } + } catch (Exception ex) { + LOG.Warn("Problem retrieving word destinations, ignoring: ", ex); + } + + return presentations; + } + + /// + /// Export the image from the tmpfile to the presentation with the supplied name + /// + /// Name of the presentation to insert to + /// Filename of the image file to insert + /// Size of the image + /// A string with the image title + /// + public static bool ExportToPresentation(string presentationName, string tmpFile, Size imageSize, string title) { + using (IPowerpointApplication powerpointApplication = COMWrapper.GetInstance()) { + if (powerpointApplication != null) { + LOG.DebugFormat("Open Presentations: {0}", powerpointApplication.Presentations.Count); + for (int i = 1; i <= powerpointApplication.Presentations.Count; i++) { + IPresentation presentation = powerpointApplication.Presentations.item(i); + if (presentation != null && presentation.Name.StartsWith(presentationName)) { + try { + AddPictureToPresentation(presentation, tmpFile, imageSize, title); + return true; + } catch (Exception e) { + LOG.Error(e); + } + } + } + } + } + return false; + } + + private static void AddPictureToPresentation(IPresentation presentation, string tmpFile, Size imageSize, string title) { + if (presentation != null) { + //ISlide slide = presentation.Slides.AddSlide( presentation.Slides.Count + 1, PPSlideLayout.ppLayoutPictureWithCaption); + ISlide slide; + float left = (presentation.PageSetup.SlideWidth / 2) - (imageSize.Width / 2) ; + float top = (presentation.PageSetup.SlideHeight / 2) - (imageSize.Height / 2); + float width = imageSize.Width; + float height = imageSize.Height; + bool isLayoutPictureWithCaption = false; + IShape shapeForCaption = null; + bool hasScaledWidth = false; + bool hasScaledHeight = false; + try { + slide = presentation.Slides.Add(presentation.Slides.Count + 1, (int)PPSlideLayout.ppLayoutPictureWithCaption); + isLayoutPictureWithCaption = true; + // Shapes[2] is the image shape on this layout. + shapeForCaption = slide.Shapes.item(1); + IShape shapeForLocation = slide.Shapes.item(2); + + if (width > shapeForLocation.Width) { + width = shapeForLocation.Width; + left = shapeForLocation.Left; + hasScaledWidth = true; + } else { + shapeForLocation.Left = left; + } + shapeForLocation.Width = imageSize.Width; + + if (height > shapeForLocation.Height) { + height = shapeForLocation.Height; + top = shapeForLocation.Top; + hasScaledHeight = true; + } else { + top = (shapeForLocation.Top + (shapeForLocation.Height / 2)) - (imageSize.Height / 2); + } + shapeForLocation.Height = imageSize.Height; + } catch (Exception e) { + LOG.Error(e); + slide = presentation.Slides.Add(presentation.Slides.Count + 1, (int)PPSlideLayout.ppLayoutBlank); + } + IShape shape = slide.Shapes.AddPicture(tmpFile, MsoTriState.msoFalse, MsoTriState.msoTrue, 0, 0, width, height); + shape.LockAspectRatio = MsoTriState.msoTrue; + shape.ScaleHeight(1, MsoTriState.msoTrue, MsoScaleFrom.msoScaleFromMiddle); + shape.ScaleWidth(1, MsoTriState.msoTrue, MsoScaleFrom.msoScaleFromMiddle); + if (hasScaledWidth) { + shape.Width = width; + } + if (hasScaledHeight) { + shape.Height = height; + } + shape.Left = left; + shape.Top = top; + shape.AlternativeText = title; + if (isLayoutPictureWithCaption && shapeForCaption != null) { + try { + // Using try/catch to make sure problems with the text range don't give an exception. + ITextFrame textFrame = shapeForCaption.TextFrame; + textFrame.TextRange.Text = title; + } catch (Exception ex) { + LOG.Warn("Problem setting the title to a text-range", ex); + } + } + presentation.Application.ActiveWindow.View.GotoSlide(slide.SlideNumber); + presentation.Application.Activate(); + } + } + + public static bool InsertIntoNewPresentation(string tmpFile, Size imageSize, string title) { + bool isPictureAdded = false; + using (IPowerpointApplication powerpointApplication = COMWrapper.GetOrCreateInstance()) { + if (powerpointApplication != null) { + powerpointApplication.Visible = true; + IPresentation presentation = powerpointApplication.Presentations.Add(MsoTriState.msoTrue); + try { + AddPictureToPresentation(presentation, tmpFile, imageSize, title); + isPictureAdded = true; + presentation.Application.Activate(); + } catch (Exception e) { + LOG.Error(e); + } + } + } + return isPictureAdded; + } + } +} diff --git a/GreenshotOfficePlugin/OfficeExport/WordExporter.cs b/GreenshotOfficePlugin/OfficeExport/WordExporter.cs new file mode 100644 index 000000000..ed22f0221 --- /dev/null +++ b/GreenshotOfficePlugin/OfficeExport/WordExporter.cs @@ -0,0 +1,148 @@ +/* + * Greenshot - a free and open source screenshot tool + * Copyright (C) 2007-2012 Thomas Braun, Jens Klingen, Robin Krom + * + * For more information see: http://getgreenshot.org/ + * The Greenshot project is hosted on Sourceforge: http://sourceforge.net/projects/greenshot/ + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 1 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +using System; +using System.Collections.Generic; +using System.Text; + +using Greenshot.Interop; + +namespace Greenshot.Interop.Office { + public class WordExporter { + private static readonly log4net.ILog LOG = log4net.LogManager.GetLogger(typeof(WordExporter)); + private static string version = null; + + public static bool isAfter2003() { + if (version != null) { + return !version.StartsWith("11"); + } + return false; + } + /// + /// Insert the bitmap stored under the tempfile path into the word document with the supplied caption + /// + /// + /// + /// + public static bool InsertIntoExistingDocument(string wordCaption, string tmpFile) { + using (IWordApplication wordApplication = COMWrapper.GetInstance()) { + if (wordApplication != null) { + for (int i = 1; i <= wordApplication.Documents.Count; i++) { + using (IWordDocument wordDocument = wordApplication.Documents.item(i)) { + if (wordDocument.ActiveWindow.Caption.StartsWith(wordCaption)) { + return InsertIntoExistingDocument(wordApplication, wordDocument, tmpFile); + } + } + } + } + } + return false; + } + + /// + /// Internal method for the insert + /// + /// + /// + /// + /// + internal static bool InsertIntoExistingDocument(IWordApplication wordApplication, IWordDocument wordDocument, string tmpFile) { + if (wordApplication.Selection != null) { + AddPictureToSelection(wordApplication.Selection, tmpFile); + try { + wordDocument.ActiveWindow.ActivePane.View.Zoom.Percentage = 100; + } catch (Exception e) { + if (e.InnerException != null) { + LOG.WarnFormat("Couldn't set zoom to 100, error: {0}", e.InnerException.Message); + } else { + LOG.WarnFormat("Couldn't set zoom to 100, error: {0}", e.Message); + } + } + try { + wordApplication.Activate(); + } catch {} + try { + wordDocument.Activate(); + } catch {} + try { + wordDocument.ActiveWindow.Activate(); + } catch {} + return true; + } + return false; + } + + private static void AddPictureToSelection(ISelection selection, string tmpFile) { + selection.InlineShapes.AddPicture(tmpFile, false, true, Type.Missing); + selection.InsertAfter("\r\n"); + } + + public static void InsertIntoNewDocument(string tmpFile) { + using (IWordApplication wordApplication = COMWrapper.GetOrCreateInstance()) { + if (wordApplication != null) { + wordApplication.Visible = true; + wordApplication.Activate(); + // Create new Document + object template = string.Empty; + object newTemplate = false; + object documentType = 0; + object documentVisible = true; + IWordDocument wordDocument = wordApplication.Documents.Add(ref template, ref newTemplate, ref documentType, ref documentVisible); + // Add Picture + AddPictureToSelection(wordApplication.Selection, tmpFile); + wordDocument.Activate(); + wordDocument.ActiveWindow.Activate(); + } + } + } + + /// + /// Get the captions of all the open word documents + /// + /// + public static List GetWordDocuments() { + List documents = new List(); + try { + using (IWordApplication wordApplication = COMWrapper.GetInstance()) { + if (wordApplication != null) { + if (version == null) { + version = wordApplication.Version; + } + for (int i = 1; i <= wordApplication.Documents.Count; i++) { + IWordDocument document = wordApplication.Documents.item(i); + if (document.ReadOnly) { + continue; + } + if (isAfter2003()) { + if (document.Final) { + continue; + } + } + documents.Add(document.ActiveWindow.Caption); + } + } + } + } catch (Exception ex) { + LOG.Warn("Problem retrieving word destinations, ignoring: ", ex); + } + return documents; + } + } +} diff --git a/GreenshotOfficePlugin/OfficeInterop/ExcelInterop.cs b/GreenshotOfficePlugin/OfficeInterop/ExcelInterop.cs new file mode 100644 index 000000000..4134d1952 --- /dev/null +++ b/GreenshotOfficePlugin/OfficeInterop/ExcelInterop.cs @@ -0,0 +1,64 @@ +/* + * Greenshot - a free and open source screenshot tool + * Copyright (C) 2007-2012 Thomas Braun, Jens Klingen, Robin Krom + * + * For more information see: http://getgreenshot.org/ + * The Greenshot project is hosted on Sourceforge: http://sourceforge.net/projects/greenshot/ + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 1 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +namespace Greenshot.Interop.Office { + // See http://msdn.microsoft.com/en-us/library/microsoft.office.interop.excel.application.aspx + [ComProgId("Excel.Application")] + public interface IExcelApplication : Common { + IWorkbook ActiveWorkbook { get; } + //ISelection Selection {get;} + IWorkbooks Workbooks { get; } + bool Visible { get; set; } + } + + // See: http://msdn.microsoft.com/en-us/library/microsoft.office.interop.excel.workbooks.aspx + public interface IWorkbooks : Common, Collection { + IWorkbook Add(object template); + // Use index + 1!! + IWorkbook this[object Index] { get; } + } + + // See: http://msdn.microsoft.com/en-us/library/microsoft.office.interop.excel.workbook.aspx + public interface IWorkbook : Common { + IWorksheet ActiveSheet { get; } + string Name { get; } + void Activate(); + IWorksheets Worksheets { get; } + } + + // See: http://msdn.microsoft.com/en-us/library/microsoft.office.interop.excel._worksheet_members.aspx + public interface IWorksheet : Common { + IPictures Pictures { get; } + string Name { get; } + } + + // See: http://msdn.microsoft.com/en-us/library/microsoft.office.interop.excel.iworksheets_members.aspx + public interface IWorksheets : Common, Collection { + // Use index + 1!! + IWorksheet this[object Index] { get; } + } + + public interface IPictures : Common, Collection { + // Use index + 1!! + //IPicture this[object Index] { get; } + void Insert(string file); + } +} diff --git a/GreenshotOfficePlugin/OfficeInterop/OfficeCommunicator.cs b/GreenshotOfficePlugin/OfficeInterop/OfficeCommunicator.cs new file mode 100644 index 000000000..f659d12b3 --- /dev/null +++ b/GreenshotOfficePlugin/OfficeInterop/OfficeCommunicator.cs @@ -0,0 +1,71 @@ +using System; +using System.Collections.Generic; +using System.Text; +using Greenshot.Interop; +using Greenshot.Interop.Office; + +namespace GreenshotInterop.OfficeInterop { + // See: http://msdn.microsoft.com/en-us/library/bb758788%28v=office.12%29 + [ComProgId("Communicator.UIAutomation")] + public interface IMessenger : Common { + void AutoSignin(); + string MyServiceId { + get; + } + IMessengerContact GetContact(string signinName, string serviceId); + IMessengerWindow InstantMessage(string contact); + } + + // See: http://msdn.microsoft.com/en-us/library/bb787250%28v=office.12%29 + public interface IMessengerContact : Common { + string FriendlyName { + get; + } + string ServiceName { + get; + } + string ServiceId { + get; + } + string SigninName { + get; + } + MISTATUS Status { + get; + } + } + + // See: http://msdn.microsoft.com/en-us/library/bb787207%28v=office.12%29 + public enum MISTATUS { + MISTATUS_UNKNOWN = 0x0000, + MISTATUS_OFFLINE = 0x0001, + MISTATUS_ONLINE = 0x0002, + MISTATUS_INVISIBLE = 0x0006, + MISTATUS_BUSY = 0x000A, + MISTATUS_BE_RIGHT_BACK = 0x000E, + MISTATUS_IDLE = 0x0012, + MISTATUS_AWAY = 0x0022, + MISTATUS_ON_THE_PHONE = 0x0032, + MISTATUS_OUT_TO_LUNCH = 0x0042, + MISTATUS_IN_A_MEETING = 0x0052, + MISTATUS_OUT_OF_OFFICE = 0x0062, + MISTATUS_DO_NOT_DISTURB = 0x0072, + MISTATUS_IN_A_CONFERENCE = 0x0082, + MISTATUS_ALLOW_URGENT_INTERRUPTIONS = 0x0092, + MISTATUS_MAY_BE_AVAILABLE = 0x00A2, + MISTATUS_CUSTOM = 0x00B2, + MISTATUS_LOCAL_FINDING_SERVER = 0x0100, + MISTATUS_LOCAL_CONNECTING_TO_SERVER = 0x0200, + MISTATUS_LOCAL_SYNCHRONIZING_WITH_SERVER = 0x0300, + MISTATUS_LOCAL_DISCONNECTING_FROM_SERVER = 0x0400 + } ; + + // See: http://msdn.microsoft.com/en-us/library/bb758816%28v=office.12%29 + public interface IMessengerWindow : Common { + bool IsClosed { + get; + } + void Show(); + } + +} diff --git a/GreenshotOfficePlugin/OfficeInterop/OfficeInterop.cs b/GreenshotOfficePlugin/OfficeInterop/OfficeInterop.cs new file mode 100644 index 000000000..b69ca3045 --- /dev/null +++ b/GreenshotOfficePlugin/OfficeInterop/OfficeInterop.cs @@ -0,0 +1,31 @@ +/* + * Greenshot - a free and open source screenshot tool + * Copyright (C) 2007-2012 Thomas Braun, Jens Klingen, Robin Krom + * + * For more information see: http://getgreenshot.org/ + * The Greenshot project is hosted on Sourceforge: http://sourceforge.net/projects/greenshot/ + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 1 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +using System.Collections; + +namespace Greenshot.Interop.Office { + /// + /// If the "type" this[object index] { get; } is implemented, use index + 1!!! (starts at 1) + /// + public interface Collection : Common, IEnumerable { + int Count { get; } + void Remove(int index); + } +} diff --git a/GreenshotOfficePlugin/OfficeInterop/OneNoteInterop.cs b/GreenshotOfficePlugin/OfficeInterop/OneNoteInterop.cs new file mode 100644 index 000000000..9b3d1ad91 --- /dev/null +++ b/GreenshotOfficePlugin/OfficeInterop/OneNoteInterop.cs @@ -0,0 +1,59 @@ +/* + * Greenshot - a free and open source screenshot tool + * Copyright (C) 2007-2012 Thomas Braun, Jens Klingen, Robin Krom + * + * For more information see: http://getgreenshot.org/ + * The Greenshot project is hosted on Sourceforge: http://sourceforge.net/projects/greenshot/ + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 1 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +using System; + +namespace Greenshot.Interop.Office { + // More details about OneNote: http://msdn.microsoft.com/en-us/magazine/ff796230.aspx + + // See http://msdn.microsoft.com/de-de/library/microsoft.office.interop.word.applicationclass_members%28v=Office.11%29.aspx + [ComProgId("OneNote.Application")] + public interface IOneNoteApplication : Common { + /// + /// Make sure that the notebookXml is of type string, e.g. "", otherwise a type error occurs. + /// For more info on the methods: http://msdn.microsoft.com/en-us/library/gg649853.aspx + /// + void GetHierarchy(string startNode, HierarchyScope scope, out string notebookXml, XMLSchema schema); + void UpdatePageContent(string pageChangesXml, DateTime dateExpectedLastModified, XMLSchema schema, bool force); + void GetPageContent(string pageId, out string pageXml, PageInfo pageInfoToExport, XMLSchema schema); + } + + public enum PageInfo { + piBasic = 0, // Returns only basic page content, without selection markup and binary data objects. This is the standard value to pass. + piBinaryData = 1, // Returns page content with no selection markup, but with all binary data. + piSelection = 2, // Returns page content with selection markup, but no binary data. + piBinaryDataSelection = 3, // Returns page content with selection markup and all binary data. + piAll = 3 // Returns all page content. + } + + public enum HierarchyScope { + hsSelf = 0, // Gets just the start node specified and no descendants. + hsChildren = 1, //Gets the immediate child nodes of the start node, and no descendants in higher or lower subsection groups. + hsNotebooks = 2, // Gets all notebooks below the start node, or root. + hsSections = 3, //Gets all sections below the start node, including sections in section groups and subsection groups. + hsPages = 4 //Gets all pages below the start node, including all pages in section groups and subsection groups. + } + + public enum XMLSchema { + xs2007 = 0, + xs2010 = 1, + xsCurrent= xs2010 + } +} diff --git a/GreenshotOfficePlugin/OfficeInterop/OutlookInterop.cs b/GreenshotOfficePlugin/OfficeInterop/OutlookInterop.cs new file mode 100644 index 000000000..fc33fb0a5 --- /dev/null +++ b/GreenshotOfficePlugin/OfficeInterop/OutlookInterop.cs @@ -0,0 +1,465 @@ +/* + * Greenshot - a free and open source screenshot tool + * Copyright (C) 2007-2012 Thomas Braun, Jens Klingen, Robin Krom + * + * For more information see: http://getgreenshot.org/ + * The Greenshot project is hosted on Sourceforge: http://sourceforge.net/projects/greenshot/ + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 1 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +using System; +using System.Collections; + +/// +/// This utils class should help setting the content-id on the attachment for Outlook < 2007 +/// But this somehow doesn't work yet +/// +namespace Greenshot.Interop.Office { + /// + /// See: http://msdn.microsoft.com/en-us/library/bb208387%28v=office.12%29.aspx + /// + public interface Items : Collection, IEnumerable { + Item this[object index] { get; } + Item GetFirst(); + Item GetNext(); + Item GetLast(); + Item GetPrevious(); + + bool IncludeRecurrences { + get; + set; + } + + Items Restrict(string filter); + void Sort(string property, object descending); + + // Actual definition is "object Add( object )", just making it convenient + object Add(OlItemType type); + } + + // Common attributes of all the Items (MailItem, AppointmentItem) + // See: http://msdn.microsoft.com/en-us/library/ff861252.aspx + public interface Item : Common { + Attachments Attachments { get; } + string Body { get; set; } + OlObjectClass Class { get; } + DateTime CreationTime { get; } + string EntryID { get; } + DateTime LastModificationTime { get; } + string MessageClass { get; set; } + bool NoAging { get; set; } + int OutlookInternalVersion { get; } + string OutlookVersion { get; } + bool Saved { get; } + OlSensitivity Sensitivity { get; set; } + int Size { get; } + string Subject { get; set; } + bool UnRead { get; set; } + object Copy(); + void Display(bool Modal); + void Save(); + PropertyAccessor PropertyAccessor { get; } + Inspector GetInspector(); + } + + // See: http://msdn.microsoft.com/en-us/library/ff861252.aspx + // See: http://msdn.microsoft.com/en-us/library/microsoft.office.interop.outlook.mailitem.aspx + public interface MailItem : Item, Common { + bool Sent { get; } + object MAPIOBJECT { get; } + string HTMLBody { get; set; } + DateTime ExpiryTime { get; set; } + DateTime ReceivedTime { get; } + string SenderName { get; } + DateTime SentOn { get; } + OlBodyFormat BodyFormat { get; set; } + string To { get; set; } + string CC { get; set; } + string BCC { get; set; } + } + + // See: http://msdn.microsoft.com/en-us/library/ff869026.aspx + // See: http://msdn.microsoft.com/en-us/library/microsoft.office.interop.outlook.appointmentitem.aspx + public interface AppointmentItem : Item, Common { + string Organizer { get; set; } + string SendUsingAccount { get; } + string Categories { get; } + DateTime Start { get; } + DateTime End { get; } + OlReoccurenceState RecurrenceState { get; } + } + + // See: http://msdn.microsoft.com/en-us/library/microsoft.office.interop.outlook.contactitem.aspx + public interface ContactItem : Item, Common { + bool HasPicture { + get; + } + void SaveBusinessCardImage(string path); + void AddPicture(string path); + void RemovePicture(); + string FirstName { + get; + set; + } + string LastName { + get; + set; + } + } + + public interface Attachments : Collection { + Attachment Add(object source, object type, object position, object displayName); + // Use index+1!!!! + Attachment this[object index] { get; } + } + + // See: http://msdn.microsoft.com/en-us/library/microsoft.office.interop.outlook.attachment_members.aspx + public interface Attachment : Common { + string DisplayName { get; set; } + string FileName { get; } + OlAttachmentType Type { get; } + PropertyAccessor PropertyAccessor { get; } + object MAPIOBJECT { get; } + void SaveAsFile(string path); + } + + // See: http://msdn.microsoft.com/en-us/library/microsoft.office.interop.outlook.propertyaccessor_members.aspx + public interface PropertyAccessor : Common { + void SetProperty(string SchemaName, Object Value); + Object GetProperty(string SchemaName); + } + + // Schema definitions for the MAPI properties + // See: http://msdn.microsoft.com/en-us/library/aa454438.aspx + // and see: http://msdn.microsoft.com/en-us/library/bb446117.aspx + public static class PropTag { + public const string ATTACHMENT_CONTENT_ID = @"http://schemas.microsoft.com/mapi/proptag/0x3712001E"; + } + /// + /// Wrapper for Outlook.Application, see: http://msdn.microsoft.com/en-us/library/aa210897%28v=office.11%29.aspx + /// + [ComProgId("Outlook.Application")] + public interface IOutlookApplication : Common { + string Name { get; } + string Version { get; } + Item CreateItem(OlItemType ItemType); + object CreateItemFromTemplate(string TemplatePath, object InFolder); + object CreateObject(string ObjectName); + Inspector ActiveInspector(); + Inspectors Inspectors { get; } + INameSpace GetNameSpace(string type); + } + + /// + /// See: http://msdn.microsoft.com/en-us/library/bb176693%28v=office.12%29.aspx + /// + public interface INameSpace : Common { + IRecipient CurrentUser { get; } + IFolder GetDefaultFolder(OlDefaultFolders defaultFolder); + } + + /// + /// See: http://msdn.microsoft.com/en-us/library/bb176362%28v=office.12%29.aspx + /// + public interface IFolder : Common { + Items Items {get;} + } + + public interface IRecipient : Common { + string Name { get; } + } + + // See: http://msdn.microsoft.com/en-us/library/microsoft.office.interop.outlook.inspector_members.aspx + public interface Inspector : Common { + Item CurrentItem { get; } + OlEditorType EditorType { get; } + object ModifiedFormPages { get; } + void Close(OlInspectorClose SaveMode); + void Display(object Modal); + void HideFormPage(string PageName); + bool IsWordMail(); + void SetCurrentFormPage(string PageName); + void ShowFormPage(string PageName); + object HTMLEditor { get; } + IWordDocument WordEditor { get; } + string Caption { get; } + int Height { get; set; } + int Left { get; set; } + int Top { get; set; } + int Width { get; set; } + OlWindowState WindowState { get; set; } + void Activate(); + void SetControlItemProperty(object Control, string PropertyName); + } + + // See: http://msdn.microsoft.com/en-us/library/microsoft.office.interop.outlook._application.inspectors.aspx + public interface Inspectors : Common, Collection, IEnumerable { + // Use index + 1!! + Inspector this[Object Index] { get; } + } + + /// + /// Specifies which EmailFormat the email needs to use + /// + public enum EmailFormat { + Text, HTML + } + public enum OlBodyFormat { + // Fields + olFormatHTML = 2, + olFormatPlain = 1, + olFormatRichText = 3, + olFormatUnspecified = 0 + } + + public enum OlAttachmentType { + // Fields + olByReference = 4, + olByValue = 1, + olEmbeddeditem = 5, + olOLE = 6 + } + + public enum OlSensitivity { + // Fields + olConfidential = 3, + olNormal = 0, + olPersonal = 1, + olPrivate = 2 + } + + // See: http://msdn.microsoft.com/en-us/library/ff863329.aspx + public enum OlObjectClass { + olAccount = 105, // Represents an Account object. + olAccountRuleCondition = 135, // Represents an AccountRuleCondition object. + olAccounts = 106, // Represents an Accounts object. + olAction = 32, // Represents an Action object. + olActions = 33, // Represents an Actions object. + olAddressEntries = 21, // Represents an AddressEntries object. + olAddressEntry = 8, // Represents an AddressEntry object. + olAddressList = 7, // Represents an AddressList object. + olAddressLists = 20, // Represents an AddressLists object. + olAddressRuleCondition = 170, // Represents an AddressRuleCondition object. + olApplication = 0, // Represents an Application object. + olAppointment = 26, // Represents an AppointmentItem object. + olAssignToCategoryRuleAction = 122, // Represents an AssignToCategoryRuleAction object. + olAttachment = 5, // Represents an Attachment object. + olAttachments = 18, // Represents an Attachments object. + olAttachmentSelection = 169, // Represents an AttachmentSelection object. + olAutoFormatRule = 147, // Represents an AutoFormatRule object. + olAutoFormatRules = 148, // Represents an AutoFormatRules object. + olCalendarModule = 159, // Represents a CalendarModule object. + olCalendarSharing = 151, // Represents a CalendarSharing object. + olCategories = 153, // Represents a Categories object. + olCategory = 152, // Represents a Category object. + olCategoryRuleCondition = 130, // Represents a CategoryRuleCondition object. + olClassBusinessCardView = 168, // Represents a BusinessCardView object. + olClassCalendarView = 139, // Represents a CalendarView object. + olClassCardView = 138, // Represents a CardView object. + olClassIconView = 137, // Represents a IconView object. + olClassNavigationPane = 155, // Represents a NavigationPane object. + olClassTableView = 136, // Represents a TableView object. + olClassTimeLineView = 140, // Represents a TimelineView object. + olClassTimeZone = 174, // Represents a TimeZone object. + olClassTimeZones = 175, // Represents a TimeZones object. + olColumn = 154, // Represents a Column object. + olColumnFormat = 149, // Represents a ColumnFormat object. + olColumns = 150, // Represents a Columns object. + olConflict = 102, // Represents a Conflict object. + olConflicts = 103, // Represents a Conflicts object. + olContact = 40, // Represents a ContactItem object. + olContactsModule = 160, // Represents a ContactsModule object. + olDistributionList = 69, // Represents a ExchangeDistributionList object. + olDocument = 41, // Represents a DocumentItem object. + olException = 30, // Represents an Exception object. + olExceptions = 29, // Represents an Exceptions object. + olExchangeDistributionList = 111, // Represents an ExchangeDistributionList object. + olExchangeUser = 110, // Represents an ExchangeUser object. + olExplorer = 34, // Represents an Explorer object. + olExplorers = 60, // Represents an Explorers object. + olFolder = 2, // Represents a Folder object. + olFolders = 15, // Represents a Folders object. + olFolderUserProperties = 172, // Represents a UserDefinedProperties object. + olFolderUserProperty = 171, // Represents a UserDefinedProperty object. + olFormDescription = 37, // Represents a FormDescription object. + olFormNameRuleCondition = 131, // Represents a FormNameRuleCondition object. + olFormRegion = 129, // Represents a FormRegion object. + olFromRssFeedRuleCondition = 173, // Represents a FromRssFeedRuleCondition object. + olFromRuleCondition = 132, // Represents a ToOrFromRuleCondition object. + olImportanceRuleCondition = 128, // Represents an ImportanceRuleCondition object. + olInspector = 35, // Represents an Inspector object. + olInspectors = 61, // Represents an Inspectors object. + olItemProperties = 98, // Represents an ItemProperties object. + olItemProperty = 99, // Represents an ItemProperty object. + olItems = 16, // Represents an Items object. + olJournal = 42, // Represents a JournalItem object. + olJournalModule = 162, // Represents a JournalModule object. + olLink = 75, // Represents a Link object. + olLinks = 76, // Represents a Links object. + olMail = 43, // Represents a MailItem object. + olMailModule = 158, // Represents a MailModule object. + olMarkAsTaskRuleAction = 124, // Represents a MarkAsTaskRuleAction object. + olMeetingCancellation = 54, // Represents a MeetingItem object that is a meeting cancellation notice. + olMeetingRequest = 53, // Represents a MeetingItem object that is a meeting request. + olMeetingResponseNegative = 55, // Represents a MeetingItem object that is a refusal of a meeting request. + olMeetingResponsePositive = 56, // Represents a MeetingItem object that is an acceptance of a meeting request. + olMeetingResponseTentative = 57, // Represents a MeetingItem object that is a tentative acceptance of a meeting request. + olMoveOrCopyRuleAction = 118, // Represents a MoveOrCopyRuleAction object. + olNamespace = 1, // Represents a NameSpace object. + olNavigationFolder = 167, // Represents a NavigationFolder object. + olNavigationFolders = 166, // Represents a NavigationFolders object. + olNavigationGroup = 165, // Represents a NavigationGroup object. + olNavigationGroups = 164, // Represents a NavigationGroups object. + olNavigationModule = 157, // Represents a NavigationModule object. + olNavigationModules = 156, // Represents a NavigationModules object. + olNewItemAlertRuleAction = 125, // Represents a NewItemAlertRuleAction object. + olNote = 44, // Represents a NoteItem object. + olNotesModule = 163, // Represents a NotesModule object. + olOrderField = 144, // Represents an OrderField object. + olOrderFields = 145, // Represents an OrderFields object. + olOutlookBarGroup = 66, // Represents an OutlookBarGroup object. + olOutlookBarGroups = 65, // Represents an OutlookBarGroups object. + olOutlookBarPane = 63, // Represents an OutlookBarPane object. + olOutlookBarShortcut = 68, // Represents an OutlookBarShortcut object. + olOutlookBarShortcuts = 67, // Represents an OutlookBarShortcuts object. + olOutlookBarStorage = 64, // Represents an OutlookBarStorage object. + olPages = 36, // Represents a Pages object. + olPanes = 62, // Represents a Panes object. + olPlaySoundRuleAction = 123, // Represents a PlaySoundRuleAction object. + olPost = 45, // Represents a PostItem object. + olPropertyAccessor = 112, // Represents a PropertyAccessor object. + olPropertyPages = 71, // Represents a PropertyPages object. + olPropertyPageSite = 70, // Represents a PropertyPageSite object. + olRecipient = 4, // Represents a Recipient object. + olRecipients = 17, // Represents a Recipients object. + olRecurrencePattern = 28, // Represents a RecurrencePattern object. + olReminder = 101, // Represents a Reminder object. + olReminders = 100, // Represents a Reminders object. + olRemote = 47, // Represents a RemoteItem object. + olReport = 46, // Represents a ReportItem object. + olResults = 78, // Represents a Results object. + olRow = 121, // Represents a Row object. + olRule = 115, // Represents a Rule object. + olRuleAction = 117, // Represents a RuleAction object. + olRuleActions = 116, // Represents a RuleAction object. + olRuleCondition = 127, // Represents a RuleCondition object. + olRuleConditions = 126, // Represents a RuleConditions object. + olRules = 114, // Represents a Rules object. + olSearch = 77, // Represents a Search object. + olSelection = 74, // Represents a Selection object. + olSelectNamesDialog = 109, // Represents a SelectNamesDialog object. + olSenderInAddressListRuleCondition = 133, // Represents a SenderInAddressListRuleCondition object. + olSendRuleAction = 119, // Represents a SendRuleAction object. + olSharing = 104, // Represents a SharingItem object. + olStorageItem = 113, // Represents a StorageItem object. + olStore = 107, // Represents a Store object. + olStores = 108, // Represents a Stores object. + olSyncObject = 72, // Represents a SyncObject object. + olSyncObjects = 73, // Represents a SyncObject object. + olTable = 120, // Represents a Table object. + olTask = 48, // Represents a TaskItem object. + olTaskRequest = 49, // Represents a TaskRequestItem object. + olTaskRequestAccept = 51, // Represents a TaskRequestAcceptItem object. + olTaskRequestDecline = 52, // Represents a TaskRequestDeclineItem object. + olTaskRequestUpdate = 50, // Represents a TaskRequestUpdateItem object. + olTasksModule = 161, // Represents a TasksModule object. + olTextRuleCondition = 134, // Represents a TextRuleCondition object. + olUserDefinedProperties = 172, // Represents a UserDefinedProperties object. + olUserDefinedProperty = 171, // Represents a UserDefinedProperty object. + olUserProperties = 38, // Represents a UserProperties object. + olUserProperty = 39, // Represents a UserProperty object. + olView = 80, // Represents a View object. + olViewField = 142, // Represents a ViewField object. + olViewFields = 141, // Represents a ViewFields object. + olViewFont = 146, // Represents a ViewFont object. + olViews = 79 // Represents a Views object. + } + + public enum OlDefaultFolders { + olFolderCalendar = 9, // The Calendar folder. + olFolderConflicts = 19, // The Conflicts folder (subfolder of Sync Issues folder). Only available for an Exchange account. + olFolderContacts = 10, // The Contacts folder. + olFolderDeletedItems = 3, // The Deleted Items folder. + olFolderDrafts = 16, // The Drafts folder. + olFolderInbox = 6, // The Inbox folder. + olFolderJournal = 11, // The Journal folder. + olFolderJunk = 23, // The Junk E-Mail folder. + olFolderLocalFailures = 21, // The Local Failures folder (subfolder of Sync Issues folder). Only available for an Exchange account. + olFolderManagedEmail = 29, // The top-level folder in the Managed Folders group. For more information on Managed Folders, see Help in Microsoft Outlook. Only available for an Exchange account. + olFolderNotes = 12, // The Notes folder. + olFolderOutbox = 4, // The Outbox folder. + olFolderSentMail = 5, // The Sent Mail folder. + olFolderServerFailures = 22, // The Server Failures folder (subfolder of Sync Issues folder). Only available for an Exchange account. + olFolderSyncIssues = 20, // The Sync Issues folder. Only available for an Exchange account. + olFolderTasks = 13, // The Tasks folder. + olFolderToDo = 28, // The To Do folder. + olPublicFoldersAllPublicFolders = 18, // The All Public Folders folder in the Exchange Public Folders store. Only available for an Exchange account. + olFolderRssFeeds = 25 // The RSS Feeds folder. + } + + public enum OlItemType { + // Fields + olAppointmentItem = 1, + olContactItem = 2, + olDistributionListItem = 7, + olJournalItem = 4, + olMailItem = 0, + olNoteItem = 5, + olPostItem = 6, + olTaskItem = 3 + } + + public enum OlEditorType { + // Fields + olEditorHTML = 2, + olEditorRTF = 3, + olEditorText = 1, + olEditorWord = 4 + } + + public enum OlWindowState { + // Fields + olMaximized = 0, + olMinimized = 1, + olNormalWindow = 2 + } + + public enum OlInspectorClose { + // Fields + olDiscard = 1, + olPromptForSave = 2, + olSave = 0 + } + + public enum MsoTriState { + msoTrue = -1, + msoFalse = 0, + msoCTrue = 1, + msoTriStateToggle = -3, + msoTriStateMixed = -2 + } + + public enum OlReoccurenceState { + olApptException, + olApptMaster, + olApptNotRecurring, + olApptOccurrence + } + + public enum MsoScaleFrom { + msoScaleFromTopLeft = 0, + msoScaleFromMiddle = 1, + msoScaleFromBottomRight = 2 + } +} diff --git a/GreenshotOfficePlugin/OfficeInterop/OutlookUtils.cs b/GreenshotOfficePlugin/OfficeInterop/OutlookUtils.cs new file mode 100644 index 000000000..fa27c4c7d --- /dev/null +++ b/GreenshotOfficePlugin/OfficeInterop/OutlookUtils.cs @@ -0,0 +1,853 @@ +/* + * Greenshot - a free and open source screenshot tool + * Copyright (C) 2007-2012 Thomas Braun, Jens Klingen, Robin Krom + * + * For more information see: http://getgreenshot.org/ + * The Greenshot project is hosted on Sourceforge: http://sourceforge.net/projects/greenshot/ + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 1 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +using System; +using System.Runtime.InteropServices; + +namespace Greenshot.Interop.Office { + enum PT : uint { + PT_UNSPECIFIED = 0, /* (Reserved for interface use) type doesn't matter to caller */ + PT_NULL = 1, /* NULL property value */ + PT_I2 = 2, /* Signed 16-bit value */ + PT_LONG = 3, /* Signed 32-bit value */ + PT_R4 = 4, /* 4-byte floating point */ + PT_DOUBLE = 5, /* Floating point double */ + PT_CURRENCY = 6, /* Signed 64-bit int (decimal w/ 4 digits right of decimal pt) */ + PT_APPTIME = 7, /* Application time */ + PT_ERROR = 10, /* 32-bit error value */ + PT_BOOLEAN = 11, /* 16-bit boolean (non-zero true, */ + // Use PT_BOOLEAN_DESKTOP to be specific instead of using PT_BOOLEAN which is mapped to 2 in addrmapi.h + PT_BOOLEAN_DESKTOP = 11, /* 16-bit boolean (non-zero true) */ + PT_OBJECT = 13, /* Embedded object in a property */ + PT_I8 = 20, /* 8-byte signed integer */ + PT_STRING8 = 30, /* Null terminated 8-bit character string */ + PT_UNICODE = 31, /* Null terminated Unicode string */ + PT_SYSTIME = 64, /* FILETIME 64-bit int w/ number of 100ns periods since Jan 1,1601 */ + PT_CLSID = 72, /* OLE GUID */ + PT_BINARY = 258, /* Uninterpreted (counted byte array) */ + + PT_TSTRING = PT_UNICODE + }; + + public enum PropTags : uint { + PR_ERROR = 10, + + // Common non-transmittable + PR_ENTRYID = PT.PT_BINARY | 0x0FFF << 16, + PR_OBJECT_TYPE = PT.PT_LONG | 0x0FFE << 16, + PR_ICON = PT.PT_BINARY | 0x0FFD << 16, + PR_MINI_ICON = PT.PT_BINARY | 0x0FFC << 16, + PR_STORE_ENTRYID = PT.PT_BINARY | 0x0FFB << 16, + PR_STORE_RECORD_KEY = PT.PT_BINARY | 0x0FFA << 16, + PR_RECORD_KEY = PT.PT_BINARY | 0x0FF9 << 16, + PR_MAPPING_SIGNATURE = PT.PT_BINARY | 0x0FF8 << 16, + PR_ACCESS_LEVEL = PT.PT_LONG | 0x0FF7 << 16, + PR_INSTANCE_KEY = PT.PT_BINARY | 0x0FF6 << 16, + PR_ROW_TYPE = PT.PT_LONG | 0x0FF5 << 16, + PR_ACCESS = PT.PT_LONG | 0x0FF4 << 16, + + // Common transmittable + PR_ROWID = PT.PT_LONG | 0x3000 << 16, + PR_DISPLAY_NAME = PT.PT_TSTRING | 0x3001 << 16, + PR_DISPLAY_NAME_W = PT.PT_UNICODE | 0x3001 << 16, + PR_DISPLAY_NAME_A = PT.PT_STRING8 | 0x3001 << 16, + PR_ADDRTYPE = PT.PT_TSTRING | 0x3002 << 16, + PR_ADDRTYPE_W = PT.PT_UNICODE | 0x3002 << 16, + PR_ADDRTYPE_A = PT.PT_STRING8 | 0x3002 << 16, + PR_EMAIL_ADDRESS = PT.PT_TSTRING | 0x3003 << 16, + PR_EMAIL_ADDRESS_W = PT.PT_UNICODE | 0x3003 << 16, + PR_EMAIL_ADDRESS_A = PT.PT_STRING8 | 0x3003 << 16, + PR_COMMENT = PT.PT_TSTRING | 0x3004 << 16, + PR_COMMENT_W = PT.PT_UNICODE | 0x3004 << 16, + PR_COMMENT_A = PT.PT_STRING8 | 0x3004 << 16, + PR_DEPTH = PT.PT_LONG | 0x3005 << 16, + PR_PROVIDER_DISPLAY = PT.PT_TSTRING | 0x3006 << 16, + PR_PROVIDER_DISPLAY_W = PT.PT_UNICODE | 0x3006 << 16, + PR_PROVIDER_DISPLAY_A = PT.PT_STRING8 | 0x3006 << 16, + PR_CREATION_TIME = PT.PT_SYSTIME | 0x3007 << 16, + PR_LAST_MODIFICATION_TIME = PT.PT_SYSTIME | 0x3008 << 16, + PR_RESOURCE_FLAGS = PT.PT_LONG | 0x3009 << 16, + PR_PROVIDER_DLL_NAME = PT.PT_TSTRING | 0x300A << 16, + PR_PROVIDER_DLL_NAME_W = PT.PT_UNICODE | 0x300A << 16, + PR_PROVIDER_DLL_NAME_A = PT.PT_STRING8 | 0x300A << 16, + PR_SEARCH_KEY = PT.PT_BINARY | 0x300B << 16, + PR_PROVIDER_UID = PT.PT_BINARY | 0x300C << 16, + PR_PROVIDER_ORDINAL = PT.PT_LONG | 0x300D << 16, + + // Message store specific + PR_DEFAULT_STORE = PT.PT_BOOLEAN | 0x3400 << 16, + PR_STORE_SUPPORT_MASK = PT.PT_LONG | 0x340D << 16, + PR_STORE_STATE = PT.PT_LONG | 0x340E << 16, + + PR_IPM_SUBTREE_SEARCH_KEY = PT.PT_BINARY | 0x3410 << 16, + PR_IPM_OUTBOX_SEARCH_KEY = PT.PT_BINARY | 0x3411 << 16, + PR_IPM_WASTEBASKET_SEARCH_KEY = PT.PT_BINARY | 0x3412 << 16, + PR_IPM_SENTMAIL_SEARCH_KEY = PT.PT_BINARY | 0x3413 << 16, + PR_MDB_PROVIDER = PT.PT_BINARY | 0x3414 << 16, + PR_RECEIVE_FOLDER_SETTINGS = PT.PT_OBJECT | 0x3415 << 16, + + PR_VALID_FOLDER_MASK = PT.PT_LONG | 0x35DF << 16, + PR_IPM_SUBTREE_ENTRYID = PT.PT_BINARY | 0x35E0 << 16, + + PR_IPM_OUTBOX_ENTRYID = PT.PT_BINARY | 0x35E2 << 16, + PR_IPM_WASTEBASKET_ENTRYID = PT.PT_BINARY | 0x35E3 << 16, + PR_IPM_SENTMAIL_ENTRYID = PT.PT_BINARY | 0x35E4 << 16, + PR_VIEWS_ENTRYID = PT.PT_BINARY | 0x35E5 << 16, + PR_COMMON_VIEWS_ENTRYID = PT.PT_BINARY | 0x35E6 << 16, + PR_FINDER_ENTRYID = PT.PT_BINARY | 0x35E7 << 16, + PR_ATTACH_CONTENT_ID = PT.PT_TSTRING | (0x3712 << 16), + PR_ATTACH_CONTENT_ID_A = PT.PT_STRING8 | (0x3712 << 16), + PR_ATTACH_CONTENT_ID_W = PT.PT_TSTRING | (0x3712 << 16), + PR_ATTACH_CONTENT_LOCATION = PT.PT_TSTRING | (0x3713 << 16), + PR_ATTACH_CONTENT_LOCATION_A = PT.PT_STRING8 | (0x3713 << 16), + PR_ATTACH_CONTENT_LOCATION_W = PT.PT_TSTRING | (0x3713 << 16), + + // Message non-transmittable properties + PR_CURRENT_VERSION = PT.PT_I8 | 0x0E00 << 16, + PR_DELETE_AFTER_SUBMIT = PT.PT_BOOLEAN | 0x0E01 << 16, + PR_DISPLAY_BCC = PT.PT_TSTRING | 0x0E02 << 16, + PR_DISPLAY_BCC_W = PT.PT_UNICODE | 0x0E02 << 16, + PR_DISPLAY_BCC_A = PT.PT_STRING8 | 0x0E02 << 16, + PR_DISPLAY_CC = PT.PT_TSTRING | 0x0E03 << 16, + PR_DISPLAY_CC_W = PT.PT_UNICODE | 0x0E03 << 16, + PR_DISPLAY_CC_A = PT.PT_STRING8 | 0x0E03 << 16, + PR_DISPLAY_TO = PT.PT_TSTRING | 0x0E04 << 16, + PR_DISPLAY_TO_W = PT.PT_UNICODE | 0x0E04 << 16, + PR_DISPLAY_TO_A = PT.PT_STRING8 | 0x0E04 << 16, + PR_PARENT_DISPLAY = PT.PT_TSTRING | 0x0E05 << 16, + PR_PARENT_DISPLAY_W = PT.PT_UNICODE | 0x0E05 << 16, + PR_PARENT_DISPLAY_A = PT.PT_STRING8 | 0x0E05 << 16, + PR_MESSAGE_DELIVERY_TIME = PT.PT_SYSTIME | 0x0E06 << 16, + PR_MESSAGE_FLAGS = PT.PT_LONG | 0x0E07 << 16, + PR_MESSAGE_SIZE = PT.PT_LONG | 0x0E08 << 16, + PR_PARENT_ENTRYID = PT.PT_BINARY | 0x0E09 << 16, + PR_SENTMAIL_ENTRYID = PT.PT_BINARY | 0x0E0A << 16, + PR_CORRELATE = PT.PT_BOOLEAN | 0x0E0C << 16, + PR_CORRELATE_MTSID = PT.PT_BINARY | 0x0E0D << 16, + PR_DISCRETE_VALUES = PT.PT_BOOLEAN | 0x0E0E << 16, + PR_RESPONSIBILITY = PT.PT_BOOLEAN | 0x0E0F << 16, + PR_SPOOLER_STATUS = PT.PT_LONG | 0x0E10 << 16, + PR_TRANSPORT_STATUS = PT.PT_LONG | 0x0E11 << 16, + PR_MESSAGE_RECIPIENTS = PT.PT_OBJECT | 0x0E12 << 16, + PR_MESSAGE_ATTACHMENTS = PT.PT_OBJECT | 0x0E13 << 16, + PR_SUBMIT_FLAGS = PT.PT_LONG | 0x0E14 << 16, + PR_RECIPIENT_STATUS = PT.PT_LONG | 0x0E15 << 16, + PR_TRANSPORT_KEY = PT.PT_LONG | 0x0E16 << 16, + PR_MSG_STATUS = PT.PT_LONG | 0x0E17 << 16, + PR_MESSAGE_DOWNLOAD_TIME = PT.PT_LONG | 0x0E18 << 16, + PR_CREATION_VERSION = PT.PT_I8 | 0x0E19 << 16, + PR_MODIFY_VERSION = PT.PT_I8 | 0x0E1A << 16, + PR_HASATTACH = PT.PT_BOOLEAN | 0x0E1B << 16, + PR_BODY_CRC = PT.PT_LONG | 0x0E1C << 16, + PR_NORMALIZED_SUBJECT = PT.PT_TSTRING | 0x0E1D << 16, + PR_NORMALIZED_SUBJECT_W = PT.PT_UNICODE | 0x0E1D << 16, + PR_NORMALIZED_SUBJECT_A = PT.PT_STRING8 | 0x0E1D << 16, + PR_RTF_IN_SYNC = PT.PT_BOOLEAN | 0x0E1F << 16, + PR_ATTACH_SIZE = PT.PT_LONG | 0x0E20 << 16, + PR_ATTACH_NUM = PT.PT_LONG | 0x0E21 << 16, + PR_PREPROCESS = PT.PT_BOOLEAN | 0x0E22 << 16, + + // Message recipient properties + PR_CONTENT_INTEGRITY_CHECK = PT.PT_BINARY | 0x0C00 << 16, + PR_EXPLICIT_CONVERSION = PT.PT_LONG | 0x0C01 << 16, + PR_IPM_RETURN_REQUESTED = PT.PT_BOOLEAN | 0x0C02 << 16, + PR_MESSAGE_TOKEN = PT.PT_BINARY | 0x0C03 << 16, + PR_NDR_REASON_CODE = PT.PT_LONG | 0x0C04 << 16, + PR_NDR_DIAG_CODE = PT.PT_LONG | 0x0C05 << 16, + PR_NON_RECEIPT_NOTIFICATION_REQUESTED = PT.PT_BOOLEAN | 0x0C06 << 16, + PR_DELIVERY_POINT = PT.PT_LONG | 0x0C07 << 16, + + PR_ORIGINATOR_NON_DELIVERY_REPORT_REQUESTED = PT.PT_BOOLEAN | 0x0C08 << 16, + PR_ORIGINATOR_REQUESTED_ALTERNATE_RECIPIENT = PT.PT_BINARY | 0x0C09 << 16, + PR_PHYSICAL_DELIVERY_BUREAU_FAX_DELIVERY = PT.PT_BOOLEAN | 0x0C0A << 16, + PR_PHYSICAL_DELIVERY_MODE = PT.PT_LONG | 0x0C0B << 16, + PR_PHYSICAL_DELIVERY_REPORT_REQUEST = PT.PT_LONG | 0x0C0C << 16, + PR_PHYSICAL_FORWARDING_ADDRESS = PT.PT_BINARY | 0x0C0D << 16, + PR_PHYSICAL_FORWARDING_ADDRESS_REQUESTED = PT.PT_BOOLEAN | 0x0C0E << 16, + PR_PHYSICAL_FORWARDING_PROHIBITED = PT.PT_BOOLEAN | 0x0C0F << 16, + PR_PHYSICAL_RENDITION_ATTRIBUTES = PT.PT_BINARY | 0x0C10 << 16, + PR_PROOF_OF_DELIVERY = PT.PT_BINARY | 0x0C11 << 16, + PR_PROOF_OF_DELIVERY_REQUESTED = PT.PT_BOOLEAN | 0x0C12 << 16, + PR_RECIPIENT_CERTIFICATE = PT.PT_BINARY | 0x0C13 << 16, + PR_RECIPIENT_NUMBER_FOR_ADVICE = PT.PT_TSTRING | 0x0C14 << 16, + PR_RECIPIENT_NUMBER_FOR_ADVICE_W = PT.PT_UNICODE | 0x0C14 << 16, + PR_RECIPIENT_NUMBER_FOR_ADVICE_A = PT.PT_STRING8 | 0x0C14 << 16, + PR_RECIPIENT_TYPE = PT.PT_LONG | 0x0C15 << 16, + PR_REGISTERED_MAIL_TYPE = PT.PT_LONG | 0x0C16 << 16, + PR_REPLY_REQUESTED = PT.PT_BOOLEAN | 0x0C17 << 16, + //PR_REQUESTED_DELIVERY_METHOD = PT.PT_LONG | 0x0C18 << 16, + PR_SENDER_ENTRYID = PT.PT_BINARY | 0x0C19 << 16, + PR_SENDER_NAME = PT.PT_TSTRING | 0x0C1A << 16, + PR_SENDER_NAME_W = PT.PT_UNICODE | 0x0C1A << 16, + PR_SENDER_NAME_A = PT.PT_STRING8 | 0x0C1A << 16, + PR_SUPPLEMENTARY_INFO = PT.PT_TSTRING | 0x0C1B << 16, + PR_SUPPLEMENTARY_INFO_W = PT.PT_UNICODE | 0x0C1B << 16, + PR_SUPPLEMENTARY_INFO_A = PT.PT_STRING8 | 0x0C1B << 16, + PR_TYPE_OF_MTS_USER = PT.PT_LONG | 0x0C1C << 16, + PR_SENDER_SEARCH_KEY = PT.PT_BINARY | 0x0C1D << 16, + PR_SENDER_ADDRTYPE = PT.PT_TSTRING | 0x0C1E << 16, + PR_SENDER_ADDRTYPE_W = PT.PT_UNICODE | 0x0C1E << 16, + PR_SENDER_ADDRTYPE_A = PT.PT_STRING8 | 0x0C1E << 16, + PR_SENDER_EMAIL_ADDRESS = PT.PT_TSTRING | 0x0C1F << 16, + PR_SENDER_EMAIL_ADDRESS_W = PT.PT_UNICODE | 0x0C1F << 16, + PR_SENDER_EMAIL_ADDRESS_A = PT.PT_STRING8 | 0x0C1F << 16, + + // Message envelope properties + PR_ACKNOWLEDGEMENT_MODE = PT.PT_LONG | 0x0001 << 16, + PR_ALTERNATE_RECIPIENT_ALLOWED = PT.PT_BOOLEAN | 0x0002 << 16, + PR_AUTHORIZING_USERS = PT.PT_BINARY | 0x0003 << 16, + PR_AUTO_FORWARD_COMMENT = PT.PT_TSTRING | 0x0004 << 16, + PR_AUTO_FORWARD_COMMENT_W = PT.PT_UNICODE | 0x0004 << 16, + PR_AUTO_FORWARD_COMMENT_A = PT.PT_STRING8 | 0x0004 << 16, + PR_AUTO_FORWARDED = PT.PT_BOOLEAN | 0x0005 << 16, + PR_CONTENT_CONFIDENTIALITY_ALGORITHM_ID = PT.PT_BINARY | 0x0006 << 16, + PR_CONTENT_CORRELATOR = PT.PT_BINARY | 0x0007 << 16, + PR_CONTENT_IDENTIFIER = PT.PT_TSTRING | 0x0008 << 16, + PR_CONTENT_IDENTIFIER_W = PT.PT_UNICODE | 0x0008 << 16, + PR_CONTENT_IDENTIFIER_A = PT.PT_STRING8 | 0x0008 << 16, + PR_CONTENT_LENGTH = PT.PT_LONG | 0x0009 << 16, + PR_CONTENT_RETURN_REQUESTED = PT.PT_BOOLEAN | 0x000A << 16, + + // Message envelope properties + PR_CONVERSATION_KEY = PT.PT_BINARY | 0x000B << 16, + + PR_CONVERSION_EITS = PT.PT_BINARY | 0x000C << 16, + PR_CONVERSION_WITH_LOSS_PROHIBITED = PT.PT_BOOLEAN | 0x000D << 16, + PR_CONVERTED_EITS = PT.PT_BINARY | 0x000E << 16, + PR_DEFERRED_DELIVERY_TIME = PT.PT_SYSTIME | 0x000F << 16, + PR_DELIVER_TIME = PT.PT_SYSTIME | 0x0010 << 16, + PR_DISCARD_REASON = PT.PT_LONG | 0x0011 << 16, + PR_DISCLOSURE_OF_RECIPIENTS = PT.PT_BOOLEAN | 0x0012 << 16, + PR_DL_EXPANSION_HISTORY = PT.PT_BINARY | 0x0013 << 16, + PR_DL_EXPANSION_PROHIBITED = PT.PT_BOOLEAN | 0x0014 << 16, + PR_EXPIRY_TIME = PT.PT_SYSTIME | 0x0015 << 16, + PR_IMPLICIT_CONVERSION_PROHIBITED = PT.PT_BOOLEAN | 0x0016 << 16, + PR_IMPORTANCE = PT.PT_LONG | 0x0017 << 16, + PR_IPM_ID = PT.PT_BINARY | 0x0018 << 16, + PR_LATEST_DELIVERY_TIME = PT.PT_SYSTIME | 0x0019 << 16, + PR_MESSAGE_CLASS = PT.PT_TSTRING | 0x001A << 16, + PR_MESSAGE_CLASS_W = PT.PT_UNICODE | 0x001A << 16, + PR_MESSAGE_CLASS_A = PT.PT_STRING8 | 0x001A << 16, + PR_MESSAGE_DELIVERY_ID = PT.PT_BINARY | 0x001B << 16, + + PR_MESSAGE_SECURITY_LABEL = PT.PT_BINARY | 0x001E << 16, + PR_OBSOLETED_IPMS = PT.PT_BINARY | 0x001F << 16, + PR_ORIGINALLY_INTENDED_RECIPIENT_NAME = PT.PT_BINARY | 0x0020 << 16, + PR_ORIGINAL_EITS = PT.PT_BINARY | 0x0021 << 16, + PR_ORIGINATOR_CERTIFICATE = PT.PT_BINARY | 0x0022 << 16, + PR_ORIGINATOR_DELIVERY_REPORT_REQUESTED = PT.PT_BOOLEAN | 0x0023 << 16, + PR_ORIGINATOR_RETURN_ADDRESS = PT.PT_BINARY | 0x0024 << 16, + + PR_PARENT_KEY = PT.PT_BINARY | 0x0025 << 16, + PR_PRIORITY = PT.PT_LONG | 0x0026 << 16, + + PR_ORIGIN_CHECK = PT.PT_BINARY | 0x0027 << 16, + PR_PROOF_OF_SUBMISSION_REQUESTED = PT.PT_BOOLEAN | 0x0028 << 16, + PR_READ_RECEIPT_REQUESTED = PT.PT_BOOLEAN | 0x0029 << 16, + PR_RECEIPT_TIME = PT.PT_SYSTIME | 0x002A << 16, + PR_RECIPIENT_REASSIGNMENT_PROHIBITED = PT.PT_BOOLEAN | 0x002B << 16, + PR_REDIRECTION_HISTORY = PT.PT_BINARY | 0x002C << 16, + PR_RELATED_IPMS = PT.PT_BINARY | 0x002D << 16, + PR_ORIGINAL_SENSITIVITY = PT.PT_LONG | 0x002E << 16, + PR_LANGUAGES = PT.PT_TSTRING | 0x002F << 16, + PR_LANGUAGES_W = PT.PT_UNICODE | 0x002F << 16, + PR_LANGUAGES_A = PT.PT_STRING8 | 0x002F << 16, + PR_REPLY_TIME = PT.PT_SYSTIME | 0x0030 << 16, + PR_REPORT_TAG = PT.PT_BINARY | 0x0031 << 16, + PR_REPORT_TIME = PT.PT_SYSTIME | 0x0032 << 16, + PR_RETURNED_IPM = PT.PT_BOOLEAN | 0x0033 << 16, + PR_SECURITY = PT.PT_LONG | 0x0034 << 16, + PR_INCOMPLETE_COPY = PT.PT_BOOLEAN | 0x0035 << 16, + PR_SENSITIVITY = PT.PT_LONG | 0x0036 << 16, + PR_SUBJECT = PT.PT_TSTRING | 0x0037 << 16, + PR_SUBJECT_W = PT.PT_UNICODE | 0x0037 << 16, + PR_SUBJECT_A = PT.PT_STRING8 | 0x0037 << 16, + PR_SUBJECT_IPM = PT.PT_BINARY | 0x0038 << 16, + PR_CLIENT_SUBMIT_TIME = PT.PT_SYSTIME | 0x0039 << 16, + PR_REPORT_NAME = PT.PT_TSTRING | 0x003A << 16, + PR_REPORT_NAME_W = PT.PT_UNICODE | 0x003A << 16, + PR_REPORT_NAME_A = PT.PT_STRING8 | 0x003A << 16, + PR_SENT_REPRESENTING_SEARCH_KEY = PT.PT_BINARY | 0x003B << 16, + PR_X400_CONTENT_TYPE = PT.PT_BINARY | 0x003C << 16, + PR_SUBJECT_PREFIX = PT.PT_TSTRING | 0x003D << 16, + PR_SUBJECT_PREFIX_W = PT.PT_UNICODE | 0x003D << 16, + PR_SUBJECT_PREFIX_A = PT.PT_STRING8 | 0x003D << 16, + PR_NON_RECEIPT_REASON = PT.PT_LONG | 0x003E << 16, + PR_RECEIVED_BY_ENTRYID = PT.PT_BINARY | 0x003F << 16, + PR_RECEIVED_BY_NAME = PT.PT_TSTRING | 0x0040 << 16, + PR_RECEIVED_BY_NAME_W = PT.PT_UNICODE | 0x0040 << 16, + PR_RECEIVED_BY_NAME_A = PT.PT_STRING8 | 0x0040 << 16, + PR_SENT_REPRESENTING_ENTRYID = PT.PT_BINARY | 0x0041 << 16, + PR_SENT_REPRESENTING_NAME = PT.PT_TSTRING | 0x0042 << 16, + PR_SENT_REPRESENTING_NAME_W = PT.PT_UNICODE | 0x0042 << 16, + PR_SENT_REPRESENTING_NAME_A = PT.PT_STRING8 | 0x0042 << 16, + PR_RCVD_REPRESENTING_ENTRYID = PT.PT_BINARY | 0x0043 << 16, + PR_RCVD_REPRESENTING_NAME = PT.PT_TSTRING | 0x0044 << 16, + PR_RCVD_REPRESENTING_NAME_W = PT.PT_UNICODE | 0x0044 << 16, + PR_RCVD_REPRESENTING_NAME_A = PT.PT_STRING8 | 0x0044 << 16, + PR_REPORT_ENTRYID = PT.PT_BINARY | 0x0045 << 16, + PR_READ_RECEIPT_ENTRYID = PT.PT_BINARY | 0x0046 << 16, + PR_MESSAGE_SUBMISSION_ID = PT.PT_BINARY | 0x0047 << 16, + PR_PROVIDER_SUBMIT_TIME = PT.PT_SYSTIME | 0x0048 << 16, + PR_ORIGINAL_SUBJECT = PT.PT_TSTRING | 0x0049 << 16, + PR_ORIGINAL_SUBJECT_W = PT.PT_UNICODE | 0x0049 << 16, + PR_ORIGINAL_SUBJECT_A = PT.PT_STRING8 | 0x0049 << 16, + PR_DISC_VAL = PT.PT_BOOLEAN | 0x004A << 16, + PR_ORIG_MESSAGE_CLASS = PT.PT_TSTRING | 0x004B << 16, + PR_ORIG_MESSAGE_CLASS_W = PT.PT_UNICODE | 0x004B << 16, + PR_ORIG_MESSAGE_CLASS_A = PT.PT_STRING8 | 0x004B << 16, + PR_ORIGINAL_AUTHOR_ENTRYID = PT.PT_BINARY | 0x004C << 16, + PR_ORIGINAL_AUTHOR_NAME = PT.PT_TSTRING | 0x004D << 16, + PR_ORIGINAL_AUTHOR_NAME_W = PT.PT_UNICODE | 0x004D << 16, + PR_ORIGINAL_AUTHOR_NAME_A = PT.PT_STRING8 | 0x004D << 16, + PR_ORIGINAL_SUBMIT_TIME = PT.PT_SYSTIME | 0x004E << 16, + PR_REPLY_RECIPIENT_ENTRIES = PT.PT_BINARY | 0x004F << 16, + PR_REPLY_RECIPIENT_NAMES = PT.PT_TSTRING | 0x0050 << 16, + PR_REPLY_RECIPIENT_NAMES_W = PT.PT_UNICODE | 0x0050 << 16, + PR_REPLY_RECIPIENT_NAMES_A = PT.PT_STRING8 | 0x0050 << 16, + + PR_RECEIVED_BY_SEARCH_KEY = PT.PT_BINARY | 0x0051 << 16, + PR_RCVD_REPRESENTING_SEARCH_KEY = PT.PT_BINARY | 0x0052 << 16, + PR_READ_RECEIPT_SEARCH_KEY = PT.PT_BINARY | 0x0053 << 16, + PR_REPORT_SEARCH_KEY = PT.PT_BINARY | 0x0054 << 16, + PR_ORIGINAL_DELIVERY_TIME = PT.PT_SYSTIME | 0x0055 << 16, + PR_ORIGINAL_AUTHOR_SEARCH_KEY = PT.PT_BINARY | 0x0056 << 16, + + PR_MESSAGE_TO_ME = PT.PT_BOOLEAN | 0x0057 << 16, + PR_MESSAGE_CC_ME = PT.PT_BOOLEAN | 0x0058 << 16, + PR_MESSAGE_RECIP_ME = PT.PT_BOOLEAN | 0x0059 << 16, + + PR_ORIGINAL_SENDER_NAME = PT.PT_TSTRING | 0x005A << 16, + PR_ORIGINAL_SENDER_NAME_W = PT.PT_UNICODE | 0x005A << 16, + PR_ORIGINAL_SENDER_NAME_A = PT.PT_STRING8 | 0x005A << 16, + PR_ORIGINAL_SENDER_ENTRYID = PT.PT_BINARY | 0x005B << 16, + PR_ORIGINAL_SENDER_SEARCH_KEY = PT.PT_BINARY | 0x005C << 16, + PR_ORIGINAL_SENT_REPRESENTING_NAME = PT.PT_TSTRING | 0x005D << 16, + PR_ORIGINAL_SENT_REPRESENTING_NAME_W = PT.PT_UNICODE | 0x005D << 16, + PR_ORIGINAL_SENT_REPRESENTING_NAME_A = PT.PT_STRING8 | 0x005D << 16, + PR_ORIGINAL_SENT_REPRESENTING_ENTRYID = PT.PT_BINARY | 0x005E << 16, + PR_ORIGINAL_SENT_REPRESENTING_SEARCH_KEY = PT.PT_BINARY | 0x005F << 16, + + PR_START_DATE = PT.PT_SYSTIME | 0x0060 << 16, + PR_END_DATE = PT.PT_SYSTIME | 0x0061 << 16, + PR_OWNER_APPT_ID = PT.PT_LONG | 0x0062 << 16, + //PR_RESPONSE_REQUESTED = PT.PT_BOOLEAN | 0x0063 << 16, + + PR_SENT_REPRESENTING_ADDRTYPE = PT.PT_TSTRING | 0x0064 << 16, + PR_SENT_REPRESENTING_ADDRTYPE_W = PT.PT_UNICODE | 0x0064 << 16, + PR_SENT_REPRESENTING_ADDRTYPE_A = PT.PT_STRING8 | 0x0064 << 16, + PR_SENT_REPRESENTING_EMAIL_ADDRESS = PT.PT_TSTRING | 0x0065 << 16, + PR_SENT_REPRESENTING_EMAIL_ADDRESS_W = PT.PT_UNICODE | 0x0065 << 16, + PR_SENT_REPRESENTING_EMAIL_ADDRESS_A = PT.PT_STRING8 | 0x0065 << 16, + + PR_ORIGINAL_SENDER_ADDRTYPE = PT.PT_TSTRING | 0x0066 << 16, + PR_ORIGINAL_SENDER_ADDRTYPE_W = PT.PT_UNICODE | 0x0066 << 16, + PR_ORIGINAL_SENDER_ADDRTYPE_A = PT.PT_STRING8 | 0x0066 << 16, + PR_ORIGINAL_SENDER_EMAIL_ADDRESS = PT.PT_TSTRING | 0x0067 << 16, + PR_ORIGINAL_SENDER_EMAIL_ADDRESS_W = PT.PT_UNICODE | 0x0067 << 16, + PR_ORIGINAL_SENDER_EMAIL_ADDRESS_A = PT.PT_STRING8 | 0x0067 << 16, + + PR_ORIGINAL_SENT_REPRESENTING_ADDRTYPE = PT.PT_TSTRING | 0x0068 << 16, + PR_ORIGINAL_SENT_REPRESENTING_ADDRTYPE_W = PT.PT_UNICODE | 0x0068 << 16, + PR_ORIGINAL_SENT_REPRESENTING_ADDRTYPE_A = PT.PT_STRING8 | 0x0068 << 16, + PR_ORIGINAL_SENT_REPRESENTING_EMAIL_ADDRESS = PT.PT_TSTRING | 0x0069 << 16, + PR_ORIGINAL_SENT_REPRESENTING_EMAIL_ADDRESS_W = PT.PT_UNICODE | 0x0069 << 16, + PR_ORIGINAL_SENT_REPRESENTING_EMAIL_ADDRESS_A = PT.PT_STRING8 | 0x0069 << 16, + + PR_CONVERSATION_TOPIC = PT.PT_TSTRING | 0x0070 << 16, + PR_CONVERSATION_TOPIC_W = PT.PT_UNICODE | 0x0070 << 16, + PR_CONVERSATION_TOPIC_A = PT.PT_STRING8 | 0x0070 << 16, + PR_CONVERSATION_INDEX = PT.PT_BINARY | 0x0071 << 16, + + PR_ORIGINAL_DISPLAY_BCC = PT.PT_TSTRING | 0x0072 << 16, + PR_ORIGINAL_DISPLAY_BCC_W = PT.PT_UNICODE | 0x0072 << 16, + PR_ORIGINAL_DISPLAY_BCC_A = PT.PT_STRING8 | 0x0072 << 16, + PR_ORIGINAL_DISPLAY_CC = PT.PT_TSTRING | 0x0073 << 16, + PR_ORIGINAL_DISPLAY_CC_W = PT.PT_UNICODE | 0x0073 << 16, + PR_ORIGINAL_DISPLAY_CC_A = PT.PT_STRING8 | 0x0073 << 16, + PR_ORIGINAL_DISPLAY_TO = PT.PT_TSTRING | 0x0074 << 16, + PR_ORIGINAL_DISPLAY_TO_W = PT.PT_UNICODE | 0x0074 << 16, + PR_ORIGINAL_DISPLAY_TO_A = PT.PT_STRING8 | 0x0074 << 16, + + PR_RECEIVED_BY_ADDRTYPE = PT.PT_TSTRING | 0x0075 << 16, + PR_RECEIVED_BY_ADDRTYPE_W = PT.PT_UNICODE | 0x0075 << 16, + PR_RECEIVED_BY_ADDRTYPE_A = PT.PT_STRING8 | 0x0075 << 16, + PR_RECEIVED_BY_EMAIL_ADDRESS = PT.PT_TSTRING | 0x0076 << 16, + PR_RECEIVED_BY_EMAIL_ADDRESS_W = PT.PT_UNICODE | 0x0076 << 16, + PR_RECEIVED_BY_EMAIL_ADDRESS_A = PT.PT_STRING8 | 0x0076 << 16, + + PR_RCVD_REPRESENTING_ADDRTYPE = PT.PT_TSTRING | 0x0077 << 16, + PR_RCVD_REPRESENTING_ADDRTYPE_W = PT.PT_UNICODE | 0x0077 << 16, + PR_RCVD_REPRESENTING_ADDRTYPE_A = PT.PT_STRING8 | 0x0077 << 16, + PR_RCVD_REPRESENTING_EMAIL_ADDRESS = PT.PT_TSTRING | 0x0078 << 16, + PR_RCVD_REPRESENTING_EMAIL_ADDRESS_W = PT.PT_UNICODE | 0x0078 << 16, + PR_RCVD_REPRESENTING_EMAIL_ADDRESS_A = PT.PT_STRING8 | 0x0078 << 16, + + PR_ORIGINAL_AUTHOR_ADDRTYPE = PT.PT_TSTRING | 0x0079 << 16, + PR_ORIGINAL_AUTHOR_ADDRTYPE_W = PT.PT_UNICODE | 0x0079 << 16, + PR_ORIGINAL_AUTHOR_ADDRTYPE_A = PT.PT_STRING8 | 0x0079 << 16, + PR_ORIGINAL_AUTHOR_EMAIL_ADDRESS = PT.PT_TSTRING | 0x007A << 16, + PR_ORIGINAL_AUTHOR_EMAIL_ADDRESS_W = PT.PT_UNICODE | 0x007A << 16, + PR_ORIGINAL_AUTHOR_EMAIL_ADDRESS_A = PT.PT_STRING8 | 0x007A << 16, + + PR_ORIGINALLY_INTENDED_RECIP_ADDRTYPE = PT.PT_TSTRING | 0x007B << 16, + PR_ORIGINALLY_INTENDED_RECIP_ADDRTYPE_W = PT.PT_UNICODE | 0x007B << 16, + PR_ORIGINALLY_INTENDED_RECIP_ADDRTYPE_A = PT.PT_STRING8 | 0x007B << 16, + PR_ORIGINALLY_INTENDED_RECIP_EMAIL_ADDRESS = PT.PT_TSTRING | 0x007C << 16, + PR_ORIGINALLY_INTENDED_RECIP_EMAIL_ADDRESS_W = PT.PT_UNICODE | 0x007C << 16, + PR_ORIGINALLY_INTENDED_RECIP_EMAIL_ADDRESS_A = PT.PT_STRING8 | 0x007C << 16, + + PR_TRANSPORT_MESSAGE_HEADERS = PT.PT_TSTRING | 0x007D << 16, + PR_TRANSPORT_MESSAGE_HEADERS_W = PT.PT_UNICODE | 0x007D << 16, + PR_TRANSPORT_MESSAGE_HEADERS_A = PT.PT_STRING8 | 0x007D << 16, + + PR_DELEGATION = PT.PT_BINARY | 0x007E << 16, + + PR_TNEF_CORRELATION_KEY = PT.PT_BINARY | 0x007F << 16, + + // Message content properties + PR_BODY = PT.PT_TSTRING | 0x1000 << 16, + PR_BODY_W = PT.PT_UNICODE | 0x1000 << 16, + PR_BODY_A = PT.PT_STRING8 | 0x1000 << 16, + PR_REPORT_TEXT = PT.PT_TSTRING | 0x1001 << 16, + PR_REPORT_TEXT_W = PT.PT_UNICODE | 0x1001 << 16, + PR_REPORT_TEXT_A = PT.PT_STRING8 | 0x1001 << 16, + PR_ORIGINATOR_AND_DL_EXPANSION_HISTORY = PT.PT_BINARY | 0x1002 << 16, + PR_REPORTING_DL_NAME = PT.PT_BINARY | 0x1003 << 16, + PR_REPORTING_MTA_CERTIFICATE = PT.PT_BINARY | 0x1004 << 16, + }; + + public class OutlookUtils { + private static readonly log4net.ILog LOG = log4net.LogManager.GetLogger(typeof(OutlookUtils)); + private const uint KEEP_OPEN_READONLY = 0x00000001; + private const uint KEEP_OPEN_READWRITE = 0x00000002; + private const uint FORCE_SAVE = 0x00000004; + + #region MAPI Interface ID'S + // The Interface ID's are used to retrieve the specific MAPI Interfaces from the IUnknown Object + public const string IID_IMAPISession = "00020300-0000-0000-C000-000000000046"; + public const string IID_IMAPIProp = "00020303-0000-0000-C000-000000000046"; + public const string IID_IMAPITable = "00020301-0000-0000-C000-000000000046"; + public const string IID_IMAPIMsgStore = "00020306-0000-0000-C000-000000000046"; + public const string IID_IMAPIFolder = "0002030C-0000-0000-C000-000000000046"; + public const string IID_IMAPISpoolerService = "0002031E-0000-0000-C000-000000000046"; + public const string IID_IMAPIStatus = "0002031E-0000-0000-C000-000000000046"; + public const string IID_IMessage = "00020307-0000-0000-C000-000000000046"; + public const string IID_IAddrBook = "00020309-0000-0000-C000-000000000046"; + public const string IID_IProfSect = "00020304-0000-0000-C000-000000000046"; + public const string IID_IMAPIContainer = "0002030B-0000-0000-C000-000000000046"; + public const string IID_IABContainer = "0002030D-0000-0000-C000-000000000046"; + public const string IID_IMsgServiceAdmin = "0002031D-0000-0000-C000-000000000046"; + public const string IID_IProfAdmin = "0002031C-0000-0000-C000-000000000046"; + public const string IID_IMailUser = "0002030A-0000-0000-C000-000000000046"; + public const string IID_IDistList = "0002030E-0000-0000-C000-000000000046"; + public const string IID_IAttachment = "00020308-0000-0000-C000-000000000046"; + public const string IID_IMAPIControl = "0002031B-0000-0000-C000-000000000046"; + public const string IID_IMAPILogonRemote = "00020346-0000-0000-C000-000000000046"; + public const string IID_IMAPIForm = "00020327-0000-0000-C000-000000000046"; + #endregion + + [ComVisible(false)] + [ComImport()] + [Guid(IID_IMAPIProp)] + [InterfaceTypeAttribute(ComInterfaceType.InterfaceIsIUnknown)] + interface IMessage : IMAPIProp { + [return: MarshalAs(UnmanagedType.I4)] + [PreserveSig] + int GetAttachmentTable(); + [return: MarshalAs(UnmanagedType.I4)] + [PreserveSig] + int OpenAttach(); + [return: MarshalAs(UnmanagedType.I4)] + [PreserveSig] + int CreateAttach(); + [return: MarshalAs(UnmanagedType.I4)] + [PreserveSig] + int DeleteAttach(); + [return: MarshalAs(UnmanagedType.I4)] + [PreserveSig] + int GetRecipientTable(); + [return: MarshalAs(UnmanagedType.I4)] + [PreserveSig] + int ModifyRecipients(); + [return: MarshalAs(UnmanagedType.I4)] + [PreserveSig] + int SubmitMessage(); + [return: MarshalAs(UnmanagedType.I4)] + [PreserveSig] + int SetReadFlag(); + } + // [ComVisible(false)] + // [ComImport()] + // [Guid(IID_IMAPIFolder)] + // [InterfaceTypeAttribute(ComInterfaceType.InterfaceIsIUnknown)] + // interface IMAPIFolder : IMAPIContainer { + // [return: MarshalAs(UnmanagedType.I4)] + // [PreserveSig] + // int CreateMessage(IntPtr interf, uint uFlags, [MarshalAs(UnmanagedType.Interface)] ref IMessage pMsg); + // [return: MarshalAs(UnmanagedType.I4)] + // [PreserveSig] + // int CopyMessages(); + // [return: MarshalAs(UnmanagedType.I4)] + // [PreserveSig] + // int CreateFolder(); + // [return: MarshalAs(UnmanagedType.I4)] + // [PreserveSig] + // int CopyFolder(); + // [return: MarshalAs(UnmanagedType.I4)] + // [PreserveSig] + // int DeleteFolder(); + // [return: MarshalAs(UnmanagedType.I4)] + // [PreserveSig] + // int SetReadFlags(); + // [return: MarshalAs(UnmanagedType.I4)] + // [PreserveSig] + // int GetMessageStatus(); + // [return: MarshalAs(UnmanagedType.I4)] + // [PreserveSig] + // int SetMessageStatus(); + // [return: MarshalAs(UnmanagedType.I4)] + // [PreserveSig] + // int SaveContentsSort(); + // [return: MarshalAs(UnmanagedType.I4)] + // [PreserveSig] + // int EmptyFolder(); + // } + // [ComVisible(false)] + // [ComImport()] + // [Guid(IID_IMAPIContainer)] + // [InterfaceTypeAttribute(ComInterfaceType.InterfaceIsIUnknown)] + // interface IMAPIContainer : IMAPIProp { + // [return: MarshalAs(UnmanagedType.I4)] + // [PreserveSig] + // int GetContentsTable(uint uFlags, [MarshalAs(UnmanagedType.Interface), Out] out outlook.Table tbl); + // [return: MarshalAs(UnmanagedType.I4)] + // [PreserveSig] + // int GetHierarchyTable(); + // [return: MarshalAs(UnmanagedType.I4)] + // [PreserveSig] + // int OpenEntry(); + // [return: MarshalAs(UnmanagedType.I4)] + // [PreserveSig] + // int SetSearchCriteria(); + // [return: MarshalAs(UnmanagedType.I4)] + // [PreserveSig] + // int GetSearchCriteria(); + // } + + [ComVisible(false)] + [ComImport()] + [Guid(IID_IMAPIProp)] + [InterfaceTypeAttribute(ComInterfaceType.InterfaceIsIUnknown)] + interface IMAPIProp { + [return: MarshalAs(UnmanagedType.I4)] + [PreserveSig] + int GetLastError(); + [return: MarshalAs(UnmanagedType.I4)] + [PreserveSig] + int SaveChanges( + uint uFlags + ); + [return: MarshalAs(UnmanagedType.I4)] + [PreserveSig] + int GetProps(); + [return: MarshalAs(UnmanagedType.I4)] + [PreserveSig] + int GetPropList(); + [return: MarshalAs(UnmanagedType.I4)] + [PreserveSig] + int OpenProperty(); + [return: MarshalAs(UnmanagedType.I4)] + [PreserveSig] + int SetProps(uint values, IntPtr propArray, IntPtr problems); + [return: MarshalAs(UnmanagedType.I4)] + [PreserveSig] + int DeleteProps(); + [return: MarshalAs(UnmanagedType.I4)] + [PreserveSig] + int CopyTo(); + [return: MarshalAs(UnmanagedType.I4)] + [PreserveSig] + int CopyProps(); + [return: MarshalAs(UnmanagedType.I4)] + [PreserveSig] + int GetNamesFromIDs(); + [return: MarshalAs(UnmanagedType.I4)] + [PreserveSig] + int GetIDsFromNames(); + } + + [StructLayout(LayoutKind.Explicit)] + private struct SPropValue { + [FieldOffset(0)] + public uint propTag; + [FieldOffset(4)] + public uint alignPad; + [FieldOffset(8)] + public IntPtr Value; + [FieldOffset(8)] + public long filler; + } + + /// + /// Use MAPI32.DLL "HrGetOneProp" from managed code + /// + /// + /// + /// + public static string GetMAPIProperty(Attachment attachment, PropTags proptag) { + object mapiObject = attachment.MAPIOBJECT; + if (mapiObject == null) { + return ""; + } + + string sProperty = ""; + IntPtr pPropValue = IntPtr.Zero; + + IntPtr IUnknown = IntPtr.Zero; + IntPtr IMAPIProperty = IntPtr.Zero; + + try { + MAPIInitialize(IntPtr.Zero); + IUnknown = Marshal.GetIUnknownForObject(mapiObject); + Guid guidMAPIProp = new Guid(IID_IMAPIProp); + if (Marshal.QueryInterface(IUnknown, ref guidMAPIProp, out IMAPIProperty) != 0) { + return ""; + } + try { + HrGetOneProp(IMAPIProperty, (uint)proptag, out pPropValue); + if (pPropValue == IntPtr.Zero) { + return ""; + } + SPropValue propValue = (SPropValue)Marshal.PtrToStructure(pPropValue, typeof(SPropValue)); + sProperty = Marshal.PtrToStringUni(propValue.Value); + } catch (System.Exception ex) { + throw ex; + } + } finally { + if (pPropValue != IntPtr.Zero) { + MAPIFreeBuffer(pPropValue); + } + if (IMAPIProperty != IntPtr.Zero) { + Marshal.Release(IMAPIProperty); + } + if (IUnknown != IntPtr.Zero) { + Marshal.Release(IUnknown); + } + MAPIUninitialize(); + } + return sProperty; + } + + /// + /// Tries to save the changes we just made + /// + /// + /// + public static bool SaveChanges(MailItem mailItem) { + // Pointer to IUnknown Interface + IntPtr IUnknown = IntPtr.Zero; + // Pointer to IMAPIProp Interface + IntPtr IMAPIProp = IntPtr.Zero; + // if we have no MAPIObject everything is senseless... + if (mailItem == null) { + return false; + } + + try { + // We can pass NULL here as parameter, so we do it. + MAPIInitialize(IntPtr.Zero); + // retrive the IUnknon Interface from our MAPIObject comming from Outlook. + IUnknown = Marshal.GetIUnknownForObject(mailItem.MAPIOBJECT); + + // create a Guid that we pass to retreive the IMAPIProp Interface. + Guid guidIMAPIProp = new Guid(IID_IMAPIProp); + + // try to retrieve the IMAPIProp interface from IMessage Interface, everything else is sensless. + if (Marshal.QueryInterface(IUnknown, ref guidIMAPIProp, out IMAPIProp) != 0) { + return false; + } + IMAPIProp mapiProp = (IMAPIProp)Marshal.GetTypedObjectForIUnknown(IUnknown, typeof(IMAPIProp)); + return (mapiProp.SaveChanges(KEEP_OPEN_READWRITE) == 0); + } catch (Exception ex) { + LOG.Error(ex); + return false; + } finally { + // cleanup all references to COM Objects + if (IMAPIProp != IntPtr.Zero) Marshal.Release(IMAPIProp); + //if (IMessage != IntPtr.Zero) Marshal.Release(IMessage); + if (IUnknown != IntPtr.Zero) Marshal.Release(IUnknown); + } + } + + /// + /// Uses the IMAPIPROP.SetProps to set the content ID + /// + /// + /// + public static void SetContentID(Attachment attachment, string contentId) { + // Pointer to IUnknown Interface + IntPtr IUnknown = IntPtr.Zero; + // Pointer to IMAPIProp Interface + IntPtr IMAPIProp = IntPtr.Zero; + // A pointer that points to the SPropValue structure + IntPtr ptrPropValue = IntPtr.Zero; + // Structure that will hold the Property Value + SPropValue propValue; + // if we have no MAPIObject everything is senseless... + if (attachment == null) { + return; + } + + try { + // We can pass NULL here as parameter, so we do it. + MAPIInitialize(IntPtr.Zero); + + // retrive the IUnknon Interface from our MAPIObject comming from Outlook. + IUnknown = Marshal.GetIUnknownForObject(attachment.MAPIOBJECT); + IMAPIProp mapiProp = (IMAPIProp)Marshal.GetTypedObjectForIUnknown(IUnknown, typeof(IMAPIProp)); + + // Create structure + propValue = new SPropValue(); + propValue.propTag = (uint)PropTags.PR_ATTACH_CONTENT_ID; + //propValue.propTag = 0x3712001E; + // Create Ansi string + propValue.Value = Marshal.StringToHGlobalUni(contentId); + + // Create unmanaged memory for structure + ptrPropValue = Marshal.AllocHGlobal(Marshal.SizeOf(propValue)); + // Copy structure to unmanged memory + Marshal.StructureToPtr(propValue, ptrPropValue, false); + mapiProp.SetProps(1, ptrPropValue, IntPtr.Zero); + + propValue.propTag = (uint)PropTags.PR_ATTACH_CONTENT_LOCATION; + // Copy structure to unmanged memory + Marshal.StructureToPtr(propValue, ptrPropValue, false); + mapiProp.SetProps(1, ptrPropValue, IntPtr.Zero); + + + // Free string + Marshal.FreeHGlobal(propValue.Value); + mapiProp.SaveChanges(KEEP_OPEN_READWRITE); + } catch (Exception ex) { + LOG.Error(ex); + } finally { + // Free used Memory structures + if (ptrPropValue != IntPtr.Zero) Marshal.FreeHGlobal(ptrPropValue); + // cleanup all references to COM Objects + if (IMAPIProp != IntPtr.Zero) Marshal.Release(IMAPIProp); + //if (IMessage != IntPtr.Zero) Marshal.Release(IMessage); + if (IUnknown != IntPtr.Zero) Marshal.Release(IUnknown); + } + } + + /// + /// Use MAPI32.DLL "HrSetOneProp" from managed code + /// + /// + /// + /// + /// + public static bool SetMAPIProperty(Attachment attachment, PropTags proptag, string propertyValue) { + // Pointer to IUnknown Interface + IntPtr IUnknown = IntPtr.Zero; + // Pointer to IMAPIProp Interface + IntPtr IMAPIProp = IntPtr.Zero; + // Structure that will hold the Property Value + SPropValue propValue; + // A pointer that points to the SPropValue structure + IntPtr ptrPropValue = IntPtr.Zero; + object mapiObject = attachment.MAPIOBJECT; + // if we have no MAPIObject everything is senseless... + if (mapiObject == null) { + return false; + } + + try { + // We can pass NULL here as parameter, so we do it. + MAPIInitialize(IntPtr.Zero); + + // retrive the IUnknon Interface from our MAPIObject comming from Outlook. + IUnknown = Marshal.GetIUnknownForObject(mapiObject); + + // create a Guid that we pass to retreive the IMAPIProp Interface. + Guid guidIMAPIProp = new Guid(IID_IMAPIProp); + + // try to retrieve the IMAPIProp interface from IMessage Interface, everything else is sensless. + if (Marshal.QueryInterface(IUnknown, ref guidIMAPIProp, out IMAPIProp) != 0) { + return false; + } + + // double check, if we wave no pointer, exit... + if (IMAPIProp == IntPtr.Zero) { + return false; + } + + // Create structure + propValue = new SPropValue(); + propValue.propTag = (uint)proptag; + // Create Ansi string + propValue.Value = Marshal.StringToHGlobalUni(propertyValue); + + // Create unmanaged memory for structure + ptrPropValue = Marshal.AllocHGlobal(Marshal.SizeOf(propValue)); + // Copy structure to unmanged memory + Marshal.StructureToPtr(propValue, ptrPropValue, false); + + // Set the property + HrSetOneProp(IMAPIProp, ptrPropValue); + + // Free string + Marshal.FreeHGlobal(propValue.Value); + IMAPIProp mapiProp = (IMAPIProp)Marshal.GetTypedObjectForIUnknown(IUnknown, typeof(IMAPIProp)); + return mapiProp.SaveChanges(4) == 0; + } catch (System.Exception ex) { + LOG.Error(ex); + return false; + } finally { + // Free used Memory structures + if (ptrPropValue != IntPtr.Zero) Marshal.FreeHGlobal(ptrPropValue); + // cleanup all references to COM Objects + if (IMAPIProp != IntPtr.Zero) Marshal.Release(IMAPIProp); + //if (IMessage != IntPtr.Zero) Marshal.Release(IMessage); + if (IUnknown != IntPtr.Zero) Marshal.Release(IUnknown); + MAPIUninitialize(); + } + } + + #region MAPI DLL Imports + + [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(); + #endregion + } +} \ No newline at end of file diff --git a/GreenshotOfficePlugin/OfficeInterop/PowerpointInterop.cs b/GreenshotOfficePlugin/OfficeInterop/PowerpointInterop.cs new file mode 100644 index 000000000..41f81f3a8 --- /dev/null +++ b/GreenshotOfficePlugin/OfficeInterop/PowerpointInterop.cs @@ -0,0 +1,149 @@ +/* + * Greenshot - a free and open source screenshot tool + * Copyright (C) 2007-2012 Thomas Braun, Jens Klingen, Robin Krom + * + * For more information see: http://getgreenshot.org/ + * The Greenshot project is hosted on Sourceforge: http://sourceforge.net/projects/greenshot/ + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 1 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +using System.Collections; + +namespace Greenshot.Interop.Office { + // See http://msdn.microsoft.com/en-us/library/microsoft.office.interop.powerpoint.application_members.aspx + [ComProgId("Powerpoint.Application")] + public interface IPowerpointApplication : Common { + IPresentation ActivePresentation { get; } + IPresentations Presentations { get; } + bool Visible { get; set; } + void Activate(); + IPowerpointWindow ActiveWindow { get; } + string Version { get; } + } + + // See: http://msdn.microsoft.com/en-us/library/microsoft.office.interop.powerpoint.slides_members.aspx + public interface ISlides : Common { + int Count { get; } + ISlide Add(int Index, int layout); + } + + // See: http://msdn.microsoft.com/en-us/library/microsoft.office.interop.powerpoint.documentwindow.view.aspx + public interface IPowerpointWindow : Common { + void Activate(); + IPowerpointView View { get; } + } + // See: http://msdn.microsoft.com/en-us/library/microsoft.office.interop.powerpoint.view_members.aspx + public interface IPowerpointView : Common { + IZoom Zoom { get; } + void GotoSlide(int index); + } + + // See: http://msdn.microsoft.com/en-us/library/microsoft.office.interop.powerpoint.presentation_members.aspx + public interface IPresentation : Common { + string Name { get; } + ISlides Slides { get; } + IPowerpointApplication Application { get; } + MsoTriState ReadOnly { get; } + bool Final { get; set; } + IPageSetup PageSetup { get; } + } + + // See: http://msdn.microsoft.com/en-us/library/microsoft.office.interop.powerpoint.presentations_members.aspx + public interface IPresentations : Common, Collection { + IPresentation Add(MsoTriState WithWindow); + IPresentation item(int index); + } + + // See: http://msdn.microsoft.com/en-us/library/microsoft.office.interop.powerpoint.pagesetup_members.aspx + public interface IPageSetup : Common, Collection { + float SlideWidth { get; set; } + float SlideHeight { get; set; } + } + + // See: http://msdn.microsoft.com/en-us/library/microsoft.office.interop.powerpoint.slide_members.aspx + public interface ISlide : Common { + IShapes Shapes { get; } + void Select(); + int SlideNumber { get; } + + } + + // See: http://msdn.microsoft.com/en-us/library/microsoft.office.interop.powerpoint.shapes_members.aspx + public interface IShapes : Common, IEnumerable { + int Count { get; } + IShape item(int index); + IShape AddPicture(string FileName, MsoTriState LinkToFile, MsoTriState SaveWithDocument, float Left, float Top, float Width, float Height); + } + + // See: http://msdn.microsoft.com/en-us/library/microsoft.office.interop.powerpoint.shape_members.aspx + public interface IShape : Common { + float Left { get; set; } + float Top { get; set; } + float Width { get; set; } + float Height { get; set; } + ITextFrame TextFrame { get; } + void ScaleWidth(float Factor, MsoTriState RelativeToOriginalSize, MsoScaleFrom fScale); + void ScaleHeight(float Factor, MsoTriState RelativeToOriginalSize, MsoScaleFrom fScale); + string AlternativeText { get; set; } + MsoTriState LockAspectRatio { get; set; } + } + + public interface ITextFrame : Common { + ITextRange TextRange { get; } + MsoTriState HasText { get; } + } + public interface ITextRange : Common { + string Text { get; set; } + } + + public enum PPSlideLayout : int { + ppLayoutMixed = -2, + ppLayoutTitle = 1, + ppLayoutText = 2, + ppLayoutTwoColumnText = 3, + ppLayoutTable = 4, + ppLayoutTextAndChart = 5, + ppLayoutChartAndText = 6, + ppLayoutOrgchart = 7, + ppLayoutChart = 8, + ppLayoutTextAndClipart = 9, + ppLayoutClipartAndText = 10, + ppLayoutTitleOnly = 11, + ppLayoutBlank = 12, + ppLayoutTextAndObject = 13, + ppLayoutObjectAndText = 14, + ppLayoutLargeObject = 15, + ppLayoutObject = 16, + ppLayoutTextAndMediaClip = 17, + ppLayoutMediaClipAndText = 18, + ppLayoutObjectOverText = 19, + ppLayoutTextOverObject = 20, + ppLayoutTextAndTwoObjects = 21, + ppLayoutTwoObjectsAndText = 22, + ppLayoutTwoObjectsOverText = 23, + ppLayoutFourObjects = 24, + ppLayoutVerticalText = 25, + ppLayoutClipArtAndVerticalText = 26, + ppLayoutVerticalTitleAndText = 27, + ppLayoutVerticalTitleAndTextOverChart = 28, + ppLayoutTwoObjects = 29, + ppLayoutObjectAndTwoObjects = 30, + ppLayoutTwoObjectsAndObject = 31, + ppLayoutCustom = 32, + ppLayoutSectionHeader = 33, + ppLayoutComparison = 34, + ppLayoutContentWithCaption = 35, + ppLayoutPictureWithCaption = 36 + } +} diff --git a/GreenshotOfficePlugin/OfficeInterop/WordInterop.cs b/GreenshotOfficePlugin/OfficeInterop/WordInterop.cs new file mode 100644 index 000000000..31745f300 --- /dev/null +++ b/GreenshotOfficePlugin/OfficeInterop/WordInterop.cs @@ -0,0 +1,84 @@ +/* + * Greenshot - a free and open source screenshot tool + * Copyright (C) 2007-2012 Thomas Braun, Jens Klingen, Robin Krom + * + * For more information see: http://getgreenshot.org/ + * The Greenshot project is hosted on Sourceforge: http://sourceforge.net/projects/greenshot/ + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 1 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +namespace Greenshot.Interop.Office { + // See http://msdn.microsoft.com/de-de/library/microsoft.office.interop.word.applicationclass_members%28v=Office.11%29.aspx + [ComProgId("Word.Application")] + public interface IWordApplication : Common { + IWordDocument ActiveDocument { get; } + ISelection Selection { get; } + IDocuments Documents { get; } + bool Visible { get; set; } + void Activate(); + string Version { get; } + } + + // See: http://msdn.microsoft.com/de-de/library/microsoft.office.interop.word.documents_members(v=office.11).aspx + public interface IDocuments : Common, Collection { + IWordDocument Add(ref object Template, ref object NewTemplate, ref object DocumentType, ref object Visible); + IWordDocument item(int index); + } + + // See: http://msdn.microsoft.com/en-us/library/microsoft.office.interop.word.document.aspx + public interface IWordDocument : Common { + void Activate(); + IWordApplication Application { get; } + IWordWindow ActiveWindow { get; } + bool ReadOnly { get; } + + // Only 2007 and later! + bool Final { get; set; } + } + + // See: http://msdn.microsoft.com/en-us/library/microsoft.office.interop.word.window_members.aspx + public interface IWordWindow : Common { + IPane ActivePane { get; } + void Activate(); + string Caption { + get; + } + } + + // See: http://msdn.microsoft.com/en-us/library/microsoft.office.interop.word.pane_members.aspx + public interface IPane : Common { + IWordView View { get; } + } + + // See: http://msdn.microsoft.com/en-us/library/microsoft.office.interop.word.view_members.aspx + public interface IWordView : Common { + IZoom Zoom { get; } + } + + // See: http://msdn.microsoft.com/en-us/library/microsoft.office.interop.word.zoom_members.aspx + public interface IZoom : Common { + int Percentage { get; set; } + } + + // See: http://msdn.microsoft.com/de-de/library/microsoft.office.interop.word.selection_members(v=office.11).aspx + public interface ISelection : Common { + IInlineShapes InlineShapes { get; } + void InsertAfter(string text); + } + + public interface IInlineShapes : Common { + object AddPicture(string FileName, object LinkToFile, object SaveWithDocument, object Range); + } +}