[C#/COMMON/OUTLOOK] MAPIFolder 인터페이스 : 전체 폴더 경로를 사용해 폴더 구하기
■ MAPIFolder 인터페이스를 사용해 전체 폴더 경로를 사용해 폴더를 구하는 방법을 보여준다. ▶ MAPIFolder 인터페이스 : 전체 폴더 경로를 사용해 폴더 구하기
■ MAPIFolder 인터페이스를 사용해 전체 폴더 경로를 사용해 폴더를 구하는 방법을 보여준다. ▶ MAPIFolder 인터페이스 : 전체 폴더 경로를 사용해 폴더 구하기
■ ExplorerEvents_10_Event 인터페이스의 Close 이벤트를 사용해 프로그램 종료시 처리하는 방법을 보여준다. ▶ 예제 코드 (C#)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 |
using Microsoft.Office.Interop.Outlook; /// <summary> /// 탐색기 /// </summary> private Explorer explorer = null; #region 탐색기 닫는 경우 처리하기 - explorer_Close() /// <summary> /// 탐색기 닫는 경우 처리하기 /// </summary> private void explorer_Close() { System.Windows.Forms.MessageBox.Show("탐색기를 닫습니다."); } #endregion this.explorer = Application.ActiveExplorer(); ((ExplorerEvents_10_Event)this.explorer).Close += explorer_Close; |
■ MailItem 인터페이스를 사용해 EML 파일을 저장하는 방법을 보여준다. ▶ RibbonContextMenu.xml
1 2 3 4 5 6 7 8 9 10 11 12 |
<?xml version="1.0" encoding="UTF-8"?> <customUI xmlns="http://schemas.microsoft.com/office/2009/07/customui" onLoad="customUI_onLoad"> <contextMenus> <contextMenu idMso="ContextMenuMailItem"> <button id="saveEMLFileButton" label="EML 파일 저장하기" onAction="contextMenu_onAction" /> </contextMenu> </contextMenus> </customUI> |
▶ RibbonContextMenu.cs
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 |
using Microsoft.Office.Core; using Microsoft.Office.Interop.Outlook; using System; using System.Collections.Generic; using System.IO; using System.Reflection; using System.Runtime.InteropServices; using System.Windows.Forms; using MimeKit; namespace TestProject { /// <summary> /// 리본 컨텍스트 메뉴 /// </summary> [ComVisible(true)] public class RibbonContextMenu : IRibbonExtensibility { //////////////////////////////////////////////////////////////////////////////////////////////////// Field ////////////////////////////////////////////////////////////////////////////////////////// Private #region Field /// <summary> /// 리본 UI /// </summary> private IRibbonUI ribbonUI; #endregion //////////////////////////////////////////////////////////////////////////////////////////////////// Constructor ////////////////////////////////////////////////////////////////////////////////////////// Public #region 생성자 - RibbonContextMenu() /// <summary> /// 생성자 /// </summary> public RibbonContextMenu() { } #endregion //////////////////////////////////////////////////////////////////////////////////////////////////// Method ////////////////////////////////////////////////////////////////////////////////////////// Public //////////////////////////////////////////////////////////////////////////////// Event #region 커스텀 UI 로드시 처리하기 - customUI_onLoad(ribbonUI) /// <summary> /// 커스텀 UI 로드시 처리하기 /// </summary> /// <param name="ribbonUI">리본 UI</param> public void customUI_onLoad(IRibbonUI ribbonUI) { this.ribbonUI = ribbonUI; } #endregion #region 컨텍스트 메뉴 작업시 처리하기 - contextMenu_onAction(ribbonControl) /// <summary> /// 컨텍스트 메뉴 작업시 처리하기 /// </summary> /// <param name="ribbonControl">리본 컨트롤</param> public void contextMenu_onAction(IRibbonControl ribbonControl) { switch(ribbonControl.Id) { case "saveEMLFileButton" : try { dynamic itemCollection = ribbonControl.Context; foreach(dynamic item in itemCollection) { if(item is MailItem mailItem) { SaveEMLFile(mailItem, "d:\\test.eml"); } } } catch(System.Exception exception) { MessageBox.Show($"예외가 발생하였습니다.\r\n{exception.ToString()}"); } break; } } #endregion //////////////////////////////////////////////////////////////////////////////// Function #region (IRibbonExtensibility) 커스텀 UI 구하기 - GetCustomUI(ribbonID) /// <summary> /// 커스텀 UI 구하기 /// </summary> /// <param name="ribbonID">리본 ID</param> /// <returns>커스텀 UI</returns> public string GetCustomUI(string ribbonID) { return ribbonID.Equals("Microsoft.Outlook.Explorer") ? GetResourceText("TestProject.RibbonContextMenu.xml") : null; } #endregion ////////////////////////////////////////////////////////////////////////////////////////// Private //////////////////////////////////////////////////////////////////////////////// Function #region 리소스 텍스트 구하기 - GetResourceText(resourceName) /// <summary> /// 리소스 텍스트 구하기 /// </summary> /// <param name="resourceName">리소스명</param> /// <returns>리소스 텍스트</returns> private static string GetResourceText(string resourceName) { Assembly assembly = Assembly.GetExecutingAssembly(); string[] resourceNameArray = assembly.GetManifestResourceNames(); int count = resourceNameArray.Length; for(int i = 0; i < count; ++i) { if(string.Compare(resourceName, resourceNameArray[i], StringComparison.OrdinalIgnoreCase) == 0) { using(StreamReader reader = new StreamReader(assembly.GetManifestResourceStream(resourceNameArray[i]))) { if(reader != null) { return reader.ReadToEnd(); } } } } return null; } #endregion #region EML 파일 저장하기 - SaveEMLFile(mailItem, filePath) /// <summary> /// EML 파일 저장하기 /// </summary> /// <param name="mailItem">메일 항목</param> /// <param name="filePath">파일 경로</param> private void SaveEMLFile(MailItem mailItem, string filePath) { System.Net.Mail.MailMessage mailMessage = new System.Net.Mail.MailMessage(); mailMessage.Subject = mailItem.Subject; mailMessage.From = new System.Net.Mail.MailAddress(mailItem.Sender.Address, mailItem.Sender.Name); mailMessage.IsBodyHtml = mailItem.BodyFormat == OlBodyFormat.olFormatHTML; mailMessage.Body = mailItem.BodyFormat == OlBodyFormat.olFormatHTML ? mailItem.HTMLBody : mailItem.Body; foreach(Recipient recipient in mailItem.Recipients) { if(recipient.Type == (int)OlMailRecipientType.olTo) { mailMessage.To.Add(new System.Net.Mail.MailAddress(recipient.Address, recipient.Name)); } else if(recipient.Type == (int)OlMailRecipientType.olCC) { mailMessage.CC.Add(new System.Net.Mail.MailAddress(recipient.Address, recipient.Name)); } else if(recipient.Type == (int)OlMailRecipientType.olBCC) { mailMessage.Bcc.Add(new System.Net.Mail.MailAddress(recipient.Address, recipient.Name)); } } List<string> temporaryDirectoryPathList = new List<string>(); try { foreach(Attachment attachment in mailItem.Attachments) { #region 임시 디렉토리 경로를 설정한다. string temporaryDirectoryPath = Path.Combine(Path.GetTempPath(), "Temp", Guid.NewGuid().ToString()); #endregion #region 임시 디렉토리 경로를 생성한다. if(!Directory.Exists(temporaryDirectoryPath)) { Directory.CreateDirectory(temporaryDirectoryPath); } #endregion temporaryDirectoryPathList.Add(temporaryDirectoryPath); #region 첨부 파일을 저장한다. string attachmentFilePath = Path.Combine(temporaryDirectoryPath, attachment.FileName); attachment.SaveAsFile(attachmentFilePath); #endregion #region MIME 타입을 설정한다. string fileExtension = Path.GetExtension(attachment.FileName); string mimeType = MIMETypeHelper.GetMIMEType(fileExtension); #endregion mailMessage.Attachments.Add(new System.Net.Mail.Attachment(attachmentFilePath, mimeType)); } MimeMessage mimeMessage = (MimeMessage)mailMessage; mimeMessage.Date = mailItem.CreationTime; mimeMessage.WriteTo(filePath); mailMessage.Dispose(); } finally { foreach(string path in temporaryDirectoryPathList) { if(Directory.Exists(path)) { Directory.Delete(path, true); } } } } #endregion } } |
▶ CustomAddIn.cs
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 |
using Microsoft.Office.Core; using System; namespace TestProject { /// <summary> /// 커스텀 애드인 /// </summary> public partial class CustomAddIn { //////////////////////////////////////////////////////////////////////////////////////////////////// Method ////////////////////////////////////////////////////////////////////////////////////////// Protected #region 리본 확장성 객체 생성하기 - CreateRibbonExtensibilityObject() /// <summary> /// 리본 확장성 객체 생성하기 /// </summary> /// <returns>리본 확장성 인터페이스 객체</returns> protected override IRibbonExtensibility CreateRibbonExtensibilityObject() { return new RibbonContextMenu(); } #endregion ////////////////////////////////////////////////////////////////////////////////////////// Private #region 커스텀 애드인 시작시 처리하기 - CustomAddIn_Startup(sender, e) /// <summary> /// 커스텀 애드인 시작시 처리하기 /// </summary> /// <param name="sender">이벤트 발생자</param> /// <param name="e">이벤트 인자</param> private void CustomAddIn_Startup(object sender, EventArgs e) { } #endregion #region 커스텀 애드인 셧다운시 처리하기 - CustomAddIn_Shutdown(sender, e) /// <summary> /// 커스텀 애드인 셧다운시 처리하기 /// </summary> /// <param name="sender">이벤트 발생자</param> /// <param name="e">이벤트 인자</param> private void CustomAddIn_Shutdown(object sender, EventArgs e) { } #endregion #region VSTO에서 생성한 코드 /// <summary> /// 디자이너 지원에 필요한 메서드입니다. /// 이 메서드의 내용을 코드 편집기로 수정하지 마세요. /// </summary> private void InternalStartup() { this.Startup += new EventHandler(CustomAddIn_Startup ); this.Shutdown += new EventHandler(CustomAddIn_Shutdown); } #endregion } } |
TestProject.zip
■ NameSpace 인터페이스의 Accounts 속성/GetDefaultFolder 메소드를 사용해 메일 계정별 디폴트 폴더를 구하는 방법을 보여준다. ▶ 예제 코드 (C#)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 |
using Microsoft.Office.Interop.Outlook; using System; using System.Text; using System.Windows.Forms; OlDefaultFolders[] defaultFolderArray = (OlDefaultFolders[])Enum.GetValues(typeof(OlDefaultFolders)); StringBuilder stringBuilder = new StringBuilder(); foreach(Account account in Application.Session.Accounts) { stringBuilder.AppendLine(account.DisplayName); foreach(OlDefaultFolders defaultFolder in defaultFolderArray) { try { MAPIFolder folder = account.Session.GetDefaultFolder(defaultFolder); stringBuilder.AppendLine(folder.FullFolderPath); } catch { } } } MessageBox.Show(stringBuilder.ToString()); |
※ Application은 Microsoft.Office.Tools.Outlook.OutlookAddInBase
■ Account 인터페이스의 Session 속성을 사용해 해당 메일 계정의 받은 편지함 폴더를 구하는 방법을 보여준다. ▶ 예제 코드 (C#)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 |
using Microsoft.Office.Interop.Outlook; using System.Text; using System.Windows.Forms; StringBuilder stringBuilder = new StringBuilder(); foreach(Account account in Application.Session.Accounts) { stringBuilder.AppendLine(account.DisplayName); MAPIFolder folder = account.Session.GetDefaultFolder(OlDefaultFolders.olFolderInbox); stringBuilder.AppendLine($" {folder.FullFolderPath}"); } MessageBox.Show(stringBuilder.ToString()); |
※ Application은
■ NameSpace 인터페이스의 GetDefaultFolder 메소드를 사용해 디폴트 폴더를 구하는 방법을 보여준다. ▶ 예제 코드 (C#)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 |
using Microsoft.Office.Interop.Outlook; using System; using System.Text; using System.Windows.Forms; OlDefaultFolders[] defaultFolderArray = (OlDefaultFolders[])Enum.GetValues(typeof(OlDefaultFolders)); StringBuilder stringBuilder = new StringBuilder(); foreach(OlDefaultFolders defaultFolder in defaultFolderArray) { try { Folder folder = (Folder)Application.ActiveExplorer().Session.GetDefaultFolder(defaultFolder); stringBuilder.AppendLine(folder.Name); } catch { } } MessageBox.Show(stringBuilder.ToString()); |
※ Application은 Microsoft.Office.Tools.Outlook.OutlookAddInBase 클래스의 속성이다.
■ MAPIFolderEvents_12_Event 인터페이스의 BeforeFolderMove/BeforeItemMove 이벤트를 사용해 폴더/메일 삭제/이동을 방지하는 방법을 보여준다. (기능 개선) ▶ ConstantHelper.cs
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 |
namespace TestProject { /// <summary> /// 상수 헬퍼 /// </summary> public static class ConstantHelper { //////////////////////////////////////////////////////////////////////////////////////////////////// Method ////////////////////////////////////////////////////////////////////////////////////////// Static //////////////////////////////////////////////////////////////////////////////// Public #region Field /// <summary> /// Sales Force 폴더명 /// </summary> public static readonly string SalesForceFolderName = "Sales Force"; #endregion } } |
▶ SessionExtensions.cs
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 |
using Microsoft.Office.Interop.Outlook; namespace TestProject { /// <summary> /// 세션 확장 /// </summary> public static class SessionExtensions { //////////////////////////////////////////////////////////////////////////////////////////////////// Method ////////////////////////////////////////////////////////////////////////////////////////// Static //////////////////////////////////////////////////////////////////////////////// Public #region Sales Force 폴더 생성하기 - CreatSalesForceFolders(session) /// <summary> /// Sales Force 폴더 생성하기 /// </summary> /// <param name="session">세션</param> public static void CreatSalesForceFolders(this NameSpace session) { foreach(Folder rootFolder in session.Folders) { if(!rootFolder.HasFolder(ConstantHelper.SalesForceFolderName)) { rootFolder.AddFolder(ConstantHelper.SalesForceFolderName); } } } #endregion } } |
▶ MAPIFolderExtensions.cs
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 |
using Microsoft.Office.Interop.Outlook; namespace TestProject { /// <summary> /// MAPI 폴더 확장 /// </summary> public static class MAPIFolderExtensions { //////////////////////////////////////////////////////////////////////////////////////////////////// Method ////////////////////////////////////////////////////////////////////////////////////////// Static //////////////////////////////////////////////////////////////////////////////// Public #region 폴더 소유 여부 구하기 - HasFolder(rootFolder, targetFolderName) /// <summary> /// 폴더 소유 여부 구하기 /// </summary> /// <param name="rootFolder">루트 폴더</param> /// <param name="targetFolderName">타겟 폴더명</param> /// <returns>폴더 소유 여부</returns> public static bool HasFolder(this MAPIFolder rootFolder, string targetFolderName) { foreach(Folder folder in rootFolder.Folders) { if(folder.Name == targetFolderName) { return true; } } return false; } #endregion #region 폴더 구하기 - GetFolder(rootFolder, targetFolderName) /// <summary> /// 폴더 구하기 /// </summary> /// <param name="rootFolder">루트 폴더</param> /// <param name="targetFolderName">타겟 폴더명</param> /// <returns>폴더</returns> public static Folder GetFolder(this MAPIFolder rootFolder, string targetFolderName) { foreach(Folder folder in rootFolder.Folders) { if(folder.Name == targetFolderName) { return folder; } } return null; } #endregion #region 폴더 추가하기 - AddFolder(parentFolder, folderName) /// <summary> /// 폴더 추가하기 /// </summary> /// <param name="parentFolder">부모 폴더</param> /// <param name="folderName">폴더명</param> /// <returns>MAPI 폴더</returns> public static MAPIFolder AddFolder(this MAPIFolder parentFolder, string folderName) { MAPIFolder folder = parentFolder.Folders.Add(folderName, OlDefaultFolders.olFolderInbox); return folder; } #endregion } } |
■ 폴더/메일 항목에 사용자 속성을 추가/조회/삭제하는 방법을 보여준다. ▶ PictureConverter.cs
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 |
using System; using System.Drawing; using System.Runtime.InteropServices; namespace TestProject { /// <summary> /// PICTURE 변환자 /// </summary> public static class PictureConverter { //////////////////////////////////////////////////////////////////////////////////////////////////// Class ////////////////////////////////////////////////////////////////////////////////////////// Static //////////////////////////////////////////////////////////////////////////////// Private #region 그림 설명 - PICTDESC /// <summary> /// 그림 설명 /// </summary> private static class PICTDESC { //////////////////////////////////////////////////////////////////////////////////////////////////// Field ////////////////////////////////////////////////////////////////////////////////////////// Static //////////////////////////////////////////////////////////////////////////////// Public #region Field /// <summary> /// PICTYPE_UNINITIALIZED /// </summary> public const short PICTYPE_UNINITIALIZED = -1; /// <summary> /// PICTYPE_NONE /// </summary> public const short PICTYPE_NONE = 0; /// <summary> /// PICTYPE_BITMAP /// </summary> public const short PICTYPE_BITMAP = 1; /// <summary> /// PICTYPE_METAFILE /// </summary> public const short PICTYPE_METAFILE = 2; /// <summary> /// PICTYPE_ICON /// </summary> public const short PICTYPE_ICON = 3; /// <summary> /// PICTYPE_ENHMETAFILE /// </summary> public const short PICTYPE_ENHMETAFILE = 4; #endregion //////////////////////////////////////////////////////////////////////////////////////////////////// Class ////////////////////////////////////////////////////////////////////////////////////////// Public #region 아이콘 - Icno /// <summary> /// 아이콘 /// </summary> [StructLayout(LayoutKind.Sequential)] public class Icon { //////////////////////////////////////////////////////////////////////////////////////////////////// Field ////////////////////////////////////////////////////////////////////////////////////////// Public #region Field /// <summary> /// 크기 /// </summary> public int Size = Marshal.SizeOf(typeof(PICTDESC.Icon)); /// <summary> /// 그림 타입 /// </summary> public int PictureType = PICTDESC.PICTYPE_ICON; /// <summary> /// 아이콘 핸들 /// </summary> public IntPtr IconHandle = IntPtr.Zero; /// <summary> /// 미사용 1 /// </summary> public int Unused1 = 0; /// <summary> /// 미사용 2 /// </summary> public int Unused2 = 0; #endregion //////////////////////////////////////////////////////////////////////////////////////////////////// Constructor ////////////////////////////////////////////////////////////////////////////////////////// Public #region 생성자 - Icon(icon) /// <summary> /// 생성자 /// </summary> /// <param name="icon">아이콘</param> public Icon(System.Drawing.Icon icon) { IconHandle = icon.ToBitmap().GetHicon(); } #endregion } #endregion #region 비트맵 - Bitmap /// <summary> /// 비트맵 /// </summary> [StructLayout(LayoutKind.Sequential)] public class Bitmap { //////////////////////////////////////////////////////////////////////////////////////////////////// Field ////////////////////////////////////////////////////////////////////////////////////////// Public #region Field /// <summary> /// 크기 /// </summary> public int Size = Marshal.SizeOf(typeof(PICTDESC.Bitmap)); /// <summary> /// 그림 타입 /// </summary> public int PictureType = PICTDESC.PICTYPE_BITMAP; /// <summary> /// 비트맵 핸들 /// </summary> public IntPtr BitmapHandle = IntPtr.Zero; /// <summary> /// 팔레트 핸들 /// </summary> public IntPtr PaletteHandle = IntPtr.Zero; /// <summary> /// 미사용 /// </summary> public int Unused = 0; #endregion //////////////////////////////////////////////////////////////////////////////////////////////////// Constructor ////////////////////////////////////////////////////////////////////////////////////////// Public #region 생성자 - Bitmap(bitmap) /// <summary> /// 생성자 /// </summary> public Bitmap(System.Drawing.Bitmap bitmap) { BitmapHandle = bitmap.GetHbitmap(); } #endregion } #endregion } #endregion //////////////////////////////////////////////////////////////////////////////////////////////////// Import ////////////////////////////////////////////////////////////////////////////////////////// Static //////////////////////////////////////////////////////////////////////////////// Private #region OLE 그림 생성하기 (간접) - OleCreatePictureIndirect(pictureDescription, interfaceID, own); /// <summary> /// OLE 그림 생성하기 (간접) /// </summary> /// <param name="pictureDescription">그림 설명</param> /// <param name="interfaceID">인터페이스 ID</param> /// <param name="own">소유 여부</param> /// <returns>IPictureDisp 인터페이스 객체</returns> [DllImport("OleAut32.dll", EntryPoint = "OleCreatePictureIndirect", ExactSpelling = true, PreserveSig = false)] private static extern stdole.IPictureDisp OleCreatePictureIndirect ( [MarshalAs(UnmanagedType.AsAny)] object pictureDescription, ref Guid interfaceID, bool own ); #endregion //////////////////////////////////////////////////////////////////////////////////////////////////// Field ////////////////////////////////////////////////////////////////////////////////////////// Static //////////////////////////////////////////////////////////////////////////////// Private #region Field /// <summary> /// IPictureDisp 인터페이스 GUID /// </summary> private static Guid _iPictureDispGUID = typeof(stdole.IPictureDisp).GUID; #endregion //////////////////////////////////////////////////////////////////////////////////////////////////// Method ////////////////////////////////////////////////////////////////////////////////////////// Static //////////////////////////////////////////////////////////////////////////////// Public #region IPictureDisp 인터페이스 객체 구하기 - ToPicture(icon) /// <summary> /// IPictureDisp 인터페이스 객체 구하기 /// </summary> /// <param name="icon">아이콘</param> /// <returns>IPictureDisp 인터페이스 객체</returns> public static stdole.IPictureDisp ToPicture(Icon icon) { PICTDESC.Icon pictDescIcon = new PICTDESC.Icon(icon); return OleCreatePictureIndirect(pictDescIcon, ref _iPictureDispGUID, true); } #endregion #region IPictureDisp 인터페이스 객체 구하기 - ToPicture(image) /// <summary> /// IPictureDisp 인터페이스 객체 구하기 /// </summary> /// <param name="image">이미지</param> /// <returns>IPictureDisp 인터페이스 객체</returns> public static stdole.IPictureDisp ToPicture(Image image) { Bitmap bitmap = (image is Bitmap) ? (Bitmap)image : new Bitmap(image); PICTDESC.Bitmap pictDescBitmap = new PICTDESC.Bitmap(bitmap); return OleCreatePictureIndirect(pictDescBitmap, ref _iPictureDispGUID, true); } #endregion } } |
▶ FolderExtension.cs
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 |
using Microsoft.Office.Interop.Outlook; using System.Drawing; namespace TestProject { /// <summary> /// 폴더 확장 /// </summary> public static class FolderExtension { //////////////////////////////////////////////////////////////////////////////////////////////////// Field ////////////////////////////////////////////////////////////////////////////////////////// Static //////////////////////////////////////////////////////////////////////////////// Private #region Field /// <summary> /// 속성 스키마 헤더 /// </summary> private static string _propertySchemaHeader = "http://schemas.microsoft.com/mapi/string/{C18E58E4-1F09-44BD-85AA-D5E2641EBA4D}/"; #endregion //////////////////////////////////////////////////////////////////////////////////////////////////// Method ////////////////////////////////////////////////////////////////////////////////////////// Static //////////////////////////////////////////////////////////////////////////////// Private #region 사용자 속성 값 설정하기 - SetUserPropertyValue(folder, propertyName, propertyValue) /// <summary> /// 사용자 속성 값 설정하기 /// </summary> /// <param name="folder">폴더</param> /// <param name="propertyName">속성명</param> /// <param name="propertyValue">속성값</param> public static void SetUserPropertyValue(this Folder folder, string propertyName, object propertyValue) { folder?.PropertyAccessor?.SetProperty($"{_propertySchemaHeader}{propertyName}", propertyValue); } #endregion #region 사용자 속성 값 구하기 - GetUserPropertyValue(folder, propertyName) /// <summary> /// 사용자 속성 값 구하기 /// </summary> /// <param name="folder">폴더</param> /// <param name="propertyName">속성명</param> /// <returns>사용자 속성 값</returns> public static object GetUserPropertyValue(this Folder folder, string propertyName) { return folder?.PropertyAccessor?.GetProperty($"{_propertySchemaHeader}{propertyName}"); } #endregion #region 사용자 속성 값 소유 여부 구하기 - HasUserPropertyValue(folder, propertyName) /// <summary> /// 사용자 속성 값 소유 여부 구하기 /// </summary> /// <param name="folder">폴더</param> /// <param name="propertyName">속성명</param> /// <returns>사용자 속성 값 소유 여부</returns> public static bool HasUserPropertyValue(this Folder folder, string propertyName) { try { return GetUserPropertyValue(folder, propertyName) != null ? true : false; } catch(System.Exception) { return false; } } #endregion #region 사용자 속성 삭제하기 - DeleteUserProperty(folder, propertyName) /// <summary> /// 사용자 속성 삭제하기 /// </summary> /// <param name="folder">폴더</param> /// <param name="propertyName">속성명</param> public static void DeleteUserProperty(this Folder folder, string propertyName) { folder?.PropertyAccessor?.DeleteProperty($"{_propertySchemaHeader}{propertyName}"); } #endregion #region 아이콘 설정하기 - SetIcon(folder, bitmap) /// <summary> /// 아이콘 설정하기 /// </summary> /// <param name="folder">폴더</param> /// <param name="iconBitmap">비트맵</param> public static void SetIcon(this Folder folder, Bitmap bitmap) { stdole.StdPicture picture = PictureConverter.ToPicture(bitmap) as stdole.StdPicture; folder.SetCustomIcon(picture); } #endregion #region 아이콘 설정하기 - SetIcon(folder, icon) /// <summary> /// 아이콘 설정하기 /// </summary> /// <param name="folder">폴더</param> /// <param name="icon">아이콘</param> public static void SetIcon(this Folder folder, Icon icon) { stdole.StdPicture picture = PictureConverter.ToPicture(icon) as stdole.StdPicture; folder.SetCustomIcon(picture); } #endregion #region 아이콘 삭제하기 - DeleteIcon(folder) /// <summary> /// 아이콘 삭제하기 /// </summary> /// <param name="folder">폴더</param> public static void DeleteIcon(this Folder folder) { folder.SetCustomIcon(null); } #endregion } } |
▶ MailItemExtension.cs
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 |
using Microsoft.Office.Interop.Outlook; namespace TestProject { /// <summary> /// 메일 항목 확장 /// </summary> public static class MailItemExtension { //////////////////////////////////////////////////////////////////////////////////////////////////// Field ////////////////////////////////////////////////////////////////////////////////////////// Static //////////////////////////////////////////////////////////////////////////////// Private #region Field /// <summary> /// 속성 스키마 헤더 /// </summary> private static string _propertySchemaHeader = "http://schemas.microsoft.com/mapi/string/{2ECFB886-7542-463C-8D56-0F9C29D02368}/"; #endregion //////////////////////////////////////////////////////////////////////////////////////////////////// Method ////////////////////////////////////////////////////////////////////////////////////////// Static //////////////////////////////////////////////////////////////////////////////// Private #region 사용자 속성 값 설정하기 - SetUserPropertyValue(mailItem, propertyName, propertyValue) /// <summary> /// 사용자 속성 값 설정하기 /// </summary> /// <param name="mailItem">메일 항목</param> /// <param name="propertyName">속성명</param> /// <param name="propertyValue">속성값</param> public static void SetUserPropertyValue(this MailItem mailItem, string propertyName, object propertyValue) { mailItem?.PropertyAccessor?.SetProperty($"{_propertySchemaHeader}{propertyName}", propertyValue); } #endregion #region 사용자 속성 값 구하기 - GetUserPropertyValue(mailItem, propertyName) /// <summary> /// 사용자 속성 값 구하기 /// </summary> /// <param name="mailItem">메일 항목</param> /// <param name="propertyName">속성명</param> /// <returns>사용자 속성 값</returns> public static object GetUserPropertyValue(this MailItem mailItem, string propertyName) { return mailItem?.PropertyAccessor?.GetProperty($"{_propertySchemaHeader}{propertyName}"); } #endregion #region 사용자 속성 값 소유 여부 구하기 - HasUserPropertyValue(mailItem, propertyName) /// <summary> /// 사용자 속성 값 소유 여부 구하기 /// </summary> /// <param name="mailItem">메일 항목</param> /// <param name="propertyName">속성명</param> /// <returns>사용자 속성 값 소유 여부</returns> public static bool HasUserPropertyValue(this MailItem mailItem, string propertyName) { try { return GetUserPropertyValue(mailItem, propertyName) != null ? true : false; } catch(System.Exception) { return false; } } #endregion #region 사용자 속성 삭제하기 - DeleteUserProperty(mailItem, propertyName) /// <summary> /// 사용자 속성 삭제하기 /// </summary> /// <param name="mailItem">메일 항목</param> /// <param name="propertyName">속성명</param> public static void DeleteUserProperty(this MailItem mailItem, string propertyName) { mailItem?.PropertyAccessor?.DeleteProperty($"{_propertySchemaHeader}{propertyName}"); } #endregion #region 아이콘 설정하기 - SetIcon(mailItem, iconIndex) /// <summary> /// 아이콘 설정하기 /// </summary> /// <param name="mailItem">메일 항목</param> /// <param name="iconIndex">아이콘 인덱스</param> public static void SetIcon(this MailItem mailItem, int iconIndex) { mailItem.PropertyAccessor.SetProperty("http://schemas.microsoft.com/mapi/proptag/0x10800003", iconIndex); mailItem.Save(); } #endregion #region 아이콘 삭제하기 - DeleteIcon(mailItem) /// <summary> /// 아이콘 삭제하기 /// </summary> /// <param name="mailItem">메일 항목</param> public static void DeleteIcon(this MailItem mailItem) { SetIcon(mailItem, 315); } #endregion #region 체크 아이콘 설정하기 - SetCheckIcon(mailItem) /// <summary> /// 체크 아이콘 설정하기 /// </summary> /// <param name="mailItem">메일 항목</param> public static void SetCheckIcon(this MailItem mailItem) { SetIcon(mailItem, 311); } #endregion } } |
▶ RibbonContextMenu.xml
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 |
<?xml version="1.0" encoding="UTF-8"?> <customUI xmlns="http://schemas.microsoft.com/office/2009/07/customui" onLoad="customUI_onLoad"> <contextMenus> <contextMenu idMso="ContextMenuFolder"> <button id="setFolderUserPropertyValueButton" label="사용자 속성 값 설정하기" getVisible="contextMenu_getVisible" onAction="contextMenu_onAction" /> <button id="getFolderUserPropertyValueButton" label="사용자 속성 값 구하기" getVisible="contextMenu_getVisible" onAction="contextMenu_onAction" /> <button id="deleteFolderUserPropertyButton" label="사용자 속성 삭제하기" getVisible="contextMenu_getVisible" onAction="contextMenu_onAction" /> </contextMenu> <contextMenu idMso="ContextMenuMailItem"> <button id="setMailItemUserPropertyValueButton" label="사용자 속성 값 설정하기" getVisible="contextMenu_getVisible" onAction="contextMenu_onAction" /> <button id="getMailItemUserPropertyValueButton" label="사용자 속성 값 구하기" getVisible="contextMenu_getVisible" onAction="contextMenu_onAction" /> <button id="deleteMailItemUserPropertyButton" label="사용자 속성 삭제하기" getVisible="contextMenu_getVisible" onAction="contextMenu_onAction" /> </contextMenu> <contextMenu idMso="ContextMenuMultipleItems"> <button id="setMailItemUserPropertyValuesButton" label="사용자 속성 값 설정하기" getVisible="contextMenu_getVisible" onAction="contextMenu_onAction" /> <button id="getMailItemUserPropertyValuesButton" label="사용자 속성 값 구하기" getVisible="contextMenu_getVisible" onAction="contextMenu_onAction" /> <button id="deleteMailItemUserPropertiesButton" label="사용자 속성 삭제하기" getVisible="contextMenu_getVisible" onAction="contextMenu_onAction" /> </contextMenu> </contextMenus> </customUI> |
▶ RibbonContextMenu.cs
■ MAPIFolder 인터페이스의 PropertyAccessor 속성을 사용해 사용자 속성을 추가/조회/삭제하는 방법을 보여준다. ▶ RibbonContextMenu.xml
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 |
<?xml version="1.0" encoding="UTF-8"?> <customUI xmlns="http://schemas.microsoft.com/office/2009/07/customui" onLoad="customUI_Load"> <contextMenus> <contextMenu idMso="ContextMenuFolder"> <button id="setFolderUserPropertyContextMenu" label="폴더 사용자 속성 설정하기" getVisible="folderContextMenu_getVisible" onAction="folderContextMenu_onAction" /> <button id="getFolderUserPropertyContextMenu" label="폴더 사용자 속성 가져오기" getVisible="folderContextMenu_getVisible" onAction="folderContextMenu_onAction" /> <button id="deleteFolderUserPropertyContextMenu" label="폴더 사용자 속성 제거하기" getVisible="folderContextMenu_getVisible" onAction="folderContextMenu_onAction" /> </contextMenu> </contextMenus> </customUI> |
▶ RibbonContextMenu.cs
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 |
using Microsoft.Office.Core; using Microsoft.Office.Interop.Outlook; using System; using System.IO; using System.Reflection; using System.Runtime.InteropServices; namespace TestProject { /// <summary> /// 리본 컨텍스트 메뉴 /// </summary> [ComVisible(true)] public class RibbonContextMenu : IRibbonExtensibility { //////////////////////////////////////////////////////////////////////////////////////////////////// Field ////////////////////////////////////////////////////////////////////////////////////////// Private #region Field /// <summary> /// 리본 UID /// </summary> private IRibbonUI ribbonUI; /// <summary> /// 폴더 속성 스키마입니다. /// </summary> private string folderPropertySchema = "http://schemas.microsoft.com/mapi/string/{F0974C06-6AD7-4ADF-B334-78C4B3B15B87}/CUSTOM-TAG"; #endregion //////////////////////////////////////////////////////////////////////////////////////////////////// Constructor ////////////////////////////////////////////////////////////////////////////////////////// Public #region 생성자 - RibbonContextMenu() /// <summary> /// 생성자 /// </summary> public RibbonContextMenu() { } #endregion //////////////////////////////////////////////////////////////////////////////////////////////////// Method ////////////////////////////////////////////////////////////////////////////////////////// Public //////////////////////////////////////////////////////////////////////////////// Event #region 커스텀 UI 로드시 처리하기 - customUI_Load(ribbonUI) /// <summary> /// 커스텀 UI 로드시 처리하기 /// </summary> /// <param name="ribbonUI">리본 UI</param> public void customUI_Load(IRibbonUI ribbonUI) { this.ribbonUI = ribbonUI; } #endregion #region 폴더 컨텍스트 메뉴 표시 여부 구하기 - folderContextMenu_getVisible(ribbonControl) /// <summary> /// 폴더 컨텍스트 메뉴 표시 여부 구하기 /// </summary> /// <param name="ribbonControl">리본 컨트롤</param> /// <returns>처리 결과</returns> public bool folderContextMenu_getVisible(IRibbonControl ribbonControl) { string id = ribbonControl.Id; if(id == "setFolderUserPropertyContextMenu") { try { Folder folder = ribbonControl.Context as Folder; PropertyAccessor propertyAccessor = folder?.PropertyAccessor; dynamic propertyValue = propertyAccessor?.GetProperty(folderPropertySchema); } catch { return true; } return false; } else if(id == "getFolderUserPropertyContextMenu" || id == "deleteFolderUserPropertyContextMenu") { try { Folder folder = ribbonControl.Context as Folder; PropertyAccessor propertyAccessor = folder?.PropertyAccessor; dynamic propertyValue = propertyAccessor?.GetProperty(folderPropertySchema); } catch { return false; } return true; } return false; } #endregion #region 폴더 컨텍스트 메뉴 작업시 처리하기 - folderContextMenu_onAction(ribbonControl) /// <summary> /// 폴더 컨텍스트 메뉴 작업시 처리하기 /// </summary> /// <param name="ribbonControl">리본 컨트롤</param> public void folderContextMenu_onAction(IRibbonControl ribbonControl) { string id = ribbonControl.Id; if(id == "setFolderUserPropertyContextMenu") { try { Folder folder = ribbonControl.Context as Folder; PropertyAccessor propertyAccessor = folder?.PropertyAccessor; propertyAccessor?.SetProperty(folderPropertySchema, DateTime.Now.ToString()); dynamic propertyValue = propertyAccessor?.GetProperty(folderPropertySchema); System.Windows.Forms.MessageBox.Show($"사용자 속성을 설정하였습니다.\r\n폴더 : {folder.Name}\r\n사용자 속성값 : {propertyValue}"); } catch(System.Exception exception) { System.Windows.Forms.MessageBox.Show($"예외가 발생하였습니다.\r\n{exception.ToString()}"); } } else if(id == "getFolderUserPropertyContextMenu") { try { Folder folder = ribbonControl.Context as Folder; PropertyAccessor propertyAccessor = folder?.PropertyAccessor; dynamic propertyValue = propertyAccessor?.GetProperty(folderPropertySchema); System.Windows.Forms.MessageBox.Show($"사용자 속성을 가져왔습니다.\r\n폴더 : {folder.Name}\r\n사용자 속성값 : {propertyValue}"); } catch(System.Exception exception) { System.Windows.Forms.MessageBox.Show($"예외가 발생하였습니다.\r\n{exception.ToString()}"); } } else if(id == "deleteFolderUserPropertyContextMenu") { try { Folder folder = ribbonControl.Context as Folder; PropertyAccessor propertyAccessor = folder?.PropertyAccessor; propertyAccessor?.DeleteProperty(folderPropertySchema); System.Windows.Forms.MessageBox.Show($"사용자 속성을 제거하였습니다.\r\n폴더 : {folder.Name}"); } catch(System.Exception exception) { System.Windows.Forms.MessageBox.Show($"예외가 발생하였습니다.\r\n{exception.ToString()}"); } } } #endregion //////////////////////////////////////////////////////////////////////////////// Function #region (IRibbonExtensibility) 커스텀 UI 구하기 - GetCustomUI(ribbonID) /// <summary> /// 커스텀 UI 구하기 /// </summary> /// <param name="ribbonID"></param> /// <returns>커스텀 UI</returns> public string GetCustomUI(string ribbonID) { return GetResourceText("TestProject.RibbonContextMenu.xml"); } #endregion ////////////////////////////////////////////////////////////////////////////////////////// Private //////////////////////////////////////////////////////////////////////////////// Function #region 리소스 텍스트 구하기 - GetResourceText(resourceName) /// <summary> /// 리소스 텍스트 구하기 /// </summary> /// <param name="resourceName">리소스명</param> /// <returns>리소스 텍스트</returns> private static string GetResourceText(string resourceName) { Assembly assembly = Assembly.GetExecutingAssembly(); string[] resourceNameArray = assembly.GetManifestResourceNames(); for(int i = 0; i < resourceNameArray.Length; ++i) { if(string.Compare(resourceName, resourceNameArray[i], StringComparison.OrdinalIgnoreCase) == 0) { using(StreamReader resourceReader = new StreamReader(assembly.GetManifestResourceStream(resourceNameArray[i]))) { if(resourceReader != null) { return resourceReader.ReadToEnd(); } } } } return null; } #endregion } } |
▶ CustomAddIn.cs
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 |
using Microsoft.Office.Core; using System; namespace TestProject { /// <summary> /// 커스텀 애드인 /// </summary> public partial class CustomAddIn { //////////////////////////////////////////////////////////////////////////////////////////////////// Method ////////////////////////////////////////////////////////////////////////////////////////// Protected #region 리본 확장성 객체 생성하기 - CreateRibbonExtensibilityObject() /// <summary> /// 리본 확장성 객체 생성하기 /// </summary> /// <returns>리본 확장성 인터페이스 객체</returns> protected override IRibbonExtensibility CreateRibbonExtensibilityObject() { return new RibbonContextMenu(); } #endregion ////////////////////////////////////////////////////////////////////////////////////////// Private #region 커스텀 애드인 시작시 처리하기 - CustomAddIn_Startup(sender, e) /// <summary> /// 커스텀 애드인 시작시 처리하기 /// </summary> /// <param name="sender">이벤트 발생자</param> /// <param name="e">이벤트 인자</param> private void CustomAddIn_Startup(object sender, EventArgs e) { } #endregion #region 커스텀 애드인 셧다운시 처리하기 - CustomAddIn_Shutdown(sender, e) /// <summary> /// 커스텀 애드인 셧다운시 처리하기 /// </summary> /// <param name="sender">이벤트 발생자</param> /// <param name="e">이벤트 인자</param> private void CustomAddIn_Shutdown(object sender, EventArgs e) { } #endregion #region VSTO에서 생성한 코드 /// <summary> /// 디자이너 지원에 필요한 메서드입니다. /// 이 메서드의 내용을 코드 편집기로 수정하지 마세요. /// </summary> private void InternalStartup() { this.Startup += new System.EventHandler(CustomAddIn_Startup); this.Shutdown += new System.EventHandler(CustomAddIn_Shutdown); } #endregion } } |
TestProject.zip
■ MAPIFolder 인터페이스의 GetStorage 메소드를 사용해 폴더 사용자 속성을 추가/조회하는 방법을 보여준다. ▶ CustomAddIn.cs
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 |
using Microsoft.Office.Interop.Outlook; using System; namespace TestProject { /// <summary> /// 커스텀 애드인 /// </summary> public partial class CustomAddIn { //////////////////////////////////////////////////////////////////////////////////////////////////// Method ////////////////////////////////////////////////////////////////////////////////////////// Private #region 커스텀 애드인 시작시 처리하기 - CustomAddIn_Startup(sender, e) /// <summary> /// 커스텀 애드인 시작시 처리하기 /// </summary> /// <param name="sender">이벤트 발생자</param> /// <param name="e">이벤트 인자</param> private void CustomAddIn_Startup(object sender, EventArgs e) { try { string parentFolderName = "세일즈포스"; string childFolderName = "테스트"; string storageIdentifier = "SalesForce"; string propertyName = "SFID"; string propertyValue = "SFID3"; Folder parentFolder = Application.ActiveExplorer().Session.Folders[1].Folders[parentFolderName] as Folder; Folder childFolder = parentFolder.Folders[childFolderName] as Folder; StorageItem storageItem = childFolder.GetStorage(storageIdentifier, OlStorageIdentifierType.olIdentifyBySubject); UserProperty property1 = storageItem.UserProperties[propertyName]; if(property1 == null) { System.Windows.Forms.MessageBox.Show($"{childFolderName} 폴더에 {propertyName} 속성이 없습니다."); } else { System.Windows.Forms.MessageBox.Show($"{childFolderName} 폴더의 {propertyName} 속성 값은 [{property1.Value}] 입니다."); return; } storageItem.UserProperties.Add(propertyName, OlUserPropertyType.olText).Value = propertyValue; storageItem.Save(); System.Windows.Forms.MessageBox.Show($"{childFolderName} 폴더의 {propertyName} 속성에 [{propertyValue}] 값을 추가했습니다."); UserProperty property2 = storageItem.UserProperties[propertyName]; if(property2 == null) { System.Windows.Forms.MessageBox.Show($"{childFolderName} 폴더에 {propertyName} 속성이 없습니다."); } else { System.Windows.Forms.MessageBox.Show($"{childFolderName} 폴더의 {propertyName} 속성 값은 [{property2.Value}] 입니다."); } } catch(System.Exception exception) { System.Windows.Forms.MessageBox.Show(exception.ToString()); } } #endregion #region 커스텀 애드인 셧다운시 처리하기 - CustomAddIn_Shutdown(sender, e) /// <summary> /// 커스텀 애드인 셧다운시 처리하기 /// </summary> /// <param name="sender">이벤트 발생자</param> /// <param name="e">이벤트 인자</param> private void CustomAddIn_Shutdown(object sender, EventArgs e) { } #endregion #region VSTO에서 생성한 코드 /// <summary> /// 디자이너 지원에 필요한 메서드입니다. /// 이 메서드의 내용을 코드 편집기로 수정하지 마세요. /// </summary> private void InternalStartup() { this.Startup += new System.EventHandler(CustomAddIn_Startup ); this.Shutdown += new System.EventHandler(CustomAddIn_Shutdown); } #endregion } } |
TestProject.zip
■ MAPIFolder 인터페이스의 GetStorage 메소드를 사용해 폴더 사용자 속성 값을 제거하는 방법을 보여준다. ▶ 예제 코드 (C#)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 |
using Microsoft.Office.Interop.Outlook; Folder parentFolder = Application.ActiveExplorer().Session.Folders[1].Folders["Sales Force"] as Folder; Folder testFolder = parentFolder.Folders["Test"] as Folder; StorageItem storageItem = testFolder.GetStorage("SalesForce", OlStorageIdentifierType.olIdentifyBySubject); UserProperty property = storageItem.UserProperties["SFID"]; if(property != null) { property.Delete(); storageItem.Save(); } |
※ 첫번째 계정 아래에
■ MAPIFolder 인터페이스의 GetStorage 메소드를 사용해 폴더 사용자 속성 값을 구하는 방법을 보여준다. ▶ 예제 코드 (C#)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 |
using Microsoft.Office.Interop.Outlook; Folder parentFolder = Application.ActiveExplorer().Session.Folders[1].Folders["Sales Force"] as Folder; Folder testFolder = parentFolder.Folders["Test"] as Folder; StorageItem storageItem = testFolder.GetStorage("SalesForce", OlStorageIdentifierType.olIdentifyBySubject); UserProperty property = storageItem.UserProperties["SFID"]; if(property == null) { System.Windows.Forms.MessageBox.Show("null"); } else { System.Windows.Forms.MessageBox.Show(property.Value); } |
※ 첫번째 계정 아래에
■ MAPIFolder 인터페이스의 GetStorage 메소드를 사용해 폴더 사용자 속성 값을 추가하는 방법을 보여준다. ▶ 예제 코드 (C#)
1 2 3 4 5 6 7 8 9 10 11 12 13 |
using Microsoft.Office.Interop.Outlook; Folder parentFolder = Application.ActiveExplorer().Session.Folders[1].Folders["Sales Force"] as Folder; Folder testFolder = parentFolder.Folders["Test"] as Folder; StorageItem storageItem = testFolder.GetStorage("SalesForce", OlStorageIdentifierType.olIdentifyBySubject); storageItem.UserProperties.Add("SFID", OlUserPropertyType.olText).Value = "SFID3"; storageItem.Save(); |
※ 첫번째 계정 아래에
■ ExplorerEvents_10_Event 인터페이스의 FolderSwitch 이벤트를 사용하는 방법을 보여준다. ▶ CustomAddIn.cs
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 |
using Microsoft.Office.Interop.Outlook; using System; using System.Windows.Forms; namespace TestProject { /// <summary> /// 커스텀 애드인 /// </summary> public partial class CustomAddIn { //////////////////////////////////////////////////////////////////////////////////////////////////// Field ////////////////////////////////////////////////////////////////////////////////////////// Private #region Field /// <summary> /// 탐색기 /// </summary> private Explorer explorer; /// <summary> /// 현재 폴더 /// </summary> private Folder currentFolder; #endregion //////////////////////////////////////////////////////////////////////////////////////////////////// Method ////////////////////////////////////////////////////////////////////////////////////////// Private //////////////////////////////////////////////////////////////////////////////// Event #region 커스텀 애드인 시작시 처리하기 - CustomAddIn_Startup(sender, e) /// <summary> /// 커스텀 애드인 시작시 처리하기 /// </summary> /// <param name="sender">이벤트 발생자</param> /// <param name="e">이벤트 인자</param> private void CustomAddIn_Startup(object sender, EventArgs e) { this.explorer = Application.ActiveExplorer(); this.explorer.FolderSwitch += explorer_FolderSwitch; } #endregion #region 커스텀 애드인 셧다운시 처리하기 - CustomAddIn_Shutdown(sender, e) /// <summary> /// 커스텀 애드인 셧다운시 처리하기 /// </summary> /// <param name="sender">이벤트 발생자</param> /// <param name="e">이벤트 인자</param> private void CustomAddIn_Shutdown(object sender, EventArgs e) { } #endregion #region 현재 폴더 항목 이동 전 처리하기 - currentFolder_BeforeItemMove(item, targetFolder, cancel) /// <summary> /// 현재 폴더 항목 이동 전 처리하기 /// </summary> /// <param name="item">항목</param> /// <param name="targetFolder">타겟 폴더</param> /// <param name="cancel">취소 여부</param> private void currentFolder_BeforeItemMove(object item, MAPIFolder targetFolder, ref bool cancel) { cancel = true; } #endregion #region 현재 폴더 이동 전 처리하기 - currentFolder_BeforeFolderMove(targetFolder, cancel) /// <summary> /// 현재 폴더 이동 전 처리하기 /// </summary> /// <param name="targetFolder">타겟 폴더</param> /// <param name="cancel">취소 여부</param> private void currentFolder_BeforeFolderMove(MAPIFolder targetFolder, ref bool cancel) { cancel = true; } #endregion #region 탐색기 폴더 전환시 처리하기 - explorer_FolderSwitch() /// <summary> /// 탐색기 폴더 전환시 처리하기 /// </summary> private void explorer_FolderSwitch() { this.currentFolder = this.explorer.CurrentFolder as Folder; this.currentFolder.BeforeFolderMove += currentFolder_BeforeFolderMove; this.currentFolder.BeforeItemMove += currentFolder_BeforeItemMove; } #endregion //////////////////////////////////////////////////////////////////////////////// Function #region VSTO에서 생성한 코드 /// <summary> /// 디자이너 지원에 필요한 메서드입니다. /// 이 메서드의 내용을 코드 편집기로 수정하지 마세요. /// </summary> private void InternalStartup() { this.Startup += new System.EventHandler(CustomAddIn_Startup ); this.Shutdown += new System.EventHandler(CustomAddIn_Shutdown); } #endregion } } |
TestProject.zip
■ Explorer 인터페이스의 Selection 속성을 사용하는 방법을 보여준다. ▶ 예제 코드 (C#)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
using Microsoft.Office.Interop.Outlook; Explorer explorer = Application.ActiveExplorer(); Selection selection = explorer.Selection; if(selection.Count > 0) { foreach(MailItem mailItem in selection) { //... } } |
■ Explorer 인터페이스의 Selection 속성을 사용해 선택 메일 항목의 열거 가능형을 구하는 방법을 보여준다. ▶ 예제 코드 (C#)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 |
using Microsoft.Office.Interop.Outlook; using System.Collections.Generic; #region 선택 메일 항목 열거 가능형 구하기 - GetSelectedMailItemEnumerable() /// <summary> /// 선택 메일 항목 열거 가능형 구하기 /// </summary> /// <returns>선택된 메일 항목 열거 가능형</returns> public IEnumerable<MailItem> GetSelectedMailItemEnumerable() { foreach(MailItem mailItem in new Application().ActiveExplorer().Selection) { yield return mailItem; } } #endregion |
■ 메일 컨텍스트 메뉴에서 커스텀 컨텍스트 메뉴를 추가하는 방법을 보여준다. ▶ RibbonContextMenu.xml
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 |
<?xml version="1.0" encoding="UTF-8"?> <customUI xmlns="http://schemas.microsoft.com/office/2009/07/customui" onLoad="customUI_Load"> <ribbon> </ribbon> <contextMenus> <contextMenu idMso="ContextMenuMailItem"> <button id="customContextMenu1" label="커스텀 컨텍스트 메뉴 1" getVisible="customContextMenu_GetVisible" onAction="customContextMenu1_Click"/> </contextMenu> <contextMenu idMso="ContextMenuMultipleItems"> <button id="customContextMenu2" label="커스텀 컨텍스트 메뉴 2" getVisible="customContextMenu_GetVisible" onAction="customContextMenu2_Click"/> </contextMenu> </contextMenus> </customUI> |
▶ RibbonContextMenu.cs
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 |
using Microsoft.Office.Core; using Microsoft.Office.Interop.Outlook; using System; using System.IO; using System.Reflection; using System.Runtime.InteropServices; namespace TestProject { /// <summary> /// 리본 컨텍스트 메뉴 /// </summary> [ComVisible(true)] public class RibbonContextMenu : IRibbonExtensibility { //////////////////////////////////////////////////////////////////////////////////////////////////// Field ////////////////////////////////////////////////////////////////////////////////////////// Private #region Field /// <summary> /// 리본 UI /// </summary> private IRibbonUI ribbonUI; #endregion //////////////////////////////////////////////////////////////////////////////////////////////////// Constructor ////////////////////////////////////////////////////////////////////////////////////////// Public #region 생성자 - RibbonContextMenu() /// <summary> /// 생성자 /// </summary> public RibbonContextMenu() { } #endregion //////////////////////////////////////////////////////////////////////////////////////////////////// Method ////////////////////////////////////////////////////////////////////////////////////////// Public #region (IRibbonExtensibility) 커스텀 UI 구하기 - GetCustomUI(ribbonID) /// <summary> /// 커스텀 UI 구하기 /// </summary> /// <param name="ribbonID">리본 ID</param> /// <returns>커스텀 UI</returns> public string GetCustomUI(string ribbonID) { return GetResourceText("TestProject.RibbonContextMenu.xml"); } #endregion #region 커스텀 UI 로드시 처리하기 - customUI_Load(ribbonUI) /// <summary> /// 커스텀 UI 로드시 처리하기 /// </summary> /// <param name="ribbonUI">리본 UI 인터페이스 객체</param> public void customUI_Load(IRibbonUI ribbonUI) { this.ribbonUI = ribbonUI; } #endregion #region 커스텀 컨텍스트 메뉴 표시 여부 구하기 - customContextMenu_GetVisible(ribbonControl) /// <summary> /// 커스텀 컨텍스트 메뉴 표시 여부 구하기 /// </summary> /// <param name="ribbonControl">리본 컨트롤</param> /// <returns>처리 결과</returns> public bool customContextMenu_GetVisible(IRibbonControl ribbonControl) { string id = ribbonControl.Id; if(id == "customContextMenu1" || id == "customContextMenu2") { dynamic items = ribbonControl.Context; foreach(dynamic item in items) { if(item is MailItem mailItem && mailItem.Parent is Folder folder && folder.FullFolderPath.Contains("받은 편지함")) { return true; } break; } } return false; } #endregion #region 커스텀 컨텍스트 메뉴 1 클릭시 처리하기 - customContextMenu1Click(ribbonControl) /// <summary> /// 커스텀 컨텍스트 메뉴 1 클릭시 처리하기 /// </summary> /// <param name="ribbonControl">리본 컨트롤</param> public void customContextMenu1_Click(IRibbonControl ribbonControl) { if(ribbonControl.Id == "customContextMenu1") { System.Windows.Forms.MessageBox.Show("커스텀 컨텍스트 메뉴 1을 클릭했습니다."); } } #endregion #region 커스텀 컨텍스트 메뉴 2 클릭시 처리하기 - customContextMenu2_Click(ribbonControl) /// <summary> /// 커스텀 컨텍스트 메뉴 2 클릭시 처리하기 /// </summary> /// <param name="ribbonControl">리본 컨트롤</param> public void customContextMenu2_Click(IRibbonControl ribbonControl) { if(ribbonControl.Id == "customContextMenu2") { System.Windows.Forms.MessageBox.Show("커스텀 컨텍스트 메뉴 2를 클릭했습니다."); } } #endregion ////////////////////////////////////////////////////////////////////////////////////////// Private #region 리소스 텍스트 구하기 - GetResourceText(resourceName) /// <summary> /// 리소스 텍스트 구하기 /// </summary> /// <param name="resourceName">리소스명</param> /// <returns>리소스 텍스트</returns> private static string GetResourceText(string resourceName) { Assembly assembly = Assembly.GetExecutingAssembly(); string[] resourceNameArray = assembly.GetManifestResourceNames(); for(int i = 0; i < resourceNameArray.Length; ++i) { if(string.Compare(resourceName, resourceNameArray[i], StringComparison.OrdinalIgnoreCase) == 0) { using(StreamReader resourceReader = new StreamReader(assembly.GetManifestResourceStream(resourceNameArray[i]))) { if(resourceReader != null) { return resourceReader.ReadToEnd(); } } } } return null; } #endregion } } |
▶ CustomAddIn.cs
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 |
using Microsoft.Office.Core; using System; namespace TestProject { /// <summary> /// 커스텀 애드인 /// </summary> public partial class CustomAddIn { //////////////////////////////////////////////////////////////////////////////////////////////////// Method ////////////////////////////////////////////////////////////////////////////////////////// Protected //////////////////////////////////////////////////////////////////////////////// Function #region 리본 확장성 객체 생성하기 - CreateRibbonExtensibilityObject() /// <summary> /// 리본 확장성 객체 생성하기 /// </summary> /// <returns>리본 확장성 인터페이스 객체</returns> protected override IRibbonExtensibility CreateRibbonExtensibilityObject() { return new RibbonContextMenu(); } #endregion ////////////////////////////////////////////////////////////////////////////////////////// Private //////////////////////////////////////////////////////////////////////////////// Event #region 커스텀 애드인 시작시 처리하기 - CustomAddIn_Startup(sender, e) /// <summary> /// 커스텀 애드인 시작시 처리하기 /// </summary> /// <param name="sender">이벤트 발생자</param> /// <param name="e">이벤트 인자</param> private void CustomAddIn_Startup(object sender, EventArgs e) { } #endregion #region 커스텀 애드인 셧다운시 처리하기 - CustomAddIn_Shutdown(sender, e) /// <summary> /// 커스텀 애드인 셧다운시 처리하기 /// </summary> /// <param name="sender">이벤트 발생자</param> /// <param name="e">이벤트 인자</param> private void CustomAddIn_Shutdown(object sender, EventArgs e) { } #endregion //////////////////////////////////////////////////////////////////////////////// Function #region VSTO에서 생성한 코드 /// <summary> /// 디자이너 지원에 필요한 메서드입니다. /// 이 메서드의 내용을 코드 편집기로 수정하지 마세요. /// </summary> private void InternalStartup() { this.Startup += new System.EventHandler(CustomAddIn_Startup ); this.Shutdown += new System.EventHandler(CustomAddIn_Shutdown); } #endregion } } |
TestProject.zip
■ 폴더 컨텍스트 메뉴에서 커스텀 컨텍스트 메뉴를 추가하는 방법을 보여준다. (기능 개선) ▶ RibbonContextMenu.xml
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 |
<?xml version="1.0" encoding="UTF-8"?> <customUI xmlns="http://schemas.microsoft.com/office/2009/07/customui" onLoad="customUI_Load"> <ribbon> </ribbon> <contextMenus> <contextMenu idMso="ContextMenuFolder"> <button id="customContextMenu1" label="커스텀 컨텍스트 메뉴 1" getVisible="customContextMenu_GetVisible" onAction="customContextMenu1_Click" /> <button id="customContextMenu2" label="커스텀 컨텍스트 메뉴 2" getVisible="customContextMenu_GetVisible" onAction="customContextMenu2_Click" /> </contextMenu> </contextMenus> </customUI> |
▶ RibbonContextMenu.cs
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 |
using Microsoft.Office.Core; using Microsoft.Office.Interop.Outlook; using System; using System.IO; using System.Reflection; using System.Runtime.InteropServices; namespace TestProject { /// <summary> /// 리본 컨텍스트 메뉴 /// </summary> [ComVisible(true)] public class RibbonContextMenu : IRibbonExtensibility { //////////////////////////////////////////////////////////////////////////////////////////////////// Field ////////////////////////////////////////////////////////////////////////////////////////// Private #region Field /// <summary> /// 리본 UI /// </summary> private IRibbonUI ribbonUI; #endregion //////////////////////////////////////////////////////////////////////////////////////////////////// Constructor ////////////////////////////////////////////////////////////////////////////////////////// Public #region 생성자 - RibbonContextMenu() /// <summary> /// 생성자 /// </summary> public RibbonContextMenu() { } #endregion //////////////////////////////////////////////////////////////////////////////////////////////////// Method ////////////////////////////////////////////////////////////////////////////////////////// Public #region (IRibbonExtensibility) 커스텀 UI 구하기 - GetCustomUI(ribbonID) /// <summary> /// 커스텀 UI 구하기 /// </summary> /// <param name="ribbonID">리본 ID</param> /// <returns>커스텀 UI</returns> public string GetCustomUI(string ribbonID) { return GetResourceText("TestProject.RibbonContextMenu.xml"); } #endregion #region 커스텀 UI 로드시 처리하기 - customUI_Load(ribbonUI) /// <summary> /// 커스텀 UI 로드시 처리하기 /// </summary> /// <param name="ribbonUI">리본 UI 인터페이스 객체</param> public void customUI_Load(IRibbonUI ribbonUI) { this.ribbonUI = ribbonUI; } #endregion #region 커스텀 컨텍스트 메뉴 표시 여부 구하기 - customContextMenu_GetVisible(ribbonControl) /// <summary> /// 커스텀 컨텍스트 메뉴 표시 여부 구하기 /// </summary> /// <param name="ribbonControl">리본 컨트롤</param> /// <returns>처리 결과</returns> public bool customContextMenu_GetVisible(IRibbonControl ribbonControl) { string id = ribbonControl.Id; string folderName = ((Folder)ribbonControl.Context).Name; if(id == "customContextMenu1" && folderName == "받은 편지함") { return true; } if(id == "customContextMenu2" && folderName == "보낼 편지함") { return true; } return false; } #endregion #region 커스텀 컨텍스트 메뉴 1 클릭시 처리하기 - customContextMenu1_Click(ribbonControl) /// <summary> /// 커스텀 컨텍스트 메뉴 1 클릭시 처리하기 /// </summary> /// <param name="ribbonControl">리본 컨트롤</param> public void customContextMenu1_Click(IRibbonControl ribbonControl) { if(ribbonControl.Id == "customContextMenu1") { System.Windows.Forms.MessageBox.Show("커스텀 컨텍스트 메뉴 1을 클릭했습니다."); } } #endregion #region 커스텀 컨텍스트 메뉴 2 클릭시 처리하기 - customContextMenu2_Click(ribbonControl) /// <summary> /// 커스텀 컨텍스트 메뉴 2 클릭시 처리하기 /// </summary> /// <param name="ribbonControl">리본 컨트롤</param> public void customContextMenu2_Click(IRibbonControl ribbonControl) { if(ribbonControl.Id == "customContextMenu2") { System.Windows.Forms.MessageBox.Show("커스텀 컨텍스트 메뉴 2을 클릭했습니다."); } } #endregion ////////////////////////////////////////////////////////////////////////////////////////// Private #region 리소스 텍스트 구하기 - GetResourceText(resourceName) /// <summary> /// 리소스 텍스트 구하기 /// </summary> /// <param name="resourceName">리소스명</param> /// <returns>리소스 텍스트</returns> private static string GetResourceText(string resourceName) { Assembly assembly = Assembly.GetExecutingAssembly(); string[] resourceNameArray = assembly.GetManifestResourceNames(); for(int i = 0; i < resourceNameArray.Length; ++i) { if(string.Compare(resourceName, resourceNameArray[i], StringComparison.OrdinalIgnoreCase) == 0) { using(StreamReader resourceReader = new StreamReader(assembly.GetManifestResourceStream(resourceNameArray[i]))) { if(resourceReader != null) { return resourceReader.ReadToEnd(); } } } } return null; } #endregion } } |
▶ CustomAddIn.cs
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 |
using Microsoft.Office.Core; using System; namespace TestProject { /// <summary> /// 커스텀 애드인 /// </summary> public partial class CustomAddIn { //////////////////////////////////////////////////////////////////////////////////////////////////// Method ////////////////////////////////////////////////////////////////////////////////////////// Protected //////////////////////////////////////////////////////////////////////////////// Function #region 리본 확장성 객체 생성하기 - CreateRibbonExtensibilityObject() /// <summary> /// 리본 확장성 객체 생성하기 /// </summary> /// <returns>리본 확장성 인터페이스 객체</returns> protected override IRibbonExtensibility CreateRibbonExtensibilityObject() { return new RibbonContextMenu(); } #endregion ////////////////////////////////////////////////////////////////////////////////////////// Private //////////////////////////////////////////////////////////////////////////////// Event #region 커스텀 애드인 시작시 처리하기 - CustomAddIn_Startup(sender, e) /// <summary> /// 커스텀 애드인 시작시 처리하기 /// </summary> /// <param name="sender">이벤트 발생자</param> /// <param name="e">이벤트 인자</param> private void CustomAddIn_Startup(object sender, EventArgs e) { } #endregion #region 커스텀 애드인 셧다운시 처리하기 - CustomAddIn_Shutdown(sender, e) /// <summary> /// 커스텀 애드인 셧다운시 처리하기 /// </summary> /// <param name="sender">이벤트 발생자</param> /// <param name="e">이벤트 인자</param> private void CustomAddIn_Shutdown(object sender, EventArgs e) { } #endregion //////////////////////////////////////////////////////////////////////////////// Function #region VSTO에서 생성한 코드 /// <summary> /// 디자이너 지원에 필요한 메서드입니다. /// 이 메서드의 내용을 코드 편집기로 수정하지 마세요. /// </summary> private void InternalStartup() { this.Startup += new System.EventHandler(CustomAddIn_Startup ); this.Shutdown += new System.EventHandler(CustomAddIn_Shutdown); } #endregion } } |
TestProject.zip
■ 폴더 컨텍스트 메뉴에서 커스텀 컨텍스트 메뉴를 추가하는 방법을 보여준다. ▶ RibbonContextMenu.xml
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
<?xml version="1.0" encoding="UTF-8"?> <customUI xmlns="http://schemas.microsoft.com/office/2009/07/customui" onLoad="customUI_Load"> <ribbon> </ribbon> <contextMenus> <contextMenu idMso="ContextMenuFolder"> <button id="customContextMenu1" label="커스텀 컨텍스트 메뉴 1" onAction="customContextMenu1_Click" /> </contextMenu> </contextMenus> </customUI> |
▶ RibbonContextMenu.cs
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 |
using Microsoft.Office.Core; using System; using System.IO; using System.Reflection; using System.Runtime.InteropServices; namespace TestProject { /// <summary> /// 리본 컨텍스트 메뉴 /// </summary> [ComVisible(true)] public class RibbonContextMenu : IRibbonExtensibility { //////////////////////////////////////////////////////////////////////////////////////////////////// Field ////////////////////////////////////////////////////////////////////////////////////////// Private #region Field /// <summary> /// 리본 UI /// </summary> private IRibbonUI ribbonUI; #endregion //////////////////////////////////////////////////////////////////////////////////////////////////// Constructor ////////////////////////////////////////////////////////////////////////////////////////// Public #region 생성자 - RibbonContextMenu() /// <summary> /// 생성자 /// </summary> public RibbonContextMenu() { } #endregion //////////////////////////////////////////////////////////////////////////////////////////////////// Method ////////////////////////////////////////////////////////////////////////////////////////// Public #region (IRibbonExtensibility) 커스텀 UI 구하기 - GetCustomUI(ribbonID) /// <summary> /// 커스텀 UI 구하기 /// </summary> /// <param name="ribbonID">리본 ID</param> /// <returns>커스텀 UI</returns> public string GetCustomUI(string ribbonID) { return GetResourceText("TestProject.RibbonContextMenu.xml"); } #endregion #region 커스텀 UI 로드시 처리하기 - customUI_Load(ribbonUI) /// <summary> /// 커스텀 UI 로드시 처리하기 /// </summary> /// <param name="ribbonUI">리본 UI 인터페이스 객체</param> public void customUI_Load(IRibbonUI ribbonUI) { this.ribbonUI = ribbonUI; } #endregion #region 커스텀 컨텍스트 메뉴 1 클릭시 처리하기 - customContextMenu1_Click(ribbonControl) /// <summary> /// 커스텀 컨텍스트 메뉴 1 클릭시 처리하기 /// </summary> /// <param name="ribbonControl">리본 컨트롤</param> public void customContextMenu1_Click(IRibbonControl ribbonControl) { if(ribbonControl.Id == "customContextMenu1") { System.Windows.Forms.MessageBox.Show("커스텀 컨텍스트 메뉴 1을 클릭했습니다."); } } #endregion ////////////////////////////////////////////////////////////////////////////////////////// Private #region 리소스 텍스트 구하기 - GetResourceText(resourceName) /// <summary> /// 리소스 텍스트 구하기 /// </summary> /// <param name="resourceName">리소스명</param> /// <returns>리소스 텍스트</returns> private static string GetResourceText(string resourceName) { Assembly assembly = Assembly.GetExecutingAssembly(); string[] resourceNameArray = assembly.GetManifestResourceNames(); for(int i = 0; i < resourceNameArray.Length; ++i) { if(string.Compare(resourceName, resourceNameArray[i], StringComparison.OrdinalIgnoreCase) == 0) { using(StreamReader resourceReader = new StreamReader(assembly.GetManifestResourceStream(resourceNameArray[i]))) { if(resourceReader != null) { return resourceReader.ReadToEnd(); } } } } return null; } #endregion } } |
▶ CustomAddIn.cs
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 |
using Microsoft.Office.Core; using System; namespace TestProject { /// <summary> /// 커스텀 애드인 /// </summary> public partial class CustomAddIn { //////////////////////////////////////////////////////////////////////////////////////////////////// Method ////////////////////////////////////////////////////////////////////////////////////////// Protected //////////////////////////////////////////////////////////////////////////////// Function #region 리본 확장성 객체 생성하기 - CreateRibbonExtensibilityObject() /// <summary> /// 리본 확장성 객체 생성하기 /// </summary> /// <returns>리본 확장성 인터페이스 객체</returns> protected override IRibbonExtensibility CreateRibbonExtensibilityObject() { return new RibbonContextMenu(); } #endregion ////////////////////////////////////////////////////////////////////////////////////////// Private //////////////////////////////////////////////////////////////////////////////// Event #region 커스텀 애드인 시작시 처리하기 - CustomAddIn_Startup(sender, e) /// <summary> /// 커스텀 애드인 시작시 처리하기 /// </summary> /// <param name="sender">이벤트 발생자</param> /// <param name="e">이벤트 인자</param> private void CustomAddIn_Startup(object sender, EventArgs e) { } #endregion #region 커스텀 애드인 셧다운시 처리하기 - CustomAddIn_Shutdown(sender, e) /// <summary> /// 커스텀 애드인 셧다운시 처리하기 /// </summary> /// <param name="sender">이벤트 발생자</param> /// <param name="e">이벤트 인자</param> private void CustomAddIn_Shutdown(object sender, EventArgs e) { } #endregion //////////////////////////////////////////////////////////////////////////////// Function #region VSTO에서 생성한 코드 /// <summary> /// 디자이너 지원에 필요한 메서드입니다. /// 이 메서드의 내용을 코드 편집기로 수정하지 마세요. /// </summary> private void InternalStartup() { this.Startup += new System.EventHandler(CustomAddIn_Startup ); this.Shutdown += new System.EventHandler(CustomAddIn_Shutdown); } #endregion } } |
TestProject.zip
■ MAPIFolder 인터페이스를 사용해 폴더 아이콘을 설정하는 방법을 보여준다. ▶ PictureConverter.cs
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 |
using System; using System.Drawing; using System.Runtime.InteropServices; namespace TestProject { /// <summary> /// PICTURE 변환자 /// </summary> public static class PictureConverter { //////////////////////////////////////////////////////////////////////////////////////////////////// Class ////////////////////////////////////////////////////////////////////////////////////////// Static //////////////////////////////////////////////////////////////////////////////// Private #region 그림 설명 - PICTDESC /// <summary> /// 그림 설명 /// </summary> private static class PICTDESC { //////////////////////////////////////////////////////////////////////////////////////////////////// Field ////////////////////////////////////////////////////////////////////////////////////////// Static //////////////////////////////////////////////////////////////////////////////// Public #region Field /// <summary> /// PICTYPE_UNINITIALIZED /// </summary> public const short PICTYPE_UNINITIALIZED = -1; /// <summary> /// PICTYPE_NONE /// </summary> public const short PICTYPE_NONE = 0; /// <summary> /// PICTYPE_BITMAP /// </summary> public const short PICTYPE_BITMAP = 1; /// <summary> /// PICTYPE_METAFILE /// </summary> public const short PICTYPE_METAFILE = 2; /// <summary> /// PICTYPE_ICON /// </summary> public const short PICTYPE_ICON = 3; /// <summary> /// PICTYPE_ENHMETAFILE /// </summary> public const short PICTYPE_ENHMETAFILE = 4; #endregion //////////////////////////////////////////////////////////////////////////////////////////////////// Class ////////////////////////////////////////////////////////////////////////////////////////// Public #region 아이콘 - Icno /// <summary> /// 아이콘 /// </summary> [StructLayout(LayoutKind.Sequential)] public class Icon { //////////////////////////////////////////////////////////////////////////////////////////////////// Field ////////////////////////////////////////////////////////////////////////////////////////// Public #region Field /// <summary> /// 크기 /// </summary> public int Size = Marshal.SizeOf(typeof(PICTDESC.Icon)); /// <summary> /// 그림 타입 /// </summary> public int PictureType = PICTDESC.PICTYPE_ICON; /// <summary> /// 아이콘 핸들 /// </summary> public IntPtr IconHandle = IntPtr.Zero; /// <summary> /// 미사용 1 /// </summary> public int Unused1 = 0; /// <summary> /// 미사용 2 /// </summary> public int Unused2 = 0; #endregion //////////////////////////////////////////////////////////////////////////////////////////////////// Constructor ////////////////////////////////////////////////////////////////////////////////////////// Public #region 생성자 - Icon(icon) /// <summary> /// 생성자 /// </summary> /// <param name="icon">아이콘</param> public Icon(System.Drawing.Icon icon) { IconHandle = icon.ToBitmap().GetHicon(); } #endregion } #endregion #region 비트맵 - Bitmap /// <summary> /// 비트맵 /// </summary> [StructLayout(LayoutKind.Sequential)] public class Bitmap { //////////////////////////////////////////////////////////////////////////////////////////////////// Field ////////////////////////////////////////////////////////////////////////////////////////// Public #region Field /// <summary> /// 크기 /// </summary> public int Size = Marshal.SizeOf(typeof(PICTDESC.Bitmap)); /// <summary> /// 그림 타입 /// </summary> public int PictureType = PICTDESC.PICTYPE_BITMAP; /// <summary> /// 비트맵 핸들 /// </summary> public IntPtr BitmapHandle = IntPtr.Zero; /// <summary> /// 팔레트 핸들 /// </summary> public IntPtr PaletteHandle = IntPtr.Zero; /// <summary> /// 미사용 /// </summary> public int Unused = 0; #endregion //////////////////////////////////////////////////////////////////////////////////////////////////// Constructor ////////////////////////////////////////////////////////////////////////////////////////// Public #region 생성자 - Bitmap(bitmap) /// <summary> /// 생성자 /// </summary> public Bitmap(System.Drawing.Bitmap bitmap) { BitmapHandle = bitmap.GetHbitmap(); } #endregion } #endregion } #endregion //////////////////////////////////////////////////////////////////////////////////////////////////// Import ////////////////////////////////////////////////////////////////////////////////////////// Static //////////////////////////////////////////////////////////////////////////////// Private #region OLE 그림 생성하기 (간접) - OleCreatePictureIndirect(pictureDescription, interfaceID, own); /// <summary> /// OLE 그림 생성하기 (간접) /// </summary> /// <param name="pictureDescription">그림 설명</param> /// <param name="interfaceID">인터페이스 ID</param> /// <param name="own">소유 여부</param> /// <returns>IPictureDisp 인터페이스 객체</returns> [DllImport("OleAut32.dll", EntryPoint = "OleCreatePictureIndirect", ExactSpelling = true, PreserveSig = false)] private static extern stdole.IPictureDisp OleCreatePictureIndirect([MarshalAs(UnmanagedType.AsAny)] object pictureDescription, ref Guid interfaceID, bool own); #endregion //////////////////////////////////////////////////////////////////////////////////////////////////// Field ////////////////////////////////////////////////////////////////////////////////////////// Static //////////////////////////////////////////////////////////////////////////////// Private #region Field /// <summary> /// IPictureDisp 인터페이스 GUID /// </summary> private static Guid _iPictureDispGUID = typeof(stdole.IPictureDisp).GUID; #endregion //////////////////////////////////////////////////////////////////////////////////////////////////// Method ////////////////////////////////////////////////////////////////////////////////////////// Static //////////////////////////////////////////////////////////////////////////////// Public #region IPictureDisp 인터페이스 객체 구하기 - ToPicture(icon) /// <summary> /// IPictureDisp 인터페이스 객체 구하기 /// </summary> /// <param name="icon">아이콘</param> /// <returns>IPictureDisp 인터페이스 객체</returns> public static stdole.IPictureDisp ToPicture(Icon icon) { PICTDESC.Icon pictDescIcon = new PICTDESC.Icon(icon); return OleCreatePictureIndirect(pictDescIcon, ref _iPictureDispGUID, true); } #endregion #region IPictureDisp 인터페이스 객체 구하기 - ToPicture(image) /// <summary> /// IPictureDisp 인터페이스 객체 구하기 /// </summary> /// <param name="image">이미지</param> /// <returns>IPictureDisp 인터페이스 객체</returns> public static stdole.IPictureDisp ToPicture(Image image) { Bitmap bitmap = (image is Bitmap) ? (Bitmap)image : new Bitmap(image); PICTDESC.Bitmap pictDescBitmap = new PICTDESC.Bitmap(bitmap); return OleCreatePictureIndirect(pictDescBitmap, ref _iPictureDispGUID, true); } #endregion } } |
▶ CustomAddIn.cs
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 |
using Microsoft.Office.Interop.Outlook; using System; using System.Drawing; namespace TestProject { /// <summary> /// 커스텀 애드인 /// </summary> public partial class CustomAddIn { //////////////////////////////////////////////////////////////////////////////////////////////////// Field ////////////////////////////////////////////////////////////////////////////////////////// Private #region Field /// <summary> /// 애플리케이션 /// </summary> private Application application = null; /// <summary> /// 타겟 폴더 /// </summary> private Folder targetFolder = null; #endregion //////////////////////////////////////////////////////////////////////////////////////////////////// Method ////////////////////////////////////////////////////////////////////////////////////////// Private //////////////////////////////////////////////////////////////////////////////// Event #region 커스텀 애드인 시작시 처리하기 - CustomAddIn_Startup(sender, e) /// <summary> /// 커스텀 애드인 시작시 처리하기 /// </summary> /// <param name="sender">이벤트 발생자</param> /// <param name="e">이벤트 인자</param> private void CustomAddIn_Startup(object sender, EventArgs e) { this.application = Application; // Outlook에서 계정 폴더 아래에 Parent\Child 폴더가 사전에 생성되어 있어야 한다. Folder parentFolder = this.application.ActiveExplorer().Session.Folders[1].Folders["Parent"] as Folder; this.targetFolder = parentFolder.Folders["Child"] as Folder; SetCustomIcon(this.targetFolder); } #endregion #region 커스텀 애드인 셧다운시 처리하기 - CustomAddIn_Shutdown(sender, e) /// <summary> /// 커스텀 애드인 셧다운시 처리하기 /// </summary> /// <param name="sender">이벤트 발생자</param> /// <param name="e">이벤트 인자</param> private void CustomAddIn_Shutdown(object sender, EventArgs e) { } #endregion //////////////////////////////////////////////////////////////////////////////// Function #region VSTO에서 생성한 코드 /// <summary> /// 디자이너 지원에 필요한 메서드입니다. /// 이 메서드의 내용을 코드 편집기로 수정하지 마세요. /// </summary> private void InternalStartup() { this.Startup += new System.EventHandler(CustomAddIn_Startup ); this.Shutdown += new System.EventHandler(CustomAddIn_Shutdown); } #endregion #region 커스텀 아이콘 설정하기 - SetCustomIcon(folder) /// <summary> /// 커스텀 아이콘 설정하기 /// </summary> /// <param name="folder">폴더</param> private void SetCustomIcon(MAPIFolder folder) { Bitmap bitmap = null; try { bitmap = Properties.Resources.sample; stdole.StdPicture picture = PictureConverter.ToPicture(bitmap) as stdole.StdPicture; folder.SetCustomIcon(picture); } finally { bitmap.Dispose(); } } #endregion } } |
TestProject.zip
■ MailItem 인터페이스를 사용해 메일 아이콘을 설정하는 방법을 보여준다. ▶ CustomAddIn.cs
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 |
using Microsoft.Office.Interop.Outlook; using System; using System.Runtime.InteropServices; namespace TestProject { /// <summary> /// 커스텀 애드인 /// </summary> public partial class CustomAddIn { //////////////////////////////////////////////////////////////////////////////////////////////////// Field ////////////////////////////////////////////////////////////////////////////////////////// Private #region Field /// <summary> /// 애플리케이션 /// </summary> private Application application = null; /// <summary> /// PR_ICON_INDEX /// </summary> private const string PR_ICON_INDEX = "http://schemas.microsoft.com/mapi/proptag/0x10800003"; #endregion //////////////////////////////////////////////////////////////////////////////////////////////////// Method ////////////////////////////////////////////////////////////////////////////////////////// Private //////////////////////////////////////////////////////////////////////////////// Event #region 커스텀 애드인 시작시 처리하기 - CustomAddIn_Startup(sender, e) /// <summary> /// 커스텀 애드인 시작시 처리하기 /// </summary> /// <param name="sender">이벤트 발생자</param> /// <param name="e">이벤트 인자</param> private void CustomAddIn_Startup(object sender, EventArgs e) { this.application = Application; this.application.NewMailEx += application_NewMailEx; } #endregion #region 커스텀 애드인 셧다운시 처리하기 - CustomAddIn_Shutdown(sender, e) /// <summary> /// 커스텀 애드인 셧다운시 처리하기 /// </summary> /// <param name="sender">이벤트 발생자</param> /// <param name="e">이벤트 인자</param> private void CustomAddIn_Shutdown(object sender, EventArgs e) { } #endregion #region 애플리케이션 신규 메일 수신시 처리하기 (확장) - application_NewMailEx(entryIDCollection) /// <summary> /// 애플리케이션 신규 메일 수신시 처리하기 (확장) /// </summary> /// <param name="entryIDCollection">엔트리 ID 컬렉션</param> private void application_NewMailEx(string entryIDCollection) { string[] entryIDArray = entryIDCollection.Split(','); foreach(string entryID in entryIDArray) { MailItem mailItem = this.application.ActiveExplorer().Session.GetItemFromID(entryID); if(mailItem != null) { SetExtendedPropertyValue(mailItem, PR_ICON_INDEX, 311); mailItem.Save(); } } } #endregion //////////////////////////////////////////////////////////////////////////////// Function #region VSTO에서 생성한 코드 /// <summary> /// 디자이너 지원에 필요한 메서드입니다. /// 이 메서드의 내용을 코드 편집기로 수정하지 마세요. /// </summary> private void InternalStartup() { this.Startup += new System.EventHandler(CustomAddIn_Startup ); this.Shutdown += new System.EventHandler(CustomAddIn_Shutdown); } #endregion #region 확장된 속성 값 구하기 - GetExtendedPropertyValue(mailitem, propertyName, value) /// <summary> /// 확장된 속성 값 구하기 /// </summary> /// <param name="mailitem">메일 항목</param> /// <param name="propertyName">속성명</param> /// <param name="value">값</param> /// <returns>처리 결과</returns> private bool GetExtendedPropertyValue(MailItem mailitem, string propertyName, ref object value) { PropertyAccessor propertyAccessor = null; try { propertyAccessor = mailitem.PropertyAccessor as PropertyAccessor; value = propertyAccessor.GetProperty(propertyName); return true; } catch(System.Exception) { } finally { if(propertyAccessor != null) { Marshal.ReleaseComObject(propertyAccessor); propertyAccessor = null; } } return false; } #endregion #region 확장된 속성 값 설정하기 - SetExtendedPropertyValue(mailItem, propertyName, value) /// <summary> /// 확장된 속성 값 설정하기 /// </summary> /// <param name="mailItem">메일 항목</param> /// <param name="propertyName">속성명</param> /// <param name="value">값</param> /// <returns>처리 결과</returns> private bool SetExtendedPropertyValue(MailItem mailItem, string propertyName, object value) { PropertyAccessor propertyAccessor = null; try { propertyAccessor = mailItem.PropertyAccessor as PropertyAccessor; propertyAccessor.SetProperty(propertyName, value); return true; } catch { } finally { if(propertyAccessor != null) { Marshal.ReleaseComObject(propertyAccessor); propertyAccessor = null; } } return false; } #endregion } } |
TestProject.zip
■ 신규 메일 수신시 지정 폴더로 이동시키는 방법을 보여준다. ▶ CustomAddIn.cs
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 |
using Microsoft.Office.Interop.Outlook; using System; using System.Diagnostics; namespace TestProject { /// <summary> /// 커스텀 애드인 /// </summary> public partial class CustomAddIn { //////////////////////////////////////////////////////////////////////////////////////////////////// Field ////////////////////////////////////////////////////////////////////////////////////////// Private #region Field /// <summary> /// 애플리케이션 /// </summary> private Application application = null; /// <summary> /// 타겟 폴더 /// </summary> private Folder targetFolder = null; #endregion //////////////////////////////////////////////////////////////////////////////////////////////////// Method ////////////////////////////////////////////////////////////////////////////////////////// Private //////////////////////////////////////////////////////////////////////////////// Event #region 커스텀 애드인 시작시 처리하기 - CustomAddIn_Startup(sender, e) /// <summary> /// 커스텀 애드인 시작시 처리하기 /// </summary> /// <param name="sender">이벤트 발생자</param> /// <param name="e">이벤트 인자</param> private void CustomAddIn_Startup(object sender, EventArgs e) { this.application = Application; // Outlook에서 계정 폴더 아래에 Parent\Child 폴더가 사전에 생성되어 있어야 한다. Folder parentFolder = this.application.ActiveExplorer().Session.Folders[1].Folders["Parent"] as Folder; this.targetFolder = parentFolder.Folders["Child"] as Folder; this.application.NewMailEx += application_NewMailEx; } #endregion #region 커스텀 애드인 셧다운시 처리하기 - CustomAddIn_Shutdown(sender, e) /// <summary> /// 커스텀 애드인 셧다운시 처리하기 /// </summary> /// <param name="sender">이벤트 발생자</param> /// <param name="e">이벤트 인자</param> private void CustomAddIn_Shutdown(object sender, EventArgs e) { } #endregion #region 애플리케이션 신규 메일 수신시 처리하기 (확장) - application_NewMailEx(entryIDCollection) /// <summary> /// 애플리케이션 신규 메일 수신시 처리하기 (확장) /// </summary> /// <param name="entryIDCollection">엔트리 ID 컬렉션</param> private void application_NewMailEx(string entryIDCollection) { Debug.WriteLine("BEGIN APPLICATIOn NEW MAIL EX"); Debug.WriteLine($"ENTRY ID COLLECTION : {entryIDCollection}"); string[] entryIDArray = entryIDCollection.Split(','); foreach(string entryID in entryIDArray) { MailItem mailItem = this.application.ActiveExplorer().Session.GetItemFromID(entryID); if(mailItem != null) { Debug.WriteLine($" {entryID}:{mailItem.Subject}"); try { mailItem.Move(this.targetFolder); } catch(System.Exception exception) { Debug.WriteLine(exception.ToString()); } } } Debug.WriteLine("END APPLICATION NEW MAIL EX"); } #endregion //////////////////////////////////////////////////////////////////////////////// Function #region VSTO에서 생성한 코드 /// <summary> /// 디자이너 지원에 필요한 메서드입니다. /// 이 메서드의 내용을 코드 편집기로 수정하지 마세요. /// </summary> private void InternalStartup() { this.Startup += new System.EventHandler(CustomAddIn_Startup ); this.Shutdown += new System.EventHandler(CustomAddIn_Shutdown); } #endregion } } |
TestProject.zip
■ ExplorerEvents_10_Event 인터페이스의 FolderSwitch/SelectionChange 이벤트를 사용하는 방법을 보여준다. ▶ CustomAddIn.cs
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 |
using Microsoft.Office.Interop.Outlook; using System; using System.Diagnostics; using System.Windows.Forms; namespace TestProject { /// <summary> /// 커스텀 애드인 /// </summary> public partial class CustomAddIn { //////////////////////////////////////////////////////////////////////////////////////////////////// Field ////////////////////////////////////////////////////////////////////////////////////////// Private #region Field /// <summary> /// 탐색기 /// </summary> private Explorer explorer = null; #endregion //////////////////////////////////////////////////////////////////////////////////////////////////// Method ////////////////////////////////////////////////////////////////////////////////////////// Private //////////////////////////////////////////////////////////////////////////////// Event #region 커스텀 애드인 시작시 처리하기 - CustomAddIn_Startup(sender, e) /// <summary> /// 커스텀 애드인 시작시 처리하기 /// </summary> /// <param name="sender">이벤트 발생자</param> /// <param name="e">이벤트 인자</param> private void CustomAddIn_Startup(object sender, EventArgs e) { this.explorer = Application.ActiveExplorer(); this.explorer.FolderSwitch += explorer_FolderSwitch; // 폴더 선택 변경시 this.explorer.SelectionChange += explorer_SelectionChange; // 메일 선택 변경시 } #endregion #region 커스텀 애드인 셧다운시 처리하기 - CustomAddIn_Shutdown(sender, e) /// <summary> /// 커스텀 애드인 셧다운시 처리하기 /// </summary> /// <param name="sender">이벤트 발생자</param> /// <param name="e">이벤트 인자</param> private void CustomAddIn_Shutdown(object sender, EventArgs e) { } #endregion #region 탐색기 폴더 스위칭시 처리하기 - explorer_FolderSwitch() /// <summary> /// 탐색기 폴더 스위칭시 처리하기 /// </summary> private void explorer_FolderSwitch() { Debug.WriteLine("BEGIN EXPLORER FOLDER SWITCH"); Debug.WriteLine($" CURRENT FOLDER : {this.explorer.CurrentFolder.Name}"); Debug.WriteLine("END EXPLORER FOLDER SWITCH"); } #endregion #region 탐색기 선택 변경시 처리하기 - explorer_SelectionChange() /// <summary> /// 탐색기 선택 변경시 처리하기 /// </summary> private void explorer_SelectionChange() { Debug.WriteLine("BEGIN EXPLORER SELECTION CHANGE"); Debug.WriteLine($" CURRENT FOLDER : {this.explorer.CurrentFolder.Name}"); foreach(MailItem mailItem in this.explorer.Selection) { Debug.WriteLine($" {mailItem.Subject}"); Debug.WriteLine($" {mailItem.Sender.Name}"); Debug.WriteLine($" {mailItem.SenderEmailType}"); Debug.WriteLine($" {mailItem.SenderEmailAddress}"); } Debug.WriteLine("END EXPLORER SELECTION CHANGE"); } #endregion //////////////////////////////////////////////////////////////////////////////// Function #region VSTO에서 생성한 코드 /// <summary> /// 디자이너 지원에 필요한 메서드입니다. /// 이 메서드의 내용을 코드 편집기로 수정하지 마세요. /// </summary> private void InternalStartup() { this.Startup += new System.EventHandler(CustomAddIn_Startup ); this.Shutdown += new System.EventHandler(CustomAddIn_Shutdown); } #endregion } } |
TestProject.zip
■ COMAddIn 인터페이스의 Connect 속성을 사용해 애드인 언로드시키는 방법을 보여준다. ▶ COMAddIn 인터페이스 : Connect 속성을 사용해 애드인 언로드시키기 예제 (C#)
1 2 3 |
UnloadAddIn("TestProject"); |
■ _Explorer 인터페이스의 Selection 속성을 사용해 선택 메일 항목의 열거 가능형을 구하는 방법을 보여준다. ▶ 예제 코드 (C#)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 |
using System.Collections.Generic; using Microsoft.Office.Interop.Outlook; #region 선택 메일 항목 열거 가능형 - GetSelectedMailItemEnumerable() /// <summary> /// 선택 메일 항목 열거 가능형 구하기 /// </summary> /// <returns>선택 메일 항목 열거 가능형</returns> public IEnumerable<MailItem> GetSelectedMailItemEnumerable() { foreach(MailItem mailItem in Application.ActiveExplorer().Selection) { yield return mailItem; } } #endregion |
※ Application은 Microsoft.Office.Tools.Outlook.OutlookAddInBase