Possible to cast active Microsoft Word window to WPF Window? - c#

I've created a Microsoft Word 2010 vsto add-in which displays a number of custom Wpf Window dialogs when users click on ribbon buttons.
The issue I'm having is that the custom dialog dissapears behind the Word instance if you click the Word icon in the task bar.
After some Googling it appears that this can be fixed by setting the Owner property of my window, but I'm struggling to get the Window instance of the Word application.
I've attached the relevant code below, any suggestions?
using WordNS = Microsoft.Office.Interop.Word;
Window wrapperWindow = new Window();
wrapperWindow.ResizeMode = ResizeMode.NoResize;
wrapperWindow.WindowStartupLocation = System.Windows.WindowStartupLocation.CenterScreen;
wrapperWindow.ShowInTaskbar = false;
wrapperWindow.Content = dialogViewModel.View;
wrapperWindow.Title = dialogViewModel.Title;
wrapperWindow.SizeToContent = SizeToContent.WidthAndHeight;
WordNS.Application app = (WordNS.Application)Marshal.GetActiveObject("Word.Application");
wrapperWindow.Owner = (Window)app.ActiveWindow;

The exception clearly states that the answer to your question is No.
If Microsoft.Office.Interop.Word provides any means to get the window handle (HWND) of Word's main window (or if you get that handle by some Win32 call), you might try to set your window's owner by the WindowInteropHelper.Owner property.

Used Clemens' suggestion to go with the WindowInteropHelper route, below is the complete code to get this working:
1) Define this pointer anywhere inside your class:
[DllImport("user32.dll")]
private static extern IntPtr GetForegroundWindow();
2) Add the following code to the window declaration code:
Window wrapperWindow = new Window();
//Set all the relevant window properties
//Set the owner of the window to the Word application
IntPtr wordWindow = GetForegroundWindow();
WindowInteropHelper wih = new WindowInteropHelper(wrapperWindow);
wih.Owner = wordWindow;

Related

Can't select text in RichEditComponent control

I want to keep my app's window in front of another programs's window.
My app is created with WPF, I set owner with another window's hwnd like this:
// this: my wpf window
WindowInteropHelper helper = new WindowInteropHelper(this);
//The hwnd is handle of window that other program I want to follow
helper.Owner = new IntPtr(hwnd);
Everything is perfect, but I can't select text with mouse within RichEditComponent of the window (the hwnd window).
Any idea to fix this?
Don't know other program write with which language,maybe c++. Handle of other program's window obtained with windows api "FindWindowEx".
If your other program is a Winforms program, you need to add a reference to
System.Windows.Forms.Integration.dll
and add a call to ElementHost.EnableModelessKeyboardInterop(Window window) like shown below:
WindowInteropHelper helper = new WindowInteropHelper(this);
helper.Owner = new IntPtr(hwnd);
ElementHost.EnableModelessKeyboardInterop(this);
because apparently Winforms and WPF have different ways of handling text input (and therefore also affecting text selection - more specific, copy & paste of selected text - as well).
Other than that, the issue might be the HWND pointer - how do you obtain it?
e.g. this is how you can obtain the main window handle by specifying a process name:
Process process = Process.GetProcessesByName("...")[0];
IntPtr hwnd = process.MainWindowHandle;
I had resolved the question by detect Mouse drag event use global hook. When drag start,cancel set owner,and then,when drag finished,set owner with the follow window again.
Use MouseKeyHook to detect global mouse drag event.
https://www.nuget.org/packages/MouseKeyHook
Thanks #Thomas Flinkow again,for your help!

Modal WPF dialog does not invoke at center of the invoking window

I'm trying to invoke a WPF dialog from a child window of a Win32 application and was able to achieve this using the Window Handle (HWND) of the invoking window and passing it to the WPF code where I use the WindowInteropHelper class to set the Owner property to the handle of the invoking window. The code snippet below shows the WPF code where I'm setting the Owner property.
public void ShowModal(IntPtr ownerWindow)
{
WindowInteropHelper helper = new WindowInteropHelper(this);
helper.Owner = ownerWindow;
this.ShowDialog();
}
I'm getting the HWND of the invoking dialog using the Windows function as shown below:
HWND handle = GetTopWindow(GetActiveWindow());
While this works as expected functionally (the WPF dialog invokes as a modal dialog), it gets invoked at the top left corner of the screen. I've even set the WindowStartupLocation="CenterOwner" property in the XAML code. It works perfectly fine when invoked from a WPF window but not when Win32 window is involved. I guess I'm missing something in the WPF-Win32 interop here although it seems to me that the problem lies with the HWND retrieved from GetTopWindow(GetActiveWindow()).
UPDATE: I replaced the above code to get the HWND of the invoking window to the code below and now the WPF dialog always invokes at the center of the screen irrespective of the position of the window that invokes it.
HWND hWnd = GetActiveWindow();
if (hWnd != NULL)
{
hWnd = FindWindowEx(hWnd, NULL, "Window1", NULL);
if (hWnd != NULL)
{
hWnd = FindWindowEx(hWnd, NULL, "Window2", NULL);
}
}
Here Window2 is the Window that invokes the WPF dialog.
In your ShowModal() can you try :
this.Owner = App.MainWindow;

Lost focus issue when using WPF and WindowsInteropHelper

I have a problem with hosting a WPF window inside Excel. What we want to achieve is a window similar to Excel 2013 chart icons next to the chart when chart is selected.
The normal logic is already in place, but there was an issue with click on the ribbon or switching to another window and back to Excel. Both of those scenarios resulted in our window getting hidden.
The solution to this is to set the Owner of our WPF window which is not straight forward when combining Excel and WPF windows. The solution for now was this:
// Getting the active window
[DllImport("user32.dll")]
static extern IntPtr GetActiveWindow();
// Using the WindowInteropHelper to bind WPF window to excel
var wpfWindow = new WPFWindow();
var handle = GetActiveWindow();
helper = new WindowInteropHelper(wpfWindow) { Owner = handle };
wpfWindow.Show();
The above code works fine as long as we only stay in Excel. However the following steps produce a problem:
show our wpfWindow from an Excel addin
switch to another program that is currently running (like browser,...)
switchback to Excel
when our form hides the previously selected program becomes activated and is shown on top of Excel
Any solution to this issue? I have read two similar problems here and here, but they don't offer a working solution.
(I realise this is an old question but hopefully will help someone in the future)
This seems to be a known bug with using window.Show() in wpf windows that hasn't been fixed ( here and here )
Forcing focus to the Owner before Closing seems to work for me (Solution posted in the first link):
[DllImport("user32.dll")]
[return: MarshalAs(UnmanagedType.Bool)]
static extern bool SetForegroundWindow(IntPtr hWnd);
// Getting the active window
[DllImport("user32.dll")]
static extern IntPtr GetActiveWindow();
// Using the WindowInteropHelper to bind WPF window to excel
var wpfWindow = new WPFWindow();
wpfWindow.Closing += (sender, args) => SetForegroundWindow(new WindowInteropHelper(wpfWindow).Owner);
var handle = GetActiveWindow();
helper = new WindowInteropHelper(wpfWindow) { Owner = handle };
wpfWindow.Show();

WPF window should be modal to native owner window, but isn't

I have the following C# code in a WPF project:
private static void RunConfig(string owner)
{
long ownerHandle;
var settingsWindow = new SettingsWindow();
if (long.TryParse(owner, out ownerHandle))
{
WindowInteropHelper helper = new WindowInteropHelper(settingsWindow);
helper.Owner = new IntPtr(ownerHandle);
}
settingsWindow.ShowDialog();
}
The SettingsWindow isn't properly modal to the owner window (i.e. I can focus on, interact with, and even close the owner window while the SettingsWindow is still open). What am I doing wrong?
For context, this code is part of a screen saver program, and the owner window is the Control Panel screen saver selection window (which passes in the handle to use as owner via command line parameter). I know the IF statement is evaluating true and correctly parsing the handle.
I have also tried using the SetWindowLongPtr method from user32.dll (compiling for x64, hence not using SetWindowLong) which is briefly described here and shown in use here. This method works in WinForms, but doesn't seem to work here in WPF. Help me Obi-Wan Kenobi, you're my only hope.
It turns out that using WindowInteropHelper to set the native window as owner of the WPF Window does work, it just doesn't do the whole job. When set this way, the WPF Window will remain visible on top of the native window, even if the native window has focus. However, that is the only effect obtained. The WPF Window does not prevent interaction with the native Window, and the native window can even be closed, without the WPF Window closing or being affected.
In order to get the rest of the desired behaviour, we need to use the EnableWindow function in user32.dll to disable the native Window before calling ShowDialog on the WPF Window, and again to re-enable it once the WPF Window closes.
The modified code looks like this:
private static void RunConfig(string owner)
{
long ownerHandle;
var settingsForm = new SettingsWindow();
if (long.TryParse(owner, out ownerHandle))
{
WindowInteropHelper helper = new WindowInteropHelper(settingsForm);
helper.Owner = new IntPtr(ownerHandle);
NativeMethods.EnableWindow(helper.Owner, false);
settingsForm.ShowDialog();
NativeMethods.EnableWindow(helper.Owner, true);
}
else
{
settingsForm.ShowDialog();
}
}
(Note: The above code is correct in general, but incomplete in the case of screen savers, which is what this code is actually being used for. In the case that this code is being used for the config window of a screen saver, the string passed in for the owner handle is not the handle of the Control Panel window to be used as owner, but rather a handle for a control that is a child of the Control Panel window. The extra step in this case is to get the handle of the parent of that control. We can do this by calling GetParent, also in user32.dll, on the passed-in handle. This will return the real handle we want to use for the owner and EnableWindow calls.)
If anyone from Microsoft ever finds this, maybe consider modifying WindowInteropHelper to properly set all of this up when Owner is assigned and ShowDialog used, since this is the proper complete behavior for modal windows.

Refer to active Window in WPF?

How can I refer to active Window of WPF application in C#, using something like ActiveForm property in WinForms?
One possible way would be to scan the list of open windows in the application and check which one of them has IsActive = true:
Application.Current.Windows.OfType<Window>().SingleOrDefault(x => x.IsActive);
Not sure if there may be more than one active window if, for example, there's a modal dialog showing, in which case, the owner of the dialog and the dialog itself might be active.
There is better way to do this using PInvoke. Aviads answer is not working all the time (there are some edge cases with dialogs).
IntPtr active = GetActiveWindow();
ActiveWindow = Application.Current.Windows.OfType<Window>()
.SingleOrDefault(window => new WindowInteropHelper(window).Handle == active);
One must include following import first:
[DllImport("user32.dll")]
static extern IntPtr GetActiveWindow();
I know this is a bit old question but I think my answer could help someone.
My problem was this: I had a WPF MVVM application and I needed to get my MainWindow instance in the second view, i.e. second view model, in order to set the visibility of title bar button to visible.
This is my solution:
MainWindow window = (MyApp.MainWindow)App.Current.MainWindow;
window.btnSearch.Visibility = System.Windows.Visibility.Visible;
Hope this would help someone.
I have problems With this way "Application.Current.Windows.OfType().SingleOrDefault(x => x.IsActive);" specialy because I was building an aplication with a main Window then i had problems when the main window was selected. I resolve it creating this:
In some base class or App.xaml.cs create this:
public static Window ActivatedWindow {get;set;}
Then put in your base class deriving Window or all of your Window's Activate Event:
First Option - personal Window Base Class:
public class MetroToolWindowBase
{
public MetroToolWindowBase()
{
Activated += new EventHandler(MakeActive);
}
private void MakeActive(object sender, EventArgs e)
{
App.ActivatedWindow= this;
}
}
Second Option- In Activated Event of Windows:
private void XWindow_Activated(object sender,EventArgs e)
{
App.ActivatedWindow= this;
}
Another way to do it is to use the native GetActiveWindow function from user32.dll.
[DllImport("user32.dll", CharSet = CharSet.Auto)]
public static extern IntPtr GetActiveWindow();
To convert it to an actual WPF Window:
IntPtr handle = GetActiveWindow();
HwndSource hwndSource = HwndSource.FromHwnd(handle);
var window = hwndSource?.RootVisual as Window;
If hosting a WPF Window in a WinForms app, WindowInteropHelper should be used. This makes for example the Window owner work correctly:
var wih = new WindowInteropHelper(window)
{
Owner = GetActiveWindow()
};
I edited my old answer because the edge case I encountered disappeared after a Visual Studio update, but it can be checked from answer history. I encountered an issue there where I was getting null for active window in certain circumstances while debugging.

Categories

Resources