Your Privacy Matters: We use our own and third-party cookies to improve your experience on our website. By continuing to use the website we understand that you accept their use. Cookie Policy
565
Hooking a tool windows WNDPROC in XamDockManager
posted

This is an odd one and a work around to problems on a customer system.  It also happens to be something I'd like to do as my app doesn't function well across monitos.

Using an app written in WPF/C#, a customer tries to maximize the window.  His machine is running win 8.1, 640bit with three monitors.  On maximizing the window it expand to cover all three windows, and then terminates with a "invalid DPI error", which I believe is coming from the display driver.  This is easy enough to fix by hooking the main windows wndproc and limiting its max size to be only as large as the monitor it is on.

Now the app uses XamDockManager, and consists of  several tabs that the user can 'pop out' to be their own window.  They end up being PaneToolWindows, I've tried to find the HWND so I can hook into the wndproc of the window that manages this window so when the users presses maximize on the tool bar window it maximize to the monitor it is located on.  Unfortunately I haven't been successful. 

I am sure I am missing something that will allow me to limit the size of the tool window (hopefully dynamically so it can be limited to the monitor it on.)  

What can you recommend I try?

On the main window this is what I do:

Hooking the WNDPROC in the loaded event:

// Attach our WndProc handler to this Window
HwndSource source = HwndSource.FromHwnd(Handle);

Debug.Assert(source != null, "source != null");
// ReSharper disable once ConditionIsAlwaysTrueOrFalse
if (source != null) source.AddHook(WndProc);

The Wnd Proc

// ReSharper disable PossibleNullReferenceException
private IntPtr WndProc(IntPtr hwnd, int msg, IntPtr wParam, IntPtr lParam, ref bool handled)
{
// Check if a System Command has been executed
switch (msg)
{
case NativeMethods.WM_GETMINMAXINFO:
{
MonitorInfo.WmGetMinMaxInfo(hwnd, lParam);
handled = true;
}
break;

break;

}

return IntPtr.Zero;
}

Routine to set the MIn/max Info stucture based on windows monitor:

public static void WmGetMinMaxInfo(IntPtr hwnd, IntPtr lParam)
{
var mmi = (MINMAXINFO)Marshal.PtrToStructure(lParam, typeof(MINMAXINFO));

// Adjust the maximized size and position to fit the work area of the correct monitor
IntPtr monitor = MonitorFromWindow(hwnd, (int)MonitorFromWindowFlags.MONITOR_DEFAULTTONEAREST);

if (monitor != IntPtr.Zero)
{
var monitorInfo = new MONITORINFO();
GetMonitorInfo(monitor, monitorInfo);
RECT rcWorkArea = monitorInfo.rcWork;
RECT rcMonitorArea = monitorInfo.rcMonitor;
mmi.ptMaxPosition.X = Math.Abs(rcWorkArea.Left - rcMonitorArea.Left);
mmi.ptMaxPosition.Y = Math.Abs(rcWorkArea.Top - rcMonitorArea.Top);
mmi.ptMaxSize.X = Math.Abs(rcWorkArea.Right - rcWorkArea.Left);
mmi.ptMaxSize.Y = Math.Abs(rcWorkArea.Bottom - rcWorkArea.Top);
}

Marshal.StructureToPtr(mmi, lParam, true);
}

I'm looking for a way to accomplish the same thing on a tool window.

I've try hooking in the toolwindow loaded event, but with out success:

//ToolWindow toolWindow = VisualTreeHelperExtended.GetAncestor(e.Window, typeof (ToolWindow)) as ToolWindow;
//if (toolWindow != null)
//{
// DependencyObject toolWindowPresenter = VisualTreeHelper.GetParent(toolWindow as DependencyObject);

// if (toolWindowPresenter != null)
// {
// DependencyObject toolWindowHost = VisualTreeHelper.GetParent(toolWindowPresenter);

// if (toolWindowHost != null)
// {
// Window twh = toolWindowHost as Window;

// if (twh != null)
// {
// IntPtr handle = new WindowInteropHelper(twh).EnsureHandle();

// HwndSource source = (HwndSource) HwndSource.FromHwnd(handle);

// Debug.Assert(source != null, "source != null");

// // ReSharper disable once ConditionIsAlwaysTrueOrFalse
// if (source != null)
// source.AddHook(ToolWindowWndProc);
// }
// }
// }
//}

I know it a weird one, but anything you can do to help is appreciated.

  • 54937
    Verified Answer
    Offline posted

    Well one option might be to just set the MaxWidth and MaxHeight of the PaneToolWindow in the ToolWindowLoaded event (via the Window property of the event args).

    If that isn't sufficient then you might try getting the HwndSource using the PresentationSource.FromVisual method in the ToolWindowLoaded; you'll need to check the return type and upcast from PresenationSource to HwndSource. I'm not sure if it will be available at that point but even if it is then you probably want to add a handler into the PresentationSource.AddSourceChangedHandler method in the ToolWindowLoaded so you can respond (unhook from the old and hook into the new assuming its non-null) when/if the HwndSource changes. You should also hook into the ToolWindowUnloaded and make sure you remove that handler (using PresentationSource.RemoveSourceChangedHandler).