|
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.