A
Alex
Hello,
Here's an interesting problem:
In my Word add-in (C#) I have a Windows Form that must always float above the currently active Word window.
I accomplished it by changing the owner of the form to be the active Word window (see implementation below).
This works but, unfortunately, after playing around a little (minimizing and restoring windows, switching applications) the system will no longer let me switch between Word windows by clicking on their icons on the Taskbar or using Alt-TAB (Alt-F6 seems to work OK). Sometimes, if I continue playing around, the form will decide to hide itself...
One way to recreate this behaviour is to open two Word documents, show the form, click on it to make it active and then start switching between the Word windows using the Taskbar.
Can anyone help me figure out what is going on?
Best wishes,
Alex.
The implementation:
// This class handles the interaction with MS-Word
class MyAddIn
{
// The floating Form
private FormMainUI mainUI;
// Hook events
public void Init(Word.Application app)
{
((Word.ApplicationEvents3_Event) app).WindowActivate +=
new Word.ApplicationEvents3_WindowActivateEventHandler(EventWindowActivate);
}
private void EventWindowActivate(Word.Document document, Word.Window window)
{
// Get the current window handle
IntPtr hWnd = Win32.GetActiveWindow();
// Verify that it's a Word window
const string wordClass = "OpusApp";
int len = wordClass.Length + 1;
StringBuilder className = new StringBuilder(len);
Win32.GetClassName(Win32.GetAncestor(hWnd, Win32.GA_ROOT), className, len);
if (className.ToString() != wordClass)
return;
// Set owner
mainUI.SetOwner(hWnd);
}
}
// The floating Form
internal class FormMainUI : System.Windows.Forms.Form
{
// Non-default settings
private void InitializeComponent()
{
// ...
this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.FixedDialog;
this.MaximizeBox = false;
this.Name = "FormMainUI";
// ...
}
// Here's the beef:
public void SetOwner(IntPtr hWnd)
{
// SetWindowLong() does not play nicely with Marshal.GetHRForLastWin32Error()
// so no error checking
Win32.SetWindowLong(this.Handle, Win32.GWL_HWNDPARENT, (int)hWnd);
// Refresh window
uint flags = Win32.SWP_NOSIZE | Win32.SWP_NOMOVE | Win32.SWP_FRAMECHANGED;
if (this.Visible)
flags |= Win32.SWP_SHOWWINDOW;
if (!this.ContainsFocus)
flags |= Win32.SWP_NOACTIVATE;
Win32.SetWindowPos(this.Handle, Win32.HWND_TOP, 0, 0, 0, 0, flags);
}
}
// P/Invoke stuff
public abstract class Win32
{
private Win32() {} // static class
[DllImport("user32.dll")]
public static extern IntPtr GetAncestor(IntPtr hwnd, uint gaFlags);
[DllImport("user32.dll", SetLastError = true, CharSet = CharSet.Auto)]
public static extern int GetClassName(IntPtr hWnd, [Out] StringBuilder lpClassName, int nMaxCount);
[DllImport("user32.dll", SetLastError = true)]
public static extern int SetWindowLong(IntPtr hWnd, int nIndex, int dwNewLong);
[DllImport("user32.dll", SetLastError = true)]
public static extern bool SetWindowPos(IntPtr hWnd, IntPtr hWndInsertAfter, int X, int Y, int cx, int cy, uint uFlags);
public const uint GA_ROOT = 2;
public const int GWL_HWNDPARENT = -8;
public const uint SWP_NOSIZE = 0x0001;
public const uint SWP_NOMOVE = 0x0002;
public const uint SWP_FRAMECHANGED = 0x0020;
public const uint SWP_SHOWWINDOW = 0x0040;
public const uint SWP_NOACTIVATE = 0x0010;
public static IntPtr HWND_TOP = (IntPtr)(0);
}
Here's an interesting problem:
In my Word add-in (C#) I have a Windows Form that must always float above the currently active Word window.
I accomplished it by changing the owner of the form to be the active Word window (see implementation below).
This works but, unfortunately, after playing around a little (minimizing and restoring windows, switching applications) the system will no longer let me switch between Word windows by clicking on their icons on the Taskbar or using Alt-TAB (Alt-F6 seems to work OK). Sometimes, if I continue playing around, the form will decide to hide itself...
One way to recreate this behaviour is to open two Word documents, show the form, click on it to make it active and then start switching between the Word windows using the Taskbar.
Can anyone help me figure out what is going on?
Best wishes,
Alex.
The implementation:
// This class handles the interaction with MS-Word
class MyAddIn
{
// The floating Form
private FormMainUI mainUI;
// Hook events
public void Init(Word.Application app)
{
((Word.ApplicationEvents3_Event) app).WindowActivate +=
new Word.ApplicationEvents3_WindowActivateEventHandler(EventWindowActivate);
}
private void EventWindowActivate(Word.Document document, Word.Window window)
{
// Get the current window handle
IntPtr hWnd = Win32.GetActiveWindow();
// Verify that it's a Word window
const string wordClass = "OpusApp";
int len = wordClass.Length + 1;
StringBuilder className = new StringBuilder(len);
Win32.GetClassName(Win32.GetAncestor(hWnd, Win32.GA_ROOT), className, len);
if (className.ToString() != wordClass)
return;
// Set owner
mainUI.SetOwner(hWnd);
}
}
// The floating Form
internal class FormMainUI : System.Windows.Forms.Form
{
// Non-default settings
private void InitializeComponent()
{
// ...
this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.FixedDialog;
this.MaximizeBox = false;
this.Name = "FormMainUI";
// ...
}
// Here's the beef:
public void SetOwner(IntPtr hWnd)
{
// SetWindowLong() does not play nicely with Marshal.GetHRForLastWin32Error()
// so no error checking
Win32.SetWindowLong(this.Handle, Win32.GWL_HWNDPARENT, (int)hWnd);
// Refresh window
uint flags = Win32.SWP_NOSIZE | Win32.SWP_NOMOVE | Win32.SWP_FRAMECHANGED;
if (this.Visible)
flags |= Win32.SWP_SHOWWINDOW;
if (!this.ContainsFocus)
flags |= Win32.SWP_NOACTIVATE;
Win32.SetWindowPos(this.Handle, Win32.HWND_TOP, 0, 0, 0, 0, flags);
}
}
// P/Invoke stuff
public abstract class Win32
{
private Win32() {} // static class
[DllImport("user32.dll")]
public static extern IntPtr GetAncestor(IntPtr hwnd, uint gaFlags);
[DllImport("user32.dll", SetLastError = true, CharSet = CharSet.Auto)]
public static extern int GetClassName(IntPtr hWnd, [Out] StringBuilder lpClassName, int nMaxCount);
[DllImport("user32.dll", SetLastError = true)]
public static extern int SetWindowLong(IntPtr hWnd, int nIndex, int dwNewLong);
[DllImport("user32.dll", SetLastError = true)]
public static extern bool SetWindowPos(IntPtr hWnd, IntPtr hWndInsertAfter, int X, int Y, int cx, int cy, uint uFlags);
public const uint GA_ROOT = 2;
public const int GWL_HWNDPARENT = -8;
public const uint SWP_NOSIZE = 0x0001;
public const uint SWP_NOMOVE = 0x0002;
public const uint SWP_FRAMECHANGED = 0x0020;
public const uint SWP_SHOWWINDOW = 0x0040;
public const uint SWP_NOACTIVATE = 0x0010;
public static IntPtr HWND_TOP = (IntPtr)(0);
}