Click here to Skip to main content
15,896,207 members
Articles / Desktop Programming / Win32

Determining if Excel is in Edit mode with Win32 Interop

Rate me:
Please Sign up or sign in to vote.
4.56/5 (6 votes)
13 Apr 2009CPOL3 min read 46.4K   742   22  
In this article, one can find a possible solution how to check or to be notified if the Excel Application is in Edit mode
using System;
using System.Collections.Generic;
using System.Text;
using System.Windows.Forms;
using System.Runtime.InteropServices;


namespace ExcelUtil
{   


    /// <summary>
    /// Viktor Hamori 09/04/2009 - This class represents the EditMode status of Excel
    /// with safe subclassing the Excel cell editor window 
    /// </summary>
    public class ExcelEditorModeEventPublisher : NativeWindow, IDisposable
    {
        private class Win32
        {
            public enum WM
            {
                WM_WINDOWPOSCHANGED = 0x0047,
                WM_STYLECHANGED = 0x007D
            }

            [DllImport("user32.dll", CharSet = CharSet.Auto)]
            static public extern IntPtr FindWindowEx(IntPtr hWnd, IntPtr hChild, string strClassName, string strName);
            [DllImport("user32.dll", CharSet = CharSet.Auto)]
            static public extern bool IsWindowVisible(IntPtr hWnd);
            [DllImport("user32.dll", CharSet = CharSet.Auto)]
            static public extern bool IsWindowEnabled(IntPtr hWnd);
        }

        #region Declaration
        // disposing ...
        private object _lock = new object();
        private volatile bool _isDisposed = false;
        // editor window status
        private bool _isEditorWindowActive = false;

        // event declarations
        protected event EventHandler _editModeOn;
        protected event EventHandler _editModeOff;
        #endregion

        #region Constructor and Destructor
        /// <summary>
        /// Constructor accepting the editor window
        /// </summary>
        /// <param name="editorWindow"></param>
        internal ExcelEditorModeEventPublisher(IntPtr editorWindow)
        {
            if (editorWindow == IntPtr.Zero)
                return;
            InitObservation(editorWindow);
        }
        /// <summary>
        /// Constructor for finding the Editor Window in Excel window hierarchy
        /// </summary>
        /// <param name="excelApp"></param>
        internal ExcelEditorModeEventPublisher(Microsoft.Office.Interop.Excel.Application excelApp)
        {

            if (excelApp == null)
                throw new ArgumentNullException("excelApp");

            // first get the container window for each workbooks
            IntPtr workbookContainer = Win32.FindWindowEx(new IntPtr( excelApp.Hwnd ), 
                                                          IntPtr.Zero, 
                                                          "XLDESK", String.Empty);
            // check if the search was positive
            if (workbookContainer != IntPtr.Zero)
            {   // continue with finding the editor window
                IntPtr editorWindow = Win32.FindWindowEx(workbookContainer, 
                                                         IntPtr.Zero,
                                                         "EXCEL6", String.Empty);
                // subclass it if the search was successful
                if (editorWindow != IntPtr.Zero)
                {
                    InitObservation(editorWindow);
                    return;
                }
            }

            throw new Exception("Unfortunatelly, Excel editor window cannot be detected!");
        }
        /// <summary>
        /// Init the observer mechanism.
        /// </summary>
        private void InitObservation(IntPtr editorWindow)
        {
            AssignHandle(editorWindow);
            CheckWindowState();
        }
        /// <summary>
        /// Releasing the window in the destructor
        /// </summary>
        ~ExcelEditorModeEventPublisher()
        {
            Disposing();
        }
        /// <summary>
        /// The real dispose method
        /// </summary>
        protected void Disposing()
        {
            lock (_lock)
            {
                if (!_isDisposed)
                {
                    ReleaseHandle();
                    _isDisposed = true;
                }
            }
        }
        #region IDisposable Members
        /// <summary>
        /// Explicit clear up
        /// </summary>
        public void Dispose()
        {
            Disposing();
            GC.SuppressFinalize(this);
        }
        #endregion
        
        #endregion

        #region Window Procedure
        /// <summary>
        /// We have to observe the window changes (visibility, enabled state)
        /// </summary>
        /// <param name="m"></param>
        protected override void WndProc(ref Message m)
        {
            switch (m.Msg)
            {
                // win32 message if style of the targetwindow has changed by any Win32 API call
                // WS_VISIBLE flag or any other
                case (int)Win32.WM.WM_STYLECHANGED:
                    CheckWindowState();
                    break;
                // win32 message if position of the targetwindow has changed by SetWindowPos API call
                // SWP_SHOWWINDOW for instance
                case (int)Win32.WM.WM_WINDOWPOSCHANGED:
                    CheckWindowState();
                    break;
            }
            base.WndProc(ref m);
        }
        #endregion

        #region Event handling
        /// <summary>
        /// Run the style/pos change checker ..
        /// </summary>
        private void CheckWindowState()
        {
            // check if the window now visible andalso enabled
            if (Win32.IsWindowVisible(this.Handle) && Win32.IsWindowEnabled(this.Handle))
            {
                if (!_isEditorWindowActive)
                {   // change the state and raise event
                    _isEditorWindowActive = true;
                    OnRaiseSafetyEvent(_editModeOn, new object[] {this, EventArgs.Empty} );
                }
            }
            // check if the mode has changed back to non-edit mode
            else
            {
                if (_isEditorWindowActive)
                {   // change the state and raise event
                    _isEditorWindowActive = false;
                    OnRaiseSafetyEvent( _editModeOff, new object[]{this, EventArgs.Empty} );
                }
            }
        }
        /// <summary>
        /// Protect the Excel message mechanism against client code!
        /// </summary>
        /// <param name="eventHandler"></param>
        /// <param name="args"></param>
        protected static void OnRaiseSafetyEvent(Delegate eventHandler, object[] args)
        {
            if (eventHandler == null)
                return;
            Delegate[] delegates = eventHandler.GetInvocationList();
            if (delegates != null)
            {
                foreach (Delegate del in delegates)
                {
                    try { del.DynamicInvoke(args); }
                    catch { }
                }
            }
        }
        /// <summary>
        /// Edit mode switched on event accessor
        /// </summary>
        public event EventHandler EditModeOn
        {
            add
            {
                _editModeOn += value;
            }
            remove
            {
                _editModeOn -= value;
            }
        }

        /// <summary>
        /// Edit mode switched on event accessor
        /// </summary>
        public event EventHandler EditModeOff
        {
            add
            {
                _editModeOff += value;
            }
            remove
            {
                _editModeOff -= value;
            }
        }


        #endregion

        #region Properties
        /// <summary>
        /// Property reflecting editor mode state
        /// </summary>
        public bool IsExcelInEditMode
        {
            get
            {
                return _isEditorWindowActive;
            }
        }
        #endregion
    }
}

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)
Hungary Hungary
Office (Word, Excel) specialist
C#, COM, VC++, VB6
MFC, ATL,

Comments and Discussions