Click here to Skip to main content
15,892,537 members
Articles / Desktop Programming / Windows Forms

Additional custom panel in Microsoft Outlook

Rate me:
Please Sign up or sign in to vote.
4.98/5 (44 votes)
25 Jun 2008CPOL7 min read 301.9K   4.1K   125  
An example of undocumented integration into the user interface of Microsoft Office applications.
// --------------------------------------------------------------------------
// Copyright (c) MEMOS Software s.r.o. All rights reserved.
//
// Outlook Panel Demonstration
// 
// File     : PanelManager.cs
// Author   : Lukas Neumann <lukas.neumann@memos.cz>
// Created  : 080622
//
// -------------------------------------------------------------------------- 

using System;
using System.Drawing;
using System.Windows.Forms;

namespace OutlookPanel
{
    /// <summary>
    /// Class that manages nested panel control
    /// </summary>
    public class PanelManager : IDisposable
    {
        private PanelContainer _panelContainer;
        private SubclassedWindow _subclassedSiblingWindow;
        private bool _changingSize;

        /// <summary>
        /// Default constructor
        /// </summary>
        /// <param name="parentWindow">Parent window handle, most likely a main window of host application</param>
        /// <param name="siblingWindow">Sibling window from which we will 'steal' the space to display our own panel</param>
        public PanelManager(IntPtr parentWindow, IntPtr siblingWindow)
        {
            this._parentWindow = parentWindow;
            this._siblingWindow = siblingWindow;
                    
        }

        private readonly IntPtr _parentWindow;

        /// <summary>
        /// Parent window handle
        /// </summary>
        public IntPtr ParentWindow
        {
            get { return _parentWindow; }
        }

        private readonly IntPtr _siblingWindow;

        /// <summary>
        /// Sibling window handle
        /// </summary>
        public IntPtr SiblingWindow
        {
            get { return _siblingWindow; }
        }


        /// <summary>
        /// Clean up method
        /// </summary>
        public void Dispose()
        {
            //Dispose the container (if it was initialised)
            if (_panelContainer != null)
                _panelContainer.Dispose();

            //Dispose the subclassing wrapper (if it was initialised)
            if (_subclassedSiblingWindow != null)
                _subclassedSiblingWindow.ReleaseHandle();
            
        }

        /// <summary>
        /// Show bar control
        /// </summary>
        /// <param name="nestedControl">Nested custom panel to show</param>
        public void ShowBarControl(UserControl nestedControl)
        {
            //Create new container instance
            _panelContainer = new PanelContainer();
            

            //Set the parent window of the bar container
            SafeNativeMethods.SetParent(_panelContainer.Handle, this.ParentWindow );

            //Resize both sibling and our container
            ResizePanels();

            //Subclass sibling window to monitor SizeChange event
            _subclassedSiblingWindow = new SubclassedWindow();
            _subclassedSiblingWindow.AssignHandle(this.SiblingWindow);
            _subclassedSiblingWindow.SizeChanged += new EventHandler(subclassedSiblingWindow_SizeChanged);

            //Attach nested panel to our container
            _panelContainer.AttachControl(nestedControl);
            _panelContainer.Show();
            
        }
               
        /// <summary>
        /// Resize original sibling window and our panel container window
        /// </summary>
        private void ResizePanels()
        {
            if (_changingSize)
                return; //Prevent infinite loops

            _changingSize = true;
            
            try
            {
                //Get size of the sibling window and main parent window
                Rectangle siblingRect = SafeNativeMethods.GetWindowRectange(this.SiblingWindow);
                Rectangle parentRect = SafeNativeMethods.GetWindowRectange(this.ParentWindow);

                //Calculate position of sibling window in screen coordinates
                SafeNativeMethods.POINT topLeft = new SafeNativeMethods.POINT(siblingRect.Left, siblingRect.Top);
                SafeNativeMethods.ScreenToClient(this.ParentWindow, ref topLeft);

                //Decrease size of the sibling window
                int newWidth = parentRect.Width - topLeft.X - _panelContainer.Width;
                SafeNativeMethods.SetWindowPos(this.SiblingWindow, IntPtr.Zero, 0, 0, newWidth, siblingRect.Height, SafeNativeMethods.SWP_NOMOVE | SafeNativeMethods.SWP_NOZORDER);

                //Move the bar to correct position
                _panelContainer.Left = topLeft.X + newWidth;
                _panelContainer.Top = topLeft.Y;

                //Set correct height of the panel container
                _panelContainer.Height = siblingRect.Height;
            }
            finally
            {
                _changingSize = false;
            }
        }

     
        /// <summary>
        /// Called when size of the sibling window has been changed
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void subclassedSiblingWindow_SizeChanged(object sender, EventArgs e)
        {
            //Since sibling has changed its size, we need to resize both windows again
            ResizePanels();
        }
    }
}

By viewing downloads associated with this article you agree to the Terms of Service and the article's licence.

If a file you wish to view isn't highlighted, and is a text file (not binary), please let us know and we'll add colourisation support for it.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


Written By
Software Developer (Senior) MEMOS Software (www.memos.cz)
Czech Republic Czech Republic
I started developing software in Quick Basic on my very first PC running 8086 CPU @ 8MHz. Then I moved to Visual Basic, followed by MFC and for last 4 years i am stuck with C# and Microsoft .NET. Now I work as a senior developer for MEMOS Software. My hobby is Office integration, especially Microsoft Outlook.


Check out my blog at
http://blog.memos.cz

Comments and Discussions