Magnum
Magnum

Reputation: 1595

How to programmatically set a custom icon on an Outlook search folder? (i.e. Outlook Folder SetCustomIcon)

I am attempting to use the Folder.SetCustomIcon() method to place a custom icon on a saved search folder I programmatically created. The SetCustomIcon() documentation is very sparse but can be found here for reference.

Also, the object it expects is here and again the examples are very sparse.

Would anybody know how to set the custom icon for a folder? The following is the code I have thus far:

searchFolders = inboxFolder.Store.GetSearchFolders();
foreach (Outlook.Folder folder in searchFolders)
{
    if (folder.Name == "Expiring Retention Policy Mail")
    {
        folder.ShowItemCount = Microsoft.Office.Interop.Outlook.OlShowItemCount.olShowTotalItemCount;
        folder.SetCustomIcon(new Bitmap(32, 32));   // <=-- this isn't working because it's expecting stdPicture which has very sparse information on how to convert to this type.
        Globals.ThisAddIn.Application.ActiveExplorer().CurrentFolder = folder;  
    }
}

Upvotes: 3

Views: 3277

Answers (2)

Stefan
Stefan

Reputation: 382

here is simple version if you want to realize it in VBA

Sub Change_mapiRootFolder_Icon()
Dim mapiRootFolder As Outlook.MAPIFolder, mapiCurrFolder As Outlook.MAPIFolder 
Dim stFullFolderPath As String, stCurrItemType As String, stIconPath As String, stCurrFolder As String
Dim i As Integer
Dim ipdMyPic As IPictureDisp

Set mapiCurrFolder = Application.ActiveExplorer.CurrentFolder
stCurrItemType = Application.ActiveExplorer.CurrentFolder.DefaultMessageClass

If stCurrItemType = "IPM.Note" Then  'mail Item types    https://msdn.microsoft.com/en-us/library/office/ff861573.aspx
    Set mapiRootFolder = mapiCurrFolder
    stFullFolderPath = mapiRootFolder.Name
    Do Until mapiRootFolder.Parent = "Mapi"
      Set mapiRootFolder = mapiRootFolder.Parent
      stFullFolderPath = mapiRootFolder.Name & "\" & stFullFolderPath
    Loop
    Debug.Print stFullFolderPath

    stIconPath = "U:\OUTLOOK\Icons\Sent\iconarchive_sent1.ico"
    stIconPath = "C:\Temp\iconarchive_sent1.bmp"
    Set ipdMyPic = LoadPicture(stIconPath)
    If Not (mapiCurrFolder Is Nothing) Then
        mapiCurrFolder.SetCustomIcon ipdMyPic
    End If

End If

End Sub

Upvotes: 0

SliverNinja - MSFT
SliverNinja - MSFT

Reputation: 31651

You just need to use a PictureDispConverter to go from an image/icon to IPictureDisp. Below is an example from MSDN. This only works in Outlook 2010+. To view custom Folder Icons in Outlook 2013, you need to view the Folder List - not the Mail view.

SetCustomIcon from MAPIFolder

private static void SetCustomIcon(Outlook.MAPIFolder folder)
{
    Icon icon = null;
    try
    {
        icon = Properties.Resources.myCustomIcon_16x16;
        stdole.StdPicture iconPictureDisp = PictureDispConverter.ToIPictureDisp(icon) as stdole.StdPicture;
        folder.SetCustomIcon(iconPictureDisp);
    }
    finally
    {
        icon.Dispose();
    }
}

PictureDispConverter (Icon->IPictureDisp, Image->IPictureDisp)

public static class PictureDispConverter
{
    //IPictureDisp GUID. 
    public static Guid iPictureDispGuid = typeof(stdole.IPictureDisp).GUID;

    // Converts an Icon into an IPictureDisp. 
    public static stdole.IPictureDisp ToIPictureDisp(Icon icon)
    {
        PICTDESC.Icon pictIcon = new PICTDESC.Icon(icon);
        return PictureDispConverter.OleCreatePictureIndirect(pictIcon, ref iPictureDispGuid, true);
    }

    // Converts an image into an IPictureDisp. 
    public static stdole.IPictureDisp ToIPictureDisp(Image image)
    {
        Bitmap bitmap = (image is Bitmap) ? (Bitmap)image : new Bitmap(image);
        PICTDESC.Bitmap pictBit = new PICTDESC.Bitmap(bitmap);
        return PictureDispConverter.OleCreatePictureIndirect(pictBit, ref iPictureDispGuid, true);
    }


    [DllImport("OleAut32.dll", EntryPoint = "OleCreatePictureIndirect", ExactSpelling = true,
    PreserveSig = false)]
    private static extern stdole.IPictureDisp OleCreatePictureIndirect(
    [MarshalAs(UnmanagedType.AsAny)] object picdesc, ref Guid iid, bool fOwn);

    private readonly static HandleCollector handleCollector =
    new HandleCollector("Icon handles", 1000);

    // WINFORMS COMMENT: 
    // PICTDESC is a union in native, so we'll just 
    // define different ones for the different types 
    // the "unused" fields are there to make it the right 
    // size, since the struct in native is as big as the biggest 
    // union. 
    private static class PICTDESC
    {
        //Picture Types 
        public const short PICTYPE_UNINITIALIZED = -1;
        public const short PICTYPE_NONE = 0;
        public const short PICTYPE_BITMAP = 1;
        public const short PICTYPE_METAFILE = 2;
        public const short PICTYPE_ICON = 3;
        public const short PICTYPE_ENHMETAFILE = 4;

        [StructLayout(LayoutKind.Sequential)]
        public class Icon
        {
            internal int cbSizeOfStruct = Marshal.SizeOf(typeof(PICTDESC.Icon));
            internal int picType = PICTDESC.PICTYPE_ICON;
            internal IntPtr hicon = IntPtr.Zero;
            internal int unused1 = 0;
            internal int unused2 = 0;

            internal Icon(System.Drawing.Icon icon)
            {
                this.hicon = icon.ToBitmap().GetHicon();
            }
        }

        [StructLayout(LayoutKind.Sequential)]
        public class Bitmap
        {
            internal int cbSizeOfStruct = Marshal.SizeOf(typeof(PICTDESC.Bitmap));
            internal int picType = PICTDESC.PICTYPE_BITMAP;
            internal IntPtr hbitmap = IntPtr.Zero;
            internal IntPtr hpal = IntPtr.Zero;
            internal int unused = 0;
            internal Bitmap(System.Drawing.Bitmap bitmap)
            {
                this.hbitmap = bitmap.GetHbitmap();
            }
        }
    }
} 

Upvotes: 2

Related Questions